[U-Boot] [PATCH v2 05/13] usb: dwc3: change DWC3 core support code into a driver

Masahiro Yamada
2016-05-16T12:51:18Z

Synopsys DWC3 IP generally works with an SoC-specific glue layer.
DT binding for that is like this:

usb3_glue {
compatible = "foo,dwc3";
...

usb3 {
compatible = "snps,dwc3";
...
};
};

The glue layer initializes some SoC-specific parts, then populates
the child DWC3 core. To see how it works, refer to

drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-keystone.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-st.c

of Linux Kernel.

This commit implements a driver compatible with "snps,dwc3", allowing
to use the same binding in U-Boot. The glue layer can be simply
implemented based on Simple Bus Uclass.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Marek Vasut <marex@denx.de>
---

Changes in v2: None

drivers/usb/host/xhci-dwc3.c | 71 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c
index 33961cd..c7c8324 100644
--- a/drivers/usb/host/xhci-dwc3.c
+++ b/drivers/usb/host/xhci-dwc3.c
@@ -9,8 +9,13 @@
*/

#include <common.h>
-#include <asm/io.h>
+#include <dm/device.h>
+#include <mapmem.h>
+#include <linux/io.h>
#include <linux/usb/dwc3.h>
+#include <linux/sizes.h>
+
+#include "xhci.h"

void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
{
@@ -97,3 +102,67 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val)
setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL |
GFLADJ_30MHZ(val));
}
+
+struct dwc3_priv {
+ struct xhci_ctrl ctrl; /* should be the first member */
+ void __iomem *regs;
+};
+
+static int dwc3_probe(struct udevice *dev)
+{
+ struct dwc3_priv *priv = dev_get_priv(dev);
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
+ fdt_addr_t base;
+ int ret;
+
+ base = dev_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = map_sysmem(base, SZ_32K);
+ if (!priv->regs)
+ return -ENOMEM;
+
+ hccr = priv->regs;
+
+ hcor = priv->regs + HC_LENGTH(xhci_readl(&hccr->cr_capbase));
+
+ ret = dwc3_core_init(priv->regs + DWC3_REG_OFFSET);
+ if (ret) {
+ puts("XHCI: failed to initialize controller\n");
+ return ret;
+ }
+
+ /* We are hard-coding DWC3 core to Host Mode */
+ dwc3_set_mode(priv->regs + DWC3_REG_OFFSET, DWC3_GCTL_PRTCAP_HOST);
+
+ return xhci_register(dev, hccr, hcor);
+}
+
+static int dwc3_remove(struct udevice *dev)
+{
+ struct dwc3_priv *priv = dev_get_priv(dev);
+
+ xhci_deregister(dev);
+ unmap_sysmem(priv->regs);
+
+ return 0;
+}
+
+static const struct udevice_id of_dwc3_match[] = {
+ { .compatible = "snps,dwc3" },
+ { .compatible = "synopsys,dwc3" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(dwc3) = {
+ .name = "dwc3",
+ .id = UCLASS_USB,
+ .of_match = of_dwc3_match,
+ .probe = dwc3_probe,
+ .remove = dwc3_remove,
+ .ops = &xhci_usb_ops,
+ .priv_auto_alloc_size = sizeof(struct dwc3_priv),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
--
1.9.1