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