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 61struct kobo_usbc_softc { 62 struct imxusbc_softc sc_imxusbc; /* Must be first */ 63}; 64 65static int imxusbc_match(device_t, cfdata_t, void *); 66static void imxusbc_attach(device_t, device_t, void *); 67static void kobo_usb_init(struct imxehci_softc *, uintptr_t); 68 69static void init_otg(struct imxehci_softc *); 70static void init_h1(struct imxehci_softc *); 71 72extern const struct iomux_conf iomux_usb1_config[]; 73 74/* attach structures */ 75CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct kobo_usbc_softc), 76 imxusbc_match, imxusbc_attach, NULL, NULL); 77 78static int 79imxusbc_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 88static void 89imxusbc_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 107static void 108kobo_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 123static void 124init_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 150static void 151init_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