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 58struct netwalker_usbc_softc { 59 struct imxusbc_softc sc_imxusbc; /* Must be first */ 60}; 61 62static int imxusbc_match(device_t, cfdata_t, void *); 63static void imxusbc_attach(device_t, device_t, void *); 64static void netwalker_usb_init(struct imxehci_softc *, uintptr_t); 65 66static void init_otg(struct imxehci_softc *); 67static void init_h1(struct imxehci_softc *); 68 69extern const struct iomux_conf iomux_usb1_config[]; 70 71/* attach structures */ 72CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct netwalker_usbc_softc), 73 imxusbc_match, imxusbc_attach, NULL, NULL); 74 75static int 76imxusbc_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 86static void 87imxusbc_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 105static void 106netwalker_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 121static void 122init_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 144static void 145init_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 */ 207const 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