[PATCH 0/6] rockchip: rk3568: Fix use of PCIe bifurcation

This series add support for use of PCIe bifurcation on RK3568, and as a bonus support for the RK3588 PHY is also included. With PCIe bifurcation supported it is possible to enable PCIe on more RK3568 boards, e.g. on NanoPi R5C and NanoPi R5S. This series only include fixing the mini PCIe slot on Radxa E25.
Most parts of this series was imported almost 1:1 from mainline linux.
Patch 1 fixes configuration of number of lanes in pcie_dw_rockchip. Patch 2-3 refactor the snps-pcie3 phy driver. Patch 4 add bifurcation support for RK3568. Patch 5 add support for RK3588. Patch 6 enables the mini PCIe slot on Radxa E25.
The RK3588 PHY part was tested on a ROCK 5B together with device tree files picked from Sebastian Reichel's rk3588 branch at [1].
Patches in this series is also aviliable at [2].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-misc.git/tree/?h=r... [2] https://github.com/Kwiboo/u-boot-rockchip/commits/rk35xx-pcie-bifurcation-v1
Jonas Karlman (6): pci: pcie_dw_rockchip: Configure number of lanes and link width speed phy: rockchip: snps-pcie3: Refactor to use clk_bulk API phy: rockchip: snps-pcie3: Refactor to use a phy_init ops phy: rockchip: snps-pcie3: Add bifurcation support for RK3568 phy: rockchip: snps-pcie3: Add support for RK3588 rockchip: rk3568-radxa-e25: Enable pcie3x1 node
arch/arm/dts/rk3568-radxa-e25-u-boot.dtsi | 11 +- configs/radxa-e25-rk3568_defconfig | 1 - drivers/pci/pcie_dw_rockchip.c | 58 ++++- .../phy/rockchip/phy-rockchip-snps-pcie3.c | 230 ++++++++++++++---- 4 files changed, 235 insertions(+), 65 deletions(-)

Change to use clk_bulk API and syscon_regmap_lookup_by_phandle to simplify in preparation for upcoming support of a RK3588 variant.
Signed-off-by: Jonas Karlman jonas@kwiboo.se --- .../phy/rockchip/phy-rockchip-snps-pcie3.c | 58 +++---------------- 1 file changed, 9 insertions(+), 49 deletions(-)
diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 66c75f98e6d1..3053543a3329 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -26,17 +26,13 @@ * @mmio: The base address of PHY internal registers * @phy_grf: The regmap for controlling pipe signal * @p30phy: The reset signal for PHY - * @ref_clk_m: The reference clock of M for PHY - * @ref_clk_n: The reference clock of N for PHY - * @pclk: The clock for accessing PHY blocks + * @clks: The clocks for PHY */ struct rockchip_p3phy_priv { void __iomem *mmio; struct regmap *phy_grf; struct reset_ctl p30phy; - struct clk ref_clk_m; - struct clk ref_clk_n; - struct clk pclk; + struct clk_bulk clks; };
static int rochchip_p3phy_init(struct phy *phy) @@ -44,18 +40,10 @@ static int rochchip_p3phy_init(struct phy *phy) struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); int ret;
- ret = clk_enable(&priv->ref_clk_m); - if (ret < 0 && ret != -ENOSYS) + ret = clk_enable_bulk(&priv->clks); + if (ret) return ret;
- ret = clk_enable(&priv->ref_clk_n); - if (ret < 0 && ret != -ENOSYS) - goto err_ref; - - ret = clk_enable(&priv->pclk); - if (ret < 0 && ret != -ENOSYS) - goto err_pclk; - reset_assert(&priv->p30phy); udelay(1);
@@ -67,21 +55,13 @@ static int rochchip_p3phy_init(struct phy *phy) udelay(1);
return 0; -err_pclk: - clk_disable(&priv->ref_clk_n); -err_ref: - clk_disable(&priv->ref_clk_m); - - return ret; }
static int rochchip_p3phy_exit(struct phy *phy) { struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
- clk_disable(&priv->ref_clk_m); - clk_disable(&priv->ref_clk_n); - clk_disable(&priv->pclk); + clk_disable_bulk(&priv->clks); reset_assert(&priv->p30phy);
return 0; @@ -90,21 +70,13 @@ static int rochchip_p3phy_exit(struct phy *phy) static int rockchip_p3phy_probe(struct udevice *dev) { struct rockchip_p3phy_priv *priv = dev_get_priv(dev); - struct udevice *syscon; int ret;
priv->mmio = dev_read_addr_ptr(dev); if (!priv->mmio) return -EINVAL;
- ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, - "rockchip,phy-grf", &syscon); - if (ret) { - pr_err("unable to find syscon device for rockchip,phy-grf\n"); - return ret; - } - - priv->phy_grf = syscon_get_regmap(syscon); + priv->phy_grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,phy-grf"); if (IS_ERR(priv->phy_grf)) { dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); return PTR_ERR(priv->phy_grf); @@ -116,22 +88,10 @@ static int rockchip_p3phy_probe(struct udevice *dev) return ret; }
- ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m); + ret = clk_get_bulk(dev, &priv->clks); if (ret) { - dev_err(dev, "failed to find ref clock M\n"); - return PTR_ERR(&priv->ref_clk_m); - } - - ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n); - if (ret) { - dev_err(dev, "failed to find ref clock N\n"); - return PTR_ERR(&priv->ref_clk_n); - } - - ret = clk_get_by_name(dev, "pclk", &priv->pclk); - if (ret) { - dev_err(dev, "failed to find pclk\n"); - return PTR_ERR(&priv->pclk); + dev_err(dev, "failed to get clocks\n"); + return ret; }
return 0;

