From: Alex Elder <elder@riscstar.com>
To: "Inochi Amaoto" <inochiama@gmail.com>,
"Jingoo Han" <jingoohan1@gmail.com>,
"Manivannan Sadhasivam" <mani@kernel.org>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Yixun Lan" <dlan@kernel.org>, "Paul Walmsley" <pjw@kernel.org>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
"Albert Ou" <aou@eecs.berkeley.edu>,
"Alexandre Ghiti" <alex@ghiti.fr>,
"Christian Bruel" <christian.bruel@foss.st.com>,
"Frank Li" <Frank.Li@nxp.com>, "Nam Cao" <namcao@linutronix.de>,
"Qiang Yu" <qiang.yu@oss.qualcomm.com>,
"Krishna Chaitanya Chundru" <krishna.chundru@oss.qualcomm.com>,
"Xincheng Zhang" <zhangxincheng@ultrarisc.com>,
"Siddharth Vadapalli" <s-vadapalli@ti.com>,
"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
"Vidya Sagar" <vidyas@nvidia.com>,
"Neil Armstrong" <neil.armstrong@linaro.org>,
"Gustavo Pimentel" <gustavo.pimentel@synopsys.com>
Cc: linux-pci@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org,
spacemit@lists.linux.dev, Yixun Lan <dlan@gentoo.org>,
Longbin Li <looong.bin@gmail.com>
Subject: Re: [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support
Date: Fri, 10 Jul 2026 11:01:44 -0500 [thread overview]
Message-ID: <900e6239-bc00-46b6-aa9f-abe219c039d2@riscstar.com> (raw)
In-Reply-To: <20260709040027.958400-7-inochiama@gmail.com>
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 is almost a standard Synopsys
> DesignWare PCIe IP with extra link and reset control. Unlike
> the PCIe controller on K1, this controller supports external MSI
> interrupt controller and can use multiple PHYs at the same time.
>
> Add driver to support PCIe controller on Spacemit K3 PCIe.
I think it would be good to summarize how the K3 differs from
the K1 here as well, since they're sharing code. It looks
like it supports up to 6 PHYs, not just 1 (as the K1 does).
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
> drivers/pci/controller/dwc/Kconfig | 4 +-
> drivers/pci/controller/dwc/pcie-spacemit-k1.c | 126 ++++++++++++++++++
> 2 files changed, 128 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index aa0b784c85b4..dacbac5cc35c 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -440,7 +440,7 @@ config PCIE_SOPHGO_DW
> Sophgo SoCs.
>
> config PCIE_SPACEMIT_K1
> - tristate "SpacemiT K1 PCIe controller (host mode)"
> + tristate "SpacemiT PCIe controller (host mode)"
> depends on ARCH_SPACEMIT || COMPILE_TEST
> depends on HAS_IOMEM
> select PCIE_DW_HOST
> @@ -448,7 +448,7 @@ config PCIE_SPACEMIT_K1
> default ARCH_SPACEMIT
> help
> Enables support for the DesignWare based PCIe controller in
> - the SpacemiT K1 SoC operating in host mode. Three controllers
> + the SpacemiT SoC operating in host mode. Three controllers
> are available on the K1 SoC; the first of these shares a PHY
> with a USB 3.0 host controller (one or the other can be used).
>
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index 31aac056b68e..680acc93f539 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -23,6 +23,7 @@
>
> #define PCI_VENDOR_ID_SPACEMIT 0x201f
> #define PCI_DEVICE_ID_SPACEMIT_K1 0x0001
> +#define PCI_DEVICE_ID_SPACEMIT_K3 0x0002
>
> /* Offsets and field definitions for link management registers */
> #define K1_PHY_AHB_IRQ_EN 0x0000
> @@ -32,8 +33,18 @@
> #define SMLH_LINK_UP BIT(1)
> #define RDLH_LINK_UP BIT(12)
>
> +#define INTR_STATUS 0x0010
This register offset should probably be named K3_PHY_INTR_STATUS
(or maybe it's just K3_INTR_STATUS?). I see that INTR_ENABLE
doesn't have a prefix, and I don't know why--that should have
a similar name. (Please fix that in your next version as well;
I think it's OK to included it with this patch with a simple
mention in the patch description.)
> +
> #define INTR_ENABLE 0x0014
> #define MSI_CTRL_INT BIT(11)
> +#define RDLH_LINK_UP_INT BIT(20)
> +
> +#define K3_PHY_AHB_IRQSTATUS_INTX 0x0008
So is this enabling INTX support? If so, you should do that
first in a separate patch that only applies to K1 (and that
should be verified to work correctly). If all you're doing
is ensuring the status is cleared, that's OK here, but if
you don't enable it I'm not sure it matters.
> +
> +#define K3_ADDR_INTR_STATUS1 0x0018
> +
> +#define K3_CACHE_MSTR_AWCACHE_MODE GENMASK(14, 11)
> +#define K3_CACHE_MSTR_AWCACHE_BEHAVIOR 0xf
>
> /* Some controls require APMU regmap access */
> #define SYSCON_APMU "spacemit,apmu"
> @@ -48,6 +59,9 @@
>
> #define PCIE_CONTROL_LOGIC 0x0004
> #define PCIE_SOFT_RESET BIT(0)
> +#define PCIE_PERSTN_OE BIT(24)
> +#define PCIE_PERSTN_OUT BIT(25)
> +#define PCIE_IGNORE_PERSTN BIT(31)
>
> struct k1_pcie;
>
> @@ -340,6 +354,109 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
> return ret;
> }
>
I ask a few questions in this function; I'm basically
asking "are you *sure* this must be different for K3
than K1?" Because for the most part this function looks
very similar to k1_pcie_init().
> +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);
Would it be OK to clear this bit in the reset control
register for K1 as well?
> +
> + k1_pcie_toggle_soft_reset(k1);
> +
> + ret = k1_pcie_enable_resources(k1);
> + if (ret)
> + return ret;
> +
> + regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
> + regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
> +
> + ret = k1_pcie_enable_phy(k1);
> + if (ret) {
> + k1_pcie_disable_resources(k1);
> + return ret;
> + }
> +
The handling of PERSTN looks different for K3 than K1. Could you
implement a helper function that abstracts the differences?
I don't really understand what's happening here, but if it's
comparable to this for K1:
/* Deassert fundamental reset (drive PERST# high) */
regmap_clear_bits(k1->pmu, reset_ctrl, PCIE_RC_PERST);
...then a callback function (similar to parse_port) in the device
data might be able to be called for both platforms, allowing
the init function to be common for both.
> + /* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
> + regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> + PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> + usleep_range(1000, 2000);
> + regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> +
> + msleep(PCIE_T_PVPERL_MS);
> +
> + /*
> + * Put the controller in root complex mode, and indicate that
> + * Vaux (3.3v) is present.
Here too, you could abstract what's happening and that might
allow the init function to be common for both (all) platforms.
> + */
> + 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);
This is done earlier in k1_pcie_init(). Could it be done at the
same time for both platforms?
> +
> + /* Finally, as a workaround, disable ASPM L1 */
> + k1_pcie_disable_aspm_l1(k1);
> +
> + return 0;
> +}
> +
> +static int k3_pcie_msi_host_init(struct dw_pcie_rp *pp)
Why is this needed for K3, but not for K1? Does this
enable any functionality that K1 could use and benefit
from?
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + u32 val;
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> +
> + val = dw_pcie_readl_dbi(pci, COHERENCY_CONTROL_3_OFF);
> + val = u32_replace_bits(val, K3_CACHE_MSTR_AWCACHE_BEHAVIOR,
> + K3_CACHE_MSTR_AWCACHE_MODE);
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, val);
> +
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + return 0;
> +}
> +
> +static const struct dw_pcie_host_ops k3_pcie_host_ops = {
> + .init = k3_pcie_init,
> + .deinit = k1_pcie_deinit,
> + .msi_init = k3_pcie_msi_host_init,
> +};
> +
> +static const struct dw_pcie_ops k3_pcie_ops = {
This is identical to k1_pcie_ops, so isn't needed.
> + .link_up = k1_pcie_link_up,
> + .start_link = k1_pcie_start_link,
> + .stop_link = k1_pcie_stop_link,
> +};
> +
> +static void k3_pcie_clear_irq_status(struct k1_pcie *k1,
> + u32 *status0, u32 *status1, u32 *status2)
I don't see any value in this helper function, at
least not based on how it's used now. It is used
exactly once, to clear (by writing) three interrupt
status registers. Just do that inline.
Even if you want to use this helper function in a
second place (when handling the itnerrupt), don't
pass in these status arguments, they're not needed
in the caller. Just define them here.
Also you could read/write each register, and use
a single local variable (status) to hold the value
read and written.
> +{
> + *status0 = readl_relaxed(k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> + *status1 = readl_relaxed(k1->link + INTR_STATUS);
> + *status2 = readl_relaxed(k1->link + K3_ADDR_INTR_STATUS1);
> +
> + writel_relaxed(*status0, k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> + writel_relaxed(*status1, k1->link + INTR_STATUS);
> + writel_relaxed(*status2, k1->link + K3_ADDR_INTR_STATUS1);
> +}
> +
> +static int k3_pcie_parse_port(struct k1_pcie *k1)
> +{
> + u32 status0, status1, status2;
> +
> + k3_pcie_clear_irq_status(k1, &status0, &status1, &status2);
Is it really necessary to clear the IRQ status *only* for K3?
It seems like it would be a good idea (or at least harmless)
to do it for K1 as well. And in that case, it should just be
added to the existing k1_pcie_parse_port() function.
> +
> + return k1_pcie_parse_port(k1);
> +}
> +
> static int k1_pcie_probe(struct platform_device *pdev)
> {
> const struct k1_pcie_device_data *data;
> @@ -417,8 +534,17 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
> .device_id = PCI_DEVICE_ID_SPACEMIT_K1,
> };
>
> +static const struct k1_pcie_device_data k3_pcie_device_data = {
> + .host_ops = &k3_pcie_host_ops,
> + .ops = &k3_pcie_ops,
I think ops could just point to k1_pcie_ops here.
-Alex
> + .parse_port = k3_pcie_parse_port,
> + .max_phy_count = 6,
> + .device_id = PCI_DEVICE_ID_SPACEMIT_K3,
> +};
> +
> static const struct of_device_id k1_pcie_of_match_table[] = {
> { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
> + { .compatible = "spacemit,k3-pcie", .data = &k3_pcie_device_data},
> { }
> };
>
prev parent reply other threads:[~2026-07-10 16:01 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
2026-07-09 4:00 ` [PATCH v4 1/6] PCI: spacemit-k1: Add device data support Inochi Amaoto
2026-07-09 4:05 ` sashiko-bot
2026-07-09 7:09 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support Inochi Amaoto
2026-07-09 4:09 ` sashiko-bot
2026-07-09 7:16 ` Andy Shevchenko
2026-07-10 1:57 ` Inochi Amaoto
2026-07-10 8:07 ` Andy Shevchenko
2026-07-10 10:55 ` Inochi Amaoto
2026-07-10 12:42 ` Alex Elder
2026-07-11 13:01 ` Andy Shevchenko
2026-07-11 12:44 ` Andy Shevchenko
2026-07-10 12:51 ` Alex Elder
2026-07-11 13:04 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 3/6] PCI: spacemit-k1: Add device id update helper Inochi Amaoto
2026-07-09 4:06 ` sashiko-bot
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 4/6] dt-bindings: PCI: snps,dw-pcie: Add msi-parent for MSI handle check Inochi Amaoto
2026-07-09 4:06 ` sashiko-bot
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 5/6] dt-bindings: PCI: spacemit: Introduce Spacemit K3 PCIe host controller Inochi Amaoto
2026-07-09 4:09 ` sashiko-bot
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support Inochi Amaoto
2026-07-09 4:12 ` sashiko-bot
2026-07-09 7:21 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=900e6239-bc00-46b6-aa9f-abe219c039d2@riscstar.com \
--to=elder@riscstar.com \
--cc=Frank.Li@nxp.com \
--cc=alex@ghiti.fr \
--cc=andriy.shevchenko@linux.intel.com \
--cc=aou@eecs.berkeley.edu \
--cc=bhelgaas@google.com \
--cc=christian.bruel@foss.st.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlan@gentoo.org \
--cc=dlan@kernel.org \
--cc=gustavo.pimentel@synopsys.com \
--cc=inochiama@gmail.com \
--cc=jingoohan1@gmail.com \
--cc=krishna.chundru@oss.qualcomm.com \
--cc=krzk+dt@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=looong.bin@gmail.com \
--cc=lpieralisi@kernel.org \
--cc=mani@kernel.org \
--cc=namcao@linutronix.de \
--cc=neil.armstrong@linaro.org \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=qiang.yu@oss.qualcomm.com \
--cc=robh@kernel.org \
--cc=s-vadapalli@ti.com \
--cc=spacemit@lists.linux.dev \
--cc=vidyas@nvidia.com \
--cc=zhangxincheng@ultrarisc.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox