SpacemiT K3 PCIe Root Complex Heads for Upstream Linux: v7 Patch Series
On September 29, 2026, Inochi Amaoto posted v7 of the patch series that adds PCIe Root Complex (RC) controller support for the SpacemiT K3 to upstream Linux. The series is short — six patches, four files, 270 insertions and 33 deletions — but it is one of the last big platform gaps standing between the K3 and a fully upstream kernel. Without it, NVMe drives, Wi-Fi cards, Ethernet controllers, GPUs and other PCIe endpoints on K3 boards still depend on a vendor tree.
This article walks what the series does, how it reuses the existing K1 driver, and what still has to happen before upstream Linux can drive a PCIe slot on a K3 board.
Why PCIe Matters for the K3
The SpacemiT K3 is marketed as an RVA23 application processor: 8 × X100 + 8 × A100 cores, up to 60 TOPS of AI compute, and a modern I/O set. In practice, much of that I/O — high-speed NVMe, Wi-Fi 6/7, 10 GbE NICs, AI accelerators — only becomes useful if the SoC can speak PCIe to expansion devices.
The K1 already had a PCIe controller, but the K3's is different in two important ways that prevented the existing driver from simply working:
| Feature | SpacemiT K1 | SpacemiT K3 |
|---|---|---|
| MSI controller | Internal / legacy | External IMSIC (part of RISC-V AIA) |
| PHY handling | Single PHY | Multiple PHYs can be active at once |
| Reset / link control | Basic | Extra PERST#, LTSSM and power-control registers |
| ASPM | Supported | L1 disabled as a workaround in current series |
IMSIC is the Incoming MSI Controller defined by the RISC-V Advanced Interrupt Architecture (AIA). Moving MSI handling out of the PCIe block and into the SoC-level interrupt fabric is the RVA23-style way to do MSI, but it means the PCIe driver has to wire up an msi-parent property and let the platform handle interrupt delivery rather than synthesizing MSIs inside the controller.
What the Six Patches Do
The series reuses the existing drivers/pci/controller/dwc/pcie-spacemit-k1.c driver and generalizes it into a shared SpacemiT DesignWare PCIe driver rather than forking a new file. The patch order is deliberate: infrastructure first, K3 bindings and support last.
| Patch | File(s) | Purpose |
|---|---|---|
| 1/6 | pcie-spacemit-k1.c | Add device-data support so one driver can distinguish K1 and K3 silicon |
| 2/6 | pcie-spacemit-k1.c | Add multiple PHY handles support (required for K3 multi-PHY topology) |
| 3/6 | pcie-spacemit-k1.c | Add device-ID update helper used by both K1 and K3 |
| 4/6 | snps,dw-pcie.yaml | Add msi-parent property for MSI handle validation |
| 5/6 | spacemit,k1-pcie-host.yaml | Introduce SpacemiT K3 PCIe host-controller binding |
| 6/6 | pcie-spacemit-k1.c | Add the K3 PCIe host-controller support itself |
The diff is small because most of the logic is shared. Patches 1–3 refactor the K1 driver into a shape that can absorb K3, and patch 6 adds the K3-specific init sequence. The K3 init is where the reset dance happens: clear LTSSM enable, toggle soft reset, assert PERST# via PMU registers, bring PHYs up in bulk, wait the required TPVPERL delay, then deassert PERST# and finally disable ASPM L1.
K3 PCIe Init in Code
The K3-specific initialization, as shown in the posted patch and reviewed by Andy Shevchenko, follows the standard DesignWare bring-up but adds SpacemiT PMU register choreography:
static int k3_pcie_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct k1_pcie *k1 = to_k1_pcie(pci);
u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
u32 val;
int ret;
regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);
k1_pcie_toggle_soft_reset(k1);
/* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
regmap_update_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT,
PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE);
ret = k1_pcie_enable_resources(k1);
if (ret)
goto failed_resources;
regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
ret = phy_bulk_init(k1->phy_count, k1->phys);
if (ret)
goto failed_phy_init;
ret = phy_bulk_power_on(k1->phy_count, k1->phys);
if (ret)
goto failed_phy_power_on;
msleep(PCIE_T_PVPERL_MS);
regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
val = u32_replace_bits(val, BIT(7),
GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
k1_pcie_set_device_id(k1);
/* Finally, as a workaround, disable ASPM L1 */
k1_pcie_disable_aspm_l1(k1);
return 0;
failed_phy_power_on:
phy_bulk_exit(k1->phy_count, k1->phys);
failed_phy_init:
k1_pcie_disable_resources(k1);
failed_resources:
regmap_update_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
PCIE_PERSTN_OUT | PCIE_PERSTN_OE,
PCIE_PERSTN_OE);
return ret;
}
The code paths for error cleanup were a focus of the v7 revision: patch 6 now keeps PERST# asserted when initialization fails, matching the deinit behavior. That is the kind of detail that matters when the controller is wired to a real slot on a board like the Milk-V Jupiter 2.
From v1 to v7: What Took Six Revisions
The series has been on the mailing list since May 2026. The changelog in the cover letter shows a typical upstream driver maturation arc:
- v1 → v2: unified PHY get/enable/exit for both K1 and K3; introduced device-ID update helper; reused K1 binding for K3.
- v2 → v3: added missing interrupt/interrupt-names checks for K1.
- v3 → v4: switched to phy bulk data to simplify the code; rebased to latest master; separated K3 init/deinit and added error handling.
- v4 → v5: returned
ENODATAfor missing device data; added PHY power_on/power_off hooks and a zero-PHY guard; added K3 device description. - v5 → v6: kept PERST# asserted on init failure, matching deinit.
- v6 → v7: the current version, with the same PERST# fix and additional review.
Review on September 30 from Andy Shevchenko focused on style (bit-mask permutations, single-line formatting) and on a regmap I/O error path that the cover letter should perhaps note. These are ordinary late-review comments, not architectural objections.
What This Unlocks on Real Hardware
The K3 appears on several shipping or announced boards. A working upstream PCIe driver matters most for the ones that expose physical slots or M.2 connectors:
| Board / module | PCIe exposure | Why upstream PCIe matters |
|---|---|---|
| Milk-V Jupiter 2 | PCIe slot (reported by Zig CI fleet users) | NVMe / NIC expansion without vendor kernel |
| Banana Pi BPI-SM10 / BPI-F3 | SoM carrier designs | Industrial / gateway custom carriers |
| K3 Pico-ITX | M.2 / expansion | All-in-one AI edge box storage and networking |
| DeepComputing DC-ROMA III | Laptop-class I/O | Internal Wi-Fi, SSD, optional GPU |
It is worth repeating: this series is only the host controller side. A board still needs correct pinmux, clock, reset and PHY device-tree nodes for the link to train. But the controller driver is the piece that has to live in the upstream kernel; the rest is board-specific device tree.
Takeaways
- K3 PCIe is now a review-cycle problem, not a missing-driver problem. v7 is a sign the code is converging.
- The K1 and K3 share more than the marketing suggests. Refactoring one driver to cover both reduces long-term maintenance load and makes backports easier.
- IMSIC/AIA integration is the architectural headline. K3's move to an external MSI controller aligns the SoC with RVA23 interrupt architecture.
- ASPM L1 is disabled for now. Power users should expect a small idle-power penalty on PCIe links until the workaround is replaced with a proper fix.
- Do not ship on this yet. Wait for the series to land and for board vendors to test it against their own PHY/clock trees.
Related coverage on this site: the K3 Pico-ITX review, K3 RVA23 architecture, OpenSBI K3 platform support, Xen on the K3, and HPL on the K3's VLEN=1024 AI cores.
2026 年 9 月 29 日,Inochi Amaoto 向 linux-riscv 邮件列表提交了为 SpacemiT(进迭时空)K3 添加上游 Linux PCIe Root Complex(RC)控制器支持的 v7 补丁系列。整套补丁很短:6 个 patch、4 个文件、增 270 行删 33 行——但它几乎是 K3 距离「完整上游内核支持」所剩的最后一个大型平台缺口。没有它,K3 板子上的 NVMe 固态盘、Wi-Fi 网卡、以太网控制器、GPU 等 PCIe 设备仍要依赖厂商内核。
本文梳理这套补丁做了什么、如何复用现有 K1 驱动,以及在上游 Linux 真正能驱动 K3 的 PCIe 插槽之前还需要哪些步骤。
为什么 PCIe 对 K3 至关重要
SpacemiT K3 的定位是 RVA23 应用处理器:8 × X100 + 8 × A100 核心、最高 60 TOPS AI 算力,以及一套现代化 I/O。但实际上,这些 I/O 中的大部分——高速 NVMe、Wi-Fi 6/7、10GbE 网卡、AI 加速卡——只有在 SoC 能通过 PCIe 与扩展设备通信时才有意义。
K1 已经带有 PCIe 控制器,但 K3 在两方面明显不同,导致无法直接复用 K1 驱动:
| 特性 | SpacemiT K1 | SpacemiT K3 |
|---|---|---|
| MSI 控制器 | 内部 / 传统实现 | 外部 IMSIC(RISC-V AIA 的一部分) |
| PHY 处理 | 单 PHY | 可同时使用多个 PHY |
| 复位 / 链路控制 | 基础实现 | 额外的 PERST#、LTSSM 与电源控制寄存器 |
| ASPM | 支持 | 当前系列中作为规避方案禁用 L1 |
IMSIC 即 RISC-V 高级中断架构(AIA)定义的入向 MSI 控制器。把 MSI 处理从 PCIe 控制器内部移到 SoC 级中断网络,是 RVA23 风格的实现方式;但这要求 PCIe 驱动在设备树中配置 msi-parent 属性,由平台负责中断投递,而不是在控制器内部合成 MSI。
六个补丁分别做什么
本系列复用现有的 drivers/pci/controller/dwc/pcie-spacemit-k1.c 驱动,将其泛化为一个共享的 SpacemiT DesignWare PCIe 驱动,而不是另起新文件。补丁顺序经过设计:先基础设施,再 K3 绑定与支持。
| Patch | 文件 | 作用 |
|---|---|---|
| 1/6 | pcie-spacemit-k1.c | 加入 device-data 支持,使同一驱动能区分 K1 与 K3 芯片 |
| 2/6 | pcie-spacemit-k1.c | 加入多 PHY handle 支持(K3 多 PHY 拓扑所需) |
| 3/6 | pcie-spacemit-k1.c | 加入 K1/K3 共用的 device-ID 更新 helper |
| 4/6 | snps,dw-pcie.yaml | 添加 msi-parent 属性以校验 MSI handle |
| 5/6 | spacemit,k1-pcie-host.yaml | 引入 SpacemiT K3 PCIe host-controller 绑定 |
| 6/6 | pcie-spacemit-k1.c | 添加 K3 PCIe host-controller 支持本身 |
diff 很小,因为大部分逻辑是共享的。补丁 1–3 把 K1 驱动重构为可吸收 K3 的形状,补丁 6 再添加 K3 特有的初始化序列。K3 初始化集中处理复位流程:清除 LTSSM 使能、触发软复位、通过 PMU 寄存器置位 PERST#、批量上电 PHY、等待必需的 TPVPERL 延时、解除 PERST#,最后禁用 ASPM L1。
K3 PCIe 初始化代码
K3 特有的初始化逻辑在提交的补丁中如下(Andy Shevchenko 评审版),它在标准 DesignWare 启动流程基础上增加了 SpacemiT PMU 寄存器编排:
static int k3_pcie_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct k1_pcie *k1 = to_k1_pcie(pci);
u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
u32 val;
int ret;
regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);
k1_pcie_toggle_soft_reset(k1);
/* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
regmap_update_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT,
PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE);
ret = k1_pcie_enable_resources(k1);
if (ret)
goto failed_resources;
regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
ret = phy_bulk_init(k1->phy_count, k1->phys);
if (ret)
goto failed_phy_init;
ret = phy_bulk_power_on(k1->phy_count, k1->phys);
if (ret)
goto failed_phy_power_on;
msleep(PCIE_T_PVPERL_MS);
regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
val = u32_replace_bits(val, BIT(7),
GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
k1_pcie_set_device_id(k1);
/* Finally, as a workaround, disable ASPM L1 */
k1_pcie_disable_aspm_l1(k1);
return 0;
failed_phy_power_on:
phy_bulk_exit(k1->phy_count, k1->phys);
failed_phy_init:
k1_pcie_disable_resources(k1);
failed_resources:
regmap_update_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
PCIE_PERSTN_OUT | PCIE_PERSTN_OE,
PCIE_PERSTN_OE);
return ret;
}
v7 对错误清理路径做了重点修正:初始化失败时保持 PERST# 置位,与 deinit 行为一致。这种细节对于 Milk-V Jupiter 2 等带真实 PCIe 插槽的板子至关重要。
从 v1 到 v7:六次迭代做了什么
该系列从 2026 年 5 月开始出现在邮件列表。封面信中的 changelog 展现了典型的上游驱动成熟曲线:
- v1 → v2:统一 K1/K3 的 PHY get/enable/exit;引入 device-ID 更新 helper;复用 K1 绑定描述 K3。
- v2 → v3:补充 K1 缺失的 interrupt/interrupt-names 检查。
- v3 → v4:改用 phy bulk data 简化代码;rebase 到最新 master;拆分 K3 init/deinit 并增加错误处理。
- v4 → v5:缺失 device data 时返回
ENODATA;增加 PHY power_on/power_off 钩子与 zero-PHY 保护;添加 K3 设备描述。 - v5 → v6:初始化失败时保持 PERST# 置位,与 deinit 对齐。
- v6 → v7:当前版本,保留上述 PERST# 修正并继续评审。
9 月 30 日 Andy Shevchenko 的评审集中在代码风格(位掩码排列、单行格式)以及 regmap I/O 错误路径是否应在封面信中说明。这些属于普通晚期评审意见,而非架构性反对。
在真实硬件上能解锁什么
K3 已出现在多款已出货或已公布的板卡上。对带有物理插槽或 M.2 接口的板子来说,上游 PCIe 驱动尤为关键:
| 板卡 / 模组 | PCIe 暴露方式 | 上游 PCIe 支持的意义 |
|---|---|---|
| Milk-V Jupiter 2 | PCIe 插槽(Zig CI 用户报告) | 无需厂商内核即可扩展 NVMe / 网卡 |
| Banana Pi BPI-SM10 / BPI-F3 | SoM 载板设计 | 工业 / 网关自定义载板 |
| K3 Pico-ITX | M.2 / 扩展接口 | 一体式 AI 边缘盒子的存储与网络 |
| DeepComputing DC-ROMA III | 笔记本级 I/O | 内置 Wi-Fi、SSD、可选 GPU |
值得再次强调:本系列只解决主机控制器一侧。板卡仍需要正确的 pinmux、时钟、复位和 PHY 设备树节点,链路才能 train 起来。但控制器驱动是必须进入上游内核的那部分;其余是板级设备树工作。
要点总结
- K3 的 PCIe 现在是一个「评审周期问题」,而不是「缺驱动问题」。v7 的出现说明代码正在收敛。
- K1 与 K3 的共性比宣传口径更大。把单一驱动重构为覆盖两者,能降低长期维护负担,也便于 backport。
- IMSIC/AIA 集成是架构层面的核心看点。K3 把 MSI 控制器外置,与 RVA23 中断架构对齐。
- ASPM L1 目前被禁用。在规避方案被正式修复前,PCIe 链路的空闲功耗会略高。
- 尚未可商用。请等待系列合入,并由板卡厂商针对各自 PHY/时钟树完成验证。
本站相关报道:K3 Pico-ITX 评测、K3 RVA23 架构、OpenSBI K3 平台支持、Xen 在 K3 上引导,以及 在 K3 VLEN=1024 AI 核上跑 HPL。
Краткое содержание (RU)
29 сентября 2026 года Inochi Amaoto отправил v7 патч-серию для добавления поддержки PCIe Root Complex в апстрим Linux для SpacemiT K3. Контроллер представляет собой почти стандартный Synopsys DesignWare PCIe IP с дополнительным управлением ссылкой / сбросом и внешним MSI-контроллером IMSIC (часть RISC-V AIA). В отличие от K1, K3 поддерживает несколько PHY одновременно. Серия из 6 патчей рефакторит существующий драйвер K1, добавляя device-data, множественные PHY-handle, helper обновления device-ID и K3-специфичную init-последовательность с обходным отключением ASPM L1. Aurelien Jarno дал Tested-by на патчи 1, 2, 3, 6; Andy Shevchenko опубликовал ревью 30 сентября. Код ещё не входит в upstream и зависит от phy bulk-data.
Resumen (ES)
El 29 de septiembre de 2026, Inochi Amaoto envió la v7 de la serie de parches que añade soporte para el controlador PCIe Root Complex del SpacemiT K3 al kernel upstream de Linux. El controlador es prácticamente un IP Synopsys DesignWare PCIe estándar con control adicional de enlace / reset y un controlador MSI externo IMSIC (parte de RISC-V AIA). A diferencia del K1, el K3 admite varios PHY simultáneamente. La serie de 6 parches refactoriza el driver existente del K1 añadiendo device-data, múltiples PHY handles, un helper de actualización de device-ID y una secuencia init específica para K3 que deshabilita ASPM L1 como workaround. Aurelien Jarno aportó Tested-by en los parches 1, 2, 3 y 6; Andy Shevchenko publicó revisión el 30 de septiembre. El código aún no está en upstream y depende de soporte phy bulk-data.
Résumé (FR)
Le 29 septembre 2026, Inochi Amaoto a posté la v7 de la série de patches ajoutant la prise en charge du contrôleur PCIe Root Complex du SpacemiT K3 dans le noyau Linux upstream. Le contrôleur est un IP Synopsys DesignWare PCIe quasi standard avec des contrôles de lien / reset supplémentaires et un contrôleur MSI externe IMSIC (partie de RISC-V AIA). Contrairement au K1, le K3 peut utiliser plusieurs PHY en même temps. La série de 6 patches refactorise le driver K1 existant en ajoutant le device-data, plusieurs handles PHY, un helper de mise à jour du device-ID et une séquence init spécifique au K3 qui désactive ASPM L1 en contournement. Aurelien Jarno a fourni Tested-by sur les patches 1, 2, 3 et 6 ; Andy Shevchenko a publié une revue le 30 septembre. Le code n'est pas encore upstream et dépend du phy bulk-data.
Kurzfassung (DE)
Am 29. September 2026 veröffentlichte Inochi Amaoto die v7 der Patch-Serie, die PCIe-Root-Complex-Unterstützung für den SpacemiT K3 im upstream-Linux-Kernel hinzufügt. Der Controller ist im Grunde ein Standard-Synopsys-DesignWare-PCIe-IP mit zusätzlicher Link-/Reset-Steuerung und einem externen MSI-Controller IMSIC (Teil von RISC-V AIA). Im Unterschied zum K1 unterstützt der K3 mehrere PHYs gleichzeitig. Die Serie aus 6 Patches refactort den vorhandenen K1-Treiber, fügt Device-Daten, mehrere PHY-Handles, einen Device-ID-Update-Helper und eine K3-spezifische Init-Sequenz hinzu, die ASPM L1 als Workaround deaktiviert. Aurelien Jarno lieferte Tested-by für die Patches 1, 2, 3 und 6; Andy Shevchenko veröffentlichte am 30. September ein Review. Der Code ist noch nicht upstream und hängt von phy bulk-data ab.
خلاصه (FA)
در 29 سپتامبر 2026، Inochi Amaoto نسخه v7 سری پچ را برای اضافهکردن پشتیبانی PCIe Root Complex برای SpacemiT K3 به کرنل upstream Linux ارسال کرد. کنترلکننده یک IP Synopsys DesignWare PCIe نسبتا ستاندارد با کنترل اضافی لینک/ریست و کنترلکننده MSI خارجی IMSIC (بخشی از RISC-V AIA) است. برخلاف K1، K3 چندین PHY را همزمان پشتیبانی میکند. سری 6 پچی دایور K1 را بازنگری میکند، device-data، چندین handle PHY، helper بهروزرسانی device-ID و سلسله init مخصوص K3 را اضافه میکند که ASPM L1 را به عنوان workaround غیرفعال میکند. Aurelien Jarno برای پچهای 1، 2، 3 و 6 Tested-by داده است؛ Andy Shevchenko در 30 سپتامبر نظریه ارسال کرد. کد هنوز وارد upstream نشده و به phy bulk-data وابسته است.
Sources / 参考来源
- linux-riscv — [PATCH v7 0/6] riscv: spacemit: Add PCIe RC controller support for K3, Inochi Amaoto, Sep 29 2026 — cover letter, changelog, patch list, Tested-by Aurelien Jarno
- linux-riscv — [PATCH v7 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support, Andy Shevchenko review, Sep 30 2026
- SpacemiT vendor tree — pcie-spacemit-k1.c on k3-br-v1.0.y (referenced as source of vendor fixes in cover letter)
- linux-phy — phy bulk data support prerequisite (Sep 4 2026), referenced in cover letter
- RISC-V Advanced Interrupt Architecture (AIA) specification — IMSIC definition
- Our coverage of the SpacemiT K3 Pico-ITX — board specs, PCIe slot note, KVM caveat
- K3 RVA23 architecture overview