Add a phy_init ops in preparation for upcoming support of a RK3588 variant in the driver.
Signed-off-by: Jonas Karlman jonas@kwiboo.se --- .../phy/rockchip/phy-rockchip-snps-pcie3.c | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 3053543a3329..b76b5386bef0 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -35,8 +35,32 @@ struct rockchip_p3phy_priv { struct clk_bulk clks; };
+struct rockchip_p3phy_ops { + int (*phy_init)(struct phy *phy); +}; + +static int rockchip_p3phy_rk3568_init(struct phy *phy) +{ + struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); + + /* Deassert PCIe PMA output clamp mode */ + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, + (0x1 << 15) | (0x1 << 31)); + + reset_deassert(&priv->p30phy); + udelay(1); + + return 0; +} + +static const struct rockchip_p3phy_ops rk3568_ops = { + .phy_init = rockchip_p3phy_rk3568_init, +}; + static int rochchip_p3phy_init(struct phy *phy) { + struct rockchip_p3phy_ops *ops = + (struct rockchip_p3phy_ops *)dev_get_driver_data(phy->dev); struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); int ret;
@@ -47,14 +71,11 @@ static int rochchip_p3phy_init(struct phy *phy) reset_assert(&priv->p30phy); udelay(1);
- /* Deassert PCIe PMA output clamp mode */ - regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, - (0x1 << 15) | (0x1 << 31)); - - reset_deassert(&priv->p30phy); - udelay(1); + ret = ops->phy_init(phy); + if (ret) + clk_disable_bulk(&priv->clks);
- return 0; + return ret; }
static int rochchip_p3phy_exit(struct phy *phy) @@ -103,7 +124,10 @@ static struct phy_ops rochchip_p3phy_ops = { };
static const struct udevice_id rockchip_p3phy_of_match[] = { - { .compatible = "rockchip,rk3568-pcie3-phy" }, + { + .compatible = "rockchip,rk3568-pcie3-phy", + .data = (ulong)&rk3568_ops, + }, { }, };

