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