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
, enum usb_init_type init
,
81 struct ehci_hccr
**hccr
, struct ehci_hcor
**hcor
)
85 uint32_t usb_base
, cap_base
;
86 const struct ehci_mxs_port
*port
;
88 if ((index
< 0) || (index
>= ARRAY_SIZE(mxs_port
))) {
89 printf("Invalid port index (index = %d)!\n", index
);
93 port
= &mxs_port
[index
];
95 /* Reset the PHY block */
96 writel(USBPHY_CTRL_SFTRST
, &port
->phy_regs
->hw_usbphy_ctrl_set
);
98 writel(USBPHY_CTRL_SFTRST
| USBPHY_CTRL_CLKGATE
,
99 &port
->phy_regs
->hw_usbphy_ctrl_clr
);
101 /* Enable USB clock */
102 ret
= ehci_mxs_toggle_clock(port
, 1);
107 writel(0, &port
->phy_regs
->hw_usbphy_pwd
);
109 /* Enable UTMI+ Level 2 and Level 3 compatibility */
110 writel(USBPHY_CTRL_ENUTMILEVEL3
| USBPHY_CTRL_ENUTMILEVEL2
| 1,
111 &port
->phy_regs
->hw_usbphy_ctrl_set
);
113 usb_base
= port
->usb_regs
+ 0x100;
114 *hccr
= (struct ehci_hccr
*)usb_base
;
116 cap_base
= ehci_readl(&(*hccr
)->cr_capbase
);
117 *hcor
= (struct ehci_hcor
*)(usb_base
+ HC_LENGTH(cap_base
));
122 int ehci_hcd_stop(int index
)
125 uint32_t usb_base
, cap_base
, tmp
;
126 struct ehci_hccr
*hccr
;
127 struct ehci_hcor
*hcor
;
128 const struct ehci_mxs_port
*port
;
130 if ((index
< 0) || (index
>= ARRAY_SIZE(mxs_port
))) {
131 printf("Invalid port index (index = %d)!\n", index
);
135 port
= &mxs_port
[index
];
137 /* Stop the USB port */
138 usb_base
= port
->usb_regs
+ 0x100;
139 hccr
= (struct ehci_hccr
*)usb_base
;
140 cap_base
= ehci_readl(&hccr
->cr_capbase
);
141 hcor
= (struct ehci_hcor
*)(usb_base
+ HC_LENGTH(cap_base
));
143 tmp
= ehci_readl(&hcor
->or_usbcmd
);
145 ehci_writel(tmp
, &hcor
->or_usbcmd
);
147 /* Disable the PHY */
148 tmp
= USBPHY_PWD_RXPWDRX
| USBPHY_PWD_RXPWDDIFF
|
149 USBPHY_PWD_RXPWD1PT1
| USBPHY_PWD_RXPWDENV
|
150 USBPHY_PWD_TXPWDV2I
| USBPHY_PWD_TXPWDIBIAS
|
152 writel(tmp
, &port
->phy_regs
->hw_usbphy_pwd
);
154 /* Disable USB clock */
155 ret
= ehci_mxs_toggle_clock(port
, 0);