Add support for the RK3588 variant to the driver.
Code imported almost 1:1 from mainline linux driver.
Signed-off-by: Jonas Karlman jonas@kwiboo.se --- .../phy/rockchip/phy-rockchip-snps-pcie3.c | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+)
diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 642819b1f672..a4392daf4c92 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -27,6 +27,17 @@
#define RK3568_BIFURCATION_LANE_0_1 BIT(0)
+/* Register for RK3588 */ +#define PHP_GRF_PCIESEL_CON 0x100 +#define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 +#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 +#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 +#define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) + +#define RK3588_BIFURCATION_LANE_0_1 BIT(0) +#define RK3588_BIFURCATION_LANE_2_3 BIT(1) +#define RK3588_LANE_AGGREGATION BIT(2) + /** * struct rockchip_p3phy_priv - RK DW PCIe PHY state * @@ -40,6 +51,7 @@ struct rockchip_p3phy_priv { void __iomem *mmio; struct regmap *phy_grf; + struct regmap *pipe_grf; struct reset_ctl p30phy; struct clk_bulk clks; int num_lanes; @@ -93,6 +105,66 @@ static const struct rockchip_p3phy_ops rk3568_ops = { .phy_init = rockchip_p3phy_rk3568_init, };
+static int rockchip_p3phy_rk3588_init(struct phy *phy) +{ + struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); + u32 reg = 0; + u8 mode = 0; + int ret; + + /* Deassert PCIe PMA output clamp mode */ + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + BIT(8) | BIT(24)); + + /* Set bifurcation if needed */ + for (int i = 0; i < priv->num_lanes; i++) { + if (!priv->lanes[i]) + mode |= (BIT(i) << 3); + + if (priv->lanes[i] > 1) + mode |= (BIT(i) >> 1); + } + + if (!mode) { + reg = RK3588_LANE_AGGREGATION; + } else { + if (mode & (BIT(0) | BIT(1))) + reg |= RK3588_BIFURCATION_LANE_0_1; + + if (mode & (BIT(2) | BIT(3))) + reg |= RK3588_BIFURCATION_LANE_2_3; + } + + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + (0x7 << 16) | reg); + + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ + reg = (mode & (BIT(6) | BIT(7))) >> 6; + if (reg) + regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, + (reg << 16) | reg); + + reset_deassert(&priv->p30phy); + udelay(1); + + ret = regmap_read_poll_timeout(priv->phy_grf, + RK3588_PCIE3PHY_GRF_PHY0_STATUS1, + reg, RK3588_SRAM_INIT_DONE(reg), + 0, 500); + ret |= regmap_read_poll_timeout(priv->phy_grf, + RK3588_PCIE3PHY_GRF_PHY1_STATUS1, + reg, RK3588_SRAM_INIT_DONE(reg), + 0, 500); + if (ret) + dev_err(phy->dev, "lock failed 0x%x\n", reg); + + return ret; +} + +static const struct rockchip_p3phy_ops rk3588_ops = { + .phy_init = rockchip_p3phy_rk3588_init, +}; + static int rochchip_p3phy_init(struct phy *phy) { struct rockchip_p3phy_ops *ops = @@ -139,6 +211,15 @@ static int rockchip_p3phy_probe(struct udevice *dev) return PTR_ERR(priv->phy_grf); }
+ if (device_is_compatible(dev, "rockchip,rk3588-pcie3-phy")) { + priv->pipe_grf = + syscon_regmap_lookup_by_phandle(dev, "rockchip,pipe-grf"); + if (IS_ERR(priv->pipe_grf)) { + dev_err(dev, "failed to find rockchip,pipe_grf regmap\n"); + return PTR_ERR(priv->pipe_grf); + } + } + ret = dev_read_size(dev, "data-lanes"); if (ret > 0) { priv->num_lanes = ret / sizeof(u32); @@ -181,6 +262,10 @@ static const struct udevice_id rockchip_p3phy_of_match[] = { .compatible = "rockchip,rk3568-pcie3-phy", .data = (ulong)&rk3568_ops, }, + { + .compatible = "rockchip,rk3588-pcie3-phy", + .data = (ulong)&rk3588_ops, + }, { }, };

