xref: /rk3399_rockchip-uboot/drivers/usb/musb-new/omap2430.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
1673a524bSIlya Yanok /*
2673a524bSIlya Yanok  * Copyright (C) 2005-2007 by Texas Instruments
3673a524bSIlya Yanok  * Some code has been taken from tusb6010.c
4673a524bSIlya Yanok  * Copyrights for that are attributable to:
5673a524bSIlya Yanok  * Copyright (C) 2006 Nokia Corporation
6673a524bSIlya Yanok  * Tony Lindgren <tony@atomide.com>
7673a524bSIlya Yanok  *
8673a524bSIlya Yanok  * This file is part of the Inventra Controller Driver for Linux.
9673a524bSIlya Yanok  *
105b8031ccSTom Rini  * SPDX-License-Identifier:	GPL-2.0
11673a524bSIlya Yanok  */
12673a524bSIlya Yanok #include <common.h>
13b30beda2SAdam Ford #include <dm.h>
14b30beda2SAdam Ford #include <dm/device-internal.h>
15b30beda2SAdam Ford #include <dm/lists.h>
16b30beda2SAdam Ford #include <linux/usb/otg.h>
1727754d18SPaul Kocialkowski #include <asm/omap_common.h>
18673a524bSIlya Yanok #include <asm/omap_musb.h>
19673a524bSIlya Yanok #include <twl4030.h>
2027754d18SPaul Kocialkowski #include <twl6030.h>
21673a524bSIlya Yanok #include "linux-compat.h"
22673a524bSIlya Yanok #include "musb_core.h"
23673a524bSIlya Yanok #include "omap2430.h"
24b30beda2SAdam Ford #include "musb_uboot.h"
25673a524bSIlya Yanok 
omap2430_low_level_exit(struct musb * musb)26673a524bSIlya Yanok static inline void omap2430_low_level_exit(struct musb *musb)
27673a524bSIlya Yanok {
28673a524bSIlya Yanok 	u32 l;
29673a524bSIlya Yanok 
30673a524bSIlya Yanok 	/* in any role */
31673a524bSIlya Yanok 	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
32673a524bSIlya Yanok 	l |= ENABLEFORCE;	/* enable MSTANDBY */
33673a524bSIlya Yanok 	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
34673a524bSIlya Yanok }
35673a524bSIlya Yanok 
omap2430_low_level_init(struct musb * musb)36673a524bSIlya Yanok static inline void omap2430_low_level_init(struct musb *musb)
37673a524bSIlya Yanok {
38673a524bSIlya Yanok 	u32 l;
39673a524bSIlya Yanok 
40673a524bSIlya Yanok 	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
41673a524bSIlya Yanok 	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
42673a524bSIlya Yanok 	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
43673a524bSIlya Yanok }
44673a524bSIlya Yanok 
45673a524bSIlya Yanok 
omap2430_musb_init(struct musb * musb)46673a524bSIlya Yanok static int omap2430_musb_init(struct musb *musb)
47673a524bSIlya Yanok {
48673a524bSIlya Yanok 	u32 l;
49673a524bSIlya Yanok 	int status = 0;
50193d7d15SPaul Kocialkowski 	unsigned long int start;
51b30beda2SAdam Ford 
52673a524bSIlya Yanok 	struct omap_musb_board_data *data =
53673a524bSIlya Yanok 		(struct omap_musb_board_data *)musb->controller;
54673a524bSIlya Yanok 
55193d7d15SPaul Kocialkowski 	/* Reset the controller */
56193d7d15SPaul Kocialkowski 	musb_writel(musb->mregs, OTG_SYSCONFIG, SOFTRST);
57193d7d15SPaul Kocialkowski 
58193d7d15SPaul Kocialkowski 	start = get_timer(0);
59193d7d15SPaul Kocialkowski 
60193d7d15SPaul Kocialkowski 	while (1) {
61193d7d15SPaul Kocialkowski 		l = musb_readl(musb->mregs, OTG_SYSCONFIG);
62193d7d15SPaul Kocialkowski 		if ((l & SOFTRST) == 0)
63193d7d15SPaul Kocialkowski 			break;
64193d7d15SPaul Kocialkowski 
65193d7d15SPaul Kocialkowski 		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
66193d7d15SPaul Kocialkowski 			dev_err(musb->controller, "MUSB reset is taking too long\n");
67193d7d15SPaul Kocialkowski 			return -ENODEV;
68193d7d15SPaul Kocialkowski 		}
69193d7d15SPaul Kocialkowski 	}
70673a524bSIlya Yanok 
71673a524bSIlya Yanok 	l = musb_readl(musb->mregs, OTG_INTERFSEL);
72673a524bSIlya Yanok 
73673a524bSIlya Yanok 	if (data->interface_type == MUSB_INTERFACE_UTMI) {
74673a524bSIlya Yanok 		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
75673a524bSIlya Yanok 		l &= ~ULPI_12PIN;       /* Disable ULPI */
76673a524bSIlya Yanok 		l |= UTMI_8BIT;         /* Enable UTMI  */
77673a524bSIlya Yanok 	} else {
78673a524bSIlya Yanok 		l |= ULPI_12PIN;
79673a524bSIlya Yanok 	}
80673a524bSIlya Yanok 
81673a524bSIlya Yanok 	musb_writel(musb->mregs, OTG_INTERFSEL, l);
82673a524bSIlya Yanok 
83673a524bSIlya Yanok 	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
84673a524bSIlya Yanok 			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
85673a524bSIlya Yanok 			musb_readl(musb->mregs, OTG_REVISION),
86673a524bSIlya Yanok 			musb_readl(musb->mregs, OTG_SYSCONFIG),
87673a524bSIlya Yanok 			musb_readl(musb->mregs, OTG_SYSSTATUS),
88673a524bSIlya Yanok 			musb_readl(musb->mregs, OTG_INTERFSEL),
89673a524bSIlya Yanok 			musb_readl(musb->mregs, OTG_SIMENABLE));
90673a524bSIlya Yanok 	return 0;
91673a524bSIlya Yanok 
92673a524bSIlya Yanok err1:
93673a524bSIlya Yanok 	return status;
94673a524bSIlya Yanok }
95673a524bSIlya Yanok 
omap2430_musb_enable(struct musb * musb)9615837236SHans de Goede static int omap2430_musb_enable(struct musb *musb)
97673a524bSIlya Yanok {
98673a524bSIlya Yanok #ifdef CONFIG_TWL4030_USB
99673a524bSIlya Yanok 	if (twl4030_usb_ulpi_init()) {
100673a524bSIlya Yanok 		serial_printf("ERROR: %s Could not initialize PHY\n",
101673a524bSIlya Yanok 				__PRETTY_FUNCTION__);
102673a524bSIlya Yanok 	}
103673a524bSIlya Yanok #endif
10427754d18SPaul Kocialkowski 
10527754d18SPaul Kocialkowski #ifdef CONFIG_TWL6030_POWER
10627754d18SPaul Kocialkowski 	twl6030_usb_device_settings();
10727754d18SPaul Kocialkowski #endif
10827754d18SPaul Kocialkowski 
10977777f76STom Rini #ifdef CONFIG_OMAP44XX
11027754d18SPaul Kocialkowski 	u32 *usbotghs_control = (u32 *)((*ctrl)->control_usbotghs_ctrl);
11127754d18SPaul Kocialkowski 	*usbotghs_control = USBOTGHS_CONTROL_AVALID |
11227754d18SPaul Kocialkowski 		USBOTGHS_CONTROL_VBUSVALID | USBOTGHS_CONTROL_IDDIG;
11327754d18SPaul Kocialkowski #endif
11427754d18SPaul Kocialkowski 
11515837236SHans de Goede 	return 0;
116673a524bSIlya Yanok }
117673a524bSIlya Yanok 
omap2430_musb_disable(struct musb * musb)118673a524bSIlya Yanok static void omap2430_musb_disable(struct musb *musb)
119673a524bSIlya Yanok {
120673a524bSIlya Yanok 
121673a524bSIlya Yanok }
122673a524bSIlya Yanok 
omap2430_musb_exit(struct musb * musb)123673a524bSIlya Yanok static int omap2430_musb_exit(struct musb *musb)
124673a524bSIlya Yanok {
125673a524bSIlya Yanok 	del_timer_sync(&musb_idle_timer);
126673a524bSIlya Yanok 
127673a524bSIlya Yanok 	omap2430_low_level_exit(musb);
128673a524bSIlya Yanok 
129673a524bSIlya Yanok 	return 0;
130673a524bSIlya Yanok }
131673a524bSIlya Yanok 
132673a524bSIlya Yanok const struct musb_platform_ops omap2430_ops = {
133673a524bSIlya Yanok 	.init		= omap2430_musb_init,
134673a524bSIlya Yanok 	.exit		= omap2430_musb_exit,
135673a524bSIlya Yanok 	.enable		= omap2430_musb_enable,
136673a524bSIlya Yanok 	.disable	= omap2430_musb_disable,
137673a524bSIlya Yanok };
138b30beda2SAdam Ford 
1393739bf7eSSven Schwermer #if CONFIG_IS_ENABLED(DM_USB)
140b30beda2SAdam Ford 
141b30beda2SAdam Ford struct omap2430_musb_platdata {
142b30beda2SAdam Ford 	void *base;
143b30beda2SAdam Ford 	void *ctrl_mod_base;
144b30beda2SAdam Ford 	struct musb_hdrc_platform_data plat;
145b30beda2SAdam Ford 	struct musb_hdrc_config musb_config;
146b30beda2SAdam Ford 	struct omap_musb_board_data otg_board_data;
147b30beda2SAdam Ford };
148b30beda2SAdam Ford 
omap2430_musb_ofdata_to_platdata(struct udevice * dev)149b30beda2SAdam Ford static int omap2430_musb_ofdata_to_platdata(struct udevice *dev)
150b30beda2SAdam Ford {
151b30beda2SAdam Ford 	struct omap2430_musb_platdata *platdata = dev_get_platdata(dev);
152b30beda2SAdam Ford 	const void *fdt = gd->fdt_blob;
153b30beda2SAdam Ford 	int node = dev_of_offset(dev);
154b30beda2SAdam Ford 
155b30beda2SAdam Ford 	platdata->base = (void *)dev_read_addr_ptr(dev);
156b30beda2SAdam Ford 
157b30beda2SAdam Ford 	platdata->musb_config.multipoint = fdtdec_get_int(fdt, node,
158b30beda2SAdam Ford 							  "multipoint",
159b30beda2SAdam Ford 							  -1);
160b30beda2SAdam Ford 	if (platdata->musb_config.multipoint < 0) {
161b30beda2SAdam Ford 		pr_err("MUSB multipoint DT entry missing\n");
162b30beda2SAdam Ford 		return -ENOENT;
163b30beda2SAdam Ford 	}
164b30beda2SAdam Ford 
165b30beda2SAdam Ford 	platdata->musb_config.dyn_fifo = 1;
166b30beda2SAdam Ford 	platdata->musb_config.num_eps = fdtdec_get_int(fdt, node,
167b30beda2SAdam Ford 						       "num-eps", -1);
168b30beda2SAdam Ford 	if (platdata->musb_config.num_eps < 0) {
169b30beda2SAdam Ford 		pr_err("MUSB num-eps DT entry missing\n");
170b30beda2SAdam Ford 		return -ENOENT;
171b30beda2SAdam Ford 	}
172b30beda2SAdam Ford 
173b30beda2SAdam Ford 	platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node,
174b30beda2SAdam Ford 							"ram-bits", -1);
175b30beda2SAdam Ford 	if (platdata->musb_config.ram_bits < 0) {
176b30beda2SAdam Ford 		pr_err("MUSB ram-bits DT entry missing\n");
177b30beda2SAdam Ford 		return -ENOENT;
178b30beda2SAdam Ford 	}
179b30beda2SAdam Ford 
180b30beda2SAdam Ford 	platdata->plat.power = fdtdec_get_int(fdt, node,
181b30beda2SAdam Ford 								"power", -1);
182b30beda2SAdam Ford 	if (platdata->plat.power < 0) {
183b30beda2SAdam Ford 		pr_err("MUSB power DT entry missing\n");
184b30beda2SAdam Ford 		return -ENOENT;
185b30beda2SAdam Ford 	}
186b30beda2SAdam Ford 
187b30beda2SAdam Ford 	platdata->otg_board_data.interface_type = fdtdec_get_int(fdt, node,
188b30beda2SAdam Ford 									"interface-type", -1);
189b30beda2SAdam Ford 	if (platdata->otg_board_data.interface_type < 0) {
190b30beda2SAdam Ford 		pr_err("MUSB interface-type DT entry missing\n");
191b30beda2SAdam Ford 		return -ENOENT;
192b30beda2SAdam Ford 	}
193b30beda2SAdam Ford 
194b30beda2SAdam Ford #if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */
195b30beda2SAdam Ford 	platdata->plat.mode = fdtdec_get_int(fdt, node,
196b30beda2SAdam Ford 										"mode", -1);
197b30beda2SAdam Ford 	if (platdata->plat.mode < 0) {
198b30beda2SAdam Ford 		pr_err("MUSB mode DT entry missing\n");
199b30beda2SAdam Ford 		return -ENOENT;
200b30beda2SAdam Ford 	}
201b30beda2SAdam Ford #else /* MUSB_OTG, it doesn't work */
202b30beda2SAdam Ford #ifdef CONFIG_USB_MUSB_HOST /* Host seems to be the only option that works */
203b30beda2SAdam Ford 	platdata->plat.mode = MUSB_HOST;
204b30beda2SAdam Ford #else /* For that matter, MUSB_PERIPHERAL doesn't either */
205b30beda2SAdam Ford 	platdata->plat.mode = MUSB_PERIPHERAL;
206b30beda2SAdam Ford #endif
207b30beda2SAdam Ford #endif
208b30beda2SAdam Ford 	platdata->otg_board_data.dev = dev;
209b30beda2SAdam Ford 	platdata->plat.config = &platdata->musb_config;
210b30beda2SAdam Ford 	platdata->plat.platform_ops = &omap2430_ops;
211b30beda2SAdam Ford 	platdata->plat.board_data = &platdata->otg_board_data;
212b30beda2SAdam Ford 	return 0;
213b30beda2SAdam Ford }
214b30beda2SAdam Ford 
omap2430_musb_probe(struct udevice * dev)215b30beda2SAdam Ford static int omap2430_musb_probe(struct udevice *dev)
216b30beda2SAdam Ford {
217b30beda2SAdam Ford #ifdef CONFIG_USB_MUSB_HOST
218b30beda2SAdam Ford 	struct musb_host_data *host = dev_get_priv(dev);
219b30beda2SAdam Ford #endif
220b30beda2SAdam Ford 	struct omap2430_musb_platdata *platdata = dev_get_platdata(dev);
221b30beda2SAdam Ford 	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
222b30beda2SAdam Ford 	struct omap_musb_board_data *otg_board_data;
223b30beda2SAdam Ford 	int ret;
224b30beda2SAdam Ford 	void *base = dev_read_addr_ptr(dev);
225b30beda2SAdam Ford 
226b30beda2SAdam Ford 	priv->desc_before_addr = true;
227b30beda2SAdam Ford 
228b30beda2SAdam Ford 	otg_board_data = &platdata->otg_board_data;
229b30beda2SAdam Ford 
230b30beda2SAdam Ford #ifdef CONFIG_USB_MUSB_HOST
231b30beda2SAdam Ford 	host->host = musb_init_controller(&platdata->plat,
232b30beda2SAdam Ford 					  (struct device *)otg_board_data,
233b30beda2SAdam Ford 					  platdata->base);
234b30beda2SAdam Ford 	if (!host->host) {
235b30beda2SAdam Ford 		return -EIO;
236b30beda2SAdam Ford 	}
237b30beda2SAdam Ford 
238b30beda2SAdam Ford 	ret = musb_lowlevel_init(host);
239b30beda2SAdam Ford #else
240b30beda2SAdam Ford 	ret = musb_register(&platdata->plat,
241b30beda2SAdam Ford 			  (struct device *)otg_board_data,
242b30beda2SAdam Ford 			  platdata->base);
243b30beda2SAdam Ford #endif
244b30beda2SAdam Ford 	return ret;
245b30beda2SAdam Ford }
246b30beda2SAdam Ford 
omap2430_musb_remove(struct udevice * dev)247b30beda2SAdam Ford static int omap2430_musb_remove(struct udevice *dev)
248b30beda2SAdam Ford {
249b30beda2SAdam Ford 	struct musb_host_data *host = dev_get_priv(dev);
250b30beda2SAdam Ford 
251b30beda2SAdam Ford 	musb_stop(host->host);
252b30beda2SAdam Ford 
253b30beda2SAdam Ford 	return 0;
254b30beda2SAdam Ford }
255b30beda2SAdam Ford 
256b30beda2SAdam Ford static const struct udevice_id omap2430_musb_ids[] = {
257b30beda2SAdam Ford 	{ .compatible = "ti,omap3-musb" },
258b30beda2SAdam Ford 	{ .compatible = "ti,omap4-musb" },
259b30beda2SAdam Ford 	{ }
260b30beda2SAdam Ford };
261b30beda2SAdam Ford 
262b30beda2SAdam Ford U_BOOT_DRIVER(omap2430_musb) = {
263b30beda2SAdam Ford 	.name	= "omap2430-musb",
264b30beda2SAdam Ford #ifdef CONFIG_USB_MUSB_HOST
265b30beda2SAdam Ford 	.id		= UCLASS_USB,
266b30beda2SAdam Ford #else
267*20828bbaSJean-Jacques Hiblot 	.id		= UCLASS_USB_GADGET_GENERIC,
268b30beda2SAdam Ford #endif
269b30beda2SAdam Ford 	.of_match = omap2430_musb_ids,
270b30beda2SAdam Ford 	.ofdata_to_platdata = omap2430_musb_ofdata_to_platdata,
271b30beda2SAdam Ford 	.probe = omap2430_musb_probe,
272b30beda2SAdam Ford 	.remove = omap2430_musb_remove,
273b30beda2SAdam Ford #ifdef CONFIG_USB_MUSB_HOST
274b30beda2SAdam Ford 	.ops = &musb_usb_ops,
275b30beda2SAdam Ford #endif
276b30beda2SAdam Ford 	.platdata_auto_alloc_size = sizeof(struct omap2430_musb_platdata),
277b30beda2SAdam Ford 	.priv_auto_alloc_size = sizeof(struct musb_host_data),
278b30beda2SAdam Ford };
279b30beda2SAdam Ford 
2803739bf7eSSven Schwermer #endif /* CONFIG_IS_ENABLED(DM_USB) */
281