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