netwalker_usb.c revision 1.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.2 2012/04/15 10:16:37 bsh 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
55struct netwalker_usbc_softc {
56	struct imxusbc_softc  sc_imxusbc;
57};
58
59
60static int	imxusbc_match(device_t, cfdata_t, void *);
61static void	imxusbc_attach(device_t, device_t, void *);
62static void	netwalker_usb_init(struct imxehci_softc *);
63
64static void	init_otg(struct imxehci_softc *);
65static void	init_h1(struct imxehci_softc *);
66
67extern const struct iomux_conf iomux_usb1_config[];
68
69/* attach structures */
70CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct netwalker_usbc_softc),
71    imxusbc_match, imxusbc_attach, NULL, NULL);
72
73static int
74imxusbc_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
85static void
86imxusbc_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
98static void
99netwalker_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
114static void
115init_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
140static void
141init_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	/* Drive 26M_OSC_EN line high 3_1 */
184	gpio_data_write(GPIO_NO(3, 1), 1);
185	gpio_set_direction(GPIO_NO(3, 1), GPIO_DIR_OUT);
186
187	/* Drive USB_CLK_EN_B line low  2_1 */
188	gpio_data_write(GPIO_NO(2, 1), 0);
189	gpio_set_direction(GPIO_NO(2, 1), GPIO_DIR_IN);
190
191	/* MX51_PIN_EIM_D21 - De-assert USB PHY RESETB */
192	delay(10 * 1000);
193	gpio_data_write(GPIO_NO(2, 5), 1);
194	gpio_set_direction(GPIO_NO(2, 5), GPIO_DIR_OUT);
195	iomux_set_function(MUX_PIN(EIM_D21), IOMUX_CONFIG_ALT1);
196	delay(5 * 1000);
197}
198
199/*
200 * IOMUX setting for USB Host1
201 * taken from Linux driver
202 */
203const struct iomux_conf iomux_usb1_config[] = {
204
205	{
206		/* Initially setup this pin for GPIO, and change to
207		 * USBH1_STP later */
208		.pin = MUX_PIN(USBH1_STP),
209		.mux = IOMUX_CONFIG_ALT2,
210		.pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
211		    PAD_CTL_KEEPER | PAD_CTL_HYS)
212	},
213
214	{
215		/* Clock */
216		.pin = MUX_PIN(USBH1_CLK),
217		.mux = IOMUX_CONFIG_ALT0,
218		.pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
219		    PAD_CTL_KEEPER | PAD_CTL_HYS)
220	},
221	{
222		/* DIR */
223		.pin = MUX_PIN(USBH1_DIR),
224		.mux = IOMUX_CONFIG_ALT0,
225		.pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
226		    PAD_CTL_KEEPER | PAD_CTL_HYS)
227	},
228
229	{
230		/* NXT */
231		.pin = MUX_PIN(USBH1_NXT),
232		.mux = IOMUX_CONFIG_ALT0,
233		.pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |
234		    PAD_CTL_KEEPER | PAD_CTL_HYS)
235	},
236
237#define	USBH1_DATA_CONFIG(n)					\
238	{							\
239		/* DATA n */					\
240		.pin = MUX_PIN(USBH1_DATA##n),			\
241		.mux = IOMUX_CONFIG_ALT0,			\
242		.pad = (PAD_CTL_SRE | PAD_CTL_DSE_HIGH |	\
243		    PAD_CTL_KEEPER | PAD_CTL_PUS_100K_PU |	\
244		    PAD_CTL_HYS),				\
245		/* XXX: what does 100K_PU with KEEPER ? */	\
246	}
247
248	USBH1_DATA_CONFIG(0),
249	USBH1_DATA_CONFIG(1),
250	USBH1_DATA_CONFIG(2),
251	USBH1_DATA_CONFIG(3),
252	USBH1_DATA_CONFIG(4),
253	USBH1_DATA_CONFIG(5),
254	USBH1_DATA_CONFIG(6),
255	USBH1_DATA_CONFIG(7),
256
257	{
258		/* USB_CLK_EN_B  GPIO2[1]*/
259		.pin = MUX_PIN(EIM_D17),
260		.mux = IOMUX_CONFIG_ALT1,
261		.pad = (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | PAD_CTL_SRE),
262	},
263
264	{
265		/* USB PHY RESETB */
266		.pin = MUX_PIN(EIM_D21),
267		.mux = IOMUX_CONFIG_ALT1,
268		.pad = (PAD_CTL_DSE_HIGH | PAD_CTL_KEEPER |
269		    PAD_CTL_PUS_100K_PU | PAD_CTL_SRE)
270	},
271	{
272		/* USB HUB RESET */
273		.pin = MUX_PIN(GPIO1_7),
274		.mux = IOMUX_CONFIG_ALT0,
275		.pad = (PAD_CTL_DSE_HIGH | PAD_CTL_SRE),
276	},
277
278	/* end of table */
279	{.pin = IOMUX_CONF_EOT}
280};
281