RISC-V Development

SpacemiT K3 PCIe Root Complex Heads for Upstream Linux: v7 Patch Series

📅 2026-10-01 ⏱ 8 min read 🔗 Source: linux-riscv mailing list, Inochi Amaoto, Sep 29 2026

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.

Honesty note. The patches are v7 and under active review. They are not merged into Linus's tree as of October 1, 2026. Andy Shevchenko posted review comments on September 30; Aurelien Jarno has provided Tested-by tags on patches 1, 2, 3 and 6. The series also depends on phy bulk-data support that was posted separately. Do not plan a production K3 storage build around this code until it lands.

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:

FeatureSpacemiT K1SpacemiT K3
MSI controllerInternal / legacyExternal IMSIC (part of RISC-V AIA)
PHY handlingSingle PHYMultiple PHYs can be active at once
Reset / link controlBasicExtra PERST#, LTSSM and power-control registers
ASPMSupportedL1 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.

PatchFile(s)Purpose
1/6pcie-spacemit-k1.cAdd device-data support so one driver can distinguish K1 and K3 silicon
2/6pcie-spacemit-k1.cAdd multiple PHY handles support (required for K3 multi-PHY topology)
3/6pcie-spacemit-k1.cAdd device-ID update helper used by both K1 and K3
4/6snps,dw-pcie.yamlAdd msi-parent property for MSI handle validation
5/6spacemit,k1-pcie-host.yamlIntroduce SpacemiT K3 PCIe host-controller binding
6/6pcie-spacemit-k1.cAdd 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:

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 / modulePCIe exposureWhy upstream PCIe matters
Milk-V Jupiter 2PCIe slot (reported by Zig CI fleet users)NVMe / NIC expansion without vendor kernel
Banana Pi BPI-SM10 / BPI-F3SoM carrier designsIndustrial / gateway custom carriers
K3 Pico-ITXM.2 / expansionAll-in-one AI edge box storage and networking
DeepComputing DC-ROMA IIILaptop-class I/OInternal 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

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 插槽之前还需要哪些步骤。

诚实声明。 该补丁系列目前为 v7,仍在活跃评审中,尚未合并到 Linus 树(截至 2026-10-01)。Andy Shevchenko 在 9 月 30 日给出了评审意见;Aurelien Jarno 已为 patch 1、2、3、6 提供 Tested-by。本系列还依赖单独提交的 phy bulk-data 支持。在代码落地之前,请勿将其用于生产级 K3 存储方案。

为什么 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 K1SpacemiT 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/6pcie-spacemit-k1.c加入 device-data 支持,使同一驱动能区分 K1 与 K3 芯片
2/6pcie-spacemit-k1.c加入多 PHY handle 支持(K3 多 PHY 拓扑所需)
3/6pcie-spacemit-k1.c加入 K1/K3 共用的 device-ID 更新 helper
4/6snps,dw-pcie.yaml添加 msi-parent 属性以校验 MSI handle
5/6spacemit,k1-pcie-host.yaml引入 SpacemiT K3 PCIe host-controller 绑定
6/6pcie-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 展现了典型的上游驱动成熟曲线:

9 月 30 日 Andy Shevchenko 的评审集中在代码风格(位掩码排列、单行格式)以及 regmap I/O 错误路径是否应在封面信中说明。这些属于普通晚期评审意见,而非架构性反对。

在真实硬件上能解锁什么

K3 已出现在多款已出货或已公布的板卡上。对带有物理插槽或 M.2 接口的板子来说,上游 PCIe 驱动尤为关键:

板卡 / 模组PCIe 暴露方式上游 PCIe 支持的意义
Milk-V Jupiter 2PCIe 插槽(Zig CI 用户报告)无需厂商内核即可扩展 NVMe / 网卡
Banana Pi BPI-SM10 / BPI-F3SoM 载板设计工业 / 网关自定义载板
K3 Pico-ITXM.2 / 扩展接口一体式 AI 边缘盒子的存储与网络
DeepComputing DC-ROMA III笔记本级 I/O内置 Wi-Fi、SSD、可选 GPU

值得再次强调:本系列只解决主机控制器一侧。板卡仍需要正确的 pinmux、时钟、复位和 PHY 设备树节点,链路才能 train 起来。但控制器驱动是必须进入上游内核的那部分;其余是板级设备树工作。

要点总结

本站相关报道: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 / 参考来源

← Back to Tech Blog