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 <dm.h> 12 #include <dm/device-internal.h> 13 #include <dm/lists.h> 14 #include <linux/usb/otg.h> 15 #include <linux/compat.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 "linux-compat.h" 23 24 #if CONFIG_IS_ENABLED(DM_USB_GADGET) 25 int dm_usb_gadget_handle_interrupts(struct udevice *dev) 26 { 27 struct dwc3 *priv = dev_get_priv(dev); 28 29 dwc3_gadget_uboot_handle_interrupt(priv); 30 31 return 0; 32 } 33 34 static int dwc3_generic_peripheral_probe(struct udevice *dev) 35 { 36 struct dwc3 *priv = dev_get_priv(dev); 37 38 return dwc3_init(priv); 39 } 40 41 static int dwc3_generic_peripheral_remove(struct udevice *dev) 42 { 43 struct dwc3 *priv = dev_get_priv(dev); 44 45 dwc3_remove(priv); 46 47 return 0; 48 } 49 50 static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) 51 { 52 struct dwc3 *priv = dev_get_priv(dev); 53 int node = dev_of_offset(dev); 54 55 priv->regs = (void *)devfdt_get_addr(dev); 56 priv->regs += DWC3_GLOBALS_REGS_START; 57 58 priv->maximum_speed = usb_get_maximum_speed(node); 59 if (priv->maximum_speed == USB_SPEED_UNKNOWN) { 60 pr_err("Invalid usb maximum speed\n"); 61 return -ENODEV; 62 } 63 64 priv->dr_mode = usb_get_dr_mode(node); 65 if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { 66 pr_err("Invalid usb mode setup\n"); 67 return -ENODEV; 68 } 69 70 return 0; 71 } 72 73 static int dwc3_generic_peripheral_bind(struct udevice *dev) 74 { 75 return device_probe(dev); 76 } 77 78 U_BOOT_DRIVER(dwc3_generic_peripheral) = { 79 .name = "dwc3-generic-peripheral", 80 .id = UCLASS_USB_DEV_GENERIC, 81 .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, 82 .probe = dwc3_generic_peripheral_probe, 83 .remove = dwc3_generic_peripheral_remove, 84 .bind = dwc3_generic_peripheral_bind, 85 .platdata_auto_alloc_size = sizeof(struct usb_platdata), 86 .priv_auto_alloc_size = sizeof(struct dwc3), 87 .flags = DM_FLAG_ALLOC_PRIV_DMA, 88 }; 89 #endif 90 91 static int dwc3_generic_bind(struct udevice *parent) 92 { 93 const void *fdt = gd->fdt_blob; 94 int node; 95 int ret; 96 97 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 98 node = fdt_next_subnode(fdt, node)) { 99 const char *name = fdt_get_name(fdt, node, NULL); 100 enum usb_dr_mode dr_mode; 101 struct udevice *dev; 102 const char *driver; 103 104 debug("%s: subnode name: %s\n", __func__, name); 105 if (strncmp(name, "dwc3@", 4)) 106 continue; 107 108 dr_mode = usb_get_dr_mode(node); 109 110 switch (dr_mode) { 111 case USB_DR_MODE_PERIPHERAL: 112 case USB_DR_MODE_OTG: 113 debug("%s: dr_mode: OTG or Peripheral\n", __func__); 114 driver = "dwc3-generic-peripheral"; 115 break; 116 case USB_DR_MODE_HOST: 117 debug("%s: dr_mode: HOST\n", __func__); 118 driver = "dwc3-generic-host"; 119 break; 120 default: 121 debug("%s: unsupported dr_mode\n", __func__); 122 return -ENODEV; 123 }; 124 125 ret = device_bind_driver_to_node(parent, driver, name, 126 offset_to_ofnode(node), &dev); 127 if (ret) { 128 debug("%s: not able to bind usb device mode\n", 129 __func__); 130 return ret; 131 } 132 } 133 134 return 0; 135 } 136 137 static const struct udevice_id dwc3_generic_ids[] = { 138 { .compatible = "xlnx,zynqmp-dwc3" }, 139 { } 140 }; 141 142 U_BOOT_DRIVER(dwc3_generic_wrapper) = { 143 .name = "dwc3-generic-wrapper", 144 .id = UCLASS_MISC, 145 .of_match = dwc3_generic_ids, 146 .bind = dwc3_generic_bind, 147 }; 148