blob: 82655f26dd6e1a40efa2a11affb1ff6ee0729cd5 [file] [log] [blame]
Neil Armstrong277d9162019-02-19 15:17:29 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Meson G12A USB3+PCIE Combo PHY driver
4 *
5 * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
6 * Copyright (C) 2019 BayLibre, SAS
7 * Author: Neil Armstrong <narmstron@baylibre.com>
8 */
9
10#include <common.h>
11#include <clk.h>
12#include <dm.h>
Simon Glass336d4612020-02-03 07:36:16 -070013#include <malloc.h>
Neil Armstrong277d9162019-02-19 15:17:29 +010014#include <regmap.h>
15#include <errno.h>
16#include <asm/io.h>
17#include <reset.h>
18#include <bitfield.h>
19#include <generic-phy.h>
20
21#include <linux/bitops.h>
22#include <linux/compat.h>
23#include <linux/bitfield.h>
24
25#define PHY_R0 0x00
26 #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0)
27 #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5)
28
29#define PHY_R1 0x04
30 #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0)
31 #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5)
32 #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10)
33 #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13)
34 #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16)
35 #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21)
36 #define PHY_R1_PHY_REF_CLKDIV2 BIT(24)
37 #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25)
38
39#define PHY_R2 0x08
40 #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0)
41 #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6)
42 #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12)
43 #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18)
44
45#define PHY_R4 0x10
46 #define PHY_R4_PHY_CR_WRITE BIT(0)
47 #define PHY_R4_PHY_CR_READ BIT(1)
48 #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2)
49 #define PHY_R4_PHY_CR_CAP_DATA BIT(18)
50 #define PHY_R4_PHY_CR_CAP_ADDR BIT(19)
51
52#define PHY_R5 0x14
53 #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0)
54 #define PHY_R5_PHY_CR_ACK BIT(16)
55 #define PHY_R5_PHY_BS_OUT BIT(17)
56
57struct phy_g12a_usb3_pcie_priv {
58 struct regmap *regmap;
59#if CONFIG_IS_ENABLED(CLK)
60 struct clk clk;
61#endif
62 struct reset_ctl_bulk resets;
63};
64
65static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv,
66 unsigned int addr)
67{
68 unsigned int val, reg;
69 int ret;
70
71 reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr);
72
73 regmap_write(priv->regmap, PHY_R4, reg);
74 regmap_write(priv->regmap, PHY_R4, reg);
75
76 regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR);
77
78 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
79 (val & PHY_R5_PHY_CR_ACK),
80 5, 1000);
81 if (ret)
82 return ret;
83
84 regmap_write(priv->regmap, PHY_R4, reg);
85
86 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
87 !(val & PHY_R5_PHY_CR_ACK),
88 5, 1000);
89 if (ret)
90 return ret;
91
92 return 0;
93}
94
95static int
96phy_g12a_usb3_pcie_cr_bus_read(struct phy_g12a_usb3_pcie_priv *priv,
97 unsigned int addr, unsigned int *data)
98{
99 unsigned int val;
100 int ret;
101
102 ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
103 if (ret)
104 return ret;
105
106 regmap_write(priv->regmap, PHY_R4, 0);
107 regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ);
108
109 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
110 (val & PHY_R5_PHY_CR_ACK),
111 5, 1000);
112 if (ret)
113 return ret;
114
115 *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val);
116
117 regmap_write(priv->regmap, PHY_R4, 0);
118
119 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
120 !(val & PHY_R5_PHY_CR_ACK),
121 5, 1000);
122 if (ret)
123 return ret;
124
125 return 0;
126}
127
128static int
129phy_g12a_usb3_pcie_cr_bus_write(struct phy_g12a_usb3_pcie_priv *priv,
130 unsigned int addr, unsigned int data)
131{
132 unsigned int val, reg;
133 int ret;
134
135 ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
136 if (ret)
137 return ret;
138
139 reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data);
140
141 regmap_write(priv->regmap, PHY_R4, reg);
142 regmap_write(priv->regmap, PHY_R4, reg);
143
144 regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA);
145
146 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
147 (val & PHY_R5_PHY_CR_ACK),
148 5, 1000);
149 if (ret)
150 return ret;
151
152 regmap_write(priv->regmap, PHY_R4, reg);
153
154 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
155 (val & PHY_R5_PHY_CR_ACK) == 0,
156 5, 1000);
157 if (ret)
158 return ret;
159
160 regmap_write(priv->regmap, PHY_R4, reg);
161
162 regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE);
163
164 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
165 (val & PHY_R5_PHY_CR_ACK),
166 5, 1000);
167 if (ret)
168 return ret;
169
170 regmap_write(priv->regmap, PHY_R4, reg);
171
172 ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
173 (val & PHY_R5_PHY_CR_ACK) == 0,
174 5, 1000);
175 if (ret)
176 return ret;
177
178 return 0;
179}
180
181static int
182phy_g12a_usb3_pcie_cr_bus_update_bits(struct phy_g12a_usb3_pcie_priv *priv,
183 uint offset, uint mask, uint val)
184{
185 uint reg;
186 int ret;
187
188 ret = phy_g12a_usb3_pcie_cr_bus_read(priv, offset, &reg);
189 if (ret)
190 return ret;
191
192 reg &= ~mask;
193
194 return phy_g12a_usb3_pcie_cr_bus_write(priv, offset, reg | val);
195}
196
197static int phy_meson_g12a_usb3_init(struct phy *phy)
198{
199 struct udevice *dev = phy->dev;
200 struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
201 unsigned int data;
202 int ret;
203
204 /* TOFIX Handle PCIE mode */
205
206 ret = reset_assert_bulk(&priv->resets);
207 udelay(1);
208 ret |= reset_deassert_bulk(&priv->resets);
209 if (ret)
210 return ret;
211
212 /* Switch PHY to USB3 */
213 regmap_update_bits(priv->regmap, PHY_R0,
214 PHY_R0_PCIE_USB3_SWITCH,
215 PHY_R0_PCIE_USB3_SWITCH);
216
217 /*
218 * WORKAROUND: There is SSPHY suspend bug due to
219 * which USB enumerates
220 * in HS mode instead of SS mode. Workaround it by asserting
221 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus
222 * mode
223 */
224 ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x102d,
225 BIT(7), BIT(7));
226 if (ret)
227 return ret;
228
229 ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x1010, 0xff0, 20);
230 if (ret)
231 return ret;
232
233 /*
234 * Fix RX Equalization setting as follows
235 * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
236 * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
237 * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
238 * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
239 */
240 ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1006, &data);
241 if (ret)
242 return ret;
243
244 data &= ~BIT(6);
245 data |= BIT(7);
246 data &= ~(0x7 << 8);
247 data |= (0x3 << 8);
248 data |= (1 << 11);
249 ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1006, data);
250 if (ret)
251 return ret;
252
253 /*
254 * Set EQ and TX launch amplitudes as follows
255 * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
256 * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
257 * LANE0.TX_OVRD_DRV_LO.EN set to 1.
258 */
259 ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1002, &data);
260 if (ret)
261 return ret;
262
263 data &= ~0x3f80;
264 data |= (0x16 << 7);
265 data &= ~0x7f;
266 data |= (0x7f | BIT(14));
267 ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1002, data);
268 if (ret)
269 return ret;
270
271 /*
272 * MPLL_LOOP_CTL.PROP_CNTRL = 8
273 */
274 ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x30,
275 0xf << 4, 8 << 4);
276 if (ret)
277 return ret;
278
279 regmap_update_bits(priv->regmap, PHY_R2,
280 PHY_R2_PHY_TX_VBOOST_LVL,
281 FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4));
282
283 regmap_update_bits(priv->regmap, PHY_R1,
284 PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL,
285 FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) |
286 FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9));
287
288 return ret;
289}
290
291static int phy_meson_g12a_usb3_exit(struct phy *phy)
292{
293 struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
294
295 return reset_assert_bulk(&priv->resets);
296}
297
298struct phy_ops meson_g12a_usb3_pcie_phy_ops = {
299 .init = phy_meson_g12a_usb3_init,
300 .exit = phy_meson_g12a_usb3_exit,
301};
302
303int meson_g12a_usb3_pcie_phy_probe(struct udevice *dev)
304{
305 struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
306 int ret;
307
308 ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
309 if (ret)
310 return ret;
311
312 ret = reset_get_bulk(dev, &priv->resets);
313 if (ret == -ENOTSUPP)
314 return 0;
315 else if (ret)
316 return ret;
317
318#if CONFIG_IS_ENABLED(CLK)
319 ret = clk_get_by_index(dev, 0, &priv->clk);
320 if (ret < 0)
321 return ret;
322
323 ret = clk_enable(&priv->clk);
324 if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
325 pr_err("failed to enable PHY clock\n");
326 clk_free(&priv->clk);
327 return ret;
328 }
329#endif
330
331 return 0;
332}
333
334static const struct udevice_id meson_g12a_usb3_pcie_phy_ids[] = {
335 { .compatible = "amlogic,g12a-usb3-pcie-phy" },
336 { }
337};
338
339U_BOOT_DRIVER(meson_g12a_usb3_pcie_phy) = {
340 .name = "meson_g12a_usb3_pcie_phy",
341 .id = UCLASS_PHY,
342 .of_match = meson_g12a_usb3_pcie_phy_ids,
343 .probe = meson_g12a_usb3_pcie_phy_probe,
344 .ops = &meson_g12a_usb3_pcie_phy_ops,
345 .priv_auto_alloc_size = sizeof(struct phy_g12a_usb3_pcie_priv),
346};