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