2 * Freescale i.MX28 USB Host driver
4 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5 * on behalf of DENX Software Engineering GmbH
7 * SPDX-License-Identifier: GPL-2.0+
12 #include <asm/arch/imx-regs.h>
17 /* This DIGCTL register ungates clock to USB */
18 #define HW_DIGCTL_CTRL 0x8001c000
19 #define HW_DIGCTL_CTRL_USB0_CLKGATE (1 << 2)
20 #define HW_DIGCTL_CTRL_USB1_CLKGATE (1 << 16)
22 struct ehci_mxs_port
{
24 struct mxs_usbphy_regs
*phy_regs
;
26 struct mxs_register_32
*pll
;
28 uint32_t pll_dis_bits
;
32 static const struct ehci_mxs_port mxs_port
[] = {
33 #ifdef CONFIG_EHCI_MXS_PORT0
36 (struct mxs_usbphy_regs
*)MXS_USBPHY0_BASE
,
37 (struct mxs_register_32
*)(MXS_CLKCTRL_BASE
+
38 offsetof(struct mxs_clkctrl_regs
,
39 hw_clkctrl_pll0ctrl0_reg
)),
40 CLKCTRL_PLL0CTRL0_EN_USB_CLKS
| CLKCTRL_PLL0CTRL0_POWER
,
41 CLKCTRL_PLL0CTRL0_EN_USB_CLKS
,
42 HW_DIGCTL_CTRL_USB0_CLKGATE
,
45 #ifdef CONFIG_EHCI_MXS_PORT1
48 (struct mxs_usbphy_regs
*)MXS_USBPHY1_BASE
,
49 (struct mxs_register_32
*)(MXS_CLKCTRL_BASE
+
50 offsetof(struct mxs_clkctrl_regs
,
51 hw_clkctrl_pll1ctrl0_reg
)),
52 CLKCTRL_PLL1CTRL0_EN_USB_CLKS
| CLKCTRL_PLL1CTRL0_POWER
,
53 CLKCTRL_PLL1CTRL0_EN_USB_CLKS
,
54 HW_DIGCTL_CTRL_USB1_CLKGATE
,
59 static int ehci_mxs_toggle_clock(const struct ehci_mxs_port
*port
, int enable
)
61 struct mxs_register_32
*digctl_ctrl
=
62 (struct mxs_register_32
*)HW_DIGCTL_CTRL
;
63 int pll_offset
, dig_offset
;
66 pll_offset
= offsetof(struct mxs_register_32
, reg_set
);
67 dig_offset
= offsetof(struct mxs_register_32
, reg_clr
);
68 writel(port
->gate_bits
, (u32
)&digctl_ctrl
->reg
+ dig_offset
);
69 writel(port
->pll_en_bits
, (u32
)port
->pll
+ pll_offset
);
71 pll_offset
= offsetof(struct mxs_register_32
, reg_clr
);
72 dig_offset
= offsetof(struct mxs_register_32
, reg_set
);
73 writel(port
->pll_dis_bits
, (u32
)port
->pll
+ pll_offset
);
74 writel(port
->gate_bits
, (u32
)&digctl_ctrl
->reg
+ dig_offset
);
80 int ehci_hcd_init(int index
, struct ehci_hccr
**hccr
, struct ehci_hcor
**hcor
)
84 uint32_t usb_base
, cap_base
;
85 const struct ehci_mxs_port
*port
;
87 if ((index
< 0) || (index
>= ARRAY_SIZE(mxs_port
))) {
88 printf("Invalid port index (index = %d)!\n", index
);
92 port
= &mxs_port
[index
];
94 /* Reset the PHY block */
95 writel(USBPHY_CTRL_SFTRST
, &port
->phy_regs
->hw_usbphy_ctrl_set
);
97 writel(USBPHY_CTRL_SFTRST
| USBPHY_CTRL_CLKGATE
,
98 &port
->phy_regs
->hw_usbphy_ctrl_clr
);
100 /* Enable USB clock */
101 ret
= ehci_mxs_toggle_clock(port
, 1);
106 writel(0, &port
->phy_regs
->hw_usbphy_pwd
);
108 /* Enable UTMI+ Level 2 and Level 3 compatibility */
109 writel(USBPHY_CTRL_ENUTMILEVEL3
| USBPHY_CTRL_ENUTMILEVEL2
| 1,
110 &port
->phy_regs
->hw_usbphy_ctrl_set
);
112 usb_base
= port
->usb_regs
+ 0x100;
113 *hccr
= (struct ehci_hccr
*)usb_base
;
115 cap_base
= ehci_readl(&(*hccr
)->cr_capbase
);
116 *hcor
= (struct ehci_hcor
*)(usb_base
+ HC_LENGTH(cap_base
));
121 int ehci_hcd_stop(int index
)
124 uint32_t usb_base
, cap_base
, tmp
;
125 struct ehci_hccr
*hccr
;
126 struct ehci_hcor
*hcor
;
127 const struct ehci_mxs_port
*port
;
129 if ((index
< 0) || (index
>= ARRAY_SIZE(mxs_port
))) {
130 printf("Invalid port index (index = %d)!\n", index
);
134 port
= &mxs_port
[index
];
136 /* Stop the USB port */
137 usb_base
= port
->usb_regs
+ 0x100;
138 hccr
= (struct ehci_hccr
*)usb_base
;
139 cap_base
= ehci_readl(&hccr
->cr_capbase
);
140 hcor
= (struct ehci_hcor
*)(usb_base
+ HC_LENGTH(cap_base
));
142 tmp
= ehci_readl(&hcor
->or_usbcmd
);
144 ehci_writel(tmp
, &hcor
->or_usbcmd
);
146 /* Disable the PHY */
147 tmp
= USBPHY_PWD_RXPWDRX
| USBPHY_PWD_RXPWDDIFF
|
148 USBPHY_PWD_RXPWD1PT1
| USBPHY_PWD_RXPWDENV
|
149 USBPHY_PWD_TXPWDV2I
| USBPHY_PWD_TXPWDIBIAS
|
151 writel(tmp
, &port
->phy_regs
->hw_usbphy_pwd
);
153 /* Disable USB clock */
154 ret
= ehci_mxs_toggle_clock(port
, 0);