[PATCH v2 8/9] usb: xhci: Add Qualcomm DWC3 xHCI driver

Robert Marko robert.marko at sartura.hr
Tue Sep 1 19:23:01 CEST 2020


Add driver for Qualcomm DWC3 based dual role xHCI USB controller.
Currently tested on IPQ40xx, but should support other Qualcomm SoC families as well.

Only host mode is supported.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Cc: Luka Perkov <luka.perkov at sartura.hr>
---
 MAINTAINERS                                   |   2 +
 .../usb/qcom-dwc3-ipq.txt                     |  34 +++++
 drivers/usb/host/Kconfig                      |   6 +
 drivers/usb/host/Makefile                     |   1 +
 drivers/usb/host/xhci-ipq.c                   | 117 ++++++++++++++++++
 5 files changed, 160 insertions(+)
 create mode 100644 doc/device-tree-bindings/usb/qcom-dwc3-ipq.txt
 create mode 100644 drivers/usb/host/xhci-ipq.c

diff --git a/MAINTAINERS b/MAINTAINERS
index d8d2c6278b..99828f656a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -241,6 +241,8 @@ F:	include/dt-bindings/clock/qcom,ipq4019-gcc.h
 F:	include/dt-bindings/reset/qcom,ipq4019-reset.h
 F:	drivers/reset/reset-ipq4019.c
 F:	drivers/phy/phy-qcom-ipq4019-usb.c
+F:	doc/device-tree-bindings/usb/qcom-dwc3-ipq.txt
+F:	drivers/usb/host/xhci-ipq.c
 
 ARM MARVELL KIRKWOOD ARMADA-XP ARMADA-38X ARMADA-37XX ARMADA-7K/8K
 M:	Stefan Roese <sr at denx.de>
diff --git a/doc/device-tree-bindings/usb/qcom-dwc3-ipq.txt b/doc/device-tree-bindings/usb/qcom-dwc3-ipq.txt
new file mode 100644
index 0000000000..a910a06fa2
--- /dev/null
+++ b/doc/device-tree-bindings/usb/qcom-dwc3-ipq.txt
@@ -0,0 +1,34 @@
+Qualcomm SuperSpeed DWC3 USB SoC controller
+
+This controller is integrated in IPQ40xx SoC-s.
+It is a dual role USB3.0/USB2.0 controller.
+
+Required properties :
+ - compatible: must be "qcom,dwc3-ipq"
+ - reg: should contain address and length of the standard XHCI
+   register set for the device.
+ - #address-cells: must be 1
+ - #size-cells: must be 1
+ - phys: list of PHY specifiers
+ - phy-names: shall be "usb2-phy" and "usb3-phy"(In case of USB3.0 only)
+
+Example:
+	usb3: xhci at 8a00000 {
+		compatible = "qcom,dwc3-ipq";
+		reg = <0x8a00000 0xcd00>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		phys = <&usb3_hs_phy>, <&usb3_ss_phy>;
+		phy-names = "usb2-phy", "usb3-phy";
+		status = "disabled";
+	};
+
+	usb2: xhci at 6000000 {
+		compatible = "qcom,dwc3-ipq";
+		reg = <0x6000000 0xcd00>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		phys = <&usb2_hs_phy>;
+		phy-names = "usb2-phy";
+		status = "disabled";
+	};
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1c374a7bd8..7e0b1ab4ce 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -93,6 +93,12 @@ config USB_XHCI_BRCM
 	  USB controller based on the Broadcom USB3 IP Core.
 	  Supports USB2/3 functionality.
 
+config USB_XHCI_IPQ
+	bool "Support for Qualcomm IPQ on-chip DWC3 xHCI USB controller"
+	depends on DM_USB && PHY && USB_XHCI_DWC3 && ARCH_IPQ40XX 
+	help
+	  Enables support for the on-chip xHCI DWC3 controller on Qualcomm IPQ SoCs.
+
 endif # USB_XHCI_HCD
 
 config USB_EHCI_HCD
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 29d4f87e38..0fa9c8f32a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
 obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
 obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
 obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o
