* [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC
@ 2026-09-13 4:23 Eric Chung
2026-09-13 4:23 ` [PATCH v2 1/4] phy: spacemit: add K1 PCIe/USB3 combo PHY driver Eric Chung
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Eric Chung @ 2026-09-13 4:23 UTC (permalink / raw)
To: u-boot-spacemit, u-boot, u-boot
Cc: Tom Rini, Tim Ouyang, Leo Liang, Scott Bambrough, Eric Chung,
Neil Armstrong, David Lechner, Julien Stephan, Johan Jonker,
Siu Ming Tong, Lucien.Jheng, Huan Zhou, Michal Simek,
Pranav Sanwal, Raymond Mao, Yixun Lan
Signed-off-by: Eric Chung <eric.chung@riscstar.com>
---
Changes in v2:
- dts: Rebase on upstream DTS. So drop the changes in overlay DTS.
- pci: Find the phy by index instead.
- maintainer: Add the driver in the Spacemit MAINTAINER entry.
- Link to v1: https://patch.msgid.link/20260705-pci-v1-0-beca83440a27@riscstar.com
To: u-boot@lists.u-boot-project.org
To: u-boot-spacemit@groups.io
Cc: Tom Rini <trini@konsulko.com>
Cc: Neil Armstrong <neil.armstrong@linaro.org>
Cc: David Lechner <dlechner@baylibre.com>
Cc: Julien Stephan <jstephan@baylibre.com>
Cc: Johan Jonker <jbx6244@gmail.com>
Cc: Siu Ming Tong <smtong@axiado.com>
Cc: "Lucien.Jheng" <lucienzx159@gmail.com>
Cc: Eric Chung <eric.chung@riscstar.com>
Cc: Huan Zhou <pericycle.cc@gmail.com>
Cc: Michal Simek <michal.simek@amd.com>
Cc: Pranav Sanwal <pranav.sanwal@amd.com>
Cc: Raymond Mao <raymond.mao@riscstar.com>
Cc: Yixun Lan <dlan@gentoo.org>
---
Eric Chung (4):
phy: spacemit: add K1 PCIe/USB3 combo PHY driver
pci: spacemit: add DesignWare PCIe host controller driver
configs: k1: enable PCIe and NVMe support
MAINTAINER: add K1 PCIe driver to Spacemit entry
board/spacemit/k1/MAINTAINERS | 1 +
configs/spacemit_k1_defconfig | 10 +
drivers/pci/Kconfig | 7 +
drivers/pci/Makefile | 1 +
drivers/pci/pcie_dw_spacemit.c | 391 +++++++++++++++++++++++++++++
drivers/pci/pcie_dw_spacemit.h | 78 ++++++
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 1 +
drivers/phy/spacemit/Kconfig | 11 +
drivers/phy/spacemit/Makefile | 1 +
drivers/phy/spacemit/phy-k1-pcie.c | 492 +++++++++++++++++++++++++++++++++++++
11 files changed, 994 insertions(+)
---
base-commit: b739fb09a011558396287e077108d2e5379069c1
change-id: 20260705-pci-38358b570d03
Best regards,
--
Eric Chung <eric.chung@riscstar.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/4] phy: spacemit: add K1 PCIe/USB3 combo PHY driver
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
@ 2026-09-13 4:23 ` Eric Chung
2026-09-13 4:23 ` [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver Eric Chung
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eric Chung @ 2026-09-13 4:23 UTC (permalink / raw)
To: u-boot-spacemit, u-boot, u-boot
Cc: Tom Rini, Tim Ouyang, Leo Liang, Scott Bambrough, Eric Chung,
Neil Armstrong, David Lechner, Julien Stephan, Johan Jonker,
Siu Ming Tong, Lucien.Jheng, Huan Zhou, Michal Simek,
Pranav Sanwal, Raymond Mao, Yixun Lan
Add PHY driver for Spacemit K1 SoC supporting:
- Combo PHY (PCIe/USB3) with auto-calibration of RX/TX termination
- PCIe-only PHY (2 lanes) using combo PHY calibration values
The combo PHY calibrates at probe time, and the result is shared
globally so PCIe-only PHYs can apply the same termination settings.
Signed-off-by: Eric Chung <eric.chung@riscstar.com>
---
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 1 +
drivers/phy/spacemit/Kconfig | 11 +
drivers/phy/spacemit/Makefile | 1 +
drivers/phy/spacemit/phy-k1-pcie.c | 492 +++++++++++++++++++++++++++++++++++++
5 files changed, 506 insertions(+)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 6262380a60a0..6c5816e67a78 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -369,6 +369,7 @@ source "drivers/phy/ti/Kconfig"
source "drivers/phy/qcom/Kconfig"
source "drivers/phy/renesas/Kconfig"
source "drivers/phy/starfive/Kconfig"
+source "drivers/phy/spacemit/Kconfig"
config PHY_COMMON_PROPS
bool "Common PHY properties support"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 19cf95759e57..3256e8bad8d6 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -51,3 +51,4 @@ obj-y += ti/
obj-y += qcom/
obj-y += renesas/
obj-y += starfive/
+obj-y += spacemit/
diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
new file mode 100644
index 000000000000..3c47601c1fd4
--- /dev/null
+++ b/drivers/phy/spacemit/Kconfig
@@ -0,0 +1,11 @@
+config PHY_SPACEMIT_K1_PCIE
+ bool "Spacemit K1 PCIe PHY driver"
+ depends on PHY
+ help
+ Support for the Spacemit K1 SoC PCIe and Combo (PCIe/USB3) PHYs.
+
+ This driver handles both the combo PHY used for port A (which
+ calibrates RX/TX termination values) and the PCIe-only PHYs for
+ ports B and C. The combo PHY must be enabled even if port A
+ is not used for PCIe, because it provides calibration values
+ required by the other ports.
diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
new file mode 100644
index 000000000000..3496c099cdf3
--- /dev/null
+++ b/drivers/phy/spacemit/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-k1-pcie.o
diff --git a/drivers/phy/spacemit/phy-k1-pcie.c b/drivers/phy/spacemit/phy-k1-pcie.c
new file mode 100644
index 000000000000..e54742a2a9c2
--- /dev/null
+++ b/drivers/phy/spacemit/phy-k1-pcie.c
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Spacemit K1 PCIe and PCIe/USB 3 combo PHY driver
+ *
+ * Copyright (C) 2026 RISCstar Ltd. All rights reserved.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/ofnode.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <reset.h>
+
+#include <dt-bindings/phy/phy.h>
+
+/*
+ * Three PCIe ports are supported in the SpacemiT K1 SoC.
+ *
+ * Port A (combo PHY): 1 lane, can switch between PCIe and USB 3.
+ * The only PHY that can auto-calibrate RX/TX termination.
+ * Port B (pcie-phy): 2 lanes, PCIe only.
+ * Port C (pcie-phy): 2 lanes, PCIe only.
+ *
+ * Calibration values from port A are used to configure ports B and C.
+ * Port B/C must not probe until port A has completed calibration.
+ */
+
+/* Offset between lane 0 and lane 1 registers */
+#define PHY_LANE_OFFSET 0x0400
+
+/* PHY PLL configuration */
+#define PCIE_PU_ADDR_CLK_CFG 0x0008
+#define PLL_READY BIT(0)
+#define CFG_INTERNAL_TIMER_ADJ GENMASK(10, 7)
+#define TIMER_ADJ_PCIE 0x6
+#define CFG_SW_PHY_INIT_DONE BIT(11)
+
+#define PCIE_RC_DONE_STATUS 0x0018
+#define CFG_FORCE_RCV_RETRY BIT(10)
+
+/* PCIe PHY lane calibration */
+#define PCIE_RC_CAL_REG2 0x0020
+#define RC_CAL_TOGGLE BIT(22)
+#define CLKSEL GENMASK(31, 29)
+#define CLKSEL_24M 0x3
+
+/* Additional PHY PLL configuration */
+#define PCIE_PU_PLL_1 0x0048
+#define REF_100_WSSC BIT(12)
+#define FREF_SEL GENMASK(15, 13)
+#define FREF_24M 0x1
+#define SSC_DEP_SEL GENMASK(19, 16)
+#define SSC_DEP_NONE 0x0
+
+/* PCIe PHY configuration */
+#define PCIE_PU_PLL_2 0x004c
+#define GEN_REF100 BIT(4)
+
+#define PCIE_RX_REG1 0x0050
+#define EN_RTERM BIT(3)
+#define AFE_RTERM_REG GENMASK(11, 8)
+
+#define PCIE_RX_REG2 0x0054
+#define RX_RTERM_SEL BIT(5)
+
+#define PCIE_LTSSM_DIS_ENTRY 0x005c
+#define CFG_REFCLK_MODE GENMASK(9, 8)
+#define RFCLK_MODE_DRIVER 0x1
+#define RFCLK_MODE_RECEIVER 0x2
+#define OVRD_REFCLK_MODE BIT(10)
+
+#define PCIE_TX_REG1 0x0064
+#define TX_RTERM_REG GENMASK(15, 12)
+#define TX_RTERM_SEL BIT(25)
+
+/* PHY calibration values */
+#define PCIE_RCAL_RESULT 0x0084
+#define RTERM_VALUE_RX GENMASK(3, 0)
+#define RTERM_VALUE_TX GENMASK(7, 4)
+#define R_TUNE_DONE BIT(10)
+
+/* PMU register offsets (shared APMU space) */
+#define PMUA_USB_PHY_CTRL0 0x0110
+#define COMBO_PHY_SEL BIT(3) /* 0: PCIe; 1: USB 3 */
+#define PCIE_CLK_RES_CTRL 0x03cc
+#define PCIE_APP_HOLD_PHY_RST BIT(30)
+#define DEVICE_TYPE_RC BIT(31)
+#define GLOBAL_PHY_RST BIT(8)
+
+#define APMU_CLK_GATE_MASK 0x3f
+
+#define CALIBRATION_TIMEOUT_US 500000
+#define PLL_TIMEOUT_US 500000
+
+/* Global calibration value shared across PHY ports */
+static u32 k1_phy_rterm = ~0;
+
+struct k1_pcie_phy {
+ void __iomem *regs;
+ void __iomem *apmu_base; /* only for combo PHY */
+ u32 pcie_lanes;
+ bool is_combo;
+ struct clk_bulk clks;
+ struct reset_ctl_bulk rst;
+};
+
+static bool k1_phy_rterm_valid(void)
+{
+ return !(k1_phy_rterm & ~(RTERM_VALUE_RX | RTERM_VALUE_TX));
+}
+
+u32 k1_phy_rterm_rx(void)
+{
+ return FIELD_GET(RTERM_VALUE_RX, k1_phy_rterm);
+}
+
+u32 k1_phy_rterm_tx(void)
+{
+ return FIELD_GET(RTERM_VALUE_TX, k1_phy_rterm);
+}
+
+static void k1_phy_rterm_set(u32 val)
+{
+ k1_phy_rterm = val & (RTERM_VALUE_RX | RTERM_VALUE_TX);
+}
+
+static void k1_combo_phy_sel(struct k1_pcie_phy *k1_phy, bool usb)
+{
+ void __iomem *pmu = k1_phy->apmu_base;
+ u32 val;
+
+ val = readl(pmu + PMUA_USB_PHY_CTRL0);
+ if (usb)
+ val |= COMBO_PHY_SEL;
+ else
+ val &= ~COMBO_PHY_SEL;
+ writel(val, pmu + PMUA_USB_PHY_CTRL0);
+}
+
+int k1_pcie_combo_phy_calibrate(struct udevice *dev, struct k1_pcie_phy *k1_phy)
+{
+ void __iomem *regs = k1_phy->regs;
+ int ret = 0;
+ u32 val;
+
+ if (k1_phy_rterm_valid())
+ return 0;
+
+ /*
+ * Initialize the APMU control register: set RC mode, enable
+ * clock gates (bits 0-5), deassert PHY global reset, then
+ * release the PHY hold. Without this the PHY registers are
+ * not accessible and reads will hang.
+ */
+ val = readl(k1_phy->apmu_base + PCIE_CLK_RES_CTRL);
+ val |= DEVICE_TYPE_RC | PCIE_APP_HOLD_PHY_RST | APMU_CLK_GATE_MASK;
+ val &= ~GLOBAL_PHY_RST;
+ writel(val, k1_phy->apmu_base + PCIE_CLK_RES_CTRL);
+ val &= ~PCIE_APP_HOLD_PHY_RST;
+ writel(val, k1_phy->apmu_base + PCIE_CLK_RES_CTRL);
+
+ /* Put the combo PHY into PCIe mode for calibration */
+ k1_combo_phy_sel(k1_phy, false);
+
+ /* Set refclk override + clear CFG_REFCLK_MODE */
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ val |= OVRD_REFCLK_MODE;
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ val &= ~CFG_REFCLK_MODE;
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ val |= FIELD_PREP(CFG_REFCLK_MODE, RFCLK_MODE_DRIVER);
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ /* Configure PLL: select 24MHz reference, enable 100MHz output */
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~(FREF_SEL | REF_100_WSSC);
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ val = readl(regs + PCIE_PU_PLL_1);
+ val |= FIELD_PREP(FREF_SEL, FREF_24M);
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ val = readl(regs + PCIE_PU_PLL_2);
+ val |= GEN_REF100;
+ writel(val, regs + PCIE_PU_PLL_2);
+
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~SSC_DEP_SEL;
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ /* Start PHY init + force receiver */
+ writel(0x00000B78, regs + PCIE_PU_ADDR_CLK_CFG);
+ writel(CFG_FORCE_RCV_RETRY, regs + PCIE_RC_DONE_STATUS);
+
+ /* Wait for calibration to complete */
+ ret = readl_poll_sleep_timeout(regs + PCIE_RCAL_RESULT,
+ val, val & R_TUNE_DONE,
+ 500, CALIBRATION_TIMEOUT_US);
+ if (ret)
+ dev_err(dev, "PHY calib timeout, RCAL=0x%08x\n", val);
+
+ if (!ret)
+ k1_phy_rterm_set(val);
+
+ return ret;
+}
+
+static int k1_pcie_phy_init(struct phy *phy)
+{
+ struct k1_pcie_phy *k1_phy = dev_get_priv(phy->dev);
+ void __iomem *regs = k1_phy->regs;
+ int ret;
+ u32 val;
+ int i, lane;
+
+ /* If combo PHY is configured for USB 3 mode */
+ if (k1_phy->is_combo && phy->id == PHY_TYPE_USB3) {
+ k1_combo_phy_sel(k1_phy, true);
+ return 0;
+ }
+
+ /* For combo PHY, ensure it's in PCIe mode */
+ if (k1_phy->is_combo)
+ k1_combo_phy_sel(k1_phy, false);
+
+ dev_dbg(phy->dev, "init: combo=%d lanes=%u rterm=0x%02x\n",
+ k1_phy->is_combo, k1_phy->pcie_lanes, k1_phy_rterm);
+
+ lane = (k1_phy->pcie_lanes == 1) ? 1 : 2;
+
+ /* Apply rterm calibration value: LSB to RX_REG1 */
+ for (i = 0; i < lane; i++) {
+ val = readl(regs + PCIE_RX_REG1 + PHY_LANE_OFFSET * i);
+ val |= FIELD_PREP(AFE_RTERM_REG, k1_phy_rterm_rx());
+ writel(val, regs + PCIE_RX_REG1 + PHY_LANE_OFFSET * i);
+ }
+
+ /* Disable RX_RTERM_SEL for all lanes */
+ for (i = 0; i < lane; i++) {
+ val = readl(regs + PCIE_RX_REG2 + PHY_LANE_OFFSET * i);
+ val &= ~RX_RTERM_SEL;
+ writel(val, regs + PCIE_RX_REG2 + PHY_LANE_OFFSET * i);
+ }
+
+ /* Apply rterm MSB to TX_REG1 */
+ for (i = 0; i < lane; i++) {
+ val = readl(regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
+ val |= FIELD_PREP(TX_RTERM_REG, k1_phy_rterm_tx());
+ writel(val, regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
+ }
+
+ /* Enable TX_RTERM_SEL for all lanes */
+ for (i = 0; i < lane; i++) {
+ val = readl(regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
+ val |= TX_RTERM_SEL;
+ writel(val, regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
+ }
+
+ /* Set CLKSEL_24M on lane0 */
+ val = readl(regs + PCIE_RC_CAL_REG2);
+ val |= FIELD_PREP(CLKSEL, CLKSEL_24M);
+ writel(val, regs + PCIE_RC_CAL_REG2);
+
+ /* Toggle RC_CAL_TOGGLE for all lanes */
+ for (i = 0; i < lane; i++) {
+ val = readl(regs + PCIE_RC_CAL_REG2 + PHY_LANE_OFFSET * i);
+ val &= ~RC_CAL_TOGGLE;
+ writel(val, regs + PCIE_RC_CAL_REG2 + PHY_LANE_OFFSET * i);
+ }
+ for (i = 0; i < lane; i++) {
+ val = readl(regs + PCIE_RC_CAL_REG2 + PHY_LANE_OFFSET * i);
+ val |= RC_CAL_TOGGLE;
+ writel(val, regs + PCIE_RC_CAL_REG2 + PHY_LANE_OFFSET * i);
+ }
+
+ /* Configure refclk as driver mode, override */
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ val |= OVRD_REFCLK_MODE;
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ val &= ~CFG_REFCLK_MODE;
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ val = readl(regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
+ val |= OVRD_REFCLK_MODE;
+ writel(val, regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
+
+ val = readl(regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
+ val &= ~CFG_REFCLK_MODE;
+ writel(val, regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
+
+ /* Set driver mode for both lanes */
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ val |= FIELD_PREP(CFG_REFCLK_MODE, RFCLK_MODE_DRIVER);
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ val = readl(regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
+ val |= FIELD_PREP(CFG_REFCLK_MODE, RFCLK_MODE_DRIVER);
+ writel(val, regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
+
+ /* Configure PLL: select 24MHz reference */
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~FREF_SEL;
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ val = readl(regs + PCIE_PU_PLL_1);
+ val |= FIELD_PREP(FREF_SEL, FREF_24M);
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ /* Enable 100MHz reference output */
+ val = readl(regs + PCIE_PU_PLL_2);
+ val |= GEN_REF100;
+ writel(val, regs + PCIE_PU_PLL_2);
+
+ /* Disable SSC */
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~SSC_DEP_SEL;
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ /* Set PU_ADDR_CLK_CFG for both lanes */
+ val = 0x00000B78;
+ writel(val, regs + PCIE_PU_ADDR_CLK_CFG);
+ writel(val, regs + PHY_LANE_OFFSET + PCIE_PU_ADDR_CLK_CFG);
+
+ /* Force receiver done */
+ val = CFG_FORCE_RCV_RETRY;
+ writel(val, regs + PCIE_RC_DONE_STATUS);
+
+ /* Wait for PLL lock */
+ ret = readl_poll_timeout(regs + PCIE_PU_ADDR_CLK_CFG, val,
+ val & PLL_READY, PLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(phy->dev, "PLL lock timeout! reg[0x08]=0x%08x\n", val);
+ return ret;
+ }
+
+ dev_dbg(phy->dev, "PLL locked (combo=%d, lanes=%d)\n",
+ k1_phy->is_combo, k1_phy->pcie_lanes);
+
+ return 0;
+}
+
+static int k1_pcie_phy_exit(struct phy *phy)
+{
+ return 0;
+}
+
+static int k1_pcie_phy_of_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ struct k1_pcie_phy *k1_phy = dev_get_priv(phy->dev);
+
+ if (k1_phy->is_combo) {
+ if (args->args_count != 1)
+ return -EINVAL;
+ if (args->args[0] != PHY_TYPE_PCIE &&
+ args->args[0] != PHY_TYPE_USB3)
+ return -EINVAL;
+ }
+
+ if (args->args_count > 0)
+ phy->id = args->args[0];
+ else
+ phy->id = 0;
+
+ return 0;
+}
+
+static const struct phy_ops k1_pcie_phy_ops = {
+ .of_xlate = k1_pcie_phy_of_xlate,
+ .init = k1_pcie_phy_init,
+ .exit = k1_pcie_phy_exit,
+};
+
+static int k1_pcie_phy_probe(struct udevice *dev)
+{
+ struct k1_pcie_phy *k1_phy = dev_get_priv(dev);
+ struct ofnode_phandle_args apmu_args;
+ bool is_combo;
+ int ret;
+ u32 lanes;
+
+ is_combo = (bool)dev_get_driver_data(dev);
+ k1_phy->is_combo = is_combo;
+
+ k1_phy->regs = dev_read_addr_ptr(dev);
+ if (!k1_phy->regs)
+ return -EINVAL;
+
+ /* Determine number of lanes */
+ if (is_combo) {
+ lanes = 1;
+ } else {
+ u32 count = 0;
+
+ ret = dev_read_u32(dev, "num-lanes", &count);
+ if (ret == 0 && count == 1)
+ lanes = 1;
+ else
+ lanes = 2;
+ }
+ k1_phy->pcie_lanes = lanes;
+
+ /* Get APMU base for combo PHY (for mode select + calibration) */
+ if (is_combo) {
+ ret = dev_read_phandle_with_args(dev, "spacemit,apmu",
+ NULL, 0, 0,
+ &apmu_args);
+ if (ret)
+ return ret;
+
+ k1_phy->apmu_base = (void __iomem *)ofnode_get_addr(apmu_args.node);
+ if (!k1_phy->apmu_base)
+ return -EINVAL;
+
+ ret = clk_get_bulk(dev, &k1_phy->clks);
+ if (ret)
+ dev_warn(dev, "failed to get clocks: %d\n", ret);
+
+ ret = reset_get_bulk(dev, &k1_phy->rst);
+ if (ret)
+ dev_warn(dev, "failed to get resets: %d\n", ret);
+
+ ret = k1_pcie_combo_phy_calibrate(dev, k1_phy);
+ if (ret)
+ dev_warn(dev, "calibration failed: %d\n", ret);
+ } else {
+ /*
+ * PCIe-only PHYs need the calibration value from the
+ * combo PHY. In device-tree order the combo PHY probes
+ * first, but handle the case where it hasn't yet by
+ * explicitly looking it up.
+ */
+ if (!k1_phy_rterm_valid()) {
+ struct udevice *combo_dev;
+
+ ret = uclass_first_device_drvdata(UCLASS_PHY, 1UL,
+ &combo_dev);
+ if (ret)
+ dev_warn(dev,
+ "failed to probe combo PHY: %d\n",
+ ret);
+ }
+
+ if (!k1_phy_rterm_valid()) {
+ dev_err(dev,
+ "calibration value not available; "
+ "is the combo PHY enabled?\n");
+ return -ENOENT;
+ }
+
+ ret = clk_get_bulk(dev, &k1_phy->clks);
+ if (ret)
+ dev_warn(dev, "failed to get clocks: %d\n", ret);
+
+ ret = reset_get_bulk(dev, &k1_phy->rst);
+ if (ret)
+ dev_warn(dev, "failed to get resets: %d\n", ret);
+ }
+
+ dev_dbg(dev, "probed (combo=%d lanes=%u rterm=0x%02x)\n",
+ is_combo, lanes, k1_phy_rterm);
+
+ return 0;
+}
+
+static const struct udevice_id k1_pcie_phy_ids[] = {
+ { .compatible = "spacemit,k1-combo-phy", .data = 1UL },
+ { .compatible = "spacemit,k1-pcie-phy", .data = 0UL },
+ { }
+};
+
+U_BOOT_DRIVER(k1_pcie_phy) = {
+ .name = "k1_pcie_phy",
+ .id = UCLASS_PHY,
+ .of_match = k1_pcie_phy_ids,
+ .ops = &k1_pcie_phy_ops,
+ .probe = k1_pcie_phy_probe,
+ .priv_auto = sizeof(struct k1_pcie_phy),
+};
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
2026-09-13 4:23 ` [PATCH v2 1/4] phy: spacemit: add K1 PCIe/USB3 combo PHY driver Eric Chung
@ 2026-09-13 4:23 ` Eric Chung
2026-09-23 13:30 ` Yixun Lan
2026-09-13 4:23 ` [PATCH v2 3/4] configs: k1: enable PCIe and NVMe support Eric Chung
` (3 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Eric Chung @ 2026-09-13 4:23 UTC (permalink / raw)
To: u-boot-spacemit, u-boot, u-boot
Cc: Tom Rini, Tim Ouyang, Leo Liang, Scott Bambrough, Eric Chung,
Neil Armstrong, David Lechner, Julien Stephan, Johan Jonker,
Siu Ming Tong, Lucien.Jheng, Huan Zhou, Michal Simek,
Pranav Sanwal, Raymond Mao, Yixun Lan
Add PCIe host controller driver for Spacemit K1 SoC using the
Synopsys DesignWare PCIe core. Supports up to 3 ports.
Signed-off-by: Eric Chung <eric.chung@riscstar.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
---
v2:
- Locate the phy by index instead.
---
drivers/pci/Kconfig | 7 +
drivers/pci/Makefile | 1 +
drivers/pci/pcie_dw_spacemit.c | 391 +++++++++++++++++++++++++++++++++++++++++
drivers/pci/pcie_dw_spacemit.h | 78 ++++++++
4 files changed, 477 insertions(+)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 42edc73bcdaa..86fafc5a3c73 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -498,4 +498,11 @@ config PCIE_DW_IMX
Say Y here if you want to enable DW PCIe controller support on
iMX SoCs.
+config PCIE_DW_SPACEMIT
+ bool "Enable Spacemit K1 PCIe"
+ select PCIE_DW_COMMON
+ help
+ Say Y here if you want to enable PCIe controller support on
+ K1 SoC.
+
endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 3873f357a45f..f839ea1d396f 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -60,3 +60,4 @@ obj-$(CONFIG_PCIE_PLDA_COMMON) += pcie_plda_common.o
obj-$(CONFIG_PCIE_STARFIVE_JH7110) += pcie_starfive_jh7110.o
obj-$(CONFIG_PCIE_DW_AMD) += pcie_dw_amd.o
obj-$(CONFIG_PCIE_DW_IMX) += pcie_dw_imx.o
+obj-$(CONFIG_PCIE_DW_SPACEMIT) += pcie_dw_spacemit.o
diff --git a/drivers/pci/pcie_dw_spacemit.c b/drivers/pci/pcie_dw_spacemit.c
new file mode 100644
index 000000000000..09c56d8a4c4a
--- /dev/null
+++ b/drivers/pci/pcie_dw_spacemit.c
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Spacemit K1 PCIe host controller driver
+ *
+ * Copyright (c) 2023, Spacemit Corporation.
+ * Copyright (c) 2026, RISCstar Ltd.
+ *
+ */
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/ofnode.h>
+#include <dm/read.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <log.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
+
+#include "pcie_dw_common.h"
+#include "pcie_dw_spacemit.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pcie_dw_spacemit {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
+ void __iomem *apmu_base;
+ u32 apmu_offset;
+ void __iomem *phy_ahb; /* DT "link" */
+ int port_id;
+
+ /* reset, clock resources */
+ struct clk_bulk clks;
+ struct reset_ctl_bulk rsts;
+ struct gpio_desc pwr_on_gpio;
+ int power_on_status;
+};
+
+static inline u32 spacemit_pcie_readl(struct pcie_dw_spacemit *pcie, u32 offset)
+{
+ return readl(pcie->apmu_base + pcie->apmu_offset + offset);
+}
+
+static inline void spacemit_pcie_writel(struct pcie_dw_spacemit *pcie,
+ u32 offset, u32 value)
+{
+ writel(value, pcie->apmu_base + pcie->apmu_offset + offset);
+}
+
+static inline u32 spacemit_pcie_phy_ahb_readl(struct pcie_dw_spacemit *pcie, u32 offset)
+{
+ return readl(pcie->phy_ahb + offset);
+}
+
+static void pcie_dw_configure(struct pcie_dw_spacemit *pci, u32 cap_speed)
+{
+ u32 val;
+
+ dw_pcie_dbi_write_enable(&pci->dw, true);
+
+ val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
+ val &= ~TARGET_LINK_SPEED_MASK;
+ val |= cap_speed;
+ writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
+
+ val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2);
+ val &= ~TARGET_LINK_SPEED_MASK;
+ val |= cap_speed;
+ writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2);
+
+ dw_pcie_dbi_write_enable(&pci->dw, false);
+}
+
+static int is_link_up(struct pcie_dw_spacemit *pci)
+{
+ u32 val;
+
+ val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0);
+ val &= PORT_LOGIC_LTSSM_STATE_MASK;
+
+ return (val == PORT_LOGIC_LTSSM_STATE_L0);
+}
+
+static int wait_link_up(struct pcie_dw_spacemit *pci)
+{
+ unsigned long timeout;
+
+ timeout = get_timer(0) + PCIE_LINK_UP_TIMEOUT_MS;
+ while (!is_link_up(pci)) {
+ if (get_timer(0) > timeout) {
+ dev_dbg(pci->dw.dev, "LTSSM link training timeout\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int pcie_dw_spacemit_pcie_link_up(struct pcie_dw_spacemit *pci, u32 cap_speed)
+{
+ u32 reg;
+
+ if (is_link_up(pci)) {
+ printf("PCI Link already up before configuration!\n");
+ return 1;
+ }
+
+ /* DW pre link configurations */
+ pcie_dw_configure(pci, cap_speed);
+
+ /* Initiate link training */
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg |= LTSSM_EN;
+ reg &= ~APP_HOLD_PHY_RST;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+ /* Check that link was established */
+ if (!wait_link_up(pci))
+ return 0;
+
+ /*
+ * Link can be established in Gen 1, still need to wait
+ * until MAC negotiation is completed
+ */
+ udelay(100);
+
+ return 1;
+}
+
+static int pcie_set_mode(struct pcie_dw_spacemit *pci,
+ enum dw_pcie_device_mode mode)
+{
+ u32 reg;
+
+ switch (mode) {
+ case DW_PCIE_RC_TYPE:
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg |= DEVICE_TYPE_RC | PCIE_AUX_PWR_DET;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+ reg = spacemit_pcie_readl(pci, PCIE_CTRL_LOGIC);
+ reg |= PCIE_IGNORE_PERSTN;
+ spacemit_pcie_writel(pci, PCIE_CTRL_LOGIC, reg);
+ break;
+ case DW_PCIE_EP_TYPE:
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg &= ~DEVICE_TYPE_RC;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+ break;
+ default:
+ dev_err(pci->dw.dev, "INVALID device type %d\n", mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spacemit_pcie_host_init(struct pcie_dw_spacemit *pci)
+{
+ u32 reg;
+
+ mdelay(100);
+ /* set Perst# gpio high state*/
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg &= ~PCIE_RC_PERST;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+ return 0;
+}
+
+static int pcie_dw_init_id(struct pcie_dw_spacemit *pci)
+{
+ dw_pcie_dbi_write_enable(&pci->dw, true);
+ writew(SPACEMIT_PCIE_VENDOR_ID, pci->dw.dbi_base + PCI_VENDOR_ID);
+ writew(SPACEMIT_PCIE_DEVICE_ID, pci->dw.dbi_base + PCI_DEVICE_ID);
+ dw_pcie_dbi_write_enable(&pci->dw, false);
+
+ return 0;
+}
+
+static int k1x_power_on(struct pcie_dw_spacemit *pci, int on)
+{
+ struct pcie_dw *dwp = &pci->dw;
+ int gpio_val = 0;
+
+ if (on) {
+ if (pci->power_on_status)
+ gpio_val = 1;
+ else
+ gpio_val = 0;
+ } else {
+ if (pci->power_on_status)
+ gpio_val = 0;
+ else
+ gpio_val = 1;
+ }
+
+ if (dm_gpio_is_valid(&pci->pwr_on_gpio)) {
+ dev_info(dwp->dev, "PCIe interface power %s, set gpio %d to %d\n",
+ on ? "on" : "off", pci->pwr_on_gpio.offset, gpio_val);
+ dm_gpio_set_value(&pci->pwr_on_gpio, gpio_val);
+ }
+
+ return 0;
+}
+
+static int pcie_dw_spacemit_probe(struct udevice *dev)
+{
+ struct pcie_dw_spacemit *pci = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ struct phy phy0 = {0};
+ ofnode port;
+ int ret;
+ u32 reg;
+
+ /* enable pcie clk and deassert resets */
+ clk_enable_bulk(&pci->clks);
+ reset_deassert_bulk(&pci->rsts);
+
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg &= ~LTSSM_EN;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+ /* set Perst# (fundamental reset) gpio low state*/
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg |= PCIE_RC_PERST;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+ /* The PHY is described on the root port child node */
+ port = ofnode_first_subnode(dev_ofnode(dev));
+ if (!ofnode_valid(port)) {
+ dev_err(dev, "failed to find PCIe port node\n");
+ return -ENODEV;
+ }
+
+ ret = generic_phy_get_by_index_nodev(port, 0, &phy0);
+ if (!ret) {
+ reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+ reg |= DEVICE_TYPE_RC | APP_HOLD_PHY_RST | PCIE_PHY_LANE_CTRL_MASK;
+ reg &= ~GLOBAL_PHY_RST;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+ reg &= ~(u32)APP_HOLD_PHY_RST;
+ spacemit_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+ ret = generic_phy_init(&phy0);
+ if (ret) {
+ dev_err(dev, "failed to init PHY: %d\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&phy0);
+ if (ret) {
+ dev_err(dev, "failed to power on PHY: %d\n", ret);
+ return ret;
+ }
+ } else {
+ dev_err(dev, "failed to get pcie-phy: %d\n", ret);
+ return ret;
+ }
+
+ pci->dw.first_busno = dev_seq(dev);
+ pci->dw.dev = dev;
+
+ pcie_set_mode(pci, DW_PCIE_RC_TYPE);
+
+ /* power on the interface */
+ k1x_power_on(pci, 1);
+
+ spacemit_pcie_host_init(pci);
+ pcie_dw_setup_host(&pci->dw);
+ pcie_dw_init_id(pci);
+
+ if (!pcie_dw_spacemit_pcie_link_up(pci, LINK_SPEED_GEN_1)) {
+ printf("PCIE-%d: Link down\n", dev_seq(dev));
+ return -ENODEV;
+ }
+
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
+ pcie_dw_get_link_speed(&pci->dw),
+ pcie_dw_get_link_width(&pci->dw),
+ hose->first_busno);
+
+ ret = pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ pci->dw.mem.phys_start,
+ pci->dw.mem.bus_start,
+ pci->dw.mem.size);
+
+ return 0;
+}
+
+static int pcie_dw_spacemit_of_to_plat(struct udevice *dev)
+{
+ int ret = 0;
+ struct pcie_dw_spacemit *pcie = dev_get_priv(dev);
+ struct ofnode_phandle_args args;
+ fdt_addr_t dbi_addr;
+
+ /* Get the controller base address */
+ pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi");
+ if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ dbi_addr = (fdt_addr_t)pcie->dw.dbi_base;
+
+ /* Get the config space base address and size */
+ pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+ &pcie->dw.cfg_size);
+ if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Get the iATU base address and size */
+ pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+ if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Get the PHY AHB base address (called "link" in Linux DTS) */
+ pcie->phy_ahb = (void *)dev_read_addr_name(dev, "link");
+ if ((fdt_addr_t)pcie->phy_ahb == FDT_ADDR_T_NONE) {
+ pcie->phy_ahb = (void *)dev_read_addr_name(dev, "phy_ahb");
+ if ((fdt_addr_t)pcie->phy_ahb == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ }
+
+ /* Get APMU regmap from spacemit,apmu property */
+ ret = dev_read_phandle_with_args(dev, "spacemit,apmu", NULL, 1, 0,
+ &args);
+ if (ret)
+ return ret;
+
+ pcie->apmu_base = (void __iomem *)ofnode_get_addr(args.node);
+ if (!pcie->apmu_base)
+ return -EINVAL;
+ pcie->apmu_offset = args.args[0];
+
+ /* Derive port ID from DBI base address */
+ pcie->port_id = (dbi_addr - SPACEMIT_PCIE_DBI_BASE) / SPACEMIT_PCIE_DBI_STRIDE;
+
+ ret = clk_get_bulk(dev, &pcie->clks);
+ if (ret) {
+ dev_warn(dev, "failed to get clocks: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_bulk(dev, &pcie->rsts);
+ if (ret) {
+ dev_warn(dev, "failed to get resets: %d\n", ret);
+ return ret;
+ }
+
+ gpio_request_by_name(dev, "k1x,pwr_on", 0, &pcie->pwr_on_gpio,
+ GPIOD_IS_OUT);
+ if (!dm_gpio_is_valid(&pcie->pwr_on_gpio))
+ dev_info(dev, "has no power on gpio.\n");
+
+ ret = dev_read_u32(dev, "power-on-status", &pcie->power_on_status);
+ if (ret) {
+ dev_info(dev, "has no power-on-status flag, use default.\n");
+ pcie->power_on_status = 1;
+ }
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_dw_spacemit_ops = {
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
+};
+
+static const struct udevice_id pcie_dw_spacemit_ids[] = {
+ { .compatible = "spacemit,k1-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_dw_spacemit) = {
+ .name = "pcie_dw_spacemit",
+ .id = UCLASS_PCI,
+ .of_match = pcie_dw_spacemit_ids,
+ .ops = &pcie_dw_spacemit_ops,
+ .of_to_plat = pcie_dw_spacemit_of_to_plat,
+ .probe = pcie_dw_spacemit_probe,
+ .priv_auto = sizeof(struct pcie_dw_spacemit),
+};
diff --git a/drivers/pci/pcie_dw_spacemit.h b/drivers/pci/pcie_dw_spacemit.h
new file mode 100644
index 000000000000..2c17f113b75c
--- /dev/null
+++ b/drivers/pci/pcie_dw_spacemit.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Spacemit K1 DesignWare PCIe host controller driver
+ *
+ * Copyright (c) 2023, Spacemit Corporation.
+ * Copyright (c) 2026, RISCstar Ltd.
+ */
+
+#ifndef _PCIE_DW_SPACEMIT_H_
+#define _PCIE_DW_SPACEMIT_H_
+
+#include <linux/bitops.h>
+
+/* PCIe DW common registers */
+#define PCIE_LINK_CAPABILITY 0x7c
+#define PCIE_LINK_CTL_2 0xa0
+#define TARGET_LINK_SPEED_MASK 0xf
+#define LINK_SPEED_GEN_1 0x1
+#define LINK_SPEED_GEN_2 0x2
+#define LINK_SPEED_GEN_3 0x3
+
+#define PCIE_MISC_CONTROL_1_OFF 0x8bc
+#define PCIE_DBI_RO_WR_EN BIT(0)
+
+#define PLR_OFFSET 0x700
+#define PCIE_PORT_DEBUG0 (PLR_OFFSET + 0x28)
+#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
+#define PORT_LOGIC_LTSSM_STATE_L0 0x11
+
+#define PCIE_LINK_UP_TIMEOUT_MS 1000
+
+/* Vendor and device IDs */
+#define PCIE_VENDORID_MASK GENMASK(15, 0)
+#define PCIE_DEVICEID_SHIFT 16
+#define SPACEMIT_PCIE_VENDOR_ID 0x201F
+#define SPACEMIT_PCIE_DEVICE_ID 0x0001
+
+/* Application register offsets */
+#define PCIE_CMD_STATUS 0x04
+#define LTSSM_EN_VAL BIT(0)
+
+/* K1X_CONF_DEVICE_CMD register */
+#define PCIECTRL_K1X_CONF_DEVICE_CMD 0x0000
+#define LTSSM_EN BIT(6)
+#define PCIE_PERST_IN BIT(7)
+#define GLOBAL_PHY_RST BIT(8)
+#define PCIE_AUX_PWR_DET BIT(9)
+#define PCIE_CLKREQ_IN BIT(10) /* read-only: CLKREQ# IO input value */
+#define PCIE_REFCLK_EN BIT(11)
+#define PCIE_RC_PERST BIT(12)
+#define PCIE_EP_WAKE BIT(13)
+#define APP_HOLD_PHY_RST BIT(30)
+#define DEVICE_TYPE_RC BIT(31)
+
+/* PCIE_CTRL_LOGIC register */
+#define PCIE_CTRL_LOGIC 0x0004
+#define PCIE_SOFT_RESET BIT(0)
+#define PCIE_IGNORE_PERSTN BIT(2)
+
+/* PHY AHB link status */
+#define K1X_PHY_AHB_LINK_STS 0x0004
+#define SMLH_LINK_UP BIT(1)
+#define RDLH_LINK_UP BIT(12)
+
+/* PHY lane control mask (bits 0-5 in DEVICE_CMD) */
+#define PCIE_PHY_LANE_CTRL_MASK 0x3f
+
+/* PCIe DBI address calculation */
+#define SPACEMIT_PCIE_DBI_BASE 0xca000000
+#define SPACEMIT_PCIE_DBI_STRIDE 0x400000
+
+enum dw_pcie_device_mode {
+ DW_PCIE_UNKNOWN_TYPE,
+ DW_PCIE_EP_TYPE,
+ DW_PCIE_RC_TYPE,
+};
+
+#endif /* _PCIE_DW_SPACEMIT_H_ */
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/4] configs: k1: enable PCIe and NVMe support
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
2026-09-13 4:23 ` [PATCH v2 1/4] phy: spacemit: add K1 PCIe/USB3 combo PHY driver Eric Chung
2026-09-13 4:23 ` [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver Eric Chung
@ 2026-09-13 4:23 ` Eric Chung
2026-09-13 4:23 ` [PATCH v2 4/4] MAINTAINER: add K1 PCIe driver to Spacemit entry Eric Chung
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eric Chung @ 2026-09-13 4:23 UTC (permalink / raw)
To: u-boot-spacemit, u-boot, u-boot
Cc: Tom Rini, Tim Ouyang, Leo Liang, Scott Bambrough, Eric Chung,
Neil Armstrong, David Lechner, Julien Stephan, Johan Jonker,
Siu Ming Tong, Lucien.Jheng, Huan Zhou, Michal Simek,
Pranav Sanwal, Raymond Mao, Yixun Lan
Enable PCIe and NVMe support on K1 based boards.
Signed-off-by: Eric Chung <eric.chung@riscstar.com>
---
configs/spacemit_k1_defconfig | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/configs/spacemit_k1_defconfig b/configs/spacemit_k1_defconfig
index 5f9923c7f470..9c15d96eae20 100644
--- a/configs/spacemit_k1_defconfig
+++ b/configs/spacemit_k1_defconfig
@@ -105,6 +105,16 @@ CONFIG_CMD_MMC=y
CONFIG_CMD_MEMINFO=y
CONFIG_CMD_MEMINFO_MAP=y
CONFIG_EFI_PARTITION=y
+CONFIG_PCI=y
+CONFIG_CMD_PCI=y
+CONFIG_NVME=y
+CONFIG_NVME_PCI=y
+CONFIG_CMD_NVME=y
+CONFIG_PCIE_DW_SPACEMIT=y
+CONFIG_PHY=y
+CONFIG_PHY_SPACEMIT_K1_PCIE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_EXT4=y
CONFIG_SPL_SPI=y
CONFIG_SPL_DM_SPI=y
CONFIG_SPL_DM_SPI_FLASH=y
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 4/4] MAINTAINER: add K1 PCIe driver to Spacemit entry
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
` (2 preceding siblings ...)
2026-09-13 4:23 ` [PATCH v2 3/4] configs: k1: enable PCIe and NVMe support Eric Chung
@ 2026-09-13 4:23 ` Eric Chung
2026-09-23 13:16 ` [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Yixun Lan
2026-09-29 10:15 ` Yixun Lan
5 siblings, 0 replies; 9+ messages in thread
From: Eric Chung @ 2026-09-13 4:23 UTC (permalink / raw)
To: u-boot-spacemit, u-boot, u-boot
Cc: Tom Rini, Tim Ouyang, Leo Liang, Scott Bambrough, Eric Chung,
Neil Armstrong, David Lechner, Julien Stephan, Johan Jonker,
Siu Ming Tong, Lucien.Jheng, Huan Zhou, Michal Simek,
Pranav Sanwal, Raymond Mao, Yixun Lan
Add drivers/pci/pcie_dw_spacemit.c to the list of files
maintained for the Spacemit K1 board.
Signed-off-by: Eric Chung <eric.chung@riscstar.com>
---
board/spacemit/k1/MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/board/spacemit/k1/MAINTAINERS b/board/spacemit/k1/MAINTAINERS
index e12288a206e0..c1d6b8f3a1c0 100644
--- a/board/spacemit/k1/MAINTAINERS
+++ b/board/spacemit/k1/MAINTAINERS
@@ -10,6 +10,7 @@ F: doc/board/spacemit/
F: drivers/gpio/spacemit_gpio.c
F: drivers/i2c/k1_i2c.c
F: drivers/mmc/spacemit_sdhci.c
+F: drivers/pci/pcie_dw_spacemit.c
F: drivers/pinctrl/spacemit/
F: drivers/power/pmic/pmic_spacemit_p1.c
F: drivers/power/regulator/spacemit_p1_regulator.c
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
` (3 preceding siblings ...)
2026-09-13 4:23 ` [PATCH v2 4/4] MAINTAINER: add K1 PCIe driver to Spacemit entry Eric Chung
@ 2026-09-23 13:16 ` Yixun Lan
2026-09-29 10:15 ` Yixun Lan
5 siblings, 0 replies; 9+ messages in thread
From: Yixun Lan @ 2026-09-23 13:16 UTC (permalink / raw)
To: Eric Chung
Cc: u-boot-spacemit, u-boot, Tom Rini, Tim Ouyang, Leo Liang,
Scott Bambrough, Neil Armstrong, David Lechner, Julien Stephan,
Johan Jonker, Siu Ming Tong, Lucien.Jheng, Huan Zhou,
Michal Simek, Pranav Sanwal, Raymond Mao, Yixun Lan
On 12:23 Sun 13 Sep , Eric Chung wrote:
> Signed-off-by: Eric Chung <eric.chung@riscstar.com>
> ---
> Changes in v2:
> - dts: Rebase on upstream DTS. So drop the changes in overlay DTS.
> - pci: Find the phy by index instead.
> - maintainer: Add the driver in the Spacemit MAINTAINER entry.
> - Link to v1: https://patch.msgid.link/20260705-pci-v1-0-beca83440a27@riscstar.com
>
> To: u-boot@lists.u-boot-project.org
> To: u-boot-spacemit@groups.io
> Cc: Tom Rini <trini@konsulko.com>
> Cc: Neil Armstrong <neil.armstrong@linaro.org>
> Cc: David Lechner <dlechner@baylibre.com>
> Cc: Julien Stephan <jstephan@baylibre.com>
> Cc: Johan Jonker <jbx6244@gmail.com>
> Cc: Siu Ming Tong <smtong@axiado.com>
> Cc: "Lucien.Jheng" <lucienzx159@gmail.com>
> Cc: Eric Chung <eric.chung@riscstar.com>
> Cc: Huan Zhou <pericycle.cc@gmail.com>
> Cc: Michal Simek <michal.simek@amd.com>
> Cc: Pranav Sanwal <pranav.sanwal@amd.com>
> Cc: Raymond Mao <raymond.mao@riscstar.com>
> Cc: Yixun Lan <dlan@gentoo.org>
>
> ---
> Eric Chung (4):
> phy: spacemit: add K1 PCIe/USB3 combo PHY driver
> pci: spacemit: add DesignWare PCIe host controller driver
> configs: k1: enable PCIe and NVMe support
> MAINTAINER: add K1 PCIe driver to Spacemit entry
>
> board/spacemit/k1/MAINTAINERS | 1 +
> configs/spacemit_k1_defconfig | 10 +
> drivers/pci/Kconfig | 7 +
> drivers/pci/Makefile | 1 +
> drivers/pci/pcie_dw_spacemit.c | 391 +++++++++++++++++++++++++++++
> drivers/pci/pcie_dw_spacemit.h | 78 ++++++
> drivers/phy/Kconfig | 1 +
> drivers/phy/Makefile | 1 +
> drivers/phy/spacemit/Kconfig | 11 +
> drivers/phy/spacemit/Makefile | 1 +
> drivers/phy/spacemit/phy-k1-pcie.c | 492 +++++++++++++++++++++++++++++++++++++
> 11 files changed, 994 insertions(+)
> ---
For the series, tested on Bananapi-f3 board
Reviewed-by: Yixun Lan <dlan@kernel.org>
Tested-by: Yixun Lan <dlan@kernel.org>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver
2026-09-13 4:23 ` [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver Eric Chung
@ 2026-09-23 13:30 ` Yixun Lan
2026-09-24 14:00 ` Neil Armstrong
0 siblings, 1 reply; 9+ messages in thread
From: Yixun Lan @ 2026-09-23 13:30 UTC (permalink / raw)
To: Neil Armstrong
Cc: u-boot-spacemit, u-boot, Tom Rini, Eric Chung, Tim Ouyang,
Leo Liang, Scott Bambrough, Neil Armstrong, David Lechner,
Julien Stephan, Johan Jonker, Siu Ming Tong, Lucien.Jheng,
Huan Zhou, Michal Simek, Pranav Sanwal, Raymond Mao, Yixun Lan
Hi Neil,
On 12:23 Sun 13 Sep , Eric Chung wrote:
> Add PCIe host controller driver for Spacemit K1 SoC using the
> Synopsys DesignWare PCIe core. Supports up to 3 ports.
>
> Signed-off-by: Eric Chung <eric.chung@riscstar.com>
> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
>
> ---
> v2:
> - Locate the phy by index instead.
> ---
> drivers/pci/Kconfig | 7 +
> drivers/pci/Makefile | 1 +
> drivers/pci/pcie_dw_spacemit.c | 391 +++++++++++++++++++++++++++++++++++++++++
> drivers/pci/pcie_dw_spacemit.h | 78 ++++++++
> 4 files changed, 477 insertions(+)
>
Would you like to merge this patch via pci tree? otherwise, I could take all
of this series via spacemit custodian tree, let me know which way you'd prefer?
Thanks
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver
2026-09-23 13:30 ` Yixun Lan
@ 2026-09-24 14:00 ` Neil Armstrong
0 siblings, 0 replies; 9+ messages in thread
From: Neil Armstrong @ 2026-09-24 14:00 UTC (permalink / raw)
To: Yixun Lan
Cc: u-boot-spacemit, u-boot, Tom Rini, Eric Chung, Tim Ouyang,
Leo Liang, Scott Bambrough, David Lechner, Julien Stephan,
Johan Jonker, Siu Ming Tong, Lucien.Jheng, Huan Zhou,
Michal Simek, Pranav Sanwal, Raymond Mao, Yixun Lan
Hi,
On 9/23/26 15:30, Yixun Lan wrote:
> Hi Neil,
>
> On 12:23 Sun 13 Sep , Eric Chung wrote:
>> Add PCIe host controller driver for Spacemit K1 SoC using the
>> Synopsys DesignWare PCIe core. Supports up to 3 ports.
>>
>> Signed-off-by: Eric Chung <eric.chung@riscstar.com>
>> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
>>
>> ---
>> v2:
>> - Locate the phy by index instead.
>> ---
>> drivers/pci/Kconfig | 7 +
>> drivers/pci/Makefile | 1 +
>> drivers/pci/pcie_dw_spacemit.c | 391 +++++++++++++++++++++++++++++++++++++++++
>> drivers/pci/pcie_dw_spacemit.h | 78 ++++++++
>> 4 files changed, 477 insertions(+)
>>
>
> Would you like to merge this patch via pci tree? otherwise, I could take all
> of this series via spacemit custodian tree, let me know which way you'd prefer?
Feel free to pick it via your tree!
Thanks,
Neil
>
> Thanks
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
` (4 preceding siblings ...)
2026-09-23 13:16 ` [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Yixun Lan
@ 2026-09-29 10:15 ` Yixun Lan
5 siblings, 0 replies; 9+ messages in thread
From: Yixun Lan @ 2026-09-29 10:15 UTC (permalink / raw)
To: u-boot-spacemit, u-boot, Eric Chung
Cc: Yixun Lan, Tom Rini, Tim Ouyang, Leo Liang, Scott Bambrough,
Neil Armstrong, David Lechner, Julien Stephan, Johan Jonker,
Siu Ming Tong, Lucien.Jheng, Huan Zhou, Michal Simek,
Pranav Sanwal, Raymond Mao, Yixun Lan
On Sun, 13 Sep 2026 12:23:09 +0800, Eric Chung wrote:
>
Applied, thanks!
[1/4] phy: spacemit: add K1 PCIe/USB3 combo PHY driver
https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit/-/commit/57eb5723d5feb3226cff9ac1d8379f0b31eb09b1
[2/4] pci: spacemit: add DesignWare PCIe host controller driver
https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit/-/commit/c8764b8db670152ff8e3b393c8de52823bef51ec
[3/4] configs: k1: enable PCIe and NVMe support
https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit/-/commit/d70d033928044754e9ac6ea103bfaea19b300816
[4/4] MAINTAINER: add K1 PCIe driver to Spacemit entry
https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit/-/commit/dfa681ec397aed90bd13aa5e0e887ee533d41988
Best regards,
--
Yixun Lan <dlan@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-29 10:15 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-13 4:23 [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Eric Chung
2026-09-13 4:23 ` [PATCH v2 1/4] phy: spacemit: add K1 PCIe/USB3 combo PHY driver Eric Chung
2026-09-13 4:23 ` [PATCH v2 2/4] pci: spacemit: add DesignWare PCIe host controller driver Eric Chung
2026-09-23 13:30 ` Yixun Lan
2026-09-24 14:00 ` Neil Armstrong
2026-09-13 4:23 ` [PATCH v2 3/4] configs: k1: enable PCIe and NVMe support Eric Chung
2026-09-13 4:23 ` [PATCH v2 4/4] MAINTAINER: add K1 PCIe driver to Spacemit entry Eric Chung
2026-09-23 13:16 ` [PATCH v2 0/4] pci: enable designware pci and phy on spacemit k1 SoC Yixun Lan
2026-09-29 10:15 ` Yixun Lan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.