1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Generic DWC3 Glue layer 4 * 5 * Copyright (C) 2016 - 2018 Xilinx, Inc. 6 * 7 * Based on dwc3-omap.c. 8 */ 9 10 #include <common.h> 11 #include <asm-generic/io.h> 12 #include <dm.h> 13 #include <dm/device-internal.h> 14 #include <dm/lists.h> 15 #include <dwc3-uboot.h> 16 #include <linux/usb/ch9.h> 17 #include <linux/usb/gadget.h> 18 #include <malloc.h> 19 #include <usb.h> 20 #include "core.h" 21 #include "gadget.h" 22 #include <reset.h> 23 #include <clk.h> 24 25 struct dwc3_generic_plat { 26 fdt_addr_t base; 27 u32 maximum_speed; 28 enum usb_dr_mode dr_mode; 29 }; 30 31 struct dwc3_generic_priv { 32 void *base; 33 struct dwc3 dwc3; 34 struct phy *phys; 35 int num_phys; 36 }; 37 38 static int dwc3_generic_probe(struct udevice *dev, 39 struct dwc3_generic_priv *priv) 40 { 41 int rc; 42 struct dwc3_generic_plat *plat = dev_get_platdata(dev); 43 struct dwc3 *dwc3 = &priv->dwc3; 44 45 dwc3->maximum_speed = plat->maximum_speed; 46 dwc3->dr_mode = plat->dr_mode; 47 48 rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys); 49 if (rc) 50 return rc; 51 52 priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE); 53 dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START; 54 dwc3->dev = dev; 55 56 rc = dwc3_init(dwc3); 57 if (rc) { 58 unmap_physmem(priv->base, MAP_NOCACHE); 59 return rc; 60 } 61 62 return 0; 63 } 64 65 static int dwc3_generic_remove(struct udevice *dev, 66 struct dwc3_generic_priv *priv) 67 { 68 struct dwc3 *dwc3 = &priv->dwc3; 69 70 dwc3_remove(dwc3); 71 dwc3_shutdown_phy(dev, priv->phys, priv->num_phys); 72 unmap_physmem(dwc3->regs, MAP_NOCACHE); 73 74 return 0; 75 } 76 77 static int dwc3_generic_ofdata_to_platdata(struct udevice *dev) 78 { 79 struct dwc3_generic_plat *plat = dev_get_platdata(dev); 80 int node = dev_of_offset(dev); 81 82 plat->base = devfdt_get_addr(dev); 83 84 plat->maximum_speed = usb_get_maximum_speed(node); 85 if (plat->maximum_speed == USB_SPEED_UNKNOWN) { 86 pr_err("Invalid usb maximum speed\n"); 87 return -ENODEV; 88 } 89 90 plat->dr_mode = usb_get_dr_mode(node); 91 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) { 92 pr_err("Invalid usb mode setup\n"); 93 return -ENODEV; 94 } 95 96 return 0; 97 } 98 99 #if CONFIG_IS_ENABLED(DM_USB_GADGET) 100 int dm_usb_gadget_handle_interrupts(struct udevice *dev) 101 { 102 struct dwc3_generic_priv *priv = dev_get_priv(dev); 103 struct dwc3 *dwc3 = &priv->dwc3; 104 105 dwc3_gadget_uboot_handle_interrupt(dwc3); 106 107 return 0; 108 } 109 110 static int dwc3_generic_peripheral_probe(struct udevice *dev) 111 { 112 struct dwc3_generic_priv *priv = dev_get_priv(dev); 113 114 return dwc3_generic_probe(dev, priv); 115 } 116 117 static int dwc3_generic_peripheral_remove(struct udevice *dev) 118 { 119 struct dwc3_generic_priv *priv = dev_get_priv(dev); 120 121 return dwc3_generic_remove(dev, priv); 122 } 123 124 U_BOOT_DRIVER(dwc3_generic_peripheral) = { 125 .name = "dwc3-generic-peripheral", 126 .id = UCLASS_USB_GADGET_GENERIC, 127 .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata, 128 .probe = dwc3_generic_peripheral_probe, 129 .remove = dwc3_generic_peripheral_remove, 130 .priv_auto_alloc_size = sizeof(struct dwc3_generic_priv), 131 .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat), 132 }; 133 #endif 134 135 struct dwc3_glue_data { 136 struct clk_bulk clks; 137 struct reset_ctl_bulk resets; 138 fdt_addr_t regs; 139 }; 140 141 struct dwc3_glue_ops { 142 void (*select_dr_mode)(struct udevice *dev, int index, 143 enum usb_dr_mode mode); 144 }; 145 146 void dwc3_ti_select_dr_mode(struct udevice *dev, int index, 147 enum usb_dr_mode mode) 148 { 149 #define USBOTGSS_UTMI_OTG_STATUS 0x0084 150 #define USBOTGSS_UTMI_OTG_OFFSET 0x0480 151 152 /* UTMI_OTG_STATUS REGISTER */ 153 #define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31) 154 #define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9) 155 #define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8) 156 #define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4) 157 #define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3) 158 #define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2) 159 #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1) 160 enum dwc3_omap_utmi_mode { 161 DWC3_OMAP_UTMI_MODE_UNKNOWN = 0, 162 DWC3_OMAP_UTMI_MODE_HW, 163 DWC3_OMAP_UTMI_MODE_SW, 164 }; 165 166 u32 use_id_pin; 167 u32 host_mode; 168 u32 reg; 169 u32 utmi_mode; 170 u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS; 171 172 struct dwc3_glue_data *glue = dev_get_platdata(dev); 173 void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE); 174 175 if (device_is_compatible(dev, "ti,am437x-dwc3")) 176 utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET; 177 178 utmi_mode = dev_read_u32_default(dev, "utmi-mode", 179 DWC3_OMAP_UTMI_MODE_UNKNOWN); 180 if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) { 181 debug("%s: OTG is not supported. defaulting to PERIPHERAL\n", 182 dev->name); 183 mode = USB_DR_MODE_PERIPHERAL; 184 } 185 186 switch (mode) { 187 case USB_DR_MODE_PERIPHERAL: 188 use_id_pin = 0; 189 host_mode = 0; 190 break; 191 case USB_DR_MODE_HOST: 192 use_id_pin = 0; 193 host_mode = 1; 194 break; 195 case USB_DR_MODE_OTG: 196 default: 197 use_id_pin = 1; 198 host_mode = 0; 199 break; 200 } 201 202 reg = readl(base + utmi_status_offset); 203 204 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE); 205 if (!use_id_pin) 206 reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; 207 208 writel(reg, base + utmi_status_offset); 209 210 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND | 211 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID | 212 USBOTGSS_UTMI_OTG_STATUS_IDDIG); 213 214 reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID | 215 USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT; 216 217 if (!host_mode) 218 reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG | 219 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID; 220 221 writel(reg, base + utmi_status_offset); 222 223 unmap_physmem(base, MAP_NOCACHE); 224 } 225 226 struct dwc3_glue_ops ti_ops = { 227 .select_dr_mode = dwc3_ti_select_dr_mode, 228 }; 229 230 static int dwc3_glue_bind(struct udevice *parent) 231 { 232 const void *fdt = gd->fdt_blob; 233 int node; 234 int ret; 235 236 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 237 node = fdt_next_subnode(fdt, node)) { 238 const char *name = fdt_get_name(fdt, node, NULL); 239 enum usb_dr_mode dr_mode; 240 struct udevice *dev; 241 const char *driver = NULL; 242 243 debug("%s: subnode name: %s\n", __func__, name); 244 245 dr_mode = usb_get_dr_mode(node); 246 247 switch (dr_mode) { 248 case USB_DR_MODE_PERIPHERAL: 249 case USB_DR_MODE_OTG: 250 #if CONFIG_IS_ENABLED(DM_USB_GADGET) 251 debug("%s: dr_mode: OTG or Peripheral\n", __func__); 252 driver = "dwc3-generic-peripheral"; 253 #endif 254 break; 255 case USB_DR_MODE_HOST: 256 debug("%s: dr_mode: HOST\n", __func__); 257 driver = "xhci-dwc3"; 258 break; 259 default: 260 debug("%s: unsupported dr_mode\n", __func__); 261 return -ENODEV; 262 }; 263 264 if (!driver) 265 continue; 266 267 ret = device_bind_driver_to_node(parent, driver, name, 268 offset_to_ofnode(node), &dev); 269 if (ret) { 270 debug("%s: not able to bind usb device mode\n", 271 __func__); 272 return ret; 273 } 274 } 275 276 return 0; 277 } 278 279 static int dwc3_glue_reset_init(struct udevice *dev, 280 struct dwc3_glue_data *glue) 281 { 282 int ret; 283 284 ret = reset_get_bulk(dev, &glue->resets); 285 if (ret == -ENOTSUPP) 286 return 0; 287 else if (ret) 288 return ret; 289 290 ret = reset_deassert_bulk(&glue->resets); 291 if (ret) { 292 reset_release_bulk(&glue->resets); 293 return ret; 294 } 295 296 return 0; 297 } 298 299 static int dwc3_glue_clk_init(struct udevice *dev, 300 struct dwc3_glue_data *glue) 301 { 302 int ret; 303 304 ret = clk_get_bulk(dev, &glue->clks); 305 if (ret == -ENOSYS) 306 return 0; 307 if (ret) 308 return ret; 309 310 #if CONFIG_IS_ENABLED(CLK) 311 ret = clk_enable_bulk(&glue->clks); 312 if (ret) { 313 clk_release_bulk(&glue->clks); 314 return ret; 315 } 316 #endif 317 318 return 0; 319 } 320 321 static int dwc3_glue_probe(struct udevice *dev) 322 { 323 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); 324 struct dwc3_glue_data *glue = dev_get_platdata(dev); 325 struct udevice *child = NULL; 326 int index = 0; 327 int ret; 328 329 glue->regs = dev_read_addr(dev); 330 331 ret = dwc3_glue_clk_init(dev, glue); 332 if (ret) 333 return ret; 334 335 ret = dwc3_glue_reset_init(dev, glue); 336 if (ret) 337 return ret; 338 339 ret = device_find_first_child(dev, &child); 340 if (ret) 341 return ret; 342 343 while (child) { 344 enum usb_dr_mode dr_mode; 345 346 dr_mode = usb_get_dr_mode(dev_of_offset(child)); 347 device_find_next_child(&child); 348 if (ops && ops->select_dr_mode) 349 ops->select_dr_mode(dev, index, dr_mode); 350 index++; 351 } 352 353 return 0; 354 } 355 356 static int dwc3_glue_remove(struct udevice *dev) 357 { 358 struct dwc3_glue_data *glue = dev_get_platdata(dev); 359 360 reset_release_bulk(&glue->resets); 361 362 clk_release_bulk(&glue->clks); 363 364 return 0; 365 } 366 367 static const struct udevice_id dwc3_glue_ids[] = { 368 { .compatible = "xlnx,zynqmp-dwc3" }, 369 { .compatible = "ti,keystone-dwc3"}, 370 { .compatible = "ti,dwc3", .data = (ulong)&ti_ops }, 371 { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops }, 372 { } 373 }; 374 375 U_BOOT_DRIVER(dwc3_generic_wrapper) = { 376 .name = "dwc3-generic-wrapper", 377 .id = UCLASS_NOP, 378 .of_match = dwc3_glue_ids, 379 .bind = dwc3_glue_bind, 380 .probe = dwc3_glue_probe, 381 .remove = dwc3_glue_remove, 382 .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data), 383 384 }; 385