// SPDX-License-Identifier: GPL-2.0 /* * SpacemiT K1 PCIe and PCIe/USB 3 combo PHY driver * * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include /* * Three PCIe ports are supported in the SpacemiT K1 SoC, and this driver * supports their PHYs. * * The PHY for PCIe port A is different from the PHYs for ports B and C: * - It has one lane, while ports B and C have two * - It is a combo PHY can be used for PCIe or USB 3 * - It can automatically calibrate PCIe TX and RX termination settings * * The PHY functionality for PCIe ports B and C is identical: * - They have two PCIe lanes (but can be restricted to 1 via device tree) * - They are used for PCIe only * - They are configured using TX and RX values computed for port A * * A given board is designed to use the combo PHY for either PCIe or USB 3. * Whether the combo PHY is configured for PCIe or USB 3 is specified in * device tree using a phandle plus an argument. The argument indicates * the type (either PHY_TYPE_PCIE or PHY_TYPE_USB3). * * Each PHY has a reset that it gets and deasserts during initialization. * Each depends also on other clocks and resets provided by the controller * hardware (PCIe or USB) it is associated with. The controller drivers * are required to enable any clocks and de-assert any resets that affect * PHY operation. In addition each PHY implements an internal PLL, driven * by an external (24 MHz) oscillator. * * PCIe PHYs must be programmed with RX and TX calibration values. The * combo PHY is the only one that can determine these values. They are * determined by temporarily enabling the combo PHY in PCIe mode at probe * time (if necessary). This calibration only needs to be done once, and * when it has completed the TX and RX values are saved. * * To allow the combo PHY to be enabled for calibration, the resets and * clocks it uses in PCIe mode must be supplied. */ struct k1_pcie_phy { struct device *dev; /* PHY provider device */ struct phy *phy; void __iomem *regs; u32 pcie_lanes; /* Max (1 or 2) unless limited by DT */ struct clk *pll; struct clk_hw pll_hw; /* Private PLL clock */ /* The remaining fields are only used for the combo PHY */ u32 type; /* PHY_TYPE_PCIE or PHY_TYPE_USB3 */ struct regmap *pmu; /* MMIO regmap (no errors) */ }; #define CALIBRATION_TIMEOUT 500000 /* For combo PHY (usec) */ #define PLL_TIMEOUT 500000 /* For PHY PLL lock (usec) */ #define POLL_DELAY 500 /* Time between polls (usec) */ /* Selecting the combo PHY operating mode requires APMU regmap access */ #define SYSCON_APMU "spacemit,apmu" /* PMU space, for selecting between PCIe and USB 3 mode (combo PHY only) */ #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) /* PHY register space */ /* Offset between lane 0 and lane 1 registers when there are two */ #define PHY_LANE_OFFSET 0x0400 /* PHY PLL configuration */ #define PCIE_PU_ADDR_CLK_CFG 0x0008 #define PLL_READY BIT(0) /* read-only */ #define CFG_INTERNAL_TIMER_ADJ GENMASK(10, 7) #define TIMER_ADJ_USB 0x2 #define TIMER_ADJ_PCIE 0x6 #define CFG_SW_PHY_INIT_DONE BIT(11) /* We set after PLL config */ #define PCIE_RC_DONE_STATUS 0x0018 #define CFG_FORCE_RCV_RETRY BIT(10) /* Used for PCIe */ /* PCIe PHY lane calibration; assumes 24MHz input clock */ #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 (USB 3 and PCIe) */ #define PCIE_PU_PLL_1 0x0048 #define REF_100_WSSC BIT(12) /* 1: input is 100MHz, SSC */ #define FREF_SEL GENMASK(15, 13) #define FREF_24M 0x1 #define SSC_DEP_SEL GENMASK(19, 16) #define SSC_DEP_NONE 0x0 #define SSC_DEP_5000PPM 0xa /* PCIe PHY configuration */ #define PCIE_PU_PLL_2 0x004c #define GEN_REF100 BIT(4) /* 1: generate 100MHz clk */ #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) /* 0: use AFE_RTERM_REG value */ #define PCIE_LTSSM_DIS_ENTRY 0x005c #define CFG_REFCLK_MODE GENMASK(9, 8) #define RFCLK_MODE_DRIVER 0x1 #define OVRD_REFCLK_MODE BIT(10) /* 1: use CFG_RFCLK_MODE */ #define PCIE_TX_REG1 0x0064 #define TX_RTERM_REG GENMASK(15, 12) #define TX_RTERM_SEL BIT(25) /* 1: use TX_RTERM_REG */ /* Zeroed for the combo PHY operating in USB mode */ #define USB3_TEST_CTRL 0x0068 /* PHY calibration values, determined by the combo PHY at probe time */ #define PCIE_RCAL_RESULT 0x0084 /* Port A PHY only */ #define RTERM_VALUE_RX GENMASK(3, 0) #define RTERM_VALUE_TX GENMASK(7, 4) #define R_TUNE_DONE BIT(10) static u32 k1_phy_rterm = ~0; /* Invalid initial value */ /* Save the RX and TX receiver termination values */ static void k1_phy_rterm_set(u32 val) { k1_phy_rterm = val & (RTERM_VALUE_RX | RTERM_VALUE_TX); } static bool k1_phy_rterm_valid(void) { /* Valid if no bits outside those we care about are set */ return !(k1_phy_rterm & ~(RTERM_VALUE_RX | RTERM_VALUE_TX)); } static u32 k1_phy_rterm_rx(void) { return FIELD_GET(RTERM_VALUE_RX, k1_phy_rterm); } static u32 k1_phy_rterm_tx(void) { return FIELD_GET(RTERM_VALUE_TX, k1_phy_rterm); } /* Only the combo PHY has a PMU pointer defined */ static bool k1_phy_port_a(struct k1_pcie_phy *k1_phy) { return !!k1_phy->pmu; } /* The PLL clocks are driven by the external oscillator */ static const struct clk_parent_data k1_pcie_phy_data[] = { { .fw_name = "refclk", }, }; static struct k1_pcie_phy *clk_hw_to_k1_phy(struct clk_hw *clk_hw) { return container_of(clk_hw, struct k1_pcie_phy, pll_hw); } /* USB mode only works on the combo PHY, which has only one lane */ static void k1_pcie_phy_pll_prepare_usb(struct k1_pcie_phy *k1_phy) { void __iomem *regs = k1_phy->regs; u32 val; val = readl(regs + PCIE_PU_ADDR_CLK_CFG); val &= ~CFG_INTERNAL_TIMER_ADJ; val |= FIELD_PREP(CFG_INTERNAL_TIMER_ADJ, TIMER_ADJ_USB); writel(val, regs + PCIE_PU_ADDR_CLK_CFG); val = readl(regs + PCIE_PU_PLL_1); val &= ~SSC_DEP_SEL; val |= FIELD_PREP(SSC_DEP_SEL, SSC_DEP_5000PPM); writel(val, regs + PCIE_PU_PLL_1); } /* Perform PCIe-specific register updates before starting the PLL clock */ static void k1_pcie_phy_pll_prepare_pcie(struct k1_pcie_phy *k1_phy) { void __iomem *regs = k1_phy->regs; u32 val; u32 i; for (i = 0; i < k1_phy->pcie_lanes; i++) { val = readl(regs + PCIE_PU_ADDR_CLK_CFG); val &= ~CFG_INTERNAL_TIMER_ADJ; val |= FIELD_PREP(CFG_INTERNAL_TIMER_ADJ, TIMER_ADJ_PCIE); writel(val, regs + PCIE_PU_ADDR_CLK_CFG); regs += PHY_LANE_OFFSET; /* Next lane */ } regs = k1_phy->regs; val = readl(regs + PCIE_RC_DONE_STATUS); val |= CFG_FORCE_RCV_RETRY; writel(val, regs + PCIE_RC_DONE_STATUS); val = readl(regs + PCIE_PU_PLL_1); val &= ~SSC_DEP_SEL; val |= FIELD_PREP(SSC_DEP_SEL, SSC_DEP_NONE); writel(val, regs + PCIE_PU_PLL_1); val = readl(regs + PCIE_PU_PLL_2); val |= GEN_REF100; /* Enable 100 MHz PLL output clock */ writel(val, regs + PCIE_PU_PLL_2); } static int k1_pcie_phy_pll_prepare(struct clk_hw *clk_hw) { struct k1_pcie_phy *k1_phy = clk_hw_to_k1_phy(clk_hw); void __iomem *regs = k1_phy->regs; u32 val; u32 i; if (k1_phy_port_a(k1_phy) && k1_phy->type == PHY_TYPE_USB3) k1_pcie_phy_pll_prepare_usb(k1_phy); else k1_pcie_phy_pll_prepare_pcie(k1_phy); /* * Disable 100 MHz input reference with spread-spectrum * clocking and select the 24 MHz clock input frequency */ val = readl(regs + PCIE_PU_PLL_1); val &= ~REF_100_WSSC; val &= ~FREF_SEL; val |= FIELD_PREP(FREF_SEL, FREF_24M); writel(val, regs + PCIE_PU_PLL_1); /* Mark PLL configuration done on all lanes */ for (i = 0; i < k1_phy->pcie_lanes; i++) { val = readl(regs + PCIE_PU_ADDR_CLK_CFG); val |= CFG_SW_PHY_INIT_DONE; writel(val, regs + PCIE_PU_ADDR_CLK_CFG); regs += PHY_LANE_OFFSET; /* Next lane */ } /* * Wait for indication the PHY PLL is locked. Lanes for ports * B and C share a PLL, so it's enough to sample just lane 0. */ return readl_poll_timeout(k1_phy->regs + PCIE_PU_ADDR_CLK_CFG, val, val & PLL_READY, POLL_DELAY, PLL_TIMEOUT); } /* Prepare implies enable, and once enabled, it's always on */ static const struct clk_ops k1_pcie_phy_pll_ops = { .prepare = k1_pcie_phy_pll_prepare, }; /* We represent the PHY PLL as a private clock */ static int k1_pcie_phy_pll_setup(struct k1_pcie_phy *k1_phy) { struct clk_hw *hw = &k1_phy->pll_hw; struct device *dev = k1_phy->dev; struct clk_init_data init = { }; char *name; int ret; name = kasprintf(GFP_KERNEL, "pcie%u_phy_pll", k1_phy->phy->id); if (!name) return -ENOMEM; init.name = name; init.ops = &k1_pcie_phy_pll_ops; init.parent_data = k1_pcie_phy_data; init.num_parents = ARRAY_SIZE(k1_pcie_phy_data); hw->init = &init; ret = devm_clk_hw_register(dev, hw); kfree(name); /* __clk_register() duplicates the name we provide */ if (ret) return ret; k1_phy->pll = devm_clk_hw_get_clk(dev, hw, "pll"); if (IS_ERR(k1_phy->pll)) return PTR_ERR(k1_phy->pll); return 0; } /* Select PCIe or USB 3 mode for the combo PHY. */ static void k1_combo_phy_sel(struct k1_pcie_phy *k1_phy, bool usb) { struct regmap *pmu = k1_phy->pmu; /* Only change it if it's not already in the desired state */ if (!regmap_test_bits(pmu, PMUA_USB_PHY_CTRL0, COMBO_PHY_SEL) == usb) regmap_assign_bits(pmu, PMUA_USB_PHY_CTRL0, COMBO_PHY_SEL, usb); } static void k1_pcie_phy_init_pcie(struct k1_pcie_phy *k1_phy) { u32 rx_rterm = k1_phy_rterm_rx(); u32 tx_rterm = k1_phy_rterm_tx(); void __iomem *regs; u32 val; int i; /* For the combo PHY, set PHY to PCIe mode */ if (k1_phy_port_a(k1_phy)) k1_combo_phy_sel(k1_phy, false); regs = k1_phy->regs; for (i = 0; i < k1_phy->pcie_lanes; i++) { val = readl(regs + PCIE_RX_REG1); /* Set RX analog front-end receiver termination value */ val &= ~AFE_RTERM_REG; val |= FIELD_PREP(AFE_RTERM_REG, rx_rterm); /* And enable refclock receiver termination */ val |= EN_RTERM; writel(val, regs + PCIE_RX_REG1); val = readl(regs + PCIE_RX_REG2); /* Use PCIE_RX_REG1 AFE_RTERM_REG value */ val &= ~RX_RTERM_SEL; writel(val, regs + PCIE_RX_REG2); val = readl(regs + PCIE_TX_REG1); /* Set TX driver termination value */ val &= ~TX_RTERM_REG; val |= FIELD_PREP(TX_RTERM_REG, tx_rterm); /* Use PCIE_TX_REG1 TX_RTERM_REG value */ val |= TX_RTERM_SEL; writel(val, regs + PCIE_TX_REG1); /* Set the input clock to 24 MHz, and clear RC_CAL_TOGGLE */ val = readl(regs + PCIE_RC_CAL_REG2); val &= CLKSEL; val |= FIELD_PREP(CLKSEL, CLKSEL_24M); val &= ~RC_CAL_TOGGLE; writel(val, regs + PCIE_RC_CAL_REG2); /* Now trigger recalibration by setting RC_CAL_TOGGLE again */ val |= RC_CAL_TOGGLE; writel(val, regs + PCIE_RC_CAL_REG2); val = readl(regs + PCIE_LTSSM_DIS_ENTRY); /* Override the reference clock; set to refclk driver mode */ val |= OVRD_REFCLK_MODE; val &= ~CFG_REFCLK_MODE; val |= FIELD_PREP(CFG_REFCLK_MODE, RFCLK_MODE_DRIVER); writel(val, regs + PCIE_LTSSM_DIS_ENTRY); regs += PHY_LANE_OFFSET; /* Next lane */ } } /* Only called for combo PHY */ static void k1_pcie_phy_init_usb(struct k1_pcie_phy *k1_phy) { k1_combo_phy_sel(k1_phy, true); /* We're not doing any testing */ writel(0, k1_phy->regs + USB3_TEST_CTRL); } static int k1_pcie_phy_init(struct phy *phy) { struct k1_pcie_phy *k1_phy = phy_get_drvdata(phy); /* Note: port type is only valid for port A (both checks needed) */ if (k1_phy_port_a(k1_phy) && k1_phy->type == PHY_TYPE_USB3) k1_pcie_phy_init_usb(k1_phy); else k1_pcie_phy_init_pcie(k1_phy); return clk_prepare_enable(k1_phy->pll); } static int k1_pcie_phy_exit(struct phy *phy) { struct k1_pcie_phy *k1_phy = phy_get_drvdata(phy); clk_disable_unprepare(k1_phy->pll); return 0; } static const struct phy_ops k1_pcie_phy_ops = { .init = k1_pcie_phy_init, .exit = k1_pcie_phy_exit, .owner = THIS_MODULE, }; /* * Get values needed for calibrating PHYs operating in PCIe mode. Only * the combo PHY is able to do this, and its calibration values are used * for configuring all PCIe PHYs. * * We always need to de-assert the "global" reset on the combo PHY, * because the USB driver depends on it. If used for PCIe, that driver * will (also) de-assert this, but by leaving it de-asserted for the * combo PHY, the USB driver doesn't have to do this. Note: although * SpacemiT refers to this as the global reset, we name the "phy" reset. * * In addition, we guarantee the APP_HOLD_PHY_RESET bit is clear for the * combo PHY, so the USB driver doesn't have to manage that either. The * PCIe driver is free to change this bit for normal operation. * * Calibration only needs to be done once. It's possible calibration has * already completed (e.g., it might have happened in the boot loader, or * -EPROBE_DEFER might result in this function being called again). So we * check that early too, to avoid doing it more than once. * * Otherwise we temporarily power up the PHY using the PCIe app clocks * and resets, wait for the hardware to indicate calibration is done, * grab the value, then shut the PHY down again. */ static int k1_pcie_combo_phy_calibrate(struct k1_pcie_phy *k1_phy) { struct reset_control_bulk_data resets[] = { { .id = "dbi", }, { .id = "mstr", }, { .id = "slv", }, }; struct clk_bulk_data clocks[] = { { .id = "dbi", }, { .id = "mstr", }, { .id = "slv", }, }; struct device *dev = k1_phy->dev; int ret = 0; int val; /* Nothing to do if we already set the receiver termination value */ if (k1_phy_rterm_valid()) return 0; /* * We also guarantee the APP_HOLD_PHY_RESET bit is clear. We can * leave this bit clear even if an error happens below. */ regmap_assign_bits(k1_phy->pmu, PCIE_CLK_RES_CTRL, PCIE_APP_HOLD_PHY_RST, false); /* If the calibration already completed (e.g. by U-Boot), we're done */ val = readl(k1_phy->regs + PCIE_RCAL_RESULT); if (val & R_TUNE_DONE) goto out_tune_done; /* Put the PHY into PCIe mode */ k1_combo_phy_sel(k1_phy, false); /* Get and enable the PCIe app clocks */ ret = clk_bulk_get(dev, ARRAY_SIZE(clocks), clocks); if (ret < 0) goto out_tune_done; ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks); if (ret) goto out_put_clocks; /* Get the PCIe application resets (not the PHY reset) */ ret = reset_control_bulk_get_shared(dev, ARRAY_SIZE(resets), resets); if (ret) goto out_disable_clocks; /* De-assert the PCIe application resets */ ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets); if (ret) goto out_put_resets; /* * This is the core activity here. Wait for the hardware to * signal that it has completed calibration/tuning. Once it * has, the register value will contain the values we'll * use to configure PCIe PHYs. */ ret = readl_poll_timeout(k1_phy->regs + PCIE_RCAL_RESULT, val, val & R_TUNE_DONE, POLL_DELAY, CALIBRATION_TIMEOUT); /* Clean up. We're done with the resets and clocks */ reset_control_bulk_assert(ARRAY_SIZE(resets), resets); out_put_resets: reset_control_bulk_put(ARRAY_SIZE(resets), resets); out_disable_clocks: clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks); out_put_clocks: clk_bulk_put(ARRAY_SIZE(clocks), clocks); out_tune_done: /* If we got the value without timing out, set k1_phy_rterm */ if (!ret) k1_phy_rterm_set(val); return ret; } static struct phy * k1_pcie_combo_phy_xlate(struct device *dev, const struct of_phandle_args *args) { struct k1_pcie_phy *k1_phy = dev_get_drvdata(dev); u32 type; /* The argument specifying the PHY mode is required */ if (args->args_count != 1) return ERR_PTR(-EINVAL); /* We only support PCIe and USB 3 mode */ type = args->args[0]; if (type != PHY_TYPE_PCIE && type != PHY_TYPE_USB3) return ERR_PTR(-EINVAL); /* This PHY can only be used once */ if (k1_phy->type != PHY_NONE) return ERR_PTR(-EBUSY); k1_phy->type = type; return k1_phy->phy; } /* Use the maximum number of PCIe lanes unless limited by device tree */ static u32 k1_pcie_num_lanes(struct k1_pcie_phy *k1_phy, bool port_a) { struct device *dev = k1_phy->dev; u32 count = 0; u32 max; int ret; ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &count); if (count == 1) return 1; if (count == 2 && !port_a) return 2; max = port_a ? 1 : 2; if (ret != -EINVAL) dev_warn(dev, "bad lane count %u for port; using %u\n", count, max); return max; } static int k1_pcie_combo_phy_probe(struct k1_pcie_phy *k1_phy) { struct device *dev = k1_phy->dev; struct regmap *regmap; int ret; /* Setting the PHY mode requires access to the PMU regmap */ regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev), SYSCON_APMU); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "failed to get PMU\n"); k1_phy->pmu = regmap; ret = k1_pcie_combo_phy_calibrate(k1_phy); if (ret) return dev_err_probe(dev, ret, "calibration failed\n"); /* Needed by k1_pcie_combo_phy_xlate(), which also sets k1_phy->type */ dev_set_drvdata(dev, k1_phy); return 0; } static int k1_pcie_phy_probe(struct platform_device *pdev) { struct phy *(*xlate)(struct device *dev, const struct of_phandle_args *args); struct device *dev = &pdev->dev; struct reset_control *phy_reset; struct phy_provider *provider; struct k1_pcie_phy *k1_phy; bool probing_port_a; int ret; xlate = of_device_get_match_data(dev); probing_port_a = xlate == k1_pcie_combo_phy_xlate; /* Only the combo PHY can calibrate, so it must probe first */ if (!k1_phy_rterm_valid() && !probing_port_a) return -EPROBE_DEFER; k1_phy = devm_kzalloc(dev, sizeof(*k1_phy), GFP_KERNEL); if (!k1_phy) return -ENOMEM; k1_phy->dev = dev; k1_phy->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(k1_phy->regs)) return dev_err_probe(dev, PTR_ERR(k1_phy->regs), "error mapping registers\n"); /* De-assert the PHY (global) reset and leave it that way */ phy_reset = devm_reset_control_get_exclusive_deasserted(dev, "phy"); if (IS_ERR(phy_reset)) return PTR_ERR(phy_reset); if (probing_port_a) { ret = k1_pcie_combo_phy_probe(k1_phy); if (ret) return dev_err_probe(dev, ret, "error probing combo phy\n"); } k1_phy->pcie_lanes = k1_pcie_num_lanes(k1_phy, probing_port_a); k1_phy->phy = devm_phy_create(dev, NULL, &k1_pcie_phy_ops); if (IS_ERR(k1_phy->phy)) return dev_err_probe(dev, PTR_ERR(k1_phy->phy), "error creating phy\n"); phy_set_drvdata(k1_phy->phy, k1_phy); ret = k1_pcie_phy_pll_setup(k1_phy); if (ret) return dev_err_probe(dev, ret, "error initializing clock\n"); provider = devm_of_phy_provider_register(dev, xlate); if (IS_ERR(provider)) return dev_err_probe(dev, PTR_ERR(provider), "error registering provider\n"); return 0; } static const struct of_device_id k1_pcie_phy_of_match[] = { { .compatible = "spacemit,k1-combo-phy", k1_pcie_combo_phy_xlate, }, { .compatible = "spacemit,k1-pcie-phy", of_phy_simple_xlate, }, { }, }; MODULE_DEVICE_TABLE(of, k1_pcie_phy_of_match); static struct platform_driver k1_pcie_phy_driver = { .probe = k1_pcie_phy_probe, .driver = { .of_match_table = k1_pcie_phy_of_match, .name = "spacemit-k1-pcie-phy", } }; module_platform_driver(k1_pcie_phy_driver); MODULE_DESCRIPTION("SpacemiT K1 PCIe and USB 3 PHY driver"); MODULE_LICENSE("GPL");