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