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