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