diff options
Diffstat (limited to 'drivers/usb/dwc3/dwc3-generic.c')
-rw-r--r-- | drivers/usb/dwc3/dwc3-generic.c | 146 |
1 files changed, 113 insertions, 33 deletions
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 406bf0b362..023e95395b 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -21,51 +21,60 @@ #include "gadget.h" #include <reset.h> #include <clk.h> +#include <usb/xhci.h> -#if CONFIG_IS_ENABLED(DM_USB_GADGET) -struct dwc3_generic_peripheral { +struct dwc3_generic_plat { + fdt_addr_t base; + u32 maximum_speed; + enum usb_dr_mode dr_mode; +}; + +struct dwc3_generic_priv { + void *base; struct dwc3 dwc3; struct phy *phys; int num_phys; - fdt_addr_t base; }; -int dm_usb_gadget_handle_interrupts(struct udevice *dev) -{ - struct dwc3_generic_peripheral *priv = dev_get_priv(dev); - struct dwc3 *dwc3 = &priv->dwc3; - - dwc3_gadget_uboot_handle_interrupt(dwc3); - - return 0; -} +struct dwc3_generic_host_priv { + struct xhci_ctrl xhci_ctrl; + struct dwc3_generic_priv gen_priv; +}; -static int dwc3_generic_peripheral_probe(struct udevice *dev) +static int dwc3_generic_probe(struct udevice *dev, + struct dwc3_generic_priv *priv) { int rc; - struct dwc3_generic_peripheral *priv = dev_get_priv(dev); + struct dwc3_generic_plat *plat = dev_get_platdata(dev); struct dwc3 *dwc3 = &priv->dwc3; + dwc3->dev = dev; + dwc3->maximum_speed = plat->maximum_speed; + dwc3->dr_mode = plat->dr_mode; +#if CONFIG_IS_ENABLED(OF_CONTROL) + dwc3_of_parse(dwc3); +#endif + rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys); if (rc) return rc; - dwc3->regs = map_physmem(priv->base, DWC3_OTG_REGS_END, MAP_NOCACHE); - dwc3->regs += DWC3_GLOBALS_REGS_START; - dwc3->dev = dev; + priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE); + dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START; + rc = dwc3_init(dwc3); if (rc) { - unmap_physmem(dwc3->regs, MAP_NOCACHE); + unmap_physmem(priv->base, MAP_NOCACHE); return rc; } return 0; } -static int dwc3_generic_peripheral_remove(struct udevice *dev) +static int dwc3_generic_remove(struct udevice *dev, + struct dwc3_generic_priv *priv) { - struct dwc3_generic_peripheral *priv = dev_get_priv(dev); struct dwc3 *dwc3 = &priv->dwc3; dwc3_remove(dwc3); @@ -75,22 +84,21 @@ static int dwc3_generic_peripheral_remove(struct udevice *dev) return 0; } -static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) +static int dwc3_generic_ofdata_to_platdata(struct udevice *dev) { - struct dwc3_generic_peripheral *priv = dev_get_priv(dev); - struct dwc3 *dwc3 = &priv->dwc3; + struct dwc3_generic_plat *plat = dev_get_platdata(dev); int node = dev_of_offset(dev); - priv->base = devfdt_get_addr(dev); + plat->base = devfdt_get_addr(dev); - dwc3->maximum_speed = usb_get_maximum_speed(node); - if (dwc3->maximum_speed == USB_SPEED_UNKNOWN) { - pr_err("Invalid usb maximum speed\n"); - return -ENODEV; + plat->maximum_speed = usb_get_maximum_speed(node); + if (plat->maximum_speed == USB_SPEED_UNKNOWN) { + pr_info("No USB maximum speed specified. Using super speed\n"); + plat->maximum_speed = USB_SPEED_SUPER; } - dwc3->dr_mode = usb_get_dr_mode(node); - if (dwc3->dr_mode == USB_DR_MODE_UNKNOWN) { + plat->dr_mode = usb_get_dr_mode(node); + if (plat->dr_mode == USB_DR_MODE_UNKNOWN) { pr_err("Invalid usb mode setup\n"); return -ENODEV; } @@ -98,13 +106,83 @@ static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) return 0; } +#if CONFIG_IS_ENABLED(DM_USB_GADGET) +int dm_usb_gadget_handle_interrupts(struct udevice *dev) +{ + struct dwc3_generic_priv *priv = dev_get_priv(dev); + struct dwc3 *dwc3 = &priv->dwc3; + + dwc3_gadget_uboot_handle_interrupt(dwc3); + + return 0; +} + +static int dwc3_generic_peripheral_probe(struct udevice *dev) +{ + struct dwc3_generic_priv *priv = dev_get_priv(dev); + + return dwc3_generic_probe(dev, priv); +} + +static int dwc3_generic_peripheral_remove(struct udevice *dev) +{ + struct dwc3_generic_priv *priv = dev_get_priv(dev); + + return dwc3_generic_remove(dev, priv); +} + U_BOOT_DRIVER(dwc3_generic_peripheral) = { .name = "dwc3-generic-peripheral", .id = UCLASS_USB_GADGET_GENERIC, - .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, + .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata, .probe = dwc3_generic_peripheral_probe, .remove = dwc3_generic_peripheral_remove, - .priv_auto_alloc_size = sizeof(struct dwc3_generic_peripheral), + .priv_auto_alloc_size = sizeof(struct dwc3_generic_priv), + .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat), +}; +#endif + +#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD) +static int dwc3_generic_host_probe(struct udevice *dev) +{ + struct xhci_hcor *hcor; + struct xhci_hccr *hccr; + struct dwc3_generic_host_priv *priv = dev_get_priv(dev); + int rc; + + rc = dwc3_generic_probe(dev, &priv->gen_priv); + if (rc) + return rc; + + hccr = (struct xhci_hccr *)priv->gen_priv.base; + hcor = (struct xhci_hcor *)(priv->gen_priv.base + + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); + + return xhci_register(dev, hccr, hcor); +} + +static int dwc3_generic_host_remove(struct udevice *dev) +{ + struct dwc3_generic_host_priv *priv = dev_get_priv(dev); + int rc; + + rc = xhci_deregister(dev); + if (rc) + return rc; + + return dwc3_generic_remove(dev, &priv->gen_priv); +} + +U_BOOT_DRIVER(dwc3_generic_host) = { + .name = "dwc3-generic-host", + .id = UCLASS_USB, + .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata, + .probe = dwc3_generic_host_probe, + .remove = dwc3_generic_host_remove, + .priv_auto_alloc_size = sizeof(struct dwc3_generic_host_priv), + .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat), + .ops = &xhci_usb_ops, + .flags = DM_FLAG_ALLOC_PRIV_DMA, }; #endif @@ -228,10 +306,12 @@ static int dwc3_glue_bind(struct udevice *parent) driver = "dwc3-generic-peripheral"; #endif break; +#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD) case USB_DR_MODE_HOST: debug("%s: dr_mode: HOST\n", __func__); - driver = "xhci-dwc3"; + driver = "dwc3-generic-host"; break; +#endif default: debug("%s: unsupported dr_mode\n", __func__); return -ENODEV; |