mirror of
https://github.com/LineageOS/android_kernel_samsung_msm8226.git
synced 2026-09-28 00:00:22 +02:00
USB: ehci-msm2: Correct USB PHY RESET sequence
Existing code assumes that USB PHY is reset as part of block reset using GCC, but that is not the case. This results in PHY access failures later when ulpi accesses are performed, or device enumeration fails as CORE can't access PHY. Correct PHY reset sequence by using USB_PHY_PON bit with USB_OTG_HS_PHY_CTRL register as per hardware programming guidelines. Since, driver supports selection of primary or secondary PHY with CI controller, choose PHY_CTRL_REG accordingly. Also, debug out important USB register when ulpi read/write timeout is seen with USB PHY. CRs-fixed: 676343 Change-Id: Ie69e44a1134c1f4458619ae93520e722aad9e0c8 Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
This commit is contained in:
@@ -82,6 +82,7 @@ struct msm_hcd {
|
||||
bool wakeup_irq_enabled;
|
||||
int wakeup_irq;
|
||||
enum usb_vdd_type vdd_type;
|
||||
void __iomem *usb_phy_ctrl_reg;
|
||||
};
|
||||
|
||||
static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
|
||||
@@ -497,6 +498,9 @@ static int msm_ulpi_read(struct msm_hcd *mhcd, u32 reg)
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(mhcd->dev, "msm_ulpi_read: timeout %08x\n",
|
||||
readl_relaxed(USB_ULPI_VIEWPORT));
|
||||
dev_err(mhcd->dev, "PORTSC: %08x USBCMD: %08x\n",
|
||||
readl_relaxed(USB_PORTSC),
|
||||
readl_relaxed(USB_USBCMD));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
@@ -521,6 +525,9 @@ static int msm_ulpi_write(struct msm_hcd *mhcd, u32 val, u32 reg)
|
||||
while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(mhcd->dev, "msm_ulpi_write: timeout\n");
|
||||
dev_err(mhcd->dev, "PORTSC: %08x USBCMD: %08x\n",
|
||||
readl_relaxed(USB_PORTSC),
|
||||
readl_relaxed(USB_USBCMD));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
@@ -572,13 +579,13 @@ static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
|
||||
struct msm_usb_host_platform_data *pdata;
|
||||
u32 val;
|
||||
int ret;
|
||||
int retries;
|
||||
|
||||
ret = msm_ehci_link_clk_reset(mhcd, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(10, 12);
|
||||
/* Minimum 10msec delay for block reset as per hardware spec */
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
ret = msm_ehci_link_clk_reset(mhcd, 0);
|
||||
if (ret)
|
||||
@@ -592,29 +599,34 @@ static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
|
||||
val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
|
||||
writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
|
||||
|
||||
for (retries = 3; retries > 0; retries--) {
|
||||
ret = msm_ulpi_write(mhcd, ULPI_FUNC_CTRL_SUSPENDM,
|
||||
ULPI_CLR(ULPI_FUNC_CTRL));
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
if (!retries)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Wakeup the PHY with a reg-access for calibration */
|
||||
for (retries = 3; retries > 0; retries--) {
|
||||
ret = msm_ulpi_read(mhcd, ULPI_DEBUG);
|
||||
if (ret != -ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
if (!retries)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
dev_info(mhcd->dev, "phy_reset: success\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_phy_reset(struct msm_hcd *mhcd)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Assert USB PHY_PON */
|
||||
val = readl_relaxed(mhcd->usb_phy_ctrl_reg);
|
||||
val &= ~PHY_POR_BIT_MASK;
|
||||
val |= PHY_POR_ASSERT;
|
||||
writel_relaxed(val, mhcd->usb_phy_ctrl_reg);
|
||||
|
||||
/* wait for minimum 10 microseconds as suggested in hardware spec */
|
||||
usleep_range(10, 15);
|
||||
|
||||
/* Deassert USB PHY_PON */
|
||||
val = readl_relaxed(mhcd->usb_phy_ctrl_reg);
|
||||
val &= ~PHY_POR_BIT_MASK;
|
||||
val |= PHY_POR_DEASSERT;
|
||||
writel_relaxed(val, mhcd->usb_phy_ctrl_reg);
|
||||
|
||||
/* Ensure that RESET operation is completed. */
|
||||
mb();
|
||||
}
|
||||
|
||||
#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
|
||||
static int msm_hsusb_reset(struct msm_hcd *mhcd)
|
||||
{
|
||||
@@ -649,6 +661,9 @@ static int msm_hsusb_reset(struct msm_hcd *mhcd)
|
||||
writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
|
||||
USB_PHY_CTRL2);
|
||||
|
||||
/* Reset USB PHY after performing USB Link RESET */
|
||||
usb_phy_reset(mhcd);
|
||||
|
||||
msleep(100);
|
||||
|
||||
writel_relaxed(0x0, USB_AHBBURST);
|
||||
@@ -1523,6 +1538,13 @@ static int __devinit ehci_msm2_probe(struct platform_device *pdev)
|
||||
goto disable_ldo;
|
||||
}
|
||||
|
||||
pdata = mhcd->dev->platform_data;
|
||||
|
||||
if (pdata && pdata->use_sec_phy)
|
||||
mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL2;
|
||||
else
|
||||
mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL;
|
||||
|
||||
ret = msm_hsusb_reset(mhcd);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "hsusb PHY initialization failed\n");
|
||||
@@ -1535,7 +1557,6 @@ static int __devinit ehci_msm2_probe(struct platform_device *pdev)
|
||||
goto vbus_deinit;
|
||||
}
|
||||
|
||||
pdata = mhcd->dev->platform_data;
|
||||
if (pdata && (!pdata->dock_connect_irq ||
|
||||
!irq_read_line(pdata->dock_connect_irq)))
|
||||
msm_ehci_vbus_power(mhcd, 1);
|
||||
|
||||
Reference in New Issue
Block a user