blob: f66f083453097300c9d3787dd08052ad8ec0d8cc [file] [log] [blame]
Neil Armstrong1f708892019-02-19 13:42:01 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Amlogic G12A DWC3 Glue layer
4 *
5 * Copyright (C) 2019 BayLibre, SAS
6 * Author: Neil Armstrong <narmstrong@baylibre.com>
7 */
8
9#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Neil Armstrong1f708892019-02-19 13:42:01 +010011#include <asm-generic/io.h>
12#include <dm.h>
13#include <dm/device-internal.h>
14#include <dm/lists.h>
15#include <dwc3-uboot.h>
16#include <generic-phy.h>
17#include <linux/usb/ch9.h>
18#include <linux/usb/gadget.h>
19#include <malloc.h>
20#include <regmap.h>
21#include <usb.h>
22#include "core.h"
23#include "gadget.h"
24#include <reset.h>
25#include <clk.h>
26#include <power/regulator.h>
27#include <linux/bitfield.h>
28#include <linux/bitops.h>
29#include <linux/compat.h>
30
31/* USB2 Ports Control Registers */
32
33#define U2P_REG_SIZE 0x20
34
35#define U2P_R0 0x0
36 #define U2P_R0_HOST_DEVICE BIT(0)
37 #define U2P_R0_POWER_OK BIT(1)
38 #define U2P_R0_HAST_MODE BIT(2)
39 #define U2P_R0_POWER_ON_RESET BIT(3)
40 #define U2P_R0_ID_PULLUP BIT(4)
41 #define U2P_R0_DRV_VBUS BIT(5)
42
43#define U2P_R1 0x4
44 #define U2P_R1_PHY_READY BIT(0)
45 #define U2P_R1_ID_DIG BIT(1)
46 #define U2P_R1_OTG_SESSION_VALID BIT(2)
47 #define U2P_R1_VBUS_VALID BIT(3)
48
49/* USB Glue Control Registers */
50
51#define USB_R0 0x80
52 #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
53 #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
54 #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
55 #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
56 #define USB_R0_U2D_ACT BIT(31)
57
58#define USB_R1 0x84
59 #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
60 #define USB_R1_U3H_PME_ENABLE BIT(1)
61 #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2)
62 #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7)
63 #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12)
64 #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
65 #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
66 #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
67 #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
68 #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
69
70#define USB_R2 0x88
71 #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
72 #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
73
74#define USB_R3 0x8c
75 #define USB_R3_P30_SSC_ENABLE BIT(0)
76 #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
77 #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
78 #define USB_R3_P30_REF_SSP_EN BIT(13)
79
80#define USB_R4 0x90
81 #define USB_R4_P21_PORT_RESET_0 BIT(0)
82 #define USB_R4_P21_SLEEP_M0 BIT(1)
83 #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
84 #define USB_R4_P21_ONLY BIT(4)
85
86#define USB_R5 0x94
87 #define USB_R5_ID_DIG_SYNC BIT(0)
88 #define USB_R5_ID_DIG_REG BIT(1)
89 #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
90 #define USB_R5_ID_DIG_EN_0 BIT(4)
91 #define USB_R5_ID_DIG_EN_1 BIT(5)
92 #define USB_R5_ID_DIG_CURR BIT(6)
93 #define USB_R5_ID_DIG_IRQ BIT(7)
94 #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
95 #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
96
97enum {
98 USB2_HOST_PHY = 0,
99 USB2_OTG_PHY,
100 USB3_HOST_PHY,
101 PHY_COUNT,
102};
103
104static const char *phy_names[PHY_COUNT] = {
105 "usb2-phy0", "usb2-phy1", "usb3-phy0",
106};
107
108struct dwc3_meson_g12a {
109 struct udevice *dev;
110 struct regmap *regmap;
111 struct clk clk;
112 struct reset_ctl reset;
113 struct phy phys[PHY_COUNT];
114 enum usb_dr_mode otg_mode;
115 enum usb_dr_mode otg_phy_mode;
116 unsigned int usb2_ports;
117 unsigned int usb3_ports;
118#if CONFIG_IS_ENABLED(DM_REGULATOR)
119 struct udevice *vbus_supply;
120#endif
121};
122
123#define U2P_REG_SIZE 0x20
124#define USB_REG_OFFSET 0x80
125
126static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
127 int i, enum usb_dr_mode mode)
128{
129 switch (mode) {
130 case USB_DR_MODE_HOST:
131 case USB_DR_MODE_OTG:
132 case USB_DR_MODE_UNKNOWN:
133 regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
134 U2P_R0_HOST_DEVICE,
135 U2P_R0_HOST_DEVICE);
136 break;
137
138 case USB_DR_MODE_PERIPHERAL:
139 regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
140 U2P_R0_HOST_DEVICE, 0);
141 break;
142 }
143}
144
145static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
146{
147 int i;
148
149 if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
150 priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
151 else
152 priv->otg_phy_mode = USB_DR_MODE_HOST;
153
154 for (i = 0 ; i < USB3_HOST_PHY ; ++i) {
155 if (!priv->phys[i].dev)
156 continue;
157
158 regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
159 U2P_R0_POWER_ON_RESET,
160 U2P_R0_POWER_ON_RESET);
161
162 if (i == USB2_OTG_PHY) {
163 regmap_update_bits(priv->regmap,
164 U2P_R0 + (U2P_REG_SIZE * i),
165 U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
166 U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
167
168 dwc3_meson_g12a_usb2_set_mode(priv, i,
169 priv->otg_phy_mode);
170 } else
171 dwc3_meson_g12a_usb2_set_mode(priv, i,
172 USB_DR_MODE_HOST);
173
174 regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
175 U2P_R0_POWER_ON_RESET, 0);
176 }
177
178 return 0;
179}
180
181static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
182{
183 regmap_update_bits(priv->regmap, USB_R3,
184 USB_R3_P30_SSC_RANGE_MASK |
185 USB_R3_P30_REF_SSP_EN,
186 USB_R3_P30_SSC_ENABLE |
187 FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
188 USB_R3_P30_REF_SSP_EN);
189 udelay(2);
190
191 regmap_update_bits(priv->regmap, USB_R2,
192 USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
193 FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
194
195 regmap_update_bits(priv->regmap, USB_R2,
196 USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
197 FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
198
199 udelay(2);
200
201 regmap_update_bits(priv->regmap, USB_R1,
202 USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
203 USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
204
205 regmap_update_bits(priv->regmap, USB_R1,
206 USB_R1_P30_PCS_TX_SWING_FULL_MASK,
207 FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
208}
209
210static void dwc3_meson_g12a_usb_init_mode(struct dwc3_meson_g12a *priv)
211{
212 if (priv->otg_phy_mode == USB_DR_MODE_PERIPHERAL) {
213 regmap_update_bits(priv->regmap, USB_R0,
214 USB_R0_U2D_ACT, USB_R0_U2D_ACT);
215 regmap_update_bits(priv->regmap, USB_R0,
216 USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
217 regmap_update_bits(priv->regmap, USB_R4,
218 USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
219 } else {
220 regmap_update_bits(priv->regmap, USB_R0,
221 USB_R0_U2D_ACT, 0);
222 regmap_update_bits(priv->regmap, USB_R4,
223 USB_R4_P21_SLEEP_M0, 0);
224 }
225}
226
227static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
228{
229 int ret;
230
231 ret = dwc3_meson_g12a_usb2_init(priv);
232 if (ret)
233 return ret;
234
235 regmap_update_bits(priv->regmap, USB_R1,
236 USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
237 FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
238
239 regmap_update_bits(priv->regmap, USB_R5,
240 USB_R5_ID_DIG_EN_0,
241 USB_R5_ID_DIG_EN_0);
242 regmap_update_bits(priv->regmap, USB_R5,
243 USB_R5_ID_DIG_EN_1,
244 USB_R5_ID_DIG_EN_1);
245 regmap_update_bits(priv->regmap, USB_R5,
246 USB_R5_ID_DIG_TH_MASK,
247 FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
248
249 /* If we have an actual SuperSpeed port, initialize it */
250 if (priv->usb3_ports)
251 dwc3_meson_g12a_usb3_init(priv);
252
253 dwc3_meson_g12a_usb_init_mode(priv);
254
255 return 0;
256}
257
258int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
259{
260 struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
261
262 if (!priv)
263 return -EINVAL;
264
265 if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
266 return -EINVAL;
267
268 if (!priv->phys[USB2_OTG_PHY].dev)
269 return -EINVAL;
270
271 if (mode == priv->otg_mode)
272 return 0;
273
274 if (mode == USB_DR_MODE_HOST)
275 debug("%s: switching to Host Mode\n", __func__);
276 else
277 debug("%s: switching to Device Mode\n", __func__);
278
279#if CONFIG_IS_ENABLED(DM_REGULATOR)
280 if (priv->vbus_supply) {
281 int ret = regulator_set_enable(priv->vbus_supply,
282 (mode == USB_DR_MODE_PERIPHERAL));
283 if (ret)
284 return ret;
285 }
286#endif
287 priv->otg_phy_mode = mode;
288
289 dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode);
290
291 dwc3_meson_g12a_usb_init_mode(priv);
292
293 return 0;
294}
295
296static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
297{
298 int i, ret;
299
300 for (i = 0 ; i < PHY_COUNT ; ++i) {
301 ret = generic_phy_get_by_name(priv->dev, phy_names[i],
302 &priv->phys[i]);
303 if (ret == -ENOENT)
304 continue;
305
306 if (ret)
307 return ret;
308
309 if (i == USB3_HOST_PHY)
310 priv->usb3_ports++;
311 else
312 priv->usb2_ports++;
313 }
314
315 debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
316 debug("%s: usb3 ports: %d\n", __func__, priv->usb3_ports);
317
318 return 0;
319}
320
321static int dwc3_meson_g12a_reset_init(struct dwc3_meson_g12a *priv)
322{
323 int ret;
324
325 ret = reset_get_by_index(priv->dev, 0, &priv->reset);
326 if (ret)
327 return ret;
328
329 ret = reset_assert(&priv->reset);
330 udelay(1);
331 ret |= reset_deassert(&priv->reset);
332 if (ret) {
333 reset_free(&priv->reset);
334 return ret;
335 }
336
337 return 0;
338}
339
340static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv)
341{
342 int ret;
343
344 ret = clk_get_by_index(priv->dev, 0, &priv->clk);
345 if (ret)
346 return ret;
347
348#if CONFIG_IS_ENABLED(CLK)
349 ret = clk_enable(&priv->clk);
350 if (ret) {
351 clk_free(&priv->clk);
352 return ret;
353 }
354#endif
355
356 return 0;
357}
358
359static int dwc3_meson_g12a_probe(struct udevice *dev)
360{
361 struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
362 int ret, i;
363
364 priv->dev = dev;
365
366 ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
367 if (ret)
368 return ret;
369
370 ret = dwc3_meson_g12a_clk_init(priv);
371 if (ret)
372 return ret;
373
374 ret = dwc3_meson_g12a_reset_init(priv);
375 if (ret)
376 return ret;
377
378 ret = dwc3_meson_g12a_get_phys(priv);
379 if (ret)
380 return ret;
381
382#if CONFIG_IS_ENABLED(DM_REGULATOR)
383 ret = device_get_supply_regulator(dev, "vbus-supply",
384 &priv->vbus_supply);
385 if (ret && ret != -ENOENT) {
386 pr_err("Failed to get PHY regulator\n");
387 return ret;
388 }
389
390 if (priv->vbus_supply) {
391 ret = regulator_set_enable(priv->vbus_supply, true);
392 if (ret)
393 return ret;
394 }
395#endif
396
Kever Yang1b807052020-03-04 08:59:50 +0800397 priv->otg_mode = usb_get_dr_mode(dev->node);
Neil Armstrong1f708892019-02-19 13:42:01 +0100398
399 ret = dwc3_meson_g12a_usb_init(priv);
400 if (ret)
401 return ret;
402
403 for (i = 0 ; i < PHY_COUNT ; ++i) {
404 if (!priv->phys[i].dev)
405 continue;
406
407 ret = generic_phy_init(&priv->phys[i]);
408 if (ret)
409 goto err_phy_init;
410 }
411
Neil Armstronga29def22020-04-21 10:17:42 +0200412 for (i = 0; i < PHY_COUNT; ++i) {
413 if (!priv->phys[i].dev)
414 continue;
415
416 ret = generic_phy_power_on(&priv->phys[i]);
417 if (ret)
418 goto err_phy_init;
419 }
420
Neil Armstrong1f708892019-02-19 13:42:01 +0100421 return 0;
422
423err_phy_init:
424 for (i = 0 ; i < PHY_COUNT ; ++i) {
425 if (!priv->phys[i].dev)
426 continue;
427
428 generic_phy_exit(&priv->phys[i]);
429 }
430
431 return ret;
432}
433
434static int dwc3_meson_g12a_remove(struct udevice *dev)
435{
436 struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
437 int i;
438
439 reset_release_all(&priv->reset, 1);
440
441 clk_release_all(&priv->clk, 1);
442
Neil Armstronga29def22020-04-21 10:17:42 +0200443 for (i = 0; i < PHY_COUNT; ++i) {
444 if (!priv->phys[i].dev)
445 continue;
446
447 generic_phy_power_off(&priv->phys[i]);
448 }
449
Neil Armstrong1f708892019-02-19 13:42:01 +0100450 for (i = 0 ; i < PHY_COUNT ; ++i) {
451 if (!priv->phys[i].dev)
452 continue;
453
454 generic_phy_exit(&priv->phys[i]);
455 }
456
457 return dm_scan_fdt_dev(dev);
458}
459
460static const struct udevice_id dwc3_meson_g12a_ids[] = {
461 { .compatible = "amlogic,meson-g12a-usb-ctrl" },
462 { }
463};
464
465U_BOOT_DRIVER(dwc3_generic_wrapper) = {
466 .name = "dwc3-meson-g12a",
467 .id = UCLASS_SIMPLE_BUS,
468 .of_match = dwc3_meson_g12a_ids,
469 .probe = dwc3_meson_g12a_probe,
470 .remove = dwc3_meson_g12a_remove,
471 .platdata_auto_alloc_size = sizeof(struct dwc3_meson_g12a),
472
473};