Home | History | Annotate | Line # | Download | only in netwalker
      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
     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
     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
    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
    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
    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