usb: dwc3-generic: add a new host driver that uses the dwc3 core
authorJean-Jacques Hiblot <jjhiblot@ti.com>
Wed, 11 Sep 2019 09:33:50 +0000 (11:33 +0200)
committerMarek Vasut <marek.vasut+renesas@gmail.com>
Thu, 24 Oct 2019 09:28:17 +0000 (11:28 +0200)
Currently the host driver used by dwc3-generic is "xhci-dwc3". This is
a functional driver but it doesn't use the dwc3 core and, in particular,
it lacks some bits that may be important.
For example on the k2 platforms, it is important that the phy are properly
suspended when the USB is not used anymore. The dwc3 core also has a
partial support for quirks.
The new driver can be used as a drop-in replacement for "xhci-dwc3".

In terms of implementation, it may seem strange that 2 private structures
dwc3_generic_host_priv and dwc3_generic_priv) are used. The reason for this
is simply that the xhci layer expects a struct xhci_ctrl at the beginning
of the private data and it seemed wasteful to include it also for the
peripheral case.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-generic.c

index 1bd41f8bc771da6a324d6b5e4547ce721bf0da24..bb3f9d2fc82e0e7043ead21589bd0792ca7358e5 100644 (file)
@@ -887,7 +887,7 @@ int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys)
 }
 #endif
 
-#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+#if CONFIG_IS_ENABLED(DM_USB)
 int dwc3_init(struct dwc3 *dwc)
 {
        int ret;
index d5c71d024f37844cf3db2c99a101cc567380a690..4924d07553fabe9733063be04d6c33b6713db2a3 100644 (file)
@@ -21,6 +21,7 @@
 #include "gadget.h"
 #include <reset.h>
 #include <clk.h>
+#include <usb/xhci.h>
 
 struct dwc3_generic_plat {
        fdt_addr_t base;
@@ -35,6 +36,11 @@ struct dwc3_generic_priv {
        int num_phys;
 };
 
+struct dwc3_generic_host_priv {
+       struct xhci_ctrl xhci_ctrl;
+       struct dwc3_generic_priv gen_priv;
+};
+
 static int dwc3_generic_probe(struct udevice *dev,
                              struct dwc3_generic_priv *priv)
 {
@@ -132,6 +138,50 @@ U_BOOT_DRIVER(dwc3_generic_peripheral) = {
 };
 #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
+
 struct dwc3_glue_data {
        struct clk_bulk         clks;
        struct reset_ctl_bulk   resets;
@@ -252,10 +302,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;