]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/usb/host/ehci-omap.c
Merge branch 'master' of git://git.denx.de/u-boot-microblaze
[karo-tx-uboot.git] / drivers / usb / host / ehci-omap.c
1 /*
2  * (C) Copyright 2011 Ilya Yanok, Emcraft Systems
3  * (C) Copyright 2004-2008
4  * Texas Instruments, <www.ti.com>
5  *
6  * Derived from Beagle Board code by
7  *      Sunil Kumar <sunilsaini05@gmail.com>
8  *      Shashi Ranjan <shashiranjanmca05@gmail.com>
9  *
10  *
11  * See file CREDITS for list of people who contributed to this
12  * project.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of
17  * the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc.
27  */
28 #include <common.h>
29 #include <usb.h>
30 #include <usb/ulpi.h>
31 #include <errno.h>
32 #include <asm/io.h>
33 #include <asm/gpio.h>
34 #include <asm/arch/ehci.h>
35 #include <asm/ehci-omap.h>
36 #include "ehci-core.h"
37
38 static struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE;
39 static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE;
40 static struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
41
42 static int omap_uhh_reset(void)
43 {
44         unsigned long init = get_timer(0);
45
46         /* perform UHH soft reset, and wait until reset is complete */
47         writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
48
49         /* Wait for UHH reset to complete */
50         while (!(readl(&uhh->syss) & OMAP_UHH_SYSSTATUS_EHCI_RESETDONE))
51                 if (get_timer(init) > CONFIG_SYS_HZ) {
52                         debug("OMAP UHH error: timeout resetting ehci\n");
53                         return -EL3RST;
54                 }
55
56         return 0;
57 }
58
59 static int omap_ehci_tll_reset(void)
60 {
61         unsigned long init = get_timer(0);
62
63         /* perform TLL soft reset, and wait until reset is complete */
64         writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET, &usbtll->sysc);
65
66         /* Wait for TLL reset to complete */
67         while (!(readl(&usbtll->syss) & OMAP_USBTLL_SYSSTATUS_RESETDONE))
68                 if (get_timer(init) > CONFIG_SYS_HZ) {
69                         debug("OMAP EHCI error: timeout resetting TLL\n");
70                         return -EL3RST;
71         }
72
73         return 0;
74 }
75
76 static void omap_usbhs_hsic_init(int port)
77 {
78         unsigned int reg;
79
80         /* Enable channels now */
81         reg = readl(&usbtll->channel_conf + port);
82
83         setbits_le32(&reg, (OMAP_TLL_CHANNEL_CONF_CHANMODE_TRANSPARENT_UTMI
84                 | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
85                 | OMAP_TLL_CHANNEL_CONF_DRVVBUS
86                 | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
87                 | OMAP_TLL_CHANNEL_CONF_CHANEN));
88
89         writel(reg, &usbtll->channel_conf + port);
90 }
91
92 static void omap_ehci_soft_phy_reset(int port)
93 {
94         struct ulpi_viewport ulpi_vp;
95
96         ulpi_vp.viewport_addr = (u32)&ehci->insreg05_utmi_ulpi;
97         ulpi_vp.port_num = port;
98
99         ulpi_reset(&ulpi_vp);
100 }
101
102 inline int __board_usb_init(void)
103 {
104         return 0;
105 }
106 int board_usb_init(void) __attribute__((weak, alias("__board_usb_init")));
107
108 #if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \
109         defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO)
110 /* controls PHY(s) reset signal(s) */
111 static inline void omap_ehci_phy_reset(int on, int delay)
112 {
113         /*
114          * Refer ISSUE1:
115          * Hold the PHY in RESET for enough time till
116          * PHY is settled and ready
117          */
118         if (delay && !on)
119                 udelay(delay);
120 #ifdef CONFIG_OMAP_EHCI_PHY1_RESET_GPIO
121         gpio_request(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, "USB PHY1 reset");
122         gpio_direction_output(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, !on);
123 #endif
124 #ifdef CONFIG_OMAP_EHCI_PHY2_RESET_GPIO
125         gpio_request(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, "USB PHY2 reset");
126         gpio_direction_output(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, !on);
127 #endif
128
129         /* Hold the PHY in RESET for enough time till DIR is high */
130         /* Refer: ISSUE1 */
131         if (delay && on)
132                 udelay(delay);
133 }
134 #else
135 #define omap_ehci_phy_reset(on, delay)  do {} while (0)
136 #endif
137
138 /* Reset is needed otherwise the kernel-driver will throw an error. */
139 int omap_ehci_hcd_stop(void)
140 {
141         debug("Resetting OMAP EHCI\n");
142         omap_ehci_phy_reset(1, 0);
143
144         if (omap_uhh_reset() < 0)
145                 return -1;
146
147         if (omap_ehci_tll_reset() < 0)
148                 return -1;
149
150         return 0;
151 }
152
153 /*
154  * Initialize the OMAP EHCI controller and PHY.
155  * Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1
156  * See there for additional Copyrights.
157  */
158 int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata)
159 {
160         int ret;
161         unsigned int i, reg = 0, rev = 0;
162
163         debug("Initializing OMAP EHCI\n");
164
165         ret = board_usb_init();
166         if (ret < 0)
167                 return ret;
168
169         /* Put the PHY in RESET */
170         omap_ehci_phy_reset(1, 10);
171
172         ret = omap_uhh_reset();
173         if (ret < 0)
174                 return ret;
175
176         ret = omap_ehci_tll_reset();
177         if (ret)
178                 return ret;
179
180         writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
181                 OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
182                 OMAP_USBTLL_SYSCONFIG_CACTIVITY, &usbtll->sysc);
183
184         /* Put UHH in NoIdle/NoStandby mode */
185         writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
186
187         /* setup ULPI bypass and burst configurations */
188         clrsetbits_le32(&reg, OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN,
189                 (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
190                 OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN |
191                 OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN));
192
193         rev = readl(&uhh->rev);
194         if (rev == OMAP_USBHS_REV1) {
195                 if (is_ehci_phy_mode(usbhs_pdata->port_mode[0]))
196                         clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
197                 else
198                         setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
199
200                 if (is_ehci_phy_mode(usbhs_pdata->port_mode[1]))
201                         clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
202                 else
203                         setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
204
205                 if (is_ehci_phy_mode(usbhs_pdata->port_mode[2]))
206                         clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
207                 else
208                         setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
209         } else if (rev == OMAP_USBHS_REV2) {
210                 clrsetbits_le32(&reg, (OMAP_P1_MODE_CLEAR | OMAP_P2_MODE_CLEAR),
211                                         OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
212
213                 /* Clear port mode fields for PHY mode*/
214
215                 if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
216                         setbits_le32(&reg, OMAP_P1_MODE_HSIC);
217
218                 if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
219                         setbits_le32(&reg, OMAP_P2_MODE_HSIC);
220
221                 if (is_ehci_hsic_mode(usbhs_pdata->port_mode[2]))
222                         setbits_le32(&reg, OMAP_P3_MODE_HSIC);
223         }
224
225         debug("OMAP UHH_REVISION 0x%x\n", rev);
226         writel(reg, &uhh->hostconfig);
227
228         for (i = 0; i < OMAP_HS_USB_PORTS; i++)
229                 if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i]))
230                         omap_usbhs_hsic_init(i);
231
232         omap_ehci_phy_reset(0, 10);
233
234         /*
235          * An undocumented "feature" in the OMAP3 EHCI controller,
236          * causes suspended ports to be taken out of suspend when
237          * the USBCMD.Run/Stop bit is cleared (for example when
238          * we do ehci_bus_suspend).
239          * This breaks suspend-resume if the root-hub is allowed
240          * to suspend. Writing 1 to this undocumented register bit
241          * disables this feature and restores normal behavior.
242          */
243         writel(EHCI_INSNREG04_DISABLE_UNSUSPEND, &ehci->insreg04);
244
245         for (i = 0; i < OMAP_HS_USB_PORTS; i++)
246                 if (is_ehci_phy_mode(usbhs_pdata->port_mode[i]))
247                         omap_ehci_soft_phy_reset(i);
248
249         hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
250         hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10);
251
252         debug("OMAP EHCI init done\n");
253         return 0;
254 }