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 17 #include <asm/io.h> 18 #include <asm/omap_musb.h> 19 #include "musb_uboot.h" 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 #ifdef CONFIG_DM_USB 24 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; 86 int node = dev_of_offset(dev); 87 int phys; 88 int ctrl_mod; 89 int usb_index; 90 91 platdata->base = (void *)devfdt_get_addr_index(dev, 1); 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) { 109 error("MUSB multipoint DT entry missing\n"); 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) { 118 error("MUSB num-eps DT entry missing\n"); 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) { 125 error("MUSB ram-bits DT entry missing\n"); 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) { 135 error("MUSB mentor,power DT entry missing\n"); 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; 181 int node = dev_of_offset(dev); 182 int ret; 183 184 ret = ti_musb_ofdata_to_platdata(dev); 185 if (ret) { 186 error("platdata dt parse error\n"); 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 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 212 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 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 */ 229 ret = device_bind_driver_to_node(parent, "ti-musb-host", 230 name, offset_to_ofnode(node), &dev); 231 if (ret) { 232 error("musb - not able to bind usb host node\n"); 233 return ret; 234 } 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 */ 256