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.9 2024/02/22 23:16:10 andvar Exp $");
29
30 #include "locators.h"
31
32 #define _INTR_PRIVATE
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/intr.h>
40 #include <sys/bus.h>
41 #include <sys/gpio.h>
42
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usbdi.h>
45 #include <dev/usb/usbdivar.h>
46 #include <dev/usb/usb_mem.h>
47
48 #include <dev/usb/ehcireg.h>
49 #include <dev/usb/ehcivar.h>
50
51 #include <arm/imx/imx51reg.h>
52 #include <arm/imx/imx51var.h>
53 #include <arm/imx/imxusbreg.h>
54 #include <arm/imx/imxusbvar.h>
55 #include <arm/imx/imx51_iomuxreg.h>
56 #include <arm/imx/imxgpiovar.h>
57
58 struct netwalker_usbc_softc {
59 struct imxusbc_softc sc_imxusbc; /* Must be first */
60 };
61
62 static int imxusbc_match(device_t, cfdata_t, void *);
63 static void imxusbc_attach(device_t, device_t, void *);
64 static void netwalker_usb_init(struct imxehci_softc *, uintptr_t);
65
66 static void init_otg(struct imxehci_softc *);
67 static void init_h1(struct imxehci_softc *);
68
69 extern const struct iomux_conf iomux_usb1_config[];
70
71 /* attach structures */
72 CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct netwalker_usbc_softc),
73 imxusbc_match, imxusbc_attach, NULL, NULL);
74
75 static int
imxusbc_match(device_t parent,cfdata_t cf,void * aux)76 imxusbc_match(device_t parent, cfdata_t cf, void *aux)
77 {
78 struct axi_attach_args *aa = aux;
79
80 if (aa->aa_addr == USBOH3_BASE)
81 return 1;
82
83 return 0;
84 }
85
86 static void
imxusbc_attach(device_t parent,device_t self,void * aux)87 imxusbc_attach(device_t parent, device_t self, void *aux)
88 {
89 struct imxusbc_softc *sc = device_private(self);
90 struct axi_attach_args *aa = aux;
91
92 aprint_naive("\n");
93 aprint_normal(": Universal Serial Bus Controller\n");
94
95 if (aa->aa_size == AXICF_SIZE_DEFAULT)
96 aa->aa_size = USBOH3_SIZE;
97
98 sc->sc_init_md_hook = netwalker_usb_init;
99 sc->sc_intr_establish_md_hook = NULL;
100 sc->sc_setup_md_hook = NULL;
101
102 imxusbc_attach_common(parent, self, aa->aa_iot, aa->aa_addr, aa->aa_size);
103 }
104
105 static void
netwalker_usb_init(struct imxehci_softc * sc,uintptr_t data)106 netwalker_usb_init(struct imxehci_softc *sc, uintptr_t data)
107 {
108 switch (sc->sc_unit) {
109 case 0: /* OTG controller */
110 init_otg(sc);
111 break;
112 case 1: /* EHCI Host 1 */
113 init_h1(sc);
114 break;
115 default:
116 aprint_error_dev(sc->sc_hsc.sc_dev, "unit %d not supported\n",
117 sc->sc_unit);
118 }
119 }
120
121 static void
init_otg(struct imxehci_softc * sc)122 init_otg(struct imxehci_softc *sc)
123 {
124 struct imxusbc_softc *usbc = sc->sc_usbc;
125 uint32_t reg;
126
127 sc->sc_iftype = IMXUSBC_IF_UTMI;
128
129 imxehci_reset(sc);
130
131 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0);
132 reg |= PHYCTRL0_OTG_OVER_CUR_DIS;
133 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0, reg);
134
135 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL);
136 reg &= ~(USBCTRL_OWIR|USBCTRL_OPM);
137 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL, reg);
138
139 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1);
140 reg = (reg & ~PHYCTRL1_PLLDIVVALUE_MASK) | PHYCTRL1_PLLDIVVALUE_24MHZ;
141 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1, reg);
142 }
143
144 static void
init_h1(struct imxehci_softc * sc)145 init_h1(struct imxehci_softc *sc)
146 {
147 struct imxusbc_softc *usbc = sc->sc_usbc;
148 uint32_t reg;
149
150 /* output HIGH to USBH1_STP */
151 imxgpio_data_write(GPIO_NO(1, 27), GPIO_PIN_HIGH);
152 imxgpio_set_direction(GPIO_NO(1, 27), GPIO_PIN_OUTPUT);
153
154 iomux_mux_config(iomux_usb1_config);
155
156 delay(100 * 1000);
157
158 /* XXX enable USB clock */
159
160 imxehci_reset(sc);
161
162 /* select external clock for Host 1 */
163 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
164 USBOH3_USBCTRL1);
165 reg |= USBCTRL1_UH1_EXT_CLK_EN;
166 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
167 USBOH3_USBCTRL1, reg);
168
169
170 /* select ULPI interface for Host 1 */
171 sc->sc_iftype = IMXUSBC_IF_ULPI;
172
173 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
174 USBOH3_USBCTRL);
175 reg &= ~(USBCTRL_H1PM);
176 reg |= USBCTRL_H1UIE|USBCTRL_H1WIE;
177 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
178 USBOH3_USBCTRL, reg);
179
180 iomux_set_function(MUX_PIN(USBH1_STP), IOMUX_CONFIG_ALT0);
181
182
183 /* HUB RESET release */
184 imxgpio_data_write(GPIO_NO(1, 7), GPIO_PIN_HIGH);
185 imxgpio_set_direction(GPIO_NO(1, 7), GPIO_PIN_OUTPUT);
186
187 /* Drive 26M_OSC_EN line high 3_1 */
188 imxgpio_data_write(GPIO_NO(3, 1), GPIO_PIN_HIGH);
189 imxgpio_set_direction(GPIO_NO(3, 1), GPIO_PIN_OUTPUT);
190
191 /* Drive USB_CLK_EN_B line low 2_1 */
192 imxgpio_data_write(GPIO_NO(2, 1), GPIO_PIN_LOW);
193 imxgpio_set_direction(GPIO_NO(2, 1), GPIO_PIN_INPUT);
194
195 /* MX51_PIN_EIM_D21 - De-assert USB PHY RESETB */
196 delay(10 * 1000);
197 imxgpio_data_write(GPIO_NO(2, 5), GPIO_PIN_HIGH);
198 imxgpio_set_direction(GPIO_NO(2, 5), GPIO_PIN_OUTPUT);
199 iomux_set_function(MUX_PIN(EIM_D21), IOMUX_CONFIG_ALT1);
200 delay(5 * 1000);
201 }
202
203 /*
204 * IOMUX setting for USB Host1
205 * taken from Linux driver
206 */
207 const struct iomux_conf iomux_usb1_config[] = {
208
209 {
210 /* Initially setup this pin for GPIO, and change to
211 * USBH1_STP later */
212 .pin = MUX_PIN(USBH1_STP),
213 .mux = IOMUX_CONFIG_ALT2,
214 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
215 PAD_CTL_KEEPER | PAD_CTL_HYS)
216 },
217
218 {
219 /* Clock */
220 .pin = MUX_PIN(USBH1_CLK),
221 .mux = IOMUX_CONFIG_ALT0,
222 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
223 PAD_CTL_KEEPER | PAD_CTL_HYS)
224 },
225 {
226 /* DIR */
227 .pin = MUX_PIN(USBH1_DIR),
228 .mux = IOMUX_CONFIG_ALT0,
229 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
230 PAD_CTL_KEEPER | PAD_CTL_HYS)
231 },
232
233 {
234 /* NXT */
235 .pin = MUX_PIN(USBH1_NXT),
236 .mux = IOMUX_CONFIG_ALT0,
237 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
238 PAD_CTL_KEEPER | PAD_CTL_HYS)
239 },
240
241 #define USBH1_DATA_CONFIG(n) \
242 { \
243 /* DATA n */ \
244 .pin = MUX_PIN(USBH1_DATA##n), \
245 .mux = IOMUX_CONFIG_ALT0, \
246 .pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH | \
247 PAD_CTL_KEEPER | PAD_CTL_PUS_100K_PU | \
248 PAD_CTL_HYS), \
249 /* XXX: what does 100K_PU with KEEPER ? */ \
250 }
251
252 USBH1_DATA_CONFIG(0),
253 USBH1_DATA_CONFIG(1),
254 USBH1_DATA_CONFIG(2),
255 USBH1_DATA_CONFIG(3),
256 USBH1_DATA_CONFIG(4),
257 USBH1_DATA_CONFIG(5),
258 USBH1_DATA_CONFIG(6),
259 USBH1_DATA_CONFIG(7),
260
261 {
262 /* USB_CLK_EN_B GPIO2[1]*/
263 .pin = MUX_PIN(EIM_D17),
264 .mux = IOMUX_CONFIG_ALT1,
265 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | PAD_CTL_SRE),
266 },
267
268 {
269 /* USB PHY RESETB */
270 .pin = MUX_PIN(EIM_D21),
271 .mux = IOMUX_CONFIG_ALT1,
272 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_KEEPER |
273 PAD_CTL_PUS_100K_PU | PAD_CTL_SRE)
274 },
275 {
276 /* USB HUB RESET */
277 .pin = MUX_PIN(GPIO1_7),
278 .mux = IOMUX_CONFIG_ALT0,
279 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_SRE),
280 },
281 {
282 /* 26M_OSC pin settings */
283 .pin = MUX_PIN(DI1_PIN12),
284 .mux = IOMUX_CONFIG_ALT4,
285 .pad = (PAD_CTL_DSE_HIGH | PAD_CTL_KEEPER |
286 PAD_CTL_SRE),
287 },
288
289 /* end of table */
290 {.pin = IOMUX_CONF_EOT}
291 };
292