.. | .. |
---|
13 | 13 | #include <linux/mfd/syscon.h> |
---|
14 | 14 | #include <linux/module.h> |
---|
15 | 15 | #include <linux/of_device.h> |
---|
| 16 | +#include <linux/phy/pcie.h> |
---|
16 | 17 | #include <linux/phy/phy.h> |
---|
17 | 18 | #include <linux/regmap.h> |
---|
18 | 19 | #include <linux/reset.h> |
---|
19 | | -#include <dt-bindings/phy/phy.h> |
---|
| 20 | +#include <dt-bindings/phy/phy-snps-pcie3.h> |
---|
20 | 21 | |
---|
| 22 | +/* Register for RK3568 */ |
---|
21 | 23 | #define GRF_PCIE30PHY_CON1 0x4 |
---|
22 | 24 | #define GRF_PCIE30PHY_CON4 0x10 |
---|
23 | 25 | #define GRF_PCIE30PHY_CON6 0x18 |
---|
.. | .. |
---|
25 | 27 | #define GRF_PCIE30PHY_STATUS0 0x80 |
---|
26 | 28 | #define SRAM_INIT_DONE(reg) (reg & BIT(14)) |
---|
27 | 29 | |
---|
| 30 | +/* Register for RK3588 */ |
---|
| 31 | +#define PHP_GRF_PCIESEL_CON 0x100 |
---|
| 32 | +#define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 |
---|
| 33 | +#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 |
---|
| 34 | +#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 |
---|
| 35 | +#define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) |
---|
| 36 | + |
---|
| 37 | +struct rockchip_p3phy_ops; |
---|
| 38 | + |
---|
28 | 39 | struct rockchip_p3phy_priv { |
---|
| 40 | + const struct rockchip_p3phy_ops *ops; |
---|
29 | 41 | void __iomem *mmio; |
---|
| 42 | + /* mode: RC, EP */ |
---|
30 | 43 | int mode; |
---|
| 44 | + /* pcie30_phymode: Aggregation, Bifurcation */ |
---|
| 45 | + int pcie30_phymode; |
---|
31 | 46 | struct regmap *phy_grf; |
---|
| 47 | + struct regmap *pipe_grf; |
---|
32 | 48 | struct reset_control *p30phy; |
---|
33 | | - struct clk *ref_clk_m; |
---|
34 | | - struct clk *ref_clk_n; |
---|
35 | | - struct clk *pclk; |
---|
36 | 49 | struct phy *phy; |
---|
| 50 | + struct clk_bulk_data *clks; |
---|
| 51 | + int num_clks; |
---|
37 | 52 | bool is_bifurcation; |
---|
38 | 53 | }; |
---|
39 | 54 | |
---|
40 | | -static int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode) |
---|
| 55 | +struct rockchip_p3phy_ops { |
---|
| 56 | + int (*phy_init)(struct rockchip_p3phy_priv *priv); |
---|
| 57 | +}; |
---|
| 58 | + |
---|
| 59 | +static int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) |
---|
41 | 60 | { |
---|
42 | 61 | struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); |
---|
43 | 62 | |
---|
44 | 63 | /* Acutally We don't care EP/RC mode, but just record it */ |
---|
45 | | - switch (mode) { |
---|
| 64 | + switch (submode) { |
---|
46 | 65 | case PHY_MODE_PCIE_RC: |
---|
47 | 66 | priv->mode = PHY_MODE_PCIE_RC; |
---|
48 | 67 | break; |
---|
.. | .. |
---|
64 | 83 | #include "phy-rockchip-snps-pcie3.fw" |
---|
65 | 84 | }; |
---|
66 | 85 | |
---|
67 | | -static int rochchip_p3phy_init(struct phy *phy) |
---|
| 86 | +static int rockchip_p3phy_rk3568_init(struct rockchip_p3phy_priv *priv) |
---|
68 | 87 | { |
---|
69 | | - struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); |
---|
70 | 88 | int i; |
---|
71 | 89 | int ret = 0; |
---|
72 | 90 | u32 reg; |
---|
73 | | - |
---|
74 | | - ret = clk_prepare_enable(priv->ref_clk_m); |
---|
75 | | - if (ret < 0) |
---|
76 | | - return ret; |
---|
77 | | - |
---|
78 | | - ret = clk_prepare_enable(priv->ref_clk_n); |
---|
79 | | - if (ret < 0) |
---|
80 | | - goto err_ref; |
---|
81 | | - |
---|
82 | | - ret = clk_prepare_enable(priv->pclk); |
---|
83 | | - if (ret < 0) |
---|
84 | | - goto err_pclk; |
---|
85 | | - |
---|
86 | | - reset_control_assert(priv->p30phy); |
---|
87 | | - udelay(1); |
---|
88 | 91 | |
---|
89 | 92 | /* Deassert PCIe PMA output clamp mode */ |
---|
90 | 93 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, |
---|
.. | .. |
---|
96 | 99 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1, |
---|
97 | 100 | (0x1 << 15) | (0x1 << 31)); |
---|
98 | 101 | } |
---|
99 | | - |
---|
100 | 102 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON4, |
---|
101 | 103 | (0x0 << 14) | (0x1 << (14 + 16))); //sdram_ld_done |
---|
102 | 104 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON4, |
---|
103 | 105 | (0x0 << 13) | (0x1 << (13 + 16))); //sdram_bypass |
---|
104 | | - reset_control_deassert(priv->p30phy); |
---|
105 | 106 | |
---|
| 107 | + reset_control_deassert(priv->p30phy); |
---|
106 | 108 | ret = regmap_read_poll_timeout(priv->phy_grf, |
---|
107 | 109 | GRF_PCIE30PHY_STATUS0, |
---|
108 | 110 | reg, SRAM_INIT_DONE(reg), |
---|
.. | .. |
---|
110 | 112 | if (ret) { |
---|
111 | 113 | pr_err("%s: lock failed 0x%x, check input refclk and power supply\n", |
---|
112 | 114 | __func__, reg); |
---|
113 | | - goto err_pclk; |
---|
| 115 | + goto out; |
---|
114 | 116 | } |
---|
115 | 117 | |
---|
116 | 118 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, |
---|
.. | .. |
---|
124 | 126 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON4, |
---|
125 | 127 | (0x1 << 14) | (0x1 << (14 + 16))); //sdram_ld_done |
---|
126 | 128 | |
---|
127 | | - return 0; |
---|
128 | | -err_pclk: |
---|
129 | | - clk_disable_unprepare(priv->ref_clk_n); |
---|
130 | | -err_ref: |
---|
131 | | - clk_disable_unprepare(priv->ref_clk_m); |
---|
| 129 | +out: |
---|
| 130 | + return ret; |
---|
| 131 | +} |
---|
| 132 | + |
---|
| 133 | +static const struct rockchip_p3phy_ops rk3568_ops = { |
---|
| 134 | + .phy_init = rockchip_p3phy_rk3568_init, |
---|
| 135 | +}; |
---|
| 136 | + |
---|
| 137 | +static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) |
---|
| 138 | +{ |
---|
| 139 | + int ret = 0; |
---|
| 140 | + u32 reg; |
---|
| 141 | + |
---|
| 142 | + /* Deassert PCIe PMA output clamp mode */ |
---|
| 143 | + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, |
---|
| 144 | + (0x1 << 8) | (0x1 << 24)); |
---|
| 145 | + |
---|
| 146 | + reset_control_deassert(priv->p30phy); |
---|
| 147 | + |
---|
| 148 | + ret = regmap_read_poll_timeout(priv->phy_grf, |
---|
| 149 | + RK3588_PCIE3PHY_GRF_PHY0_STATUS1, |
---|
| 150 | + reg, RK3588_SRAM_INIT_DONE(reg), |
---|
| 151 | + 0, 500); |
---|
| 152 | + ret |= regmap_read_poll_timeout(priv->phy_grf, |
---|
| 153 | + RK3588_PCIE3PHY_GRF_PHY1_STATUS1, |
---|
| 154 | + reg, RK3588_SRAM_INIT_DONE(reg), |
---|
| 155 | + 0, 500); |
---|
| 156 | + if (ret) |
---|
| 157 | + pr_err("%s: lock failed 0x%x, check input refclk and power supply\n", |
---|
| 158 | + __func__, reg); |
---|
| 159 | + return ret; |
---|
| 160 | +} |
---|
| 161 | + |
---|
| 162 | +static const struct rockchip_p3phy_ops rk3588_ops = { |
---|
| 163 | + .phy_init = rockchip_p3phy_rk3588_init, |
---|
| 164 | +}; |
---|
| 165 | + |
---|
| 166 | +static int rochchip_p3phy_init(struct phy *phy) |
---|
| 167 | +{ |
---|
| 168 | + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); |
---|
| 169 | + int ret; |
---|
| 170 | + |
---|
| 171 | + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); |
---|
| 172 | + if (ret) { |
---|
| 173 | + pr_err("failed to enable PCIe bulk clks %d\n", ret); |
---|
| 174 | + return ret; |
---|
| 175 | + } |
---|
| 176 | + |
---|
| 177 | + reset_control_assert(priv->p30phy); |
---|
| 178 | + udelay(1); |
---|
| 179 | + |
---|
| 180 | + if (priv->ops->phy_init) { |
---|
| 181 | + ret = priv->ops->phy_init(priv); |
---|
| 182 | + if (ret) |
---|
| 183 | + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); |
---|
| 184 | + }; |
---|
| 185 | + |
---|
132 | 186 | return ret; |
---|
133 | 187 | } |
---|
134 | 188 | |
---|
135 | 189 | static int rochchip_p3phy_exit(struct phy *phy) |
---|
136 | 190 | { |
---|
137 | 191 | struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); |
---|
138 | | - clk_disable_unprepare(priv->ref_clk_m); |
---|
139 | | - clk_disable_unprepare(priv->ref_clk_n); |
---|
140 | | - clk_disable_unprepare(priv->pclk); |
---|
| 192 | + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); |
---|
141 | 193 | reset_control_assert(priv->p30phy); |
---|
142 | 194 | return 0; |
---|
143 | 195 | } |
---|
.. | .. |
---|
157 | 209 | struct device_node *np = dev->of_node; |
---|
158 | 210 | struct resource *res; |
---|
159 | 211 | int ret; |
---|
| 212 | + u32 val, reg; |
---|
160 | 213 | |
---|
161 | 214 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
---|
162 | 215 | if (!priv) |
---|
.. | .. |
---|
169 | 222 | return ret; |
---|
170 | 223 | } |
---|
171 | 224 | |
---|
| 225 | + priv->ops = of_device_get_match_data(&pdev->dev); |
---|
| 226 | + if (!priv->ops) { |
---|
| 227 | + dev_err(&pdev->dev, "no of match data provided\n"); |
---|
| 228 | + return -EINVAL; |
---|
| 229 | + } |
---|
| 230 | + |
---|
172 | 231 | priv->phy_grf = syscon_regmap_lookup_by_phandle(np, "rockchip,phy-grf"); |
---|
173 | 232 | if (IS_ERR(priv->phy_grf)) { |
---|
174 | 233 | dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); |
---|
175 | 234 | return PTR_ERR(priv->phy_grf); |
---|
176 | 235 | } |
---|
| 236 | + |
---|
| 237 | + priv->pipe_grf = syscon_regmap_lookup_by_phandle(dev->of_node, |
---|
| 238 | + "rockchip,pipe-grf"); |
---|
| 239 | + if (IS_ERR(priv->pipe_grf)) |
---|
| 240 | + dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); |
---|
| 241 | + |
---|
| 242 | + ret = device_property_read_u32(dev, "rockchip,pcie30-phymode", &val); |
---|
| 243 | + if (!ret) |
---|
| 244 | + priv->pcie30_phymode = val; |
---|
| 245 | + else |
---|
| 246 | + priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; |
---|
| 247 | + |
---|
| 248 | + /* Select correct pcie30_phymode */ |
---|
| 249 | + if (priv->pcie30_phymode > 4) |
---|
| 250 | + priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; |
---|
| 251 | + |
---|
| 252 | + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, |
---|
| 253 | + (0x7<<16) | priv->pcie30_phymode); |
---|
| 254 | + |
---|
| 255 | + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ |
---|
| 256 | + if (!IS_ERR(priv->pipe_grf)) { |
---|
| 257 | + reg = priv->pcie30_phymode & 3; |
---|
| 258 | + if (reg) |
---|
| 259 | + regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, |
---|
| 260 | + (reg << 16) | reg); |
---|
| 261 | + }; |
---|
177 | 262 | |
---|
178 | 263 | priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); |
---|
179 | 264 | if (IS_ERR(priv->phy)) { |
---|
.. | .. |
---|
187 | 272 | priv->p30phy = NULL; |
---|
188 | 273 | } |
---|
189 | 274 | |
---|
190 | | - priv->ref_clk_m = devm_clk_get(dev, "refclk_m"); |
---|
191 | | - if (IS_ERR(priv->ref_clk_m)) { |
---|
192 | | - dev_err(dev, "failed to find ref clock M\n"); |
---|
193 | | - return PTR_ERR(priv->ref_clk_m); |
---|
194 | | - } |
---|
195 | | - |
---|
196 | | - priv->ref_clk_n = devm_clk_get(dev, "refclk_n"); |
---|
197 | | - if (IS_ERR(priv->ref_clk_n)) { |
---|
198 | | - dev_err(dev, "failed to find ref clock N\n"); |
---|
199 | | - return PTR_ERR(priv->ref_clk_n); |
---|
200 | | - } |
---|
201 | | - |
---|
202 | | - priv->pclk = devm_clk_get(dev, "pclk"); |
---|
203 | | - if (IS_ERR(priv->pclk)) { |
---|
204 | | - dev_err(dev, "failed to find pclk\n"); |
---|
205 | | - return PTR_ERR(priv->pclk); |
---|
206 | | - } |
---|
| 275 | + priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks); |
---|
| 276 | + if (priv->num_clks < 1) |
---|
| 277 | + return -ENODEV; |
---|
207 | 278 | |
---|
208 | 279 | dev_set_drvdata(dev, priv); |
---|
209 | 280 | phy_set_drvdata(priv->phy, priv); |
---|
.. | .. |
---|
212 | 283 | } |
---|
213 | 284 | |
---|
214 | 285 | static const struct of_device_id rockchip_p3phy_of_match[] = { |
---|
215 | | - { .compatible = "rockchip,rk3568-pcie3-phy" }, |
---|
| 286 | + { .compatible = "rockchip,rk3568-pcie3-phy", .data = &rk3568_ops }, |
---|
| 287 | + { .compatible = "rockchip,rk3588-pcie3-phy", .data = &rk3588_ops }, |
---|
216 | 288 | { }, |
---|
217 | 289 | }; |
---|
218 | 290 | MODULE_DEVICE_TABLE(of, rockchip_p3phy_of_match); |
---|