[PATCH] usb: ehci-vf: take the controller index from the device tree
Mehmet Fide <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
From: Mehmet Fide <[email protected]> "usb start" dies with a data abort on a Colibri VF50 and on a Colibri VF61, and the watchdog resets the board: Colibri VFxx # usb start starting USB... Bus usb@40034000: Port not available. data abort ... r4 : 00000003 Resetting CPU ... vf_usb_of_to_plat() takes the controller index from dev_seq(), but the sequence numbers of the two controllers are 2 and 3: Class Seq Probed Driver Name usb 2 [ ] ehci_vf usb@40034000 usb 3 [ ] ehci_vf usb@400b4000 uclass_find_next_free_seq() starts numbering above the highest alias of the uclass, and fdtdec_get_alias_highest_id() matches an alias by its name prefix plus trailing digits, so the usbphy0 and usbphy1 aliases of the vf device tree count as "usb" aliases and reserve 0 and 1. The two controllers have no aliases of their own and end up with 2 and 3, past the two entries of phy_bases[] and nc_reg_bases[]. usb_oc_config() then loads a base address from beyond the table and writes to it, which is the abort above. The bounds check that would have caught this only exists in the non-DM ehci_hcd_init(). Follow the fsl,usbphy phandle, as ehci-mx6 does, and map the PHY node to the index of the driver's own table instead of trusting the sequence number, since the alias numbering is what goes wrong here. Tested on a Colibri VF50 V1.2A on an Iris carrier, U-Boot 2026.07 from NAND: "usb start" now brings up the host controller and enumerates the root hub instead of resetting the board. Signed-off-by: Mehmet Fide <[email protected]> --- drivers/usb/host/ehci-vf.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c index 96d1363a76e..32fe05920d0 100644 --- a/drivers/usb/host/ehci-vf.c +++ b/drivers/usb/host/ehci-vf.c @@ -221,8 +221,23 @@ static int vf_usb_of_to_plat(struct udevice *dev) const void *dt_blob = gd->fdt_blob; int node = dev_of_offset(dev); const char *mode; + fdt_addr_t phy_addr; + ofnode phy_node; + int i; - priv->portnr = dev_seq(dev); + phy_node = ofnode_parse_phandle(dev_ofnode(dev), "fsl,usbphy", 0); + if (!ofnode_valid(phy_node)) + return -EINVAL; + + phy_addr = ofnode_get_addr(phy_node); + for (i = 0; i < ARRAY_SIZE(phy_bases); i++) { + if (phy_addr == phy_bases[i]) + break; + } + if (i == ARRAY_SIZE(phy_bases)) + return -EINVAL; + + priv->portnr = i; priv->ehci = dev_read_addr_ptr(dev); mode = fdt_getprop(dt_blob, node, "dr_mode", NULL); -- 2.54.0