1*d11f81afSAdrian Chadd /*- 2*d11f81afSAdrian Chadd * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*d11f81afSAdrian Chadd * 4*d11f81afSAdrian Chadd * Copyright (c) 2021, Adrian Chadd <adrian@FreeBSD.org> 5*d11f81afSAdrian Chadd * 6*d11f81afSAdrian Chadd * Redistribution and use in source and binary forms, with or without 7*d11f81afSAdrian Chadd * modification, are permitted provided that the following conditions 8*d11f81afSAdrian Chadd * are met: 9*d11f81afSAdrian Chadd * 1. Redistributions of source code must retain the above copyright 10*d11f81afSAdrian Chadd * notice unmodified, this list of conditions, and the following 11*d11f81afSAdrian Chadd * disclaimer. 12*d11f81afSAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 13*d11f81afSAdrian Chadd * notice, this list of conditions and the following disclaimer in the 14*d11f81afSAdrian Chadd * documentation and/or other materials provided with the distribution. 15*d11f81afSAdrian Chadd * 16*d11f81afSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*d11f81afSAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*d11f81afSAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*d11f81afSAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*d11f81afSAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*d11f81afSAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*d11f81afSAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*d11f81afSAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*d11f81afSAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*d11f81afSAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*d11f81afSAdrian Chadd * SUCH DAMAGE. 27*d11f81afSAdrian Chadd */ 28*d11f81afSAdrian Chadd 29*d11f81afSAdrian Chadd #include <sys/cdefs.h> 30*d11f81afSAdrian Chadd __FBSDID("$FreeBSD$"); 31*d11f81afSAdrian Chadd 32*d11f81afSAdrian Chadd #include <sys/param.h> 33*d11f81afSAdrian Chadd #include <sys/systm.h> 34*d11f81afSAdrian Chadd 35*d11f81afSAdrian Chadd #include <sys/bus.h> 36*d11f81afSAdrian Chadd #include <sys/interrupt.h> 37*d11f81afSAdrian Chadd #include <sys/malloc.h> 38*d11f81afSAdrian Chadd #include <sys/lock.h> 39*d11f81afSAdrian Chadd #include <sys/mutex.h> 40*d11f81afSAdrian Chadd #include <sys/kernel.h> 41*d11f81afSAdrian Chadd #include <sys/module.h> 42*d11f81afSAdrian Chadd #include <sys/rman.h> 43*d11f81afSAdrian Chadd #include <sys/gpio.h> 44*d11f81afSAdrian Chadd 45*d11f81afSAdrian Chadd #include <vm/vm.h> 46*d11f81afSAdrian Chadd #include <vm/pmap.h> 47*d11f81afSAdrian Chadd #include <vm/vm_extern.h> 48*d11f81afSAdrian Chadd 49*d11f81afSAdrian Chadd #include <machine/bus.h> 50*d11f81afSAdrian Chadd #include <machine/cpu.h> 51*d11f81afSAdrian Chadd 52*d11f81afSAdrian Chadd #include <dev/fdt/fdt_common.h> 53*d11f81afSAdrian Chadd #include <dev/fdt/fdt_pinctrl.h> 54*d11f81afSAdrian Chadd 55*d11f81afSAdrian Chadd #include <dev/gpio/gpiobusvar.h> 56*d11f81afSAdrian Chadd #include <dev/ofw/ofw_bus.h> 57*d11f81afSAdrian Chadd #include <dev/ofw/ofw_bus_subr.h> 58*d11f81afSAdrian Chadd 59*d11f81afSAdrian Chadd #include <dev/qcom_tcsr/qcom_tcsr_var.h> 60*d11f81afSAdrian Chadd #include <dev/qcom_tcsr/qcom_tcsr_reg.h> 61*d11f81afSAdrian Chadd 62*d11f81afSAdrian Chadd /* 63*d11f81afSAdrian Chadd * The linux-msm branches that support IPQ4018 use "ipq,tcsr". 64*d11f81afSAdrian Chadd * The openwrt addons use qcom,tcsr. So for now support both. 65*d11f81afSAdrian Chadd * 66*d11f81afSAdrian Chadd * Also, it's not quite clear yet (since this is the first port!) 67*d11f81afSAdrian Chadd * whether these options and registers are specific to the QCA IPQ401x 68*d11f81afSAdrian Chadd * part or show up in different linux branches as different registers 69*d11f81afSAdrian Chadd * but with the same driver/naming here. Let's hope that doesn't 70*d11f81afSAdrian Chadd * happen. 71*d11f81afSAdrian Chadd */ 72*d11f81afSAdrian Chadd static struct ofw_compat_data compat_data[] = { 73*d11f81afSAdrian Chadd { "qcom,tcsr", 1 }, 74*d11f81afSAdrian Chadd { "ipq,tcsr", 1 }, 75*d11f81afSAdrian Chadd { NULL, 0 } 76*d11f81afSAdrian Chadd }; 77*d11f81afSAdrian Chadd 78*d11f81afSAdrian Chadd static int 79*d11f81afSAdrian Chadd qcom_tcsr_probe(device_t dev) 80*d11f81afSAdrian Chadd { 81*d11f81afSAdrian Chadd 82*d11f81afSAdrian Chadd if (!ofw_bus_status_okay(dev)) 83*d11f81afSAdrian Chadd return (ENXIO); 84*d11f81afSAdrian Chadd 85*d11f81afSAdrian Chadd if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 86*d11f81afSAdrian Chadd return (ENXIO); 87*d11f81afSAdrian Chadd 88*d11f81afSAdrian Chadd device_set_desc(dev, "Qualcomm Core Top Control and Status Driver"); 89*d11f81afSAdrian Chadd return (BUS_PROBE_DEFAULT); 90*d11f81afSAdrian Chadd } 91*d11f81afSAdrian Chadd 92*d11f81afSAdrian Chadd static int 93*d11f81afSAdrian Chadd qcom_tcsr_attach(device_t dev) 94*d11f81afSAdrian Chadd { 95*d11f81afSAdrian Chadd struct qcom_tcsr_softc *sc = device_get_softc(dev); 96*d11f81afSAdrian Chadd int rid, ret; 97*d11f81afSAdrian Chadd uint32_t val; 98*d11f81afSAdrian Chadd 99*d11f81afSAdrian Chadd sc->sc_dev = dev; 100*d11f81afSAdrian Chadd 101*d11f81afSAdrian Chadd /* 102*d11f81afSAdrian Chadd * Hardware version is stored in the ofw_compat_data table. 103*d11f81afSAdrian Chadd */ 104*d11f81afSAdrian Chadd sc->hw_version = 105*d11f81afSAdrian Chadd ofw_bus_search_compatible(dev, compat_data)->ocd_data; 106*d11f81afSAdrian Chadd 107*d11f81afSAdrian Chadd mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 108*d11f81afSAdrian Chadd 109*d11f81afSAdrian Chadd rid = 0; 110*d11f81afSAdrian Chadd sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 111*d11f81afSAdrian Chadd RF_ACTIVE); 112*d11f81afSAdrian Chadd if (!sc->sc_mem_res) { 113*d11f81afSAdrian Chadd device_printf(dev, "ERROR: Could not map memory\n"); 114*d11f81afSAdrian Chadd ret = ENXIO; 115*d11f81afSAdrian Chadd goto error; 116*d11f81afSAdrian Chadd } 117*d11f81afSAdrian Chadd 118*d11f81afSAdrian Chadd /* 119*d11f81afSAdrian Chadd * Parse out the open firmware entries to see which particular 120*d11f81afSAdrian Chadd * configurations we need to set here. 121*d11f81afSAdrian Chadd */ 122*d11f81afSAdrian Chadd 123*d11f81afSAdrian Chadd /* 124*d11f81afSAdrian Chadd * USB control select. 125*d11f81afSAdrian Chadd * 126*d11f81afSAdrian Chadd * For linux-msm on the IPQ401x, it actually calls into the SCM 127*d11f81afSAdrian Chadd * to make the change. OpenWRT just does a register write. 128*d11f81afSAdrian Chadd * We'll do the register write for now. 129*d11f81afSAdrian Chadd */ 130*d11f81afSAdrian Chadd if (OF_getencprop(ofw_bus_get_node(dev), "qcom,usb-ctrl-select", 131*d11f81afSAdrian Chadd &val, sizeof(val)) > 0) { 132*d11f81afSAdrian Chadd if (bootverbose) 133*d11f81afSAdrian Chadd device_printf(sc->sc_dev, 134*d11f81afSAdrian Chadd "USB control select (val 0x%x)\n", 135*d11f81afSAdrian Chadd val); 136*d11f81afSAdrian Chadd QCOM_TCSR_WRITE_4(sc, QCOM_TCSR_USB_PORT_SEL, val); 137*d11f81afSAdrian Chadd } 138*d11f81afSAdrian Chadd 139*d11f81afSAdrian Chadd /* 140*d11f81afSAdrian Chadd * USB high speed phy mode select. 141*d11f81afSAdrian Chadd */ 142*d11f81afSAdrian Chadd if (OF_getencprop(ofw_bus_get_node(dev), "qcom,usb-hsphy-mode-select", 143*d11f81afSAdrian Chadd &val, sizeof(val)) > 0) { 144*d11f81afSAdrian Chadd if (bootverbose) 145*d11f81afSAdrian Chadd device_printf(sc->sc_dev, 146*d11f81afSAdrian Chadd "USB high speed PHY mode select (val 0x%x)\n", 147*d11f81afSAdrian Chadd val); 148*d11f81afSAdrian Chadd QCOM_TCSR_WRITE_4(sc, QCOM_TCSR_USB_HSPHY_CONFIG, val); 149*d11f81afSAdrian Chadd } 150*d11f81afSAdrian Chadd 151*d11f81afSAdrian Chadd /* 152*d11f81afSAdrian Chadd * Ethernet switch subsystem interface type select. 153*d11f81afSAdrian Chadd */ 154*d11f81afSAdrian Chadd if (OF_getencprop(ofw_bus_get_node(dev), "qcom,ess-interface-select", 155*d11f81afSAdrian Chadd &val, sizeof(val)) > 0) { 156*d11f81afSAdrian Chadd uint32_t reg; 157*d11f81afSAdrian Chadd 158*d11f81afSAdrian Chadd if (bootverbose) 159*d11f81afSAdrian Chadd device_printf(sc->sc_dev, 160*d11f81afSAdrian Chadd "ESS external interface select (val 0x%x)\n", 161*d11f81afSAdrian Chadd val); 162*d11f81afSAdrian Chadd reg = QCOM_TCSR_READ_4(sc, QCOM_TCSR_ESS_INTERFACE_SEL_OFFSET); 163*d11f81afSAdrian Chadd reg &= ~QCOM_TCSR_ESS_INTERFACE_SEL_MASK; 164*d11f81afSAdrian Chadd reg |= (val & QCOM_TCSR_ESS_INTERFACE_SEL_MASK); 165*d11f81afSAdrian Chadd QCOM_TCSR_WRITE_4(sc, QCOM_TCSR_ESS_INTERFACE_SEL_OFFSET, reg); 166*d11f81afSAdrian Chadd } 167*d11f81afSAdrian Chadd 168*d11f81afSAdrian Chadd /* 169*d11f81afSAdrian Chadd * WiFi GLB select. 170*d11f81afSAdrian Chadd */ 171*d11f81afSAdrian Chadd if (OF_getencprop(ofw_bus_get_node(dev), "qcom,wifi_glb_cfg", 172*d11f81afSAdrian Chadd &val, sizeof(val)) > 0) { 173*d11f81afSAdrian Chadd if (bootverbose) 174*d11f81afSAdrian Chadd device_printf(sc->sc_dev, 175*d11f81afSAdrian Chadd "WIFI GLB select (val 0x%x)\n", 176*d11f81afSAdrian Chadd val); 177*d11f81afSAdrian Chadd QCOM_TCSR_WRITE_4(sc, QCOM_TCSR_WIFI0_GLB_CFG_OFFSET, val); 178*d11f81afSAdrian Chadd QCOM_TCSR_WRITE_4(sc, QCOM_TCSR_WIFI1_GLB_CFG_OFFSET, val); 179*d11f81afSAdrian Chadd } 180*d11f81afSAdrian Chadd 181*d11f81afSAdrian Chadd /* 182*d11f81afSAdrian Chadd * WiFi NOC interconnect memory type. 183*d11f81afSAdrian Chadd */ 184*d11f81afSAdrian Chadd if (OF_getencprop(ofw_bus_get_node(dev), 185*d11f81afSAdrian Chadd "qcom,wifi_noc_memtype_m0_m2", 186*d11f81afSAdrian Chadd &val, sizeof(val)) > 0) { 187*d11f81afSAdrian Chadd if (bootverbose) 188*d11f81afSAdrian Chadd device_printf(sc->sc_dev, 189*d11f81afSAdrian Chadd "WiFi NOC memory type (val 0x%x)\n", 190*d11f81afSAdrian Chadd val); 191*d11f81afSAdrian Chadd QCOM_TCSR_WRITE_4(sc, QCOM_TCSR_PNOC_SNOC_MEMTYPE_M0_M2, val); 192*d11f81afSAdrian Chadd } 193*d11f81afSAdrian Chadd 194*d11f81afSAdrian Chadd return (0); 195*d11f81afSAdrian Chadd 196*d11f81afSAdrian Chadd error: 197*d11f81afSAdrian Chadd if (sc->sc_mem_res) 198*d11f81afSAdrian Chadd bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 199*d11f81afSAdrian Chadd mtx_destroy(&sc->sc_mtx); 200*d11f81afSAdrian Chadd return (ret); 201*d11f81afSAdrian Chadd } 202*d11f81afSAdrian Chadd 203*d11f81afSAdrian Chadd static int 204*d11f81afSAdrian Chadd qcom_tcsr_detach(device_t dev) 205*d11f81afSAdrian Chadd { 206*d11f81afSAdrian Chadd struct qcom_tcsr_softc *sc = device_get_softc(dev); 207*d11f81afSAdrian Chadd 208*d11f81afSAdrian Chadd if (sc->sc_mem_res) 209*d11f81afSAdrian Chadd bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 210*d11f81afSAdrian Chadd 211*d11f81afSAdrian Chadd mtx_destroy(&sc->sc_mtx); 212*d11f81afSAdrian Chadd 213*d11f81afSAdrian Chadd return (0); 214*d11f81afSAdrian Chadd } 215*d11f81afSAdrian Chadd 216*d11f81afSAdrian Chadd static device_method_t qcom_tcsr_methods[] = { 217*d11f81afSAdrian Chadd /* Device interface */ 218*d11f81afSAdrian Chadd DEVMETHOD(device_probe, qcom_tcsr_probe), 219*d11f81afSAdrian Chadd DEVMETHOD(device_attach, qcom_tcsr_attach), 220*d11f81afSAdrian Chadd DEVMETHOD(device_detach, qcom_tcsr_detach), 221*d11f81afSAdrian Chadd 222*d11f81afSAdrian Chadd DEVMETHOD_END 223*d11f81afSAdrian Chadd }; 224*d11f81afSAdrian Chadd 225*d11f81afSAdrian Chadd static driver_t qcom_tcsr_driver = { 226*d11f81afSAdrian Chadd "qcom_tcsr", 227*d11f81afSAdrian Chadd qcom_tcsr_methods, 228*d11f81afSAdrian Chadd sizeof(struct qcom_tcsr_softc), 229*d11f81afSAdrian Chadd }; 230*d11f81afSAdrian Chadd 231*d11f81afSAdrian Chadd static devclass_t qcom_tcsr_devclass; 232*d11f81afSAdrian Chadd 233*d11f81afSAdrian Chadd /* 234*d11f81afSAdrian Chadd * This has to be run early, before the rest of the hardware is potentially 235*d11f81afSAdrian Chadd * probed/attached. 236*d11f81afSAdrian Chadd */ 237*d11f81afSAdrian Chadd EARLY_DRIVER_MODULE(qcom_tcsr, simplebus, qcom_tcsr_driver, 238*d11f81afSAdrian Chadd qcom_tcsr_devclass, 0, 0, 239*d11f81afSAdrian Chadd BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); 240*d11f81afSAdrian Chadd SIMPLEBUS_PNP_INFO(compat_data); 241