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