1
0
Fork 0

MLK-18794-2 usb: cdns: improve the suspend routine for xhci host

The controller needs to set CFG_RXDET_P3_EN within 100ms after
USB3 port is set to U3, but when there is a USB3 HUB in port, the
USB2 port bus suspend may take more than 100ms to finish, it causes
disconnection and PHY can't enter low power mode in system suspend
routine.

To fix this issue, we implement the platform .bus_suspend, and set
CFG_RXDET_P3_EN just after xhci_bus_suspend. The LPM_2_STB_SWITCH_EN
only needs to be set one time, and OTG_STB_CLK_SWITCH_EN isn't needed
to set for host/device mode according to IC engineer's sugguestion.

Signed-off-by: Peter Chen <peter.chen@nxp.com>
(cherry picked from commit 2bc2bc9d40a5af5e8147b9281dd3c01c6dfe40d2)
5.4-rM2-2.2.x-imx-squashed
Peter Chen 2018-08-15 15:12:12 +08:00 committed by Dong Aisheng
parent 7299512a54
commit 065da5c38e
2 changed files with 34 additions and 19 deletions

View File

@ -134,6 +134,7 @@ static void cdns_set_role(struct cdns3 *cdns, enum cdns3_roles role)
{
u32 value;
int timeout_us = 100000;
void __iomem *xhci_regs = cdns->xhci_regs;
if (role == CDNS3_ROLE_END)
return;
@ -190,6 +191,10 @@ static void cdns_set_role(struct cdns3 *cdns, enum cdns3_roles role)
if (timeout_us <= 0)
dev_err(cdns->dev, "wait xhci_power_on_ready timeout\n");
value = readl(xhci_regs + XECP_PORT_CAP_REG);
value |= LPM_2_STB_SWITCH_EN;
writel(value, xhci_regs + XECP_PORT_CAP_REG);
mdelay(1);
dev_dbg(cdns->dev, "switch to host role successfully\n");
@ -704,23 +709,9 @@ static void cdns3_enter_suspend(struct cdns3 *cdns, bool suspend, bool wakeup)
disable_irq(cdns->irq);
if (suspend) {
value = readl(otg_regs + OTGREFCLK);
value |= OTG_STB_CLK_SWITCH_EN;
writel(value, otg_regs + OTGREFCLK);
value = readl(xhci_regs + XECP_PORT_CAP_REG);
value |= LPM_2_STB_SWITCH_EN;
writel(value, xhci_regs + XECP_PORT_CAP_REG);
if (cdns3_role(cdns)->suspend)
cdns3_role(cdns)->suspend(cdns, wakeup);
/*
* SW should ensure LPM_2_STB_SWITCH_EN and RXDET_IN_P3_32KHZ
* are aligned before setting CFG_RXDET_P3_EN
*/
value = readl(xhci_regs + XECP_AUX_CTRL_REG1);
value |= CFG_RXDET_P3_EN;
writel(value, xhci_regs + XECP_AUX_CTRL_REG1);
/* SW request low power when all usb ports allow to it ??? */
value = readl(xhci_regs + XECP_PM_PMCSR);
value |= PS_D0;

View File

@ -26,6 +26,7 @@
#include "core.h"
#include "host-export.h"
#include "cdns3-nxp-reg-def.h"
static struct hc_driver __read_mostly xhci_cdns3_hc_driver;
@ -56,14 +57,36 @@ static int xhci_cdns3_setup(struct usb_hcd *hcd)
return 0;
}
static const struct xhci_driver_overrides xhci_cdns3_overrides __initconst = {
.extra_priv_size = sizeof(struct xhci_hcd),
.reset = xhci_cdns3_setup,
};
struct cdns3_host {
struct device dev;
struct usb_hcd *hcd;
struct cdns3 *cdns;
};
static int xhci_cdns3_bus_suspend(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
struct cdns3_host *host = container_of(dev, struct cdns3_host, dev);
struct cdns3 *cdns = host->cdns;
void __iomem *xhci_regs = cdns->xhci_regs;
u32 value;
int ret;
ret = xhci_bus_suspend(hcd);
if (ret)
return ret;
value = readl(xhci_regs + XECP_AUX_CTRL_REG1);
value |= CFG_RXDET_P3_EN;
writel(value, xhci_regs + XECP_AUX_CTRL_REG1);
return 0;
}
static const struct xhci_driver_overrides xhci_cdns3_overrides __initconst = {
.extra_priv_size = sizeof(struct xhci_hcd),
.reset = xhci_cdns3_setup,
.bus_suspend = xhci_cdns3_bus_suspend,
};
static irqreturn_t cdns3_host_irq(struct cdns3 *cdns)
@ -107,6 +130,7 @@ static int cdns3_host_start(struct cdns3 *cdns)
dev->parent = cdns->dev;
dev_set_name(dev, "xhci-cdns3");
cdns->host_dev = dev;
host->cdns = cdns;
ret = device_register(dev);
if (ret)
goto err1;