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 static int dwc3_glue_bind(struct udevice *parent) 123 { 124 const void *fdt = gd->fdt_blob; 125 int node; 126 int ret; 127 128 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 129 node = fdt_next_subnode(fdt, node)) { 130 const char *name = fdt_get_name(fdt, node, NULL); 131 enum usb_dr_mode dr_mode; 132 struct udevice *dev; 133 const char *driver = NULL; 134 135 debug("%s: subnode name: %s\n", __func__, name); 136 137 dr_mode = usb_get_dr_mode(node); 138 139 switch (dr_mode) { 140 case USB_DR_MODE_PERIPHERAL: 141 case USB_DR_MODE_OTG: 142 #if CONFIG_IS_ENABLED(DM_USB_GADGET) 143 debug("%s: dr_mode: OTG or Peripheral\n", __func__); 144 driver = "dwc3-generic-peripheral"; 145 #endif 146 break; 147 case USB_DR_MODE_HOST: 148 debug("%s: dr_mode: HOST\n", __func__); 149 driver = "xhci-dwc3"; 150 break; 151 default: 152 debug("%s: unsupported dr_mode\n", __func__); 153 return -ENODEV; 154 }; 155 156 if (!driver) 157 continue; 158 159 ret = device_bind_driver_to_node(parent, driver, name, 160 offset_to_ofnode(node), &dev); 161 if (ret) { 162 debug("%s: not able to bind usb device mode\n", 163 __func__); 164 return ret; 165 } 166 } 167 168 return 0; 169 } 170 171 static int dwc3_glue_reset_init(struct udevice *dev, 172 struct dwc3_glue_data *glue) 173 { 174 int ret; 175 176 ret = reset_get_bulk(dev, &glue->resets); 177 if (ret == -ENOTSUPP) 178 return 0; 179 else if (ret) 180 return ret; 181 182 ret = reset_deassert_bulk(&glue->resets); 183 if (ret) { 184 reset_release_bulk(&glue->resets); 185 return ret; 186 } 187 188 return 0; 189 } 190 191 static int dwc3_glue_clk_init(struct udevice *dev, 192 struct dwc3_glue_data *glue) 193 { 194 int ret; 195 196 ret = clk_get_bulk(dev, &glue->clks); 197 if (ret == -ENOSYS) 198 return 0; 199 if (ret) 200 return ret; 201 202 #if CONFIG_IS_ENABLED(CLK) 203 ret = clk_enable_bulk(&glue->clks); 204 if (ret) { 205 clk_release_bulk(&glue->clks); 206 return ret; 207 } 208 #endif 209 210 return 0; 211 } 212 213 static int dwc3_glue_probe(struct udevice *dev) 214 { 215 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); 216 struct dwc3_glue_data *glue = dev_get_platdata(dev); 217 struct udevice *child = NULL; 218 int index = 0; 219 int ret; 220 221 glue->regs = dev_read_addr(dev); 222 223 ret = dwc3_glue_clk_init(dev, glue); 224 if (ret) 225 return ret; 226 227 ret = dwc3_glue_reset_init(dev, glue); 228 if (ret) 229 return ret; 230 231 ret = device_find_first_child(dev, &child); 232 if (ret) 233 return ret; 234 235 while (child) { 236 enum usb_dr_mode dr_mode; 237 238 dr_mode = usb_get_dr_mode(dev_of_offset(child)); 239 device_find_next_child(&child); 240 if (ops && ops->select_dr_mode) 241 ops->select_dr_mode(dev, index, dr_mode); 242 index++; 243 } 244 245 return 0; 246 } 247 248 static int dwc3_glue_remove(struct udevice *dev) 249 { 250 struct dwc3_glue_data *glue = dev_get_platdata(dev); 251 252 reset_release_bulk(&glue->resets); 253 254 clk_release_bulk(&glue->clks); 255 256 return dm_scan_fdt_dev(dev); 257 } 258 259 static const struct udevice_id dwc3_glue_ids[] = { 260 { .compatible = "xlnx,zynqmp-dwc3" }, 261 { } 262 }; 263 264 U_BOOT_DRIVER(dwc3_generic_wrapper) = { 265 .name = "dwc3-generic-wrapper", 266 .id = UCLASS_MISC, 267 .of_match = dwc3_glue_ids, 268 .bind = dwc3_glue_bind, 269 .probe = dwc3_glue_probe, 270 .remove = dwc3_glue_remove, 271 .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data), 272 273 }; 274