drivers: usb: host: Add BRCM xHCI driver
authorRayagonda Kokatanur <rayagonda.kokatanur@broadcom.com>
Thu, 9 Apr 2020 03:53:15 +0000 (09:23 +0530)
committerMarek Vasut <marek.vasut+renesas@gmail.com>
Mon, 13 Apr 2020 11:48:41 +0000 (13:48 +0200)
Base driver for Broadcom xHCI controllers

Signed-off-by: Bharat Kumar Reddy Gooty <bharat.gooty@broadcom.com>
Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com>
Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/xhci-brcm.c [new file with mode: 0644]

index 0987ff25b18ae15e2000de95fbb695f3a6ee4ad8..94ac969058e680a0c4bdccb414346382213d2446 100644 (file)
@@ -88,6 +88,14 @@ config USB_XHCI_FSL
        depends on !SPL_NO_USB
        help
          Enables support for the on-chip xHCI controller on NXP Layerscape SoCs.
+
+config USB_XHCI_BRCM
+       bool "Broadcom USB3 Host XHCI controller"
+       depends on DM_USB
+       help
+         USB controller based on the Broadcom USB3 IP Core.
+         Supports USB2/3 functionality.
+
 endif # USB_XHCI_HCD
 
 config USB_EHCI_HCD
index 7feeff679c5d2010c98eaca8c98065e765e53fc4..b62f346094fad811a2ebf75a71ecca564397ba9f 100644 (file)
@@ -44,6 +44,7 @@ obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
 obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
 
 # xhci
+obj-$(CONFIG_USB_XHCI_BRCM) += xhci-brcm.o
 obj-$(CONFIG_USB_XHCI_HCD) += xhci.o xhci-mem.o xhci-ring.o
 obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o
 obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
diff --git a/drivers/usb/host/xhci-brcm.c b/drivers/usb/host/xhci-brcm.c
new file mode 100644 (file)
index 0000000..ee65f51
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Broadcom.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <usb/xhci.h>
+
+#define DRD2U3H_XHC_REGS_AXIWRA        0xC08
+#define DRD2U3H_XHC_REGS_AXIRDA        0xC0C
+
+#define USBAXI_CACHE           0xF
+#define USBAXI_PROT            0x8
+#define USBAXI_SA_MASK         0x1FF
+#define USBAXI_UA_MASK         (0x1FF << 16)
+#define USBAXI_SA_VAL          ((USBAXI_CACHE << 4) | USBAXI_PROT)
+#define USBAXI_UA_VAL          (USBAXI_SA_VAL << 16)
+#define USBAXI_SA_UA_MASK      (USBAXI_UA_MASK | USBAXI_SA_MASK)
+#define USBAXI_SA_UA_VAL       (USBAXI_UA_VAL | USBAXI_SA_VAL)
+
+struct brcm_xhci_platdata {
+       unsigned int arcache;
+       unsigned int awcache;
+       void __iomem *hc_base;
+};
+
+static int xhci_brcm_probe(struct udevice *dev)
+{
+       struct brcm_xhci_platdata *plat = dev_get_platdata(dev);
+       struct xhci_hcor *hcor;
+       struct xhci_hccr *hcd;
+       int len, ret = 0;
+
+       if (!plat) {
+               dev_err(dev, "Can't get xHCI Plat data\n");
+               return -ENOMEM;
+       }
+
+       hcd = dev_read_addr_ptr(dev);
+       if (!hcd) {
+               dev_err(dev, "Can't get the xHCI register base address\n");
+               return -ENXIO;
+       }
+
+       plat->hc_base = hcd;
+       len = HC_LENGTH(xhci_readl(&hcd->cr_capbase));
+       hcor = (struct xhci_hcor *)(plat->hc_base + len);
+
+       /* Save the default values of AXI read and write attributes */
+       plat->awcache = readl(plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA);
+       plat->arcache = readl(plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA);
+
+       /* Enable AXI write attributes */
+       clrsetbits_le32(plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA,
+                       USBAXI_SA_UA_MASK, USBAXI_SA_UA_VAL);
+
+       /* Enable AXI read attributes */
+       clrsetbits_le32(plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA,
+                       USBAXI_SA_UA_MASK, USBAXI_SA_UA_VAL);
+
+       ret = xhci_register(dev, hcd, hcor);
+       if (ret)
+               dev_err(dev, "Failed to register xHCI\n");
+
+       return ret;
+}
+
+static int xhci_brcm_deregister(struct udevice *dev)
+{
+       struct brcm_xhci_platdata *plat = dev_get_platdata(dev);
+
+       /* Restore the default values for AXI read and write attributes */
+       writel(plat->awcache, plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA);
+       writel(plat->arcache, plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA);
+
+       return xhci_deregister(dev);
+}
+
+static const struct udevice_id xhci_brcm_ids[] = {
+       { .compatible = "brcm,generic-xhci" },
+       { }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+       .name                           = "xhci_brcm",
+       .id                             = UCLASS_USB,
+       .probe                          = xhci_brcm_probe,
+       .remove                         = xhci_brcm_deregister,
+       .ops                            = &xhci_usb_ops,
+       .of_match                       = xhci_brcm_ids,
+       .platdata_auto_alloc_size       = sizeof(struct brcm_xhci_platdata),
+       .priv_auto_alloc_size           = sizeof(struct xhci_ctrl),
+       .flags                          = DM_FLAG_ALLOC_PRIV_DMA,
+};