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 2010/12/09 04:39:07 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
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 */
204const 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