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 24*687ab545SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB_GADGET) 2549d67454SMichal Simek int usb_gadget_handle_interrupts(int index) 2649d67454SMichal Simek { 2749d67454SMichal Simek struct dwc3 *priv; 2849d67454SMichal Simek struct udevice *dev; 2949d67454SMichal Simek int ret; 3049d67454SMichal Simek 3149d67454SMichal Simek ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); 3249d67454SMichal Simek if (!dev || ret) { 3349d67454SMichal Simek pr_err("No USB device found\n"); 3449d67454SMichal Simek return -ENODEV; 3549d67454SMichal Simek } 3649d67454SMichal Simek 3749d67454SMichal Simek priv = dev_get_priv(dev); 3849d67454SMichal Simek 3949d67454SMichal Simek dwc3_gadget_uboot_handle_interrupt(priv); 4049d67454SMichal Simek 4149d67454SMichal Simek return 0; 4249d67454SMichal Simek } 4349d67454SMichal Simek 4449d67454SMichal Simek static int dwc3_generic_peripheral_probe(struct udevice *dev) 4549d67454SMichal Simek { 4649d67454SMichal Simek struct dwc3 *priv = dev_get_priv(dev); 4749d67454SMichal Simek 4849d67454SMichal Simek return dwc3_init(priv); 4949d67454SMichal Simek } 5049d67454SMichal Simek 5149d67454SMichal Simek static int dwc3_generic_peripheral_remove(struct udevice *dev) 5249d67454SMichal Simek { 5349d67454SMichal Simek struct dwc3 *priv = dev_get_priv(dev); 5449d67454SMichal Simek 5549d67454SMichal Simek dwc3_remove(priv); 5649d67454SMichal Simek 5749d67454SMichal Simek return 0; 5849d67454SMichal Simek } 5949d67454SMichal Simek 6049d67454SMichal Simek static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) 6149d67454SMichal Simek { 6249d67454SMichal Simek struct dwc3 *priv = dev_get_priv(dev); 6349d67454SMichal Simek int node = dev_of_offset(dev); 6449d67454SMichal Simek 6549d67454SMichal Simek priv->regs = (void *)devfdt_get_addr(dev); 6649d67454SMichal Simek priv->regs += DWC3_GLOBALS_REGS_START; 6749d67454SMichal Simek 6849d67454SMichal Simek priv->maximum_speed = usb_get_maximum_speed(node); 6949d67454SMichal Simek if (priv->maximum_speed == USB_SPEED_UNKNOWN) { 7049d67454SMichal Simek pr_err("Invalid usb maximum speed\n"); 7149d67454SMichal Simek return -ENODEV; 7249d67454SMichal Simek } 7349d67454SMichal Simek 7449d67454SMichal Simek priv->dr_mode = usb_get_dr_mode(node); 7549d67454SMichal Simek if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { 7649d67454SMichal Simek pr_err("Invalid usb mode setup\n"); 7749d67454SMichal Simek return -ENODEV; 7849d67454SMichal Simek } 7949d67454SMichal Simek 8049d67454SMichal Simek return 0; 8149d67454SMichal Simek } 8249d67454SMichal Simek 8349d67454SMichal Simek static int dwc3_generic_peripheral_bind(struct udevice *dev) 8449d67454SMichal Simek { 8549d67454SMichal Simek return device_probe(dev); 8649d67454SMichal Simek } 8749d67454SMichal Simek 8849d67454SMichal Simek U_BOOT_DRIVER(dwc3_generic_peripheral) = { 8949d67454SMichal Simek .name = "dwc3-generic-peripheral", 9049d67454SMichal Simek .id = UCLASS_USB_DEV_GENERIC, 9149d67454SMichal Simek .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, 9249d67454SMichal Simek .probe = dwc3_generic_peripheral_probe, 9349d67454SMichal Simek .remove = dwc3_generic_peripheral_remove, 9449d67454SMichal Simek .bind = dwc3_generic_peripheral_bind, 9549d67454SMichal Simek .platdata_auto_alloc_size = sizeof(struct usb_platdata), 9649d67454SMichal Simek .priv_auto_alloc_size = sizeof(struct dwc3), 9749d67454SMichal Simek .flags = DM_FLAG_ALLOC_PRIV_DMA, 9849d67454SMichal Simek }; 99*687ab545SJean-Jacques Hiblot #endif 10049d67454SMichal Simek 10149d67454SMichal Simek static int dwc3_generic_bind(struct udevice *parent) 10249d67454SMichal Simek { 10349d67454SMichal Simek const void *fdt = gd->fdt_blob; 10449d67454SMichal Simek int node; 10549d67454SMichal Simek int ret; 10649d67454SMichal Simek 10749d67454SMichal Simek for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 10849d67454SMichal Simek node = fdt_next_subnode(fdt, node)) { 10949d67454SMichal Simek const char *name = fdt_get_name(fdt, node, NULL); 11049d67454SMichal Simek enum usb_dr_mode dr_mode; 11149d67454SMichal Simek struct udevice *dev; 11249d67454SMichal Simek const char *driver; 11349d67454SMichal Simek 11449d67454SMichal Simek debug("%s: subnode name: %s\n", __func__, name); 11549d67454SMichal Simek if (strncmp(name, "dwc3@", 4)) 11649d67454SMichal Simek continue; 11749d67454SMichal Simek 11849d67454SMichal Simek dr_mode = usb_get_dr_mode(node); 11949d67454SMichal Simek 12049d67454SMichal Simek switch (dr_mode) { 12149d67454SMichal Simek case USB_DR_MODE_PERIPHERAL: 12249d67454SMichal Simek case USB_DR_MODE_OTG: 12349d67454SMichal Simek debug("%s: dr_mode: OTG or Peripheral\n", __func__); 12449d67454SMichal Simek driver = "dwc3-generic-peripheral"; 12549d67454SMichal Simek break; 12649d67454SMichal Simek case USB_DR_MODE_HOST: 12749d67454SMichal Simek debug("%s: dr_mode: HOST\n", __func__); 12849d67454SMichal Simek driver = "dwc3-generic-host"; 12949d67454SMichal Simek break; 13049d67454SMichal Simek default: 13149d67454SMichal Simek debug("%s: unsupported dr_mode\n", __func__); 13249d67454SMichal Simek return -ENODEV; 13349d67454SMichal Simek }; 13449d67454SMichal Simek 13549d67454SMichal Simek ret = device_bind_driver_to_node(parent, driver, name, 13649d67454SMichal Simek offset_to_ofnode(node), &dev); 13749d67454SMichal Simek if (ret) { 13849d67454SMichal Simek debug("%s: not able to bind usb device mode\n", 13949d67454SMichal Simek __func__); 14049d67454SMichal Simek return ret; 14149d67454SMichal Simek } 14249d67454SMichal Simek } 14349d67454SMichal Simek 14449d67454SMichal Simek return 0; 14549d67454SMichal Simek } 14649d67454SMichal Simek 14749d67454SMichal Simek static const struct udevice_id dwc3_generic_ids[] = { 14849d67454SMichal Simek { .compatible = "xlnx,zynqmp-dwc3" }, 14949d67454SMichal Simek { } 15049d67454SMichal Simek }; 15149d67454SMichal Simek 15249d67454SMichal Simek U_BOOT_DRIVER(dwc3_generic_wrapper) = { 15349d67454SMichal Simek .name = "dwc3-generic-wrapper", 15449d67454SMichal Simek .id = UCLASS_MISC, 15549d67454SMichal Simek .of_match = dwc3_generic_ids, 15649d67454SMichal Simek .bind = dwc3_generic_bind, 15749d67454SMichal Simek }; 158