1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Amlogic G12A USB3 + PCIE Combo PHY driver |
4 | * |
5 | * Copyright (C) 2017 Amlogic, Inc. All rights reserved |
6 | * Copyright (C) 2019 BayLibre, SAS |
7 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
8 | */ |
9 | |
10 | #include <linux/bitfield.h> |
11 | #include <linux/bitops.h> |
12 | #include <linux/clk.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of.h> |
15 | #include <linux/phy/phy.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/reset.h> |
18 | #include <linux/platform_device.h> |
19 | #include <dt-bindings/phy/phy.h> |
20 | |
21 | #define PHY_R0 0x00 |
22 | #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0) |
23 | #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5) |
24 | |
25 | #define PHY_R1 0x04 |
26 | #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0) |
27 | #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5) |
28 | #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10) |
29 | #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13) |
30 | #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16) |
31 | #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21) |
32 | #define PHY_R1_PHY_REF_CLKDIV2 BIT(24) |
33 | #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25) |
34 | |
35 | #define PHY_R2 0x08 |
36 | #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0) |
37 | #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6) |
38 | #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12) |
39 | #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18) |
40 | |
41 | #define PHY_R4 0x10 |
42 | #define PHY_R4_PHY_CR_WRITE BIT(0) |
43 | #define PHY_R4_PHY_CR_READ BIT(1) |
44 | #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2) |
45 | #define PHY_R4_PHY_CR_CAP_DATA BIT(18) |
46 | #define PHY_R4_PHY_CR_CAP_ADDR BIT(19) |
47 | |
48 | #define PHY_R5 0x14 |
49 | #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0) |
50 | #define PHY_R5_PHY_CR_ACK BIT(16) |
51 | #define PHY_R5_PHY_BS_OUT BIT(17) |
52 | |
53 | #define PCIE_RESET_DELAY 500 |
54 | |
55 | struct phy_g12a_usb3_pcie_priv { |
56 | struct regmap *regmap; |
57 | struct regmap *regmap_cr; |
58 | struct clk *clk_ref; |
59 | struct reset_control *reset; |
60 | struct phy *phy; |
61 | unsigned int mode; |
62 | }; |
63 | |
64 | static const struct regmap_config phy_g12a_usb3_pcie_regmap_conf = { |
65 | .reg_bits = 8, |
66 | .val_bits = 32, |
67 | .reg_stride = 4, |
68 | .max_register = PHY_R5, |
69 | }; |
70 | |
71 | static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv, |
72 | unsigned int addr) |
73 | { |
74 | unsigned int val, reg; |
75 | int ret; |
76 | |
77 | reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr); |
78 | |
79 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
80 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
81 | |
82 | regmap_write(map: priv->regmap, PHY_R4, val: reg | PHY_R4_PHY_CR_CAP_ADDR); |
83 | |
84 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
85 | (val & PHY_R5_PHY_CR_ACK), |
86 | 5, 1000); |
87 | if (ret) |
88 | return ret; |
89 | |
90 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
91 | |
92 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
93 | !(val & PHY_R5_PHY_CR_ACK), |
94 | 5, 1000); |
95 | if (ret) |
96 | return ret; |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | static int phy_g12a_usb3_pcie_cr_bus_read(void *context, unsigned int addr, |
102 | unsigned int *data) |
103 | { |
104 | struct phy_g12a_usb3_pcie_priv *priv = context; |
105 | unsigned int val; |
106 | int ret; |
107 | |
108 | ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); |
109 | if (ret) |
110 | return ret; |
111 | |
112 | regmap_write(map: priv->regmap, PHY_R4, val: 0); |
113 | regmap_write(map: priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ); |
114 | |
115 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
116 | (val & PHY_R5_PHY_CR_ACK), |
117 | 5, 1000); |
118 | if (ret) |
119 | return ret; |
120 | |
121 | *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val); |
122 | |
123 | regmap_write(map: priv->regmap, PHY_R4, val: 0); |
124 | |
125 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
126 | !(val & PHY_R5_PHY_CR_ACK), |
127 | 5, 1000); |
128 | if (ret) |
129 | return ret; |
130 | |
131 | return 0; |
132 | } |
133 | |
134 | static int phy_g12a_usb3_pcie_cr_bus_write(void *context, unsigned int addr, |
135 | unsigned int data) |
136 | { |
137 | struct phy_g12a_usb3_pcie_priv *priv = context; |
138 | unsigned int val, reg; |
139 | int ret; |
140 | |
141 | ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); |
142 | if (ret) |
143 | return ret; |
144 | |
145 | reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data); |
146 | |
147 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
148 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
149 | |
150 | regmap_write(map: priv->regmap, PHY_R4, val: reg | PHY_R4_PHY_CR_CAP_DATA); |
151 | |
152 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
153 | (val & PHY_R5_PHY_CR_ACK), |
154 | 5, 1000); |
155 | if (ret) |
156 | return ret; |
157 | |
158 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
159 | |
160 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
161 | (val & PHY_R5_PHY_CR_ACK) == 0, |
162 | 5, 1000); |
163 | if (ret) |
164 | return ret; |
165 | |
166 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
167 | |
168 | regmap_write(map: priv->regmap, PHY_R4, val: reg | PHY_R4_PHY_CR_WRITE); |
169 | |
170 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
171 | (val & PHY_R5_PHY_CR_ACK), |
172 | 5, 1000); |
173 | if (ret) |
174 | return ret; |
175 | |
176 | regmap_write(map: priv->regmap, PHY_R4, val: reg); |
177 | |
178 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, |
179 | (val & PHY_R5_PHY_CR_ACK) == 0, |
180 | 5, 1000); |
181 | if (ret) |
182 | return ret; |
183 | |
184 | return 0; |
185 | } |
186 | |
187 | static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = { |
188 | .reg_bits = 16, |
189 | .val_bits = 16, |
190 | .reg_read = phy_g12a_usb3_pcie_cr_bus_read, |
191 | .reg_write = phy_g12a_usb3_pcie_cr_bus_write, |
192 | .max_register = 0xffff, |
193 | .disable_locking = true, |
194 | }; |
195 | |
196 | static int phy_g12a_usb3_init(struct phy *phy) |
197 | { |
198 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); |
199 | int data, ret; |
200 | |
201 | ret = reset_control_reset(rstc: priv->reset); |
202 | if (ret) |
203 | return ret; |
204 | |
205 | /* Switch PHY to USB3 */ |
206 | /* TODO figure out how to handle when PCIe was set in the bootloader */ |
207 | regmap_update_bits(map: priv->regmap, PHY_R0, |
208 | PHY_R0_PCIE_USB3_SWITCH, |
209 | PHY_R0_PCIE_USB3_SWITCH); |
210 | |
211 | /* |
212 | * WORKAROUND: There is SSPHY suspend bug due to |
213 | * which USB enumerates |
214 | * in HS mode instead of SS mode. Workaround it by asserting |
215 | * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus |
216 | * mode |
217 | */ |
218 | ret = regmap_update_bits(map: priv->regmap_cr, reg: 0x102d, BIT(7), BIT(7)); |
219 | if (ret) |
220 | return ret; |
221 | |
222 | ret = regmap_update_bits(map: priv->regmap_cr, reg: 0x1010, mask: 0xff0, val: 20); |
223 | if (ret) |
224 | return ret; |
225 | |
226 | /* |
227 | * Fix RX Equalization setting as follows |
228 | * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 |
229 | * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 |
230 | * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 |
231 | * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 |
232 | */ |
233 | ret = regmap_read(map: priv->regmap_cr, reg: 0x1006, val: &data); |
234 | if (ret) |
235 | return ret; |
236 | |
237 | data &= ~BIT(6); |
238 | data |= BIT(7); |
239 | data &= ~(0x7 << 8); |
240 | data |= (0x3 << 8); |
241 | data |= (1 << 11); |
242 | ret = regmap_write(map: priv->regmap_cr, reg: 0x1006, val: data); |
243 | if (ret) |
244 | return ret; |
245 | |
246 | /* |
247 | * Set EQ and TX launch amplitudes as follows |
248 | * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 |
249 | * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 |
250 | * LANE0.TX_OVRD_DRV_LO.EN set to 1. |
251 | */ |
252 | ret = regmap_read(map: priv->regmap_cr, reg: 0x1002, val: &data); |
253 | if (ret) |
254 | return ret; |
255 | |
256 | data &= ~0x3f80; |
257 | data |= (0x16 << 7); |
258 | data &= ~0x7f; |
259 | data |= (0x7f | BIT(14)); |
260 | ret = regmap_write(map: priv->regmap_cr, reg: 0x1002, val: data); |
261 | if (ret) |
262 | return ret; |
263 | |
264 | /* MPLL_LOOP_CTL.PROP_CNTRL = 8 */ |
265 | ret = regmap_update_bits(map: priv->regmap_cr, reg: 0x30, mask: 0xf << 4, val: 8 << 4); |
266 | if (ret) |
267 | return ret; |
268 | |
269 | regmap_update_bits(map: priv->regmap, PHY_R2, |
270 | PHY_R2_PHY_TX_VBOOST_LVL, |
271 | FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4)); |
272 | |
273 | regmap_update_bits(map: priv->regmap, PHY_R1, |
274 | PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL, |
275 | FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) | |
276 | FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9)); |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static int phy_g12a_usb3_pcie_power_on(struct phy *phy) |
282 | { |
283 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); |
284 | |
285 | if (priv->mode == PHY_TYPE_USB3) |
286 | return 0; |
287 | |
288 | regmap_update_bits(map: priv->regmap, PHY_R0, |
289 | PHY_R0_PCIE_POWER_STATE, |
290 | FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); |
291 | |
292 | return 0; |
293 | } |
294 | |
295 | static int phy_g12a_usb3_pcie_power_off(struct phy *phy) |
296 | { |
297 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); |
298 | |
299 | if (priv->mode == PHY_TYPE_USB3) |
300 | return 0; |
301 | |
302 | regmap_update_bits(map: priv->regmap, PHY_R0, |
303 | PHY_R0_PCIE_POWER_STATE, |
304 | FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d)); |
305 | |
306 | return 0; |
307 | } |
308 | |
309 | static int phy_g12a_usb3_pcie_reset(struct phy *phy) |
310 | { |
311 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); |
312 | int ret; |
313 | |
314 | if (priv->mode == PHY_TYPE_USB3) |
315 | return 0; |
316 | |
317 | ret = reset_control_assert(rstc: priv->reset); |
318 | if (ret) |
319 | return ret; |
320 | |
321 | udelay(PCIE_RESET_DELAY); |
322 | |
323 | ret = reset_control_deassert(rstc: priv->reset); |
324 | if (ret) |
325 | return ret; |
326 | |
327 | udelay(PCIE_RESET_DELAY); |
328 | |
329 | return 0; |
330 | } |
331 | |
332 | static int phy_g12a_usb3_pcie_init(struct phy *phy) |
333 | { |
334 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); |
335 | |
336 | if (priv->mode == PHY_TYPE_USB3) |
337 | return phy_g12a_usb3_init(phy); |
338 | |
339 | return 0; |
340 | } |
341 | |
342 | static int phy_g12a_usb3_pcie_exit(struct phy *phy) |
343 | { |
344 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); |
345 | |
346 | if (priv->mode == PHY_TYPE_USB3) |
347 | return reset_control_reset(rstc: priv->reset); |
348 | |
349 | return 0; |
350 | } |
351 | |
352 | static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, |
353 | const struct of_phandle_args *args) |
354 | { |
355 | struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); |
356 | unsigned int mode; |
357 | |
358 | if (args->args_count < 1) { |
359 | dev_err(dev, "invalid number of arguments\n" ); |
360 | return ERR_PTR(error: -EINVAL); |
361 | } |
362 | |
363 | mode = args->args[0]; |
364 | |
365 | if (mode != PHY_TYPE_USB3 && mode != PHY_TYPE_PCIE) { |
366 | dev_err(dev, "invalid phy mode select argument\n" ); |
367 | return ERR_PTR(error: -EINVAL); |
368 | } |
369 | |
370 | priv->mode = mode; |
371 | |
372 | return priv->phy; |
373 | } |
374 | |
375 | static const struct phy_ops phy_g12a_usb3_pcie_ops = { |
376 | .init = phy_g12a_usb3_pcie_init, |
377 | .exit = phy_g12a_usb3_pcie_exit, |
378 | .power_on = phy_g12a_usb3_pcie_power_on, |
379 | .power_off = phy_g12a_usb3_pcie_power_off, |
380 | .reset = phy_g12a_usb3_pcie_reset, |
381 | .owner = THIS_MODULE, |
382 | }; |
383 | |
384 | static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) |
385 | { |
386 | struct device *dev = &pdev->dev; |
387 | struct device_node *np = dev->of_node; |
388 | struct phy_g12a_usb3_pcie_priv *priv; |
389 | struct phy_provider *phy_provider; |
390 | void __iomem *base; |
391 | |
392 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
393 | if (!priv) |
394 | return -ENOMEM; |
395 | |
396 | base = devm_platform_ioremap_resource(pdev, index: 0); |
397 | if (IS_ERR(ptr: base)) |
398 | return PTR_ERR(ptr: base); |
399 | |
400 | priv->regmap = devm_regmap_init_mmio(dev, base, |
401 | &phy_g12a_usb3_pcie_regmap_conf); |
402 | if (IS_ERR(ptr: priv->regmap)) |
403 | return PTR_ERR(ptr: priv->regmap); |
404 | |
405 | priv->regmap_cr = devm_regmap_init(dev, NULL, priv, |
406 | &phy_g12a_usb3_pcie_cr_regmap_conf); |
407 | if (IS_ERR(ptr: priv->regmap_cr)) |
408 | return PTR_ERR(ptr: priv->regmap_cr); |
409 | |
410 | priv->clk_ref = devm_clk_get_enabled(dev, id: "ref_clk" ); |
411 | if (IS_ERR(ptr: priv->clk_ref)) |
412 | return PTR_ERR(ptr: priv->clk_ref); |
413 | |
414 | priv->reset = devm_reset_control_array_get_exclusive(dev); |
415 | if (IS_ERR(ptr: priv->reset)) |
416 | return PTR_ERR(ptr: priv->reset); |
417 | |
418 | priv->phy = devm_phy_create(dev, node: np, ops: &phy_g12a_usb3_pcie_ops); |
419 | if (IS_ERR(ptr: priv->phy)) |
420 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->phy), fmt: "failed to create PHY\n" ); |
421 | |
422 | phy_set_drvdata(phy: priv->phy, data: priv); |
423 | dev_set_drvdata(dev, data: priv); |
424 | |
425 | phy_provider = devm_of_phy_provider_register(dev, |
426 | phy_g12a_usb3_pcie_xlate); |
427 | return PTR_ERR_OR_ZERO(ptr: phy_provider); |
428 | } |
429 | |
430 | static const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { |
431 | { .compatible = "amlogic,g12a-usb3-pcie-phy" , }, |
432 | { }, |
433 | }; |
434 | MODULE_DEVICE_TABLE(of, phy_g12a_usb3_pcie_of_match); |
435 | |
436 | static struct platform_driver phy_g12a_usb3_pcie_driver = { |
437 | .probe = phy_g12a_usb3_pcie_probe, |
438 | .driver = { |
439 | .name = "phy-g12a-usb3-pcie" , |
440 | .of_match_table = phy_g12a_usb3_pcie_of_match, |
441 | }, |
442 | }; |
443 | module_platform_driver(phy_g12a_usb3_pcie_driver); |
444 | |
445 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>" ); |
446 | MODULE_DESCRIPTION("Amlogic G12A USB3 + PCIE Combo PHY driver" ); |
447 | MODULE_LICENSE("GPL v2" ); |
448 | |