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) 25256dc48fSJean-Jacques Hiblot int dm_usb_gadget_handle_interrupts(struct udevice *dev) 26e2f919a1SMichal Simek { 27256dc48fSJean-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 U_BOOT_DRIVER(dwc3_generic_peripheral) = { 74e2f919a1SMichal Simek .name = "dwc3-generic-peripheral", 75*20828bbaSJean-Jacques Hiblot .id = UCLASS_USB_GADGET_GENERIC, 76e2f919a1SMichal Simek .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, 77e2f919a1SMichal Simek .probe = dwc3_generic_peripheral_probe, 78e2f919a1SMichal Simek .remove = dwc3_generic_peripheral_remove, 79e2f919a1SMichal Simek .platdata_auto_alloc_size = sizeof(struct usb_platdata), 80e2f919a1SMichal Simek .priv_auto_alloc_size = sizeof(struct dwc3), 81e2f919a1SMichal Simek }; 82717f5765SJean-Jacques Hiblot #endif 83e2f919a1SMichal Simek 84e2f919a1SMichal Simek static int dwc3_generic_bind(struct udevice *parent) 85e2f919a1SMichal Simek { 86e2f919a1SMichal Simek const void *fdt = gd->fdt_blob; 87e2f919a1SMichal Simek int node; 88e2f919a1SMichal Simek int ret; 89e2f919a1SMichal Simek 90e2f919a1SMichal Simek for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 91e2f919a1SMichal Simek node = fdt_next_subnode(fdt, node)) { 92e2f919a1SMichal Simek const char *name = fdt_get_name(fdt, node, NULL); 93e2f919a1SMichal Simek enum usb_dr_mode dr_mode; 94e2f919a1SMichal Simek struct udevice *dev; 95e2f919a1SMichal Simek const char *driver; 96e2f919a1SMichal Simek 97e2f919a1SMichal Simek debug("%s: subnode name: %s\n", __func__, name); 98e2f919a1SMichal Simek if (strncmp(name, "dwc3@", 4)) 99e2f919a1SMichal Simek continue; 100e2f919a1SMichal Simek 101e2f919a1SMichal Simek dr_mode = usb_get_dr_mode(node); 102e2f919a1SMichal Simek 103e2f919a1SMichal Simek switch (dr_mode) { 104e2f919a1SMichal Simek case USB_DR_MODE_PERIPHERAL: 105e2f919a1SMichal Simek case USB_DR_MODE_OTG: 106e2f919a1SMichal Simek debug("%s: dr_mode: OTG or Peripheral\n", __func__); 107e2f919a1SMichal Simek driver = "dwc3-generic-peripheral"; 108e2f919a1SMichal Simek break; 109e2f919a1SMichal Simek case USB_DR_MODE_HOST: 110e2f919a1SMichal Simek debug("%s: dr_mode: HOST\n", __func__); 111e2f919a1SMichal Simek driver = "dwc3-generic-host"; 112e2f919a1SMichal Simek break; 113e2f919a1SMichal Simek default: 114e2f919a1SMichal Simek debug("%s: unsupported dr_mode\n", __func__); 115e2f919a1SMichal Simek return -ENODEV; 116e2f919a1SMichal Simek }; 117e2f919a1SMichal Simek 118e2f919a1SMichal Simek ret = device_bind_driver_to_node(parent, driver, name, 119e2f919a1SMichal Simek offset_to_ofnode(node), &dev); 120e2f919a1SMichal Simek if (ret) { 121e2f919a1SMichal Simek debug("%s: not able to bind usb device mode\n", 122e2f919a1SMichal Simek __func__); 123e2f919a1SMichal Simek return ret; 124e2f919a1SMichal Simek } 125e2f919a1SMichal Simek } 126e2f919a1SMichal Simek 127e2f919a1SMichal Simek return 0; 128e2f919a1SMichal Simek } 129e2f919a1SMichal Simek 130e2f919a1SMichal Simek static const struct udevice_id dwc3_generic_ids[] = { 131e2f919a1SMichal Simek { .compatible = "xlnx,zynqmp-dwc3" }, 132e2f919a1SMichal Simek { } 133e2f919a1SMichal Simek }; 134e2f919a1SMichal Simek 135e2f919a1SMichal Simek U_BOOT_DRIVER(dwc3_generic_wrapper) = { 136e2f919a1SMichal Simek .name = "dwc3-generic-wrapper", 137e2f919a1SMichal Simek .id = UCLASS_MISC, 138e2f919a1SMichal Simek .of_match = dwc3_generic_ids, 139e2f919a1SMichal Simek .bind = dwc3_generic_bind, 140e2f919a1SMichal Simek }; 141