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 <dwc3-uboot.h> 15 #include <linux/usb/ch9.h> 16 #include <linux/usb/gadget.h> 17 #include <malloc.h> 18 #include <usb.h> 19 #include "core.h" 20 #include "gadget.h" 21 #include <reset.h> 22 #include <clk.h> 23 24 #if CONFIG_IS_ENABLED(DM_USB_GADGET) 25 struct dwc3_generic_peripheral { 26 struct dwc3 dwc3; 27 struct phy *phys; 28 int num_phys; 29 fdt_addr_t base; 30 }; 31 32 int dm_usb_gadget_handle_interrupts(struct udevice *dev) 33 { 34 struct dwc3_generic_peripheral *priv = dev_get_priv(dev); 35 struct dwc3 *dwc3 = &priv->dwc3; 36 37 dwc3_gadget_uboot_handle_interrupt(dwc3); 38 39 return 0; 40 } 41 42 static int dwc3_generic_peripheral_probe(struct udevice *dev) 43 { 44 int rc; 45 struct dwc3_generic_peripheral *priv = dev_get_priv(dev); 46 struct dwc3 *dwc3 = &priv->dwc3; 47 48 rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys); 49 if (rc) 50 return rc; 51 52 dwc3->regs = map_physmem(priv->base, DWC3_OTG_REGS_END, MAP_NOCACHE); 53 dwc3->regs += DWC3_GLOBALS_REGS_START; 54 dwc3->dev = dev; 55 56 rc = dwc3_init(dwc3); 57 if (rc) { 58 unmap_physmem(dwc3->regs, MAP_NOCACHE); 59 return rc; 60 } 61 62 return 0; 63 } 64 65 static int dwc3_generic_peripheral_remove(struct udevice *dev) 66 { 67 struct dwc3_generic_peripheral *priv = dev_get_priv(dev); 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_peripheral_ofdata_to_platdata(struct udevice *dev) 78 { 79 struct dwc3_generic_peripheral *priv = dev_get_priv(dev); 80 struct dwc3 *dwc3 = &priv->dwc3; 81 int node = dev_of_offset(dev); 82 83 priv->base = devfdt_get_addr(dev); 84 85 dwc3->maximum_speed = usb_get_maximum_speed(node); 86 if (dwc3->maximum_speed == USB_SPEED_UNKNOWN) { 87 pr_err("Invalid usb maximum speed\n"); 88 return -ENODEV; 89 } 90 91 dwc3->dr_mode = usb_get_dr_mode(node); 92 if (dwc3->dr_mode == USB_DR_MODE_UNKNOWN) { 93 pr_err("Invalid usb mode setup\n"); 94 return -ENODEV; 95 } 96 97 return 0; 98 } 99 100 U_BOOT_DRIVER(dwc3_generic_peripheral) = { 101 .name = "dwc3-generic-peripheral", 102 .id = UCLASS_USB_GADGET_GENERIC, 103 .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, 104 .probe = dwc3_generic_peripheral_probe, 105 .remove = dwc3_generic_peripheral_remove, 106 .priv_auto_alloc_size = sizeof(struct dwc3_generic_peripheral), 107 }; 108 #endif 109 110 struct dwc3_glue_data { 111 struct clk_bulk clks; 112 struct reset_ctl_bulk resets; 113 }; 114 115 static int dwc3_glue_bind(struct udevice *parent) 116 { 117 const void *fdt = gd->fdt_blob; 118 int node; 119 int ret; 120 121 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 122 node = fdt_next_subnode(fdt, node)) { 123 const char *name = fdt_get_name(fdt, node, NULL); 124 enum usb_dr_mode dr_mode; 125 struct udevice *dev; 126 const char *driver = NULL; 127 128 debug("%s: subnode name: %s\n", __func__, name); 129 130 dr_mode = usb_get_dr_mode(node); 131 132 switch (dr_mode) { 133 case USB_DR_MODE_PERIPHERAL: 134 case USB_DR_MODE_OTG: 135 #if CONFIG_IS_ENABLED(DM_USB_GADGET) 136 debug("%s: dr_mode: OTG or Peripheral\n", __func__); 137 driver = "dwc3-generic-peripheral"; 138 #endif 139 break; 140 case USB_DR_MODE_HOST: 141 debug("%s: dr_mode: HOST\n", __func__); 142 driver = "xhci-dwc3"; 143 break; 144 default: 145 debug("%s: unsupported dr_mode\n", __func__); 146 return -ENODEV; 147 }; 148 149 if (!driver) 150 continue; 151 152 ret = device_bind_driver_to_node(parent, driver, name, 153 offset_to_ofnode(node), &dev); 154 if (ret) { 155 debug("%s: not able to bind usb device mode\n", 156 __func__); 157 return ret; 158 } 159 } 160 161 return 0; 162 } 163 164 static int dwc3_glue_reset_init(struct udevice *dev, 165 struct dwc3_glue_data *glue) 166 { 167 int ret; 168 169 ret = reset_get_bulk(dev, &glue->resets); 170 if (ret == -ENOTSUPP) 171 return 0; 172 else if (ret) 173 return ret; 174 175 ret = reset_deassert_bulk(&glue->resets); 176 if (ret) { 177 reset_release_bulk(&glue->resets); 178 return ret; 179 } 180 181 return 0; 182 } 183 184 static int dwc3_glue_clk_init(struct udevice *dev, 185 struct dwc3_glue_data *glue) 186 { 187 int ret; 188 189 ret = clk_get_bulk(dev, &glue->clks); 190 if (ret == -ENOSYS) 191 return 0; 192 if (ret) 193 return ret; 194 195 #if CONFIG_IS_ENABLED(CLK) 196 ret = clk_enable_bulk(&glue->clks); 197 if (ret) { 198 clk_release_bulk(&glue->clks); 199 return ret; 200 } 201 #endif 202 203 return 0; 204 } 205 206 static int dwc3_glue_probe(struct udevice *dev) 207 { 208 struct dwc3_glue_data *glue = dev_get_platdata(dev); 209 int ret; 210 211 ret = dwc3_glue_clk_init(dev, glue); 212 if (ret) 213 return ret; 214 215 ret = dwc3_glue_reset_init(dev, glue); 216 if (ret) 217 return ret; 218 219 return 0; 220 } 221 222 static int dwc3_glue_remove(struct udevice *dev) 223 { 224 struct dwc3_glue_data *glue = dev_get_platdata(dev); 225 226 reset_release_bulk(&glue->resets); 227 228 clk_release_bulk(&glue->clks); 229 230 return dm_scan_fdt_dev(dev); 231 } 232 233 static const struct udevice_id dwc3_glue_ids[] = { 234 { .compatible = "xlnx,zynqmp-dwc3" }, 235 { } 236 }; 237 238 U_BOOT_DRIVER(dwc3_generic_wrapper) = { 239 .name = "dwc3-generic-wrapper", 240 .id = UCLASS_MISC, 241 .of_match = dwc3_glue_ids, 242 .bind = dwc3_glue_bind, 243 .probe = dwc3_glue_probe, 244 .remove = dwc3_glue_remove, 245 .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data), 246 247 }; 248