diff mbox series

[2/2] ehci: msm: bring up iface + core clocks

Message ID 20240502-msm8916-hs-usb-clocks-v1-2-eeccf483b68d@samcday.com
State Superseded
Delegated to: Caleb Connolly
Headers show
Series qcom: ehci: enable core + iface clocks | expand

Commit Message

Sam Day May 2, 2024, 1:16 p.m. UTC
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(-)

Comments

Caleb Connolly May 2, 2024, 1:39 p.m. UTC | #1
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;
>
diff mbox series

Patch

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;
 };
 
 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;