]>
Commit | Line | Data |
---|---|---|
28b8d5fd M |
1 | /* |
2 | * MISC driver for TI MUSB Glue. | |
3 | * | |
4 | * (C) Copyright 2016 | |
5 | * Texas Instruments Incorporated, <www.ti.com> | |
6 | * | |
7 | * SPDX-License-Identifier: GPL-2.0+ | |
8 | */ | |
9 | #include <common.h> | |
10 | #include <command.h> | |
11 | #include <console.h> | |
12 | #include <dm.h> | |
13 | #include <linux/usb/otg.h> | |
14 | #include <dm/device-internal.h> | |
15 | #include <dm/lists.h> | |
16 | ||
ae6acf9f M |
17 | #include <asm/io.h> |
18 | #include <asm/omap_musb.h> | |
19 | #include "musb_uboot.h" | |
20 | ||
28b8d5fd M |
21 | DECLARE_GLOBAL_DATA_PTR; |
22 | ||
23 | #ifdef CONFIG_DM_USB | |
24 | ||
ae6acf9f M |
25 | /* USB 2.0 PHY Control */ |
26 | #define CM_PHY_PWRDN (1 << 0) | |
27 | #define CM_PHY_OTG_PWRDN (1 << 1) | |
28 | #define OTGVDET_EN (1 << 19) | |
29 | #define OTGSESSENDEN (1 << 20) | |
30 | ||
31 | #define AM335X_USB1_CTRL 0x8 | |
32 | ||
33 | struct ti_musb_platdata { | |
34 | void *base; | |
35 | void *ctrl_mod_base; | |
36 | struct musb_hdrc_platform_data plat; | |
37 | struct musb_hdrc_config musb_config; | |
38 | struct omap_musb_board_data otg_board_data; | |
39 | }; | |
40 | ||
41 | static int ti_musb_get_usb_index(int node) | |
42 | { | |
43 | const void *fdt = gd->fdt_blob; | |
44 | int i = 0; | |
45 | char path[64]; | |
46 | const char *alias_path; | |
47 | char alias[16]; | |
48 | ||
49 | fdt_get_path(fdt, node, path, sizeof(path)); | |
50 | ||
51 | do { | |
52 | snprintf(alias, sizeof(alias), "usb%d", i); | |
53 | alias_path = fdt_get_alias(fdt, alias); | |
54 | if (alias_path == NULL) { | |
55 | debug("USB index not found\n"); | |
56 | return -ENOENT; | |
57 | } | |
58 | ||
59 | if (!strcmp(path, alias_path)) | |
60 | return i; | |
61 | ||
62 | i++; | |
63 | } while (alias_path); | |
64 | ||
65 | return -ENOENT; | |
66 | } | |
67 | ||
68 | static void ti_musb_set_phy_power(struct udevice *dev, u8 on) | |
69 | { | |
70 | struct ti_musb_platdata *platdata = dev_get_platdata(dev); | |
71 | ||
72 | if (on) { | |
73 | clrsetbits_le32(platdata->ctrl_mod_base, | |
74 | CM_PHY_PWRDN | CM_PHY_OTG_PWRDN, | |
75 | OTGVDET_EN | OTGSESSENDEN); | |
76 | } else { | |
77 | clrsetbits_le32(platdata->ctrl_mod_base, 0, | |
78 | CM_PHY_PWRDN | CM_PHY_OTG_PWRDN); | |
79 | } | |
80 | } | |
81 | ||
82 | static int ti_musb_ofdata_to_platdata(struct udevice *dev) | |
83 | { | |
84 | struct ti_musb_platdata *platdata = dev_get_platdata(dev); | |
85 | const void *fdt = gd->fdt_blob; | |
e160f7d4 | 86 | int node = dev_of_offset(dev); |
ae6acf9f M |
87 | int phys; |
88 | int ctrl_mod; | |
89 | int usb_index; | |
90 | ||
a821c4af | 91 | platdata->base = (void *)devfdt_get_addr_index(dev, 1); |
ae6acf9f M |
92 | |
93 | phys = fdtdec_lookup_phandle(fdt, node, "phys"); | |
94 | ctrl_mod = fdtdec_lookup_phandle(fdt, phys, "ti,ctrl_mod"); | |
95 | platdata->ctrl_mod_base = (void *)fdtdec_get_addr(fdt, ctrl_mod, "reg"); | |
96 | usb_index = ti_musb_get_usb_index(node); | |
97 | switch (usb_index) { | |
98 | case 1: | |
99 | platdata->ctrl_mod_base += AM335X_USB1_CTRL; | |
100 | case 0: | |
101 | default: | |
102 | break; | |
103 | } | |
104 | ||
105 | platdata->musb_config.multipoint = fdtdec_get_int(fdt, node, | |
106 | "mentor,multipoint", | |
107 | -1); | |
108 | if (platdata->musb_config.multipoint < 0) { | |
9b643e31 | 109 | pr_err("MUSB multipoint DT entry missing\n"); |
ae6acf9f M |
110 | return -ENOENT; |
111 | } | |
112 | ||
113 | platdata->musb_config.dyn_fifo = 1; | |
114 | ||
115 | platdata->musb_config.num_eps = fdtdec_get_int(fdt, node, | |
116 | "mentor,num-eps", -1); | |
117 | if (platdata->musb_config.num_eps < 0) { | |
9b643e31 | 118 | pr_err("MUSB num-eps DT entry missing\n"); |
ae6acf9f M |
119 | return -ENOENT; |
120 | } | |
121 | ||
122 | platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node, | |
123 | "mentor,ram-bits", -1); | |
124 | if (platdata->musb_config.ram_bits < 0) { | |
9b643e31 | 125 | pr_err("MUSB ram-bits DT entry missing\n"); |
ae6acf9f M |
126 | return -ENOENT; |
127 | } | |
128 | ||
129 | platdata->otg_board_data.set_phy_power = ti_musb_set_phy_power; | |
130 | platdata->otg_board_data.dev = dev; | |
131 | platdata->plat.config = &platdata->musb_config; | |
132 | ||
133 | platdata->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1); | |
134 | if (platdata->plat.power < 0) { | |
9b643e31 | 135 | pr_err("MUSB mentor,power DT entry missing\n"); |
ae6acf9f M |
136 | return -ENOENT; |
137 | } | |
138 | ||
139 | platdata->plat.platform_ops = &musb_dsps_ops; | |
140 | platdata->plat.board_data = &platdata->otg_board_data; | |
141 | ||
142 | return 0; | |
143 | } | |
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 | struct omap_musb_board_data *otg_board_data; | |
151 | int ret; | |
152 | ||
153 | priv->desc_before_addr = true; | |
154 | ||
155 | otg_board_data = &platdata->otg_board_data; | |
156 | ||
157 | host->host = musb_init_controller(&platdata->plat, | |
158 | (struct device *)otg_board_data, | |
159 | platdata->base); | |
160 | if (!host->host) | |
161 | return -EIO; | |
162 | ||
163 | ret = musb_lowlevel_init(host); | |
164 | ||
165 | return ret; | |
166 | } | |
167 | ||
168 | static int ti_musb_host_remove(struct udevice *dev) | |
169 | { | |
170 | struct musb_host_data *host = dev_get_priv(dev); | |
171 | ||
172 | musb_stop(host->host); | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
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; | |
e160f7d4 | 181 | int node = dev_of_offset(dev); |
ae6acf9f M |
182 | int ret; |
183 | ||
184 | ret = ti_musb_ofdata_to_platdata(dev); | |
185 | if (ret) { | |
9b643e31 | 186 | pr_err("platdata dt parse error\n"); |
ae6acf9f M |
187 | return ret; |
188 | } | |
189 | ||
190 | platdata->plat.mode = MUSB_HOST; | |
191 | ||
192 | return 0; | |
193 | } | |
194 | ||
195 | U_BOOT_DRIVER(ti_musb_host) = { | |
196 | .name = "ti-musb-host", | |
197 | .id = UCLASS_USB, | |
198 | .ofdata_to_platdata = ti_musb_host_ofdata_to_platdata, | |
199 | .probe = ti_musb_host_probe, | |
200 | .remove = ti_musb_host_remove, | |
201 | .ops = &musb_usb_ops, | |
202 | .platdata_auto_alloc_size = sizeof(struct ti_musb_platdata), | |
203 | .priv_auto_alloc_size = sizeof(struct musb_host_data), | |
204 | }; | |
205 | ||
28b8d5fd M |
206 | static int ti_musb_wrapper_bind(struct udevice *parent) |
207 | { | |
208 | const void *fdt = gd->fdt_blob; | |
209 | int node; | |
210 | int ret; | |
211 | ||
e160f7d4 | 212 | for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; |
28b8d5fd M |
213 | node = fdt_next_subnode(fdt, node)) { |
214 | struct udevice *dev; | |
215 | const char *name = fdt_get_name(fdt, node, NULL); | |
216 | enum usb_dr_mode dr_mode; | |
217 | struct driver *drv; | |
218 | ||
219 | if (strncmp(name, "usb@", 4)) | |
220 | continue; | |
221 | ||
222 | dr_mode = usb_get_dr_mode(node); | |
223 | switch (dr_mode) { | |
224 | case USB_DR_MODE_PERIPHERAL: | |
225 | /* Bind MUSB device */ | |
226 | break; | |
227 | case USB_DR_MODE_HOST: | |
228 | /* Bind MUSB host */ | |
ae6acf9f | 229 | ret = device_bind_driver_to_node(parent, "ti-musb-host", |
45a26867 | 230 | name, offset_to_ofnode(node), &dev); |
ae6acf9f | 231 | if (ret) { |
9b643e31 | 232 | pr_err("musb - not able to bind usb host node\n"); |
ae6acf9f M |
233 | return ret; |
234 | } | |
28b8d5fd M |
235 | break; |
236 | default: | |
237 | break; | |
238 | }; | |
239 | } | |
240 | return 0; | |
241 | } | |
242 | ||
243 | static const struct udevice_id ti_musb_ids[] = { | |
244 | { .compatible = "ti,am33xx-usb" }, | |
245 | { } | |
246 | }; | |
247 | ||
248 | U_BOOT_DRIVER(ti_musb_wrapper) = { | |
249 | .name = "ti-musb-wrapper", | |
250 | .id = UCLASS_MISC, | |
251 | .of_match = ti_musb_ids, | |
252 | .bind = ti_musb_wrapper_bind, | |
253 | }; | |
254 | ||
255 | #endif /* CONFIG_DM_USB */ |