149d67454SMichal Simek // SPDX-License-Identifier: GPL-2.0 249d67454SMichal Simek /* 349d67454SMichal Simek * Generic DWC3 Glue layer 449d67454SMichal Simek * 549d67454SMichal Simek * Copyright (C) 2016 - 2018 Xilinx, Inc. 649d67454SMichal Simek * 749d67454SMichal Simek * Based on dwc3-omap.c. 849d67454SMichal Simek */ 949d67454SMichal Simek 1049d67454SMichal Simek #include <common.h> 1149d67454SMichal Simek #include <dm.h> 1249d67454SMichal Simek #include <dm/device-internal.h> 1349d67454SMichal Simek #include <dm/lists.h> 1449d67454SMichal Simek #include <linux/usb/otg.h> 1549d67454SMichal Simek #include <linux/compat.h> 1649d67454SMichal Simek #include <linux/usb/ch9.h> 1749d67454SMichal Simek #include <linux/usb/gadget.h> 1849d67454SMichal Simek #include <malloc.h> 1949d67454SMichal Simek #include <usb.h> 2049d67454SMichal Simek #include "core.h" 2149d67454SMichal Simek #include "gadget.h" 2249d67454SMichal Simek #include "linux-compat.h" 2349d67454SMichal Simek 24687ab545SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB_GADGET) 25*ff8d7558SJean-Jacques Hiblot int dm_usb_gadget_handle_interrupts(struct udevice *dev) 2649d67454SMichal Simek { 27*ff8d7558SJean-Jacques Hiblot struct dwc3 *priv = dev_get_priv(dev); 2849d67454SMichal Simek 2949d67454SMichal Simek dwc3_gadget_uboot_handle_interrupt(priv); 3049d67454SMichal Simek 3149d67454SMichal Simek return 0; 3249d67454SMichal Simek } 3349d67454SMichal Simek 3449d67454SMichal Simek static int dwc3_generic_peripheral_probe(struct udevice *dev) 3549d67454SMichal Simek { 3649d67454SMichal Simek struct dwc3 *priv = dev_get_priv(dev); 3749d67454SMichal Simek 3849d67454SMichal Simek return dwc3_init(priv); 3949d67454SMichal Simek } 4049d67454SMichal Simek 4149d67454SMichal Simek static int dwc3_generic_peripheral_remove(struct udevice *dev) 4249d67454SMichal Simek { 4349d67454SMichal Simek struct dwc3 *priv = dev_get_priv(dev); 4449d67454SMichal Simek 4549d67454SMichal Simek dwc3_remove(priv); 4649d67454SMichal Simek 4749d67454SMichal Simek return 0; 4849d67454SMichal Simek } 4949d67454SMichal Simek 5049d67454SMichal Simek static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) 5149d67454SMichal Simek { 5249d67454SMichal Simek struct dwc3 *priv = dev_get_priv(dev); 5349d67454SMichal Simek int node = dev_of_offset(dev); 5449d67454SMichal Simek 5549d67454SMichal Simek priv->regs = (void *)devfdt_get_addr(dev); 5649d67454SMichal Simek priv->regs += DWC3_GLOBALS_REGS_START; 5749d67454SMichal Simek 5849d67454SMichal Simek priv->maximum_speed = usb_get_maximum_speed(node); 5949d67454SMichal Simek if (priv->maximum_speed == USB_SPEED_UNKNOWN) { 6049d67454SMichal Simek pr_err("Invalid usb maximum speed\n"); 6149d67454SMichal Simek return -ENODEV; 6249d67454SMichal Simek } 6349d67454SMichal Simek 6449d67454SMichal Simek priv->dr_mode = usb_get_dr_mode(node); 6549d67454SMichal Simek if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { 6649d67454SMichal Simek pr_err("Invalid usb mode setup\n"); 6749d67454SMichal Simek return -ENODEV; 6849d67454SMichal Simek } 6949d67454SMichal Simek 7049d67454SMichal Simek return 0; 7149d67454SMichal Simek } 7249d67454SMichal Simek 7349d67454SMichal Simek static int dwc3_generic_peripheral_bind(struct udevice *dev) 7449d67454SMichal Simek { 7549d67454SMichal Simek return device_probe(dev); 7649d67454SMichal Simek } 7749d67454SMichal Simek 7849d67454SMichal Simek U_BOOT_DRIVER(dwc3_generic_peripheral) = { 7949d67454SMichal Simek .name = "dwc3-generic-peripheral", 8049d67454SMichal Simek .id = UCLASS_USB_DEV_GENERIC, 8149d67454SMichal Simek .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, 8249d67454SMichal Simek .probe = dwc3_generic_peripheral_probe, 8349d67454SMichal Simek .remove = dwc3_generic_peripheral_remove, 8449d67454SMichal Simek .bind = dwc3_generic_peripheral_bind, 8549d67454SMichal Simek .platdata_auto_alloc_size = sizeof(struct usb_platdata), 8649d67454SMichal Simek .priv_auto_alloc_size = sizeof(struct dwc3), 8749d67454SMichal Simek .flags = DM_FLAG_ALLOC_PRIV_DMA, 8849d67454SMichal Simek }; 89687ab545SJean-Jacques Hiblot #endif 9049d67454SMichal Simek 9149d67454SMichal Simek static int dwc3_generic_bind(struct udevice *parent) 9249d67454SMichal Simek { 9349d67454SMichal Simek const void *fdt = gd->fdt_blob; 9449d67454SMichal Simek int node; 9549d67454SMichal Simek int ret; 9649d67454SMichal Simek 9749d67454SMichal Simek for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 9849d67454SMichal Simek node = fdt_next_subnode(fdt, node)) { 9949d67454SMichal Simek const char *name = fdt_get_name(fdt, node, NULL); 10049d67454SMichal Simek enum usb_dr_mode dr_mode; 10149d67454SMichal Simek struct udevice *dev; 10249d67454SMichal Simek const char *driver; 10349d67454SMichal Simek 10449d67454SMichal Simek debug("%s: subnode name: %s\n", __func__, name); 10549d67454SMichal Simek if (strncmp(name, "dwc3@", 4)) 10649d67454SMichal Simek continue; 10749d67454SMichal Simek 10849d67454SMichal Simek dr_mode = usb_get_dr_mode(node); 10949d67454SMichal Simek 11049d67454SMichal Simek switch (dr_mode) { 11149d67454SMichal Simek case USB_DR_MODE_PERIPHERAL: 11249d67454SMichal Simek case USB_DR_MODE_OTG: 11349d67454SMichal Simek debug("%s: dr_mode: OTG or Peripheral\n", __func__); 11449d67454SMichal Simek driver = "dwc3-generic-peripheral"; 11549d67454SMichal Simek break; 11649d67454SMichal Simek case USB_DR_MODE_HOST: 11749d67454SMichal Simek debug("%s: dr_mode: HOST\n", __func__); 11849d67454SMichal Simek driver = "dwc3-generic-host"; 11949d67454SMichal Simek break; 12049d67454SMichal Simek default: 12149d67454SMichal Simek debug("%s: unsupported dr_mode\n", __func__); 12249d67454SMichal Simek return -ENODEV; 12349d67454SMichal Simek }; 12449d67454SMichal Simek 12549d67454SMichal Simek ret = device_bind_driver_to_node(parent, driver, name, 12649d67454SMichal Simek offset_to_ofnode(node), &dev); 12749d67454SMichal Simek if (ret) { 12849d67454SMichal Simek debug("%s: not able to bind usb device mode\n", 12949d67454SMichal Simek __func__); 13049d67454SMichal Simek return ret; 13149d67454SMichal Simek } 13249d67454SMichal Simek } 13349d67454SMichal Simek 13449d67454SMichal Simek return 0; 13549d67454SMichal Simek } 13649d67454SMichal Simek 13749d67454SMichal Simek static const struct udevice_id dwc3_generic_ids[] = { 13849d67454SMichal Simek { .compatible = "xlnx,zynqmp-dwc3" }, 13949d67454SMichal Simek { } 14049d67454SMichal Simek }; 14149d67454SMichal Simek 14249d67454SMichal Simek U_BOOT_DRIVER(dwc3_generic_wrapper) = { 14349d67454SMichal Simek .name = "dwc3-generic-wrapper", 14449d67454SMichal Simek .id = UCLASS_MISC, 14549d67454SMichal Simek .of_match = dwc3_generic_ids, 14649d67454SMichal Simek .bind = dwc3_generic_bind, 14749d67454SMichal Simek }; 148