1 /* $NetBSD: kobo_usb.c,v 1.4 2024/02/22 23:16:10 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Genetec Corporation. All rights reserved. 5 * Written by Hiroyuki Bessho for Genetec Corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: kobo_usb.c,v 1.4 2024/02/22 23:16:10 andvar Exp $"); 31 32 #include "opt_imx.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/conf.h> 37 #include <sys/kernel.h> 38 #include <sys/kthread.h> 39 #include <sys/device.h> 40 #include <sys/intr.h> 41 #include <sys/bus.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/imx50_iomuxreg.h> 56 #include <arm/imx/imx51_ccmreg.h> 57 #include <arm/imx/imx51_ccmvar.h> 58 59 #include "locators.h" 60 61 struct kobo_usbc_softc { 62 struct imxusbc_softc sc_imxusbc; /* Must be first */ 63 }; 64 65 static int imxusbc_match(device_t, cfdata_t, void *); 66 static void imxusbc_attach(device_t, device_t, void *); 67 static void kobo_usb_init(struct imxehci_softc *, uintptr_t); 68 69 static void init_otg(struct imxehci_softc *); 70 static void init_h1(struct imxehci_softc *); 71 72 extern const struct iomux_conf iomux_usb1_config[]; 73 74 /* attach structures */ 75 CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct kobo_usbc_softc), 76 imxusbc_match, imxusbc_attach, NULL, NULL); 77 78 static int 79 imxusbc_match(device_t parent, cfdata_t cf, void *aux) 80 { 81 struct axi_attach_args *aa = aux; 82 83 if (aa->aa_addr == USBOH3_BASE) 84 return 1; 85 return 0; 86 } 87 88 static void 89 imxusbc_attach(device_t parent, device_t self, void *aux) 90 { 91 struct imxusbc_softc *sc = device_private(self); 92 struct axi_attach_args *aa = aux; 93 94 aprint_normal("\n"); 95 aprint_normal(": Universal Serial Bus Controller\n"); 96 97 if (aa->aa_size == AXICF_SIZE_DEFAULT) 98 aa->aa_size = USBOH3_SIZE; 99 100 sc->sc_init_md_hook = kobo_usb_init; 101 sc->sc_intr_establish_md_hook = NULL; 102 sc->sc_setup_md_hook = NULL; 103 104 imxusbc_attach_common(parent, self, aa->aa_iot, aa->aa_addr, aa->aa_size); 105 } 106 107 static void 108 kobo_usb_init(struct imxehci_softc *sc, uintptr_t data) 109 { 110 switch (sc->sc_unit) { 111 case 0: /* OTG controller */ 112 init_otg(sc); 113 break; 114 case 1: /* EHCI Host 1 */ 115 init_h1(sc); 116 break; 117 default: 118 aprint_error_dev(sc->sc_hsc.sc_dev, "unit %d not supported\n", 119 sc->sc_unit); 120 } 121 } 122 123 static void 124 init_otg(struct imxehci_softc *sc) 125 { 126 struct imxusbc_softc *usbc = sc->sc_usbc; 127 uint32_t reg; 128 129 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL); 130 reg &= ~USB_CLKONOFF_CTRL_OTG_AHBCLK_OFF; 131 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL, reg); 132 133 sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE; 134 135 imxehci_reset(sc); 136 137 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0); 138 reg |= PHYCTRL0_OTG_OVER_CUR_DIS | PHYCTRL0_SUSPENDM; 139 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0, reg); 140 141 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL); 142 reg &= ~USBCTRL_OWIR; 143 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL, reg); 144 145 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1); 146 reg = (reg & ~PHYCTRL1_PLLDIVVALUE_MASK) | PHYCTRL1_PLLDIVVALUE_24MHZ; 147 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1, reg); 148 } 149 150 static void 151 init_h1(struct imxehci_softc *sc) 152 { 153 struct imxusbc_softc *usbc = sc->sc_usbc; 154 uint32_t reg; 155 156 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL); 157 reg &= ~USB_CLKONOFF_CTRL_H1_AHBCLK_OFF; 158 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL, reg); 159 160 imxehci_reset(sc); 161 162 /* select INTERNAL PHY interface for Host 1 */ 163 sc->sc_iftype = IMXUSBC_IF_UTMI; 164 165 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, 166 USBOH3_USBCTRL); 167 reg |= USBCTRL_H1PM; 168 reg &= ~(USBCTRL_H1WIE); 169 reg &= ~(USBCTRL_H1UIE); 170 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, 171 USBOH3_USBCTRL, reg); 172 173 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0); 174 reg &= ~PHYCTRL0_H1_OVER_CUR_DIS; 175 reg |= PHYCTRL0_H1_OVER_CUR_POL; 176 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,USBOH3_PHYCTRL0 , reg); 177 178 delay(1000); 179 180 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_1); 181 reg &= ~PHYCTRL1_PLLDIVVALUE_MASK; 182 reg |= PHYCTRL1_PLLDIVVALUE_24MHZ; 183 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_1, reg); 184 185 reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_0); 186 reg &= ~PHYCTRL0_CHGRDETON; 187 reg &= ~PHYCTRL0_CHGRDETEN; 188 bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_0, reg); 189 } 190 191 192