mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
ehci: msm: bring up iface + core clocks
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. Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org> Signed-off-by: Sam Day <me@samcday.com> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
This commit is contained in:
@@ -7,7 +7,9 @@
|
|||||||
* Based on Linux driver
|
* Based on Linux driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <clk.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
|
#include <dm/device_compat.h>
|
||||||
#include <dm/lists.h>
|
#include <dm/lists.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
@@ -24,6 +26,8 @@ struct msm_ehci_priv {
|
|||||||
struct usb_ehci *ehci; /* Start of IP core*/
|
struct usb_ehci *ehci; /* Start of IP core*/
|
||||||
struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
|
struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
|
||||||
struct phy phy;
|
struct phy phy;
|
||||||
|
struct clk iface_clk;
|
||||||
|
struct clk core_clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int msm_init_after_reset(struct ehci_ctrl *dev)
|
static int msm_init_after_reset(struct ehci_ctrl *dev)
|
||||||
@@ -52,20 +56,46 @@ static int ehci_usb_probe(struct udevice *dev)
|
|||||||
struct ehci_hcor *hcor;
|
struct ehci_hcor *hcor;
|
||||||
int ret;
|
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);
|
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
|
||||||
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
|
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
|
||||||
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
|
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
|
||||||
|
|
||||||
ret = generic_setup_phy(dev, &p->phy, 0);
|
ret = generic_setup_phy(dev, &p->phy, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto cleanup_iface;
|
||||||
|
|
||||||
ret = board_usb_init(0, plat->init_type);
|
ret = board_usb_init(0, plat->init_type);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto cleanup_iface;
|
||||||
|
|
||||||
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
|
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
|
||||||
plat->init_type);
|
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)
|
static int ehci_usb_remove(struct udevice *dev)
|
||||||
@@ -81,6 +111,9 @@ static int ehci_usb_remove(struct udevice *dev)
|
|||||||
/* Stop controller. */
|
/* Stop controller. */
|
||||||
clrbits_le32(&ehci->usbcmd, CMD_RUN);
|
clrbits_le32(&ehci->usbcmd, CMD_RUN);
|
||||||
|
|
||||||
|
clk_disable_unprepare(&p->iface_clk);
|
||||||
|
clk_disable_unprepare(&p->core_clk);
|
||||||
|
|
||||||
ret = generic_shutdown_phy(&p->phy);
|
ret = generic_shutdown_phy(&p->phy);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user