xref: /openbmc/u-boot/drivers/usb/musb-new/omap2430.c (revision cd71b1d5)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2005-2007 by Texas Instruments
4  * Some code has been taken from tusb6010.c
5  * Copyrights for that are attributable to:
6  * Copyright (C) 2006 Nokia Corporation
7  * Tony Lindgren <tony@atomide.com>
8  *
9  * This file is part of the Inventra Controller Driver for Linux.
10  */
11 #include <common.h>
12 #include <dm.h>
13 #include <dm/device-internal.h>
14 #include <dm/lists.h>
15 #include <linux/usb/otg.h>
16 #include <asm/omap_common.h>
17 #include <asm/omap_musb.h>
18 #include <twl4030.h>
19 #include <twl6030.h>
20 #include "linux-compat.h"
21 #include "musb_core.h"
22 #include "omap2430.h"
23 #include "musb_uboot.h"
24 
25 static inline void omap2430_low_level_exit(struct musb *musb)
26 {
27 	u32 l;
28 
29 	/* in any role */
30 	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
31 	l |= ENABLEFORCE;	/* enable MSTANDBY */
32 	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
33 }
34 
35 static inline void omap2430_low_level_init(struct musb *musb)
36 {
37 	u32 l;
38 
39 	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
40 	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
41 	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
42 }
43 
44 
45 static int omap2430_musb_init(struct musb *musb)
46 {
47 	u32 l;
48 	int status = 0;
49 	unsigned long int start;
50 
51 	struct omap_musb_board_data *data =
52 		(struct omap_musb_board_data *)musb->controller;
53 
54 	/* Reset the controller */
55 	musb_writel(musb->mregs, OTG_SYSCONFIG, SOFTRST);
56 
57 	start = get_timer(0);
58 
59 	while (1) {
60 		l = musb_readl(musb->mregs, OTG_SYSCONFIG);
61 		if ((l & SOFTRST) == 0)
62 			break;
63 
64 		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
65 			dev_err(musb->controller, "MUSB reset is taking too long\n");
66 			return -ENODEV;
67 		}
68 	}
69 
70 	l = musb_readl(musb->mregs, OTG_INTERFSEL);
71 
72 	if (data->interface_type == MUSB_INTERFACE_UTMI) {
73 		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
74 		l &= ~ULPI_12PIN;       /* Disable ULPI */
75 		l |= UTMI_8BIT;         /* Enable UTMI  */
76 	} else {
77 		l |= ULPI_12PIN;
78 	}
79 
80 	musb_writel(musb->mregs, OTG_INTERFSEL, l);
81 
82 	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
83 			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
84 			musb_readl(musb->mregs, OTG_REVISION),
85 			musb_readl(musb->mregs, OTG_SYSCONFIG),
86 			musb_readl(musb->mregs, OTG_SYSSTATUS),
87 			musb_readl(musb->mregs, OTG_INTERFSEL),
88 			musb_readl(musb->mregs, OTG_SIMENABLE));
89 	return 0;
90 
91 err1:
92 	return status;
93 }
94 
95 static int omap2430_musb_enable(struct musb *musb)
96 {
97 #ifdef CONFIG_TWL4030_USB
98 	if (twl4030_usb_ulpi_init()) {
99 		serial_printf("ERROR: %s Could not initialize PHY\n",
100 				__PRETTY_FUNCTION__);
101 	}
102 #endif
103 
104 #ifdef CONFIG_TWL6030_POWER
105 	twl6030_usb_device_settings();
106 #endif
107 
108 #ifdef CONFIG_OMAP44XX
109 	u32 *usbotghs_control = (u32 *)((*ctrl)->control_usbotghs_ctrl);
110 	*usbotghs_control = USBOTGHS_CONTROL_AVALID |
111 		USBOTGHS_CONTROL_VBUSVALID | USBOTGHS_CONTROL_IDDIG;
112 #endif
113 
114 	return 0;
115 }
116 
117 static void omap2430_musb_disable(struct musb *musb)
118 {
119 
120 }
121 
122 static int omap2430_musb_exit(struct musb *musb)
123 {
124 	del_timer_sync(&musb_idle_timer);
125 
126 	omap2430_low_level_exit(musb);
127 
128 	return 0;
129 }
130 
131 const struct musb_platform_ops omap2430_ops = {
132 	.init		= omap2430_musb_init,
133 	.exit		= omap2430_musb_exit,
134 	.enable		= omap2430_musb_enable,
135 	.disable	= omap2430_musb_disable,
136 };
137 
138 #if CONFIG_IS_ENABLED(DM_USB)
139 
140 struct omap2430_musb_platdata {
141 	void *base;
142 	void *ctrl_mod_base;
143 	struct musb_hdrc_platform_data plat;
144 	struct musb_hdrc_config musb_config;
145 	struct omap_musb_board_data otg_board_data;
146 };
147 
148 static int omap2430_musb_ofdata_to_platdata(struct udevice *dev)
149 {
150 	struct omap2430_musb_platdata *platdata = dev_get_platdata(dev);
151 	const void *fdt = gd->fdt_blob;
152 	int node = dev_of_offset(dev);
153 
154 	platdata->base = (void *)dev_read_addr_ptr(dev);
155 
156 	platdata->musb_config.multipoint = fdtdec_get_int(fdt, node,
157 							  "multipoint",
158 							  -1);
159 	if (platdata->musb_config.multipoint < 0) {
160 		pr_err("MUSB multipoint DT entry missing\n");
161 		return -ENOENT;
162 	}
163 
164 	platdata->musb_config.dyn_fifo = 1;
165 	platdata->musb_config.num_eps = fdtdec_get_int(fdt, node,
166 						       "num-eps", -1);
167 	if (platdata->musb_config.num_eps < 0) {
168 		pr_err("MUSB num-eps DT entry missing\n");
169 		return -ENOENT;
170 	}
171 
172 	platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node,
173 							"ram-bits", -1);
174 	if (platdata->musb_config.ram_bits < 0) {
175 		pr_err("MUSB ram-bits DT entry missing\n");
176 		return -ENOENT;
177 	}
178 
179 	platdata->plat.power = fdtdec_get_int(fdt, node,
180 								"power", -1);
181 	if (platdata->plat.power < 0) {
182 		pr_err("MUSB power DT entry missing\n");
183 		return -ENOENT;
184 	}
185 
186 	platdata->otg_board_data.interface_type = fdtdec_get_int(fdt, node,
187 									"interface-type", -1);
188 	if (platdata->otg_board_data.interface_type < 0) {
189 		pr_err("MUSB interface-type DT entry missing\n");
190 		return -ENOENT;
191 	}
192 
193 #if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */
194 	platdata->plat.mode = fdtdec_get_int(fdt, node,
195 										"mode", -1);
196 	if (platdata->plat.mode < 0) {
197 		pr_err("MUSB mode DT entry missing\n");
198 		return -ENOENT;
199 	}
200 #else /* MUSB_OTG, it doesn't work */
201 #ifdef CONFIG_USB_MUSB_HOST /* Host seems to be the only option that works */
202 	platdata->plat.mode = MUSB_HOST;
203 #else /* For that matter, MUSB_PERIPHERAL doesn't either */
204 	platdata->plat.mode = MUSB_PERIPHERAL;
205 #endif
206 #endif
207 	platdata->otg_board_data.dev = dev;
208 	platdata->plat.config = &platdata->musb_config;
209 	platdata->plat.platform_ops = &omap2430_ops;
210 	platdata->plat.board_data = &platdata->otg_board_data;
211 	return 0;
212 }
213 
214 static int omap2430_musb_probe(struct udevice *dev)
215 {
216 #ifdef CONFIG_USB_MUSB_HOST
217 	struct musb_host_data *host = dev_get_priv(dev);
218 #endif
219 	struct omap2430_musb_platdata *platdata = dev_get_platdata(dev);
220 	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
221 	struct omap_musb_board_data *otg_board_data;
222 	int ret;
223 	void *base = dev_read_addr_ptr(dev);
224 
225 	priv->desc_before_addr = true;
226 
227 	otg_board_data = &platdata->otg_board_data;
228 
229 #ifdef CONFIG_USB_MUSB_HOST
230 	host->host = musb_init_controller(&platdata->plat,
231 					  (struct device *)otg_board_data,
232 					  platdata->base);
233 	if (!host->host) {
234 		return -EIO;
235 	}
236 
237 	ret = musb_lowlevel_init(host);
238 #else
239 	ret = musb_register(&platdata->plat,
240 			  (struct device *)otg_board_data,
241 			  platdata->base);
242 #endif
243 	return ret;
244 }
245 
246 static int omap2430_musb_remove(struct udevice *dev)
247 {
248 	struct musb_host_data *host = dev_get_priv(dev);
249 
250 	musb_stop(host->host);
251 
252 	return 0;
253 }
254 
255 static const struct udevice_id omap2430_musb_ids[] = {
256 	{ .compatible = "ti,omap3-musb" },
257 	{ .compatible = "ti,omap4-musb" },
258 	{ }
259 };
260 
261 U_BOOT_DRIVER(omap2430_musb) = {
262 	.name	= "omap2430-musb",
263 #ifdef CONFIG_USB_MUSB_HOST
264 	.id		= UCLASS_USB,
265 #else
266 	.id		= UCLASS_USB_GADGET_GENERIC,
267 #endif
268 	.of_match = omap2430_musb_ids,
269 	.ofdata_to_platdata = omap2430_musb_ofdata_to_platdata,
270 	.probe = omap2430_musb_probe,
271 	.remove = omap2430_musb_remove,
272 #ifdef CONFIG_USB_MUSB_HOST
273 	.ops = &musb_usb_ops,
274 #endif
275 	.platdata_auto_alloc_size = sizeof(struct omap2430_musb_platdata),
276 	.priv_auto_alloc_size = sizeof(struct musb_host_data),
277 };
278 
279 #endif /* CONFIG_IS_ENABLED(DM_USB) */
280