xref: /OK3568_Linux_fs/u-boot/drivers/usb/host/dwc3-sti-glue.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * STiH407 family DWC3 specific Glue layer
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
5*4882a593Smuzhiyun  * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun #include <dm.h>
13*4882a593Smuzhiyun #include <errno.h>
14*4882a593Smuzhiyun #include <dm/lists.h>
15*4882a593Smuzhiyun #include <regmap.h>
16*4882a593Smuzhiyun #include <reset-uclass.h>
17*4882a593Smuzhiyun #include <syscon.h>
18*4882a593Smuzhiyun #include <usb.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/usb/dwc3.h>
21*4882a593Smuzhiyun #include <linux/usb/otg.h>
22*4882a593Smuzhiyun #include <dwc3-sti-glue.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun  * struct sti_dwc3_glue_platdata - dwc3 STi glue driver private structure
28*4882a593Smuzhiyun  * @syscfg_base:	addr for the glue syscfg
29*4882a593Smuzhiyun  * @glue_base:		addr for the glue registers
30*4882a593Smuzhiyun  * @syscfg_offset:	usb syscfg control offset
31*4882a593Smuzhiyun  * @powerdown_ctl:	rest controller for powerdown signal
32*4882a593Smuzhiyun  * @softreset_ctl:	reset controller for softreset signal
33*4882a593Smuzhiyun  * @mode:		drd static host/device config
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun struct sti_dwc3_glue_platdata {
36*4882a593Smuzhiyun 	phys_addr_t syscfg_base;
37*4882a593Smuzhiyun 	phys_addr_t glue_base;
38*4882a593Smuzhiyun 	phys_addr_t syscfg_offset;
39*4882a593Smuzhiyun 	struct reset_ctl powerdown_ctl;
40*4882a593Smuzhiyun 	struct reset_ctl softreset_ctl;
41*4882a593Smuzhiyun 	enum usb_dr_mode mode;
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata * plat)44*4882a593Smuzhiyun static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata *plat)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	unsigned long val;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	val = readl(plat->syscfg_base + plat->syscfg_offset);
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	val &= USB3_CONTROL_MASK;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	switch (plat->mode) {
53*4882a593Smuzhiyun 	case USB_DR_MODE_PERIPHERAL:
54*4882a593Smuzhiyun 		val &= ~(USB3_DELAY_VBUSVALID
55*4882a593Smuzhiyun 			| USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
56*4882a593Smuzhiyun 			| USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
57*4882a593Smuzhiyun 			| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 		val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID;
60*4882a593Smuzhiyun 		break;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	case USB_DR_MODE_HOST:
63*4882a593Smuzhiyun 		val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID
64*4882a593Smuzhiyun 			| USB3_SEL_FORCE_OPMODE	| USB3_FORCE_OPMODE(0x3)
65*4882a593Smuzhiyun 			| USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
66*4882a593Smuzhiyun 			| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 		val |= USB3_DELAY_VBUSVALID;
69*4882a593Smuzhiyun 		break;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	default:
72*4882a593Smuzhiyun 		pr_err("Unsupported mode of operation %d\n", plat->mode);
73*4882a593Smuzhiyun 		return -EINVAL;
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 	writel(val, plat->syscfg_base + plat->syscfg_offset);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
sti_dwc3_glue_init(struct sti_dwc3_glue_platdata * plat)80*4882a593Smuzhiyun static void sti_dwc3_glue_init(struct sti_dwc3_glue_platdata *plat)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	unsigned long reg;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	reg = readl(plat->glue_base + CLKRST_CTRL);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION;
87*4882a593Smuzhiyun 	reg &= ~SW_PIPEW_RESET_N;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	writel(reg, plat->glue_base + CLKRST_CTRL);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	/* configure mux for vbus, powerpresent and bvalid signals */
92*4882a593Smuzhiyun 	reg = readl(plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
95*4882a593Smuzhiyun 	       SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
96*4882a593Smuzhiyun 	       SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	writel(reg, plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	setbits_le32(plat->glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
sti_dwc3_glue_ofdata_to_platdata(struct udevice * dev)103*4882a593Smuzhiyun static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
106*4882a593Smuzhiyun 	struct udevice *syscon;
107*4882a593Smuzhiyun 	struct regmap *regmap;
108*4882a593Smuzhiyun 	int ret;
109*4882a593Smuzhiyun 	u32 reg[4];
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	ret = ofnode_read_u32_array(dev->node, "reg", reg, ARRAY_SIZE(reg));
112*4882a593Smuzhiyun 	if (ret) {
113*4882a593Smuzhiyun 		pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret);
114*4882a593Smuzhiyun 		return ret;
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	plat->glue_base = reg[0];
118*4882a593Smuzhiyun 	plat->syscfg_offset = reg[2];
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* get corresponding syscon phandle */
121*4882a593Smuzhiyun 	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg",
122*4882a593Smuzhiyun 					   &syscon);
123*4882a593Smuzhiyun 	if (ret) {
124*4882a593Smuzhiyun 		pr_err("unable to find syscon device (%d)\n", ret);
125*4882a593Smuzhiyun 		return ret;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* get syscfg-reg base address */
129*4882a593Smuzhiyun 	regmap = syscon_get_regmap(syscon);
130*4882a593Smuzhiyun 	if (!regmap) {
131*4882a593Smuzhiyun 		pr_err("unable to find regmap\n");
132*4882a593Smuzhiyun 		return -ENODEV;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 	plat->syscfg_base = regmap->base;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/* get powerdown reset */
137*4882a593Smuzhiyun 	ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl);
138*4882a593Smuzhiyun 	if (ret) {
139*4882a593Smuzhiyun 		pr_err("can't get powerdown reset for %s (%d)", dev->name, ret);
140*4882a593Smuzhiyun 		return ret;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* get softreset reset */
144*4882a593Smuzhiyun 	ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl);
145*4882a593Smuzhiyun 	if (ret)
146*4882a593Smuzhiyun 		pr_err("can't get soft reset for %s (%d)", dev->name, ret);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return ret;
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
sti_dwc3_glue_bind(struct udevice * dev)151*4882a593Smuzhiyun static int sti_dwc3_glue_bind(struct udevice *dev)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
154*4882a593Smuzhiyun 	ofnode node, dwc3_node;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* Find snps,dwc3 node from subnode */
157*4882a593Smuzhiyun 	ofnode_for_each_subnode(node, dev->node) {
158*4882a593Smuzhiyun 		if (ofnode_device_is_compatible(node, "snps,dwc3"))
159*4882a593Smuzhiyun 			dwc3_node = node;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (!ofnode_valid(node)) {
163*4882a593Smuzhiyun 		pr_err("Can't find dwc3 subnode for %s\n", dev->name);
164*4882a593Smuzhiyun 		return -ENODEV;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/* retrieve the DWC3 dual role mode */
168*4882a593Smuzhiyun 	plat->mode = usb_get_dr_mode(dwc3_node);
169*4882a593Smuzhiyun 	if (plat->mode == USB_DR_MODE_UNKNOWN)
170*4882a593Smuzhiyun 		/* by default set dual role mode to HOST */
171*4882a593Smuzhiyun 		plat->mode = USB_DR_MODE_HOST;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return dm_scan_fdt_dev(dev);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
sti_dwc3_glue_probe(struct udevice * dev)176*4882a593Smuzhiyun static int sti_dwc3_glue_probe(struct udevice *dev)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
179*4882a593Smuzhiyun 	int ret;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	/* deassert both powerdown and softreset */
182*4882a593Smuzhiyun 	ret = reset_deassert(&plat->powerdown_ctl);
183*4882a593Smuzhiyun 	if (ret < 0) {
184*4882a593Smuzhiyun 		pr_err("DWC3 powerdown reset deassert failed: %d", ret);
185*4882a593Smuzhiyun 		return ret;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	ret = reset_deassert(&plat->softreset_ctl);
189*4882a593Smuzhiyun 	if (ret < 0) {
190*4882a593Smuzhiyun 		pr_err("DWC3 soft reset deassert failed: %d", ret);
191*4882a593Smuzhiyun 		goto softreset_err;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	ret = sti_dwc3_glue_drd_init(plat);
195*4882a593Smuzhiyun 	if (ret)
196*4882a593Smuzhiyun 		goto init_err;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	sti_dwc3_glue_init(plat);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	return 0;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun init_err:
203*4882a593Smuzhiyun 	ret = reset_assert(&plat->softreset_ctl);
204*4882a593Smuzhiyun 	if (ret < 0) {
205*4882a593Smuzhiyun 		pr_err("DWC3 soft reset deassert failed: %d", ret);
206*4882a593Smuzhiyun 		return ret;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun softreset_err:
210*4882a593Smuzhiyun 	ret = reset_assert(&plat->powerdown_ctl);
211*4882a593Smuzhiyun 	if (ret < 0)
212*4882a593Smuzhiyun 		pr_err("DWC3 powerdown reset deassert failed: %d", ret);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	return ret;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
sti_dwc3_glue_remove(struct udevice * dev)217*4882a593Smuzhiyun static int sti_dwc3_glue_remove(struct udevice *dev)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
220*4882a593Smuzhiyun 	int ret;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* assert both powerdown and softreset */
223*4882a593Smuzhiyun 	ret = reset_assert(&plat->powerdown_ctl);
224*4882a593Smuzhiyun 	if (ret < 0) {
225*4882a593Smuzhiyun 		pr_err("DWC3 powerdown reset deassert failed: %d", ret);
226*4882a593Smuzhiyun 		return ret;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	ret = reset_assert(&plat->softreset_ctl);
230*4882a593Smuzhiyun 	if (ret < 0)
231*4882a593Smuzhiyun 		pr_err("DWC3 soft reset deassert failed: %d", ret);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	return ret;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun static const struct udevice_id sti_dwc3_glue_ids[] = {
237*4882a593Smuzhiyun 	{ .compatible = "st,stih407-dwc3" },
238*4882a593Smuzhiyun 	{ }
239*4882a593Smuzhiyun };
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun U_BOOT_DRIVER(dwc3_sti_glue) = {
242*4882a593Smuzhiyun 	.name = "dwc3_sti_glue",
243*4882a593Smuzhiyun 	.id = UCLASS_MISC,
244*4882a593Smuzhiyun 	.of_match = sti_dwc3_glue_ids,
245*4882a593Smuzhiyun 	.ofdata_to_platdata = sti_dwc3_glue_ofdata_to_platdata,
246*4882a593Smuzhiyun 	.probe = sti_dwc3_glue_probe,
247*4882a593Smuzhiyun 	.remove = sti_dwc3_glue_remove,
248*4882a593Smuzhiyun 	.bind = sti_dwc3_glue_bind,
249*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct sti_dwc3_glue_platdata),
250*4882a593Smuzhiyun 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
251*4882a593Smuzhiyun };
252