Message ID | 20200523232304.23976-4-peter.chen@nxp.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | usb: some PM changes for cdns3 and xhci-plat | expand |
Hi > -----Original Message----- > From: Peter Chen <peter.chen@nxp.com> > Sent: 2020年5月24日 7:23 > To: balbi@kernel.org; mathias.nyman@intel.com > Cc: linux-usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; > pawell@cadence.com; rogerq@ti.com; gregkh@linuxfoundation.org; Jun Li > <jun.li@nxp.com>; Peter Chen <peter.chen@nxp.com> > Subject: [PATCH v2 3/9] usb: cdns3: imx: add glue layer runtime pm implementation > > Add imx glue layer runtime pm implementation, and the runtime pm is default off. > > Signed-off-by: Peter Chen <peter.chen@nxp.com> > --- > drivers/usb/cdns3/cdns3-imx.c | 179 +++++++++++++++++++++++++++++++++- > 1 file changed, 177 insertions(+), 2 deletions(-) > > diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c index > aba988e71958..9d247de8e7eb 100644 > --- a/drivers/usb/cdns3/cdns3-imx.c > +++ b/drivers/usb/cdns3/cdns3-imx.c > @@ -15,6 +15,8 @@ > #include <linux/io.h> > #include <linux/of_platform.h> > #include <linux/iopoll.h> > +#include <linux/pm_runtime.h> > +#include "core.h" > > #define USB3_CORE_CTRL1 0x00 > #define USB3_CORE_CTRL2 0x04 > @@ -66,11 +68,30 @@ > #define CLK_VALID_COMPARE_BITS (0xf << 28) GENMASK(31, 28) > #define PHY_REFCLK_REQ (1 << 0) BIT(0), also for others > > +/* OTG registers definition */ > +#define OTGSTS 0x4 > +/* OTGSTS */ > +#define OTG_NRDY (1 << 11) > + > +/* xHCI registers definition */ > +#define XECP_PM_PMCSR 0x8018 > +#define XECP_AUX_CTRL_REG1 0x8120 > + > +/* Register bits definition */ > +/* XECP_AUX_CTRL_REG1 */ > +#define CFG_RXDET_P3_EN (1 << 15) > + > +/* XECP_PM_PMCSR */ > +#define PS_MASK (3 << 0) > +#define PS_D0 0 > +#define PS_D1 (1 << 0) > + > struct cdns_imx { > struct device *dev; > void __iomem *noncore; > struct clk_bulk_data *clks; > int num_clks; > + struct platform_device *cdns3_pdev; > }; > > static inline u32 cdns_imx_readl(struct cdns_imx *data, u32 offset) @@ -126,6 > +147,20 @@ static int cdns_imx_noncore_init(struct cdns_imx *data) > return ret; > } > > +static int cdns_imx_platform_suspend(struct device *dev, > + bool suspend, bool wakeup); > +static struct cdns3_platform_data cdns_imx_pdata = { > + .platform_suspend = cdns_imx_platform_suspend, }; > + > +static struct of_dev_auxdata cdns_imx_auxdata[] = { > + { > + .compatible = "cdns,usb3", > + .platform_data = &cdns_imx_pdata, > + }, > + {}, > +}; > + > static int cdns_imx_probe(struct platform_device *pdev) { > struct device *dev = &pdev->dev; > @@ -162,14 +197,18 @@ static int cdns_imx_probe(struct platform_device *pdev) > if (ret) > goto err; > > - ret = of_platform_populate(node, NULL, NULL, dev); > + ret = of_platform_populate(node, NULL, cdns_imx_auxdata, dev); > if (ret) { > dev_err(dev, "failed to create children: %d\n", ret); > goto err; > } > > - return ret; > + device_set_wakeup_capable(dev, true); > + pm_runtime_set_active(dev); > + pm_runtime_enable(dev); > + pm_runtime_forbid(dev); > > + return ret; > err: > clk_bulk_disable_unprepare(data->num_clks, data->clks); > return ret; > @@ -194,6 +233,141 @@ static int cdns_imx_remove(struct platform_device *pdev) > return 0; > } > > +#ifdef CONFIG_PM > +static void cdns3_set_wakeup(struct cdns_imx *data, bool enable) { > + u32 value; > + > + value = cdns_imx_readl(data, USB3_INT_REG); > + if (enable) > + value |= OTG_WAKEUP_EN | DEVU3_WAEKUP_EN; > + else > + value &= ~(OTG_WAKEUP_EN | DEVU3_WAEKUP_EN); > + > + cdns_imx_writel(data, USB3_INT_REG, value); } > + > +static int cdns_imx_platform_suspend(struct device *dev, > + bool suspend, bool wakeup) > +{ > + struct cdns3 *cdns = dev_get_drvdata(dev); > + struct device *parent = dev->parent; > + struct cdns_imx *data = dev_get_drvdata(parent); > + void __iomem *otg_regs = cdns->otg_regs; > + void __iomem *xhci_regs = cdns->xhci_regs; > + u32 value; > + int ret = 0; > + > + if (cdns->role != USB_ROLE_HOST) > + return 0; > + > + if (suspend) { > + /* SW request low power when all usb ports allow to it ??? */ > + value = readl(xhci_regs + XECP_PM_PMCSR); > + value &= ~PS_MASK; > + value |= PS_D1; > + writel(value, xhci_regs + XECP_PM_PMCSR); > + > + /* mdctrl_clk_sel */ > + value = cdns_imx_readl(data, USB3_CORE_CTRL1); > + value |= MDCTRL_CLK_SEL; > + cdns_imx_writel(data, USB3_CORE_CTRL1, value); > + > + /* wait for mdctrl_clk_status */ > + value = cdns_imx_readl(data, USB3_CORE_STATUS); > + ret = readl_poll_timeout_atomic(data->noncore + USB3_CORE_STATUS, value, > + (value & MDCTRL_CLK_STATUS) == MDCTRL_CLK_STATUS, > + 10, 100000); > + if (ret) > + dev_warn(parent, "wait mdctrl_clk_status timeout\n"); > + > + /* wait lpm_clk_req to be 0 */ > + value = cdns_imx_readl(data, USB3_INT_REG); > + ret = readl_poll_timeout_atomic(data->noncore + USB3_INT_REG, value, > + (value & LPM_CLK_REQ) != LPM_CLK_REQ, > + 10, 100000); > + if (ret) > + dev_warn(parent, "wait lpm_clk_req timeout\n"); > + > + /* wait phy_refclk_req to be 0 */ > + value = cdns_imx_readl(data, USB3_SSPHY_STATUS); > + ret = readl_poll_timeout_atomic(data->noncore + USB3_SSPHY_STATUS, value, > + (value & PHY_REFCLK_REQ) != PHY_REFCLK_REQ, > + 10, 100000); > + if (ret) > + dev_warn(parent, "wait phy_refclk_req timeout\n"); > + > + cdns3_set_wakeup(data, wakeup); > + } else { > + /* wait CLK_125_REQ to be 1 */ > + value = cdns_imx_readl(data, USB3_INT_REG); > + ret = readl_poll_timeout_atomic(data->noncore + USB3_INT_REG, value, > + (value & CLK_125_REQ) != CLK_125_REQ, > + 10, 100000); > + if (ret) > + dev_warn(parent, "wait CLK_125_REQ timeout\n"); > + > + cdns3_set_wakeup(data, false); > + > + /* SW request D0 */ > + value = readl(xhci_regs + XECP_PM_PMCSR); > + value &= ~PS_MASK; > + value |= PS_D0; > + writel(value, xhci_regs + XECP_PM_PMCSR); > + > + /* clr 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); > + > + /* clear mdctrl_clk_sel */ > + value = cdns_imx_readl(data, USB3_CORE_CTRL1); > + value &= ~MDCTRL_CLK_SEL; > + cdns_imx_writel(data, USB3_CORE_CTRL1, value); > + > + /* wait for mdctrl_clk_status is cleared */ > + value = cdns_imx_readl(data, USB3_CORE_STATUS); > + ret = readl_poll_timeout_atomic(data->noncore + USB3_CORE_STATUS, value, > + (value & MDCTRL_CLK_STATUS) != MDCTRL_CLK_STATUS, > + 10, 100000); > + if (ret) > + dev_warn(parent, "wait mdctrl_clk_status cleared timeout\n"); > + > + /* Wait until OTG_NRDY is 0 */ > + value = readl(otg_regs + OTGSTS); > + ret = readl_poll_timeout_atomic(otg_regs + OTGSTS, value, > + (value & OTG_NRDY) != OTG_NRDY, > + 10, 100000); > + if (ret) > + dev_warn(parent, "wait OTG ready timeout\n"); Make sense to move forward if any of above timeout happens? Li Jun > + } > + > + return ret; > + > +} > + > +static int cdns_imx_resume(struct device *dev) { > + struct cdns_imx *data = dev_get_drvdata(dev); > + > + return clk_bulk_prepare_enable(data->num_clks, data->clks); } > + > +static int cdns_imx_suspend(struct device *dev) { > + struct cdns_imx *data = dev_get_drvdata(dev); > + > + clk_bulk_disable_unprepare(data->num_clks, data->clks); > + > + return 0; > +} > + > +#endif /* CONFIG_PM */ > + > +static const struct dev_pm_ops cdns_imx_pm_ops = { > + SET_RUNTIME_PM_OPS(cdns_imx_suspend, cdns_imx_resume, NULL) }; > + > static const struct of_device_id cdns_imx_of_match[] = { > { .compatible = "fsl,imx8qm-usb3", }, > {}, > @@ -206,6 +380,7 @@ static struct platform_driver cdns_imx_driver = { > .driver = { > .name = "cdns3-imx", > .of_match_table = cdns_imx_of_match, > + .pm = &cdns_imx_pm_ops, > }, > }; > module_platform_driver(cdns_imx_driver); > -- > 2.17.1
On 20-05-24 06:55:02, Jun Li wrote: > > > > #define USB3_CORE_CTRL1 0x00 > > #define USB3_CORE_CTRL2 0x04 > > @@ -66,11 +68,30 @@ > > #define CLK_VALID_COMPARE_BITS (0xf << 28) > > GENMASK(31, 28) > > > #define PHY_REFCLK_REQ (1 << 0) > > BIT(0), also for others Will change for all. > > > > > +/* OTG registers definition */ > > +#define OTGSTS 0x4 > > +/* OTGSTS */ > > +#define OTG_NRDY (1 << 11) > > + > > +/* xHCI registers definition */ > > +#define XECP_PM_PMCSR 0x8018 > > +#define XECP_AUX_CTRL_REG1 0x8120 > > + > > +/* Register bits definition */ > > +/* XECP_AUX_CTRL_REG1 */ > > +#define CFG_RXDET_P3_EN (1 << 15) > > + > > +/* XECP_PM_PMCSR */ > > +#define PS_MASK (3 << 0) > > +#define PS_D0 0 > > +#define PS_D1 (1 << 0) > > + > > + /* wait for mdctrl_clk_status is cleared */ > > + value = cdns_imx_readl(data, USB3_CORE_STATUS); > > + ret = readl_poll_timeout_atomic(data->noncore + USB3_CORE_STATUS, value, > > + (value & MDCTRL_CLK_STATUS) != MDCTRL_CLK_STATUS, > > + 10, 100000); > > + if (ret) > > + dev_warn(parent, "wait mdctrl_clk_status cleared timeout\n"); > > + > > + /* Wait until OTG_NRDY is 0 */ > > + value = readl(otg_regs + OTGSTS); > > + ret = readl_poll_timeout_atomic(otg_regs + OTGSTS, value, > > + (value & OTG_NRDY) != OTG_NRDY, > > + 10, 100000); > > + if (ret) > > + dev_warn(parent, "wait OTG ready timeout\n"); > > Make sense to move forward if any of above timeout happens? I will return -ETIMEOUT for all timeout case, thanks. Peter > > Li Jun > > > + } > > + > > + return ret; > > + > > +} > > + > > +static int cdns_imx_resume(struct device *dev) { > > + struct cdns_imx *data = dev_get_drvdata(dev); > > + > > + return clk_bulk_prepare_enable(data->num_clks, data->clks); } > > + > > +static int cdns_imx_suspend(struct device *dev) { > > + struct cdns_imx *data = dev_get_drvdata(dev); > > + > > + clk_bulk_disable_unprepare(data->num_clks, data->clks); > > + > > + return 0; > > +} > > + > > +#endif /* CONFIG_PM */ > > + > > +static const struct dev_pm_ops cdns_imx_pm_ops = { > > + SET_RUNTIME_PM_OPS(cdns_imx_suspend, cdns_imx_resume, NULL) }; > > + > > static const struct of_device_id cdns_imx_of_match[] = { > > { .compatible = "fsl,imx8qm-usb3", }, > > {}, > > @@ -206,6 +380,7 @@ static struct platform_driver cdns_imx_driver = { > > .driver = { > > .name = "cdns3-imx", > > .of_match_table = cdns_imx_of_match, > > + .pm = &cdns_imx_pm_ops, > > }, > > }; > > module_platform_driver(cdns_imx_driver); > > -- > > 2.17.1 >
Hi Peter, I love your patch! Perhaps something to improve: [auto build test WARNING on usb/usb-testing] [also build test WARNING on balbi-usb/testing/next next-20200522] [cannot apply to shawnguo/for-next v5.7-rc7] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Peter-Chen/usb-some-PM-changes-for-cdns3-and-xhci-plat/20200524-072451 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing config: s390-randconfig-s002-20200524 (attached as .config) compiler: s390-linux-gcc (GCC) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.1-240-gf0fe1cd9-dirty # save the attached .config to linux build tree make W=1 C=1 ARCH=s390 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' If you fix the issue, kindly add following tag as appropriate Reported-by: kbuild test robot <lkp@intel.com> All warnings (new ones prefixed by >>, old ones prefixed by <<): >> drivers/usb/cdns3/cdns3-imx.c:150:12: warning: 'cdns_imx_platform_suspend' used but never defined 150 | static int cdns_imx_platform_suspend(struct device *dev, | ^~~~~~~~~~~~~~~~~~~~~~~~~ vim +/cdns_imx_platform_suspend +150 drivers/usb/cdns3/cdns3-imx.c 149 > 150 static int cdns_imx_platform_suspend(struct device *dev, 151 bool suspend, bool wakeup); 152 static struct cdns3_platform_data cdns_imx_pdata = { 153 .platform_suspend = cdns_imx_platform_suspend, 154 }; 155 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 20-05-25 12:53:11, kbuild test robot wrote: > Hi Peter, > > I love your patch! Perhaps something to improve: > > [auto build test WARNING on usb/usb-testing] > [also build test WARNING on balbi-usb/testing/next next-20200522] > [cannot apply to shawnguo/for-next v5.7-rc7] > [if your patch is applied to the wrong git tree, please drop us a note to help > improve the system. BTW, we also suggest to use '--base' option to specify the > base tree in git format-patch, please see https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstackoverflow.com%2Fa%2F37406982&data=02%7C01%7Cpeter.chen%40nxp.com%7Cd98349851abc4e0abf1408d8006799d7%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637259792390096024&sdata=yRFR26%2FjlA8dg0wS4xGplfPvXtG8tYa1qb2lroSsq0Y%3D&reserved=0] > > url: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2F0day-ci%2Flinux%2Fcommits%2FPeter-Chen%2Fusb-some-PM-changes-for-cdns3-and-xhci-plat%2F20200524-072451&data=02%7C01%7Cpeter.chen%40nxp.com%7Cd98349851abc4e0abf1408d8006799d7%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637259792390096024&sdata=mJmxpr0897Sk415jiIGMg0Q7jIxAO93t%2FvUoJxAOXIg%3D&reserved=0 > base: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Fgregkh%2Fusb.git&data=02%7C01%7Cpeter.chen%40nxp.com%7Cd98349851abc4e0abf1408d8006799d7%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637259792390096024&sdata=nrCKZGGd4%2FFUKaIGm1PTn2OzeJ3XbSZvb9sn7GHgFBw%3D&reserved=0 usb-testing > config: s390-randconfig-s002-20200524 (attached as .config) > compiler: s390-linux-gcc (GCC) 9.3.0 > reproduce: > # apt-get install sparse > # sparse version: v0.6.1-240-gf0fe1cd9-dirty > # save the attached .config to linux build tree > make W=1 C=1 ARCH=s390 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' > > If you fix the issue, kindly add following tag as appropriate > Reported-by: kbuild test robot <lkp@intel.com> > > All warnings (new ones prefixed by >>, old ones prefixed by <<): > > >> drivers/usb/cdns3/cdns3-imx.c:150:12: warning: 'cdns_imx_platform_suspend' used but never defined Will fix it at next revision, thanks. Peter > 150 | static int cdns_imx_platform_suspend(struct device *dev, > | ^~~~~~~~~~~~~~~~~~~~~~~~~ > > vim +/cdns_imx_platform_suspend +150 drivers/usb/cdns3/cdns3-imx.c > > 149 > > 150 static int cdns_imx_platform_suspend(struct device *dev, > 151 bool suspend, bool wakeup); > 152 static struct cdns3_platform_data cdns_imx_pdata = { > 153 .platform_suspend = cdns_imx_platform_suspend, > 154 }; > 155 >
Hi Peter,
I love your patch! Yet something to improve:
[auto build test ERROR on usb/usb-testing]
[also build test ERROR on balbi-usb/testing/next next-20200522]
[cannot apply to shawnguo/for-next v5.7-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Peter-Chen/usb-some-PM-changes-for-cdns3-and-xhci-plat/20200524-072451
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: parisc-allyesconfig (attached as .config)
compiler: hppa-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=parisc
If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>, old ones prefixed by <<):
>> hppa-linux-ld: drivers/usb/cdns3/cdns3-imx.o:(.data+0x88): undefined reference to `cdns_imx_platform_suspend'
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c index aba988e71958..9d247de8e7eb 100644 --- a/drivers/usb/cdns3/cdns3-imx.c +++ b/drivers/usb/cdns3/cdns3-imx.c @@ -15,6 +15,8 @@ #include <linux/io.h> #include <linux/of_platform.h> #include <linux/iopoll.h> +#include <linux/pm_runtime.h> +#include "core.h" #define USB3_CORE_CTRL1 0x00 #define USB3_CORE_CTRL2 0x04 @@ -66,11 +68,30 @@ #define CLK_VALID_COMPARE_BITS (0xf << 28) #define PHY_REFCLK_REQ (1 << 0) +/* OTG registers definition */ +#define OTGSTS 0x4 +/* OTGSTS */ +#define OTG_NRDY (1 << 11) + +/* xHCI registers definition */ +#define XECP_PM_PMCSR 0x8018 +#define XECP_AUX_CTRL_REG1 0x8120 + +/* Register bits definition */ +/* XECP_AUX_CTRL_REG1 */ +#define CFG_RXDET_P3_EN (1 << 15) + +/* XECP_PM_PMCSR */ +#define PS_MASK (3 << 0) +#define PS_D0 0 +#define PS_D1 (1 << 0) + struct cdns_imx { struct device *dev; void __iomem *noncore; struct clk_bulk_data *clks; int num_clks; + struct platform_device *cdns3_pdev; }; static inline u32 cdns_imx_readl(struct cdns_imx *data, u32 offset) @@ -126,6 +147,20 @@ static int cdns_imx_noncore_init(struct cdns_imx *data) return ret; } +static int cdns_imx_platform_suspend(struct device *dev, + bool suspend, bool wakeup); +static struct cdns3_platform_data cdns_imx_pdata = { + .platform_suspend = cdns_imx_platform_suspend, +}; + +static struct of_dev_auxdata cdns_imx_auxdata[] = { + { + .compatible = "cdns,usb3", + .platform_data = &cdns_imx_pdata, + }, + {}, +}; + static int cdns_imx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -162,14 +197,18 @@ static int cdns_imx_probe(struct platform_device *pdev) if (ret) goto err; - ret = of_platform_populate(node, NULL, NULL, dev); + ret = of_platform_populate(node, NULL, cdns_imx_auxdata, dev); if (ret) { dev_err(dev, "failed to create children: %d\n", ret); goto err; } - return ret; + device_set_wakeup_capable(dev, true); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_forbid(dev); + return ret; err: clk_bulk_disable_unprepare(data->num_clks, data->clks); return ret; @@ -194,6 +233,141 @@ static int cdns_imx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static void cdns3_set_wakeup(struct cdns_imx *data, bool enable) +{ + u32 value; + + value = cdns_imx_readl(data, USB3_INT_REG); + if (enable) + value |= OTG_WAKEUP_EN | DEVU3_WAEKUP_EN; + else + value &= ~(OTG_WAKEUP_EN | DEVU3_WAEKUP_EN); + + cdns_imx_writel(data, USB3_INT_REG, value); +} + +static int cdns_imx_platform_suspend(struct device *dev, + bool suspend, bool wakeup) +{ + struct cdns3 *cdns = dev_get_drvdata(dev); + struct device *parent = dev->parent; + struct cdns_imx *data = dev_get_drvdata(parent); + void __iomem *otg_regs = cdns->otg_regs; + void __iomem *xhci_regs = cdns->xhci_regs; + u32 value; + int ret = 0; + + if (cdns->role != USB_ROLE_HOST) + return 0; + + if (suspend) { + /* SW request low power when all usb ports allow to it ??? */ + value = readl(xhci_regs + XECP_PM_PMCSR); + value &= ~PS_MASK; + value |= PS_D1; + writel(value, xhci_regs + XECP_PM_PMCSR); + + /* mdctrl_clk_sel */ + value = cdns_imx_readl(data, USB3_CORE_CTRL1); + value |= MDCTRL_CLK_SEL; + cdns_imx_writel(data, USB3_CORE_CTRL1, value); + + /* wait for mdctrl_clk_status */ + value = cdns_imx_readl(data, USB3_CORE_STATUS); + ret = readl_poll_timeout_atomic(data->noncore + USB3_CORE_STATUS, value, + (value & MDCTRL_CLK_STATUS) == MDCTRL_CLK_STATUS, + 10, 100000); + if (ret) + dev_warn(parent, "wait mdctrl_clk_status timeout\n"); + + /* wait lpm_clk_req to be 0 */ + value = cdns_imx_readl(data, USB3_INT_REG); + ret = readl_poll_timeout_atomic(data->noncore + USB3_INT_REG, value, + (value & LPM_CLK_REQ) != LPM_CLK_REQ, + 10, 100000); + if (ret) + dev_warn(parent, "wait lpm_clk_req timeout\n"); + + /* wait phy_refclk_req to be 0 */ + value = cdns_imx_readl(data, USB3_SSPHY_STATUS); + ret = readl_poll_timeout_atomic(data->noncore + USB3_SSPHY_STATUS, value, + (value & PHY_REFCLK_REQ) != PHY_REFCLK_REQ, + 10, 100000); + if (ret) + dev_warn(parent, "wait phy_refclk_req timeout\n"); + + cdns3_set_wakeup(data, wakeup); + } else { + /* wait CLK_125_REQ to be 1 */ + value = cdns_imx_readl(data, USB3_INT_REG); + ret = readl_poll_timeout_atomic(data->noncore + USB3_INT_REG, value, + (value & CLK_125_REQ) != CLK_125_REQ, + 10, 100000); + if (ret) + dev_warn(parent, "wait CLK_125_REQ timeout\n"); + + cdns3_set_wakeup(data, false); + + /* SW request D0 */ + value = readl(xhci_regs + XECP_PM_PMCSR); + value &= ~PS_MASK; + value |= PS_D0; + writel(value, xhci_regs + XECP_PM_PMCSR); + + /* clr 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); + + /* clear mdctrl_clk_sel */ + value = cdns_imx_readl(data, USB3_CORE_CTRL1); + value &= ~MDCTRL_CLK_SEL; + cdns_imx_writel(data, USB3_CORE_CTRL1, value); + + /* wait for mdctrl_clk_status is cleared */ + value = cdns_imx_readl(data, USB3_CORE_STATUS); + ret = readl_poll_timeout_atomic(data->noncore + USB3_CORE_STATUS, value, + (value & MDCTRL_CLK_STATUS) != MDCTRL_CLK_STATUS, + 10, 100000); + if (ret) + dev_warn(parent, "wait mdctrl_clk_status cleared timeout\n"); + + /* Wait until OTG_NRDY is 0 */ + value = readl(otg_regs + OTGSTS); + ret = readl_poll_timeout_atomic(otg_regs + OTGSTS, value, + (value & OTG_NRDY) != OTG_NRDY, + 10, 100000); + if (ret) + dev_warn(parent, "wait OTG ready timeout\n"); + } + + return ret; + +} + +static int cdns_imx_resume(struct device *dev) +{ + struct cdns_imx *data = dev_get_drvdata(dev); + + return clk_bulk_prepare_enable(data->num_clks, data->clks); +} + +static int cdns_imx_suspend(struct device *dev) +{ + struct cdns_imx *data = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(data->num_clks, data->clks); + + return 0; +} + +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops cdns_imx_pm_ops = { + SET_RUNTIME_PM_OPS(cdns_imx_suspend, cdns_imx_resume, NULL) +}; + static const struct of_device_id cdns_imx_of_match[] = { { .compatible = "fsl,imx8qm-usb3", }, {}, @@ -206,6 +380,7 @@ static struct platform_driver cdns_imx_driver = { .driver = { .name = "cdns3-imx", .of_match_table = cdns_imx_of_match, + .pm = &cdns_imx_pm_ops, }, }; module_platform_driver(cdns_imx_driver);
Add imx glue layer runtime pm implementation, and the runtime pm is default off. Signed-off-by: Peter Chen <peter.chen@nxp.com> --- drivers/usb/cdns3/cdns3-imx.c | 179 +++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 2 deletions(-)