Merge tag 'u-boot-imx-20190101' of git://www.denx.de/git/u-boot-imx
[pandora-u-boot.git] / drivers / usb / musb-new / ti-musb.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * MISC driver for TI MUSB Glue.
4  *
5  * (C) Copyright 2016
6  *     Texas Instruments Incorporated, <www.ti.com>
7  */
8 #include <common.h>
9 #include <command.h>
10 #include <console.h>
11 #include <dm.h>
12 #include <linux/usb/otg.h>
13 #include <dm/device-internal.h>
14 #include <dm/lists.h>
15
16 #include <asm/io.h>
17 #include <asm/omap_musb.h>
18 #include "musb_uboot.h"
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 #if CONFIG_IS_ENABLED(DM_USB)
23 /* USB 2.0 PHY Control */
24 #define CM_PHY_PWRDN                    (1 << 0)
25 #define CM_PHY_OTG_PWRDN                (1 << 1)
26 #define OTGVDET_EN                      (1 << 19)
27 #define OTGSESSENDEN                    (1 << 20)
28
29 #define AM335X_USB0_CTRL        0x0
30 #define AM335X_USB1_CTRL        0x8
31
32 static void ti_musb_set_phy_power(struct udevice *dev, u8 on)
33 {
34         struct ti_musb_platdata *platdata = dev_get_platdata(dev);
35
36         if (!platdata->ctrl_mod_base)
37                 return;
38
39         if (on) {
40                 clrsetbits_le32(platdata->ctrl_mod_base,
41                                 CM_PHY_PWRDN | CM_PHY_OTG_PWRDN,
42                                 OTGVDET_EN | OTGSESSENDEN);
43         } else {
44                 clrsetbits_le32(platdata->ctrl_mod_base, 0,
45                                 CM_PHY_PWRDN | CM_PHY_OTG_PWRDN);
46         }
47 }
48
49 #if CONFIG_IS_ENABLED(OF_CONTROL)
50
51 static int ti_musb_get_usb_index(int node)
52 {
53         const void *fdt = gd->fdt_blob;
54         int i = 0;
55         char path[64];
56         const char *alias_path;
57         char alias[16];
58
59         fdt_get_path(fdt, node, path, sizeof(path));
60
61         do {
62                 snprintf(alias, sizeof(alias), "usb%d", i);
63                 alias_path = fdt_get_alias(fdt, alias);
64                 if (alias_path == NULL) {
65                         debug("USB index not found\n");
66                         return -ENOENT;
67                 }
68
69                 if (!strcmp(path, alias_path))
70                         return i;
71
72                 i++;
73         } while (alias_path);
74
75         return -ENOENT;
76 }
77
78 static int ti_musb_ofdata_to_platdata(struct udevice *dev)
79 {
80         struct ti_musb_platdata *platdata = dev_get_platdata(dev);
81         const void *fdt = gd->fdt_blob;
82         int node = dev_of_offset(dev);
83         int phys;
84         int ctrl_mod;
85         int usb_index;
86         struct musb_hdrc_config *musb_config;
87
88         platdata->base = (void *)devfdt_get_addr_index(dev, 1);
89
90         phys = fdtdec_lookup_phandle(fdt, node, "phys");
91         ctrl_mod = fdtdec_lookup_phandle(fdt, phys, "ti,ctrl_mod");
92         platdata->ctrl_mod_base = (void *)fdtdec_get_addr(fdt, ctrl_mod, "reg");
93         usb_index = ti_musb_get_usb_index(node);
94         switch (usb_index) {
95         case 1:
96                 platdata->ctrl_mod_base += AM335X_USB1_CTRL;
97                 break;
98         case 0:
99                 platdata->ctrl_mod_base += AM335X_USB0_CTRL;
100                 break;
101         default:
102                 break;
103         }
104
105         musb_config = malloc(sizeof(struct musb_hdrc_config));
106         memset(musb_config, 0, sizeof(struct musb_hdrc_config));
107
108         musb_config->multipoint = fdtdec_get_int(fdt, node,
109                                                  "mentor,multipoint", -1);
110         if (musb_config->multipoint < 0) {
111                 pr_err("MUSB multipoint DT entry missing\n");
112                 return -ENOENT;
113         }
114
115         musb_config->dyn_fifo = 1;
116
117         musb_config->num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps",
118                                               -1);
119         if (musb_config->num_eps < 0) {
120                 pr_err("MUSB num-eps DT entry missing\n");
121                 return -ENOENT;
122         }
123
124         musb_config->ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits",
125                                                -1);
126         if (musb_config->ram_bits < 0) {
127                 pr_err("MUSB ram-bits DT entry missing\n");
128                 return -ENOENT;
129         }
130
131         platdata->plat.config = musb_config;
132
133         platdata->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1);
134         if (platdata->plat.power < 0) {
135                 pr_err("MUSB mentor,power DT entry missing\n");
136                 return -ENOENT;
137         }
138
139         platdata->plat.platform_ops = &musb_dsps_ops;
140
141         return 0;
142 }
143 #endif
144
145 static int ti_musb_host_probe(struct udevice *dev)
146 {
147         struct musb_host_data *host = dev_get_priv(dev);
148         struct ti_musb_platdata *platdata = dev_get_platdata(dev);
149         struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
150         int ret;
151
152         priv->desc_before_addr = true;
153
154         host->host = musb_init_controller(&platdata->plat,
155                                           NULL,
156                                           platdata->base);
157         if (!host->host)
158                 return -EIO;
159
160         ti_musb_set_phy_power(dev, 1);
161         ret = musb_lowlevel_init(host);
162
163         return ret;
164 }
165
166 static int ti_musb_host_remove(struct udevice *dev)
167 {
168         struct musb_host_data *host = dev_get_priv(dev);
169
170         musb_stop(host->host);
171         ti_musb_set_phy_power(dev, 0);
172
173         return 0;
174 }
175
176 #if CONFIG_IS_ENABLED(OF_CONTROL)
177 static int ti_musb_host_ofdata_to_platdata(struct udevice *dev)
178 {
179         struct ti_musb_platdata *platdata = dev_get_platdata(dev);
180         const void *fdt = gd->fdt_blob;
181         int node = dev_of_offset(dev);
182         int ret;
183
184         ret = ti_musb_ofdata_to_platdata(dev);
185         if (ret) {
186                 pr_err("platdata dt parse error\n");
187                 return ret;
188         }
189
190         platdata->plat.mode = MUSB_HOST;
191
192         return 0;
193 }
194 #endif
195
196 U_BOOT_DRIVER(ti_musb_host) = {
197         .name   = "ti-musb-host",
198         .id     = UCLASS_USB,
199 #if CONFIG_IS_ENABLED(OF_CONTROL)
200         .ofdata_to_platdata = ti_musb_host_ofdata_to_platdata,
201 #endif
202         .probe = ti_musb_host_probe,
203         .remove = ti_musb_host_remove,
204         .ops    = &musb_usb_ops,
205         .platdata_auto_alloc_size = sizeof(struct ti_musb_platdata),
206         .priv_auto_alloc_size = sizeof(struct musb_host_data),
207 };
208
209 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
210 struct ti_musb_peripheral {
211         struct musb *periph;
212 };
213
214 #if CONFIG_IS_ENABLED(OF_CONTROL)
215 static int ti_musb_peripheral_ofdata_to_platdata(struct udevice *dev)
216 {
217         struct ti_musb_platdata *platdata = dev_get_platdata(dev);
218         const void *fdt = gd->fdt_blob;
219         int node = dev_of_offset(dev);
220         int ret;
221
222         ret = ti_musb_ofdata_to_platdata(dev);
223         if (ret) {
224                 pr_err("platdata dt parse error\n");
225                 return ret;
226         }
227         platdata->plat.mode = MUSB_PERIPHERAL;
228
229         return 0;
230 }
231 #endif
232
233 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
234 {
235         struct ti_musb_peripheral *priv = dev_get_priv(dev);
236
237         priv->periph->isr(0, priv->periph);
238
239         return 0;
240 }
241
242 static int ti_musb_peripheral_probe(struct udevice *dev)
243 {
244         struct ti_musb_peripheral *priv = dev_get_priv(dev);
245         struct ti_musb_platdata *platdata = dev_get_platdata(dev);
246         int ret;
247
248         priv->periph = musb_init_controller(&platdata->plat,
249                                             NULL,
250                                             platdata->base);
251         if (!priv->periph)
252                 return -EIO;
253
254         ti_musb_set_phy_power(dev, 1);
255         musb_gadget_setup(priv->periph);
256         return usb_add_gadget_udc((struct device *)dev, &priv->periph->g);
257 }
258
259 static int ti_musb_peripheral_remove(struct udevice *dev)
260 {
261         struct ti_musb_peripheral *priv = dev_get_priv(dev);
262
263         usb_del_gadget_udc(&priv->periph->g);
264         ti_musb_set_phy_power(dev, 0);
265
266         return 0;
267 }
268
269 U_BOOT_DRIVER(ti_musb_peripheral) = {
270         .name   = "ti-musb-peripheral",
271         .id     = UCLASS_USB_GADGET_GENERIC,
272 #if CONFIG_IS_ENABLED(OF_CONTROL)
273         .ofdata_to_platdata = ti_musb_peripheral_ofdata_to_platdata,
274 #endif
275         .probe = ti_musb_peripheral_probe,
276         .remove = ti_musb_peripheral_remove,
277         .ops    = &musb_usb_ops,
278         .platdata_auto_alloc_size = sizeof(struct ti_musb_platdata),
279         .priv_auto_alloc_size = sizeof(struct ti_musb_peripheral),
280         .flags = DM_FLAG_PRE_RELOC,
281 };
282 #endif
283
284 #if CONFIG_IS_ENABLED(OF_CONTROL)
285 static int ti_musb_wrapper_bind(struct udevice *parent)
286 {
287         const void *fdt = gd->fdt_blob;
288         int node;
289         int ret;
290
291         for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
292              node = fdt_next_subnode(fdt, node)) {
293                 struct udevice *dev;
294                 const char *name = fdt_get_name(fdt, node, NULL);
295                 enum usb_dr_mode dr_mode;
296                 struct driver *drv;
297
298                 if (strncmp(name, "usb@", 4))
299                         continue;
300
301                 dr_mode = usb_get_dr_mode(node);
302                 switch (dr_mode) {
303                 case USB_DR_MODE_PERIPHERAL:
304                         /* Bind MUSB device */
305                         ret = device_bind_driver_to_node(parent,
306                                                          "ti-musb-peripheral",
307                                                          name,
308                                                          offset_to_ofnode(node),
309                                                          &dev);
310                         if (ret)
311                                 pr_err("musb - not able to bind usb peripheral node\n");
312                         break;
313                 case USB_DR_MODE_HOST:
314                         /* Bind MUSB host */
315                         ret = device_bind_driver_to_node(parent,
316                                                          "ti-musb-host",
317                                                          name,
318                                                          offset_to_ofnode(node),
319                                                          &dev);
320                         if (ret)
321                                 pr_err("musb - not able to bind usb host node\n");
322                         break;
323                 default:
324                         break;
325                 };
326         }
327         return 0;
328 }
329
330 static const struct udevice_id ti_musb_ids[] = {
331         { .compatible = "ti,am33xx-usb" },
332         { }
333 };
334
335 U_BOOT_DRIVER(ti_musb_wrapper) = {
336         .name   = "ti-musb-wrapper",
337         .id     = UCLASS_MISC,
338         .of_match = ti_musb_ids,
339         .bind = ti_musb_wrapper_bind,
340 };
341 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
342
343 #endif /* CONFIG_IS_ENABLED(DM_USB) */