|
@@ -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;
|