xref: /rk3399_rockchip-uboot/drivers/usb/dwc3/dwc3-meson-g12a.c (revision c637f2321bc4ce8e021571daba5bf82a677b865f)
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