1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Rockchip PCIE3.0 phy driver 4 * 5 * Copyright (C) 2021 Rockchip Electronics Co., Ltd. 6 */ 7 8 #include <common.h> 9 #include <clk.h> 10 #include <dm.h> 11 #include <dm/lists.h> 12 #include <generic-phy.h> 13 #include <syscon.h> 14 #include <asm/io.h> 15 #include <asm/arch/clock.h> 16 #include <regmap.h> 17 #include <reset-uclass.h> 18 19 /* Register for RK3568 */ 20 #define GRF_PCIE30PHY_RK3568_CON1 0x4 21 #define GRF_PCIE30PHY_RK3568_CON6 0x18 22 #define GRF_PCIE30PHY_RK3568_CON9 0x24 23 24 /* Register for RK3588 */ 25 #define PHP_GRF_PCIESEL_CON 0x100 26 #define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 27 #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 28 #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 29 30 /* 31 * pcie30_phy_mode[2:0] 32 * bit2: aggregation 33 * bit1: bifurcation for port 1 34 * bit0: bifurcation for port 0 35 */ 36 #define PHY_MODE_PCIE_AGGREGATION 4 /* PCIe3x4 */ 37 #define PHY_MODE_PCIE_NANBNB 0 /* P1:PCIe3x2 + P0:PCIe3x2 */ 38 #define PHY_MODE_PCIE_NANBBI 1 /* P1:PCIe3x2 + P0:PCIe3x1*2 */ 39 #define PHY_MODE_PCIE_NABINB 2 /* P1:PCIe3x1*2 + P0:PCIe3x2 */ 40 #define PHY_MODE_PCIE_NABIBI 3 /* P1:PCIe3x1*2 + P0:PCIe3x1*2 */ 41 42 struct rockchip_p3phy_ops; 43 44 struct rockchip_p3phy_priv { 45 const struct rockchip_p3phy_ops *ops; 46 struct clk_bulk clks; 47 void __iomem *mmio; 48 int mode; 49 struct regmap *phy_grf; 50 struct regmap *pipe_grf; 51 struct reset_ctl p30phy; 52 bool is_bifurcation; 53 /* pcie30_phymode: Aggregation, Bifurcation */ 54 int pcie30_phymode; 55 }; 56 57 struct rockchip_p3phy_ops { 58 int (*phy_init)(struct rockchip_p3phy_priv *priv); 59 }; 60 61 static int rockchip_p3phy_rk3568_init(struct rockchip_p3phy_priv *priv) 62 { 63 /* Deassert PCIe PMA output clamp mode */ 64 regmap_write(priv->phy_grf, GRF_PCIE30PHY_RK3568_CON9, 65 (0x1 << 15) | (0x1 << 31)); 66 67 /* Set bifurcation if needed */ 68 if (priv->is_bifurcation) { 69 regmap_write(priv->phy_grf, GRF_PCIE30PHY_RK3568_CON6, 70 0x1 | (0xf << 16)); 71 regmap_write(priv->phy_grf, GRF_PCIE30PHY_RK3568_CON1, 72 (0x1 << 15) | (0x1 << 31)); 73 } 74 75 reset_deassert(&priv->p30phy); 76 udelay(5); 77 78 /* Updata RX VCO calibration controls */ 79 writel(0x2800, priv->mmio + (0x104a << 2)); 80 writel(0x2800, priv->mmio + (0x114a << 2)); 81 udelay(10); 82 83 return 0; 84 } 85 86 static const struct rockchip_p3phy_ops rk3568_ops = { 87 .phy_init = &rockchip_p3phy_rk3568_init, 88 }; 89 90 static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) 91 { 92 u32 reg; 93 u32 timeout; 94 95 /* Deassert PCIe PMA output clamp mode */ 96 regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, 97 (0x1 << 8) | (0x1 << 24)); 98 99 /* Select correct pcie30_phymode */ 100 if (priv->pcie30_phymode > 4) 101 priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; 102 103 regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, 104 (0x7<<16) | priv->pcie30_phymode); 105 106 /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ 107 reg = priv->pcie30_phymode & 3; 108 if (reg) 109 regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, 110 (reg << 16) | reg); 111 112 timeout = 500; 113 while (timeout--) { 114 regmap_read(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_STATUS1, ®); 115 if (reg & 0x1) 116 break; 117 udelay(1); 118 } 119 120 if (timeout <= 0) { 121 pr_err("%s: phy0 lock failed, check input refclk and power supply\n", __func__); 122 return -ETIMEDOUT; 123 } 124 125 timeout = 500; 126 while (timeout--) { 127 regmap_read(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_STATUS1, ®); 128 if (reg & 0x1) 129 break; 130 udelay(1); 131 } 132 133 if (timeout <= 0) { 134 pr_err("%s: phy1 lock failed, check input refclk and power supply\n", __func__); 135 return -ETIMEDOUT; 136 } 137 138 reset_deassert(&priv->p30phy); 139 udelay(5); 140 141 return 0; 142 } 143 144 static const struct rockchip_p3phy_ops rk3588_ops = { 145 .phy_init = &rockchip_p3phy_rk3588_init, 146 }; 147 148 static int rochchip_p3phy_init(struct phy *phy) 149 { 150 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); 151 int ret; 152 153 ret = clk_enable_bulk(&priv->clks); 154 if (ret) { 155 pr_err("failed to enable clks (ret=%d)\n", ret); 156 return ret; 157 } 158 159 reset_assert(&priv->p30phy); 160 udelay(1); 161 162 if (priv->ops->phy_init) { 163 ret = priv->ops->phy_init(priv); 164 if (ret) { 165 clk_disable_bulk(&priv->clks); 166 return ret; 167 } 168 169 } 170 171 return 0; 172 } 173 174 static int rochchip_p3phy_exit(struct phy *phy) 175 { 176 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); 177 178 clk_disable_bulk(&priv->clks); 179 reset_assert(&priv->p30phy); 180 return 0; 181 } 182 183 static int rockchip_p3phy_probe(struct udevice *dev) 184 { 185 struct rockchip_p3phy_priv *priv = dev_get_priv(dev); 186 dev_get_driver_data(dev); 187 struct udevice *syscon; 188 int ret; 189 190 priv->mmio = (void __iomem *)dev_read_addr(dev); 191 if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE) 192 return -EINVAL; 193 194 priv->ops = (struct rockchip_p3phy_ops *)dev_get_driver_data(dev); 195 if (!priv->ops) { 196 dev_err(dev, "no of match data provided\n"); 197 return -EINVAL; 198 } 199 200 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 201 "rockchip,phy-grf", &syscon); 202 if (ret) { 203 pr_err("unable to find syscon device for rockchip,phy-grf\n"); 204 return ret; 205 } 206 207 priv->phy_grf = syscon_get_regmap(syscon); 208 if (IS_ERR(priv->phy_grf)) { 209 dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); 210 return PTR_ERR(priv->phy_grf); 211 } 212 213 dev_dbg(priv->dev, "phy_grf is 0x%llx\n", priv->phy_grf->base); 214 215 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 216 "rockchip,pipe-grf", &syscon); 217 if (ret) { 218 /* It's optional, rk3568 doesn't need it */ 219 priv->pipe_grf = NULL; 220 pr_err("unable to get syscon device for rockchip,pipe-grf\n"); 221 goto skip_pipe_grf; 222 } 223 224 priv->pipe_grf = syscon_get_regmap(syscon); 225 if (IS_ERR(priv->pipe_grf)) 226 dev_err(dev, "failed to find rockchip,pipe_grf regmap\n"); 227 228 229 priv->pcie30_phymode = dev_read_u32_default(dev, "rockchip,pcie30-phymode", PHY_MODE_PCIE_AGGREGATION); 230 231 skip_pipe_grf: 232 ret = reset_get_by_name(dev, "phy", &priv->p30phy); 233 if (ret) { 234 dev_err(dev, "no phy reset control specified\n"); 235 return ret; 236 } 237 238 if (ret) { 239 dev_err(dev, "Can't get clock: %d\n", ret); 240 return ret; 241 } 242 243 return 0; 244 } 245 246 static int rockchip_p3phy_configure(struct phy *phy, union phy_configure_opts *opts) 247 { 248 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); 249 250 priv->is_bifurcation = opts->pcie.is_bifurcation; 251 252 return 0; 253 } 254 255 static struct phy_ops rochchip_p3phy_ops = { 256 .init = rochchip_p3phy_init, 257 .exit = rochchip_p3phy_exit, 258 .configure = rockchip_p3phy_configure, 259 }; 260 261 static const struct udevice_id rockchip_p3phy_of_match[] = { 262 { .compatible = "rockchip,rk3568-pcie3-phy", .data = (ulong)&rk3568_ops}, 263 { .compatible = "rockchip,rk3588-pcie3-phy", .data = (ulong)&rk3588_ops }, 264 { }, 265 }; 266 267 U_BOOT_DRIVER(rockchip_pcie3phy) = { 268 .name = "rockchip_pcie3phy", 269 .id = UCLASS_PHY, 270 .of_match = rockchip_p3phy_of_match, 271 .ops = &rochchip_p3phy_ops, 272 .probe = rockchip_p3phy_probe, 273 .priv_auto_alloc_size = sizeof(struct rockchip_p3phy_priv), 274 }; 275