1 1.13 rin /* $NetBSD: dwc2_fdt.c,v 1.13 2023/07/31 04:59:47 rin Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jmcneill * by Nick Hudson 9 1.1 jmcneill * 10 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 11 1.1 jmcneill * modification, are permitted provided that the following conditions 12 1.1 jmcneill * are met: 13 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 14 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 15 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 17 1.1 jmcneill * documentation and/or other materials provided with the distribution. 18 1.1 jmcneill * 19 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jmcneill */ 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/cdefs.h> 33 1.13 rin __KERNEL_RCSID(0, "$NetBSD: dwc2_fdt.c,v 1.13 2023/07/31 04:59:47 rin Exp $"); 34 1.1 jmcneill 35 1.1 jmcneill #include <sys/param.h> 36 1.1 jmcneill #include <sys/systm.h> 37 1.1 jmcneill #include <sys/device.h> 38 1.1 jmcneill #include <sys/mutex.h> 39 1.1 jmcneill #include <sys/bus.h> 40 1.1 jmcneill #include <sys/workqueue.h> 41 1.1 jmcneill 42 1.1 jmcneill #include <dev/fdt/fdtvar.h> 43 1.1 jmcneill 44 1.1 jmcneill #include <dev/usb/usb.h> 45 1.1 jmcneill #include <dev/usb/usbdi.h> 46 1.1 jmcneill #include <dev/usb/usbdivar.h> 47 1.1 jmcneill #include <dev/usb/usb_mem.h> 48 1.1 jmcneill 49 1.1 jmcneill #include <dwc2/dwc2var.h> 50 1.1 jmcneill 51 1.1 jmcneill #include <dwc2/dwc2.h> 52 1.1 jmcneill #include "dwc2_core.h" 53 1.1 jmcneill 54 1.1 jmcneill struct dwc2_fdt_softc { 55 1.1 jmcneill struct dwc2_softc sc_dwc2; 56 1.1 jmcneill 57 1.1 jmcneill struct dwc2_core_params sc_params; 58 1.1 jmcneill 59 1.1 jmcneill void *sc_ih; 60 1.1 jmcneill int sc_phandle; 61 1.1 jmcneill }; 62 1.1 jmcneill 63 1.1 jmcneill static int dwc2_fdt_match(device_t, struct cfdata *, void *); 64 1.1 jmcneill static void dwc2_fdt_attach(device_t, device_t, void *); 65 1.1 jmcneill static void dwc2_fdt_deferred(device_t); 66 1.1 jmcneill 67 1.4 jmcneill static void dwc2_fdt_amlogic_params(struct dwc2_fdt_softc *, struct dwc2_core_params *); 68 1.1 jmcneill static void dwc2_fdt_rockchip_params(struct dwc2_fdt_softc *, struct dwc2_core_params *); 69 1.1 jmcneill 70 1.1 jmcneill struct dwc2_fdt_config { 71 1.1 jmcneill void (*params)(struct dwc2_fdt_softc *, struct dwc2_core_params *); 72 1.1 jmcneill }; 73 1.1 jmcneill 74 1.1 jmcneill static const struct dwc2_fdt_config dwc2_fdt_rk3066_config = { 75 1.1 jmcneill .params = dwc2_fdt_rockchip_params, 76 1.1 jmcneill }; 77 1.1 jmcneill 78 1.4 jmcneill static const struct dwc2_fdt_config dwc2_fdt_meson8b_config = { 79 1.4 jmcneill .params = dwc2_fdt_amlogic_params, 80 1.4 jmcneill }; 81 1.4 jmcneill 82 1.2 jmcneill static const struct dwc2_fdt_config dwc2_fdt_generic_config = { 83 1.2 jmcneill }; 84 1.2 jmcneill 85 1.7 thorpej static const struct device_compatible_entry compat_data[] = { 86 1.7 thorpej { .compat = "amlogic,meson8b-usb", 87 1.7 thorpej .data = &dwc2_fdt_meson8b_config }, 88 1.7 thorpej { .compat = "amlogic,meson-gxbb-usb", 89 1.7 thorpej .data = &dwc2_fdt_meson8b_config }, 90 1.7 thorpej { .compat = "rockchip,rk3066-usb", 91 1.7 thorpej .data = &dwc2_fdt_rk3066_config }, 92 1.7 thorpej { .compat = "snps,dwc2", 93 1.7 thorpej .data = &dwc2_fdt_generic_config }, 94 1.7 thorpej 95 1.9 thorpej DEVICE_COMPAT_EOL 96 1.1 jmcneill }; 97 1.1 jmcneill 98 1.1 jmcneill CFATTACH_DECL_NEW(dwc2_fdt, sizeof(struct dwc2_fdt_softc), 99 1.1 jmcneill dwc2_fdt_match, dwc2_fdt_attach, NULL, NULL); 100 1.1 jmcneill 101 1.1 jmcneill /* ARGSUSED */ 102 1.1 jmcneill static int 103 1.1 jmcneill dwc2_fdt_match(device_t parent, struct cfdata *match, void *aux) 104 1.1 jmcneill { 105 1.1 jmcneill struct fdt_attach_args * const faa = aux; 106 1.1 jmcneill 107 1.10 thorpej return of_compatible_match(faa->faa_phandle, compat_data); 108 1.1 jmcneill } 109 1.1 jmcneill 110 1.1 jmcneill /* ARGSUSED */ 111 1.1 jmcneill static void 112 1.1 jmcneill dwc2_fdt_attach(device_t parent, device_t self, void *aux) 113 1.1 jmcneill { 114 1.1 jmcneill struct dwc2_fdt_softc *sc = device_private(self); 115 1.1 jmcneill struct fdt_attach_args * const faa = aux; 116 1.1 jmcneill const int phandle = faa->faa_phandle; 117 1.1 jmcneill const struct dwc2_fdt_config *conf = 118 1.10 thorpej of_compatible_lookup(phandle, compat_data)->data; 119 1.1 jmcneill char intrstr[128]; 120 1.1 jmcneill struct fdtbus_phy *phy; 121 1.1 jmcneill struct clk *clk; 122 1.1 jmcneill bus_addr_t addr; 123 1.1 jmcneill bus_size_t size; 124 1.1 jmcneill int error; 125 1.1 jmcneill 126 1.1 jmcneill const char *dr_mode = fdtbus_get_string(phandle, "dr_mode"); 127 1.1 jmcneill if (dr_mode == NULL || strcmp(dr_mode, "host") != 0) { 128 1.1 jmcneill aprint_error(": mode '%s' not supported\n", dr_mode); 129 1.1 jmcneill return; 130 1.1 jmcneill } 131 1.1 jmcneill 132 1.1 jmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 133 1.1 jmcneill aprint_error(": couldn't get registers\n"); 134 1.1 jmcneill return; 135 1.1 jmcneill } 136 1.1 jmcneill 137 1.1 jmcneill clk = fdtbus_clock_get(phandle, "otg"); 138 1.1 jmcneill if (clk == NULL || clk_enable(clk) != 0) { 139 1.1 jmcneill aprint_error(": couldn't enable otg clock\n"); 140 1.1 jmcneill return; 141 1.1 jmcneill } 142 1.1 jmcneill 143 1.1 jmcneill /* Enable optional phy */ 144 1.1 jmcneill phy = fdtbus_phy_get(phandle, "usb2-phy"); 145 1.1 jmcneill if (phy && fdtbus_phy_enable(phy, true) != 0) { 146 1.1 jmcneill aprint_error(": couldn't enable phy\n"); 147 1.1 jmcneill return; 148 1.1 jmcneill } 149 1.1 jmcneill 150 1.1 jmcneill sc->sc_phandle = phandle; 151 1.1 jmcneill sc->sc_dwc2.sc_dev = self; 152 1.1 jmcneill sc->sc_dwc2.sc_iot = faa->faa_bst; 153 1.1 jmcneill sc->sc_dwc2.sc_bus.ub_dmatag = faa->faa_dmat; 154 1.1 jmcneill 155 1.1 jmcneill error = bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_dwc2.sc_ioh); 156 1.1 jmcneill if (error) { 157 1.1 jmcneill aprint_error(": couldn't map device\n"); 158 1.1 jmcneill return; 159 1.1 jmcneill } 160 1.1 jmcneill 161 1.1 jmcneill if (conf->params) { 162 1.1 jmcneill conf->params(sc, &sc->sc_params); 163 1.1 jmcneill sc->sc_dwc2.sc_params = &sc->sc_params; 164 1.1 jmcneill } 165 1.1 jmcneill 166 1.1 jmcneill if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 167 1.1 jmcneill aprint_error(": failed to decode interrupt\n"); 168 1.1 jmcneill return; 169 1.1 jmcneill } 170 1.1 jmcneill 171 1.1 jmcneill aprint_naive("\n"); 172 1.1 jmcneill aprint_normal(": DesignWare USB2 OTG\n"); 173 1.1 jmcneill 174 1.6 jmcneill sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 175 1.6 jmcneill FDT_INTR_MPSAFE, dwc2_intr, &sc->sc_dwc2, device_xname(self)); 176 1.1 jmcneill if (sc->sc_ih == NULL) { 177 1.1 jmcneill aprint_error_dev(self, "failed to establish interrupt %s\n", 178 1.1 jmcneill intrstr); 179 1.1 jmcneill goto fail; 180 1.1 jmcneill } 181 1.1 jmcneill aprint_normal_dev(self, "interrupting on %s\n", intrstr); 182 1.1 jmcneill config_interrupts(self, dwc2_fdt_deferred); 183 1.1 jmcneill 184 1.1 jmcneill return; 185 1.1 jmcneill 186 1.1 jmcneill fail: 187 1.1 jmcneill if (sc->sc_ih) { 188 1.1 jmcneill fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 189 1.1 jmcneill sc->sc_ih = NULL; 190 1.1 jmcneill } 191 1.1 jmcneill bus_space_unmap(sc->sc_dwc2.sc_iot, sc->sc_dwc2.sc_ioh, size); 192 1.1 jmcneill } 193 1.1 jmcneill 194 1.1 jmcneill static void 195 1.1 jmcneill dwc2_fdt_deferred(device_t self) 196 1.1 jmcneill { 197 1.1 jmcneill struct dwc2_fdt_softc *sc = device_private(self); 198 1.1 jmcneill int error; 199 1.1 jmcneill 200 1.1 jmcneill error = dwc2_init(&sc->sc_dwc2); 201 1.1 jmcneill if (error != 0) { 202 1.1 jmcneill aprint_error_dev(self, "couldn't initialize host, error=%d\n", 203 1.1 jmcneill error); 204 1.1 jmcneill return; 205 1.1 jmcneill } 206 1.1 jmcneill sc->sc_dwc2.sc_child = config_found(sc->sc_dwc2.sc_dev, 207 1.12 thorpej &sc->sc_dwc2.sc_bus, usbctlprint, CFARGS_NONE); 208 1.1 jmcneill } 209 1.1 jmcneill 210 1.1 jmcneill static void 211 1.4 jmcneill dwc2_fdt_amlogic_params(struct dwc2_fdt_softc *sc, struct dwc2_core_params *params) 212 1.4 jmcneill { 213 1.4 jmcneill dwc2_set_all_params(params, -1); 214 1.4 jmcneill 215 1.4 jmcneill params->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; 216 1.4 jmcneill params->speed = DWC2_SPEED_PARAM_HIGH; 217 1.5 jmcneill params->dma_enable = 1; 218 1.13 rin params->enable_dynamic_fifo = 1; 219 1.4 jmcneill params->host_rx_fifo_size = 512; 220 1.4 jmcneill params->host_nperio_tx_fifo_size = 500; 221 1.4 jmcneill params->host_perio_tx_fifo_size = 500; 222 1.4 jmcneill params->host_channels = 16; 223 1.4 jmcneill params->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; 224 1.13 rin params->reload_ctl = 1; 225 1.4 jmcneill params->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << GAHBCFG_HBSTLEN_SHIFT; 226 1.4 jmcneill #ifdef DWC2_POWER_DOWN_PARAM_NONE 227 1.4 jmcneill params->power_down = DWC2_POWER_DOWN_PARAM_NONE; 228 1.4 jmcneill #endif 229 1.4 jmcneill } 230 1.4 jmcneill 231 1.4 jmcneill static void 232 1.1 jmcneill dwc2_fdt_rockchip_params(struct dwc2_fdt_softc *sc, struct dwc2_core_params *params) 233 1.1 jmcneill { 234 1.1 jmcneill dwc2_set_all_params(params, -1); 235 1.1 jmcneill 236 1.1 jmcneill params->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; 237 1.1 jmcneill params->host_rx_fifo_size = 525; 238 1.1 jmcneill params->host_nperio_tx_fifo_size = 128; 239 1.1 jmcneill params->host_perio_tx_fifo_size = 256; 240 1.1 jmcneill params->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; 241 1.1 jmcneill } 242