netwalker_usb.c revision 1.5
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.5 2019/07/24 11:20:55 hkenken 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
54struct netwalker_usbc_softc {
55	struct imxusbc_softc sc_imxusbc; /* Must be first */
56};
57
58static int	imxusbc_match(device_t, cfdata_t, void *);
59static void	imxusbc_attach(device_t, device_t, void *);
60static void	netwalker_usb_init(struct imxehci_softc *);
61
62static void	init_otg(struct imxehci_softc *);
63static void	init_h1(struct imxehci_softc *);
64
65extern const struct iomux_conf iomux_usb1_config[];
66
67/* attach structures */
68CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct netwalker_usbc_softc),
69    imxusbc_match, imxusbc_attach, NULL, NULL);
70
71static int
72imxusbc_match(device_t parent, cfdata_t cf, void *aux)
73{
74	struct axi_attach_args *aa = aux;
75
76	printf("%s\n", __func__);
77
78	if (aa->aa_addr == USBOH3_BASE)
79		return 1;
80	return 0;
81}
82
83static void
84imxusbc_attach(device_t parent, device_t self, void *aux)
85{
86	struct imxusbc_softc *sc = device_private(self);
87	struct axi_attach_args *aa = aux;
88
89	aprint_normal("\n");
90	aprint_normal(": Universal Serial Bus Controller\n");
91
92	if (aa->aa_size == AXICF_SIZE_DEFAULT)
93		aa->aa_size = USBOH3_SIZE;
94
95	sc->sc_init_md_hook = netwalker_usb_init;
96	sc->sc_intr_establish_md_hook = NULL;
97	sc->sc_setup_md_hook = NULL;
98
99	imxusbc_attach_common(parent, self, aa->aa_iot, aa->aa_addr, aa->aa_size);
100}
101
102static void
103netwalker_usb_init(struct imxehci_softc *sc)
104{
105	switch (sc->sc_unit) {
106	case 0:	/* OTG controller */
107		init_otg(sc);
108		break;
109	case 1:	/* EHCI Host 1 */
110		init_h1(sc);
111		break;
112	default:
113		aprint_error_dev(sc->sc_hsc.sc_dev, "unit %d not supported\n",
114		    sc->sc_unit);
115	}
116}
117
118static void
119init_otg(struct imxehci_softc *sc)
120{
121	struct imxusbc_softc *usbc = sc->sc_usbc;
122	uint32_t reg;
123
124	sc->sc_iftype = IMXUSBC_IF_UTMI;
125
126	imxehci_reset(sc);
127
128	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0);
129	reg |= PHYCTRL0_OTG_OVER_CUR_DIS;
130	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0, reg);
131
132	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL);
133	reg &= ~(USBCTRL_OWIR|USBCTRL_OPM);
134	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL, reg);
135
136	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1);
137	reg = (reg & ~PHYCTRL1_PLLDIVVALUE_MASK) | PHYCTRL1_PLLDIVVALUE_24MHZ;
138	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1, reg);
139}
140
141static void
142init_h1(struct imxehci_softc *sc)
143{
144	struct imxusbc_softc *usbc = sc->sc_usbc;
145	uint32_t reg;
146
147	/* output HIGH to USBH1_STP */
148	gpio_data_write(GPIO_NO(1, 27), 1);
149	gpio_set_direction(GPIO_NO(1, 27), GPIO_DIR_OUT);
150
151	iomux_mux_config(iomux_usb1_config);
152
153	delay(100 * 1000);
154
155	/* XXX enable USB clock */
156
157	imxehci_reset(sc);
158
159	/* select external clock for Host 1 */
160	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
161			       USBOH3_USBCTRL1);
162	reg |= USBCTRL1_UH1_EXT_CLK_EN;
163	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
164			  USBOH3_USBCTRL1, reg);
165
166
167	/* select ULPI interface for Host 1 */
168	sc->sc_iftype = IMXUSBC_IF_ULPI;
169
170	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
171			       USBOH3_USBCTRL);
172	reg &= ~(USBCTRL_H1PM);
173	reg |= USBCTRL_H1UIE|USBCTRL_H1WIE;
174	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
175			  USBOH3_USBCTRL, reg);
176
177	iomux_set_function(MUX_PIN(USBH1_STP), IOMUX_CONFIG_ALT0);
178
179
180	/* HUB RESET release */
181	gpio_data_write(GPIO_NO(1, 7), 1);
182	gpio_set_direction(GPIO_NO(1, 7), GPIO_DIR_OUT);
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 = 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		/* 26M_OSC pin settings */
280		.pin = MUX_PIN(DI1_PIN12),
281		.mux = IOMUX_CONFIG_ALT4,
282		.pad = (PAD_CTL_DSE_HIGH | PAD_CTL_KEEPER |
283		    PAD_CTL_SRE),
284	},
285
286	/* end of table */
287	{.pin = IOMUX_CONF_EOT}
288};
289