Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: rockchip: Support PCIe v3

RK3568 supports PCIe v3 using not Combphy like PCIe v2 on rk3566.
It use a dedicated PCIe-phy. Add support for this.

Initial support by Shawn Lin, modifications by Peter Geis and Frank
Wunderlich.

Add data-lanes property for splitting pcie-lanes across controllers.

The data-lanes is an array where x=0 means lane is disabled and x > 0
means controller x is assigned to phy lane.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Suggested-by: Peter Geis <pgwipeout@gmail.com>
Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
Link: https://lore.kernel.org/r/20220825193836.54262-4-linux@fw-web.de
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Shawn Lin and committed by
Vinod Koul
2e9bffc4 75be98ee

+341
+9
drivers/phy/rockchip/Kconfig
··· 83 83 help 84 84 Enable this to support the Rockchip PCIe PHY. 85 85 86 + config PHY_ROCKCHIP_SNPS_PCIE3 87 + tristate "Rockchip Snps PCIe3 PHY Driver" 88 + depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST 89 + depends on HAS_IOMEM 90 + select GENERIC_PHY 91 + select MFD_SYSCON 92 + help 93 + Enable this to support the Rockchip snps PCIe3 PHY. 94 + 86 95 config PHY_ROCKCHIP_TYPEC 87 96 tristate "Rockchip TYPEC PHY Driver" 88 97 depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
+1
drivers/phy/rockchip/Makefile
··· 8 8 obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o 9 9 obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o 10 10 obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o 11 + obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o 11 12 obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o 12 13 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
+319
drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Rockchip PCIE3.0 phy driver 4 + * 5 + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. 6 + */ 7 + 8 + #include <linux/clk.h> 9 + #include <linux/delay.h> 10 + #include <linux/io.h> 11 + #include <linux/iopoll.h> 12 + #include <linux/kernel.h> 13 + #include <linux/mfd/syscon.h> 14 + #include <linux/module.h> 15 + #include <linux/of_device.h> 16 + #include <linux/phy/pcie.h> 17 + #include <linux/phy/phy.h> 18 + #include <linux/regmap.h> 19 + #include <linux/reset.h> 20 + 21 + /* Register for RK3568 */ 22 + #define GRF_PCIE30PHY_CON1 0x4 23 + #define GRF_PCIE30PHY_CON6 0x18 24 + #define GRF_PCIE30PHY_CON9 0x24 25 + #define GRF_PCIE30PHY_DA_OCM (BIT(15) | BIT(31)) 26 + #define GRF_PCIE30PHY_STATUS0 0x80 27 + #define GRF_PCIE30PHY_WR_EN (0xf << 16) 28 + #define SRAM_INIT_DONE(reg) (reg & BIT(14)) 29 + 30 + #define RK3568_BIFURCATION_LANE_0_1 BIT(0) 31 + 32 + /* Register for RK3588 */ 33 + #define PHP_GRF_PCIESEL_CON 0x100 34 + #define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 35 + #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 36 + #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 37 + #define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) 38 + 39 + #define RK3588_BIFURCATION_LANE_0_1 BIT(0) 40 + #define RK3588_BIFURCATION_LANE_2_3 BIT(1) 41 + #define RK3588_LANE_AGGREGATION BIT(2) 42 + 43 + struct rockchip_p3phy_ops; 44 + 45 + struct rockchip_p3phy_priv { 46 + const struct rockchip_p3phy_ops *ops; 47 + void __iomem *mmio; 48 + /* mode: RC, EP */ 49 + int mode; 50 + /* pcie30_phymode: Aggregation, Bifurcation */ 51 + int pcie30_phymode; 52 + struct regmap *phy_grf; 53 + struct regmap *pipe_grf; 54 + struct reset_control *p30phy; 55 + struct phy *phy; 56 + struct clk_bulk_data *clks; 57 + int num_clks; 58 + int num_lanes; 59 + u32 lanes[4]; 60 + }; 61 + 62 + struct rockchip_p3phy_ops { 63 + int (*phy_init)(struct rockchip_p3phy_priv *priv); 64 + }; 65 + 66 + static int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) 67 + { 68 + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); 69 + 70 + /* Actually We don't care EP/RC mode, but just record it */ 71 + switch (submode) { 72 + case PHY_MODE_PCIE_RC: 73 + priv->mode = PHY_MODE_PCIE_RC; 74 + break; 75 + case PHY_MODE_PCIE_EP: 76 + priv->mode = PHY_MODE_PCIE_EP; 77 + break; 78 + default: 79 + dev_err(&phy->dev, "%s, invalid mode\n", __func__); 80 + return -EINVAL; 81 + } 82 + 83 + return 0; 84 + } 85 + 86 + static int rockchip_p3phy_rk3568_init(struct rockchip_p3phy_priv *priv) 87 + { 88 + struct phy *phy = priv->phy; 89 + bool bifurcation = false; 90 + int ret; 91 + u32 reg; 92 + 93 + /* Deassert PCIe PMA output clamp mode */ 94 + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM); 95 + 96 + for (int i = 0; i < priv->num_lanes; i++) { 97 + dev_info(&phy->dev, "lane number %d, val %d\n", i, priv->lanes[i]); 98 + if (priv->lanes[i] > 1) 99 + bifurcation = true; 100 + } 101 + 102 + /* Set bifurcation if needed, and it doesn't care RC/EP */ 103 + if (bifurcation) { 104 + dev_info(&phy->dev, "bifurcation enabled\n"); 105 + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, 106 + GRF_PCIE30PHY_WR_EN | RK3568_BIFURCATION_LANE_0_1); 107 + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1, 108 + GRF_PCIE30PHY_DA_OCM); 109 + } else { 110 + dev_dbg(&phy->dev, "bifurcation disabled\n"); 111 + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, 112 + GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1); 113 + } 114 + 115 + reset_control_deassert(priv->p30phy); 116 + 117 + ret = regmap_read_poll_timeout(priv->phy_grf, 118 + GRF_PCIE30PHY_STATUS0, 119 + reg, SRAM_INIT_DONE(reg), 120 + 0, 500); 121 + if (ret) 122 + dev_err(&priv->phy->dev, "%s: lock failed 0x%x, check input refclk and power supply\n", 123 + __func__, reg); 124 + return ret; 125 + } 126 + 127 + static const struct rockchip_p3phy_ops rk3568_ops = { 128 + .phy_init = rockchip_p3phy_rk3568_init, 129 + }; 130 + 131 + static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) 132 + { 133 + u32 reg = 0; 134 + u8 mode = 0; 135 + int ret; 136 + 137 + /* Deassert PCIe PMA output clamp mode */ 138 + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24)); 139 + 140 + /* Set bifurcation if needed */ 141 + for (int i = 0; i < priv->num_lanes; i++) { 142 + if (!priv->lanes[i]) 143 + mode |= (BIT(i) << 3); 144 + 145 + if (priv->lanes[i] > 1) 146 + mode |= (BIT(i) >> 1); 147 + } 148 + 149 + if (!mode) 150 + reg = RK3588_LANE_AGGREGATION; 151 + else { 152 + if (mode & (BIT(0) | BIT(1))) 153 + reg |= RK3588_BIFURCATION_LANE_0_1; 154 + 155 + if (mode & (BIT(2) | BIT(3))) 156 + reg |= RK3588_BIFURCATION_LANE_2_3; 157 + } 158 + 159 + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, (0x7<<16) | reg); 160 + 161 + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ 162 + if (!IS_ERR(priv->pipe_grf)) { 163 + reg = (mode & (BIT(6) | BIT(7))) >> 6; 164 + if (reg) 165 + regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, 166 + (reg << 16) | reg); 167 + } 168 + 169 + reset_control_deassert(priv->p30phy); 170 + 171 + ret = regmap_read_poll_timeout(priv->phy_grf, 172 + RK3588_PCIE3PHY_GRF_PHY0_STATUS1, 173 + reg, RK3588_SRAM_INIT_DONE(reg), 174 + 0, 500); 175 + ret |= regmap_read_poll_timeout(priv->phy_grf, 176 + RK3588_PCIE3PHY_GRF_PHY1_STATUS1, 177 + reg, RK3588_SRAM_INIT_DONE(reg), 178 + 0, 500); 179 + if (ret) 180 + dev_err(&priv->phy->dev, "lock failed 0x%x, check input refclk and power supply\n", 181 + reg); 182 + return ret; 183 + } 184 + 185 + static const struct rockchip_p3phy_ops rk3588_ops = { 186 + .phy_init = rockchip_p3phy_rk3588_init, 187 + }; 188 + 189 + static int rochchip_p3phy_init(struct phy *phy) 190 + { 191 + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); 192 + int ret; 193 + 194 + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); 195 + if (ret) { 196 + dev_err(&priv->phy->dev, "failed to enable PCIe bulk clks %d\n", ret); 197 + return ret; 198 + } 199 + 200 + reset_control_assert(priv->p30phy); 201 + udelay(1); 202 + 203 + if (priv->ops->phy_init) { 204 + ret = priv->ops->phy_init(priv); 205 + if (ret) 206 + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); 207 + } 208 + 209 + return ret; 210 + } 211 + 212 + static int rochchip_p3phy_exit(struct phy *phy) 213 + { 214 + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); 215 + 216 + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); 217 + reset_control_assert(priv->p30phy); 218 + return 0; 219 + } 220 + 221 + static const struct phy_ops rochchip_p3phy_ops = { 222 + .init = rochchip_p3phy_init, 223 + .exit = rochchip_p3phy_exit, 224 + .set_mode = rockchip_p3phy_set_mode, 225 + .owner = THIS_MODULE, 226 + }; 227 + 228 + static int rockchip_p3phy_probe(struct platform_device *pdev) 229 + { 230 + struct phy_provider *phy_provider; 231 + struct device *dev = &pdev->dev; 232 + struct rockchip_p3phy_priv *priv; 233 + struct device_node *np = dev->of_node; 234 + struct resource *res; 235 + int ret; 236 + 237 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 238 + if (!priv) 239 + return -ENOMEM; 240 + 241 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 242 + priv->mmio = devm_ioremap_resource(dev, res); 243 + if (IS_ERR(priv->mmio)) { 244 + ret = PTR_ERR(priv->mmio); 245 + return ret; 246 + } 247 + 248 + priv->ops = of_device_get_match_data(&pdev->dev); 249 + if (!priv->ops) { 250 + dev_err(dev, "no of match data provided\n"); 251 + return -EINVAL; 252 + } 253 + 254 + priv->phy_grf = syscon_regmap_lookup_by_phandle(np, "rockchip,phy-grf"); 255 + if (IS_ERR(priv->phy_grf)) { 256 + dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); 257 + return PTR_ERR(priv->phy_grf); 258 + } 259 + 260 + priv->pipe_grf = syscon_regmap_lookup_by_phandle(dev->of_node, 261 + "rockchip,pipe-grf"); 262 + if (IS_ERR(priv->pipe_grf)) 263 + dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); 264 + 265 + priv->num_lanes = of_property_read_variable_u32_array(dev->of_node, "data-lanes", 266 + priv->lanes, 2, 267 + ARRAY_SIZE(priv->lanes)); 268 + 269 + /* if no data-lanes assume aggregation */ 270 + if (priv->num_lanes == -EINVAL) { 271 + dev_dbg(dev, "no data-lanes property found\n"); 272 + priv->num_lanes = 1; 273 + priv->lanes[0] = 1; 274 + } else if (priv->num_lanes < 0) { 275 + dev_err(dev, "failed to read data-lanes property %d\n", priv->num_lanes); 276 + return priv->num_lanes; 277 + } 278 + 279 + priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); 280 + if (IS_ERR(priv->phy)) { 281 + dev_err(dev, "failed to create combphy\n"); 282 + return PTR_ERR(priv->phy); 283 + } 284 + 285 + priv->p30phy = devm_reset_control_get_optional_exclusive(dev, "phy"); 286 + if (IS_ERR(priv->p30phy)) { 287 + return dev_err_probe(dev, PTR_ERR(priv->p30phy), 288 + "failed to get phy reset control\n"); 289 + } 290 + if (!priv->p30phy) 291 + dev_info(dev, "no phy reset control specified\n"); 292 + 293 + priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks); 294 + if (priv->num_clks < 1) 295 + return -ENODEV; 296 + 297 + dev_set_drvdata(dev, priv); 298 + phy_set_drvdata(priv->phy, priv); 299 + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 300 + return PTR_ERR_OR_ZERO(phy_provider); 301 + } 302 + 303 + static const struct of_device_id rockchip_p3phy_of_match[] = { 304 + { .compatible = "rockchip,rk3568-pcie3-phy", .data = &rk3568_ops }, 305 + { .compatible = "rockchip,rk3588-pcie3-phy", .data = &rk3588_ops }, 306 + { }, 307 + }; 308 + MODULE_DEVICE_TABLE(of, rockchip_p3phy_of_match); 309 + 310 + static struct platform_driver rockchip_p3phy_driver = { 311 + .probe = rockchip_p3phy_probe, 312 + .driver = { 313 + .name = "rockchip-snps-pcie3-phy", 314 + .of_match_table = rockchip_p3phy_of_match, 315 + }, 316 + }; 317 + module_platform_driver(rockchip_p3phy_driver); 318 + MODULE_DESCRIPTION("Rockchip Synopsys PCIe 3.0 PHY driver"); 319 + MODULE_LICENSE("GPL");
+12
include/linux/phy/pcie.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. 4 + */ 5 + #ifndef __PHY_PCIE_H 6 + #define __PHY_PCIE_H 7 + 8 + #define PHY_MODE_PCIE_RC 20 9 + #define PHY_MODE_PCIE_EP 21 10 + #define PHY_MODE_PCIE_BIFURCATION 22 11 + 12 + #endif