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) 25ff8d7558SJean-Jacques Hiblot int dm_usb_gadget_handle_interrupts(struct udevice *dev) 2649d67454SMichal Simek { 27ff8d7558SJean-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 U_BOOT_DRIVER(dwc3_generic_peripheral) = { 7449d67454SMichal Simek .name = "dwc3-generic-peripheral", 75*01311624SJean-Jacques Hiblot .id = UCLASS_USB_GADGET_GENERIC, 7649d67454SMichal Simek .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, 7749d67454SMichal Simek .probe = dwc3_generic_peripheral_probe, 7849d67454SMichal Simek .remove = dwc3_generic_peripheral_remove, 7949d67454SMichal Simek .platdata_auto_alloc_size = sizeof(struct usb_platdata), 8049d67454SMichal Simek .priv_auto_alloc_size = sizeof(struct dwc3), 8149d67454SMichal Simek }; 82687ab545SJean-Jacques Hiblot #endif 8349d67454SMichal Simek 8449d67454SMichal Simek static int dwc3_generic_bind(struct udevice *parent) 8549d67454SMichal Simek { 8649d67454SMichal Simek const void *fdt = gd->fdt_blob; 8749d67454SMichal Simek int node; 8849d67454SMichal Simek int ret; 8949d67454SMichal Simek 9049d67454SMichal Simek for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 9149d67454SMichal Simek node = fdt_next_subnode(fdt, node)) { 9249d67454SMichal Simek const char *name = fdt_get_name(fdt, node, NULL); 9349d67454SMichal Simek enum usb_dr_mode dr_mode; 9449d67454SMichal Simek struct udevice *dev; 9549d67454SMichal Simek const char *driver; 9649d67454SMichal Simek 9749d67454SMichal Simek debug("%s: subnode name: %s\n", __func__, name); 9849d67454SMichal Simek if (strncmp(name, "dwc3@", 4)) 9949d67454SMichal Simek continue; 10049d67454SMichal Simek 10149d67454SMichal Simek dr_mode = usb_get_dr_mode(node); 10249d67454SMichal Simek 10349d67454SMichal Simek switch (dr_mode) { 10449d67454SMichal Simek case USB_DR_MODE_PERIPHERAL: 10549d67454SMichal Simek case USB_DR_MODE_OTG: 10649d67454SMichal Simek debug("%s: dr_mode: OTG or Peripheral\n", __func__); 10749d67454SMichal Simek driver = "dwc3-generic-peripheral"; 10849d67454SMichal Simek break; 10949d67454SMichal Simek case USB_DR_MODE_HOST: 11049d67454SMichal Simek debug("%s: dr_mode: HOST\n", __func__); 11149d67454SMichal Simek driver = "dwc3-generic-host"; 11249d67454SMichal Simek break; 11349d67454SMichal Simek default: 11449d67454SMichal Simek debug("%s: unsupported dr_mode\n", __func__); 11549d67454SMichal Simek return -ENODEV; 11649d67454SMichal Simek }; 11749d67454SMichal Simek 11849d67454SMichal Simek ret = device_bind_driver_to_node(parent, driver, name, 11949d67454SMichal Simek offset_to_ofnode(node), &dev); 12049d67454SMichal Simek if (ret) { 12149d67454SMichal Simek debug("%s: not able to bind usb device mode\n", 12249d67454SMichal Simek __func__); 12349d67454SMichal Simek return ret; 12449d67454SMichal Simek } 12549d67454SMichal Simek } 12649d67454SMichal Simek 12749d67454SMichal Simek return 0; 12849d67454SMichal Simek } 12949d67454SMichal Simek 13049d67454SMichal Simek static const struct udevice_id dwc3_generic_ids[] = { 13149d67454SMichal Simek { .compatible = "xlnx,zynqmp-dwc3" }, 13249d67454SMichal Simek { } 13349d67454SMichal Simek }; 13449d67454SMichal Simek 13549d67454SMichal Simek U_BOOT_DRIVER(dwc3_generic_wrapper) = { 13649d67454SMichal Simek .name = "dwc3-generic-wrapper", 13749d67454SMichal Simek .id = UCLASS_MISC, 13849d67454SMichal Simek .of_match = dwc3_generic_ids, 13949d67454SMichal Simek .bind = dwc3_generic_bind, 14049d67454SMichal Simek }; 141