diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/dwc2.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/dwc3-sti-glue.c | 28 | ||||
-rw-r--r-- | drivers/usb/host/ehci-generic.c | 20 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 12 | ||||
-rw-r--r-- | drivers/usb/host/ohci-generic.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/usb-sandbox.c | 30 | ||||
-rw-r--r-- | drivers/usb/host/usb-uclass.c | 54 | ||||
-rw-r--r-- | drivers/usb/host/xhci-dwc3.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 24 | ||||
-rw-r--r-- | drivers/usb/host/xhci-rockchip.c | 16 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 264 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 9 |
12 files changed, 402 insertions, 83 deletions
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 64c42ac4715..1293e18f75e 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -179,7 +179,7 @@ static int dwc_vbus_supply_init(struct udevice *dev) ret = regulator_set_enable(vbus_supply, true); if (ret) { - error("Error enabling vbus supply\n"); + pr_err("Error enabling vbus supply\n"); return ret; } @@ -1245,7 +1245,7 @@ static int dwc2_usb_ofdata_to_platdata(struct udevice *dev) struct dwc2_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; priv->regs = (struct dwc2_core_regs *)addr; diff --git a/drivers/usb/host/dwc3-sti-glue.c b/drivers/usb/host/dwc3-sti-glue.c index 02ad3115df4..6dc656af89b 100644 --- a/drivers/usb/host/dwc3-sti-glue.c +++ b/drivers/usb/host/dwc3-sti-glue.c @@ -71,7 +71,7 @@ static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata *plat) break; default: - error("Unsupported mode of operation %d\n", plat->mode); + pr_err("Unsupported mode of operation %d\n", plat->mode); return -EINVAL; } writel(val, plat->syscfg_base + plat->syscfg_offset); @@ -113,7 +113,7 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "reg", reg, ARRAY_SIZE(reg)); if (ret) { - error("unable to find st,stih407-dwc3 reg property(%d)\n", ret); + pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret); return ret; } @@ -124,14 +124,14 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg", &syscon); if (ret) { - error("unable to find syscon device (%d)\n", ret); + pr_err("unable to find syscon device (%d)\n", ret); return ret; } /* get syscfg-reg base address */ regmap = syscon_get_regmap(syscon); if (!regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } plat->syscfg_base = regmap->base; @@ -139,14 +139,14 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) /* get powerdown reset */ ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl); if (ret) { - error("can't get powerdown reset for %s (%d)", dev->name, ret); + pr_err("can't get powerdown reset for %s (%d)", dev->name, ret); return ret; } /* get softreset reset */ ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl); if (ret) - error("can't get soft reset for %s (%d)", dev->name, ret); + pr_err("can't get soft reset for %s (%d)", dev->name, ret); return ret; }; @@ -159,14 +159,14 @@ static int sti_dwc3_glue_bind(struct udevice *dev) /* check if one subnode is present */ dwc3_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev)); if (dwc3_node <= 0) { - error("Can't find subnode for %s\n", dev->name); + pr_err("Can't find subnode for %s\n", dev->name); return -ENODEV; } /* check if the subnode compatible string is the dwc3 one*/ if (fdt_node_check_compatible(gd->fdt_blob, dwc3_node, "snps,dwc3") != 0) { - error("Can't find dwc3 subnode for %s\n", dev->name); + pr_err("Can't find dwc3 subnode for %s\n", dev->name); return -ENODEV; } @@ -187,13 +187,13 @@ static int sti_dwc3_glue_probe(struct udevice *dev) /* deassert both powerdown and softreset */ ret = reset_deassert(&plat->powerdown_ctl); if (ret < 0) { - error("DWC3 powerdown reset deassert failed: %d", ret); + pr_err("DWC3 powerdown reset deassert failed: %d", ret); return ret; } ret = reset_deassert(&plat->softreset_ctl); if (ret < 0) { - error("DWC3 soft reset deassert failed: %d", ret); + pr_err("DWC3 soft reset deassert failed: %d", ret); goto softreset_err; } @@ -208,14 +208,14 @@ static int sti_dwc3_glue_probe(struct udevice *dev) init_err: ret = reset_assert(&plat->softreset_ctl); if (ret < 0) { - error("DWC3 soft reset deassert failed: %d", ret); + pr_err("DWC3 soft reset deassert failed: %d", ret); return ret; } softreset_err: ret = reset_assert(&plat->powerdown_ctl); if (ret < 0) - error("DWC3 powerdown reset deassert failed: %d", ret); + pr_err("DWC3 powerdown reset deassert failed: %d", ret); return ret; } @@ -228,13 +228,13 @@ static int sti_dwc3_glue_remove(struct udevice *dev) /* assert both powerdown and softreset */ ret = reset_assert(&plat->powerdown_ctl); if (ret < 0) { - error("DWC3 powerdown reset deassert failed: %d", ret); + pr_err("DWC3 powerdown reset deassert failed: %d", ret); return ret; } ret = reset_assert(&plat->softreset_ctl); if (ret < 0) - error("DWC3 soft reset deassert failed: %d", ret); + pr_err("DWC3 soft reset deassert failed: %d", ret); return ret; } diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 03f8d321af1..1cb92c03387 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -51,7 +51,7 @@ static int ehci_usb_probe(struct udevice *dev) break; err = clk_enable(&priv->clocks[i]); if (err) { - error("failed to enable clock %d\n", i); + pr_err("failed to enable clock %d\n", i); clk_free(&priv->clocks[i]); goto clk_err; } @@ -59,7 +59,7 @@ static int ehci_usb_probe(struct udevice *dev) } } else { if (clock_nb != -ENOENT) { - error("failed to get clock phandle(%d)\n", clock_nb); + pr_err("failed to get clock phandle(%d)\n", clock_nb); return clock_nb; } } @@ -80,7 +80,7 @@ static int ehci_usb_probe(struct udevice *dev) break; if (reset_deassert(&priv->resets[i])) { - error("failed to deassert reset %d\n", i); + pr_err("failed to deassert reset %d\n", i); reset_free(&priv->resets[i]); goto reset_err; } @@ -88,7 +88,7 @@ static int ehci_usb_probe(struct udevice *dev) } } else { if (reset_nb != -ENOENT) { - error("failed to get reset phandle(%d)\n", reset_nb); + pr_err("failed to get reset phandle(%d)\n", reset_nb); goto clk_err; } } @@ -96,19 +96,19 @@ static int ehci_usb_probe(struct udevice *dev) err = generic_phy_get_by_index(dev, 0, &priv->phy); if (err) { if (err != -ENOENT) { - error("failed to get usb phy\n"); + pr_err("failed to get usb phy\n"); goto reset_err; } } else { err = generic_phy_init(&priv->phy); if (err) { - error("failed to init usb phy\n"); + pr_err("failed to init usb phy\n"); goto reset_err; } } - hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); + hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); @@ -122,17 +122,17 @@ phy_err: if (generic_phy_valid(&priv->phy)) { ret = generic_phy_exit(&priv->phy); if (ret) - error("failed to release phy\n"); + pr_err("failed to release phy\n"); } reset_err: ret = reset_release_all(priv->resets, priv->reset_count); if (ret) - error("failed to assert all resets\n"); + pr_err("failed to assert all resets\n"); clk_err: ret = clk_release_all(priv->clocks, priv->clock_count); if (ret) - error("failed to disable all clocks\n"); + pr_err("failed to disable all clocks\n"); return err; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 3243c1d1cf2..be3e842dcc3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1596,6 +1596,17 @@ static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev, return _ehci_destroy_int_queue(udev, queue); } +static int ehci_get_max_xfer_size(struct udevice *dev, size_t *size) +{ + /* + * EHCD can handle any transfer length as long as there is enough + * free heap space left, hence set the theoretical max number here. + */ + *size = SIZE_MAX; + + return 0; +} + int ehci_register(struct udevice *dev, struct ehci_hccr *hccr, struct ehci_hcor *hcor, const struct ehci_ops *ops, uint tweaks, enum usb_init_type init) @@ -1658,6 +1669,7 @@ struct dm_usb_ops ehci_usb_ops = { .create_int_queue = ehci_create_int_queue, .poll_int_queue = ehci_poll_int_queue, .destroy_int_queue = ehci_destroy_int_queue, + .get_max_xfer_size = ehci_get_max_xfer_size, }; #endif diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index e22ee979391..bf55a71d66c 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -47,14 +47,14 @@ static int ohci_usb_probe(struct udevice *dev) err = clk_enable(&priv->clocks[i]); if (err) { - error("failed to enable clock %d\n", i); + pr_err("failed to enable clock %d\n", i); clk_free(&priv->clocks[i]); goto clk_err; } priv->clock_count++; } } else if (clock_nb != -ENOENT) { - error("failed to get clock phandle(%d)\n", clock_nb); + pr_err("failed to get clock phandle(%d)\n", clock_nb); return clock_nb; } @@ -74,28 +74,28 @@ static int ohci_usb_probe(struct udevice *dev) err = reset_deassert(&priv->resets[i]); if (err) { - error("failed to deassert reset %d\n", i); + pr_err("failed to deassert reset %d\n", i); reset_free(&priv->resets[i]); goto reset_err; } priv->reset_count++; } } else if (reset_nb != -ENOENT) { - error("failed to get reset phandle(%d)\n", reset_nb); + pr_err("failed to get reset phandle(%d)\n", reset_nb); goto clk_err; } err = generic_phy_get_by_index(dev, 0, &priv->phy); if (err) { if (err != -ENOENT) { - error("failed to get usb phy\n"); + pr_err("failed to get usb phy\n"); goto reset_err; } } else { err = generic_phy_init(&priv->phy); if (err) { - error("failed to init usb phy\n"); + pr_err("failed to init usb phy\n"); goto reset_err; } } @@ -110,17 +110,17 @@ phy_err: if (generic_phy_valid(&priv->phy)) { ret = generic_phy_exit(&priv->phy); if (ret) - error("failed to release phy\n"); + pr_err("failed to release phy\n"); } reset_err: ret = reset_release_all(priv->resets, priv->reset_count); if (ret) - error("failed to assert all resets\n"); + pr_err("failed to assert all resets\n"); clk_err: ret = clk_release_all(priv->clocks, priv->clock_count); if (ret) - error("failed to disable all clocks\n"); + pr_err("failed to disable all clocks\n"); return err; } diff --git a/drivers/usb/host/usb-sandbox.c b/drivers/usb/host/usb-sandbox.c index 5e3d96c208e..15055b351a5 100644 --- a/drivers/usb/host/usb-sandbox.c +++ b/drivers/usb/host/usb-sandbox.c @@ -12,6 +12,10 @@ DECLARE_GLOBAL_DATA_PTR; +struct sandbox_usb_ctrl { + int rootdev; +}; + static void usbmon_trace(struct udevice *bus, ulong pipe, struct devrequest *setup, struct udevice *emul) { @@ -40,15 +44,24 @@ static int sandbox_submit_control(struct udevice *bus, void *buffer, int length, struct devrequest *setup) { + struct sandbox_usb_ctrl *ctrl = dev_get_priv(bus); struct udevice *emul; int ret; /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, setup, emul); if (ret) return ret; + + if (usb_pipedevice(pipe) == ctrl->rootdev) { + if (setup->request == USB_REQ_SET_ADDRESS) { + debug("%s: Set root hub's USB address\n", __func__); + ctrl->rootdev = le16_to_cpu(setup->value); + } + } + ret = usb_emul_control(emul, udev, pipe, buffer, length, setup); if (ret < 0) { debug("ret=%d\n", ret); @@ -70,7 +83,7 @@ static int sandbox_submit_bulk(struct udevice *bus, struct usb_device *udev, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, NULL, emul); if (ret) return ret; @@ -96,7 +109,7 @@ static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, NULL, emul); if (ret) return ret; @@ -107,6 +120,16 @@ static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev, static int sandbox_alloc_device(struct udevice *dev, struct usb_device *udev) { + struct sandbox_usb_ctrl *ctrl = dev_get_priv(dev); + + /* + * Root hub will be the first device to be initailized. + * If this device is a root hub, initialize its device speed + * to high speed as we are a USB 2.0 controller. + */ + if (ctrl->rootdev == 0) + udev->speed = USB_SPEED_HIGH; + return 0; } @@ -133,4 +156,5 @@ U_BOOT_DRIVER(usb_sandbox) = { .of_match = sandbox_usb_ids, .probe = sandbox_usb_probe, .ops = &sandbox_usb_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_usb_ctrl), }; diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 0b8a501ce88..4e40f4bc3d2 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -150,9 +150,21 @@ int usb_update_hub_device(struct usb_device *udev) return ops->update_hub_device(bus, udev); } +int usb_get_max_xfer_size(struct usb_device *udev, size_t *size) +{ + struct udevice *bus = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(bus); + + if (!ops->get_max_xfer_size) + return -ENOSYS; + + return ops->get_max_xfer_size(bus, size); +} + int usb_stop(void) { struct udevice *bus; + struct udevice *rh; struct uclass *uc; struct usb_uclass_priv *uc_priv; int err = 0, ret; @@ -168,23 +180,20 @@ int usb_stop(void) ret = device_remove(bus, DM_REMOVE_NORMAL); if (ret && !err) err = ret; - } -#ifdef CONFIG_BLK - ret = blk_unbind_all(IF_TYPE_USB); - if (ret && !err) - err = ret; -#endif -#ifdef CONFIG_SANDBOX - struct udevice *dev; - /* Reset all enulation devices */ - ret = uclass_get(UCLASS_USB_EMUL, &uc); - if (ret) - return ret; + /* Locate root hub device */ + device_find_first_child(bus, &rh); + if (rh) { + /* + * All USB devices are children of root hub. + * Unbinding root hub will unbind all of its children. + */ + ret = device_unbind(rh); + if (ret && !err) + err = ret; + } + } - uclass_foreach_dev(dev, uc) - usb_emul_reset(dev); -#endif #ifdef CONFIG_USB_STORAGE usb_stor_reset(); #endif @@ -251,6 +260,21 @@ int usb_init(void) /* init low_level USB */ printf("USB%d: ", count); count++; + +#ifdef CONFIG_SANDBOX + /* + * For Sandbox, we need scan the device tree each time when we + * start the USB stack, in order to re-create the emulated USB + * devices and bind drivers for them before we actually do the + * driver probe. + */ + ret = dm_scan_fdt_dev(bus); + if (ret) { + printf("Sandbox USB device scan failed (%d)\n", ret); + continue; + } +#endif + ret = device_probe(bus); if (ret == -ENODEV) { /* No such device. */ puts("Port not available.\n"); diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 4191a894218..258d1cd00a0 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -128,13 +128,13 @@ static int xhci_dwc3_probe(struct udevice *dev) ret = generic_phy_get_by_index(dev, 0, &plat->usb_phy); if (ret) { if (ret != -ENOENT) { - error("Failed to get USB PHY for %s\n", dev->name); + pr_err("Failed to get USB PHY for %s\n", dev->name); return ret; } } else { ret = generic_phy_init(&plat->usb_phy); if (ret) { - error("Can't init USB PHY for %s\n", dev->name); + pr_err("Can't init USB PHY for %s\n", dev->name); return ret; } } @@ -161,7 +161,7 @@ static int xhci_dwc3_remove(struct udevice *dev) if (generic_phy_valid(&plat->usb_phy)) { ret = generic_phy_exit(&plat->usb_phy); if (ret) { - error("Can't deinit USB PHY for %s\n", dev->name); + pr_err("Can't deinit USB PHY for %s\n", dev->name); return ret; } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d5eab3a6154..0582a9be40a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -786,12 +786,22 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, #ifdef CONFIG_DM_USB /* Set up TT fields to support FS/LS devices */ if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) { - dev = dev_get_parent_priv(udev->dev); - if (dev->speed == USB_SPEED_HIGH) { - hub = dev_get_uclass_priv(udev->dev); + struct udevice *parent = udev->dev; + + dev = udev; + do { + port_num = dev->portnr; + dev = dev_get_parent_priv(parent); + if (usb_hub_is_root_hub(dev->dev)) + break; + parent = dev->dev->parent; + } while (dev->speed != USB_SPEED_HIGH); + + if (!usb_hub_is_root_hub(dev->dev)) { + hub = dev_get_uclass_priv(dev->dev); if (hub->tt.multi) slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); - slot_ctx->tt_info |= cpu_to_le32(TT_PORT(udev->portnr)); + slot_ctx->tt_info |= cpu_to_le32(TT_PORT(port_num)); slot_ctx->tt_info |= cpu_to_le32(TT_SLOT(dev->slot_id)); } } @@ -840,6 +850,12 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, trb_64 = (uintptr_t)virt_dev->eps[0].ring->first_seg->trbs; ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state); + /* + * xHCI spec 6.2.3: + * software shall set 'Average TRB Length' to 8 for control endpoints. + */ + ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8)); + /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ xhci_flush_cache((uintptr_t)ep0_ctx, sizeof(struct xhci_ep_ctx)); diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c index ec55f4e59f7..b1f98842739 100644 --- a/drivers/usb/host/xhci-rockchip.c +++ b/drivers/usb/host/xhci-rockchip.c @@ -6,8 +6,6 @@ */ #include <common.h> #include <dm.h> -#include <fdtdec.h> -#include <libfdt.h> #include <malloc.h> #include <usb.h> #include <watchdog.h> @@ -46,9 +44,9 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - plat->hcd_base = devfdt_get_addr(dev); + plat->hcd_base = dev_read_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { - error("Can't get the XHCI register base address\n"); + pr_err("Can't get the XHCI register base address\n"); return -ENXIO; } @@ -62,7 +60,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) } if (plat->phy_base == FDT_ADDR_T_NONE) { - error("Can't get the usbphy register address\n"); + pr_err("Can't get the usbphy register address\n"); return -ENXIO; } @@ -119,7 +117,7 @@ static int rockchip_xhci_core_init(struct rockchip_xhci *rkxhci, ret = dwc3_core_init(rkxhci->dwc3_reg); if (ret) { - error("failed to initialize core\n"); + pr_err("failed to initialize core\n"); return ret; } @@ -151,14 +149,14 @@ static int xhci_usb_probe(struct udevice *dev) if (plat->vbus_supply) { ret = regulator_set_enable(plat->vbus_supply, true); if (ret) { - error("XHCI: failed to set VBus supply\n"); + pr_err("XHCI: failed to set VBus supply\n"); return ret; } } ret = rockchip_xhci_core_init(ctx, dev); if (ret) { - error("XHCI: failed to initialize controller\n"); + pr_err("XHCI: failed to initialize controller\n"); return ret; } @@ -181,7 +179,7 @@ static int xhci_usb_remove(struct udevice *dev) if (plat->vbus_supply) { ret = regulator_set_enable(plat->vbus_supply, false); if (ret) - error("XHCI: failed to set VBus supply\n"); + pr_err("XHCI: failed to set VBus supply\n"); } return ret; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9b82ee5c602..4673738d1e8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -257,6 +257,188 @@ static unsigned int xhci_get_ep_index(struct usb_endpoint_descriptor *desc) return index; } +/* + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of + * microframes, rounded down to nearest power of 2. + */ +static unsigned int xhci_microframes_to_exponent(unsigned int desc_interval, + unsigned int min_exponent, + unsigned int max_exponent) +{ + unsigned int interval; + + interval = fls(desc_interval) - 1; + interval = clamp_val(interval, min_exponent, max_exponent); + if ((1 << interval) != desc_interval) + debug("rounding interval to %d microframes, "\ + "ep desc says %d microframes\n", + 1 << interval, desc_interval); + + return interval; +} + +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + if (endpt_desc->bInterval == 0) + return 0; + + return xhci_microframes_to_exponent(endpt_desc->bInterval, 0, 15); +} + +static unsigned int xhci_parse_frame_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + return xhci_microframes_to_exponent(endpt_desc->bInterval * 8, 3, 10); +} + +/* + * Convert interval expressed as 2^(bInterval - 1) == interval into + * straight exponent value 2^n == interval. + */ +static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + unsigned int interval; + + interval = clamp_val(endpt_desc->bInterval, 1, 16) - 1; + if (interval != endpt_desc->bInterval - 1) + debug("ep %#x - rounding interval to %d %sframes\n", + endpt_desc->bEndpointAddress, 1 << interval, + udev->speed == USB_SPEED_FULL ? "" : "micro"); + + if (udev->speed == USB_SPEED_FULL) { + /* + * Full speed isoc endpoints specify interval in frames, + * not microframes. We are using microframes everywhere, + * so adjust accordingly. + */ + interval += 3; /* 1 frame = 2^3 uframes */ + } + + return interval; +} + +/* + * Return the polling or NAK interval. + * + * The polling interval is expressed in "microframes". If xHCI's Interval field + * is set to N, it will service the endpoint every 2^(Interval)*125us. + * + * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval + * is set to 0. + */ +static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + unsigned int interval = 0; + + switch (udev->speed) { + case USB_SPEED_HIGH: + /* Max NAK rate */ + if (usb_endpoint_xfer_control(endpt_desc) || + usb_endpoint_xfer_bulk(endpt_desc)) { + interval = xhci_parse_microframe_interval(udev, + endpt_desc); + break; + } + /* Fall through - SS and HS isoc/int have same decoding */ + + case USB_SPEED_SUPER: + if (usb_endpoint_xfer_int(endpt_desc) || + usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_exponent_interval(udev, + endpt_desc); + } + break; + + case USB_SPEED_FULL: + if (usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_exponent_interval(udev, + endpt_desc); + break; + } + /* + * Fall through for interrupt endpoint interval decoding + * since it uses the same rules as low speed interrupt + * endpoints. + */ + + case USB_SPEED_LOW: + if (usb_endpoint_xfer_int(endpt_desc) || + usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_frame_interval(udev, endpt_desc); + } + break; + + default: + BUG(); + } + + return interval; +} + +/* + * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. + * High speed endpoint descriptors can define "the number of additional + * transaction opportunities per microframe", but that goes in the Max Burst + * endpoint context field. + */ +static u32 xhci_get_endpoint_mult(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + if (udev->speed < USB_SPEED_SUPER || + !usb_endpoint_xfer_isoc(endpt_desc)) + return 0; + + return ss_ep_comp_desc->bmAttributes; +} + +static u32 xhci_get_endpoint_max_burst(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + /* Super speed and Plus have max burst in ep companion desc */ + if (udev->speed >= USB_SPEED_SUPER) + return ss_ep_comp_desc->bMaxBurst; + + if (udev->speed == USB_SPEED_HIGH && + (usb_endpoint_xfer_isoc(endpt_desc) || + usb_endpoint_xfer_int(endpt_desc))) + return usb_endpoint_maxp_mult(endpt_desc) - 1; + + return 0; +} + +/* + * Return the maximum endpoint service interval time (ESIT) payload. + * Basically, this is the maxpacket size, multiplied by the burst size + * and mult size. + */ +static u32 xhci_get_max_esit_payload(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + int max_burst; + int max_packet; + + /* Only applies for interrupt or isochronous endpoints */ + if (usb_endpoint_xfer_control(endpt_desc) || + usb_endpoint_xfer_bulk(endpt_desc)) + return 0; + + /* SuperSpeed Isoc ep with less than 48k per esit */ + if (udev->speed >= USB_SPEED_SUPER) + return le16_to_cpu(ss_ep_comp_desc->wBytesPerInterval); + + max_packet = usb_endpoint_maxp(endpt_desc); + max_burst = usb_endpoint_maxp_mult(endpt_desc); + + /* A 0 in max burst means 1 transfer per ESIT */ + return max_packet * max_burst; +} + /** * Issue a configure endpoint command or evaluate context command * and wait for it to finish. @@ -324,6 +506,12 @@ static int xhci_set_configuration(struct usb_device *udev) int slot_id = udev->slot_id; struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; struct usb_interface *ifdesc; + u32 max_esit_payload; + unsigned int interval; + unsigned int mult; + unsigned int max_burst; + unsigned int avg_trb_len; + unsigned int err_count = 0; out_ctx = virt_dev->out_ctx; in_ctx = virt_dev->in_ctx; @@ -357,10 +545,28 @@ static int xhci_set_configuration(struct usb_device *udev) /* filling up ep contexts */ for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { struct usb_endpoint_descriptor *endpt_desc = NULL; + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL; endpt_desc = &ifdesc->ep_desc[cur_ep]; + ss_ep_comp_desc = &ifdesc->ss_ep_comp_desc[cur_ep]; trb_64 = 0; + /* + * Get values to fill the endpoint context, mostly from ep + * descriptor. The average TRB buffer lengt for bulk endpoints + * is unclear as we have no clue on scatter gather list entry + * size. For Isoc and Int, set it to max available. + * See xHCI 1.1 spec 4.14.1.1 for details. + */ + max_esit_payload = xhci_get_max_esit_payload(udev, endpt_desc, + ss_ep_comp_desc); + interval = xhci_get_endpoint_interval(udev, endpt_desc); + mult = xhci_get_endpoint_mult(udev, endpt_desc, + ss_ep_comp_desc); + max_burst = xhci_get_endpoint_max_burst(udev, endpt_desc, + ss_ep_comp_desc); + avg_trb_len = max_esit_payload; + ep_index = xhci_get_ep_index(endpt_desc); ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); @@ -372,20 +578,38 @@ static int xhci_set_configuration(struct usb_device *udev) /*NOTE: ep_desc[0] actually represents EP1 and so on */ dir = (((endpt_desc->bEndpointAddress) & (0x80)) >> 7); ep_type = (((endpt_desc->bmAttributes) & (0x3)) | (dir << 2)); + + ep_ctx[ep_index]->ep_info = + cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | + EP_INTERVAL(interval) | EP_MULT(mult)); + ep_ctx[ep_index]->ep_info2 = cpu_to_le32(ep_type << EP_TYPE_SHIFT); ep_ctx[ep_index]->ep_info2 |= cpu_to_le32(MAX_PACKET (get_unaligned(&endpt_desc->wMaxPacketSize))); + /* Allow 3 retries for everything but isoc, set CErr = 3 */ + if (!usb_endpoint_xfer_isoc(endpt_desc)) + err_count = 3; ep_ctx[ep_index]->ep_info2 |= - cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) | - ((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT)); + cpu_to_le32(MAX_BURST(max_burst) | + ERROR_COUNT(err_count)); trb_64 = (uintptr_t) virt_dev->eps[ep_index].ring->enqueue; ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 | virt_dev->eps[ep_index].ring->cycle_state); + + /* + * xHCI spec 6.2.3: + * 'Average TRB Length' should be 8 for control endpoints. + */ + if (usb_endpoint_xfer_control(endpt_desc)) + avg_trb_len = 8; + ep_ctx[ep_index]->tx_info = + cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) | + EP_AVG_TRB_LENGTH(avg_trb_len)); } return xhci_configure_endpoints(udev, false); @@ -546,16 +770,13 @@ int xhci_check_maxpacket(struct usb_device *udev) int max_packet_size; int hw_max_packet_size; int ret = 0; - struct usb_interface *ifdesc; - - ifdesc = &udev->config.if_desc[0]; out_ctx = ctrl->devs[slot_id]->out_ctx; xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); ep_ctx = xhci_get_ep_ctx(ctrl, out_ctx, ep_index); hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); - max_packet_size = usb_endpoint_maxp(&ifdesc->ep_desc[0]); + max_packet_size = udev->epmaxpacketin[0]; if (hw_max_packet_size != max_packet_size) { debug("Max Packet Size for ep 0 changed.\n"); debug("Max packet size in usb_device = %d\n", max_packet_size); @@ -567,7 +788,8 @@ int xhci_check_maxpacket(struct usb_device *udev) ctrl->devs[slot_id]->out_ctx, ep_index); in_ctx = ctrl->devs[slot_id]->in_ctx; ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); - ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK); + ep_ctx->ep_info2 &= cpu_to_le32(~((0xffff & MAX_PACKET_MASK) + << MAX_PACKET_SHIFT)); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); /* @@ -890,11 +1112,18 @@ unknown: static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, int length, int interval) { + if (usb_pipetype(pipe) != PIPE_INTERRUPT) { + printf("non-interrupt pipe (type=%lu)", usb_pipetype(pipe)); + return -EINVAL; + } + /* - * TODO: Not addressing any interrupt type transfer requests - * Add support for it later. + * xHCI uses normal TRBs for both bulk and interrupt. When the + * interrupt endpoint is to be serviced, the xHC will consume + * (at most) one TD. A TD (comprised of sg list entries) can + * take several service intervals to transmit. */ - return -EINVAL; + return xhci_bulk_tx(udev, pipe, length, buffer); } /** @@ -1228,6 +1457,20 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev) return xhci_configure_endpoints(udev, false); } +static int xhci_get_max_xfer_size(struct udevice *dev, size_t *size) +{ + /* + * xHCD allocates one segment which includes 64 TRBs for each endpoint + * and the last TRB in this segment is configured as a link TRB to form + * a TRB ring. Each TRB can transfer up to 64K bytes, however data + * buffers referenced by transfer TRBs shall not span 64KB boundaries. + * Hence the maximum number of TRBs we can use in one transfer is 62. + */ + *size = (TRBS_PER_SEGMENT - 2) * TRB_MAX_BUFF_SIZE; + + return 0; +} + int xhci_register(struct udevice *dev, struct xhci_hccr *hccr, struct xhci_hcor *hcor) { @@ -1281,6 +1524,7 @@ struct dm_usb_ops xhci_usb_ops = { .interrupt = xhci_submit_int_msg, .alloc_device = xhci_alloc_device, .update_hub_device = xhci_update_hub_device, + .get_max_xfer_size = xhci_get_max_xfer_size, }; #endif diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a497d9d830f..ba5f650144f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -663,8 +663,9 @@ struct xhci_ep_ctx { #define GET_MAX_PACKET(p) ((p) & 0x7ff) /* tx_info bitmasks */ -#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff) -#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16) +#define EP_AVG_TRB_LENGTH(p) ((p) & 0xffff) +#define EP_MAX_ESIT_PAYLOAD_LO(p) (((p) & 0xffff) << 16) +#define EP_MAX_ESIT_PAYLOAD_HI(p) ((((p) >> 16) & 0xff) << 24) #define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff) /* deq bitmasks */ @@ -1045,9 +1046,9 @@ struct xhci_scratchpad { * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, * meaning 64 ring segments. * Initial allocated size of the ERST, in number of entries */ -#define ERST_NUM_SEGS 3 +#define ERST_NUM_SEGS 1 /* Initial number of event segment rings allocated */ -#define ERST_ENTRIES 3 +#define ERST_ENTRIES 1 /* Initial allocated size of the ERST, in number of entries */ #define ERST_SIZE 64 /* Poll every 60 seconds */ |