From 121a4d13e679d86bf55bb3941eb33b10fa8c785b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Jun 2017 16:35:14 +0900 Subject: [PATCH 01/61] usb: add static to local symbols Sparse reports "... was not declared. Should it be static?" Signed-off-by: Masahiro Yamada --- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/usb-uclass.c | 18 +++++++++--------- drivers/usb/host/xhci-dwc3.c | 2 +- drivers/usb/host/xhci.c | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 13aa70d606..f08709d021 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -937,7 +937,7 @@ unknown: return -1; } -const struct ehci_ops default_ehci_ops = { +static const struct ehci_ops default_ehci_ops = { .set_usb_mode = ehci_set_usbmode, .get_port_speed = ehci_get_port_speed, .powerup_fixup = ehci_powerup_fixup, diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 110ddc92fa..efc5d4e7d7 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -373,8 +373,8 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) } /* returns 0 if no match, 1 if match */ -int usb_match_device(const struct usb_device_descriptor *desc, - const struct usb_device_id *id) +static int usb_match_device(const struct usb_device_descriptor *desc, + const struct usb_device_id *id) { if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && id->idVendor != le16_to_cpu(desc->idVendor)) @@ -410,9 +410,9 @@ int usb_match_device(const struct usb_device_descriptor *desc, } /* returns 0 if no match, 1 if match */ -int usb_match_one_id_intf(const struct usb_device_descriptor *desc, - const struct usb_interface_descriptor *int_desc, - const struct usb_device_id *id) +static int usb_match_one_id_intf(const struct usb_device_descriptor *desc, + const struct usb_interface_descriptor *int_desc, + const struct usb_device_id *id) { /* The interface class, subclass, protocol and number should never be * checked for a match if the device class is Vendor Specific, @@ -445,9 +445,9 @@ int usb_match_one_id_intf(const struct usb_device_descriptor *desc, } /* returns 0 if no match, 1 if match */ -int usb_match_one_id(struct usb_device_descriptor *desc, - struct usb_interface_descriptor *int_desc, - const struct usb_device_id *id) +static int usb_match_one_id(struct usb_device_descriptor *desc, + struct usb_interface_descriptor *int_desc, + const struct usb_device_id *id) { if (!usb_match_device(desc, id)) return 0; @@ -680,7 +680,7 @@ int usb_detect_change(void) return change; } -int usb_child_post_bind(struct udevice *dev) +static int usb_child_post_bind(struct udevice *dev) { struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); int val; diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd634..a4591f2e02 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -19,7 +19,7 @@ void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) DWC3_GCTL_PRTCAPDIR(mode)); } -void dwc3_phy_reset(struct dwc3 *dwc3_reg) +static void dwc3_phy_reset(struct dwc3 *dwc3_reg) { /* Assert USB3 PHY reset */ setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3201177476..bd8f4c43b4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -192,7 +192,7 @@ static int xhci_start(struct xhci_hcor *hcor) * @param hcor pointer to host controller operation registers * @return -EBUSY if XHCI Controller is not halted else status of handshake */ -int xhci_reset(struct xhci_hcor *hcor) +static int xhci_reset(struct xhci_hcor *hcor) { u32 cmd; u32 state; @@ -481,7 +481,7 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr) * @param udev pointer to the Device Data Structure * @return Returns 0 on succes else return error code on failure */ -int _xhci_alloc_device(struct usb_device *udev) +static int _xhci_alloc_device(struct usb_device *udev) { struct xhci_ctrl *ctrl = xhci_get_ctrl(udev); union xhci_trb *event; From b7c1c7d2bad9eb052e80b28af6005d7f0ba1db30 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:38:40 +0200 Subject: [PATCH 02/61] usb: host: xhci-dwc3: Convert driver to DM Add Driver Model support with use of generic DT compatible string "snps,dwc3" Signed-off-by: Patrice Chotard Reviewed-by: Bin Meng --- drivers/usb/host/xhci-dwc3.c | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index a4591f2e02..fb106f328a 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,15 @@ */ #include +#include +#include + +#include "xhci.h" #include #include +DECLARE_GLOBAL_DATA_PTR; + void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl, @@ -97,3 +103,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); } + +static int xhci_dwc3_probe(struct udevice *dev) +{ + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + struct xhci_hcor *hcor; + struct xhci_hccr *hccr; + struct dwc3 *dwc3_reg; + + hccr = (struct xhci_hccr *)devfdt_get_addr(dev); + hcor = (struct xhci_hcor *)((phys_addr_t)hccr + + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); + + dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET); + + dwc3_core_init(dwc3_reg); + + return xhci_register(dev, hccr, hcor); +} + +static int xhci_dwc3_remove(struct udevice *dev) +{ + return xhci_deregister(dev); +} + +static const struct udevice_id xhci_dwc3_ids[] = { + { .compatible = "snps,dwc3" }, + { } +}; + +U_BOOT_DRIVER(xhci_dwc3) = { + .name = "xhci-dwc3", + .id = UCLASS_USB, + .of_match = xhci_dwc3_ids, + .probe = xhci_dwc3_probe, + .remove = xhci_dwc3_remove, + .ops = &xhci_usb_ops, + .priv_auto_alloc_size = sizeof(struct xhci_ctrl), + .platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; From 576e3cc700c598487fed741ee85103373a3f69d6 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:38:41 +0200 Subject: [PATCH 03/61] usb: host: xhci-dwc3: Add dual role mode support from DT DWC3 dual role mode is selected using DT "dr_mode" property. If not found, DWC3 controller is configured in HOST mode by default Signed-off-by: Patrice Chotard Reviewed-by: Marek Vasut Reviewed-by: Simon Glass --- drivers/usb/host/xhci-dwc3.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index fb106f328a..93ae986b4d 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -15,6 +15,7 @@ #include "xhci.h" #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -110,6 +111,7 @@ static int xhci_dwc3_probe(struct udevice *dev) struct xhci_hcor *hcor; struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; + enum usb_dr_mode dr_mode; hccr = (struct xhci_hccr *)devfdt_get_addr(dev); hcor = (struct xhci_hcor *)((phys_addr_t)hccr + @@ -119,6 +121,13 @@ static int xhci_dwc3_probe(struct udevice *dev) dwc3_core_init(dwc3_reg); + dr_mode = usb_get_dr_mode(dev_of_offset(dev)); + if (dr_mode == USB_DR_MODE_UNKNOWN) + /* by default set dual role mode to HOST */ + dr_mode = USB_DR_MODE_HOST; + + dwc3_set_mode(dwc3_reg, dr_mode); + return xhci_register(dev, hccr, hcor); } From b9688df3cbf4bf92fa96e1cc9ff7be510e06b54b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:38:42 +0200 Subject: [PATCH 04/61] drivers: phy: Set phy->dev to NULL when generic_phy_get_by_index() fails phy->dev need to be set to NULL in case of generic_phy_get_by_index() fails. Then phy->dev can be used to check if the phy is valid Reported-by: Jean-Jacques Hiblot Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/phy/phy-uclass.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index d8b8d58e44..68e518fc79 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -45,6 +45,7 @@ int generic_phy_get_by_index(struct udevice *dev, int index, debug("%s(dev=%p, index=%d, phy=%p)\n", __func__, dev, index, phy); assert(phy); + phy->dev = NULL; ret = dev_read_phandle_with_args(dev, "phys", "#phy-cells", 0, index, &args); if (ret) { From b94888b4c051126b02770066ce1e7f4ea9a1ced8 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:38:43 +0200 Subject: [PATCH 05/61] drivers: phy: add generic_phy_valid() method This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct. Signed-off-by: Patrice Chotard --- include/generic-phy.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/generic-phy.h b/include/generic-phy.h index 762704c208..58cd2b26a9 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -220,4 +220,15 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy); +/** + * generic_phy_valid() - check if PHY port is valid + * + * @phy: the PHY port to check + * @return TRUE if valid, or FALSE + */ +static inline bool generic_phy_valid(struct phy *phy) +{ + return phy->dev != NULL; +} + #endif /*__GENERIC_PHY_H */ From f56db163adf9f922020436e5a3f85ffbdbaed04f Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:38:44 +0200 Subject: [PATCH 06/61] usb: host: xhci-dwc3: Add generic PHY support Add support of generic PHY framework support Signed-off-by: Patrice Chotard Reviewed-by: Marek Vasut Reviewed-by: Simon Glass --- drivers/usb/host/xhci-dwc3.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 93ae986b4d..374fe743fe 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include "xhci.h" @@ -19,6 +21,10 @@ DECLARE_GLOBAL_DATA_PTR; +struct xhci_dwc3_platdata { + struct phy usb_phy; +}; + void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl, @@ -112,11 +118,26 @@ static int xhci_dwc3_probe(struct udevice *dev) struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; enum usb_dr_mode dr_mode; + int ret; hccr = (struct xhci_hccr *)devfdt_get_addr(dev); hcor = (struct xhci_hcor *)((phys_addr_t)hccr + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); + 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); + return ret; + } + } else { + ret = generic_phy_init(&plat->usb_phy); + if (ret) { + error("Can't init USB PHY for %s\n", dev->name); + return ret; + } + } + dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET); dwc3_core_init(dwc3_reg); @@ -133,6 +154,17 @@ static int xhci_dwc3_probe(struct udevice *dev) static int xhci_dwc3_remove(struct udevice *dev) { + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + int ret; + + 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); + return ret; + } + } + return xhci_deregister(dev); } From 9bd5cdf6b62b249dc48a00a23b44dc7be547f9f9 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:05 +0200 Subject: [PATCH 07/61] reset: add reset_request() This is needed in error path to assert previously deasserted reset by using a saved reset_ctl reference. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/reset/reset-uclass.c | 9 +++++++++ include/reset.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c index de3695ffaa..4fd82b9cd9 100644 --- a/drivers/reset/reset-uclass.c +++ b/drivers/reset/reset-uclass.c @@ -97,6 +97,15 @@ int reset_get_by_name(struct udevice *dev, const char *name, return reset_get_by_index(dev, index, reset_ctl); } +int reset_request(struct reset_ctl *reset_ctl) +{ + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); + + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + return ops->request(reset_ctl); +} + int reset_free(struct reset_ctl *reset_ctl) { struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); diff --git a/include/reset.h b/include/reset.h index f45fcf88c4..4f2e35f38f 100644 --- a/include/reset.h +++ b/include/reset.h @@ -99,6 +99,15 @@ int reset_get_by_index(struct udevice *dev, int index, int reset_get_by_name(struct udevice *dev, const char *name, struct reset_ctl *reset_ctl); +/** + * reset_request - Request a reset signal. + * + * @reset_ctl: A reset control struct. + * + * @return 0 if OK, or a negative error code. + */ +int reset_request(struct reset_ctl *reset_ctl); + /** * reset_free - Free a previously requested reset signal. * From 3b9d1bdd4e5fe0c44e5d4d0a0916dbccc558749d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:06 +0200 Subject: [PATCH 08/61] reset: add reset_release_all() Add reset_release_all() method which Assert/Free an array of resets signal that has been previously successfully requested by reset_get_by_*() Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/reset/reset-uclass.c | 25 +++++++++++++++++++++++++ include/reset.h | 18 ++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c index 4fd82b9cd9..307a29705f 100644 --- a/drivers/reset/reset-uclass.c +++ b/drivers/reset/reset-uclass.c @@ -42,6 +42,7 @@ int reset_get_by_index(struct udevice *dev, int index, debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index, reset_ctl); + reset_ctl->dev = NULL; ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0, index, &args); @@ -87,6 +88,7 @@ int reset_get_by_name(struct udevice *dev, const char *name, debug("%s(dev=%p, name=%s, reset_ctl=%p)\n", __func__, dev, name, reset_ctl); + reset_ctl->dev = NULL; index = dev_read_stringlist_search(dev, "reset-names", name); if (index < 0) { @@ -133,6 +135,29 @@ int reset_deassert(struct reset_ctl *reset_ctl) return ops->rst_deassert(reset_ctl); } +int reset_release_all(struct reset_ctl *reset_ctl, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + debug("%s(reset_ctl[%d]=%p)\n", __func__, i, &reset_ctl[i]); + + /* check if reset has been previously requested */ + if (!reset_ctl[i].dev) + continue; + + ret = reset_assert(&reset_ctl[i]); + if (ret) + return ret; + + ret = reset_free(&reset_ctl[i]); + if (ret) + return ret; + } + + return 0; +} + UCLASS_DRIVER(reset) = { .id = UCLASS_RESET, .name = "reset", diff --git a/include/reset.h b/include/reset.h index 4f2e35f38f..7185ade7ac 100644 --- a/include/reset.h +++ b/include/reset.h @@ -144,6 +144,18 @@ int reset_assert(struct reset_ctl *reset_ctl); */ int reset_deassert(struct reset_ctl *reset_ctl); +/** + * reset_release_all - Assert/Free an array of previously requested resets. + * + * For each reset contained in the reset array, this function will check if + * reset has been previously requested and then will assert and free it. + * + * @reset_ctl: A reset struct array that was previously successfully + * requested by reset_get_by_*(). + * @count Number of reset contained in the array + * @return 0 if OK, or a negative error code. + */ +int reset_release_all(struct reset_ctl *reset_ctl, int count); #else static inline int reset_get_by_index(struct udevice *dev, int index, struct reset_ctl *reset_ctl) @@ -171,6 +183,12 @@ static inline int reset_deassert(struct reset_ctl *reset_ctl) { return 0; } + +static inline int reset_release_all(struct reset_ctl *reset_ctl, int count) +{ + return 0; +} + #endif #endif From 82a8a669b4f7159f1f3c3251c2fcb36965896290 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:07 +0200 Subject: [PATCH 09/61] clk: add clk_release_all() Add clk_release_all() method which Disable/Free an array of clocks that has been previously requested by clk_request/get_by_*() Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/clk/clk-uclass.c | 26 ++++++++++++++++++++++++++ include/clk.h | 14 ++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 83b63288fb..ffbe872f34 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -65,6 +65,8 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk); assert(clk); + clk->dev = NULL; + ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, index, &args); if (ret) { @@ -102,6 +104,7 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) int index; debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk); + clk->dev = NULL; index = dev_read_stringlist_search(dev, "clock-names", name); if (index < 0) { @@ -187,6 +190,29 @@ int clk_disable(struct clk *clk) return ops->disable(clk); } +int clk_release_all(struct clk *clk, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]); + + /* check if clock has been previously requested */ + if (!clk[i].dev) + continue; + + ret = clk_disable(&clk[i]); + if (ret && ret != -ENOSYS) + return ret; + + ret = clk_free(&clk[i]); + if (ret && ret != -ENOSYS) + return ret; + } + + return 0; +} + UCLASS_DRIVER(clk) = { .id = UCLASS_CLK, .name = "clk", diff --git a/include/clk.h b/include/clk.h index 5a5c2ff1e6..a905a4143f 100644 --- a/include/clk.h +++ b/include/clk.h @@ -174,6 +174,20 @@ int clk_enable(struct clk *clk); */ int clk_disable(struct clk *clk); +/** + * clk_release_all() - Disable (turn off)/Free an array of previously + * requested clocks. + * + * For each clock contained in the clock array, this function will check if + * clock has been previously requested and then will disable and free it. + * + * @clk: A clock struct array that was previously successfully + * requested by clk_request/get_by_*(). + * @count Number of clock contained in the array + * @return zero on success, or -ve error code. + */ +int clk_release_all(struct clk *clk, int count); + int soc_clk_dump(void); #endif From 642346ae269c3c5c54cf7e15c426c42f4df031da Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:08 +0200 Subject: [PATCH 10/61] dm: core: add ofnode_count_phandle_with_args() This function is usefull to get phandle number contained in a property list. For example, this allows to allocate the right amount of memory to keep clock's reference contained into the "clocks" property. To implement it, either of_count_phandle_with_args() or fdtdec_parse_phandle_with_args() are used respectively for live tree and flat tree. By passing index = -1, these 2 functions returns the number of phandle contained into the property list. Add also the dev_count_phandle_with_args() based on ofnode_count_phandle_with_args() Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/core/of_access.c | 7 +++++++ drivers/core/ofnode.c | 12 ++++++++++++ include/dm/of_access.h | 18 ++++++++++++++++++ include/dm/ofnode.h | 17 +++++++++++++++++ include/dm/read.h | 25 +++++++++++++++++++++++++ 5 files changed, 79 insertions(+) diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 2bb23eef88..c31cba7fd6 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -665,6 +665,13 @@ int of_parse_phandle_with_args(const struct device_node *np, index, out_args); } +int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name) +{ + return __of_parse_phandle_with_args(np, list_name, cells_name, 0, + -1, NULL); +} + static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len) { diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index fd068b06ef..5fc77c52a0 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -313,6 +313,18 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, return 0; } +int ofnode_count_phandle_with_args(ofnode node, const char *list_name, + const char *cells_name) +{ + if (ofnode_is_np(node)) + return of_count_phandle_with_args(ofnode_to_np(node), + list_name, cells_name); + else + return fdtdec_parse_phandle_with_args(gd->fdt_blob, + ofnode_to_offset(node), list_name, cells_name, + 0, -1, NULL); +} + ofnode ofnode_path(const char *path) { if (of_live_active()) diff --git a/include/dm/of_access.h b/include/dm/of_access.h index c5ea391aec..c49d287dd6 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -352,6 +352,24 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, int index, struct of_phandle_args *out_args); +/** + * of_count_phandle_with_args() - Count the number of phandle in a list + * + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @return number of phandle found, -ENOENT if + * @list_name does not exist, -EINVAL if a phandle was not found, + * @cells_name could not be found, the arguments were truncated or there + * were too many arguments. + * + * Returns number of phandle found on success, on error returns appropriate + * errno value. + * + */ +int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name); + /** * of_alias_scan() - Scan all properties of the 'aliases' node * diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 15ad5199c2..8eecce59d1 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -432,6 +432,23 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, int index, struct ofnode_phandle_args *out_args); +/** + * ofnode_count_phandle_with_args() - Count number of phandle in a list + * + * This function is useful to count phandles into a list. + * Returns number of phandle on success, on error returns appropriate + * errno value. + * + * @node: device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @return number of phandle on success, -ENOENT if @list_name does not + * exist, -EINVAL if a phandle was not found, @cells_name could not + * be found. + */ +int ofnode_count_phandle_with_args(ofnode node, const char *list_name, + const char *cells_name); + /** * ofnode_path() - find a node by full path * diff --git a/include/dm/read.h b/include/dm/read.h index b86a2f5fec..d09b04d110 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -208,6 +208,24 @@ int dev_read_phandle_with_args(struct udevice *dev, const char *list_name, int index, struct ofnode_phandle_args *out_args); +/** + * dev_count_phandle_with_args() - Return phandle number in a list + * + * This function is usefull to get phandle number contained in a property list. + * For example, this allows to allocate the right amount of memory to keep + * clock's reference contained into the "clocks" property. + * + * + * @dev: device whose node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @Returns number of phandle found on success, on error returns appropriate + * errno value. + */ + +int dev_count_phandle_with_args(struct udevice *dev, const char *list_name, + const char *cells_name); + /** * dev_read_addr_cells() - Get the number of address cells for a device's node * @@ -416,6 +434,13 @@ static inline int dev_read_phandle_with_args(struct udevice *dev, out_args); } +static inline int dev_count_phandle_with_args(struct udevice *dev, + const char *list_name, const char *cells_name) +{ + return ofnode_count_phandle_with_args(dev_ofnode(dev), list_name, + cells_name); +} + static inline int dev_read_addr_cells(struct udevice *dev) { /* NOTE: this call should walk up the parent stack */ From 10bb775e925d2a1c516c96904a5e1d2e747c4e1b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:09 +0200 Subject: [PATCH 11/61] usb: host: ehci-generic: replace printf() by error() this allows to get file, line and function location of the current error message. Signed-off-by: patrice chotard Reviewed-by: Simon Glass --- drivers/usb/host/ehci-generic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index fb78462893..2116ae1f11 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -34,7 +34,7 @@ static int ehci_usb_probe(struct udevice *dev) if (ret < 0) break; if (clk_enable(&clk)) - printf("failed to enable clock %d\n", i); + error("failed to enable clock %d\n", i); clk_free(&clk); } @@ -46,7 +46,7 @@ static int ehci_usb_probe(struct udevice *dev) if (ret < 0) break; if (reset_deassert(&reset)) - printf("failed to deassert reset %d\n", i); + error("failed to deassert reset %d\n", i); reset_free(&reset); } From a1cee8e808042e2597d162b1687fdb470634271e Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:10 +0200 Subject: [PATCH 12/61] usb: host: ehci-generic: add error path and .remove callback Use an array to save enabled clocks reference and deasserted resets in order to respectively disabled and asserted them in case of error during probe() or during driver removal. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/usb/host/ehci-generic.c | 114 ++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 2116ae1f11..e058445dca 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -18,43 +19,114 @@ */ struct generic_ehci { struct ehci_ctrl ctrl; + struct clk *clocks; + struct reset_ctl *resets; + int clock_count; + int reset_count; }; static int ehci_usb_probe(struct udevice *dev) { + struct generic_ehci *priv = dev_get_priv(dev); struct ehci_hccr *hccr; struct ehci_hcor *hcor; - int i; + int i, err, ret, clock_nb, reset_nb; - for (i = 0; ; i++) { - struct clk clk; - int ret; + err = 0; + priv->clock_count = 0; + clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", + "#clock-cells"); + if (clock_nb > 0) { + priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), + GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; - ret = clk_get_by_index(dev, i, &clk); - if (ret < 0) - break; - if (clk_enable(&clk)) - error("failed to enable clock %d\n", i); - clk_free(&clk); + for (i = 0; i < clock_nb; i++) { + err = clk_get_by_index(dev, i, &priv->clocks[i]); + + if (err < 0) + break; + err = clk_enable(&priv->clocks[i]); + if (err) { + error("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); + return clock_nb; + } } - for (i = 0; ; i++) { - struct reset_ctl reset; - int ret; + priv->reset_count = 0; + reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", + "#reset-cells"); + if (reset_nb > 0) { + priv->resets = devm_kcalloc(dev, reset_nb, + sizeof(struct reset_ctl), + GFP_KERNEL); + if (!priv->resets) + return -ENOMEM; - ret = reset_get_by_index(dev, i, &reset); - if (ret < 0) - break; - if (reset_deassert(&reset)) - error("failed to deassert reset %d\n", i); - reset_free(&reset); + for (i = 0; i < reset_nb; i++) { + err = reset_get_by_index(dev, i, &priv->resets[i]); + if (err < 0) + break; + + if (reset_deassert(&priv->resets[i])) { + error("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); + goto clk_err; + } } hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); - return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); + err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); + if (err) + goto reset_err; + + return 0; + +reset_err: + ret = reset_release_all(priv->resets, priv->reset_count); + if (ret) + error("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"); + + return err; +} + +static int ehci_usb_remove(struct udevice *dev) +{ + struct generic_ehci *priv = dev_get_priv(dev); + int ret; + + ret = ehci_deregister(dev); + if (ret) + return ret; + + ret = reset_release_all(priv->resets, priv->reset_count); + if (ret) + return ret; + + return clk_release_all(priv->clocks, priv->clock_count); } static const struct udevice_id ehci_usb_ids[] = { @@ -67,7 +139,7 @@ U_BOOT_DRIVER(ehci_generic) = { .id = UCLASS_USB, .of_match = ehci_usb_ids, .probe = ehci_usb_probe, - .remove = ehci_deregister, + .remove = ehci_usb_remove, .ops = &ehci_usb_ops, .priv_auto_alloc_size = sizeof(struct generic_ehci), .flags = DM_FLAG_ALLOC_PRIV_DMA, From 0d0ba1a73d6c34b7668f860e90ab57eacd9dd5b4 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:11 +0200 Subject: [PATCH 13/61] usb: host: ehci-generic: add generic PHY support Extend ehci-generic driver with generic PHY framework Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/usb/host/ehci-generic.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index e058445dca..3f751f1ecd 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct generic_ehci { struct ehci_ctrl ctrl; struct clk *clocks; struct reset_ctl *resets; + struct phy phy; int clock_count; int reset_count; }; @@ -91,16 +93,37 @@ 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"); + goto reset_err; + } + } + + err = generic_phy_init(&priv->phy); + if (err) { + error("failed to init usb phy\n"); + goto reset_err; + } + hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); if (err) - goto reset_err; + goto phy_err; return 0; +phy_err: + if (generic_phy_valid(&priv->phy)) { + ret = generic_phy_exit(&priv->phy); + if (ret) + error("failed to release phy\n"); + } + reset_err: ret = reset_release_all(priv->resets, priv->reset_count); if (ret) @@ -122,6 +145,12 @@ static int ehci_usb_remove(struct udevice *dev) if (ret) return ret; + if (generic_phy_valid(&priv->phy)) { + ret = generic_phy_exit(&priv->phy); + if (ret) + return ret; + } + ret = reset_release_all(priv->resets, priv->reset_count); if (ret) return ret; From 155d9f65d3bf78cc7113475110c129dc0dbbdae1 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:12 +0200 Subject: [PATCH 14/61] usb: host: ohci-generic: add CLOCK support use array to save enabled clocks reference in order to disabled them in case of error during probe() or during driver removal. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/usb/host/ohci-generic.c | 55 +++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index f85738fb05..f5b27ccf31 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -5,7 +5,9 @@ */ #include +#include #include +#include #include "ohci.h" #if !defined(CONFIG_USB_OHCI_NEW) @@ -14,18 +16,67 @@ struct generic_ohci { ohci_t ohci; + struct clk *clocks; /* clock list */ + int clock_count; /* number of clock in clock list */ }; static int ohci_usb_probe(struct udevice *dev) { struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); + struct generic_ohci *priv = dev_get_priv(dev); + int i, err, ret, clock_nb; - return ohci_register(dev, regs); + err = 0; + priv->clock_count = 0; + clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); + if (clock_nb > 0) { + priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), + GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; + + for (i = 0; i < clock_nb; i++) { + err = clk_get_by_index(dev, i, &priv->clocks[i]); + if (err < 0) + break; + + err = clk_enable(&priv->clocks[i]); + if (err) { + error("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); + return clock_nb; + } + + err = ohci_register(dev, regs); + if (err) + goto clk_err; + + return 0; + +clk_err: + ret = clk_release_all(priv->clocks, priv->clock_count); + if (ret) + error("failed to disable all clocks\n"); + + return err; } static int ohci_usb_remove(struct udevice *dev) { - return ohci_deregister(dev); + struct generic_ohci *priv = dev_get_priv(dev); + int ret; + + ret = ohci_deregister(dev); + if (ret) + return ret; + + return clk_release_all(priv->clocks, priv->clock_count); } static const struct udevice_id ohci_usb_ids[] = { From 8a51b4b3dac35a18acca2538efe2c2979aa56417 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:13 +0200 Subject: [PATCH 15/61] usb: host: ohci-generic: add RESET support use array to save deasserted resets reference in order to assert them in case of error during probe() or during driver removal. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/usb/host/ohci-generic.c | 42 +++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index f5b27ccf31..95d54c1f09 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "ohci.h" #if !defined(CONFIG_USB_OHCI_NEW) @@ -17,14 +18,16 @@ struct generic_ohci { ohci_t ohci; struct clk *clocks; /* clock list */ + struct reset_ctl *resets; /* reset list */ int clock_count; /* number of clock in clock list */ + int reset_count; /* number of reset in reset list */ }; static int ohci_usb_probe(struct udevice *dev) { struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); struct generic_ohci *priv = dev_get_priv(dev); - int i, err, ret, clock_nb; + int i, err, ret, clock_nb, reset_nb; err = 0; priv->clock_count = 0; @@ -53,12 +56,43 @@ static int ohci_usb_probe(struct udevice *dev) return clock_nb; } + priv->reset_count = 0; + reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); + if (reset_nb > 0) { + priv->resets = devm_kcalloc(dev, reset_nb, + sizeof(struct reset_ctl), + GFP_KERNEL); + if (!priv->resets) + return -ENOMEM; + + for (i = 0; i < reset_nb; i++) { + err = reset_get_by_index(dev, i, &priv->resets[i]); + if (err < 0) + break; + + err = reset_deassert(&priv->resets[i]); + if (err) { + error("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); + goto clk_err; + } + err = ohci_register(dev, regs); if (err) - goto clk_err; + goto reset_err; return 0; +reset_err: + ret = reset_release_all(priv->resets, priv->reset_count); + if (ret) + error("failed to assert all resets\n"); clk_err: ret = clk_release_all(priv->clocks, priv->clock_count); if (ret) @@ -76,6 +110,10 @@ static int ohci_usb_remove(struct udevice *dev) if (ret) return ret; + ret = reset_release_all(priv->resets, priv->reset_count); + if (ret) + return ret; + return clk_release_all(priv->clocks, priv->clock_count); } From 28df1cfddd9e722d0016d0930b0e523a82737695 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:14 +0200 Subject: [PATCH 16/61] usb: host: ohci-generic: add generic PHY support Extend ohci-generic driver with generic PHY framework Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/usb/host/ohci-generic.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index 95d54c1f09..9249039055 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "ohci.h" @@ -19,6 +20,7 @@ struct generic_ohci { ohci_t ohci; struct clk *clocks; /* clock list */ struct reset_ctl *resets; /* reset list */ + struct phy phy; int clock_count; /* number of clock in clock list */ int reset_count; /* number of reset in reset list */ }; @@ -83,12 +85,33 @@ static int ohci_usb_probe(struct udevice *dev) 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"); + goto reset_err; + } + } + + err = generic_phy_init(&priv->phy); + if (err) { + error("failed to init usb phy\n"); + goto reset_err; + } + err = ohci_register(dev, regs); if (err) - goto reset_err; + goto phy_err; return 0; +phy_err: + if (generic_phy_valid(&priv->phy)) { + ret = generic_phy_exit(&priv->phy); + if (ret) + error("failed to release phy\n"); + } + reset_err: ret = reset_release_all(priv->resets, priv->reset_count); if (ret) @@ -110,6 +133,12 @@ static int ohci_usb_remove(struct udevice *dev) if (ret) return ret; + if (generic_phy_valid(&priv->phy)) { + ret = generic_phy_exit(&priv->phy); + if (ret) + return ret; + } + ret = reset_release_all(priv->resets, priv->reset_count); if (ret) return ret; From f2e0315e9d27a6495bde8d80983be4e0208bb63f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:53 +0800 Subject: [PATCH 17/61] usb: xhci: Remove incorrect comments for struct xhci_container_ctx There is no member called 'dma' in struct xhci_container_ctx. Remove the comments that mentions it. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/xhci.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2afa38694b..431afd864d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -482,10 +482,9 @@ struct xhci_protocol_caps { * @type: Type of context. Used to calculated offsets to contained contexts. * @size: Size of the context data * @bytes: The raw context data given to HW - * @dma: dma address of the bytes * * Represents either a Device or Input context. Holds a pointer to the raw - * memory used for the context (bytes) and dma address of it (dma). + * memory used for the context (bytes). */ struct xhci_container_ctx { unsigned type; From 43eb0d448867f9f3c7b02957a2196ac987840a17 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:54 +0800 Subject: [PATCH 18/61] usb: xhci: Correct command TRB 4th dword initialization In xhci_queue_command(), when the command is not 'reset endpoint', 'stop endpoint' or 'set TR dequeue pointer', endpoint ID should not be encoded in the TRB. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/xhci-ring.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2675a8f649..579e6707eb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -280,8 +280,15 @@ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id, fields[0] = lower_32_bits(val_64); fields[1] = upper_32_bits(val_64); fields[2] = 0; - fields[3] = TRB_TYPE(cmd) | EP_ID_FOR_TRB(ep_index) | - SLOT_ID_FOR_TRB(slot_id) | ctrl->cmd_ring->cycle_state; + fields[3] = TRB_TYPE(cmd) | SLOT_ID_FOR_TRB(slot_id) | + ctrl->cmd_ring->cycle_state; + + /* + * Only 'reset endpoint', 'stop endpoint' and 'set TR dequeue pointer' + * commands need endpoint id encoded. + */ + if (cmd >= TRB_RESET_EP && cmd <= TRB_SET_DEQ) + fields[3] |= EP_ID_FOR_TRB(ep_index); queue_trb(ctrl, ctrl->cmd_ring, false, fields); From 209b98de01d26ef199c887934cd025fdbd761d16 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:55 +0800 Subject: [PATCH 19/61] usb: xhci: Initialize scratchpad buffer array and scratchpad buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scratchpad buffer array is used to define the locations of statically allocated memory pages that are available for the private use of the xHC. The xHCI spec explicitly mentions that system software shall allocate the scratchpad buffers before placing the xHC in to Run mode (Run/Stop (R/S) = ‘1’), however U-Boot is missing this part. This causes xHC on Intel platform does not respond the very first 'enable slot' command that is given to xHC and the 'enable slot' command completion event TRB is never generated and xHC seems to hang forever. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/xhci-mem.c | 87 +++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 10 ++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 62db51d018..12e277a26d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -95,6 +95,25 @@ static void xhci_ring_free(struct xhci_ring *ring) free(ring); } +/** + * Free the scratchpad buffer array and scratchpad buffers + * + * @ctrl host controller data structure + * @return none + */ +static void xhci_scratchpad_free(struct xhci_ctrl *ctrl) +{ + if (!ctrl->scratchpad) + return; + + ctrl->dcbaa->dev_context_ptrs[0] = 0; + + free((void *)(uintptr_t)ctrl->scratchpad->sp_array[0]); + free(ctrl->scratchpad->sp_array); + free(ctrl->scratchpad); + ctrl->scratchpad = NULL; +} + /** * frees the "xhci_container_ctx" pointer passed * @@ -155,6 +174,7 @@ void xhci_cleanup(struct xhci_ctrl *ctrl) { xhci_ring_free(ctrl->event_ring); xhci_ring_free(ctrl->cmd_ring); + xhci_scratchpad_free(ctrl); xhci_free_virt_devices(ctrl); free(ctrl->erst.entries); free(ctrl->dcbaa); @@ -319,6 +339,70 @@ struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs) return ring; } +/** + * Set up the scratchpad buffer array and scratchpad buffers + * + * @ctrl host controller data structure + * @return -ENOMEM if buffer allocation fails, 0 on success + */ +static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl) +{ + struct xhci_hccr *hccr = ctrl->hccr; + struct xhci_hcor *hcor = ctrl->hcor; + struct xhci_scratchpad *scratchpad; + int num_sp; + uint32_t page_size; + void *buf; + int i; + + num_sp = HCS_MAX_SCRATCHPAD(xhci_readl(&hccr->cr_hcsparams2)); + if (!num_sp) + return 0; + + scratchpad = malloc(sizeof(*scratchpad)); + if (!scratchpad) + goto fail_sp; + ctrl->scratchpad = scratchpad; + + scratchpad->sp_array = xhci_malloc(num_sp * sizeof(u64)); + if (!scratchpad->sp_array) + goto fail_sp2; + ctrl->dcbaa->dev_context_ptrs[0] = + cpu_to_le64((uintptr_t)scratchpad->sp_array); + + page_size = xhci_readl(&hcor->or_pagesize) & 0xffff; + for (i = 0; i < 16; i++) { + if ((0x1 & page_size) != 0) + break; + page_size = page_size >> 1; + } + BUG_ON(i == 16); + + page_size = 1 << (i + 12); + buf = memalign(page_size, num_sp * page_size); + if (!buf) + goto fail_sp3; + memset(buf, '\0', num_sp * page_size); + xhci_flush_cache((uintptr_t)buf, num_sp * page_size); + + for (i = 0; i < num_sp; i++) { + uintptr_t ptr = (uintptr_t)buf + i * page_size; + scratchpad->sp_array[i] = cpu_to_le64(ptr); + } + + return 0; + +fail_sp3: + free(scratchpad->sp_array); + +fail_sp2: + free(scratchpad); + ctrl->scratchpad = NULL; + +fail_sp: + return -ENOMEM; +} + /** * Allocates the Container context * @@ -499,6 +583,9 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr, xhci_writeq(&ctrl->ir_set->erst_base, val_64); + /* set up the scratchpad buffer array and scratchpad buffers */ + xhci_scratchpad_alloc(ctrl); + /* initializing the virtual devices to NULL */ for (i = 0; i < MAX_HC_SLOTS; ++i) ctrl->devs[i] = NULL; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 431afd864d..32dd611efa 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -111,9 +111,10 @@ struct xhci_hccr { #define HCS_IST(p) (((p) >> 0) & 0xf) /* bits 4:7, max number of Event Ring segments */ #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) +/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */ /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ -/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ -#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) +/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */ +#define HCS_MAX_SCRATCHPAD(p) ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f)) /* HCSPARAMS3 - hcs_params3 - bitmasks */ /* bits 0:7, Max U1 to U0 latency for the roothub ports */ @@ -1037,6 +1038,10 @@ struct xhci_erst { unsigned int erst_size; }; +struct xhci_scratchpad { + u64 *sp_array; +}; + /* * Each segment table entry is 4*32bits long. 1K seems like an ok size: * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, @@ -1224,6 +1229,7 @@ struct xhci_ctrl { struct xhci_intr_reg *ir_set; struct xhci_erst erst; struct xhci_erst_entry entry[ERST_NUM_SEGS]; + struct xhci_scratchpad *scratchpad; struct xhci_virt_device *devs[MAX_HC_SLOTS]; int rootdev; }; From aab0db08c07de0807d609f19c17dfb8eaf589231 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:56 +0800 Subject: [PATCH 20/61] usb: xhci: Add input slot context in xhci_set_configuration() A valid input slot context for a 'configure endpoint' command requires the 'Context Entries' field to be initialized to the index of the last valid endpoint context that is defined by the target configuration. We set up the 'Context Entries' field, but we forget to include the input slot context in the input control context 'Add Context flags' bitmap. So xHC will simply ignore input slot context and continue using its own which contains old information of the device. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/xhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index bd8f4c43b4..95a0fbab50 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -332,8 +332,8 @@ static int xhci_set_configuration(struct usb_device *udev) ifdesc = &udev->config.if_desc[0]; ctrl_ctx = xhci_get_input_control_ctx(in_ctx); - /* Zero the input context control */ - ctrl_ctx->add_flags = 0; + /* Initialize the input context control */ + ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); ctrl_ctx->drop_flags = 0; /* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */ From f7a9e5dd03f83cf31a85eadf8666939abe47b739 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:57 +0800 Subject: [PATCH 21/61] usb: hub: Update handling connect status/change in usb_scan_port() It was observed that on Intel MinnowMax board, when xHCI is enabled in the BayTrail SoC, with a USB 3.0 device connected to the bottom USB 3.0 port (mapped to xHCI root port #7), its PORTSC register is always 0x201203 (CCS = 1, CSC = 0). The root cause of such behavior is unknown yet. Connect status change bit is set on the same port with a USB 2.0 device (mapped to xHCI port #1, which is a different port on the root hub). With current logic in usb_scan_port(), the enumeration process will abort if it does not detect a connect status change on a hub port. However since a device connection status is correctly reported, the enumeration process can still continue. With this change, USB device connected to the bottom blue port on MinnowMax board can be enumerated under either SS or HS mode. Signed-off-by: Bin Meng Reviewed-by: Stefan Roese Tested-by: Stefan Roese Tested-by: Dinh Nguyen --- common/usb_hub.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index d135526e4f..4fe0daa3e3 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -405,8 +405,15 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) portchange = le16_to_cpu(portsts->wPortChange); debug("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); - /* No connection change happened, wait a bit more. */ - if (!(portchange & USB_PORT_STAT_C_CONNECTION)) { + /* + * No connection change happened, wait a bit more. + * + * For some situation, the hub reports no connection change but a + * device is connected to the port (eg: CCS bit is set but CSC is not + * in the PORTSC register of a root hub), ignore such case. + */ + if (!(portchange & USB_PORT_STAT_C_CONNECTION) && + !(portstatus & USB_PORT_STAT_CONNECTION)) { if (get_timer(0) >= hub->connect_timeout) { debug("devnum=%d port=%d: timeout\n", dev->devnum, i + 1); @@ -418,10 +425,6 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) return 0; } - /* Test if the connection came up, and if not exit */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return 0; - /* A new USB device is ready at this point */ debug("devnum=%d port=%d: USB dev found\n", dev->devnum, i + 1); From f34211960214290d8b38dab2fbdfb18f07582f45 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:58 +0800 Subject: [PATCH 22/61] usb: hub: Send correct wValue to get hub descriptor of a USB 3.0 hub Testing a USB 3.0 hub by connecting it to the xHCI port on Intel MinnowMax, when issuing 'get hub descriptor' to the hub, xHCI reports a transfer event TRB with a completion code 6 which means 'Stall Error'. In fact super speed USB hub descriptor type is 0x2a, not 0x29. Sending correct SETUP packet to the hub makes it not stall anymore. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- common/usb_hub.c | 12 +++++++++++- drivers/usb/host/xhci.c | 1 + include/usb_defs.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index 4fe0daa3e3..48831b5681 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -65,11 +65,21 @@ __weak void usb_hub_reset_devices(int port) return; } +static inline bool usb_hub_is_superspeed(struct usb_device *hdev) +{ + return hdev->descriptor.bDeviceProtocol == 3; +} + static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { + unsigned short dtype = USB_DT_HUB; + + if (usb_hub_is_superspeed(dev)) + dtype = USB_DT_SS_HUB; + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT); + dtype << 8, 0, data, size, USB_CNTL_TIMEOUT); } static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 95a0fbab50..59ee476e19 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -727,6 +727,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe, case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8): switch (le16_to_cpu(req->value) >> 8) { case USB_DT_HUB: + case USB_DT_SS_HUB: debug("USB_DT_HUB config\n"); srcptr = &descriptor.hub; srclen = 0x8; diff --git a/include/usb_defs.h b/include/usb_defs.h index 8214ba9bf5..608a0ca568 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -93,6 +93,7 @@ #define USB_DT_REPORT (USB_TYPE_CLASS | 0x02) #define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) #define USB_DT_HUB (USB_TYPE_CLASS | 0x09) +#define USB_DT_SS_HUB (USB_TYPE_CLASS | 0x0a) /* Descriptor sizes per descriptor type */ #define USB_DT_DEVICE_SIZE 18 From 53771a490e05e8be750a6ee50002e30df4776e9b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:59 +0800 Subject: [PATCH 23/61] usb: hub: Revise wLength for 'get port status' request For accuracy, we should use 'sizeof(struct usb_port_status)' as the wLength for 'get port status' request, although it happens to be equal to 'sizeof(struct usb_hub_status)'. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- common/usb_hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index 48831b5681..83c6767a3b 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -107,7 +107,7 @@ int usb_get_port_status(struct usb_device *dev, int port, void *data) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, - data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); + data, sizeof(struct usb_port_status), USB_CNTL_TIMEOUT); } From 337fc7e665a20bd0c23da233ffb9e8469d999e72 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:00 +0800 Subject: [PATCH 24/61] usb: hub: Change USB hub descriptor to match USB 3.0 hubs USB 3.0 hubs have a slightly different hub descriptor than USB 2.0 hubs, with a fixed (rather than variable length) size. Change the host controller drivers that access those last two fields (DeviceRemovable and PortPowerCtrlMask) to use the union. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- common/usb_hub.c | 12 +++++++----- drivers/usb/emul/sandbox_hub.c | 7 ++++++- drivers/usb/host/ehci-hcd.c | 4 ++-- drivers/usb/host/xhci.c | 4 ++-- include/usb.h | 18 ++++++++++++++---- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index 83c6767a3b..a46d26a69e 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -583,17 +583,19 @@ static int usb_hub_configure(struct usb_device *dev) &descriptor->wHubCharacteristics)), &hub->desc.wHubCharacteristics); /* set the bitmap */ - bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; + bitmap = (unsigned char *)&hub->desc.u.hs.DeviceRemovable[0]; /* devices not removable by default */ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); - bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; + bitmap = (unsigned char *)&hub->desc.u.hs.PortPowerCtrlMask[0]; memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) - hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; + hub->desc.u.hs.DeviceRemovable[i] = + descriptor->u.hs.DeviceRemovable[i]; for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) - hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i]; + hub->desc.u.hs.PortPowerCtrlMask[i] = + descriptor->u.hs.PortPowerCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; debug("%d ports detected\n", dev->maxchild); @@ -637,7 +639,7 @@ static int usb_hub_configure(struct usb_device *dev) for (i = 0; i < dev->maxchild; i++) debug("port %d is%s removable\n", i + 1, - hub->desc.DeviceRemovable[(i + 1) / 8] & \ + hub->desc.u.hs.DeviceRemovable[(i + 1) / 8] & \ (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c index 9ffda9cc74..1432858fd5 100644 --- a/drivers/usb/emul/sandbox_hub.c +++ b/drivers/usb/emul/sandbox_hub.c @@ -96,7 +96,12 @@ static struct usb_hub_descriptor hub_desc = { 1 << 7), .bPwrOn2PwrGood = 2, .bHubContrCurrent = 5, - .DeviceRemovable = {0, 0xff}, /* all ports removeable */ + { + { + /* all ports removeable */ + .DeviceRemovable = {0, 0xff} + } + } #if SANDBOX_NUM_PORTS > 8 #error "This code sets up an incorrect mask" #endif diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index f08709d021..40ac3a602c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -52,8 +52,8 @@ static struct descriptor { 0, /* wHubCharacteristics */ 10, /* bPwrOn2PwrGood */ 0, /* bHubCntrCurrent */ - {}, /* Device removable */ - {} /* at most 7 ports! XXX */ + { /* Device removable */ + } /* at most 7 ports! XXX */ }, { 0x12, /* bLength */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 59ee476e19..d5a1b3402f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -50,8 +50,8 @@ static struct descriptor { cpu_to_le16(0x8), /* wHubCharacteristics */ 10, /* bPwrOn2PwrGood */ 0, /* bHubCntrCurrent */ - {}, /* Device removable */ - {} /* at most 7 ports! XXX */ + { /* Device removable */ + } /* at most 7 ports! XXX */ }, { 0x12, /* bLength */ diff --git a/include/usb.h b/include/usb.h index 62f051fe53..eb82cc23a8 100644 --- a/include/usb.h +++ b/include/usb.h @@ -546,10 +546,20 @@ struct usb_hub_descriptor { unsigned short wHubCharacteristics; unsigned char bPwrOn2PwrGood; unsigned char bHubContrCurrent; - unsigned char DeviceRemovable[(USB_MAXCHILDREN+1+7)/8]; - unsigned char PortPowerCtrlMask[(USB_MAXCHILDREN+1+7)/8]; - /* DeviceRemovable and PortPwrCtrlMask want to be variable-length - bitmaps that hold max 255 entries. (bit0 is ignored) */ + /* 2.0 and 3.0 hubs differ here */ + union { + struct { + /* add 1 bit for hub status change; round to bytes */ + __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; + __u8 PortPowerCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; + } __attribute__ ((packed)) hs; + + struct { + __u8 bHubHdrDecLat; + __le16 wHubDelay; + __le16 DeviceRemovable; + } __attribute__ ((packed)) ss; + } u; } __attribute__ ((packed)); From 98ba3d6c23963852c49b08e19fdbe1738edffe5b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:01 +0800 Subject: [PATCH 25/61] usb: hub: Add 3.0 hub port status mask of 2.0 hub USB 3.0 hub port status has different bit position regarding to port power, port speed, etc. But others are the same as 2.0 hubs. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- include/usb_defs.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/usb_defs.h b/include/usb_defs.h index 608a0ca568..6b4385a2d8 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -262,12 +262,17 @@ /* * Changes to wPortStatus bit field in USB 3.0 - * See USB 3.0 spec Table 10-11 + * See USB 3.0 spec Table 10-10 */ #define USB_SS_PORT_STAT_LINK_STATE 0x01e0 #define USB_SS_PORT_STAT_POWER 0x0200 #define USB_SS_PORT_STAT_SPEED 0x1c00 #define USB_SS_PORT_STAT_SPEED_5GBPS 0x0000 +/* Bits that are the same from USB 2.0 */ +#define USB_SS_PORT_STAT_MASK (USB_PORT_STAT_CONNECTION | \ + USB_PORT_STAT_ENABLE | \ + USB_PORT_STAT_OVERCURRENT | \ + USB_PORT_STAT_RESET) /* wPortChange bits */ #define USB_PORT_STAT_C_CONNECTION 0x0001 From 1bdcd9019d576b2637393e0b1ec65eab67a7c82f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:02 +0800 Subject: [PATCH 26/61] usb: xhci: Change MAX_HC_PORTS to 255 HCSPARAMS1:MaxPorts field specifies the maximum port number value, and its valid values are in the range of 1 to 255. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/xhci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 32dd611efa..3cf08e4207 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -30,7 +30,7 @@ /* Max number of USB devices for any host controller - limit in section 6.1 */ #define MAX_HC_SLOTS 256 /* Section 5.3.3 - MaxPorts */ -#define MAX_HC_PORTS 127 +#define MAX_HC_PORTS 255 /* Up to 16 ms to halt an HC */ #define XHCI_MAX_HALT_USEC (16*1000) @@ -102,8 +102,8 @@ struct xhci_hccr { #define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) /* bits 24:31, Max Ports - max value is 0x7F = 127 ports */ #define HCS_MAX_PORTS_SHIFT 24 -#define HCS_MAX_PORTS_MASK (0x7f << HCS_MAX_PORTS_SHIFT) -#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f) +#define HCS_MAX_PORTS_MASK (0xff << HCS_MAX_PORTS_SHIFT) +#define HCS_MAX_PORTS(p) (((p) >> 24) & 0xff) /* HCSPARAMS2 - hcs_params2 - bitmasks */ /* bits 0:3, frames or uframes that SW needs to queue transactions From 7274671e045ec78a0023949d99c26ae6b98b7a8e Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:03 +0800 Subject: [PATCH 27/61] usb: xhci: Get rid of CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS xHC reports supported maximum number of ports in the HCSPARAMS1 register, so it's unnecessary to use a hardcoded config option CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/xhci.c | 8 +++++--- drivers/usb/host/xhci.h | 4 +--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d5a1b3402f..62ab62b31b 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -668,12 +668,14 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe, uint32_t reg; volatile uint32_t *status_reg; struct xhci_ctrl *ctrl = xhci_get_ctrl(udev); + struct xhci_hccr *hccr = ctrl->hccr; struct xhci_hcor *hcor = ctrl->hcor; + int max_ports = HCS_MAX_PORTS(xhci_readl(&hccr->cr_hcsparams1)); if ((req->requesttype & USB_RT_PORT) && - le16_to_cpu(req->index) > CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS) { - printf("The request port(%d) is not configured\n", - le16_to_cpu(req->index) - 1); + le16_to_cpu(req->index) > max_ports) { + printf("The request port(%d) exceeds maximum port number\n", + le16_to_cpu(req->index) - 1); return -EINVAL; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3cf08e4207..b9602baa74 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -172,9 +172,7 @@ struct xhci_hcor { volatile uint64_t or_dcbaap; volatile uint32_t or_config; volatile uint32_t reserved_2[241]; - struct xhci_hcor_port_regs portregs[CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS]; - - uint32_t reserved_4[CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS * 254]; + struct xhci_hcor_port_regs portregs[MAX_HC_PORTS]; }; /* USBCMD - USB command - command bitmasks */ From 29313428744112ad8f601c86e29440a386aa6543 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:04 +0800 Subject: [PATCH 28/61] configs: Remove CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS in all boards Now that xHCD does not use CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS, remove it in all boards' config files. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- include/configs/am43xx_evm.h | 1 - include/configs/am57xx_evm.h | 1 - include/configs/cl-som-am57x.h | 1 - include/configs/cm_t43.h | 1 - include/configs/dra7xx_evm.h | 1 - include/configs/ds414.h | 1 - include/configs/exynos5-common.h | 1 - include/configs/ls1012afrdm.h | 1 - include/configs/ls1012aqds.h | 1 - include/configs/ls1012ardb.h | 1 - include/configs/ls1021aiot.h | 1 - include/configs/ls1021aqds.h | 1 - include/configs/ls1021atwr.h | 1 - include/configs/ls1043aqds.h | 1 - include/configs/ls1043ardb.h | 1 - include/configs/ls1046aqds.h | 1 - include/configs/ls1046ardb.h | 1 - include/configs/ls2080aqds.h | 1 - include/configs/ls2080ardb.h | 1 - include/configs/mvebu_armada-37xx.h | 4 +--- include/configs/mvebu_armada-8k.h | 4 +--- include/configs/rk3328_common.h | 2 -- include/configs/rk3399_common.h | 3 --- include/configs/ti_armv7_keystone2.h | 1 - include/configs/uniphier.h | 3 --- include/configs/xilinx_zynqmp.h | 2 -- scripts/config_whitelist.txt | 1 - 27 files changed, 2 insertions(+), 37 deletions(-) diff --git a/include/configs/am43xx_evm.h b/include/configs/am43xx_evm.h index a91b7df347..70e7473ee8 100644 --- a/include/configs/am43xx_evm.h +++ b/include/configs/am43xx_evm.h @@ -82,7 +82,6 @@ #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD) #define CONFIG_SYS_USB_FAT_BOOT_PARTITION 1 #define CONFIG_USB_XHCI_OMAP -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_OMAP_USB_PHY #define CONFIG_AM437X_USB2PHY2_HOST diff --git a/include/configs/am57xx_evm.h b/include/configs/am57xx_evm.h index 9216998486..9976686bd8 100644 --- a/include/configs/am57xx_evm.h +++ b/include/configs/am57xx_evm.h @@ -92,7 +92,6 @@ /* USB xHCI HOST */ #define CONFIG_USB_XHCI_OMAP -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_OMAP_USB_PHY #define CONFIG_OMAP_USB3PHY1_HOST diff --git a/include/configs/cl-som-am57x.h b/include/configs/cl-som-am57x.h index c1cf4132fe..120ac02e06 100644 --- a/include/configs/cl-som-am57x.h +++ b/include/configs/cl-som-am57x.h @@ -83,7 +83,6 @@ /* USB xHCI HOST */ #define CONFIG_USB_XHCI_OMAP -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_OMAP_USB_PHY #define CONFIG_OMAP_USB3PHY1_HOST diff --git a/include/configs/cm_t43.h b/include/configs/cm_t43.h index f6e0743b53..7a61107294 100644 --- a/include/configs/cm_t43.h +++ b/include/configs/cm_t43.h @@ -60,7 +60,6 @@ /* USB support */ #define CONFIG_USB_XHCI_OMAP -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_OMAP_USB_PHY #define CONFIG_AM437X_USB2PHY2_HOST diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h index 8566bdc569..b5091513f7 100644 --- a/include/configs/dra7xx_evm.h +++ b/include/configs/dra7xx_evm.h @@ -154,7 +154,6 @@ /* USB xHCI HOST */ #define CONFIG_USB_XHCI_OMAP -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_OMAP_USB_PHY #define CONFIG_OMAP_USB2PHY2_HOST diff --git a/include/configs/ds414.h b/include/configs/ds414.h index a209e6f09c..c1e9346290 100644 --- a/include/configs/ds414.h +++ b/include/configs/ds414.h @@ -68,7 +68,6 @@ #if 0 #undef CONFIG_DM_USB #define CONFIG_USB_XHCI_PCI -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif #if !defined(CONFIG_USB_XHCI_HCD) diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h index 378219d83a..7cb32783e6 100644 --- a/include/configs/exynos5-common.h +++ b/include/configs/exynos5-common.h @@ -135,7 +135,6 @@ /* USB */ #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_ASIX diff --git a/include/configs/ls1012afrdm.h b/include/configs/ls1012afrdm.h index f6f88e84c7..6b1ba578e9 100644 --- a/include/configs/ls1012afrdm.h +++ b/include/configs/ls1012afrdm.h @@ -39,7 +39,6 @@ #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif #define CONFIG_CMD_MEMINFO diff --git a/include/configs/ls1012aqds.h b/include/configs/ls1012aqds.h index 9e6c7a797c..bebb0dfce8 100644 --- a/include/configs/ls1012aqds.h +++ b/include/configs/ls1012aqds.h @@ -124,7 +124,6 @@ #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif /* MMC */ diff --git a/include/configs/ls1012ardb.h b/include/configs/ls1012ardb.h index 0705bc5f68..32c8cec072 100644 --- a/include/configs/ls1012ardb.h +++ b/include/configs/ls1012ardb.h @@ -27,7 +27,6 @@ #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif /* diff --git a/include/configs/ls1021aiot.h b/include/configs/ls1021aiot.h index 1f2eb52c24..58f893f4fd 100644 --- a/include/configs/ls1021aiot.h +++ b/include/configs/ls1021aiot.h @@ -26,7 +26,6 @@ #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_XHCI_DWC3 #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif #if defined(CONFIG_HAS_FSL_DR_USB) || defined(CONFIG_HAS_FSL_XHCI_USB) diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h index 251a66e595..83e7e7a50e 100644 --- a/include/configs/ls1021aqds.h +++ b/include/configs/ls1021aqds.h @@ -413,7 +413,6 @@ unsigned long get_board_ddr_clk(void); #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif /* diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h index b9e5cdbb1e..0aa6fdd09a 100644 --- a/include/configs/ls1021atwr.h +++ b/include/configs/ls1021atwr.h @@ -50,7 +50,6 @@ #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif #define CONFIG_SYS_CLK_FREQ 100000000 diff --git a/include/configs/ls1043aqds.h b/include/configs/ls1043aqds.h index 415a705508..0897da1998 100644 --- a/include/configs/ls1043aqds.h +++ b/include/configs/ls1043aqds.h @@ -377,7 +377,6 @@ unsigned long get_board_ddr_clk(void); #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 3 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif /* diff --git a/include/configs/ls1043ardb.h b/include/configs/ls1043ardb.h index 59e7760b10..617a712398 100644 --- a/include/configs/ls1043ardb.h +++ b/include/configs/ls1043ardb.h @@ -288,7 +288,6 @@ #ifdef CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 3 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif #endif diff --git a/include/configs/ls1046aqds.h b/include/configs/ls1046aqds.h index ea99676b7a..bb3d9416a8 100644 --- a/include/configs/ls1046aqds.h +++ b/include/configs/ls1046aqds.h @@ -144,7 +144,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_XHCI_DWC3 #define CONFIG_USB_MAX_CONTROLLER_COUNT 3 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_CMD_USB #define CONFIG_USB_STORAGE #endif diff --git a/include/configs/ls1046ardb.h b/include/configs/ls1046ardb.h index 20a5e7f659..8c72291f62 100644 --- a/include/configs/ls1046ardb.h +++ b/include/configs/ls1046ardb.h @@ -220,7 +220,6 @@ #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_XHCI_DWC3 #define CONFIG_USB_MAX_CONTROLLER_COUNT 3 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_CMD_USB #define CONFIG_USB_STORAGE #endif diff --git a/include/configs/ls2080aqds.h b/include/configs/ls2080aqds.h index 929ae3286a..66936c4a9e 100644 --- a/include/configs/ls2080aqds.h +++ b/include/configs/ls2080aqds.h @@ -446,7 +446,6 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 2 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #include diff --git a/include/configs/ls2080ardb.h b/include/configs/ls2080ardb.h index 0be4c4fa0b..744a78997b 100644 --- a/include/configs/ls2080ardb.h +++ b/include/configs/ls2080ardb.h @@ -346,7 +346,6 @@ unsigned long get_board_sys_clk(void); #define CONFIG_HAS_FSL_XHCI_USB #define CONFIG_USB_XHCI_FSL #define CONFIG_USB_MAX_CONTROLLER_COUNT 2 -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #undef CONFIG_CMDLINE_EDITING #include diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h index 778cc9e378..feb8112762 100644 --- a/include/configs/mvebu_armada-37xx.h +++ b/include/configs/mvebu_armada-37xx.h @@ -97,10 +97,8 @@ #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 /* USB 3.0 */ -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 3 - #define CONFIG_USB_MAX_CONTROLLER_COUNT (CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS + \ - CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS) + 3) /* USB ethernet */ #define CONFIG_USB_HOST_ETHER diff --git a/include/configs/mvebu_armada-8k.h b/include/configs/mvebu_armada-8k.h index 53db10f9bc..da66d6407e 100644 --- a/include/configs/mvebu_armada-8k.h +++ b/include/configs/mvebu_armada-8k.h @@ -101,10 +101,8 @@ #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 /* USB 3.0 */ -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 3 - #define CONFIG_USB_MAX_CONTROLLER_COUNT (CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS + \ - CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS) + 3) /* USB ethernet */ #define CONFIG_USB_HOST_ETHER diff --git a/include/configs/rk3328_common.h b/include/configs/rk3328_common.h index 7f9f0c5534..906c821aef 100644 --- a/include/configs/rk3328_common.h +++ b/include/configs/rk3328_common.h @@ -63,6 +63,4 @@ #define CONFIG_USB_OHCI_NEW #define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 1 -/* xhci host */ -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #endif diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h index 6c9d760995..33178879e2 100644 --- a/include/configs/rk3399_common.h +++ b/include/configs/rk3399_common.h @@ -80,7 +80,4 @@ #define CONFIG_USB_ETHER_SMSC95XX #define CONFIG_USB_ETHER_RTL8152 -/* rockchip xhci host driver */ -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 - #endif diff --git a/include/configs/ti_armv7_keystone2.h b/include/configs/ti_armv7_keystone2.h index c6122a0f74..26290ef1b2 100644 --- a/include/configs/ti_armv7_keystone2.h +++ b/include/configs/ti_armv7_keystone2.h @@ -193,7 +193,6 @@ /* USB Configuration */ #define CONFIG_USB_XHCI_KEYSTONE -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 #define CONFIG_USB_SS_BASE KS2_USB_SS_BASE #define CONFIG_USB_HOST_XHCI_BASE KS2_USB_HOST_XHCI_BASE #define CONFIG_DEV_USB_PHY_BASE KS2_DEV_USB_PHY_BASE diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h index cc65f072bc..6f5313931a 100644 --- a/include/configs/uniphier.h +++ b/include/configs/uniphier.h @@ -101,9 +101,6 @@ #define CONFIG_SYS_NAND_USE_FLASH_BBT #define CONFIG_SYS_NAND_BAD_BLOCK_POS 0 -/* USB */ -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 4 - /* SD/MMC */ #define CONFIG_SUPPORT_EMMC_BOOT diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index c30e37ccca..7c5ec1924d 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -90,8 +90,6 @@ #define CONFIG_SYS_LOAD_ADDR 0x8000000 #if defined(CONFIG_ZYNQMP_USB) -#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 - #define CONFIG_SYS_DFU_DATA_BUF_SIZE 0x1800000 #define DFU_DEFAULT_POLL_TIMEOUT 300 #define CONFIG_USB_CABLE_CHECK diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 93f0bf47c6..6312863c67 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -4877,7 +4877,6 @@ CONFIG_SYS_USB_OHCI_CPU_INIT CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS CONFIG_SYS_USB_OHCI_REGS_BASE CONFIG_SYS_USB_OHCI_SLOT_NAME -CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS CONFIG_SYS_USER_SWITCHES_BASE CONFIG_SYS_USE_BOOT_NORFLASH CONFIG_SYS_USE_DATAFLASH From 99c225568890df8fd224a4944d98599a5b2b721d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:05 +0800 Subject: [PATCH 29/61] usb: ehci: Get rid of CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS EHC reports supported maximum number of ports in the HCSPARAMS register, so it's unnecessary to use a hardcoded config option CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/ehci-hcd.c | 10 +++++++--- drivers/usb/host/ehci.h | 7 +++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 40ac3a602c..3243c1d1cf 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -148,9 +148,12 @@ static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg, static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port) { - if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { + int max_ports = HCS_N_PORTS(ehci_readl(&ctrl->hccr->cr_hcsparams)); + + if (port < 0 || port >= max_ports) { /* Printing the message would cause a scan failure! */ - debug("The request port(%u) is not configured\n", port); + debug("The request port(%u) exceeds maximum port number\n", + port); return NULL; } @@ -205,6 +208,7 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl) { int i, ret = 0; uint32_t cmd, reg; + int max_ports = HCS_N_PORTS(ehci_readl(&ctrl->hccr->cr_hcsparams)); if (!ctrl || !ctrl->hcor) return -EINVAL; @@ -219,7 +223,7 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl) 100 * 1000); if (!ret) { - for (i = 0; i < CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS; i++) { + for (i = 0; i < max_ports; i++) { reg = ehci_readl(&ctrl->hcor->or_portsc[i]); reg |= EHCI_PS_SUSP; ehci_writel(&ctrl->hcor->or_portsc[i], reg); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 2ab830df51..7c39becd24 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -11,9 +11,8 @@ #include -#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 -#endif +/* Section 2.2.3 - N_PORTS */ +#define MAX_HC_PORTS 15 /* * Register Space. @@ -62,7 +61,7 @@ struct ehci_hcor { uint32_t _reserved_1_[6]; uint32_t or_configflag; #define FLAG_CF (1 << 0) /* true: we'll support "high speed" */ - uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS]; + uint32_t or_portsc[MAX_HC_PORTS]; #define PORTSC_PSPD(x) (((x) >> 26) & 0x3) #define PORTSC_PSPD_FS 0x0 #define PORTSC_PSPD_LS 0x1 From cbb89ed026e761b58a2568fea7b98135abcefe21 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:06 +0800 Subject: [PATCH 30/61] configs: Remove CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS in all boards Now that EHCD does not use CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS, remove it in all boards' config files. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/arm/include/asm/ehci-omap.h | 4 ---- include/configs/MPC8572DS.h | 1 - include/configs/cm_t54.h | 1 - include/configs/corvus.h | 3 --- include/configs/duovero.h | 2 -- include/configs/exynos5-common.h | 2 -- include/configs/ma5d4evk.h | 1 - include/configs/mcx.h | 1 - include/configs/mvebu_armada-37xx.h | 7 +------ include/configs/mvebu_armada-8k.h | 7 +------ include/configs/mx35pdk.h | 1 - include/configs/odroid.h | 1 - include/configs/omap3_beagle.h | 1 - include/configs/omap3_overo.h | 1 - include/configs/omap4_panda.h | 2 -- include/configs/omap5_uevm.h | 1 - include/configs/picosam9g45.h | 3 --- include/configs/poplar.h | 1 - include/configs/sama5d2_ptc.h | 4 ---- include/configs/snapper9g45.h | 3 --- include/configs/sunxi-common.h | 1 - include/configs/tam3517-common.h | 1 - include/configs/tao3530.h | 1 - include/configs/tegra114-common.h | 1 - include/configs/tegra124-common.h | 1 - include/configs/tegra20-common.h | 1 - include/configs/tegra210-common.h | 1 - include/configs/tegra30-common.h | 1 - include/configs/vinco.h | 6 ------ include/configs/x86-common.h | 1 - scripts/config_whitelist.txt | 1 - 31 files changed, 2 insertions(+), 61 deletions(-) diff --git a/arch/arm/include/asm/ehci-omap.h b/arch/arm/include/asm/ehci-omap.h index 5a53e403a6..9dbb2c4c66 100644 --- a/arch/arm/include/asm/ehci-omap.h +++ b/arch/arm/include/asm/ehci-omap.h @@ -19,11 +19,7 @@ enum usbhs_omap_port_mode { OMAP_EHCI_PORT_MODE_HSIC, }; -#ifdef CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS -#define OMAP_HS_USB_PORTS CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS -#else #define OMAP_HS_USB_PORTS 3 -#endif #define is_ehci_phy_mode(x) ((x) == OMAP_EHCI_PORT_MODE_PHY) #define is_ehci_tll_mode(x) ((x) == OMAP_EHCI_PORT_MODE_TLL) diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h index 0a2bcb2383..32c593291a 100644 --- a/include/configs/MPC8572DS.h +++ b/include/configs/MPC8572DS.h @@ -560,7 +560,6 @@ #define CONFIG_USB_EHCI_PCI #define CONFIG_EHCI_HCD_INIT_AFTER_RESET #define CONFIG_PCI_EHCI_DEVICE 0 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 #endif #undef CONFIG_WATCHDOG /* watchdog disabled */ diff --git a/include/configs/cm_t54.h b/include/configs/cm_t54.h index 69706d254e..8a4c333564 100644 --- a/include/configs/cm_t54.h +++ b/include/configs/cm_t54.h @@ -56,7 +56,6 @@ #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ CONFIG_SYS_SCSI_MAX_LUN) /* USB UHH support options */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_EHCI_HCD_INIT_AFTER_RESET #define CONFIG_OMAP_EHCI_PHY2_RESET_GPIO 76 /* HSIC2 HUB #RESET */ diff --git a/include/configs/corvus.h b/include/configs/corvus.h index ed1a2287ab..015072720e 100644 --- a/include/configs/corvus.h +++ b/include/configs/corvus.h @@ -94,9 +94,6 @@ #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_AT91_WANTS_COMMON_PHY -/* USB */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 - #define CONFIG_MTD_DEVICE #define CONFIG_MTD_PARTITIONS diff --git a/include/configs/duovero.h b/include/configs/duovero.h index 8efcc94945..c4496a7f48 100644 --- a/include/configs/duovero.h +++ b/include/configs/duovero.h @@ -25,8 +25,6 @@ #define CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS /* USB UHH support options */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 - #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 1 #define CONFIG_OMAP_EHCI_PHY2_RESET_GPIO 62 diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h index 7cb32783e6..3b73bbc525 100644 --- a/include/configs/exynos5-common.h +++ b/include/configs/exynos5-common.h @@ -134,8 +134,6 @@ /* Enable Time Command */ /* USB */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 - #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_ASIX #define CONFIG_USB_ETHER_SMSC95XX diff --git a/include/configs/ma5d4evk.h b/include/configs/ma5d4evk.h index 2744efb922..7c28a94d92 100644 --- a/include/configs/ma5d4evk.h +++ b/include/configs/ma5d4evk.h @@ -96,7 +96,6 @@ * USB */ #ifdef CONFIG_CMD_USB -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 /* USB device */ #define CONFIG_USB_ETHER diff --git a/include/configs/mcx.h b/include/configs/mcx.h index 73fdfbd09f..3f5fdab9a9 100644 --- a/include/configs/mcx.h +++ b/include/configs/mcx.h @@ -74,7 +74,6 @@ /* EHCI */ #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 57 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_ASIX #define CONFIG_USB_ETHER_MCS7830 diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h index feb8112762..1307d215ed 100644 --- a/include/configs/mvebu_armada-37xx.h +++ b/include/configs/mvebu_armada-37xx.h @@ -93,12 +93,7 @@ #define CONFIG_NET_RETRY_COUNT 50 #define CONFIG_PHY_MARVELL -/* USB 2.0 */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 - -/* USB 3.0 */ -#define CONFIG_USB_MAX_CONTROLLER_COUNT (CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS + \ - 3) +#define CONFIG_USB_MAX_CONTROLLER_COUNT (3 + 3) /* USB ethernet */ #define CONFIG_USB_HOST_ETHER diff --git a/include/configs/mvebu_armada-8k.h b/include/configs/mvebu_armada-8k.h index da66d6407e..86ae19c9fb 100644 --- a/include/configs/mvebu_armada-8k.h +++ b/include/configs/mvebu_armada-8k.h @@ -97,12 +97,7 @@ #define CONFIG_ARP_TIMEOUT 200 #define CONFIG_NET_RETRY_COUNT 50 -/* USB 2.0 */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 - -/* USB 3.0 */ -#define CONFIG_USB_MAX_CONTROLLER_COUNT (CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS + \ - 3) +#define CONFIG_USB_MAX_CONTROLLER_COUNT (3 + 3) /* USB ethernet */ #define CONFIG_USB_HOST_ETHER diff --git a/include/configs/mx35pdk.h b/include/configs/mx35pdk.h index 9ae3d18137..8338d6df79 100644 --- a/include/configs/mx35pdk.h +++ b/include/configs/mx35pdk.h @@ -195,7 +195,6 @@ #define CONFIG_SYS_NAND_LARGEPAGE /* EHCI driver */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 #define CONFIG_EHCI_IS_TDI #define CONFIG_EHCI_HCD_INIT_AFTER_RESET #define CONFIG_USB_EHCI_MXC diff --git a/include/configs/odroid.h b/include/configs/odroid.h index 9552c967c8..563854d9bb 100644 --- a/include/configs/odroid.h +++ b/include/configs/odroid.h @@ -184,7 +184,6 @@ /* USB */ #define CONFIG_USB_EHCI_EXYNOS -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_SMSC95XX diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h index 4422d5e8d5..2fc6693579 100644 --- a/include/configs/omap3_beagle.h +++ b/include/configs/omap3_beagle.h @@ -58,7 +58,6 @@ #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 147 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_ASIX #define CONFIG_USB_ETHER_MCS7830 diff --git a/include/configs/omap3_overo.h b/include/configs/omap3_overo.h index 834822df7f..133069abbc 100644 --- a/include/configs/omap3_overo.h +++ b/include/configs/omap3_overo.h @@ -41,7 +41,6 @@ /* USB EHCI */ #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 183 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 /* commands to include */ diff --git a/include/configs/omap4_panda.h b/include/configs/omap4_panda.h index a973ce6a62..9951980836 100644 --- a/include/configs/omap4_panda.h +++ b/include/configs/omap4_panda.h @@ -17,8 +17,6 @@ */ /* USB UHH support options */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 - #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 1 #define CONFIG_OMAP_EHCI_PHY2_RESET_GPIO 62 diff --git a/include/configs/omap5_uevm.h b/include/configs/omap5_uevm.h index eb5e6df9ca..9b650090be 100644 --- a/include/configs/omap5_uevm.h +++ b/include/configs/omap5_uevm.h @@ -51,7 +51,6 @@ #define CONFIG_SYS_I2C_TCA642X_ADDR 0x22 /* USB UHH support options */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_EHCI_HCD_INIT_AFTER_RESET #define CONFIG_OMAP_EHCI_PHY2_RESET_GPIO 80 diff --git a/include/configs/picosam9g45.h b/include/configs/picosam9g45.h index 88f841dfd8..a14739f282 100644 --- a/include/configs/picosam9g45.h +++ b/include/configs/picosam9g45.h @@ -97,9 +97,6 @@ #define CONFIG_RESET_PHY_R #define CONFIG_AT91_WANTS_COMMON_PHY -/* USB */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 - #define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */ #define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE diff --git a/include/configs/poplar.h b/include/configs/poplar.h index d59f32a352..d2ecd0dec1 100644 --- a/include/configs/poplar.h +++ b/include/configs/poplar.h @@ -30,7 +30,6 @@ #define CONFIG_PL01X_SERIAL /* USB configuration */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_MAX_CONTROLLER_COUNT 2 #define CONFIG_SYS_USB_EVENT_POLL #define CONFIG_USB_HOST_ETHER diff --git a/include/configs/sama5d2_ptc.h b/include/configs/sama5d2_ptc.h index b25be974b6..401f1987ee 100644 --- a/include/configs/sama5d2_ptc.h +++ b/include/configs/sama5d2_ptc.h @@ -65,10 +65,6 @@ /* USB */ #define CONFIG_CMD_USB -#ifdef CONFIG_CMD_USB -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 -#endif - /* USB device */ #define CONFIG_USB_GADGET #define CONFIG_USB_GADGET_DUALSPEED diff --git a/include/configs/snapper9g45.h b/include/configs/snapper9g45.h index 2c5f2648ee..47dd99100b 100644 --- a/include/configs/snapper9g45.h +++ b/include/configs/snapper9g45.h @@ -60,9 +60,6 @@ #define CONFIG_TFTP_PORT #define CONFIG_TFTP_TSIZE -/* USB */ -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 - /* MMC */ #define CONFIG_GENERIC_ATMEL_MCI diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index fefd58f769..681c91cf46 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -310,7 +310,6 @@ extern int soft_i2c_gpio_scl; #define CONFIG_USB_OHCI_NEW #define CONFIG_USB_OHCI_SUNXI #define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 1 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 #endif #ifdef CONFIG_USB_MUSB_SUNXI diff --git a/include/configs/tam3517-common.h b/include/configs/tam3517-common.h index a9991fc6b8..fb173ebfb4 100644 --- a/include/configs/tam3517-common.h +++ b/include/configs/tam3517-common.h @@ -67,7 +67,6 @@ 115200} /* EHCI */ #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 25 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 /* commands to include */ #define CONFIG_CMD_NAND /* NAND support */ diff --git a/include/configs/tao3530.h b/include/configs/tao3530.h index 38f5bd015f..08134f4a1e 100644 --- a/include/configs/tao3530.h +++ b/include/configs/tao3530.h @@ -228,7 +228,6 @@ /* USB EHCI */ #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 162 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_SMSC95XX diff --git a/include/configs/tegra114-common.h b/include/configs/tegra114-common.h index 107a0f8803..75d2065177 100644 --- a/include/configs/tegra114-common.h +++ b/include/configs/tegra114-common.h @@ -63,6 +63,5 @@ /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 #endif /* _TEGRA114_COMMON_H_ */ diff --git a/include/configs/tegra124-common.h b/include/configs/tegra124-common.h index 8cf9bac156..0d61753c03 100644 --- a/include/configs/tegra124-common.h +++ b/include/configs/tegra124-common.h @@ -65,7 +65,6 @@ /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 /* GPU needs setup */ #define CONFIG_TEGRA_GPU diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h index db1cc248f4..342ffbe5b2 100644 --- a/include/configs/tegra20-common.h +++ b/include/configs/tegra20-common.h @@ -82,7 +82,6 @@ */ #define CONFIG_USB_EHCI_TXFIFO_THRESH 10 #define CONFIG_EHCI_IS_TDI -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 #define CONFIG_SYS_NAND_SELF_INIT #define CONFIG_SYS_NAND_ONFI_DETECTION diff --git a/include/configs/tegra210-common.h b/include/configs/tegra210-common.h index 874fe34d4f..4c05576a90 100644 --- a/include/configs/tegra210-common.h +++ b/include/configs/tegra210-common.h @@ -68,7 +68,6 @@ /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 /* GPU needs setup */ #define CONFIG_TEGRA_GPU diff --git a/include/configs/tegra30-common.h b/include/configs/tegra30-common.h index 60838474a6..c2096fbe7e 100644 --- a/include/configs/tegra30-common.h +++ b/include/configs/tegra30-common.h @@ -64,6 +64,5 @@ /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 #endif /* _TEGRA30_COMMON_H_ */ diff --git a/include/configs/vinco.h b/include/configs/vinco.h index dc35b289d4..adff1b6d7f 100644 --- a/include/configs/vinco.h +++ b/include/configs/vinco.h @@ -63,12 +63,6 @@ #endif -/* USB */ - -#ifdef CONFIG_CMD_USB -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 -#endif - /* USB device */ #define CONFIG_USB_ETHER #define CONFIG_USB_ETH_RNDIS diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h index 1be69748b7..aa1e505e69 100644 --- a/include/configs/x86-common.h +++ b/include/configs/x86-common.h @@ -128,7 +128,6 @@ * USB configuration */ #define CONFIG_USB_EHCI_PCI -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 12 #define CONFIG_SYS_USB_EVENT_POLL #define CONFIG_USB_HOST_ETHER diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 6312863c67..8f921c1a37 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -4868,7 +4868,6 @@ CONFIG_SYS_UNSPEC_STRID CONFIG_SYS_USBCTRL CONFIG_SYS_USBD_BASE CONFIG_SYS_USB_EHCI_CPU_INIT -CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS CONFIG_SYS_USB_EHCI_REGS_BASE CONFIG_SYS_USB_FAT_BOOT_PARTITION CONFIG_SYS_USB_HOST From 78abf14fc2ff577d0385f36fe91769d458fbc4a5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:07 +0800 Subject: [PATCH 31/61] usb: cmd: Print actual packet size for super speed devices USB 3.0 defines bMaxPacketSize0 field in the device descriptor as the exponent of 2, so let's print the calculated actual size. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- cmd/usb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/usb.c b/cmd/usb.c index 4fa456e318..992d414081 100644 --- a/cmd/usb.c +++ b/cmd/usb.c @@ -150,6 +150,8 @@ static void usb_display_string(struct usb_device *dev, int index) static void usb_display_desc(struct usb_device *dev) { + uint packet_size = dev->descriptor.bMaxPacketSize0; + if (dev->descriptor.bDescriptorType == USB_DT_DEVICE) { printf("%d: %s, USB Revision %x.%x\n", dev->devnum, usb_get_class_desc(dev->config.if_desc[0].desc.bInterfaceClass), @@ -171,9 +173,10 @@ static void usb_display_desc(struct usb_device *dev) usb_get_class_desc( dev->config.if_desc[0].desc.bInterfaceClass)); } + if (dev->descriptor.bcdUSB >= cpu_to_le16(0x0300)) + packet_size = 1 << packet_size; printf(" - PacketSize: %d Configurations: %d\n", - dev->descriptor.bMaxPacketSize0, - dev->descriptor.bNumConfigurations); + packet_size, dev->descriptor.bNumConfigurations); printf(" - Vendor: 0x%04x Product 0x%04x Version %d.%d\n", dev->descriptor.idVendor, dev->descriptor.idProduct, (dev->descriptor.bcdDevice>>8) & 0xff, From d7cde2811326731c9453b5880646b50a0b994916 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:08 +0800 Subject: [PATCH 32/61] usb: xhci: Convert CONFIG_USB_XHCI_PCI to Kconfig Add CONFIG_USB_XHCI_PCI as a Kconfig option. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- drivers/usb/host/Kconfig | 6 ++++++ scripts/config_whitelist.txt | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index bc2c1f17e5..9edc589fd0 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -31,6 +31,12 @@ config USB_XHCI_MVEBU SoCs, which includes Armada8K, Armada3700 and other Armada family SoCs. +config USB_XHCI_PCI + bool "Support for PCI-based xHCI USB controller" + default y if X86 + help + Enables support for the PCI-based xHCI controller. + config USB_XHCI_ROCKCHIP bool "Support for Rockchip on-chip xHCI USB controller" depends on ARCH_ROCKCHIP diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 8f921c1a37..2d642de729 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -5194,7 +5194,6 @@ CONFIG_USB_XHCI_EXYNOS CONFIG_USB_XHCI_FSL CONFIG_USB_XHCI_KEYSTONE CONFIG_USB_XHCI_OMAP -CONFIG_USB_XHCI_PCI CONFIG_USER_LOWLEVEL_INIT CONFIG_USE_FDT CONFIG_USE_INTERRUPT From 6e4d039aaaf87dcc83c743948c6bbcb49739e6a2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:09 +0800 Subject: [PATCH 33/61] x86: minnowmax: Add a environment variable for USB power-on delay Occasionally it was observed that on Intel MinnowMax board, with a USB 2.0 device connected to the bottom port, when doing 'usb start' on the xHCI controller: scanning bus 0 for devices... cannot reset port 3!? But neither of the two USB ports is routed to xHCI root port 3. Adding some debug information shows that xHCI port 3 PORTSC register mysteriously reports both CCS = 1 and CSC = 1. This is not seen every time. After increasing the timeout to wait for power to become stable, the issue is gone. So this indicates current default USB power-on delay (20ms) might be at a critical region where power is stable/unstable. U-Boot provides a mechanism to have a environment variable to override the default one. Add one for MinnowMax. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- include/configs/minnowmax.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index ae95485993..6ea607df67 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -20,7 +20,8 @@ #define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,serial\0" \ "stdout=vidconsole,serial\0" \ - "stderr=vidconsole,serial\0" + "stderr=vidconsole,serial\0" \ + "usb_pgood_delay=40\0" #define CONFIG_SCSI_DEV_LIST \ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA}, \ From c9621012a6f86500d60648a5e714b1c36e9111b9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:10 +0800 Subject: [PATCH 34/61] x86: minnowmax: Enable USB xHCI support BayTrail SoC supports both EHCI and xHCI controllers. However only one host controller (either EHCI or xHCI) can be used. To enable HSIC and SS ports, xHCI must be used. This turns on xHCI support on Intel MinnowMax board. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/x86/dts/minnowmax.dts | 3 +++ configs/minnowmax_defconfig | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts index 4c0a8fe26f..a0ad03ce23 100644 --- a/arch/x86/dts/minnowmax.dts +++ b/arch/x86/dts/minnowmax.dts @@ -272,6 +272,9 @@ fsp,enable-spi; fsp,enable-sata; fsp,sata-mode = ; +#ifdef CONFIG_USB_XHCI_HCD + fsp,enable-xhci; +#endif fsp,lpe-mode = ; fsp,lpss-sio-mode = ; fsp,enable-dma0; diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index 81e8253719..d05875310a 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -69,6 +69,7 @@ CONFIG_ICH_SPI=y CONFIG_TIMER=y CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y CONFIG_USB_STORAGE=y CONFIG_USB_KEYBOARD=y CONFIG_DM_VIDEO=y From 978f6a3b14f212cc7a956846c9e0cb9ca18620b1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:07 +0800 Subject: [PATCH 35/61] usb: xhci-pci: Drop non-DM version of xhci-pci driver As there is no board that currently uses xhci-pci driver without DM USB, drop its support and leave only DM support. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/Kconfig | 1 + drivers/usb/host/xhci-pci.c | 52 ------------------------------------- 2 files changed, 1 insertion(+), 52 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 9edc589fd0..67ad72b4a2 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -33,6 +33,7 @@ config USB_XHCI_MVEBU config USB_XHCI_PCI bool "Support for PCI-based xHCI USB controller" + depends on DM_USB default y if X86 help Enables support for the PCI-based xHCI controller. diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 63daaa6759..5ad8452384 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -14,56 +14,6 @@ #include "xhci.h" -#ifndef CONFIG_DM_USB - -/* - * Create the appropriate control structures to manage a new XHCI host - * controller. - */ -int xhci_hcd_init(int index, struct xhci_hccr **ret_hccr, - struct xhci_hcor **ret_hcor) -{ - struct xhci_hccr *hccr; - struct xhci_hcor *hcor; - pci_dev_t pdev; - uint32_t cmd; - int len; - - pdev = pci_find_class(PCI_CLASS_SERIAL_USB_XHCI, index); - if (pdev < 0) { - printf("XHCI host controller not found\n"); - return -1; - } - - hccr = (struct xhci_hccr *)pci_map_bar(pdev, - PCI_BASE_ADDRESS_0, PCI_REGION_MEM); - len = HC_LENGTH(xhci_readl(&hccr->cr_capbase)); - hcor = (struct xhci_hcor *)((uint32_t)hccr + len); - - debug("XHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n", - (uint32_t)hccr, (uint32_t)hcor, len); - - *ret_hccr = hccr; - *ret_hcor = hcor; - - /* enable busmaster */ - pci_read_config_dword(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_dword(pdev, PCI_COMMAND, cmd); - - return 0; -} - -/* - * Destroy the appropriate control structures corresponding * to the XHCI host - * controller - */ -void xhci_hcd_stop(int index) -{ -} - -#else - struct xhci_pci_priv { struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ }; @@ -137,5 +87,3 @@ static struct pci_device_id xhci_pci_supported[] = { }; U_BOOT_PCI_DEVICE(xhci_pci, xhci_pci_supported); - -#endif /* CONFIG_DM_USB */ From 5e941943d88aebcfc2e9c8a0801061d39e218bb5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:08 +0800 Subject: [PATCH 36/61] usb: xhci-pci: Clean up the driver a little bit This cleans up the driver a little bit. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/xhci-pci.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 5ad8452384..e4a0ef4a1a 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -8,16 +8,10 @@ #include #include -#include #include #include - #include "xhci.h" -struct xhci_pci_priv { - struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ -}; - static void xhci_pci_init(struct udevice *dev, struct xhci_hccr **ret_hccr, struct xhci_hcor **ret_hcor) { @@ -53,17 +47,6 @@ static int xhci_pci_probe(struct udevice *dev) return xhci_register(dev, hccr, hcor); } -static int xhci_pci_remove(struct udevice *dev) -{ - int ret; - - ret = xhci_deregister(dev); - if (ret) - return ret; - - return 0; -} - static const struct udevice_id xhci_pci_ids[] = { { .compatible = "xhci-pci" }, { } @@ -73,11 +56,11 @@ U_BOOT_DRIVER(xhci_pci) = { .name = "xhci_pci", .id = UCLASS_USB, .probe = xhci_pci_probe, - .remove = xhci_pci_remove, + .remove = xhci_deregister, .of_match = xhci_pci_ids, .ops = &xhci_usb_ops, .platdata_auto_alloc_size = sizeof(struct usb_platdata), - .priv_auto_alloc_size = sizeof(struct xhci_pci_priv), + .priv_auto_alloc_size = sizeof(struct xhci_ctrl), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; From dfa96e06761e223288e59d7a3e1d574f014b5a0d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:09 +0800 Subject: [PATCH 37/61] usb: hub: Use 'struct usb_hub_device' as hub device's uclass_priv Use USB hub device's dev->uclass_priv to point to 'usb_hub_device' so that with driver model usb_hub_reset() and usb_hub_allocate() are no longer needed. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 27 ++++++++++++++++++++++----- drivers/usb/host/usb-uclass.c | 2 -- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index a46d26a69e..37b358bbbb 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -55,9 +55,6 @@ struct usb_device_scan { struct list_head list; }; -/* TODO(sjg@chromium.org): Remove this when CONFIG_DM_USB is defined */ -static struct usb_hub_device hub_dev[USB_MAX_HUB]; -static int usb_hub_index; static LIST_HEAD(usb_scan_list); __weak void usb_hub_reset_devices(int port) @@ -164,6 +161,10 @@ static void usb_hub_power_on(struct usb_hub_device *hub) max(100, (int)pgood_delay) + 1000); } +#ifndef CONFIG_DM_USB +static struct usb_hub_device hub_dev[USB_MAX_HUB]; +static int usb_hub_index; + void usb_hub_reset(void) { usb_hub_index = 0; @@ -180,6 +181,7 @@ static struct usb_hub_device *usb_hub_allocate(void) printf("ERROR: USB_MAX_HUB (%d) reached\n", USB_MAX_HUB); return NULL; } +#endif #define MAX_TRIES 5 @@ -543,6 +545,20 @@ out: return ret; } +static struct usb_hub_device *usb_get_hub_device(struct usb_device *dev) +{ + struct usb_hub_device *hub; + +#ifndef CONFIG_DM_USB + /* "allocate" Hub device */ + hub = usb_hub_allocate(); +#else + hub = dev_get_uclass_priv(dev->dev); +#endif + + return hub; +} + static int usb_hub_configure(struct usb_device *dev) { int i, length; @@ -554,11 +570,11 @@ static int usb_hub_configure(struct usb_device *dev) __maybe_unused struct usb_hub_status *hubsts; int ret; - /* "allocate" Hub device */ - hub = usb_hub_allocate(); + hub = usb_get_hub_device(dev); if (hub == NULL) return -ENOMEM; hub->pusb_dev = dev; + /* Get the the hub descriptor */ ret = usb_get_hub_descriptor(dev, buffer, 4); if (ret < 0) { @@ -792,6 +808,7 @@ UCLASS_DRIVER(usb_hub) = { .child_pre_probe = usb_child_pre_probe, .per_child_auto_alloc_size = sizeof(struct usb_device), .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata), + .per_device_auto_alloc_size = sizeof(struct usb_hub_device), }; static const struct usb_device_id hub_id_table[] = { diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index efc5d4e7d7..d8d74bd04b 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -177,7 +177,6 @@ int usb_stop(void) #ifdef CONFIG_USB_STORAGE usb_stor_reset(); #endif - usb_hub_reset(); uc_priv->companion_device_count = 0; usb_started = 0; @@ -230,7 +229,6 @@ int usb_init(void) int ret; asynch_allowed = 1; - usb_hub_reset(); ret = uclass_get(UCLASS_USB, &uc); if (ret) From a199a7244899f6385035459cbc62409bd9bbcc23 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:10 +0800 Subject: [PATCH 38/61] usb: hub: Remove hub_port_reset() At present hub_port_reset() is defined in DM USB, but it is never called hence remove it (removing another ifdefs). While we are here, change legacy_hub_port_reset() name to usb_hub_port_reset() to better match other function names in the same hub module. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 25 +++++++++++++------------ include/usb.h | 18 ------------------ 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index 37b358bbbb..086b155cb7 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -207,8 +207,18 @@ static inline char *portspeed(int portstatus) return speed_str; } -int legacy_hub_port_reset(struct usb_device *dev, int port, - unsigned short *portstat) +/** + * usb_hub_port_reset() - reset a port given its usb_device pointer + * + * Reset a hub port and see if a device is present on that port, providing + * sufficient time for it to show itself. The port status is returned. + * + * @dev: USB device to reset + * @port: Port number to reset (note ports are numbered from 0 here) + * @portstat: Returns port status + */ +static int usb_hub_port_reset(struct usb_device *dev, int port, + unsigned short *portstat) { int err, tries; ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); @@ -281,15 +291,6 @@ int legacy_hub_port_reset(struct usb_device *dev, int port, return 0; } -#ifdef CONFIG_DM_USB -int hub_port_reset(struct udevice *dev, int port, unsigned short *portstat) -{ - struct usb_device *udev = dev_get_parent_priv(dev); - - return legacy_hub_port_reset(udev, port, portstat); -} -#endif - int usb_hub_port_connect_change(struct usb_device *dev, int port) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); @@ -323,7 +324,7 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port) } /* Reset the port */ - ret = legacy_hub_port_reset(dev, port, &portstatus); + ret = usb_hub_port_reset(dev, port, &portstatus); if (ret < 0) { if (ret != -ENXIO) printf("cannot reset port %i!?\n", port + 1); diff --git a/include/usb.h b/include/usb.h index eb82cc23a8..a266677677 100644 --- a/include/usb.h +++ b/include/usb.h @@ -871,24 +871,6 @@ bool usb_device_has_child_on_port(struct usb_device *parent, int port); int usb_hub_probe(struct usb_device *dev, int ifnum); void usb_hub_reset(void); -/** - * legacy_hub_port_reset() - reset a port given its usb_device pointer - * - * Reset a hub port and see if a device is present on that port, providing - * sufficient time for it to show itself. The port status is returned. - * - * With driver model this moves to hub_port_reset() and is passed a struct - * udevice. - * - * @dev: USB device to reset - * @port: Port number to reset (note ports are numbered from 0 here) - * @portstat: Returns port status - */ -int legacy_hub_port_reset(struct usb_device *dev, int port, - unsigned short *portstat); - -int hub_port_reset(struct udevice *dev, int port, unsigned short *portstat); - /* * usb_find_usb2_hub_address_port() - Get hub address and port for TT setting * From 46c1d49330fe21b3f9d2f7577ee4268248e7b666 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:11 +0800 Subject: [PATCH 39/61] usb: hub: Add a new API to test if a hub device is root hub Sometimes we need know if a given hub device is root hub or not. Add a new API to test this. This removes the xHCI driver's own version is_root_hub() and change to use the new API. While we are here, remove the unused/commented out get_usb_device() in the xHCI driver too. Signed-off-by: Bin Meng --- common/usb_hub.c | 10 ++++++++++ drivers/usb/host/xhci.c | 24 ++---------------------- include/usb.h | 8 ++++++++ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index 086b155cb7..a8c2f56006 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -67,6 +67,16 @@ static inline bool usb_hub_is_superspeed(struct usb_device *hdev) return hdev->descriptor.bDeviceProtocol == 3; } +#ifdef CONFIG_DM_USB +bool usb_hub_is_root_hub(struct udevice *hub) +{ + if (device_get_uclass_id(hub->parent) != UCLASS_USB_HUB) + return true; + + return false; +} +#endif + static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { unsigned short dtype = USB_DT_HUB; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 62ab62b31b..0c88980522 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1116,26 +1116,6 @@ int usb_lowlevel_stop(int index) #endif /* CONFIG_DM_USB */ #ifdef CONFIG_DM_USB -/* -static struct usb_device *get_usb_device(struct udevice *dev) -{ - struct usb_device *udev; - - if (device_get_uclass_id(dev) == UCLASS_USB) - udev = dev_get_uclass_priv(dev); - else - udev = dev_get_parent_priv(dev); - - return udev; -} -*/ -static bool is_root_hub(struct udevice *dev) -{ - if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) - return true; - - return false; -} static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev, unsigned long pipe, void *buffer, int length, @@ -1150,10 +1130,10 @@ static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev, hub = udev->dev; if (device_get_uclass_id(hub) == UCLASS_USB_HUB) { /* Figure out our port number on the root hub */ - if (is_root_hub(hub)) { + if (usb_hub_is_root_hub(hub)) { root_portnr = udev->portnr; } else { - while (!is_root_hub(hub->parent)) + while (!usb_hub_is_root_hub(hub->parent)) hub = hub->parent; uhop = dev_get_parent_priv(hub); root_portnr = uhop->portnr; diff --git a/include/usb.h b/include/usb.h index a266677677..64dfa84a9b 100644 --- a/include/usb.h +++ b/include/usb.h @@ -775,6 +775,14 @@ struct usb_device *usb_get_dev_index(struct udevice *bus, int index); int usb_setup_device(struct usb_device *dev, bool do_read, struct usb_device *parent); +/** + * usb_hub_is_root_hub() - Test whether a hub device is root hub or not + * + * @hub: USB hub device to test + * @return: true if the hub device is root hub, false otherwise. + */ +bool usb_hub_is_root_hub(struct udevice *hub); + /** * usb_hub_scan() - Scan a hub and find its devices * From 74ffc7cbb1d2d1f218b1bd67d1bd3cc1cba8aa79 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:12 +0800 Subject: [PATCH 40/61] usb: hub: Translate USB 3.0 hub port status into old version USB 3.0 hub port status field has different bit positions from 2.0 hubs. Since U-Boot only understands the old version, translate the new one into the old one. Since we are going to add USB 3.0 hub support, this feature is only available with driver model USB. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/common/usb_hub.c b/common/usb_hub.c index a8c2f56006..b0ff15977f 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -112,9 +112,40 @@ static int usb_get_hub_status(struct usb_device *dev, void *data) int usb_get_port_status(struct usb_device *dev, int port, void *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, sizeof(struct usb_port_status), USB_CNTL_TIMEOUT); + +#ifdef CONFIG_DM_USB + if (ret < 0) + return ret; + + /* + * Translate the USB 3.0 hub port status field into the old version + * that U-Boot understands. Do this only when the hub is not root hub. + * For root hub, the port status field has already been translated + * in the host controller driver (see xhci_submit_root() in xhci.c). + * + * Note: this only supports driver model. + */ + + if (!usb_hub_is_root_hub(dev->dev) && usb_hub_is_superspeed(dev)) { + struct usb_port_status *status = (struct usb_port_status *)data; + u16 tmp = (status->wPortStatus) & USB_SS_PORT_STAT_MASK; + + if (status->wPortStatus & USB_SS_PORT_STAT_POWER) + tmp |= USB_PORT_STAT_POWER; + if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) == + USB_SS_PORT_STAT_SPEED_5GBPS) + tmp |= USB_PORT_STAT_SUPER_SPEED; + + status->wPortStatus = tmp; + } +#endif + + return ret; } From bbc6f06c0031249bf1983b875e54cb7549bafe60 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:13 +0800 Subject: [PATCH 41/61] usb: hub: Support 'set hub depth' request for USB 3.0 hubs USB 3.0 hub uses a hub depth value multiplied by four as an offset into the 'route string' to locate the bits it uses to determine the downstream port number. We shall set the hub depth value of a USB 3.0 hub after it is configured. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ include/usb.h | 1 + include/usb_defs.h | 3 +++ 3 files changed, 56 insertions(+) diff --git a/common/usb_hub.c b/common/usb_hub.c index b0ff15977f..18c366ab7e 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -75,6 +75,16 @@ bool usb_hub_is_root_hub(struct udevice *hub) return false; } + +static int usb_set_hub_depth(struct usb_device *dev, int depth) +{ + if (depth < 0 || depth > 4) + return -EINVAL; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_HUB_DEPTH, USB_DIR_OUT | USB_RT_HUB, + depth, 0, NULL, 0, USB_CNTL_TIMEOUT); +} #endif static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) @@ -726,6 +736,48 @@ static int usb_hub_configure(struct usb_device *dev) debug("%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); + +#ifdef CONFIG_DM_USB + /* + * A maximum of seven tiers are allowed in a USB topology, and the + * root hub occupies the first tier. The last tier ends with a normal + * USB device. USB 3.0 hubs use a 20-bit field called 'route string' + * to route packets to the designated downstream port. The hub uses a + * hub depth value multiplied by four as an offset into the 'route + * string' to locate the bits it uses to determine the downstream + * port number. + */ + if (usb_hub_is_root_hub(dev->dev)) { + hub->hub_depth = -1; + } else { + struct udevice *hdev; + int depth = 0; + + hdev = dev->dev->parent; + while (!usb_hub_is_root_hub(hdev)) { + depth++; + hdev = hdev->parent; + } + + hub->hub_depth = depth; + + if (usb_hub_is_superspeed(dev)) { + debug("set hub (%p) depth to %d\n", dev, depth); + /* + * This request sets the value that the hub uses to + * determine the index into the 'route string index' + * for this hub. + */ + ret = usb_set_hub_depth(dev, depth); + if (ret < 0) { + debug("%s: failed to set hub depth (%lX)\n", + __func__, dev->status); + return ret; + } + } + } +#endif + usb_hub_power_on(hub); /* diff --git a/include/usb.h b/include/usb.h index 64dfa84a9b..f71da52b55 100644 --- a/include/usb.h +++ b/include/usb.h @@ -570,6 +570,7 @@ struct usb_hub_device { ulong connect_timeout; /* Device connection timeout in ms */ ulong query_delay; /* Device query delay in ms */ int overcurrent_count[USB_MAXCHILDREN]; /* Over-current counter */ + int hub_depth; /* USB 3.0 hub depth */ }; #ifdef CONFIG_DM_USB diff --git a/include/usb_defs.h b/include/usb_defs.h index 6b4385a2d8..273337f46a 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -306,6 +306,9 @@ /* Mask for wIndex in get/set port feature */ #define USB_HUB_PORT_MASK 0xf +/* Hub class request codes */ +#define USB_REQ_SET_HUB_DEPTH 0x0c + /* * CBI style */ From daec4691449fa4728f29260554701602e8f91d5c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:14 +0800 Subject: [PATCH 42/61] usb: xhci: Change xhci_setup_addressable_virt_dev() signature For future extension, change xhci_setup_addressable_virt_dev() signature to accept a pointer to 'struct usb_device', instead of its members slot_id & speed, as the struct already contains these two plus some other useful information of the device. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/xhci-mem.c | 6 ++++-- drivers/usb/host/xhci.c | 3 +-- drivers/usb/host/xhci.h | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 12e277a26d..9aa309237e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -713,14 +713,16 @@ void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx, * @param udev pointer to the Device Data Structure * @return returns negative value on failure else 0 on success */ -void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id, - int speed, int hop_portnr) +void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, + struct usb_device *udev, int hop_portnr) { struct xhci_virt_device *virt_dev; struct xhci_ep_ctx *ep0_ctx; struct xhci_slot_ctx *slot_ctx; u32 port_num = 0; u64 trb_64 = 0; + int slot_id = udev->slot_id; + int speed = udev->speed; virt_dev = ctrl->devs[slot_id]; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0c88980522..336613f73c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -415,8 +415,7 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr) * so setting up the slot context. */ debug("Setting up addressable devices %p\n", ctrl->dcbaa); - xhci_setup_addressable_virt_dev(ctrl, udev->slot_id, udev->speed, - root_portnr); + xhci_setup_addressable_virt_dev(ctrl, udev, root_portnr); ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx); ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index b9602baa74..cdce67c1a0 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1247,8 +1247,8 @@ void xhci_endpoint_copy(struct xhci_ctrl *ctrl, void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx, struct xhci_container_ctx *out_ctx); -void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id, - int speed, int hop_portnr); +void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, + struct usb_device *udev, int hop_portnr); void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id, u32 ep_index, trb_type cmd); void xhci_acknowledge_event(struct xhci_ctrl *ctrl); From 493b8dd070f2412b49190b71b44baddbb2b24e37 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:15 +0800 Subject: [PATCH 43/61] usb: xhci: Program 'route string' in the input slot context xHCI spec says: the values of the 'route string' field shall be initialized by the first 'Address Device' command issued to a device slot, and shall not be modified by any other command. So far U-Boot does not program this field, and it does not prevent SS device directly attached to root port, or HS device behind an HS hub, from working, due to the fact that 'route string' is used by the xHC to target SS packets. But in order to enumerate devices behind an SS hub, this field must be programmed. With this commit and along with previous commits, now SS & HS devices attached to a USB 3.0 hub can be enumerated by U-Boot. As usual, this new feature is only available when DM is on. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/xhci-mem.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 9aa309237e..c02059ee0a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -723,6 +723,11 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, u64 trb_64 = 0; int slot_id = udev->slot_id; int speed = udev->speed; + int route = 0; +#ifdef CONFIG_DM_USB + struct usb_device *dev = udev; + struct usb_hub_device *hub; +#endif virt_dev = ctrl->devs[slot_id]; @@ -733,7 +738,32 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->in_ctx); /* Only the control endpoint is valid - one endpoint context */ - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | 0); + slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1)); + +#ifdef CONFIG_DM_USB + /* Calculate the route string for this device */ + port_num = dev->portnr; + while (!usb_hub_is_root_hub(dev->dev)) { + hub = dev_get_uclass_priv(dev->dev); + /* + * Each hub in the topology is expected to have no more than + * 15 ports in order for the route string of a device to be + * unique. SuperSpeed hubs are restricted to only having 15 + * ports, but FS/LS/HS hubs are not. The xHCI specification + * says that if the port number the device is greater than 15, + * that portion of the route string shall be set to 15. + */ + if (port_num > 15) + port_num = 15; + route |= port_num << (hub->hub_depth * 4); + dev = dev_get_parent_priv(dev->dev); + port_num = dev->portnr; + dev = dev_get_parent_priv(dev->dev->parent); + } + + debug("route string %x\n", route); +#endif + slot_ctx->dev_info |= route; switch (speed) { case USB_SPEED_SUPER: From 5624dfd5aa91c244519ec60b40b4a42b4d9a43ca Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:16 +0800 Subject: [PATCH 44/61] usb: hub: Parse and save TT details from device descriptor A high speed hub has a special responsibility to handle full speed/ low speed devices connected on downstream ports. In this case, the hub must isolate the high speed signaling environment from the full speed/low speed signaling environment with the help of Transaction Translator (TT). TT details are provided by hub descriptors and we parse and save it to hub uclass_priv for later use. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ include/usb.h | 16 +++++++++++++++ include/usb_defs.h | 12 +++++++++++ 3 files changed, 78 insertions(+) diff --git a/common/usb_hub.c b/common/usb_hub.c index 18c366ab7e..bbb1155089 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -700,6 +700,56 @@ static int usb_hub_configure(struct usb_device *dev) break; } + switch (dev->descriptor.bDeviceProtocol) { + case USB_HUB_PR_FS: + break; + case USB_HUB_PR_HS_SINGLE_TT: + debug("Single TT\n"); + break; + case USB_HUB_PR_HS_MULTI_TT: + ret = usb_set_interface(dev, 0, 1); + if (ret == 0) { + debug("TT per port\n"); + hub->tt.multi = true; + } else { + debug("Using single TT (err %d)\n", ret); + } + break; + case USB_HUB_PR_SS: + /* USB 3.0 hubs don't have a TT */ + break; + default: + debug("Unrecognized hub protocol %d\n", + dev->descriptor.bDeviceProtocol); + break; + } + + /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ + switch (hubCharacteristics & HUB_CHAR_TTTT) { + case HUB_TTTT_8_BITS: + if (dev->descriptor.bDeviceProtocol != 0) { + hub->tt.think_time = 666; + debug("TT requires at most %d FS bit times (%d ns)\n", + 8, hub->tt.think_time); + } + break; + case HUB_TTTT_16_BITS: + hub->tt.think_time = 666 * 2; + debug("TT requires at most %d FS bit times (%d ns)\n", + 16, hub->tt.think_time); + break; + case HUB_TTTT_24_BITS: + hub->tt.think_time = 666 * 3; + debug("TT requires at most %d FS bit times (%d ns)\n", + 24, hub->tt.think_time); + break; + case HUB_TTTT_32_BITS: + hub->tt.think_time = 666 * 4; + debug("TT requires at most %d FS bit times (%d ns)\n", + 32, hub->tt.think_time); + break; + } + debug("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); debug("hub controller current requirement: %dmA\n", diff --git a/include/usb.h b/include/usb.h index f71da52b55..58b4549065 100644 --- a/include/usb.h +++ b/include/usb.h @@ -537,6 +537,21 @@ struct usb_hub_status { unsigned short wHubChange; } __attribute__ ((packed)); +/* + * Hub Device descriptor + * USB Hub class device protocols + */ +#define USB_HUB_PR_FS 0 /* Full speed hub */ +#define USB_HUB_PR_HS_NO_TT 0 /* Hi-speed hub without TT */ +#define USB_HUB_PR_HS_SINGLE_TT 1 /* Hi-speed hub with single TT */ +#define USB_HUB_PR_HS_MULTI_TT 2 /* Hi-speed hub with multiple TT */ +#define USB_HUB_PR_SS 3 /* Super speed hub */ + +/* Transaction Translator Think Times, in bits */ +#define HUB_TTTT_8_BITS 0x00 +#define HUB_TTTT_16_BITS 0x20 +#define HUB_TTTT_24_BITS 0x40 +#define HUB_TTTT_32_BITS 0x60 /* Hub descriptor */ struct usb_hub_descriptor { @@ -571,6 +586,7 @@ struct usb_hub_device { ulong query_delay; /* Device query delay in ms */ int overcurrent_count[USB_MAXCHILDREN]; /* Over-current counter */ int hub_depth; /* USB 3.0 hub depth */ + struct usb_tt tt; /* Transaction Translator */ }; #ifdef CONFIG_DM_USB diff --git a/include/usb_defs.h b/include/usb_defs.h index 273337f46a..b7f2eada07 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -293,6 +293,7 @@ #define HUB_CHAR_LPSM 0x0003 #define HUB_CHAR_COMPOUND 0x0004 #define HUB_CHAR_OCPM 0x0018 +#define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */ /* * Hub Status & Hub Change bit masks @@ -309,6 +310,17 @@ /* Hub class request codes */ #define USB_REQ_SET_HUB_DEPTH 0x0c +/* + * As of USB 2.0, full/low speed devices are segregated into trees. + * One type grows from USB 1.1 host controllers (OHCI, UHCI etc). + * The other type grows from high speed hubs when they connect to + * full/low speed devices using "Transaction Translators" (TTs). + */ +struct usb_tt { + bool multi; /* true means one TT per port */ + unsigned think_time; /* think time in ns */ +}; + /* * CBI style */ From 9ca1b4bab10d8b3a5dbbbd98df46ce75159222b8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:17 +0800 Subject: [PATCH 45/61] dm: usb: Add a new USB controller operation 'update_hub_device' For USB host controllers like xHC, its internal representation of hub needs to be updated after the hub descriptor is fetched. This adds a new op that does this. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/usb-uclass.c | 11 +++++++++++ include/usb.h | 21 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index d8d74bd04b..0b8a501ce8 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -139,6 +139,17 @@ int usb_reset_root_port(struct usb_device *udev) return ops->reset_root_port(bus, udev); } +int usb_update_hub_device(struct usb_device *udev) +{ + struct udevice *bus = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(bus); + + if (!ops->update_hub_device) + return -ENOSYS; + + return ops->update_hub_device(bus, udev); +} + int usb_stop(void) { struct udevice *bus; diff --git a/include/usb.h b/include/usb.h index 58b4549065..fad04016a3 100644 --- a/include/usb.h +++ b/include/usb.h @@ -758,6 +758,14 @@ struct dm_usb_ops { * reset_root_port() - Reset usb root port */ int (*reset_root_port)(struct udevice *bus, struct usb_device *udev); + + /** + * update_hub_device() - Update HCD's internal representation of hub + * + * After a hub descriptor is fetched, notify HCD so that its internal + * representation of this hub can be updated (xHCI) + */ + int (*update_hub_device)(struct udevice *bus, struct usb_device *udev); }; #define usb_get_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops) @@ -930,6 +938,17 @@ int usb_new_device(struct usb_device *dev); int usb_alloc_device(struct usb_device *dev); +/** + * update_hub_device() - Update HCD's internal representation of hub + * + * After a hub descriptor is fetched, notify HCD so that its internal + * representation of this hub can be updated. + * + * @dev: Hub device + * @return 0 if OK, -ve on error + */ +int usb_update_hub_device(struct usb_device *dev); + /** * usb_emul_setup_device() - Set up a new USB device emulation * @@ -943,7 +962,7 @@ int usb_alloc_device(struct usb_device *dev); * @desc_list: List of points or USB descriptors, terminated by NULL. * The first entry must be struct usb_device_descriptor, * and others follow on after that. - * @return 0 if OK, -ve on error + * @return 0 if OK, -ENOSYS if not implemented, other -ve on error */ int usb_emul_setup_device(struct udevice *dev, int maxpacketsize, struct usb_string *strings, void **desc_list); From 81060bb1c02abb242b73f118ce297dbe483a40f7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:18 +0800 Subject: [PATCH 46/61] usb: hub: Call usb_update_hub_device() after hub descriptor is fetched After fetching hub descriptor, we need to call USB uclass operation update_hub_device() to notify HCD to do some preparation work. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/common/usb_hub.c b/common/usb_hub.c index bbb1155089..70bc6e2931 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -788,6 +788,17 @@ static int usb_hub_configure(struct usb_device *dev) "" : "no "); #ifdef CONFIG_DM_USB + /* + * Update USB host controller's internal representation of this hub + * after the hub descriptor is fetched. + */ + ret = usb_update_hub_device(dev); + if (ret < 0 && ret != -ENOSYS) { + debug("%s: failed to update hub device for HCD (%x)\n", + __func__, ret); + return ret; + } + /* * A maximum of seven tiers are allowed in a USB topology, and the * root hub occupies the first tier. The last tier ends with a normal From d228ca362b0f2aa3679866c7a40702085653233e Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:19 +0800 Subject: [PATCH 47/61] usb: xhci: Implement update_hub_device() operation There is no way to know whether the attached device is a hub or not in advance before the device's descriptor is fetched. But once we know it's a high speed hub, per the xHCI spec, we need to tell xHC it's a hub device by initializing hub-related fields in the input slot context. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/xhci.c | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 336613f73c..9b82ee5c60 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1170,6 +1170,64 @@ static int xhci_alloc_device(struct udevice *dev, struct usb_device *udev) return _xhci_alloc_device(udev); } +static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev) +{ + struct xhci_ctrl *ctrl = dev_get_priv(dev); + struct usb_hub_device *hub = dev_get_uclass_priv(udev->dev); + struct xhci_virt_device *virt_dev; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_container_ctx *out_ctx; + struct xhci_container_ctx *in_ctx; + struct xhci_slot_ctx *slot_ctx; + int slot_id = udev->slot_id; + unsigned think_time; + + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + + /* Ignore root hubs */ + if (usb_hub_is_root_hub(udev->dev)) + return 0; + + virt_dev = ctrl->devs[slot_id]; + BUG_ON(!virt_dev); + + out_ctx = virt_dev->out_ctx; + in_ctx = virt_dev->in_ctx; + + 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->drop_flags = 0; + + xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); + + /* slot context */ + xhci_slot_copy(ctrl, in_ctx, out_ctx); + slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx); + + /* Update hub related fields */ + slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); + if (hub->tt.multi && udev->speed == USB_SPEED_HIGH) + 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. + * Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns + * + * 0 = 8 FS bit times, 1 = 16 FS bit times, + * 2 = 24 FS bit times, 3 = 32 FS bit times. + * + * This field shall be 0 if the device is not a high-spped hub. + */ + think_time = hub->tt.think_time; + if (think_time != 0) + think_time = (think_time / 666) - 1; + if (udev->speed == USB_SPEED_HIGH) + slot_ctx->tt_info |= cpu_to_le32(TT_THINK_TIME(think_time)); + + return xhci_configure_endpoints(udev, false); +} + int xhci_register(struct udevice *dev, struct xhci_hccr *hccr, struct xhci_hcor *hcor) { @@ -1222,6 +1280,7 @@ struct dm_usb_ops xhci_usb_ops = { .bulk = xhci_submit_bulk_msg, .interrupt = xhci_submit_int_msg, .alloc_device = xhci_alloc_device, + .update_hub_device = xhci_update_hub_device, }; #endif From 196ef8323c53b5d43fd9c244daaca1e2172ca47c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:20 +0800 Subject: [PATCH 48/61] usb: xhci: Correct TT_SLOT and TT_PORT macros These two macros really need a parameter to make them useful. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/xhci.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index cdce67c1a0..a497d9d830 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -548,12 +548,12 @@ struct xhci_slot_ctx { * The Slot ID of the hub that isolates the high speed signaling from * this low or full-speed device. '0' if attached to root hub port. */ -#define TT_SLOT (0xff) +#define TT_SLOT(p) (((p) & 0xff) << 0) /* * The number of the downstream facing port of the high-speed hub * '0' if the device is not low or full speed. */ -#define TT_PORT (0xff << 8) +#define TT_PORT(p) (((p) & 0xff) << 8) #define TT_THINK_TIME(p) (((p) & 0x3) << 16) /* dev_state bitmasks */ From 78e30987520870e0fc1d6b1cba5b46ce86dfff59 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:21 +0800 Subject: [PATCH 49/61] usb: xhci: Enable TT to support LS/FS devices behind a HS hub So far LS/FS devices directly attached to xHC root port can be successfully enumerated by xHCI driver, but if they are connected behind a hub, the enumeration process fails to address the device. It turns out xHCI driver still misses a part that in the device's input slot context, all Transaction Translator (TT) related fields are not programmed. The xHCI spec defines how to enable TT. Now LS/FS devices like USB keyboard/mouse can be enumerated behind a high speed hub. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/usb/host/xhci-mem.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c02059ee0a..d5eab3a615 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -783,6 +783,20 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, BUG(); } +#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); + 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_SLOT(dev->slot_id)); + } + } +#endif + port_num = hop_portnr; debug("port_num = %d\n", port_num); From bab0146ea91146aafa8cf10a34a45ae85eca5683 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Tue, 21 Jun 2016 14:50:48 +0200 Subject: [PATCH 50/61] usb: gadget: f_thor: Free the allocated out request buffer Fix the memory leak by freeing the allocated out request buffer Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/usb/gadget/f_thor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index a60e9487e7..cd4d9e659a 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -891,6 +891,7 @@ static void thor_func_disable(struct usb_function *f) } if (dev->out_ep->driver_data) { + free(dev->out_req->buf); dev->out_req->buf = NULL; usb_ep_free_request(dev->out_ep, dev->out_req); usb_ep_disable(dev->out_ep); From 4de512018ba7d57f1672be21c7459281f7c97514 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 19 Jul 2017 16:39:22 +0200 Subject: [PATCH 51/61] dfu: allow dfu read on partition greater than 2GB solve issue on get_medium_size() function the detection of error is a simple test < 0 but for ARM platform, long is 32bits and 2GB = 0x80000000 is seen as error. I solve the issue by changing the prototype fo the function to separate size and result. This patch prepare the next patch with size change to u64. Signed-off-by: Patrick Delaunay --- drivers/dfu/dfu.c | 6 +++--- drivers/dfu/dfu_mmc.c | 12 ++++++------ drivers/dfu/dfu_nand.c | 6 ++++-- drivers/dfu/dfu_ram.c | 6 ++++-- drivers/dfu/dfu_sf.c | 6 ++++-- include/dfu.h | 2 +- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index ceb33e35ee..c77701646b 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -339,9 +339,9 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if (dfu->i_buf_start == NULL) return -ENOMEM; - dfu->r_left = dfu->get_medium_size(dfu); - if (dfu->r_left < 0) - return dfu->r_left; + ret = dfu->get_medium_size(dfu, &dfu->r_left); + if (ret < 0) + return ret; debug("%s: %s %ld [B]\n", __func__, dfu->name, dfu->r_left); diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 926ccbd2ef..d918f95f5c 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -209,23 +209,23 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu) return ret; } -long dfu_get_medium_size_mmc(struct dfu_entity *dfu) +int dfu_get_medium_size_mmc(struct dfu_entity *dfu, long *size) { int ret; - long len; switch (dfu->layout) { case DFU_RAW_ADDR: - return dfu->data.mmc.lba_size * dfu->data.mmc.lba_blk_size; + *size = dfu->data.mmc.lba_size * dfu->data.mmc.lba_blk_size; + return 0; case DFU_FS_FAT: case DFU_FS_EXT4: dfu_file_buf_filled = -1; - ret = mmc_file_op(DFU_OP_SIZE, dfu, NULL, &len); + ret = mmc_file_op(DFU_OP_SIZE, dfu, NULL, size); if (ret < 0) return ret; - if (len > CONFIG_SYS_DFU_MAX_FILE_SIZE) + if (*size > CONFIG_SYS_DFU_MAX_FILE_SIZE) return -1; - return len; + return 0; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, dfu_get_layout(dfu->layout)); diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c index 97cd608e30..ed4ceb7a07 100644 --- a/drivers/dfu/dfu_nand.c +++ b/drivers/dfu/dfu_nand.c @@ -114,9 +114,11 @@ static int dfu_write_medium_nand(struct dfu_entity *dfu, return ret; } -long dfu_get_medium_size_nand(struct dfu_entity *dfu) +int dfu_get_medium_size_nand(struct dfu_entity *dfu, long *size) { - return dfu->data.nand.size; + *size = dfu->data.nand.size; + + return 0; } static int dfu_read_medium_nand(struct dfu_entity *dfu, u64 offset, void *buf, diff --git a/drivers/dfu/dfu_ram.c b/drivers/dfu/dfu_ram.c index c1b00217c9..b95cb9facf 100644 --- a/drivers/dfu/dfu_ram.c +++ b/drivers/dfu/dfu_ram.c @@ -41,9 +41,11 @@ static int dfu_write_medium_ram(struct dfu_entity *dfu, u64 offset, return dfu_transfer_medium_ram(DFU_OP_WRITE, dfu, offset, buf, len); } -long dfu_get_medium_size_ram(struct dfu_entity *dfu) +int dfu_get_medium_size_ram(struct dfu_entity *dfu, long *size) { - return dfu->data.ram.size; + *size = dfu->data.ram.size; + + return 0; } static int dfu_read_medium_ram(struct dfu_entity *dfu, u64 offset, diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index b6d5fe24dc..2b26f2c608 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -12,9 +12,11 @@ #include #include -static long dfu_get_medium_size_sf(struct dfu_entity *dfu) +static int dfu_get_medium_size_sf(struct dfu_entity *dfu, long *size) { - return dfu->data.sf.size; + *size = dfu->data.sf.size; + + return 0; } static int dfu_read_medium_sf(struct dfu_entity *dfu, u64 offset, void *buf, diff --git a/include/dfu.h b/include/dfu.h index f39d3f1171..5b621b577b 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -110,7 +110,7 @@ struct dfu_entity { struct sf_internal_data sf; } data; - long (*get_medium_size)(struct dfu_entity *dfu); + int (*get_medium_size)(struct dfu_entity *dfu, long *size); int (*read_medium)(struct dfu_entity *dfu, u64 offset, void *buf, long *len); From 15970d871c299c8a4218911ee68edb0495a69cd4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 19 Jul 2017 16:39:23 +0200 Subject: [PATCH 52/61] dfu: remove limitation on partition size Change long (32 bits on arm) to u64 (same type than offset) for size and read offset r_left So partition and device used for DFU can be greater than 4GB Signed-off-by: Patrick Delaunay --- drivers/dfu/dfu.c | 2 +- drivers/dfu/dfu_mmc.c | 10 +++++----- drivers/dfu/dfu_nand.c | 2 +- drivers/dfu/dfu_ram.c | 2 +- drivers/dfu/dfu_sf.c | 2 +- include/dfu.h | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index c77701646b..0f1ab0d9f0 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -343,7 +343,7 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if (ret < 0) return ret; - debug("%s: %s %ld [B]\n", __func__, dfu->name, dfu->r_left); + debug("%s: %s %lld [B]\n", __func__, dfu->name, dfu->r_left); dfu->i_blk_seq_num = 0; dfu->crc = 0; diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index d918f95f5c..bb23e7fdcb 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -17,7 +17,7 @@ #include static unsigned char *dfu_file_buf; -static long dfu_file_buf_len; +static u64 dfu_file_buf_len; static long dfu_file_buf_filled; static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, @@ -107,7 +107,7 @@ static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len) } static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, - void *buf, long *len) + void *buf, u64 *len) { const char *fsname, *opname; char cmd_buf[DFU_CMD_BUF_SIZE]; @@ -150,7 +150,7 @@ static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, sprintf(cmd_buf + strlen(cmd_buf), " %s", dfu->name); if (op == DFU_OP_WRITE) - sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len); + sprintf(cmd_buf + strlen(cmd_buf), " %llx", *len); debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); @@ -209,7 +209,7 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu) return ret; } -int dfu_get_medium_size_mmc(struct dfu_entity *dfu, long *size) +int dfu_get_medium_size_mmc(struct dfu_entity *dfu, u64 *size) { int ret; @@ -237,7 +237,7 @@ static int mmc_file_unbuffer(struct dfu_entity *dfu, u64 offset, void *buf, long *len) { int ret; - long file_len; + u64 file_len; if (dfu_file_buf_filled == -1) { ret = mmc_file_op(DFU_OP_READ, dfu, dfu_file_buf, &file_len); diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c index ed4ceb7a07..6dc9ff7aea 100644 --- a/drivers/dfu/dfu_nand.c +++ b/drivers/dfu/dfu_nand.c @@ -114,7 +114,7 @@ static int dfu_write_medium_nand(struct dfu_entity *dfu, return ret; } -int dfu_get_medium_size_nand(struct dfu_entity *dfu, long *size) +int dfu_get_medium_size_nand(struct dfu_entity *dfu, u64 *size) { *size = dfu->data.nand.size; diff --git a/drivers/dfu/dfu_ram.c b/drivers/dfu/dfu_ram.c index b95cb9facf..6e3f5316f5 100644 --- a/drivers/dfu/dfu_ram.c +++ b/drivers/dfu/dfu_ram.c @@ -41,7 +41,7 @@ static int dfu_write_medium_ram(struct dfu_entity *dfu, u64 offset, return dfu_transfer_medium_ram(DFU_OP_WRITE, dfu, offset, buf, len); } -int dfu_get_medium_size_ram(struct dfu_entity *dfu, long *size) +int dfu_get_medium_size_ram(struct dfu_entity *dfu, u64 *size) { *size = dfu->data.ram.size; diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index 2b26f2c608..2d2586db52 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -12,7 +12,7 @@ #include #include -static int dfu_get_medium_size_sf(struct dfu_entity *dfu, long *size) +static int dfu_get_medium_size_sf(struct dfu_entity *dfu, u64 *size) { *size = dfu->data.sf.size; diff --git a/include/dfu.h b/include/dfu.h index 5b621b577b..7e322d9d27 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -110,7 +110,7 @@ struct dfu_entity { struct sf_internal_data sf; } data; - int (*get_medium_size)(struct dfu_entity *dfu, long *size); + int (*get_medium_size)(struct dfu_entity *dfu, u64 *size); int (*read_medium)(struct dfu_entity *dfu, u64 offset, void *buf, long *len); @@ -132,7 +132,7 @@ struct dfu_entity { u8 *i_buf; u8 *i_buf_start; u8 *i_buf_end; - long r_left; + u64 r_left; long b_left; u32 bad_skip; /* for nand use */ From 57da060755ac757237bd8781f7b2aef80167301e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 19 Jul 2017 16:39:24 +0200 Subject: [PATCH 53/61] dfu: factorize transaction cleanup rename cleanup function, as now called by read Signed-off-by: Patrick Delaunay --- drivers/dfu/dfu.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 0f1ab0d9f0..63a5a442ef 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -165,7 +165,7 @@ static int dfu_write_buffer_drain(struct dfu_entity *dfu) return ret; } -void dfu_write_transaction_cleanup(struct dfu_entity *dfu) +void dfu_transaction_cleanup(struct dfu_entity *dfu) { /* clear everything */ dfu->crc = 0; @@ -174,6 +174,10 @@ void dfu_write_transaction_cleanup(struct dfu_entity *dfu) dfu->i_buf_start = dfu_buf; dfu->i_buf_end = dfu_buf; dfu->i_buf = dfu->i_buf_start; + dfu->r_left = 0; + dfu->b_left = 0; + dfu->bad_skip = 0; + dfu->inited = 0; } @@ -192,7 +196,7 @@ int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) printf("\nDFU complete %s: 0x%08x\n", dfu_hash_algo->name, dfu->crc); - dfu_write_transaction_cleanup(dfu); + dfu_transaction_cleanup(dfu); return ret; } @@ -223,7 +227,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if (dfu->i_blk_seq_num != blk_seq_num) { printf("%s: Wrong sequence number! [%d] [%d]\n", __func__, dfu->i_blk_seq_num, blk_seq_num); - dfu_write_transaction_cleanup(dfu); + dfu_transaction_cleanup(dfu); return -1; } @@ -247,7 +251,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if ((dfu->i_buf + size) > dfu->i_buf_end) { ret = dfu_write_buffer_drain(dfu); if (ret) { - dfu_write_transaction_cleanup(dfu); + dfu_transaction_cleanup(dfu); return ret; } } @@ -256,7 +260,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if ((dfu->i_buf + size) > dfu->i_buf_end) { error("Buffer overflow! (0x%p + 0x%x > 0x%p)\n", dfu->i_buf, size, dfu->i_buf_end); - dfu_write_transaction_cleanup(dfu); + dfu_transaction_cleanup(dfu); return -1; } @@ -267,7 +271,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if (size == 0 || (dfu->i_buf + size) > dfu->i_buf_end) { ret = dfu_write_buffer_drain(dfu); if (ret) { - dfu_write_transaction_cleanup(dfu); + dfu_transaction_cleanup(dfu); return ret; } } @@ -377,17 +381,7 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) dfu_hash_algo->name, dfu->crc); puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); - dfu->i_blk_seq_num = 0; - dfu->crc = 0; - dfu->offset = 0; - dfu->i_buf_start = dfu_buf; - dfu->i_buf_end = dfu_buf; - dfu->i_buf = dfu->i_buf_start; - dfu->b_left = 0; - - dfu->bad_skip = 0; - - dfu->inited = 0; + dfu_transaction_cleanup(dfu); } return ret; From 6fa8dddd069db868d64948e70c40f3d75a9fa253 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 19 Jul 2017 16:39:25 +0200 Subject: [PATCH 54/61] dfu: add common function to initiate transaction - factorize code between read and write transaction - always use dfu_transaction_cleanup() to initialize the internal variable: easy maintenance - replace direct access by dfu_get_buf() and dfu_get_buf_size() Signed-off-by: Patrick Delaunay --- drivers/dfu/dfu.c | 72 ++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 63a5a442ef..f6281f4baa 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -171,8 +171,8 @@ void dfu_transaction_cleanup(struct dfu_entity *dfu) dfu->crc = 0; dfu->offset = 0; dfu->i_blk_seq_num = 0; - dfu->i_buf_start = dfu_buf; - dfu->i_buf_end = dfu_buf; + dfu->i_buf_start = dfu_get_buf(dfu); + dfu->i_buf_end = dfu->i_buf_start; dfu->i_buf = dfu->i_buf_start; dfu->r_left = 0; dfu->b_left = 0; @@ -181,6 +181,32 @@ void dfu_transaction_cleanup(struct dfu_entity *dfu) dfu->inited = 0; } +int dfu_transaction_initiate(struct dfu_entity *dfu, bool read) +{ + int ret = 0; + + if (dfu->inited) + return 0; + + dfu_transaction_cleanup(dfu); + + if (dfu->i_buf_start == NULL) + return -ENOMEM; + + dfu->i_buf_end = dfu->i_buf_start + dfu_get_buf_size(); + + if (read) { + ret = dfu->get_medium_size(dfu, &dfu->r_left); + if (ret < 0) + return ret; + debug("%s: %s %lld [B]\n", __func__, dfu->name, dfu->r_left); + } + + dfu->inited = 1; + + return 0; +} + int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) { int ret = 0; @@ -209,20 +235,9 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) __func__, dfu->name, buf, size, blk_seq_num, dfu->offset, (unsigned long)(dfu->i_buf - dfu->i_buf_start)); - if (!dfu->inited) { - /* initial state */ - dfu->crc = 0; - dfu->offset = 0; - dfu->bad_skip = 0; - dfu->i_blk_seq_num = 0; - dfu->i_buf_start = dfu_get_buf(dfu); - if (dfu->i_buf_start == NULL) - return -ENOMEM; - dfu->i_buf_end = dfu_get_buf(dfu) + dfu_buf_size; - dfu->i_buf = dfu->i_buf_start; - - dfu->inited = 1; - } + ret = dfu_transaction_initiate(dfu, false); + if (ret < 0) + return ret; if (dfu->i_blk_seq_num != blk_seq_num) { printf("%s: Wrong sequence number! [%d] [%d]\n", @@ -338,28 +353,9 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", __func__, dfu->name, buf, size, blk_seq_num, dfu->i_buf); - if (!dfu->inited) { - dfu->i_buf_start = dfu_get_buf(dfu); - if (dfu->i_buf_start == NULL) - return -ENOMEM; - - ret = dfu->get_medium_size(dfu, &dfu->r_left); - if (ret < 0) - return ret; - - debug("%s: %s %lld [B]\n", __func__, dfu->name, dfu->r_left); - - dfu->i_blk_seq_num = 0; - dfu->crc = 0; - dfu->offset = 0; - dfu->i_buf_end = dfu_get_buf(dfu) + dfu_buf_size; - dfu->i_buf = dfu->i_buf_start; - dfu->b_left = 0; - - dfu->bad_skip = 0; - - dfu->inited = 1; - } + ret = dfu_transaction_initiate(dfu, true); + if (ret < 0) + return ret; if (dfu->i_blk_seq_num != blk_seq_num) { printf("%s: Wrong sequence number! [%d] [%d]\n", From d9fb7bece056522d659d9e17b73b3fd5549817c3 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 24 Jul 2017 17:07:02 +0200 Subject: [PATCH 55/61] dm: phy: add missing #ifdef CONFIG_PHY To avoid compilation breakage on platform that doesn't support DM PHY but uses xhci-dwc3 driver, add the missing CONFIG_PHY flag. Introduced by patch : 84e53877 "usb: host: xhci-dwc3: Add generic PHY support" Cc: Ran Wang Cc: Bin Meng Signed-off-by: Patrice Chotard Reported-by: Ran Wang --- include/generic-phy.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/generic-phy.h b/include/generic-phy.h index 58cd2b26a9..eac5adc893 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -122,6 +122,7 @@ struct phy_ops { int (*power_off)(struct phy *phy); }; +#ifdef CONFIG_PHY /** * generic_phy_init() - initialize the PHY port @@ -220,6 +221,47 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy); +#else /* CONFIG_PHY */ + +static inline int generic_phy_init(struct phy *phy) +{ + return 0; +} + +static inline int generic_phy_exit(struct phy *phy) +{ + return 0; +} + +static inline int generic_phy_reset(struct phy *phy) +{ + return 0; +} + +static inline int generic_phy_power_on(struct phy *phy) +{ + return 0; +} + +static inline int generic_phy_power_off(struct phy *phy) +{ + return 0; +} + +static inline int generic_phy_get_by_index(struct udevice *user, int index, + struct phy *phy) +{ + return 0; +} + +static inline int generic_phy_get_by_name(struct udevice *user, const char *phy_name, + struct phy *phy) +{ + return 0; +} + +#endif /* CONFIG_PHY */ + /** * generic_phy_valid() - check if PHY port is valid * From 623b7aca1f82bf1dee089c77f9a1020e80abaccc Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 24 Jul 2017 17:07:03 +0200 Subject: [PATCH 56/61] dm: usb: host: xhci-dwc3: add missing #ifdef CONFIG_DM_USB Add CONFIG_DM_USB flag to avoid following compilation errors detected by buildman : +drivers/usb/host/built-in.o: In function `xhci_dwc3_remove': +drivers/usb/host/xhci-dwc3.c:168: undefined reference to `xhci_deregister' +drivers/usb/host/built-in.o: In function `xhci_dwc3_probe': +drivers/usb/host/xhci-dwc3.c:145: undefined reference to `usb_get_dr_mode' +drivers/usb/host/xhci-dwc3.c:152: undefined reference to `xhci_register' introduced by patch d5c3f014da3 "usb: host: xhci-dwc3: Convert driver to DM" Signed-off-by: Patrice Chotard Reported-by: Ran Wang --- drivers/usb/host/xhci-dwc3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 374fe743fe..541a785081 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -111,6 +111,7 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) GFLADJ_30MHZ(val)); } +#ifdef CONFIG_DM_USB static int xhci_dwc3_probe(struct udevice *dev) { struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); @@ -184,3 +185,4 @@ U_BOOT_DRIVER(xhci_dwc3) = { .platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; +#endif From 4b3928a08f24d21c2d34487b9d89fee35814bd0d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 24 Jul 2017 17:07:04 +0200 Subject: [PATCH 57/61] usb: host: ehci-generic: initialize PHY only when found Call generic_phy_init() only when a PHY was found. This will avoid a crash if no "phys" property is found in DT. Signed-off-by: Patrice Chotard Reported-by: Patrick Delaunay --- drivers/usb/host/ehci-generic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 3f751f1ecd..03f8d321af 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -99,12 +99,13 @@ static int ehci_usb_probe(struct udevice *dev) error("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"); - goto reset_err; + err = generic_phy_init(&priv->phy); + if (err) { + error("failed to init usb phy\n"); + goto reset_err; + } } hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); From 2080d023d90e2972f82dfde624d209cf5a0c569c Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 24 Jul 2017 17:07:05 +0200 Subject: [PATCH 58/61] usb: host: ohci-generic: initialize PHY only when found Call generic_phy_init() only when a PHY was found. This will avoid a crash if no "phys" property is found in DT. Signed-off-by: Patrice Chotard Reported-by: Patrick Delaunay --- drivers/usb/host/ohci-generic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index 9249039055..e22ee97939 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -91,12 +91,13 @@ static int ohci_usb_probe(struct udevice *dev) error("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"); - goto reset_err; + err = generic_phy_init(&priv->phy); + if (err) { + error("failed to init usb phy\n"); + goto reset_err; + } } err = ohci_register(dev, regs); From 3b63db37ad7e4672684bd686fcc3fc07b84e4fb9 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 24 Jul 2017 15:18:15 +0200 Subject: [PATCH 59/61] phy: add a NO-OP phy driver This driver is used to stub PHY operations in a driver (USB, SATA). This is useful when the 'client' driver (USB, SATA, ...) uses the PHY framework and there is no actual PHY harwdare to drive. Signed-off-by: Jean-Jacques Hiblot --- .../devicetree/bindings/phy/no-op.txt | 16 ++++++++++++ drivers/phy/Kconfig | 18 +++++++++++++ drivers/phy/Makefile | 1 + drivers/phy/nop-phy.c | 26 +++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/no-op.txt create mode 100644 drivers/phy/nop-phy.c diff --git a/Documentation/devicetree/bindings/phy/no-op.txt b/Documentation/devicetree/bindings/phy/no-op.txt new file mode 100644 index 0000000000..a3381122e6 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/no-op.txt @@ -0,0 +1,16 @@ +NOP PHY driver + +This driver is used to stub PHY operations in a driver (USB, SATA). +This is useful when the 'client' driver (USB, SATA, ...) uses the PHY framework +and there is no actual PHY harwdare to drive. + +Required properties: +- compatible : must contain "nop-phy" +- #phy-cells : must contain <0> + +Example: + +nop_phy { + compatible = "nop-phy"; + #phy-cells = <0>; +}; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 7841554d09..98f2a1b047 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -41,6 +41,24 @@ config PHY_SANDBOX This select a dummy sandbox PHY driver. It used only to implement the unit tests for the phy framework +config NOP_PHY + bool "NOP PHY driver" + depends on PHY + help + Support for a no-op PHY driver (stubbed PHY driver). + + This is useful when a driver uses the PHY framework but no real PHY + hardware exists. + +config SPL_NOP_PHY + bool "NOP PHY driver in SPL" + depends on SPL_PHY + help + Support for a no-op PHY driver (stubbed PHY driver) in the SPL. + + This is useful when a driver uses the PHY framework but no real PHY + hardware exists. + config PIPE3_PHY bool "Support omap's PIPE3 PHY" depends on PHY && ARCH_OMAP2PLUS diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 6ce96d2ccc..ab56c46bb4 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -6,5 +6,6 @@ # obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o +obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o diff --git a/drivers/phy/nop-phy.c b/drivers/phy/nop-phy.c new file mode 100644 index 0000000000..2201cc35bf --- /dev/null +++ b/drivers/phy/nop-phy.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * Written by Jean-Jacques Hiblot + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +static const struct udevice_id nop_phy_ids[] = { + { .compatible = "nop-phy" }, + { } +}; + +static struct phy_ops nop_phy_ops = { +}; + +U_BOOT_DRIVER(nop_phy) = { + .name = "nop_phy", + .id = UCLASS_PHY, + .of_match = nop_phy_ids, + .ops = &nop_phy_ops, +}; From d38a8ea19c1d82296619557069618aaefc1ad977 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 25 Jul 2017 13:24:44 +0200 Subject: [PATCH 60/61] usb: host: xhci-dxc3: fix compilation warnings Fix following warnings encountered with platforms dra7xx_evm and dra7xx_hs_evm : arm: + dra7xx_evm + hccr = (struct xhci_hccr *)devfdt_get_addr(dev); + ^ + hcor = (struct xhci_hcor *)((phys_addr_t)hccr + + ^ w+drivers/usb/host/xhci-dwc3.c: In function 'xhci_dwc3_probe': w+drivers/usb/host/xhci-dwc3.c:124:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] w+drivers/usb/host/xhci-dwc3.c:125:30: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] w+drivers/usb/host/xhci-dwc3.c:125:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] arm: + dra7xx_hs_evm + hccr = (struct xhci_hccr *)devfdt_get_addr(dev); + ^ + hcor = (struct xhci_hcor *)((phys_addr_t)hccr + + ^ w+drivers/usb/host/xhci-dwc3.c: In function 'xhci_dwc3_probe': w+drivers/usb/host/xhci-dwc3.c:124:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] w+drivers/usb/host/xhci-dwc3.c:125:30: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] w+drivers/usb/host/xhci-dwc3.c:125:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] Introduced by 7e65e84 usb: host: xhci-dwc3: Convert driver to DM Signed-off-by: Patrice Chotard --- drivers/usb/host/xhci-dwc3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 541a785081..4191a89421 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -121,8 +121,8 @@ static int xhci_dwc3_probe(struct udevice *dev) enum usb_dr_mode dr_mode; int ret; - hccr = (struct xhci_hccr *)devfdt_get_addr(dev); - hcor = (struct xhci_hcor *)((phys_addr_t)hccr + + hccr = (struct xhci_hccr *)((uintptr_t)dev_read_addr(dev)); + hcor = (struct xhci_hcor *)((uintptr_t)hccr + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); ret = generic_phy_get_by_index(dev, 0, &plat->usb_phy); From b108d8a0de3ddc6fe8aae55bc54e3edc69b4778b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 25 Jul 2017 13:24:45 +0200 Subject: [PATCH 61/61] clk: fix compilation errors for poplar platform Move clk_release_all() prototype and definition inside OF_CONTROL flag to avoid following compilation error for poplar platform: aarch64: + poplar +drivers/usb/host/built-in.o: In function `ehci_usb_remove': +drivers/usb/host/ehci-generic.c:159: undefined reference to `clk_release_all' +drivers/usb/host/built-in.o: In function `ehci_usb_probe': +drivers/usb/host/ehci-generic.c:133: undefined reference to `clk_release_all' +make[1]: *** [u-boot] Error 139 +make: *** [sub-make] Error 2 Introduced by 4e542c4 clk: add clk_release_all() Signed-off-by: Patrice Chotard --- drivers/clk/clk-uclass.c | 47 ++++++++++++++++++++-------------------- include/clk.h | 35 ++++++++++++++++++------------ 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index ffbe872f34..e68d9279b9 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -114,6 +114,30 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) return clk_get_by_index(dev, index, clk); } + +int clk_release_all(struct clk *clk, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]); + + /* check if clock has been previously requested */ + if (!clk[i].dev) + continue; + + ret = clk_disable(&clk[i]); + if (ret && ret != -ENOSYS) + return ret; + + ret = clk_free(&clk[i]); + if (ret && ret != -ENOSYS) + return ret; + } + + return 0; +} + #endif /* OF_CONTROL */ int clk_request(struct udevice *dev, struct clk *clk) @@ -190,29 +214,6 @@ int clk_disable(struct clk *clk) return ops->disable(clk); } -int clk_release_all(struct clk *clk, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]); - - /* check if clock has been previously requested */ - if (!clk[i].dev) - continue; - - ret = clk_disable(&clk[i]); - if (ret && ret != -ENOSYS) - return ret; - - ret = clk_free(&clk[i]); - if (ret && ret != -ENOSYS) - return ret; - } - - return 0; -} - UCLASS_DRIVER(clk) = { .id = UCLASS_CLK, .name = "clk", diff --git a/include/clk.h b/include/clk.h index a905a4143f..c5988f78a8 100644 --- a/include/clk.h +++ b/include/clk.h @@ -98,6 +98,21 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk); * @return 0 if OK, or a negative error code. */ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk); + +/** + * clk_release_all() - Disable (turn off)/Free an array of previously + * requested clocks. + * + * For each clock contained in the clock array, this function will check if + * clock has been previously requested and then will disable and free it. + * + * @clk: A clock struct array that was previously successfully + * requested by clk_request/get_by_*(). + * @count Number of clock contained in the array + * @return zero on success, or -ve error code. + */ +int clk_release_all(struct clk *clk, int count); + #else static inline int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) @@ -110,6 +125,12 @@ static inline int clk_get_by_name(struct udevice *dev, const char *name, { return -ENOSYS; } + +static inline int clk_release_all(struct clk *clk, int count) +{ + return -ENOSYS; +} + #endif /** @@ -174,20 +195,6 @@ int clk_enable(struct clk *clk); */ int clk_disable(struct clk *clk); -/** - * clk_release_all() - Disable (turn off)/Free an array of previously - * requested clocks. - * - * For each clock contained in the clock array, this function will check if - * clock has been previously requested and then will disable and free it. - * - * @clk: A clock struct array that was previously successfully - * requested by clk_request/get_by_*(). - * @count Number of clock contained in the array - * @return zero on success, or -ve error code. - */ -int clk_release_all(struct clk *clk, int count); - int soc_clk_dump(void); #endif