1518b4f5bSNeil Armstrong // SPDX-License-Identifier: GPL-2.0
2518b4f5bSNeil Armstrong /*
3518b4f5bSNeil Armstrong * Amlogic G12A DWC3 Glue layer
4518b4f5bSNeil Armstrong *
5518b4f5bSNeil Armstrong * Copyright (C) 2019 BayLibre, SAS
6518b4f5bSNeil Armstrong * Author: Neil Armstrong <narmstrong@baylibre.com>
7518b4f5bSNeil Armstrong */
8518b4f5bSNeil Armstrong
9518b4f5bSNeil Armstrong #include <common.h>
10518b4f5bSNeil Armstrong #include <asm-generic/io.h>
11518b4f5bSNeil Armstrong #include <dm.h>
12518b4f5bSNeil Armstrong #include <dm/device-internal.h>
13518b4f5bSNeil Armstrong #include <dm/lists.h>
14518b4f5bSNeil Armstrong #include <dwc3-uboot.h>
15518b4f5bSNeil Armstrong #include <generic-phy.h>
16518b4f5bSNeil Armstrong #include <linux/usb/ch9.h>
17518b4f5bSNeil Armstrong #include <linux/usb/gadget.h>
18518b4f5bSNeil Armstrong #include <malloc.h>
19518b4f5bSNeil Armstrong #include <regmap.h>
20518b4f5bSNeil Armstrong #include <usb.h>
21518b4f5bSNeil Armstrong #include "core.h"
22518b4f5bSNeil Armstrong #include "gadget.h"
23518b4f5bSNeil Armstrong #include <reset.h>
24518b4f5bSNeil Armstrong #include <clk.h>
25518b4f5bSNeil Armstrong #include <power/regulator.h>
26518b4f5bSNeil Armstrong #include <linux/bitfield.h>
27518b4f5bSNeil Armstrong #include <linux/bitops.h>
28518b4f5bSNeil Armstrong #include <linux/compat.h>
29518b4f5bSNeil Armstrong
30518b4f5bSNeil Armstrong /* USB2 Ports Control Registers */
31518b4f5bSNeil Armstrong
32518b4f5bSNeil Armstrong #define U2P_REG_SIZE 0x20
33518b4f5bSNeil Armstrong
34518b4f5bSNeil Armstrong #define U2P_R0 0x0
35518b4f5bSNeil Armstrong #define U2P_R0_HOST_DEVICE BIT(0)
36518b4f5bSNeil Armstrong #define U2P_R0_POWER_OK BIT(1)
37518b4f5bSNeil Armstrong #define U2P_R0_HAST_MODE BIT(2)
38518b4f5bSNeil Armstrong #define U2P_R0_POWER_ON_RESET BIT(3)
39518b4f5bSNeil Armstrong #define U2P_R0_ID_PULLUP BIT(4)
40518b4f5bSNeil Armstrong #define U2P_R0_DRV_VBUS BIT(5)
41518b4f5bSNeil Armstrong
42518b4f5bSNeil Armstrong #define U2P_R1 0x4
43518b4f5bSNeil Armstrong #define U2P_R1_PHY_READY BIT(0)
44518b4f5bSNeil Armstrong #define U2P_R1_ID_DIG BIT(1)
45518b4f5bSNeil Armstrong #define U2P_R1_OTG_SESSION_VALID BIT(2)
46518b4f5bSNeil Armstrong #define U2P_R1_VBUS_VALID BIT(3)
47518b4f5bSNeil Armstrong
48518b4f5bSNeil Armstrong /* USB Glue Control Registers */
49518b4f5bSNeil Armstrong
50518b4f5bSNeil Armstrong #define USB_R0 0x80
51518b4f5bSNeil Armstrong #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
52518b4f5bSNeil Armstrong #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
53518b4f5bSNeil Armstrong #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
54518b4f5bSNeil Armstrong #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
55518b4f5bSNeil Armstrong #define USB_R0_U2D_ACT BIT(31)
56518b4f5bSNeil Armstrong
57518b4f5bSNeil Armstrong #define USB_R1 0x84
58518b4f5bSNeil Armstrong #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
59518b4f5bSNeil Armstrong #define USB_R1_U3H_PME_ENABLE BIT(1)
60518b4f5bSNeil Armstrong #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2)
61518b4f5bSNeil Armstrong #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7)
62518b4f5bSNeil Armstrong #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12)
63518b4f5bSNeil Armstrong #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
64518b4f5bSNeil Armstrong #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
65518b4f5bSNeil Armstrong #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
66518b4f5bSNeil Armstrong #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
67518b4f5bSNeil Armstrong #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
68518b4f5bSNeil Armstrong
69518b4f5bSNeil Armstrong #define USB_R2 0x88
70518b4f5bSNeil Armstrong #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
71518b4f5bSNeil Armstrong #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
72518b4f5bSNeil Armstrong
73518b4f5bSNeil Armstrong #define USB_R3 0x8c
74518b4f5bSNeil Armstrong #define USB_R3_P30_SSC_ENABLE BIT(0)
75518b4f5bSNeil Armstrong #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
76518b4f5bSNeil Armstrong #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
77518b4f5bSNeil Armstrong #define USB_R3_P30_REF_SSP_EN BIT(13)
78518b4f5bSNeil Armstrong
79518b4f5bSNeil Armstrong #define USB_R4 0x90
80518b4f5bSNeil Armstrong #define USB_R4_P21_PORT_RESET_0 BIT(0)
81518b4f5bSNeil Armstrong #define USB_R4_P21_SLEEP_M0 BIT(1)
82518b4f5bSNeil Armstrong #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
83518b4f5bSNeil Armstrong #define USB_R4_P21_ONLY BIT(4)
84518b4f5bSNeil Armstrong
85518b4f5bSNeil Armstrong #define USB_R5 0x94
86518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_SYNC BIT(0)
87518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_REG BIT(1)
88518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
89518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_EN_0 BIT(4)
90518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_EN_1 BIT(5)
91518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_CURR BIT(6)
92518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_IRQ BIT(7)
93518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
94518b4f5bSNeil Armstrong #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
95518b4f5bSNeil Armstrong
96518b4f5bSNeil Armstrong enum {
97518b4f5bSNeil Armstrong USB2_HOST_PHY = 0,
98518b4f5bSNeil Armstrong USB2_OTG_PHY,
99518b4f5bSNeil Armstrong USB3_HOST_PHY,
100518b4f5bSNeil Armstrong PHY_COUNT,
101518b4f5bSNeil Armstrong };
102518b4f5bSNeil Armstrong
103518b4f5bSNeil Armstrong static const char *phy_names[PHY_COUNT] = {
104518b4f5bSNeil Armstrong "usb2-phy0", "usb2-phy1", "usb3-phy0",
105518b4f5bSNeil Armstrong };
106518b4f5bSNeil Armstrong
107518b4f5bSNeil Armstrong struct dwc3_meson_g12a {
108518b4f5bSNeil Armstrong struct udevice *dev;
109518b4f5bSNeil Armstrong struct regmap *regmap;
110518b4f5bSNeil Armstrong struct clk clk;
111518b4f5bSNeil Armstrong struct reset_ctl reset;
112518b4f5bSNeil Armstrong struct phy phys[PHY_COUNT];
113518b4f5bSNeil Armstrong enum usb_dr_mode otg_mode;
114518b4f5bSNeil Armstrong enum usb_dr_mode otg_phy_mode;
115518b4f5bSNeil Armstrong unsigned int usb2_ports;
116518b4f5bSNeil Armstrong unsigned int usb3_ports;
117518b4f5bSNeil Armstrong #if CONFIG_IS_ENABLED(DM_REGULATOR)
118518b4f5bSNeil Armstrong struct udevice *vbus_supply;
119518b4f5bSNeil Armstrong #endif
120518b4f5bSNeil Armstrong };
121518b4f5bSNeil Armstrong
122518b4f5bSNeil Armstrong #define U2P_REG_SIZE 0x20
123518b4f5bSNeil Armstrong #define USB_REG_OFFSET 0x80
124518b4f5bSNeil Armstrong
dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a * priv,int i,enum usb_dr_mode mode)125518b4f5bSNeil Armstrong static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
126518b4f5bSNeil Armstrong int i, enum usb_dr_mode mode)
127518b4f5bSNeil Armstrong {
128518b4f5bSNeil Armstrong switch (mode) {
129518b4f5bSNeil Armstrong case USB_DR_MODE_HOST:
130518b4f5bSNeil Armstrong case USB_DR_MODE_OTG:
131518b4f5bSNeil Armstrong case USB_DR_MODE_UNKNOWN:
132518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
133518b4f5bSNeil Armstrong U2P_R0_HOST_DEVICE,
134518b4f5bSNeil Armstrong U2P_R0_HOST_DEVICE);
135518b4f5bSNeil Armstrong break;
136518b4f5bSNeil Armstrong
137518b4f5bSNeil Armstrong case USB_DR_MODE_PERIPHERAL:
138518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
139518b4f5bSNeil Armstrong U2P_R0_HOST_DEVICE, 0);
140518b4f5bSNeil Armstrong break;
141518b4f5bSNeil Armstrong }
142518b4f5bSNeil Armstrong }
143518b4f5bSNeil Armstrong
dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a * priv)144518b4f5bSNeil Armstrong static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
145518b4f5bSNeil Armstrong {
146518b4f5bSNeil Armstrong int i;
147518b4f5bSNeil Armstrong
148518b4f5bSNeil Armstrong if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
149518b4f5bSNeil Armstrong priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
150518b4f5bSNeil Armstrong else
151518b4f5bSNeil Armstrong priv->otg_phy_mode = USB_DR_MODE_HOST;
152518b4f5bSNeil Armstrong
153518b4f5bSNeil Armstrong for (i = 0 ; i < USB3_HOST_PHY ; ++i) {
154518b4f5bSNeil Armstrong if (!priv->phys[i].dev)
155518b4f5bSNeil Armstrong continue;
156518b4f5bSNeil Armstrong
157518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
158518b4f5bSNeil Armstrong U2P_R0_POWER_ON_RESET,
159518b4f5bSNeil Armstrong U2P_R0_POWER_ON_RESET);
160518b4f5bSNeil Armstrong
161518b4f5bSNeil Armstrong if (i == USB2_OTG_PHY) {
162518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap,
163518b4f5bSNeil Armstrong U2P_R0 + (U2P_REG_SIZE * i),
164518b4f5bSNeil Armstrong U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
165518b4f5bSNeil Armstrong U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
166518b4f5bSNeil Armstrong
167518b4f5bSNeil Armstrong dwc3_meson_g12a_usb2_set_mode(priv, i,
168518b4f5bSNeil Armstrong priv->otg_phy_mode);
169518b4f5bSNeil Armstrong } else
170518b4f5bSNeil Armstrong dwc3_meson_g12a_usb2_set_mode(priv, i,
171518b4f5bSNeil Armstrong USB_DR_MODE_HOST);
172518b4f5bSNeil Armstrong
173518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
174518b4f5bSNeil Armstrong U2P_R0_POWER_ON_RESET, 0);
175518b4f5bSNeil Armstrong }
176518b4f5bSNeil Armstrong
177518b4f5bSNeil Armstrong return 0;
178518b4f5bSNeil Armstrong }
179518b4f5bSNeil Armstrong
dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a * priv)180518b4f5bSNeil Armstrong static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
181518b4f5bSNeil Armstrong {
182518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R3,
183518b4f5bSNeil Armstrong USB_R3_P30_SSC_RANGE_MASK |
184518b4f5bSNeil Armstrong USB_R3_P30_REF_SSP_EN,
185518b4f5bSNeil Armstrong USB_R3_P30_SSC_ENABLE |
186518b4f5bSNeil Armstrong FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
187518b4f5bSNeil Armstrong USB_R3_P30_REF_SSP_EN);
188518b4f5bSNeil Armstrong udelay(2);
189518b4f5bSNeil Armstrong
190518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R2,
191518b4f5bSNeil Armstrong USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
192518b4f5bSNeil Armstrong FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
193518b4f5bSNeil Armstrong
194518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R2,
195518b4f5bSNeil Armstrong USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
196518b4f5bSNeil Armstrong FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
197518b4f5bSNeil Armstrong
198518b4f5bSNeil Armstrong udelay(2);
199518b4f5bSNeil Armstrong
200518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R1,
201518b4f5bSNeil Armstrong USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
202518b4f5bSNeil Armstrong USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
203518b4f5bSNeil Armstrong
204518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R1,
205518b4f5bSNeil Armstrong USB_R1_P30_PCS_TX_SWING_FULL_MASK,
206518b4f5bSNeil Armstrong FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
207518b4f5bSNeil Armstrong }
208518b4f5bSNeil Armstrong
dwc3_meson_g12a_usb_init_mode(struct dwc3_meson_g12a * priv)209518b4f5bSNeil Armstrong static void dwc3_meson_g12a_usb_init_mode(struct dwc3_meson_g12a *priv)
210518b4f5bSNeil Armstrong {
211518b4f5bSNeil Armstrong if (priv->otg_phy_mode == USB_DR_MODE_PERIPHERAL) {
212518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R0,
213518b4f5bSNeil Armstrong USB_R0_U2D_ACT, USB_R0_U2D_ACT);
214518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R0,
215518b4f5bSNeil Armstrong USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
216518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R4,
217518b4f5bSNeil Armstrong USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
218518b4f5bSNeil Armstrong } else {
219518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R0,
220518b4f5bSNeil Armstrong USB_R0_U2D_ACT, 0);
221518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R4,
222518b4f5bSNeil Armstrong USB_R4_P21_SLEEP_M0, 0);
223518b4f5bSNeil Armstrong }
224518b4f5bSNeil Armstrong }
225518b4f5bSNeil Armstrong
dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a * priv)226518b4f5bSNeil Armstrong static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
227518b4f5bSNeil Armstrong {
228518b4f5bSNeil Armstrong int ret;
229518b4f5bSNeil Armstrong
230518b4f5bSNeil Armstrong ret = dwc3_meson_g12a_usb2_init(priv);
231518b4f5bSNeil Armstrong if (ret)
232518b4f5bSNeil Armstrong return ret;
233518b4f5bSNeil Armstrong
234518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R1,
235518b4f5bSNeil Armstrong USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
236518b4f5bSNeil Armstrong FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
237518b4f5bSNeil Armstrong
238518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R5,
239518b4f5bSNeil Armstrong USB_R5_ID_DIG_EN_0,
240518b4f5bSNeil Armstrong USB_R5_ID_DIG_EN_0);
241518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R5,
242518b4f5bSNeil Armstrong USB_R5_ID_DIG_EN_1,
243518b4f5bSNeil Armstrong USB_R5_ID_DIG_EN_1);
244518b4f5bSNeil Armstrong regmap_update_bits(priv->regmap, USB_R5,
245518b4f5bSNeil Armstrong USB_R5_ID_DIG_TH_MASK,
246518b4f5bSNeil Armstrong FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
247518b4f5bSNeil Armstrong
248518b4f5bSNeil Armstrong /* If we have an actual SuperSpeed port, initialize it */
249518b4f5bSNeil Armstrong if (priv->usb3_ports)
250518b4f5bSNeil Armstrong dwc3_meson_g12a_usb3_init(priv);
251518b4f5bSNeil Armstrong
252518b4f5bSNeil Armstrong dwc3_meson_g12a_usb_init_mode(priv);
253518b4f5bSNeil Armstrong
254518b4f5bSNeil Armstrong return 0;
255518b4f5bSNeil Armstrong }
256518b4f5bSNeil Armstrong
dwc3_meson_g12a_force_mode(struct udevice * dev,enum usb_dr_mode mode)257518b4f5bSNeil Armstrong int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
258518b4f5bSNeil Armstrong {
259518b4f5bSNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
260518b4f5bSNeil Armstrong
261518b4f5bSNeil Armstrong if (!priv)
262518b4f5bSNeil Armstrong return -EINVAL;
263518b4f5bSNeil Armstrong
264518b4f5bSNeil Armstrong if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
265518b4f5bSNeil Armstrong return -EINVAL;
266518b4f5bSNeil Armstrong
267518b4f5bSNeil Armstrong if (!priv->phys[USB2_OTG_PHY].dev)
268518b4f5bSNeil Armstrong return -EINVAL;
269518b4f5bSNeil Armstrong
270518b4f5bSNeil Armstrong if (mode == priv->otg_mode)
271518b4f5bSNeil Armstrong return 0;
272518b4f5bSNeil Armstrong
273518b4f5bSNeil Armstrong if (mode == USB_DR_MODE_HOST)
274518b4f5bSNeil Armstrong debug("%s: switching to Host Mode\n", __func__);
275518b4f5bSNeil Armstrong else
276518b4f5bSNeil Armstrong debug("%s: switching to Device Mode\n", __func__);
277518b4f5bSNeil Armstrong
278518b4f5bSNeil Armstrong #if CONFIG_IS_ENABLED(DM_REGULATOR)
279518b4f5bSNeil Armstrong if (priv->vbus_supply) {
280518b4f5bSNeil Armstrong int ret = regulator_set_enable(priv->vbus_supply,
281518b4f5bSNeil Armstrong (mode == USB_DR_MODE_PERIPHERAL));
282518b4f5bSNeil Armstrong if (ret)
283518b4f5bSNeil Armstrong return ret;
284518b4f5bSNeil Armstrong }
285518b4f5bSNeil Armstrong #endif
286518b4f5bSNeil Armstrong priv->otg_phy_mode = mode;
287518b4f5bSNeil Armstrong
288518b4f5bSNeil Armstrong dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode);
289518b4f5bSNeil Armstrong
290518b4f5bSNeil Armstrong dwc3_meson_g12a_usb_init_mode(priv);
291518b4f5bSNeil Armstrong
292518b4f5bSNeil Armstrong return 0;
293518b4f5bSNeil Armstrong }
294518b4f5bSNeil Armstrong
dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a * priv)295518b4f5bSNeil Armstrong static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
296518b4f5bSNeil Armstrong {
297518b4f5bSNeil Armstrong int i, ret;
298518b4f5bSNeil Armstrong
299518b4f5bSNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) {
300518b4f5bSNeil Armstrong ret = generic_phy_get_by_name(priv->dev, phy_names[i],
301518b4f5bSNeil Armstrong &priv->phys[i]);
302518b4f5bSNeil Armstrong if (ret == -ENOENT)
303518b4f5bSNeil Armstrong continue;
304518b4f5bSNeil Armstrong
305518b4f5bSNeil Armstrong if (ret)
306518b4f5bSNeil Armstrong return ret;
307518b4f5bSNeil Armstrong
308518b4f5bSNeil Armstrong if (i == USB3_HOST_PHY)
309518b4f5bSNeil Armstrong priv->usb3_ports++;
310518b4f5bSNeil Armstrong else
311518b4f5bSNeil Armstrong priv->usb2_ports++;
312518b4f5bSNeil Armstrong }
313518b4f5bSNeil Armstrong
314518b4f5bSNeil Armstrong debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
315518b4f5bSNeil Armstrong debug("%s: usb3 ports: %d\n", __func__, priv->usb3_ports);
316518b4f5bSNeil Armstrong
317518b4f5bSNeil Armstrong return 0;
318518b4f5bSNeil Armstrong }
319518b4f5bSNeil Armstrong
dwc3_meson_g12a_reset_init(struct dwc3_meson_g12a * priv)320518b4f5bSNeil Armstrong static int dwc3_meson_g12a_reset_init(struct dwc3_meson_g12a *priv)
321518b4f5bSNeil Armstrong {
322518b4f5bSNeil Armstrong int ret;
323518b4f5bSNeil Armstrong
324518b4f5bSNeil Armstrong ret = reset_get_by_index(priv->dev, 0, &priv->reset);
325518b4f5bSNeil Armstrong if (ret)
326518b4f5bSNeil Armstrong return ret;
327518b4f5bSNeil Armstrong
328518b4f5bSNeil Armstrong ret = reset_assert(&priv->reset);
329518b4f5bSNeil Armstrong udelay(1);
330518b4f5bSNeil Armstrong ret |= reset_deassert(&priv->reset);
331518b4f5bSNeil Armstrong if (ret) {
332518b4f5bSNeil Armstrong reset_free(&priv->reset);
333518b4f5bSNeil Armstrong return ret;
334518b4f5bSNeil Armstrong }
335518b4f5bSNeil Armstrong
336518b4f5bSNeil Armstrong return 0;
337518b4f5bSNeil Armstrong }
338518b4f5bSNeil Armstrong
dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a * priv)339518b4f5bSNeil Armstrong static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv)
340518b4f5bSNeil Armstrong {
341518b4f5bSNeil Armstrong int ret;
342518b4f5bSNeil Armstrong
343518b4f5bSNeil Armstrong ret = clk_get_by_index(priv->dev, 0, &priv->clk);
344518b4f5bSNeil Armstrong if (ret)
345518b4f5bSNeil Armstrong return ret;
346518b4f5bSNeil Armstrong
347518b4f5bSNeil Armstrong #if CONFIG_IS_ENABLED(CLK)
348518b4f5bSNeil Armstrong ret = clk_enable(&priv->clk);
349518b4f5bSNeil Armstrong if (ret) {
350518b4f5bSNeil Armstrong clk_free(&priv->clk);
351518b4f5bSNeil Armstrong return ret;
352518b4f5bSNeil Armstrong }
353518b4f5bSNeil Armstrong #endif
354518b4f5bSNeil Armstrong
355518b4f5bSNeil Armstrong return 0;
356518b4f5bSNeil Armstrong }
357518b4f5bSNeil Armstrong
dwc3_meson_g12a_probe(struct udevice * dev)358518b4f5bSNeil Armstrong static int dwc3_meson_g12a_probe(struct udevice *dev)
359518b4f5bSNeil Armstrong {
360518b4f5bSNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
361518b4f5bSNeil Armstrong int ret, i;
362518b4f5bSNeil Armstrong
363518b4f5bSNeil Armstrong priv->dev = dev;
364518b4f5bSNeil Armstrong
365518b4f5bSNeil Armstrong ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
366518b4f5bSNeil Armstrong if (ret)
367518b4f5bSNeil Armstrong return ret;
368518b4f5bSNeil Armstrong
369518b4f5bSNeil Armstrong ret = dwc3_meson_g12a_clk_init(priv);
370518b4f5bSNeil Armstrong if (ret)
371518b4f5bSNeil Armstrong return ret;
372518b4f5bSNeil Armstrong
373518b4f5bSNeil Armstrong ret = dwc3_meson_g12a_reset_init(priv);
374518b4f5bSNeil Armstrong if (ret)
375518b4f5bSNeil Armstrong return ret;
376518b4f5bSNeil Armstrong
377518b4f5bSNeil Armstrong ret = dwc3_meson_g12a_get_phys(priv);
378518b4f5bSNeil Armstrong if (ret)
379518b4f5bSNeil Armstrong return ret;
380518b4f5bSNeil Armstrong
381518b4f5bSNeil Armstrong #if CONFIG_IS_ENABLED(DM_REGULATOR)
382518b4f5bSNeil Armstrong ret = device_get_supply_regulator(dev, "vbus-supply",
383518b4f5bSNeil Armstrong &priv->vbus_supply);
384518b4f5bSNeil Armstrong if (ret && ret != -ENOENT) {
385518b4f5bSNeil Armstrong pr_err("Failed to get PHY regulator\n");
386518b4f5bSNeil Armstrong return ret;
387518b4f5bSNeil Armstrong }
388518b4f5bSNeil Armstrong
389518b4f5bSNeil Armstrong if (priv->vbus_supply) {
390518b4f5bSNeil Armstrong ret = regulator_set_enable(priv->vbus_supply, true);
391518b4f5bSNeil Armstrong if (ret)
392518b4f5bSNeil Armstrong return ret;
393518b4f5bSNeil Armstrong }
394518b4f5bSNeil Armstrong #endif
395518b4f5bSNeil Armstrong
396*ef78966dSKever Yang priv->otg_mode = usb_get_dr_mode(dev->node);
397518b4f5bSNeil Armstrong
398518b4f5bSNeil Armstrong ret = dwc3_meson_g12a_usb_init(priv);
399518b4f5bSNeil Armstrong if (ret)
400518b4f5bSNeil Armstrong return ret;
401518b4f5bSNeil Armstrong
402518b4f5bSNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) {
403518b4f5bSNeil Armstrong if (!priv->phys[i].dev)
404518b4f5bSNeil Armstrong continue;
405518b4f5bSNeil Armstrong
406518b4f5bSNeil Armstrong ret = generic_phy_init(&priv->phys[i]);
407518b4f5bSNeil Armstrong if (ret)
408518b4f5bSNeil Armstrong goto err_phy_init;
409518b4f5bSNeil Armstrong }
410518b4f5bSNeil Armstrong
411518b4f5bSNeil Armstrong return 0;
412518b4f5bSNeil Armstrong
413518b4f5bSNeil Armstrong err_phy_init:
414518b4f5bSNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) {
415518b4f5bSNeil Armstrong if (!priv->phys[i].dev)
416518b4f5bSNeil Armstrong continue;
417518b4f5bSNeil Armstrong
418518b4f5bSNeil Armstrong generic_phy_exit(&priv->phys[i]);
419518b4f5bSNeil Armstrong }
420518b4f5bSNeil Armstrong
421518b4f5bSNeil Armstrong return ret;
422518b4f5bSNeil Armstrong }
423518b4f5bSNeil Armstrong
dwc3_meson_g12a_remove(struct udevice * dev)424518b4f5bSNeil Armstrong static int dwc3_meson_g12a_remove(struct udevice *dev)
425518b4f5bSNeil Armstrong {
426518b4f5bSNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
427518b4f5bSNeil Armstrong int i;
428518b4f5bSNeil Armstrong
429518b4f5bSNeil Armstrong reset_release_all(&priv->reset, 1);
430518b4f5bSNeil Armstrong
431518b4f5bSNeil Armstrong clk_release_all(&priv->clk, 1);
432518b4f5bSNeil Armstrong
433518b4f5bSNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) {
434518b4f5bSNeil Armstrong if (!priv->phys[i].dev)
435518b4f5bSNeil Armstrong continue;
436518b4f5bSNeil Armstrong
437518b4f5bSNeil Armstrong generic_phy_exit(&priv->phys[i]);
438518b4f5bSNeil Armstrong }
439518b4f5bSNeil Armstrong
440518b4f5bSNeil Armstrong return dm_scan_fdt_dev(dev);
441518b4f5bSNeil Armstrong }
442518b4f5bSNeil Armstrong
443518b4f5bSNeil Armstrong static const struct udevice_id dwc3_meson_g12a_ids[] = {
444518b4f5bSNeil Armstrong { .compatible = "amlogic,meson-g12a-usb-ctrl" },
445518b4f5bSNeil Armstrong { }
446518b4f5bSNeil Armstrong };
447518b4f5bSNeil Armstrong
448518b4f5bSNeil Armstrong U_BOOT_DRIVER(dwc3_generic_wrapper) = {
449518b4f5bSNeil Armstrong .name = "dwc3-meson-g12a",
450518b4f5bSNeil Armstrong .id = UCLASS_SIMPLE_BUS,
451518b4f5bSNeil Armstrong .of_match = dwc3_meson_g12a_ids,
452518b4f5bSNeil Armstrong .probe = dwc3_meson_g12a_probe,
453518b4f5bSNeil Armstrong .remove = dwc3_meson_g12a_remove,
454518b4f5bSNeil Armstrong .platdata_auto_alloc_size = sizeof(struct dwc3_meson_g12a),
455518b4f5bSNeil Armstrong
456518b4f5bSNeil Armstrong };
457