blob: 5fb9b477adaf07add31a0c37cc0b06984fbabcf7 [file] [log] [blame]
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Amlogic GXL DWC3 Glue layer
4 *
5 * Copyright (C) 2019 BayLibre, SAS
6 * Author: Neil Armstrong <narmstrong@baylibre.com>
7 */
8
9#define DEBUG
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +020010#include <dm.h>
11#include <dm/device-internal.h>
12#include <dm/lists.h>
13#include <dwc3-uboot.h>
14#include <generic-phy.h>
Igor Prusov89606c02023-11-14 14:02:56 +030015#include <linux/io.h>
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +020016#include <linux/usb/ch9.h>
17#include <linux/usb/gadget.h>
18#include <malloc.h>
19#include <regmap.h>
20#include <usb.h>
21#include "core.h"
22#include "gadget.h"
23#include <reset.h>
24#include <clk.h>
25#include <power/regulator.h>
26#include <linux/bitfield.h>
27#include <linux/bitops.h>
28#include <linux/compat.h>
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +020029
30/* USB Glue Control Registers */
31
32#define USB_R0 0x00
33 #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
34 #define USB_R0_P30_PHY_RESET BIT(6)
35 #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
36 #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
37 #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
38 #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
39 #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
40 #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
41 #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
42 #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
43 #define USB_R0_U2D_ACT BIT(31)
44
45#define USB_R1 0x04
46 #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
47 #define USB_R1_U3H_PME_ENABLE BIT(1)
48 #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
49 #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
50 #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
51 #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
52 #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
53 #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
54 #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
55 #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
56
57#define USB_R2 0x08
58 #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
59 #define USB_R2_P30_CR_READ BIT(16)
60 #define USB_R2_P30_CR_WRITE BIT(17)
61 #define USB_R2_P30_CR_CAP_ADDR BIT(18)
62 #define USB_R2_P30_CR_CAP_DATA BIT(19)
63 #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
64 #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
65
66#define USB_R3 0x0c
67 #define USB_R3_P30_SSC_ENABLE BIT(0)
68 #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
69 #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
70 #define USB_R3_P30_REF_SSP_EN BIT(13)
71 #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
72 #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
73 #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
74
75#define USB_R4 0x10
76 #define USB_R4_P21_PORT_RESET_0 BIT(0)
77 #define USB_R4_P21_SLEEP_M0 BIT(1)
78 #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
79 #define USB_R4_P21_ONLY BIT(4)
80
81#define USB_R5 0x14
82 #define USB_R5_ID_DIG_SYNC BIT(0)
83 #define USB_R5_ID_DIG_REG BIT(1)
84 #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
85 #define USB_R5_ID_DIG_EN_0 BIT(4)
86 #define USB_R5_ID_DIG_EN_1 BIT(5)
87 #define USB_R5_ID_DIG_CURR BIT(6)
88 #define USB_R5_ID_DIG_IRQ BIT(7)
89 #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
90 #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
91
92/* read-only register */
93#define USB_R6 0x18
94 #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
95 #define USB_R6_P30_CR_ACK BIT(16)
96
97enum {
98 USB2_HOST_PHY0 = 0,
99 USB2_OTG_PHY1,
100 USB2_HOST_PHY2,
101 PHY_COUNT,
102};
103
104static const char *phy_names[PHY_COUNT] = {
105 "usb2-phy0", "usb2-phy1", "usb2-phy2",
106};
107
108struct dwc3_meson_gxl {
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#if CONFIG_IS_ENABLED(DM_REGULATOR)
118 struct udevice *vbus_supply;
119#endif
120};
121
122#define U2P_REG_SIZE 0x20
123#define USB_REG_OFFSET 0x80
124
125#define USB2_OTG_PHY USB2_OTG_PHY1
126
127static void dwc3_meson_gxl_usb2_set_mode(struct dwc3_meson_gxl *priv, 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, USB_R1,
134 USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 0);
135 regmap_update_bits(priv->regmap, USB_R0,
136 USB_R0_U2D_ACT, 0);
137 regmap_update_bits(priv->regmap, USB_R4,
138 USB_R4_P21_SLEEP_M0, 0);
139 break;
140
141 case USB_DR_MODE_PERIPHERAL:
142 regmap_update_bits(priv->regmap, USB_R0,
143 USB_R0_U2D_ACT, USB_R0_U2D_ACT);
144 regmap_update_bits(priv->regmap, USB_R0,
145 USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
146 regmap_update_bits(priv->regmap, USB_R4,
147 USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
148 break;
149 }
150}
151
152static int dwc3_meson_gxl_usb2_init(struct dwc3_meson_gxl *priv)
153{
154 int i;
155
156 for (i = 0; i < PHY_COUNT; ++i) {
157 if (!priv->phys[i].dev)
158 continue;
159
Neil Armstrong88e98a82024-06-20 09:42:51 +0200160 generic_phy_set_mode(&priv->phys[i],
161 (i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE
162 : PHY_MODE_USB_HOST, 0);
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200163 }
164
165 return 0;
166}
167
168static int dwc3_meson_gxl_usb_init(struct dwc3_meson_gxl *priv)
169{
170 int ret;
Wolfgang Denk9d328a62021-09-27 17:42:38 +0200171
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200172 ret = dwc3_meson_gxl_usb2_init(priv);
173 if (ret)
174 return ret;
175
176 regmap_update_bits(priv->regmap, USB_R1,
177 USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
178 FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
179
180 regmap_update_bits(priv->regmap, USB_R5,
181 USB_R5_ID_DIG_EN_0,
182 USB_R5_ID_DIG_EN_0);
183 regmap_update_bits(priv->regmap, USB_R5,
184 USB_R5_ID_DIG_EN_1,
185 USB_R5_ID_DIG_EN_1);
186 regmap_update_bits(priv->regmap, USB_R5,
187 USB_R5_ID_DIG_TH_MASK,
188 FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
189
190 dwc3_meson_gxl_usb2_set_mode(priv, priv->otg_phy_mode);
191
192 return 0;
193}
194
Neil Armstrong344c2462024-06-20 09:42:53 +0200195static int dwc3_meson_gxl_force_mode(struct udevice *dev, enum usb_dr_mode mode)
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200196{
Simon Glassfa20e932020-12-03 16:55:20 -0700197 struct dwc3_meson_gxl *priv = dev_get_plat(dev);
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200198
199 if (!priv)
200 return -EINVAL;
201
202 if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
203 return -EINVAL;
204
205 if (!priv->phys[USB2_OTG_PHY].dev)
206 return -EINVAL;
207
208 if (mode == priv->otg_phy_mode)
209 return 0;
210
211 if (mode == USB_DR_MODE_HOST)
212 debug("%s: switching to Host Mode\n", __func__);
213 else
214 debug("%s: switching to Device Mode\n", __func__);
215
216#if CONFIG_IS_ENABLED(DM_REGULATOR)
217 if (priv->vbus_supply) {
218 int ret = regulator_set_enable(priv->vbus_supply,
219 (mode == USB_DR_MODE_PERIPHERAL));
220 if (ret)
221 return ret;
222 }
223#endif
224 priv->otg_phy_mode = mode;
225
Neil Armstrong88e98a82024-06-20 09:42:51 +0200226 generic_phy_set_mode(&priv->phys[USB2_OTG_PHY],
227 mode == USB_DR_MODE_PERIPHERAL ? PHY_MODE_USB_DEVICE
228 : PHY_MODE_USB_HOST, 0);
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200229
230 dwc3_meson_gxl_usb2_set_mode(priv, mode);
231
232 return 0;
233}
234
235static int dwc3_meson_gxl_get_phys(struct dwc3_meson_gxl *priv)
236{
237 int i, ret;
238
239 for (i = 0 ; i < PHY_COUNT ; ++i) {
240 ret = generic_phy_get_by_name(priv->dev, phy_names[i],
241 &priv->phys[i]);
242 if (ret == -ENOENT || ret == -ENODATA) {
243 priv->phys[i].dev = NULL;
244 continue;
245 }
246
247 if (ret)
248 return ret;
249
250 priv->usb2_ports++;
251 }
252
253 debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
254
255 return 0;
256}
257
258static int dwc3_meson_gxl_reset_init(struct dwc3_meson_gxl *priv)
259{
260 int ret;
261
262 ret = reset_get_by_index(priv->dev, 0, &priv->reset);
263 if (ret)
264 return ret;
265
266 ret = reset_assert(&priv->reset);
267 udelay(1);
268 ret |= reset_deassert(&priv->reset);
269 if (ret) {
270 reset_free(&priv->reset);
271 return ret;
272 }
273
274 return 0;
275}
276
277static int dwc3_meson_gxl_clk_init(struct dwc3_meson_gxl *priv)
278{
279 int ret;
280
281 ret = clk_get_by_index(priv->dev, 0, &priv->clk);
282 if (ret)
283 return ret;
284
285#if CONFIG_IS_ENABLED(CLK)
286 ret = clk_enable(&priv->clk);
Sean Andersond318eb32023-12-16 14:38:42 -0500287 if (ret)
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200288 return ret;
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200289#endif
290
291 return 0;
292}
293
294static int dwc3_meson_gxl_probe(struct udevice *dev)
295{
Simon Glassfa20e932020-12-03 16:55:20 -0700296 struct dwc3_meson_gxl *priv = dev_get_plat(dev);
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200297 int ret, i;
298
299 priv->dev = dev;
300
301 ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
302 if (ret)
303 return ret;
304
305 ret = dwc3_meson_gxl_clk_init(priv);
306 if (ret)
307 return ret;
308
309 ret = dwc3_meson_gxl_reset_init(priv);
310 if (ret)
311 return ret;
312
313 ret = dwc3_meson_gxl_get_phys(priv);
314 if (ret)
315 return ret;
316
317#if CONFIG_IS_ENABLED(DM_REGULATOR)
318 ret = device_get_supply_regulator(dev, "vbus-supply",
319 &priv->vbus_supply);
320 if (ret && ret != -ENOENT) {
321 pr_err("Failed to get PHY regulator\n");
322 return ret;
323 }
324
325 if (priv->vbus_supply) {
326 ret = regulator_set_enable(priv->vbus_supply, true);
327 if (ret)
328 return ret;
329 }
330#endif
331
332 /* On GXL PHY must be started in device mode for DWC2 init */
333 priv->otg_mode = USB_DR_MODE_PERIPHERAL;
334
335 ret = dwc3_meson_gxl_usb_init(priv);
336 if (ret)
337 return ret;
338
Simon Glassa7ece582020-12-19 10:40:14 -0700339 priv->otg_mode = usb_get_dr_mode(dev_ofnode(dev));
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200340
341 if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
342 priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
343 else
344 priv->otg_phy_mode = USB_DR_MODE_HOST;
345
346 for (i = 0 ; i < PHY_COUNT ; ++i) {
347 if (!priv->phys[i].dev)
348 continue;
349
350 ret = generic_phy_init(&priv->phys[i]);
351 if (ret)
352 goto err_phy_init;
353 }
354
355 for (i = 0; i < PHY_COUNT; ++i) {
356 if (!priv->phys[i].dev)
357 continue;
358
359 ret = generic_phy_power_on(&priv->phys[i]);
360 if (ret)
361 goto err_phy_init;
362 }
363
364 if (priv->phys[USB2_OTG_PHY].dev)
Neil Armstrong88e98a82024-06-20 09:42:51 +0200365 generic_phy_set_mode(&priv->phys[USB2_OTG_PHY],
366 priv->otg_phy_mode == USB_DR_MODE_PERIPHERAL ? PHY_MODE_USB_DEVICE
367 : PHY_MODE_USB_HOST, 0);
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200368
369 dwc3_meson_gxl_usb2_set_mode(priv, priv->otg_phy_mode);
370
371 return 0;
372
373err_phy_init:
374 for (i = 0 ; i < PHY_COUNT ; ++i) {
375 if (!priv->phys[i].dev)
376 continue;
377
378 generic_phy_exit(&priv->phys[i]);
379 }
380
381 return ret;
382}
383
384static int dwc3_meson_gxl_remove(struct udevice *dev)
385{
Simon Glassfa20e932020-12-03 16:55:20 -0700386 struct dwc3_meson_gxl *priv = dev_get_plat(dev);
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200387 int i;
388
389 reset_release_all(&priv->reset, 1);
390
391 clk_release_all(&priv->clk, 1);
392
393 for (i = 0; i < PHY_COUNT; ++i) {
394 if (!priv->phys[i].dev)
395 continue;
396
397 generic_phy_power_off(&priv->phys[i]);
398 }
399
400 for (i = 0 ; i < PHY_COUNT ; ++i) {
401 if (!priv->phys[i].dev)
402 continue;
403
404 generic_phy_exit(&priv->phys[i]);
405 }
406
407 return dm_scan_fdt_dev(dev);
408}
409
Neil Armstrong4a0d7182023-01-17 10:11:45 +0100410static int dwc3_meson_gxl_child_pre_probe(struct udevice *dev)
411{
412 if (ofnode_device_is_compatible(dev_ofnode(dev), "amlogic,meson-g12a-usb"))
413 return dwc3_meson_gxl_force_mode(dev->parent, USB_DR_MODE_PERIPHERAL);
414
415 return 0;
416}
417
418static int dwc3_meson_gxl_child_post_remove(struct udevice *dev)
419{
420 if (ofnode_device_is_compatible(dev_ofnode(dev), "amlogic,meson-g12a-usb"))
421 return dwc3_meson_gxl_force_mode(dev->parent, USB_DR_MODE_HOST);
422
423 return 0;
424}
425
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200426static const struct udevice_id dwc3_meson_gxl_ids[] = {
Neil Armstrong2e166c82021-09-17 09:37:01 +0200427 { .compatible = "amlogic,meson-axg-usb-ctrl" },
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200428 { .compatible = "amlogic,meson-gxl-usb-ctrl" },
429 { .compatible = "amlogic,meson-gxm-usb-ctrl" },
430 { }
431};
432
433U_BOOT_DRIVER(dwc3_generic_wrapper) = {
434 .name = "dwc3-meson-gxl",
435 .id = UCLASS_SIMPLE_BUS,
436 .of_match = dwc3_meson_gxl_ids,
437 .probe = dwc3_meson_gxl_probe,
438 .remove = dwc3_meson_gxl_remove,
Neil Armstrong4a0d7182023-01-17 10:11:45 +0100439 .child_pre_probe = dwc3_meson_gxl_child_pre_probe,
440 .child_post_remove = dwc3_meson_gxl_child_post_remove,
Simon Glass71fa5b42020-12-03 16:55:18 -0700441 .plat_auto = sizeof(struct dwc3_meson_gxl),
Neil Armstrongc1a7e72c2020-09-10 10:48:13 +0200442
443};