
On 02/05/2024 15:16, Sam Day wrote:
This seems to be necessary on my samsung-a5. Without this patch, the first access of EHCI registers causes a bus stall and subsequent reset.
I am unsure why this wasn't already necessary for db410c, perhaps those clocks are already enabled on boot.
Signed-off-by: Sam Day me@samcday.com
drivers/usb/host/ehci-msm.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 98fe7bc3bc..b2e294dd64 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -7,8 +7,10 @@
- Based on Linux driver
*/
+#include <clk.h> #include <common.h> #include <dm.h> +#include <dm/device_compat.h> #include <dm/lists.h> #include <errno.h> #include <usb.h> @@ -25,6 +27,8 @@ struct msm_ehci_priv { struct usb_ehci *ehci; /* Start of IP core*/ struct ulpi_viewport ulpi_vp; /* ULPI Viewport */ struct phy phy;
- struct clk iface_clk;
- struct clk core_clk;
You could simplify this with the bulk clock API, but I'm easy either way.
Reviewed-by: Caleb Connolly caleb.connolly@linaro.org
};
static int msm_init_after_reset(struct ehci_ctrl *dev) @@ -53,20 +57,46 @@ static int ehci_usb_probe(struct udevice *dev) struct ehci_hcor *hcor; int ret;
ret = clk_get_by_name(dev, "core", &p->core_clk);
if (ret) {
dev_err(dev, "Failed to get core clock: %d\n", ret);
return ret;
}
ret = clk_get_by_name(dev, "iface", &p->iface_clk);
if (ret) {
dev_err(dev, "Failed to get iface clock: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(&p->core_clk);
if (ret)
return ret;
ret = clk_prepare_enable(&p->iface_clk);
if (ret)
goto cleanup_core;
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength); hcor = (struct ehci_hcor *)((phys_addr_t)hccr + HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
ret = generic_setup_phy(dev, &p->phy, 0); if (ret)
return ret;
goto cleanup_iface;
ret = board_usb_init(0, plat->init_type); if (ret < 0)
return ret;
goto cleanup_iface;
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, plat->init_type);
+cleanup_iface:
- clk_disable_unprepare(&p->iface_clk);
+cleanup_core:
clk_disable_unprepare(&p->core_clk);
return ret; }
static int ehci_usb_remove(struct udevice *dev)
@@ -82,6 +112,9 @@ static int ehci_usb_remove(struct udevice *dev) /* Stop controller. */ clrbits_le32(&ehci->usbcmd, CMD_RUN);
- clk_disable_unprepare(&p->iface_clk);
- clk_disable_unprepare(&p->core_clk);
- ret = generic_shutdown_phy(&p->phy); if (ret) return ret;