netwalker_usb.c revision 1.1.6.2 1 /*
2 * Copyright (c) 2010 Genetec Corporation. All rights reserved.
3 * Written by Hiroyuki Bessho for Genetec Corporation.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: netwalker_usb.c,v 1.1.6.2 2011/03/05 20:50:08 rmind Exp $");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/conf.h>
33 #include <sys/kernel.h>
34 #include <sys/device.h>
35 #include <sys/intr.h>
36 #include <sys/bus.h>
37
38 #include <dev/usb/usb.h>
39 #include <dev/usb/usbdi.h>
40 #include <dev/usb/usbdivar.h>
41 #include <dev/usb/usb_mem.h>
42
43 #include <dev/usb/ehcireg.h>
44 #include <dev/usb/ehcivar.h>
45
46 #include <arm/imx/imx51reg.h>
47 #include <arm/imx/imx51var.h>
48 #include <arm/imx/imxusbreg.h>
49 #include <arm/imx/imxusbvar.h>
50 #include <arm/imx/imx51_iomuxreg.h>
51 #include <arm/imx/imxgpiovar.h>
52 #include "locators.h"
53
54
55 struct netwalker_usbc_softc {
56 struct imxusbc_softc sc_imxusbc;
57 };
58
59
60 static int imxusbc_match(device_t, cfdata_t, void *);
61 static void imxusbc_attach(device_t, device_t, void *);
62 static void netwalker_usb_init(struct imxehci_softc *);
63
64 static void init_otg(struct imxehci_softc *);
65 static void init_h1(struct imxehci_softc *);
66
67 extern const struct iomux_conf iomux_usb1_config[];
68
69 /* attach structures */
70 CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct netwalker_usbc_softc),
71 imxusbc_match, imxusbc_attach, NULL, NULL);
72
73 static int
74 imxusbc_match(device_t parent, cfdata_t cf, void *aux)
75 {
76 struct axi_attach_args *aa = aux;
77
78 printf("%s\n", __func__);
79
80 if (aa->aa_addr == USBOH3_BASE)
81 return 1;
82 return 0;
83 }
84
85 static void
86 imxusbc_attach(device_t parent, device_t self, void *aux)
87 {
88 struct axi_attach_args *aa = aux;
89 struct imxusbc_softc *sc = device_private(self);
90
91 sc->sc_init_md_hook = netwalker_usb_init;
92 sc->sc_setup_md_hook = NULL;
93
94 imxusbc_attach_common(parent, self, aa->aa_iot);
95
96 }
97
98 static void
99 netwalker_usb_init(struct imxehci_softc *sc)
100 {
101 switch (sc->sc_unit) {
102 case 0: /* OTG controller */
103 init_otg(sc);
104 break;
105 case 1: /* EHCI Host 1 */
106 init_h1(sc);
107 break;
108 default:
109 aprint_error_dev(sc->sc_hsc.sc_dev, "unit %d not supprted\n",
110 sc->sc_unit);
111 }
112 }
113
114 static void
115 init_otg(struct imxehci_softc *sc)
116 {
117 struct imxusbc_softc *usbc = sc->sc_usbc;
118 uint32_t reg;
119
120 sc->sc_iftype = IMXUSBC_IF_UTMI;
121
122 imxehci_reset(sc);
123
124 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0);
125 reg |= PHYCTRL0_OTG_OVER_CUR_DIS;
126 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0, reg);
127
128 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL);
129 reg &= ~(USBCTRL_OWIR|USBCTRL_OPM);
130 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL, reg);
131
132 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1);
133 reg = (reg & ~PHYCTRL1_PLLDIVVALUE_MASK) | PHYCTRL1_PLLDIVVALUE_24MHZ;
134 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1, reg);
135 }
136
137
138
139
140 static void
141 init_h1(struct imxehci_softc *sc)
142 {
143 struct imxusbc_softc *usbc = sc->sc_usbc;
144 uint32_t reg;
145
146 /* output HIGH to USBH1_STP */
147 gpio_data_write(GPIO_NO(1,27), 1);
148 gpio_set_direction(GPIO_NO(1, 27), GPIO_DIR_OUT);
149
150 iomux_mux_config(iomux_usb1_config);
151
152 delay(100 * 1000);
153
154 /* XXX enable USB clock */
155
156 imxehci_reset(sc);
157
158 /* select external clock for Host 1 */
159 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
160 USBOH3_USBCTRL1);
161 reg |= USBCTRL1_UH1_EXT_CLK_EN;
162 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
163 USBOH3_USBCTRL1, reg);
164
165
166 /* select ULPI interface for Host 1 */
167 sc->sc_iftype = IMXUSBC_IF_ULPI;
168
169 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
170 USBOH3_USBCTRL);
171 reg &= ~(USBCTRL_H1PM);
172 reg |= USBCTRL_H1UIE|USBCTRL_H1WIE;
173 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
174 USBOH3_USBCTRL, reg);
175
176 iomux_set_function(MUX_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
177
178
179 /* HUB RESET release */
180 gpio_data_write(GPIO_NO(1, 7), 1);
181 gpio_set_direction(GPIO_NO(1, 7), GPIO_DIR_OUT);
182
183
184 /* Drive 26M_OSC_EN line high 3_1 */
185 gpio_data_write(GPIO_NO(3, 1), 1);
186 gpio_set_direction(GPIO_NO(3, 1), GPIO_DIR_OUT);
187
188 /* Drive USB_CLK_EN_B line low 2_1 */
189 gpio_data_write(GPIO_NO(2, 1), 0);
190 gpio_set_direction(GPIO_NO(2, 1), GPIO_DIR_IN);
191
192 /* MX51_PIN_EIM_D21 - De-assert USB PHY RESETB */
193 delay(10 * 1000);
194 gpio_data_write(GPIO_NO(2, 5), 1);
195 gpio_set_direction(GPIO_NO(2, 5), GPIO_DIR_OUT);
196 iomux_set_function(MUX_PIN_EIM_D21, IOMUX_CONFIG_ALT1);
197 delay(5 * 1000);
198 }
199
200 /*
201 * IOMUX setting for USB Host1
202 * taken from Linux driver
203 */
204 const struct iomux_conf iomux_usb1_config[] = {
205
206 {
207 /* Initially setup this pin for GPIO, and change to
208 * USBH1_STP later */
209 .pin = MUX_PIN_USBH1_STP,
210 .mux = IOMUX_CONFIG_ALT2,
211 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
212 PAD_CTL_KEEPER | PAD_CTL_HYS)
213 },
214
215 {
216 /* Clock */
217 .pin = MUX_PIN_USBH1_CLK,
218 .mux = IOMUX_CONFIG_ALT0,
219 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
220 PAD_CTL_KEEPER | PAD_CTL_HYS)
221 },
222 {
223 /* DIR */
224 .pin = MUX_PIN_USBH1_DIR,
225 .mux = IOMUX_CONFIG_ALT0,
226 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
227 PAD_CTL_KEEPER | PAD_CTL_HYS)
228 },
229
230 {
231 /* NXT */
232 .pin = MUX_PIN_USBH1_NXT,
233 .mux = IOMUX_CONFIG_ALT0,
234 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
235 PAD_CTL_KEEPER | PAD_CTL_HYS)
236 },
237
238 #define USBH1_DATA_CONFIG(n) \
239 { \
240 /* DATA n */ \
241 .pin = __CONCAT(MUX_PIN_USBH1_DATA,n), \
242 .mux = IOMUX_CONFIG_ALT0, \
243 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH | \
244 PAD_CTL_KEEPER | PAD_CTL_PUS_100K_PU | \
245 PAD_CTL_HYS), \
246 /* XXX: what does 100K_PU with KEEPER ? */ \
247 }
248
249 USBH1_DATA_CONFIG(0),
250 USBH1_DATA_CONFIG(1),
251 USBH1_DATA_CONFIG(2),
252 USBH1_DATA_CONFIG(3),
253 USBH1_DATA_CONFIG(4),
254 USBH1_DATA_CONFIG(5),
255 USBH1_DATA_CONFIG(6),
256 USBH1_DATA_CONFIG(7),
257
258 {
259 /* USB_CLK_EN_B GPIO2[1]*/
260 .pin = MUX_PIN_EIM_D17,
261 .mux = IOMUX_CONFIG_ALT1,
262 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | PAD_CTL_SRE),
263 },
264
265 {
266 /* USB PHY RESETB */
267 .pin = MUX_PIN_EIM_D21,
268 .mux = IOMUX_CONFIG_ALT1,
269 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_KEEPER |
270 PAD_CTL_PUS_100K_PU | PAD_CTL_SRE)
271 },
272 {
273 /* USB HUB RESET */
274 .pin = MUX_PIN_GPIO1_7,
275 .mux = IOMUX_CONFIG_ALT0,
276 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_SRE),
277 },
278
279 /* end of table */
280 {.pin = IOMUX_CONF_EOT}
281 };
282