summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/host/ehci-sunxi.c66
-rw-r--r--drivers/usb/host/ohci-sunxi.c72
-rw-r--r--drivers/usb/host/xhci-rcar.c5
-rw-r--r--drivers/usb/host/xhci-rockchip.c16
-rw-r--r--drivers/usb/host/xhci-zynqmp.c87
-rw-r--r--drivers/usb/host/xhci.c14
7 files changed, 168 insertions, 93 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 3455e8113bb..b4dd005651c 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -75,6 +75,7 @@ config USB_XHCI_STI
config USB_XHCI_ZYNQMP
bool "Support for Xilinx ZynqMP on-chip xHCI USB controller"
depends on ARCH_ZYNQMP
+ depends on DM_USB
help
Enables support for the on-chip xHCI controller on Xilinx ZynqMP SoCs.
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
index 1297fdb6a71..360efc91160 100644
--- a/drivers/usb/host/ehci-sunxi.c
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -11,34 +11,62 @@
#include <common.h>
#include <asm/arch/clock.h>
-#include <asm/arch/usb_phy.h>
#include <asm/io.h>
#include <dm.h>
#include "ehci.h"
+#include <generic-phy.h>
#ifdef CONFIG_SUNXI_GEN_SUN4I
-#define BASE_DIST 0x8000
#define AHB_CLK_DIST 2
#else
-#define BASE_DIST 0x1000
#define AHB_CLK_DIST 1
#endif
struct ehci_sunxi_priv {
struct ehci_ctrl ehci;
+ struct sunxi_ccm_reg *ccm;
int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
- int phy_index; /* Index of the usb-phy attached to this hcd */
+ struct phy phy;
};
static int ehci_usb_probe(struct udevice *dev)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct usb_platdata *plat = dev_get_platdata(dev);
struct ehci_sunxi_priv *priv = dev_get_priv(dev);
struct ehci_hccr *hccr = (struct ehci_hccr *)devfdt_get_addr(dev);
struct ehci_hcor *hcor;
int extra_ahb_gate_mask = 0;
+ int phys, ret;
+ priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ if (IS_ERR(priv->ccm))
+ return PTR_ERR(priv->ccm);
+
+ phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
+ if (phys < 0) {
+ phys = 0;
+ goto no_phy;
+ }
+
+ ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
+ if (ret) {
+ pr_err("failed to get %s usb PHY\n", dev->name);
+ return ret;
+ }
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ pr_err("failed to init %s USB PHY\n", dev->name);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ pr_err("failed to power on %s USB PHY\n", dev->name);
+ return ret;
+ }
+
+no_phy:
/*
* This should go away once we've moved to the driver model for
* clocks resp. phys.
@@ -47,21 +75,16 @@ static int ehci_usb_probe(struct udevice *dev)
#if defined(CONFIG_MACH_SUNXI_H3_H5) || defined(CONFIG_MACH_SUN50I)
extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
#endif
- priv->phy_index = ((uintptr_t)hccr - SUNXI_USB1_BASE) / BASE_DIST;
- priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
- extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
- priv->phy_index++; /* Non otg phys start at 1 */
+ priv->ahb_gate_mask <<= phys * AHB_CLK_DIST;
+ extra_ahb_gate_mask <<= phys * AHB_CLK_DIST;
- setbits_le32(&ccm->ahb_gate0,
+ setbits_le32(&priv->ccm->ahb_gate0,
priv->ahb_gate_mask | extra_ahb_gate_mask);
#ifdef CONFIG_SUNXI_GEN_SUN6I
- setbits_le32(&ccm->ahb_reset0_cfg,
+ setbits_le32(&priv->ccm->ahb_reset0_cfg,
priv->ahb_gate_mask | extra_ahb_gate_mask);
#endif
- sunxi_usb_phy_init(priv->phy_index);
- sunxi_usb_phy_power_on(priv->phy_index);
-
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
@@ -70,20 +93,25 @@ static int ehci_usb_probe(struct udevice *dev)
static int ehci_usb_remove(struct udevice *dev)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct ehci_sunxi_priv *priv = dev_get_priv(dev);
int ret;
+ if (generic_phy_valid(&priv->phy)) {
+ ret = generic_phy_exit(&priv->phy);
+ if (ret) {
+ pr_err("failed to exit %s USB PHY\n", dev->name);
+ return ret;
+ }
+ }
+
ret = ehci_deregister(dev);
if (ret)
return ret;
- sunxi_usb_phy_exit(priv->phy_index);
-
#ifdef CONFIG_SUNXI_GEN_SUN6I
- clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
+ clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
#endif
- clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
+ clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask);
return 0;
}
diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c
index b78fad29a35..ce2b47a5c4b 100644
--- a/drivers/usb/host/ohci-sunxi.c
+++ b/drivers/usb/host/ohci-sunxi.c
@@ -10,35 +10,63 @@
#include <common.h>
#include <asm/arch/clock.h>
-#include <asm/arch/usb_phy.h>
#include <asm/io.h>
#include <dm.h>
#include <usb.h>
#include "ohci.h"
+#include <generic-phy.h>
#ifdef CONFIG_SUNXI_GEN_SUN4I
-#define BASE_DIST 0x8000
#define AHB_CLK_DIST 2
#else
-#define BASE_DIST 0x1000
#define AHB_CLK_DIST 1
#endif
struct ohci_sunxi_priv {
+ struct sunxi_ccm_reg *ccm;
ohci_t ohci;
int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */
- int phy_index; /* Index of the usb-phy attached to this hcd */
+ struct phy phy;
};
static int ohci_usb_probe(struct udevice *dev)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
struct ohci_sunxi_priv *priv = dev_get_priv(dev);
struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
int extra_ahb_gate_mask = 0;
+ int phys, ret;
+ priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ if (IS_ERR(priv->ccm))
+ return PTR_ERR(priv->ccm);
+
+ phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
+ if (phys < 0) {
+ phys = 0;
+ goto no_phy;
+ }
+
+ ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
+ if (ret) {
+ pr_err("failed to get %s usb PHY\n", dev->name);
+ return ret;
+ }
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ pr_err("failed to init %s USB PHY\n", dev->name);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ pr_err("failed to power on %s USB PHY\n", dev->name);
+ return ret;
+ }
+
+no_phy:
bus_priv->companion = true;
/*
@@ -50,43 +78,43 @@ static int ohci_usb_probe(struct udevice *dev)
extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
#endif
priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
- priv->phy_index = ((uintptr_t)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
- priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
- extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
- priv->usb_gate_mask <<= priv->phy_index;
- priv->phy_index++; /* Non otg phys start at 1 */
+ priv->ahb_gate_mask <<= phys * AHB_CLK_DIST;
+ extra_ahb_gate_mask <<= phys * AHB_CLK_DIST;
+ priv->usb_gate_mask <<= phys;
- setbits_le32(&ccm->ahb_gate0,
+ setbits_le32(&priv->ccm->ahb_gate0,
priv->ahb_gate_mask | extra_ahb_gate_mask);
- setbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
+ setbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask);
#ifdef CONFIG_SUNXI_GEN_SUN6I
- setbits_le32(&ccm->ahb_reset0_cfg,
+ setbits_le32(&priv->ccm->ahb_reset0_cfg,
priv->ahb_gate_mask | extra_ahb_gate_mask);
#endif
- sunxi_usb_phy_init(priv->phy_index);
- sunxi_usb_phy_power_on(priv->phy_index);
-
return ohci_register(dev, regs);
}
static int ohci_usb_remove(struct udevice *dev)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct ohci_sunxi_priv *priv = dev_get_priv(dev);
int ret;
+ if (generic_phy_valid(&priv->phy)) {
+ ret = generic_phy_exit(&priv->phy);
+ if (ret) {
+ pr_err("failed to exit %s USB PHY\n", dev->name);
+ return ret;
+ }
+ }
+
ret = ohci_deregister(dev);
if (ret)
return ret;
- sunxi_usb_phy_exit(priv->phy_index);
-
#ifdef CONFIG_SUNXI_GEN_SUN6I
- clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
+ clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
#endif
- clrbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
- clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
+ clrbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask);
+ clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask);
return 0;
}
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index a837afc483b..f2e91ef0feb 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -117,12 +117,15 @@ err_clk:
static int xhci_rcar_deregister(struct udevice *dev)
{
+ int ret;
struct rcar_xhci_platdata *plat = dev_get_platdata(dev);
+ ret = xhci_deregister(dev);
+
clk_disable(&plat->clk);
clk_free(&plat->clk);
- return xhci_deregister(dev);
+ return ret;
}
static int xhci_rcar_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c
index 060a6c43092..f19bea3a91b 100644
--- a/drivers/usb/host/xhci-rockchip.c
+++ b/drivers/usb/host/xhci-rockchip.c
@@ -17,7 +17,6 @@
struct rockchip_xhci_platdata {
fdt_addr_t hcd_base;
- fdt_addr_t phy_base;
struct udevice *vbus_supply;
};
@@ -35,7 +34,6 @@ struct rockchip_xhci {
static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
{
struct rockchip_xhci_platdata *plat = dev_get_platdata(dev);
- struct udevice *child;
int ret = 0;
/*
@@ -47,20 +45,6 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
return -ENXIO;
}
- /* Get the base address for usbphy from the device node */
- for (device_find_first_child(dev, &child); child;
- device_find_next_child(&child)) {
- if (!device_is_compatible(child, "rockchip,rk3399-usb3-phy"))
- continue;
- plat->phy_base = devfdt_get_addr(child);
- break;
- }
-
- if (plat->phy_base == FDT_ADDR_T_NONE) {
- pr_err("Can't get the usbphy register address\n");
- return -ENXIO;
- }
-
/* Vbus regulator */
ret = device_get_supply_regulator(dev, "vbus-supply",
&plat->vbus_supply);
diff --git a/drivers/usb/host/xhci-zynqmp.c b/drivers/usb/host/xhci-zynqmp.c
index 1723d2f6862..e44e1ae1d91 100644
--- a/drivers/usb/host/xhci-zynqmp.c
+++ b/drivers/usb/host/xhci-zynqmp.c
@@ -10,9 +10,10 @@
*/
#include <common.h>
+#include <dm.h>
#include <usb.h>
#include <linux/errno.h>
-#include <asm/arch-zynqmp/hardware.h>
+#include <asm/arch/hardware.h>
#include <linux/compat.h>
#include <linux/usb/dwc3.h>
#include "xhci.h"
@@ -54,13 +55,15 @@
#define USBOTGSS_IRQ_SET_1_DMADISABLECLR_EN BIT(17)
struct zynqmp_xhci {
+ struct usb_platdata usb_plat;
+ struct xhci_ctrl ctrl;
struct xhci_hccr *hcd;
struct dwc3 *dwc3_reg;
};
-static struct zynqmp_xhci zynqmp_xhci;
-
-unsigned long ctr_addr[] = CONFIG_ZYNQMP_XHCI_LIST;
+struct zynqmp_xhci_platdata {
+ fdt_addr_t hcd_base;
+};
static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci)
{
@@ -78,46 +81,66 @@ static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci)
return ret;
}
-int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
+void xhci_hcd_stop(int index)
{
- struct zynqmp_xhci *ctx = &zynqmp_xhci;
- int ret = 0;
- uint32_t hclen;
+ /*
+ * Currently zynqmp socs do not support PHY shutdown from
+ * sw. But this support may be added in future socs.
+ */
- if (index < 0 || index >= ARRAY_SIZE(ctr_addr))
- return -EINVAL;
+ return;
+}
- ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
- ctx->dwc3_reg = (struct dwc3 *)((void *)ctx->hcd + DWC3_REG_OFFSET);
+static int xhci_usb_probe(struct udevice *dev)
+{
+ struct zynqmp_xhci_platdata *plat = dev_get_platdata(dev);
+ struct zynqmp_xhci *ctx = dev_get_priv(dev);
+ struct xhci_hcor *hcor;
+ int ret;
- ret = board_usb_init(index, USB_INIT_HOST);
- if (ret != 0) {
- puts("Failed to initialize board for USB\n");
- return ret;
- }
+ ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
+ ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
ret = zynqmp_xhci_core_init(ctx);
- if (ret < 0) {
- puts("Failed to initialize xhci\n");
- return ret;
+ if (ret) {
+ puts("XHCI: failed to initialize controller\n");
+ return -EINVAL;
}
- *hccr = (struct xhci_hccr *)ctx->hcd;
- hclen = HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase));
- *hcor = (struct xhci_hcor *)((uintptr_t) *hccr + hclen);
+ hcor = (struct xhci_hcor *)((ulong)ctx->hcd +
+ HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)));
- debug("zynqmp-xhci: init hccr %p and hcor %p hc_length %d\n",
- *hccr, *hcor, hclen);
+ return xhci_register(dev, ctx->hcd, hcor);
+}
- return ret;
+static int xhci_usb_remove(struct udevice *dev)
+{
+ return xhci_deregister(dev);
}
-void xhci_hcd_stop(int index)
+static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
{
- /*
- * Currently zynqmp socs do not support PHY shutdown from
- * sw. But this support may be added in future socs.
- */
+ struct zynqmp_xhci_platdata *plat = dev_get_platdata(dev);
+ const void *blob = gd->fdt_blob;
+
+ /* Get the base address for XHCI controller from the device node */
+ plat->hcd_base = fdtdec_get_addr(blob, dev_of_offset(dev), "reg");
+ if (plat->hcd_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the XHCI register base address\n");
+ return -ENXIO;
+ }
- return;
+ return 0;
}
+
+U_BOOT_DRIVER(dwc3_generic_host) = {
+ .name = "dwc3-generic-host",
+ .id = UCLASS_USB,
+ .ofdata_to_platdata = xhci_usb_ofdata_to_platdata,
+ .probe = xhci_usb_probe,
+ .remove = xhci_usb_remove,
+ .ops = &xhci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct zynqmp_xhci_platdata),
+ .priv_auto_alloc_size = sizeof(struct zynqmp_xhci),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 3adb0028f2a..9ded14cc3cb 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -536,7 +536,7 @@ static int xhci_set_configuration(struct usb_device *udev)
/* slot context */
xhci_slot_copy(ctrl, in_ctx, out_ctx);
slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
- slot_ctx->dev_info &= ~(LAST_CTX_MASK);
+ slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK));
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0);
xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0);
@@ -1424,7 +1424,7 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev)
ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
/* Initialize the input context control */
- ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
+ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
ctrl_ctx->drop_flags = 0;
xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
@@ -1435,8 +1435,15 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev)
/* Update hub related fields */
slot_ctx->dev_info |= cpu_to_le32(DEV_HUB);
- if (hub->tt.multi && udev->speed == USB_SPEED_HIGH)
+ /*
+ * refer to section 6.2.2: MTT should be 0 for full speed hub,
+ * but it may be already set to 1 when setup an xHCI virtual
+ * device, so clear it anyway.
+ */
+ if (hub->tt.multi)
slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
+ else if (udev->speed == USB_SPEED_FULL)
+ slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT);
slot_ctx->dev_info2 |= cpu_to_le32(XHCI_MAX_PORTS(udev->maxchild));
/*
* Set TT think time - convert from ns to FS bit times.
@@ -1452,6 +1459,7 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev)
think_time = (think_time / 666) - 1;
if (udev->speed == USB_SPEED_HIGH)
slot_ctx->tt_info |= cpu_to_le32(TT_THINK_TIME(think_time));
+ slot_ctx->dev_state = 0;
return xhci_configure_endpoints(udev, false);
}