1 // SPDX-License-Identifier: GPL-2.0
3 * cdns3-imx.c - NXP i.MX specific Glue layer for Cadence USB Controller
5 * Copyright (C) 2019 NXP
8 #include <linux/bits.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/interrupt.h>
13 #include <linux/platform_device.h>
14 #include <linux/dma-mapping.h>
16 #include <linux/of_platform.h>
17 #include <linux/iopoll.h>
18 #include <linux/pm_runtime.h>
21 #define USB3_CORE_CTRL1 0x00
22 #define USB3_CORE_CTRL2 0x04
23 #define USB3_INT_REG 0x08
24 #define USB3_CORE_STATUS 0x0c
25 #define XHCI_DEBUG_LINK_ST 0x10
26 #define XHCI_DEBUG_BUS 0x14
27 #define USB3_SSPHY_CTRL1 0x40
28 #define USB3_SSPHY_CTRL2 0x44
29 #define USB3_SSPHY_STATUS 0x4c
30 #define USB2_PHY_CTRL1 0x50
31 #define USB2_PHY_CTRL2 0x54
32 #define USB2_PHY_STATUS 0x5c
34 /* Register bits definition */
37 #define SW_RESET_MASK GENMASK(31, 26)
38 #define PWR_SW_RESET BIT(31)
39 #define APB_SW_RESET BIT(30)
40 #define AXI_SW_RESET BIT(29)
41 #define RW_SW_RESET BIT(28)
42 #define PHY_SW_RESET BIT(27)
43 #define PHYAHB_SW_RESET BIT(26)
44 #define ALL_SW_RESET (PWR_SW_RESET | APB_SW_RESET | AXI_SW_RESET | \
45 RW_SW_RESET | PHY_SW_RESET | PHYAHB_SW_RESET)
46 #define OC_DISABLE BIT(9)
47 #define MDCTRL_CLK_SEL BIT(7)
48 #define MODE_STRAP_MASK (0x7)
49 #define DEV_MODE (1 << 2)
50 #define HOST_MODE (1 << 1)
51 #define OTG_MODE (1 << 0)
54 #define CLK_125_REQ BIT(29)
55 #define LPM_CLK_REQ BIT(28)
56 #define DEVU3_WAEKUP_EN BIT(14)
57 #define OTG_WAKEUP_EN BIT(12)
58 #define DEV_INT_EN (3 << 8) /* DEV INT b9:8 */
59 #define HOST_INT1_EN (1 << 0) /* HOST INT b7:0 */
61 /* USB3_CORE_STATUS */
62 #define MDCTRL_CLK_STATUS BIT(15)
63 #define DEV_POWER_ON_READY BIT(13)
64 #define HOST_POWER_ON_READY BIT(12)
66 /* USB3_SSPHY_STATUS */
67 #define CLK_VALID_MASK (0x3f << 26)
68 #define CLK_VALID_COMPARE_BITS (0xf << 28)
69 #define PHY_REFCLK_REQ (1 << 0)
71 /* OTG registers definition */
74 #define OTG_NRDY BIT(11)
76 /* xHCI registers definition */
77 #define XECP_PM_PMCSR 0x8018
78 #define XECP_AUX_CTRL_REG1 0x8120
80 /* Register bits definition */
81 /* XECP_AUX_CTRL_REG1 */
82 #define CFG_RXDET_P3_EN BIT(15)
85 #define PS_MASK GENMASK(1, 0)
91 void __iomem
*noncore
;
92 struct clk_bulk_data
*clks
;
94 struct platform_device
*cdns3_pdev
;
97 static inline u32
cdns_imx_readl(struct cdns_imx
*data
, u32 offset
)
99 return readl(data
->noncore
+ offset
);
102 static inline void cdns_imx_writel(struct cdns_imx
*data
, u32 offset
, u32 value
)
104 writel(value
, data
->noncore
+ offset
);
107 static const struct clk_bulk_data imx_cdns3_core_clks
[] = {
115 static int cdns_imx_noncore_init(struct cdns_imx
*data
)
119 struct device
*dev
= data
->dev
;
121 cdns_imx_writel(data
, USB3_SSPHY_STATUS
, CLK_VALID_MASK
);
123 ret
= readl_poll_timeout(data
->noncore
+ USB3_SSPHY_STATUS
, value
,
124 (value
& CLK_VALID_COMPARE_BITS
) == CLK_VALID_COMPARE_BITS
,
127 dev_err(dev
, "wait clkvld timeout\n");
131 value
= cdns_imx_readl(data
, USB3_CORE_CTRL1
);
132 value
|= ALL_SW_RESET
;
133 cdns_imx_writel(data
, USB3_CORE_CTRL1
, value
);
136 value
= cdns_imx_readl(data
, USB3_CORE_CTRL1
);
137 value
= (value
& ~MODE_STRAP_MASK
) | OTG_MODE
| OC_DISABLE
;
138 cdns_imx_writel(data
, USB3_CORE_CTRL1
, value
);
140 value
= cdns_imx_readl(data
, USB3_INT_REG
);
141 value
|= HOST_INT1_EN
| DEV_INT_EN
;
142 cdns_imx_writel(data
, USB3_INT_REG
, value
);
144 value
= cdns_imx_readl(data
, USB3_CORE_CTRL1
);
145 value
&= ~ALL_SW_RESET
;
146 cdns_imx_writel(data
, USB3_CORE_CTRL1
, value
);
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 .quirks
= CDNS3_DEFAULT_PM_RUNTIME_ALLOW
,
157 static const struct of_dev_auxdata cdns_imx_auxdata
[] = {
159 .compatible
= "cdns,usb3",
160 .platform_data
= &cdns_imx_pdata
,
165 static int cdns_imx_probe(struct platform_device
*pdev
)
167 struct device
*dev
= &pdev
->dev
;
168 struct device_node
*node
= dev
->of_node
;
169 struct cdns_imx
*data
;
175 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
179 platform_set_drvdata(pdev
, data
);
181 data
->noncore
= devm_platform_ioremap_resource(pdev
, 0);
182 if (IS_ERR(data
->noncore
)) {
183 dev_err(dev
, "can't map IOMEM resource\n");
184 return PTR_ERR(data
->noncore
);
187 data
->num_clks
= ARRAY_SIZE(imx_cdns3_core_clks
);
188 data
->clks
= devm_kmemdup(dev
, imx_cdns3_core_clks
,
189 sizeof(imx_cdns3_core_clks
), GFP_KERNEL
);
193 ret
= devm_clk_bulk_get(dev
, data
->num_clks
, data
->clks
);
197 ret
= clk_bulk_prepare_enable(data
->num_clks
, data
->clks
);
201 ret
= cdns_imx_noncore_init(data
);
205 ret
= of_platform_populate(node
, NULL
, cdns_imx_auxdata
, dev
);
207 dev_err(dev
, "failed to create children: %d\n", ret
);
211 device_set_wakeup_capable(dev
, true);
212 pm_runtime_set_active(dev
);
213 pm_runtime_enable(dev
);
217 clk_bulk_disable_unprepare(data
->num_clks
, data
->clks
);
221 static void cdns_imx_remove(struct platform_device
*pdev
)
223 struct device
*dev
= &pdev
->dev
;
224 struct cdns_imx
*data
= dev_get_drvdata(dev
);
226 pm_runtime_get_sync(dev
);
227 of_platform_depopulate(dev
);
228 clk_bulk_disable_unprepare(data
->num_clks
, data
->clks
);
229 pm_runtime_disable(dev
);
230 pm_runtime_put_noidle(dev
);
231 platform_set_drvdata(pdev
, NULL
);
235 static void cdns3_set_wakeup(struct cdns_imx
*data
, bool enable
)
239 value
= cdns_imx_readl(data
, USB3_INT_REG
);
241 value
|= OTG_WAKEUP_EN
| DEVU3_WAEKUP_EN
;
243 value
&= ~(OTG_WAKEUP_EN
| DEVU3_WAEKUP_EN
);
245 cdns_imx_writel(data
, USB3_INT_REG
, value
);
248 static int cdns_imx_platform_suspend(struct device
*dev
,
249 bool suspend
, bool wakeup
)
251 struct cdns
*cdns
= dev_get_drvdata(dev
);
252 struct device
*parent
= dev
->parent
;
253 struct cdns_imx
*data
= dev_get_drvdata(parent
);
254 void __iomem
*otg_regs
= (void __iomem
*)(cdns
->otg_regs
);
255 void __iomem
*xhci_regs
= cdns
->xhci_regs
;
259 if (cdns
->role
!= USB_ROLE_HOST
)
263 /* SW request low power when all usb ports allow to it ??? */
264 value
= readl(xhci_regs
+ XECP_PM_PMCSR
);
267 writel(value
, xhci_regs
+ XECP_PM_PMCSR
);
270 value
= cdns_imx_readl(data
, USB3_CORE_CTRL1
);
271 value
|= MDCTRL_CLK_SEL
;
272 cdns_imx_writel(data
, USB3_CORE_CTRL1
, value
);
274 /* wait for mdctrl_clk_status */
275 value
= cdns_imx_readl(data
, USB3_CORE_STATUS
);
276 ret
= readl_poll_timeout(data
->noncore
+ USB3_CORE_STATUS
, value
,
277 (value
& MDCTRL_CLK_STATUS
) == MDCTRL_CLK_STATUS
,
280 dev_warn(parent
, "wait mdctrl_clk_status timeout\n");
282 /* wait lpm_clk_req to be 0 */
283 value
= cdns_imx_readl(data
, USB3_INT_REG
);
284 ret
= readl_poll_timeout(data
->noncore
+ USB3_INT_REG
, value
,
285 (value
& LPM_CLK_REQ
) != LPM_CLK_REQ
,
288 dev_warn(parent
, "wait lpm_clk_req timeout\n");
290 /* wait phy_refclk_req to be 0 */
291 value
= cdns_imx_readl(data
, USB3_SSPHY_STATUS
);
292 ret
= readl_poll_timeout(data
->noncore
+ USB3_SSPHY_STATUS
, value
,
293 (value
& PHY_REFCLK_REQ
) != PHY_REFCLK_REQ
,
296 dev_warn(parent
, "wait phy_refclk_req timeout\n");
298 cdns3_set_wakeup(data
, wakeup
);
300 cdns3_set_wakeup(data
, false);
303 value
= readl(xhci_regs
+ XECP_PM_PMCSR
);
306 writel(value
, xhci_regs
+ XECP_PM_PMCSR
);
308 /* clr CFG_RXDET_P3_EN */
309 value
= readl(xhci_regs
+ XECP_AUX_CTRL_REG1
);
310 value
&= ~CFG_RXDET_P3_EN
;
311 writel(value
, xhci_regs
+ XECP_AUX_CTRL_REG1
);
313 /* clear mdctrl_clk_sel */
314 value
= cdns_imx_readl(data
, USB3_CORE_CTRL1
);
315 value
&= ~MDCTRL_CLK_SEL
;
316 cdns_imx_writel(data
, USB3_CORE_CTRL1
, value
);
318 /* wait CLK_125_REQ to be 1 */
319 value
= cdns_imx_readl(data
, USB3_INT_REG
);
320 ret
= readl_poll_timeout(data
->noncore
+ USB3_INT_REG
, value
,
321 (value
& CLK_125_REQ
) == CLK_125_REQ
,
324 dev_warn(parent
, "wait CLK_125_REQ timeout\n");
326 /* wait for mdctrl_clk_status is cleared */
327 value
= cdns_imx_readl(data
, USB3_CORE_STATUS
);
328 ret
= readl_poll_timeout(data
->noncore
+ USB3_CORE_STATUS
, value
,
329 (value
& MDCTRL_CLK_STATUS
) != MDCTRL_CLK_STATUS
,
332 dev_warn(parent
, "wait mdctrl_clk_status cleared timeout\n");
334 /* Wait until OTG_NRDY is 0 */
335 value
= readl(otg_regs
+ OTGSTS
);
336 ret
= readl_poll_timeout(otg_regs
+ OTGSTS
, value
,
337 (value
& OTG_NRDY
) != OTG_NRDY
,
340 dev_warn(parent
, "wait OTG ready timeout\n");
347 static int cdns_imx_resume(struct device
*dev
)
349 struct cdns_imx
*data
= dev_get_drvdata(dev
);
351 return clk_bulk_prepare_enable(data
->num_clks
, data
->clks
);
354 static int cdns_imx_suspend(struct device
*dev
)
356 struct cdns_imx
*data
= dev_get_drvdata(dev
);
358 clk_bulk_disable_unprepare(data
->num_clks
, data
->clks
);
364 /* Indicate if the controller was power lost before */
365 static inline bool cdns_imx_is_power_lost(struct cdns_imx
*data
)
369 value
= cdns_imx_readl(data
, USB3_CORE_CTRL1
);
370 if ((value
& SW_RESET_MASK
) == ALL_SW_RESET
)
376 static int __maybe_unused
cdns_imx_system_suspend(struct device
*dev
)
378 pm_runtime_put_sync(dev
);
382 static int __maybe_unused
cdns_imx_system_resume(struct device
*dev
)
384 struct cdns_imx
*data
= dev_get_drvdata(dev
);
387 ret
= pm_runtime_resume_and_get(dev
);
389 dev_err(dev
, "Could not get runtime PM.\n");
393 if (cdns_imx_is_power_lost(data
)) {
394 dev_dbg(dev
, "resume from power lost\n");
395 ret
= cdns_imx_noncore_init(data
);
397 cdns_imx_suspend(dev
);
404 static int cdns_imx_platform_suspend(struct device
*dev
,
405 bool suspend
, bool wakeup
)
410 #endif /* CONFIG_PM */
412 static const struct dev_pm_ops cdns_imx_pm_ops
= {
413 SET_RUNTIME_PM_OPS(cdns_imx_suspend
, cdns_imx_resume
, NULL
)
414 SET_SYSTEM_SLEEP_PM_OPS(cdns_imx_system_suspend
, cdns_imx_system_resume
)
417 static const struct of_device_id cdns_imx_of_match
[] = {
418 { .compatible
= "fsl,imx8qm-usb3", },
421 MODULE_DEVICE_TABLE(of
, cdns_imx_of_match
);
423 static struct platform_driver cdns_imx_driver
= {
424 .probe
= cdns_imx_probe
,
425 .remove
= cdns_imx_remove
,
428 .of_match_table
= cdns_imx_of_match
,
429 .pm
= &cdns_imx_pm_ops
,
432 module_platform_driver(cdns_imx_driver
);
434 MODULE_ALIAS("platform:cdns3-imx");
435 MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
436 MODULE_LICENSE("GPL v2");
437 MODULE_DESCRIPTION("Cadence USB3 i.MX Glue Layer");