+obj-$(CONFIG_USB_XHCI_IPQ) += xhci-ipq.o
 obj-$(CONFIG_USB_XHCI_STI) += dwc3-sti-glue.o
 
 # designware
diff --git a/drivers/usb/host/xhci-ipq.c b/drivers/usb/host/xhci-ipq.c
new file mode 100644
index 0000000000..840f074819
--- /dev/null
+++ b/drivers/usb/host/xhci-ipq.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Sartura Ltd.
+ *
+ * Qualcomm DWC3 controller driver
+ *
+ * Author: Robert Marko <robert.marko at sartura.hr>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/compat.h>
+#include <linux/errno.h>
+#include <linux/usb/dwc3.h>
+#include <usb.h>
+#include <usb/xhci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct ipq_xhci_priv {
+	phys_addr_t					hcd_base;
+	struct xhci_ctrl 			ctrl;
+	struct xhci_hccr 			*hcd;
+	struct dwc3 				*dwc3_reg;
+	struct phy_bulk 			phys;
+};
+
+static int ipq_xhci_core_init(struct ipq_xhci_priv *ipq)
+{
+	int ret;
+
+	ret = dwc3_core_init(ipq->dwc3_reg);
+	if (ret) {
+		return ret;
+	}
+
+	/* We are hard-coding DWC3 core to Host Mode */
+	dwc3_set_mode(ipq->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
+
+	return ret;
+}
+
+static int ipq_xhci_core_exit(struct udevice *dev)
+{
+	struct ipq_xhci_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = generic_phy_power_off_bulk(&priv->phys);
+	ret |= generic_phy_exit_bulk(&priv->phys);
+	return ret;
+}
+
+static int ipq_xhci_usb_remove(struct udevice *dev)
+{
+	int ret;
+	ret = xhci_deregister(dev);
+
+	if (ret != 0) {
+		dev_err(dev, "XHCI deregistration failed\n");
+		return ret;
+	}
+
+	ipq_xhci_core_exit(dev);
+
+	return ret;
+}
+
+static int ipq_xhci_usb_probe(struct udevice *dev)
+{
+	struct ipq_xhci_priv *priv = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int ret;
+
+	priv->hcd_base = dev_read_addr(dev);
+	if (priv->hcd_base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	ret = generic_phy_get_bulk(dev, &priv->phys);
+	if (ret)
+		return ret;
+
+	priv->hcd = (struct xhci_hccr *)priv->hcd_base;
+	priv->dwc3_reg = (struct dwc3 *)((char *)(priv->hcd) + DWC3_REG_OFFSET);
+	hcor = (struct xhci_hcor *)((uint32_t)priv->hcd +
+			HC_LENGTH(xhci_readl(&priv->hcd->cr_capbase)));
+
+	ret = generic_phy_power_on_bulk(&priv->phys);
+	if (ret)
+		generic_phy_exit_bulk(&priv->phys);
+
+	ret = ipq_xhci_core_init(priv);
+
+	if (ret) {
+		dev_err(dev, "Error initializing the XHCI controller\n");
+		return ret;
+	}
+
+	return xhci_register(dev, priv->hcd, hcor);
+}
+
+static const struct udevice_id ipq_xhci_match_ids[] = {
+	{ .compatible = "qcom,dwc3-ipq" },
+	{}
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name	= "ipq_hci",
+	.id	= UCLASS_USB,
+	.of_match = ipq_xhci_match_ids,
+	.probe = ipq_xhci_usb_probe,
+	.remove = ipq_xhci_usb_remove,
+	.ops	= &xhci_usb_ops,
+	.priv_auto_alloc_size = sizeof(struct ipq_xhci_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
-- 
2.26.2



More information about the U-Boot mailing list