It appears that you had a transmission problem with this patch as I am missing 1/6, 4/6, and 6/6.
I am pretty sure these are from your repo here: https://github.com/Kwiboo/u-boot-rockchip/tree/rk35xx-pcie-bifurcation-v1
(1/6) pci: pcie_dw_rockchip: Configure number of lanes and link width speed https://github.com/Kwiboo/u-boot-rockchip/commit/2b3f591aec3abe69adc9bbc723d...
(2/6) phy: rockchip: snps-pcie3: Refactor to use clk_bulk API https://github.com/Kwiboo/u-boot-rockchip/commit/e6c561d1e00b92e1d4c98f9ce58...
(3/6) phy: rockchip: snps-pcie3: Refactor to use a phy_init ops https://github.com/Kwiboo/u-boot-rockchip/commit/627648f509f149ac9b0ade84c2a...
(4/6) phy: rockchip: snps-pcie3: Add bifurcation support for RK3568 https://github.com/Kwiboo/u-boot-rockchip/commit/a8d3342b986df42191793e2d0f7...
(5/6) phy: rockchip: snps-pcie3: Add support for RK3588 https://github.com/Kwiboo/u-boot-rockchip/commit/031df04ac14b3ddaba7f3be07f9...
(6/6) rockchip: rk3568-radxa-e25: Enable pcie3x1 node https://github.com/Kwiboo/u-boot-rockchip/commit/4439243b10731067baf64ea6bff...
These work for me and detect a Nanopi R5S NVMe. Can you resend this patchset so I can definitively confirm? It would be great if this can be fixed in 2023.10.
Thanks,
John Clark
On 8/1/23 5:25 PM, Jonas Karlman wrote:
This series add support for use of PCIe bifurcation on RK3568, and as a bonus support for the RK3588 PHY is also included. With PCIe bifurcation supported it is possible to enable PCIe on more RK3568 boards, e.g. on NanoPi R5C and NanoPi R5S. This series only include fixing the mini PCIe slot on Radxa E25.
Most parts of this series was imported almost 1:1 from mainline linux.
Patch 1 fixes configuration of number of lanes in pcie_dw_rockchip. Patch 2-3 refactor the snps-pcie3 phy driver. Patch 4 add bifurcation support for RK3568. Patch 5 add support for RK3588. Patch 6 enables the mini PCIe slot on Radxa E25.
The RK3588 PHY part was tested on a ROCK 5B together with device tree files picked from Sebastian Reichel's rk3588 branch at [1].
Patches in this series is also aviliable at [2].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-misc.git/tree/?h=r... [2] https://github.com/Kwiboo/u-boot-rockchip/commits/rk35xx-pcie-bifurcation-v1
Jonas Karlman (6): pci: pcie_dw_rockchip: Configure number of lanes and link width speed phy: rockchip: snps-pcie3: Refactor to use clk_bulk API phy: rockchip: snps-pcie3: Refactor to use a phy_init ops phy: rockchip: snps-pcie3: Add bifurcation support for RK3568 phy: rockchip: snps-pcie3: Add support for RK3588 rockchip: rk3568-radxa-e25: Enable pcie3x1 node
arch/arm/dts/rk3568-radxa-e25-u-boot.dtsi | 11 +- configs/radxa-e25-rk3568_defconfig | 1 - drivers/pci/pcie_dw_rockchip.c | 58 ++++- .../phy/rockchip/phy-rockchip-snps-pcie3.c | 230 ++++++++++++++---- 4 files changed, 235 insertions(+), 65 deletions(-)
participants (2)
-
John Clark
-
Jonas Karlman