On Mon, Aug 17, 2020 at 12:36:05PM +0200, Robert Marko wrote: > Add driver for Qualcomm DWC3 based dual role xHCI USB controller. > Currently tested on IPQ40xx, but should support other Qualcomm SoC families > as well. > > Signed-off-by: Robert Marko <robert.ma...@sartura.hr> > --- > MAINTAINERS | 2 + > .../usb/qcom-dwc3-ipq.txt | 25 +++ > drivers/usb/host/Kconfig | 6 + > drivers/usb/host/Makefile | 1 + > drivers/usb/host/xhci-ipq.c | 193 ++++++++++++++++++ > 5 files changed, 227 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 1a55327406..0e4e281d9b 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -239,6 +239,8 @@ S: Maintained > F: arch/arm/mach-ipq40xx/ > F: include/dt-bindings/reset/qcom,ipq40xx-reset.h > F: drivers/reset/reset-ipq40xx.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 <s...@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..591683e520 > --- /dev/null > +++ b/doc/device-tree-bindings/usb/qcom-dwc3-ipq.txt > @@ -0,0 +1,25 @@ > +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. > + > +Optional properties: > + - rst-ctrl: Magic value used to reset PHY-s properly > + (PHY-s may not function properly without it) > + - hs-only : If present, specifies that board only has USB2.0(HS) > + port > + > +Example: > + xhci@8a00000 { > + compatible = "qcom,dwc3-ipq"; > + #address-cells = <1>; > + #size-cells = <1>; > + reg = <0x8a00000 0xcd00>; > + rst-ctrl = <0x181E038 0x4>; > + status = "disabled"; > + }; > diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig > index 1c374a7bd8..320c77ead5 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 && 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..b550cafac2 > --- /dev/null > +++ b/drivers/usb/host/xhci-ipq.c > @@ -0,0 +1,193 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright 2015 Freescale Semiconductor, Inc. > + * Copyright (c) 2020 Sartura Ltd. > + * > + * DWC3 controller driver > + * > + * Author: Ramneek Mehresh<ramneek.mehr...@freescale.com> > + * Author: Robert Marko <robert.ma...@sartura.hr> > + * > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <usb.h> > +#include <linux/compat.h> > +#include <linux/errno.h> > +#include <linux/delay.h> > +#include <linux/usb/dwc3.h> > +#include <usb/xhci.h> > + > +/* Declare global data pointer */ > +DECLARE_GLOBAL_DATA_PTR; > + > +struct ipq_xhci_platdata { > + fdt_addr_t hcd_base; > + unsigned int rst_ctrl; > + unsigned int hs_only; > +}; > + > +struct ipq_xhci { > + struct ipq_xhci_platdata usb_plat; > + struct xhci_ctrl ctrl; > + struct udevice* dev; > + struct xhci_hccr *hcd; > + struct dwc3 *dwc3_reg; > +}; > + > +void ipq_reset_usb_phy(void *data) > +{ > + unsigned int gcc_rst_ctrl; > + struct ipq_xhci_platdata *platdata; > + struct ipq_xhci *ipq = (struct ipq_xhci *)data; > + > + platdata = dev_get_platdata(ipq->dev); > + if (platdata == NULL) { > + printf("Error: %s Failed\n", __func__); > + return; > + } > + > + gcc_rst_ctrl = platdata->rst_ctrl; > + > + if (gcc_rst_ctrl) { > + /* assert HS PHY POR reset */ > + setbits_le32(gcc_rst_ctrl, 0x10); > + mdelay(10); > + > + /* assert HS PHY SRIF reset */ > + setbits_le32(gcc_rst_ctrl, 0x4); > + mdelay(10); > + > + /* deassert HS PHY SRIF reset and program HS PHY registers */ > + clrbits_le32(gcc_rst_ctrl, 0x4); > + mdelay(10); > + > + /* de-assert USB3 HS PHY POR reset */ > + clrbits_le32(gcc_rst_ctrl, 0x10); > + mdelay(10); > + > + if (!platdata->hs_only) { > + /* assert SS PHY POR reset */ > + setbits_le32(gcc_rst_ctrl, 0x20); > + mdelay(10); > + > + /* deassert SS PHY POR reset */ > + clrbits_le32(gcc_rst_ctrl, 0x20); > + } > + } > +} > + > +static int ipq_xhci_core_init(struct ipq_xhci *ipq) > +{ > + int ret = 0; > + > + ipq_reset_usb_phy((void *)ipq); > + > + ret = dwc3_core_init(ipq->dwc3_reg); > + if (ret) { > + debug("%s:failed to initialize core\n", __func__); > + return ret; > + } > + > + /* We are hard-coding DWC3 core to Host Mode */ > + dwc3_set_mode(ipq->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); > + > + return ret; > +} > + > +static void ipq_xhci_core_exit(struct ipq_xhci *ipq) > +{ > + > +} > + > +static int xhci_usb_remove(struct udevice *dev) > +{ > + int ret; > + ret = xhci_deregister(dev); > + > + if (ret != 0) { > + debug("%s:xhci deregistration failed\n", __func__); > + return ret; > + } > + > + ipq_xhci_core_exit(dev_get_priv(dev)); > + > + return 0; > +} > + > +static int xhci_usb_probe(struct udevice *dev) > +{ > + struct ipq_xhci *context; > + struct ipq_xhci_platdata *platdata; > + struct xhci_hcor *hcor; > + int ret; > + > + platdata = dev_get_platdata(dev); > + if (platdata == NULL) { > + printf("Error: %s Failed\n", __func__); > + return -ENODEV; > + } > + > + context = dev_get_priv(dev); > + if (context == NULL) { > + printf("Error: %s Failed\n", __func__); > + return -ENODEV; > + } > + > + context->hcd = (struct xhci_hccr *)platdata->hcd_base; > + context->dev = dev; > + context->dwc3_reg = (struct dwc3 *)((char *)(context->hcd) + > DWC3_REG_OFFSET); > + hcor = (struct xhci_hcor *)((uint32_t)context->hcd + > + HC_LENGTH(xhci_readl(&context->hcd->cr_capbase))); > + > + ret = ipq_xhci_core_init(context); > + > + if (ret) { > + puts("Error initializing the XHCI controller\n"); > + return -EINVAL; > + } > + > + return xhci_register(dev, context->hcd, hcor); > +} > + > +static int xhci_ofdata_to_platdata(struct udevice *dev) > +{ > + struct ipq_xhci_platdata *platdata; > + const void *blob = gd->fdt_blob; > + > + platdata = dev_get_platdata(dev); > + if (platdata == NULL) { > + printf("Error: %s Failed\n", __func__); > + return -ENODEV; > + } > + > + platdata->hcd_base = devfdt_get_addr(dev); > + if (platdata->hcd_base == FDT_ADDR_T_NONE) { > + debug("Error getting DWC3 base address\n"); > + return -ENXIO; > + } > + > + platdata->rst_ctrl = fdtdec_get_int(blob, dev_of_offset(dev), > "rst-ctrl", 0); > + platdata->hs_only = fdtdec_get_int(blob, dev_of_offset(dev), "hs-only", > 0); > + > + return 0; > +} > + > +static const struct udevice_id xhci_match_ids[] = { > + { .compatible = "qcom,dwc3-ipq" }, > + {} > +}; > + > +U_BOOT_DRIVER(usb_xhci) = { > + .name = "xhci_ipq", > + .id = UCLASS_USB, > + .of_match = xhci_match_ids, > + .ofdata_to_platdata = xhci_ofdata_to_platdata, > + .probe = xhci_usb_probe, > + .remove = xhci_usb_remove, > + .ops = &xhci_usb_ops, > + .platdata_auto_alloc_size = sizeof(struct ipq_xhci_platdata), > + .priv_auto_alloc_size = sizeof(struct ipq_xhci), > + .flags = DM_FLAG_ALLOC_PRIV_DMA, > +};
Adding USB maintainer. -- Tom
signature.asc
Description: PGP signature