xref: /netbsd-src/sys/arch/evbarm/netwalker/netwalker_usb.c (revision 9a3e0ce89e49e677234f3b346348e7bd1c9b0ede)
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