summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig8
-rw-r--r--drivers/usb/host/Makefile7
-rw-r--r--drivers/usb/host/ehci-tegra.c136
-rw-r--r--drivers/usb/host/xhci-generic.c75
-rw-r--r--drivers/usb/host/xhci-ring.c3
5 files changed, 204 insertions, 25 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 6e10b629a3c..bb5893d56db 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -68,6 +68,14 @@ config USB_XHCI_MVEBU
SoCs, which includes Armada8K, Armada3700 and other Armada
family SoCs.
+config USB_XHCI_GENERIC
+ bool "Generic SoC USB 3.0 support"
+ depends on OF_CONTROL
+ default n
+ help
+ Choose this option to add support for USB 3.0 driver for SoCs
+ that do not need platform specific code, like on emulated targets.
+
config USB_XHCI_OCTEON
bool "Support for Marvell Octeon family on-chip xHCI USB controller"
depends on ARCH_OCTEON
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 8dad36f9369..301bb9fdee1 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -3,13 +3,13 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-ifdef CONFIG_$(SPL_)DM_USB
+ifdef CONFIG_$(XPL_)DM_USB
obj-y += usb-uclass.o
obj-$(CONFIG_SANDBOX) += usb-sandbox.o
endif
-ifdef CONFIG_$(SPL_TPL_)USB_STORAGE
-obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += usb_bootdev.o
+ifdef CONFIG_$(PHASE_)USB_STORAGE
+obj-$(CONFIG_$(PHASE_)BOOTSTD) += usb_bootdev.o
endif
# ohci
@@ -50,6 +50,7 @@ obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o
obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
+obj-$(CONFIG_USB_XHCI_GENERIC) += xhci-generic.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
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 343893b9f19..7c73eb66b60 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -66,9 +66,24 @@ enum usb_ctlr_type {
USB_CTRL_COUNT,
};
+struct tegra_utmip_config {
+ u32 hssync_start_delay;
+ u32 elastic_limit;
+ u32 idle_wait_delay;
+ u32 term_range_adj;
+ bool xcvr_setup_use_fuses;
+ u32 xcvr_setup;
+ u32 xcvr_lsfslew;
+ u32 xcvr_lsrslew;
+ u32 xcvr_hsslew;
+ u32 hssquelch_level;
+ u32 hsdiscon_level;
+};
+
/* Information about a USB port */
struct fdt_usb {
struct ehci_ctrl ehci;
+ struct tegra_utmip_config utmip_config;
struct usb_ctlr *reg; /* address of registers in physical memory */
unsigned utmi:1; /* 1 if port has external tranceiver, else 0 */
unsigned ulpi:1; /* 1 if port has external ULPI transceiver */
@@ -192,15 +207,6 @@ static const unsigned T210_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
{ 0x028, 0x01, 0x01, 0x0, 0, 0x02, 0x2F, 0x08, 0x76, 65000, 5 }
};
-/* UTMIP Idle Wait Delay */
-static const u8 utmip_idle_wait_delay = 17;
-
-/* UTMIP Elastic limit */
-static const u8 utmip_elastic_limit = 16;
-
-/* UTMIP High Speed Sync Start Delay */
-static const u8 utmip_hs_sync_start_delay = 9;
-
struct fdt_usb_controller {
/* flag to determine whether controller supports hostpc register */
u32 has_hostpc:1;
@@ -377,6 +383,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
u32 b_sess_valid_mask, val;
int loop_count;
const unsigned *timing;
+ struct tegra_utmip_config *utmip_config = &config->utmip_config;
struct usb_ctlr *usbctlr = config->reg;
struct clk_rst_ctlr *clkrst;
struct usb_ctlr *usb1ctlr;
@@ -463,16 +470,29 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
/* Recommended PHY settings for EYE diagram */
val = readl(&usbctlr->utmip_xcvr_cfg0);
- clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MASK,
- 0x4 << UTMIP_XCVR_SETUP_SHIFT);
- clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB_MASK,
- 0x3 << UTMIP_XCVR_SETUP_MSB_SHIFT);
- clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB_MASK,
- 0x8 << UTMIP_XCVR_HSSLEW_MSB_SHIFT);
+
+ if (!utmip_config->xcvr_setup_use_fuses) {
+ clrsetbits_le32(&val, UTMIP_XCVR_SETUP(~0),
+ UTMIP_XCVR_SETUP(utmip_config->xcvr_setup));
+ clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB(~0),
+ UTMIP_XCVR_SETUP_MSB(utmip_config->xcvr_setup));
+ }
+
+ clrsetbits_le32(&val, UTMIP_XCVR_LSFSLEW(~0),
+ UTMIP_XCVR_LSFSLEW(utmip_config->xcvr_lsfslew));
+ clrsetbits_le32(&val, UTMIP_XCVR_LSRSLEW(~0),
+ UTMIP_XCVR_LSRSLEW(utmip_config->xcvr_lsrslew));
+
+ clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW(~0),
+ UTMIP_XCVR_HSSLEW(utmip_config->xcvr_hsslew));
+ clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB(~0),
+ UTMIP_XCVR_HSSLEW_MSB(utmip_config->xcvr_hsslew));
writel(val, &usbctlr->utmip_xcvr_cfg0);
+
clrsetbits_le32(&usbctlr->utmip_xcvr_cfg1,
UTMIP_XCVR_TERM_RANGE_ADJ_MASK,
- 0x7 << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT);
+ utmip_config->term_range_adj <<
+ UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT);
/* Some registers can be controlled from USB1 only. */
if (config->periph_id != PERIPH_ID_USBD) {
@@ -485,9 +505,11 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
val = readl(&usb1ctlr->utmip_bias_cfg0);
setbits_le32(&val, UTMIP_HSDISCON_LEVEL_MSB);
clrsetbits_le32(&val, UTMIP_HSDISCON_LEVEL_MASK,
- 0x1 << UTMIP_HSDISCON_LEVEL_SHIFT);
+ utmip_config->hsdiscon_level <<
+ UTMIP_HSDISCON_LEVEL_SHIFT);
clrsetbits_le32(&val, UTMIP_HSSQUELCH_LEVEL_MASK,
- 0x2 << UTMIP_HSSQUELCH_LEVEL_SHIFT);
+ utmip_config->hssquelch_level <<
+ UTMIP_HSSQUELCH_LEVEL_SHIFT);
writel(val, &usb1ctlr->utmip_bias_cfg0);
/* Miscellaneous setting mentioned in Programming Guide */
@@ -521,7 +543,11 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
setbits_le32(&usbctlr->utmip_bat_chrg_cfg0, UTMIP_PD_CHRG);
clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_XCVR_LSBIAS_SE);
- setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
+
+ if (utmip_config->xcvr_setup_use_fuses)
+ setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
+ else
+ clrbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
/*
* Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT
@@ -535,15 +561,16 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
/* Set PLL enable delay count and Crystal frequency count */
val = readl(&usbctlr->utmip_hsrx_cfg0);
clrsetbits_le32(&val, UTMIP_IDLE_WAIT_MASK,
- utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
+ utmip_config->idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
clrsetbits_le32(&val, UTMIP_ELASTIC_LIMIT_MASK,
- utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
+ utmip_config->elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
writel(val, &usbctlr->utmip_hsrx_cfg0);
/* Configure the UTMIP_HS_SYNC_START_DLY */
clrsetbits_le32(&usbctlr->utmip_hsrx_cfg1,
UTMIP_HS_SYNC_START_DLY_MASK,
- utmip_hs_sync_start_delay << UTMIP_HS_SYNC_START_DLY_SHIFT);
+ utmip_config->hssync_start_delay <<
+ UTMIP_HS_SYNC_START_DLY_SHIFT);
/* Preceed the crystal clock disable by >100ns delay. */
udelay(1);
@@ -763,6 +790,69 @@ static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config)
return 0;
}
+static void fdt_decode_usb_phy(struct udevice *dev)
+{
+ struct fdt_usb *priv = dev_get_priv(dev);
+ struct tegra_utmip_config *utmip_config = &priv->utmip_config;
+ u32 usb_phy_phandle;
+ ofnode usb_phy_node;
+ int ret;
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "nvidia,phy", &usb_phy_phandle);
+ if (ret)
+ log_debug("%s: required usb phy node isn't provided\n", __func__);
+
+ usb_phy_node = ofnode_get_by_phandle(usb_phy_phandle);
+ if (!ofnode_valid(usb_phy_node) || !ofnode_is_enabled(usb_phy_node)) {
+ log_debug("%s: failed to find usb phy node or it is disabled\n", __func__);
+ utmip_config->xcvr_setup_use_fuses = true;
+ } else {
+ utmip_config->xcvr_setup_use_fuses =
+ ofnode_read_bool(usb_phy_node, "nvidia,xcvr-setup-use-fuses");
+ }
+
+ utmip_config->hssync_start_delay =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,hssync-start-delay", 0x9);
+
+ utmip_config->elastic_limit =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,elastic-limit", 0x10);
+
+ utmip_config->idle_wait_delay =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,idle-wait-delay", 0x11);
+
+ utmip_config->term_range_adj =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,term-range-adj", 0x7);
+
+ utmip_config->xcvr_lsfslew =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,xcvr-lsfslew", 0x0);
+
+ utmip_config->xcvr_lsrslew =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,xcvr-lsrslew", 0x3);
+
+ utmip_config->xcvr_hsslew =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,xcvr-hsslew", 0x8);
+
+ utmip_config->hssquelch_level =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,hssquelch-level", 0x2);
+
+ utmip_config->hsdiscon_level =
+ ofnode_read_u32_default(usb_phy_node,
+ "nvidia,hsdiscon-level", 0x1);
+
+ if (!utmip_config->xcvr_setup_use_fuses) {
+ ofnode_read_u32(usb_phy_node, "nvidia,xcvr-setup",
+ &utmip_config->xcvr_setup);
+ }
+}
+
int usb_common_init(struct fdt_usb *config, enum usb_init_type init)
{
int ret = 0;
@@ -850,6 +940,8 @@ static int ehci_usb_of_to_plat(struct udevice *dev)
priv->type = dev_get_driver_data(dev);
+ fdt_decode_usb_phy(dev);
+
return 0;
}
diff --git a/drivers/usb/host/xhci-generic.c b/drivers/usb/host/xhci-generic.c
new file mode 100644
index 00000000000..355d4883176
--- /dev/null
+++ b/drivers/usb/host/xhci-generic.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 9elements GmbH
+ *
+ * GENERIC USB HOST xHCI Controller
+ */
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <usb/xhci.h>
+
+struct generic_xhci_plat {
+ fdt_addr_t hcd_base;
+};
+
+/**
+ * Contains pointers to register base addresses
+ * for the usb controller.
+ */
+struct generic_xhci {
+ struct xhci_ctrl ctrl; /* Needs to come first in this struct! */
+ struct usb_plat usb_plat;
+ struct xhci_hccr *hcd;
+};
+
+static int xhci_usb_probe(struct udevice *dev)
+{
+ struct generic_xhci_plat *plat = dev_get_plat(dev);
+ struct generic_xhci *ctx = dev_get_priv(dev);
+ struct xhci_hcor *hcor;
+ int len;
+
+ ctx->hcd = (struct xhci_hccr *)phys_to_virt(plat->hcd_base);
+ len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
+ hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
+
+ return xhci_register(dev, ctx->hcd, hcor);
+}
+
+static int xhci_usb_of_to_plat(struct udevice *dev)
+{
+ struct generic_xhci_plat *plat = dev_get_plat(dev);
+
+ /*
+ * Get the base address for XHCI controller from the device node
+ */
+ plat->hcd_base = dev_read_addr(dev);
+ if (plat->hcd_base == FDT_ADDR_T_NONE) {
+ dev_dbg(dev, "Can't get the XHCI register base address\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+ { .compatible = "generic-xhci" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+ .name = "xhci_generic",
+ .id = UCLASS_USB,
+ .of_match = xhci_usb_ids,
+ .of_to_plat = xhci_usb_of_to_plat,
+ .probe = xhci_usb_probe,
+ .remove = xhci_deregister,
+ .ops = &xhci_usb_ops,
+ .plat_auto = sizeof(struct generic_xhci_plat),
+ .priv_auto = sizeof(struct generic_xhci),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 68cf08e0b6b..34eb4536f0e 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -17,6 +17,7 @@
#include <log.h>
#include <asm/byteorder.h>
#include <usb.h>
+#include <watchdog.h>
#include <asm/unaligned.h>
#include <linux/bug.h>
#include <linux/errno.h>
@@ -796,6 +797,8 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
/* Calculate length for next transfer */
addr += trb_buff_len;
trb_buff_len = min((length - running_total), TRB_MAX_BUFF_SIZE);
+
+ schedule();
} while (running_total < length);
giveback_first_trb(udev, ep_index, start_cycle, start_trb);