summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig59
-rw-r--r--drivers/usb/host/ehci-fsl.c194
-rw-r--r--drivers/usb/host/ehci-mx6.c144
-rw-r--r--drivers/usb/host/xhci-fsl.c83
4 files changed, 424 insertions, 56 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 7f94c1f372..31eec0a9e0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -3,8 +3,12 @@
#
comment "USB Host Controller Drivers"
+config USB_HOST
+ bool
+
config USB_XHCI_HCD
bool "xHCI HCD (USB 3.0) support"
+ select USB_HOST
---help---
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
"SuperSpeed" host controller hardware.
@@ -24,18 +28,11 @@ config USB_XHCI_DWC3
Say Y or if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
-endif
-
-config USB_OHCI_GENERIC
- bool "Support for generic OHCI USB controller"
- depends on OF_CONTROL
- depends on DM_USB
- default n
- ---help---
- Enables support for generic OHCI controller.
+endif # USB_XHCI_HCD
config USB_EHCI_HCD
bool "EHCI HCD (USB 2.0) support"
+ select USB_HOST
---help---
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
"high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
@@ -116,4 +113,46 @@ config USB_EHCI_GENERIC
---help---
Enables support for generic EHCI controller.
-endif
+endif # USB_EHCI_HCD
+
+config USB_OHCI_HCD
+ bool "OHCI HCD (USB 1.1) support"
+ ---help---
+ The Open Host Controller Interface (OHCI) is a standard for accessing
+ USB 1.1 host controller hardware. It does more in hardware than Intel's
+ UHCI specification. If your USB host controller follows the OHCI spec,
+ say Y. On most non-x86 systems, and on x86 hardware that's not using a
+ USB controller from Intel or VIA, this is appropriate. If your host
+ controller doesn't use PCI, this is probably appropriate. For a PCI
+ based system where you're not sure, the "lspci -v" entry will list the
+ right "prog-if" for your USB controller(s): EHCI, OHCI, or UHCI.
+
+if USB_OHCI_HCD
+
+config USB_OHCI_GENERIC
+ bool "Support for generic OHCI USB controller"
+ depends on OF_CONTROL
+ depends on DM_USB
+ select USB_HOST
+ ---help---
+ Enables support for generic OHCI controller.
+
+endif # USB_OHCI_HCD
+
+config USB_UHCI_HCD
+ bool "UHCI HCD (most Intel and VIA) support"
+ select USB_HOST
+ ---help---
+ The Universal Host Controller Interface is a standard by Intel for
+ accessing the USB hardware in the PC (which is also called the USB
+ host controller). If your USB host controller conforms to this
+ standard, you may want to say Y, but see below. All recent boards
+ with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+ i810, i820) conform to this standard. Also all VIA PCI chipsets
+ (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+ 133) and LEON/GRLIB SoCs with the GRUSBHC controller.
+ If unsure, say Y.
+
+if USB_UHCI_HCD
+
+endif # USB_UHCI_HCD
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index fa916ed77f..f5e3ae796e 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,5 +1,5 @@
/*
- * (C) Copyright 2009, 2011 Freescale Semiconductor, Inc.
+ * (C) Copyright 2009, 2011, 2016 Freescale Semiconductor, Inc.
*
* (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
*
@@ -16,14 +16,32 @@
#include <hwconfig.h>
#include <fsl_usb.h>
#include <fdt_support.h>
+#include <dm.h>
#include "ehci.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
#endif
+#ifdef CONFIG_DM_USB
+struct ehci_fsl_priv {
+ struct ehci_ctrl ehci;
+ fdt_addr_t hcd_base;
+ char *phy_type;
+};
+#endif
+
static void set_txfifothresh(struct usb_ehci *, u32);
+#ifdef CONFIG_DM_USB
+static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci,
+ struct ehci_hccr *hccr, struct ehci_hcor *hcor);
+#else
+static int ehci_fsl_init(int index, struct usb_ehci *ehci,
+ struct ehci_hccr *hccr, struct ehci_hcor *hcor);
+#endif
/* Check USB PHY clock valid */
static int usb_phy_clk_valid(struct usb_ehci *ehci)
@@ -37,6 +55,99 @@ static int usb_phy_clk_valid(struct usb_ehci *ehci)
}
}
+#ifdef CONFIG_DM_USB
+static int ehci_fsl_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ehci_fsl_priv *priv = dev_get_priv(dev);
+ const void *prop;
+
+ prop = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy_type",
+ NULL);
+ if (prop) {
+ priv->phy_type = (char *)prop;
+ debug("phy_type %s\n", priv->phy_type);
+ }
+
+ return 0;
+}
+
+static int ehci_fsl_init_after_reset(struct ehci_ctrl *ctrl)
+{
+ struct usb_ehci *ehci = NULL;
+ struct ehci_fsl_priv *priv = container_of(ctrl, struct ehci_fsl_priv,
+ ehci);
+
+ ehci = (struct usb_ehci *)priv->hcd_base;
+ if (ehci_fsl_init(priv, ehci, priv->ehci.hccr, priv->ehci.hcor) < 0)
+ return -ENXIO;
+
+ return 0;
+}
+
+static const struct ehci_ops fsl_ehci_ops = {
+ .init_after_reset = ehci_fsl_init_after_reset,
+};
+
+static int ehci_fsl_probe(struct udevice *dev)
+{
+ struct ehci_fsl_priv *priv = dev_get_priv(dev);
+ struct usb_ehci *ehci = NULL;
+ struct ehci_hccr *hccr;
+ struct ehci_hcor *hcor;
+
+ /*
+ * Get the base address for EHCI controller from the device node
+ */
+ priv->hcd_base = dev_get_addr(dev);
+ if (priv->hcd_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the EHCI register base address\n");
+ return -ENXIO;
+ }
+ ehci = (struct usb_ehci *)priv->hcd_base;
+ hccr = (struct ehci_hccr *)(&ehci->caplength);
+ hcor = (struct ehci_hcor *)
+ ((u32)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ if (ehci_fsl_init(priv, ehci, hccr, hcor) < 0)
+ return -ENXIO;
+
+ debug("ehci-fsl: init hccr %x and hcor %x hc_length %d\n",
+ (u32)hccr, (u32)hcor,
+ (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return ehci_register(dev, hccr, hcor, &fsl_ehci_ops, 0, USB_INIT_HOST);
+}
+
+static int ehci_fsl_remove(struct udevice *dev)
+{
+ int ret;
+
+ ret = ehci_deregister(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+ { .compatible = "fsl-usb2-mph", },
+ { .compatible = "fsl-usb2-dr", },
+ { }
+};
+
+U_BOOT_DRIVER(ehci_fsl) = {
+ .name = "ehci_fsl",
+ .id = UCLASS_USB,
+ .of_match = ehci_usb_ids,
+ .ofdata_to_platdata = ehci_fsl_ofdata_to_platdata,
+ .probe = ehci_fsl_probe,
+ .remove = ehci_fsl_remove,
+ .ops = &ehci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct ehci_fsl_priv),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#else
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
@@ -47,9 +158,49 @@ int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct usb_ehci *ehci = NULL;
+
+ switch (index) {
+ case 0:
+ ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR;
+ break;
+ case 1:
+ ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB2_ADDR;
+ break;
+ default:
+ printf("ERROR: wrong controller index!!\n");
+ return -EINVAL;
+ };
+
+ *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+ *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+ return ehci_fsl_init(index, ehci, *hccr, *hcor);
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_DM_USB
+static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci,
+ struct ehci_hccr *hccr, struct ehci_hcor *hcor)
+#else
+static int ehci_fsl_init(int index, struct usb_ehci *ehci,
+ struct ehci_hccr *hccr, struct ehci_hcor *hcor)
+#endif
+{
const char *phy_type = NULL;
+#ifndef CONFIG_DM_USB
size_t len;
char current_usb_controller[5];
+#endif
#ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY
char usb_phy[5];
@@ -64,25 +215,6 @@ int ehci_hcd_init(int index, enum usb_init_type init,
*/
mdelay(5);
}
- memset(current_usb_controller, '\0', 5);
- snprintf(current_usb_controller, sizeof(current_usb_controller),
- "usb%d", index+1);
-
- switch (index) {
- case 0:
- ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR;
- break;
- case 1:
- ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB2_ADDR;
- break;
- default:
- printf("ERROR: wrong controller index!!\n");
- return -EINVAL;
- };
-
- *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
- *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
- HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
/* Set to Host mode */
setbits_le32(&ehci->usbmode, CM_HOST);
@@ -91,9 +223,18 @@ int ehci_hcd_init(int index, enum usb_init_type init,
out_be32(&ehci->snoop2, 0x80000000 | SNOOP_SIZE_2GB);
/* Init phy */
+#ifdef CONFIG_DM_USB
+ if (priv->phy_type)
+ phy_type = priv->phy_type;
+#else
+ memset(current_usb_controller, '\0', 5);
+ snprintf(current_usb_controller, sizeof(current_usb_controller),
+ "usb%d", index+1);
+
if (hwconfig_sub(current_usb_controller, "phy_type"))
phy_type = hwconfig_subarg(current_usb_controller,
"phy_type", &len);
+#endif
else
phy_type = getenv("usb_phy_type");
@@ -116,7 +257,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
UTMI_PHY_EN);
udelay(1000); /* delay required for PHY Clk to appear */
#endif
- out_le32(&(*hcor)->or_portsc[0], PORT_PTS_UTMI);
+ out_le32(&(hcor)->or_portsc[0], PORT_PTS_UTMI);
clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
USB_EN);
} else {
@@ -127,7 +268,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
udelay(1000); /* delay required for PHY Clk to appear */
if (!usb_phy_clk_valid(ehci))
return -EINVAL;
- out_le32(&(*hcor)->or_portsc[0], PORT_PTS_ULPI);
+ out_le32(&(hcor)->or_portsc[0], PORT_PTS_ULPI);
}
out_be32(&ehci->prictrl, 0x0000000c);
@@ -153,15 +294,6 @@ int ehci_hcd_init(int index, enum usb_init_type init,
}
/*
- * Destroy the appropriate control structures corresponding
- * the the EHCI host controller.
- */
-int ehci_hcd_stop(int index)
-{
- return 0;
-}
-
-/*
* Setting the value of TXFIFO_THRESH field in TXFILLTUNING register
* to counter DDR latencies in writing data into Tx buffer.
* This prevents Tx buffer from getting underrun
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 8352c2bfc5..602fec5394 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -15,6 +15,7 @@
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/imx-common/iomux-v3.h>
+#include <dm.h>
#include "ehci.h"
@@ -307,6 +308,30 @@ int __weak board_ehci_power(int port, int on)
return 0;
}
+int ehci_mx6_common_init(struct usb_ehci *ehci, int index)
+{
+ int ret;
+
+ enable_usboh3_clk(1);
+ mdelay(1);
+
+ /* Do board specific initialization */
+ ret = board_ehci_hcd_init(index);
+ if (ret)
+ return ret;
+
+ usb_power_config(index);
+ usb_oc_config(index);
+
+#if defined(CONFIG_MX6)
+ usb_internal_phy_clock_gate(index, 1);
+ usb_phy_enable(index, ehci);
+#endif
+
+ return 0;
+}
+
+#ifndef CONFIG_DM_USB
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
@@ -322,26 +347,18 @@ int ehci_hcd_init(int index, enum usb_init_type init,
if (index > 3)
return -EINVAL;
- enable_usboh3_clk(1);
- mdelay(1);
- /* Do board specific initialization */
- ret = board_ehci_hcd_init(index);
+ ret = ehci_mx6_common_init(ehci, index);
if (ret)
return ret;
- usb_power_config(index);
- usb_oc_config(index);
-
-#if defined(CONFIG_MX6)
- usb_internal_phy_clock_gate(index, 1);
- usb_phy_enable(index, ehci);
-#endif
type = board_usb_phy_mode(index);
- *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
- *hcor = (struct ehci_hcor *)((uint32_t)*hccr +
- HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+ if (hccr && hcor) {
+ *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+ *hcor = (struct ehci_hcor *)((uint32_t)*hccr +
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+ }
if ((type == init) || (type == USB_INIT_DEVICE))
board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1);
@@ -363,3 +380,102 @@ int ehci_hcd_stop(int index)
{
return 0;
}
+#else
+struct ehci_mx6_priv_data {
+ struct ehci_ctrl ctrl;
+ struct usb_ehci *ehci;
+ enum usb_init_type init_type;
+ int portnr;
+};
+
+static int mx6_init_after_reset(struct ehci_ctrl *dev)
+{
+ struct ehci_mx6_priv_data *priv = dev->priv;
+ enum usb_init_type type = priv->init_type;
+ struct usb_ehci *ehci = priv->ehci;
+ int ret;
+
+ ret = ehci_mx6_common_init(priv->ehci, priv->portnr);
+ if (ret)
+ return ret;
+
+ board_ehci_power(priv->portnr, (type == USB_INIT_DEVICE) ? 0 : 1);
+
+ if (type == USB_INIT_DEVICE)
+ return 0;
+
+ setbits_le32(&ehci->usbmode, CM_HOST);
+ writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+ setbits_le32(&ehci->portsc, USB_EN);
+
+ mdelay(10);
+
+ return 0;
+}
+
+static const struct ehci_ops mx6_ehci_ops = {
+ .init_after_reset = mx6_init_after_reset
+};
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+ struct usb_platdata *plat = dev_get_platdata(dev);
+ struct usb_ehci *ehci = (struct usb_ehci *)dev_get_addr(dev);
+ struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
+ struct ehci_hccr *hccr;
+ struct ehci_hcor *hcor;
+ int ret;
+
+ priv->ehci = ehci;
+ priv->portnr = dev->seq;
+ priv->init_type = plat->init_type;
+
+ ret = ehci_mx6_common_init(ehci, priv->portnr);
+ if (ret)
+ return ret;
+
+ board_ehci_power(priv->portnr, (priv->init_type == USB_INIT_DEVICE) ? 0 : 1);
+
+ if (priv->init_type == USB_INIT_HOST) {
+ setbits_le32(&ehci->usbmode, CM_HOST);
+ writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+ setbits_le32(&ehci->portsc, USB_EN);
+ }
+
+ mdelay(10);
+
+ hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+ hcor = (struct ehci_hcor *)((uint32_t)hccr +
+ HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
+
+ return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+ int ret;
+
+ ret = ehci_deregister(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id mx6_usb_ids[] = {
+ { .compatible = "fsl,imx27-usb" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_mx6) = {
+ .name = "ehci_mx6",
+ .id = UCLASS_USB,
+ .of_match = mx6_usb_ids,
+ .probe = ehci_usb_probe,
+ .remove = ehci_usb_remove,
+ .ops = &ehci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/usb/host/xhci-fsl.c b/drivers/usb/host/xhci-fsl.c
index c12a189485..bdcd4f1c99 100644
--- a/drivers/usb/host/xhci-fsl.c
+++ b/drivers/usb/host/xhci-fsl.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Freescale Semiconductor, Inc.
+ * Copyright 2015,2016 Freescale Semiconductor, Inc.
*
* FSL USB HOST xHCI Controller
*
@@ -17,12 +17,21 @@
#include "xhci.h"
#include <fsl_errata.h>
#include <fsl_usb.h>
+#include <dm.h>
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_DM_USB
static struct fsl_xhci fsl_xhci;
unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR;
+#else
+struct xhci_fsl_priv {
+ struct xhci_ctrl xhci;
+ fdt_addr_t hcd_base;
+ struct fsl_xhci ctx;
+};
+#endif
__weak int __board_usb_init(int index, enum usb_init_type init)
{
@@ -77,6 +86,77 @@ static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci)
return 0;
}
+#ifdef CONFIG_DM_USB
+static int xhci_fsl_probe(struct udevice *dev)
+{
+ struct xhci_fsl_priv *priv = dev_get_priv(dev);
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
+
+ int ret = 0;
+
+ /*
+ * Get the base address for XHCI controller from the device node
+ */
+ priv->hcd_base = dev_get_addr(dev);
+ if (priv->hcd_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the XHCI register base address\n");
+ return -ENXIO;
+ }
+ priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base;
+ priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) +
+ DWC3_REG_OFFSET);
+
+ fsl_apply_xhci_errata();
+
+ ret = fsl_xhci_core_init(&priv->ctx);
+ if (ret < 0) {
+ puts("Failed to initialize xhci\n");
+ return ret;
+ }
+
+ hccr = (struct xhci_hccr *)(priv->ctx.hcd);
+ hcor = (struct xhci_hcor *)((uintptr_t) hccr
+ + HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
+
+ debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n",
+ (uintptr_t)hccr, (uintptr_t)hcor,
+ (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
+
+ return xhci_register(dev, hccr, hcor);
+}
+
+static int xhci_fsl_remove(struct udevice *dev)
+{
+ struct xhci_fsl_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ fsl_xhci_core_exit(&priv->ctx);
+
+ ret = xhci_deregister(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+ { .compatible = "fsl,layerscape-dwc3", },
+ { }
+};
+
+U_BOOT_DRIVER(xhci_fsl) = {
+ .name = "xhci_fsl",
+ .id = UCLASS_USB,
+ .of_match = xhci_usb_ids,
+ .probe = xhci_fsl_probe,
+ .remove = xhci_fsl_remove,
+ .ops = &xhci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct xhci_fsl_priv),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#else
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
struct fsl_xhci *ctx = &fsl_xhci;
@@ -116,3 +196,4 @@ void xhci_hcd_stop(int index)
fsl_xhci_core_exit(ctx);
}
+#endif