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 return 0; 76 } 77 78 static const struct rockchip_p3phy_ops rk3568_ops = { 79 .phy_init = &rockchip_p3phy_rk3568_init, 80 }; 81 82 static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) 83 { 84 u32 reg; 85 u32 timeout; 86 87 /* Deassert PCIe PMA output clamp mode */ 88 regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, 89 (0x1 << 8) | (0x1 << 24)); 90 91 /* Select correct pcie30_phymode */ 92 if (priv->pcie30_phymode > 4) 93 priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; 94 95 regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, 96 (0x7<<16) | priv->pcie30_phymode); 97 98 /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ 99 reg = priv->pcie30_phymode & 3; 100 if (reg) 101 regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, 102 (reg << 16) | reg); 103 104 timeout = 500; 105 while (timeout--) { 106 regmap_read(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_STATUS1, ®); 107 if (reg & 0x1) 108 break; 109 udelay(1); 110 } 111 112 if (timeout <= 0) { 113 pr_err("%s: phy0 lock failed, check input refclk and power supply\n", __func__); 114 return -ETIMEDOUT; 115 } 116 117 timeout = 500; 118 while (timeout--) { 119 regmap_read(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_STATUS1, ®); 120 if (reg & 0x1) 121 break; 122 udelay(1); 123 } 124 125 if (timeout <= 0) { 126 pr_err("%s: phy1 lock failed, check input refclk and power supply\n", __func__); 127 return -ETIMEDOUT; 128 } 129 130 return 0; 131 } 132 133 static const struct rockchip_p3phy_ops rk3588_ops = { 134 .phy_init = &rockchip_p3phy_rk3588_init, 135 }; 136 137 static int rochchip_p3phy_init(struct phy *phy) 138 { 139 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); 140 int ret; 141 142 ret = clk_enable_bulk(&priv->clks); 143 if (ret) { 144 pr_err("failed to enable clks (ret=%d)\n", ret); 145 return ret; 146 } 147 148 reset_assert(&priv->p30phy); 149 udelay(1); 150 151 if (priv->ops->phy_init) { 152 ret = priv->ops->phy_init(priv); 153 if (ret) { 154 clk_disable_bulk(&priv->clks); 155 return ret; 156 } 157 158 } 159 160 reset_deassert(&priv->p30phy); 161 udelay(5); 162 163 return 0; 164 } 165 166 static int rochchip_p3phy_exit(struct phy *phy) 167 { 168 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); 169 170 clk_disable_bulk(&priv->clks); 171 reset_assert(&priv->p30phy); 172 return 0; 173 } 174 175 static int rockchip_p3phy_probe(struct udevice *dev) 176 { 177 struct rockchip_p3phy_priv *priv = dev_get_priv(dev); 178 dev_get_driver_data(dev); 179 struct udevice *syscon; 180 int ret; 181 182 priv->mmio = (void __iomem *)dev_read_addr(dev); 183 if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE) 184 return -EINVAL; 185 186 priv->ops = (struct rockchip_p3phy_ops *)dev_get_driver_data(dev); 187 if (!priv->ops) { 188 dev_err(dev, "no of match data provided\n"); 189 return -EINVAL; 190 } 191 192 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 193 "rockchip,phy-grf", &syscon); 194 if (ret) { 195 pr_err("unable to find syscon device for rockchip,phy-grf\n"); 196 return ret; 197 } 198 199 priv->phy_grf = syscon_get_regmap(syscon); 200 if (IS_ERR(priv->phy_grf)) { 201 dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); 202 return PTR_ERR(priv->phy_grf); 203 } 204 205 dev_dbg(priv->dev, "phy_grf is 0x%llx\n", priv->phy_grf->base); 206 207 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 208 "rockchip,pipe-grf", &syscon); 209 if (ret) { 210 /* It's optional, rk3568 doesn't need it */ 211 priv->pipe_grf = NULL; 212 pr_err("unable to get syscon device for rockchip,pipe-grf\n"); 213 goto skip_pipe_grf; 214 } 215 216 priv->pipe_grf = syscon_get_regmap(syscon); 217 if (IS_ERR(priv->pipe_grf)) 218 dev_err(dev, "failed to find rockchip,pipe_grf regmap\n"); 219 220 221 priv->pcie30_phymode = dev_read_u32_default(dev, "rockchip,pcie30-phymode", PHY_MODE_PCIE_AGGREGATION); 222 223 skip_pipe_grf: 224 ret = reset_get_by_name(dev, "phy", &priv->p30phy); 225 if (ret) { 226 dev_err(dev, "no phy reset control specified\n"); 227 return ret; 228 } 229 230 if (ret) { 231 dev_err(dev, "Can't get clock: %d\n", ret); 232 return ret; 233 } 234 235 return 0; 236 } 237 238 static int rockchip_p3phy_configure(struct phy *phy, union phy_configure_opts *opts) 239 { 240 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev); 241 242 priv->is_bifurcation = opts->pcie.is_bifurcation; 243 244 return 0; 245 } 246 247 static struct phy_ops rochchip_p3phy_ops = { 248 .init = rochchip_p3phy_init, 249 .exit = rochchip_p3phy_exit, 250 .configure = rockchip_p3phy_configure, 251 }; 252 253 static const struct udevice_id rockchip_p3phy_of_match[] = { 254 { .compatible = "rockchip,rk3568-pcie3-phy", .data = (ulong)&rk3568_ops}, 255 { .compatible = "rockchip,rk3588-pcie3-phy", .data = (ulong)&rk3588_ops }, 256 { }, 257 }; 258 259 U_BOOT_DRIVER(rockchip_pcie3phy) = { 260 .name = "rockchip_pcie3phy", 261 .id = UCLASS_PHY, 262 .of_match = rockchip_p3phy_of_match, 263 .ops = &rochchip_p3phy_ops, 264 .probe = rockchip_p3phy_probe, 265 .priv_auto_alloc_size = sizeof(struct rockchip_p3phy_priv), 266 }; 267