1*c2ec63e8Sjmcneill /* $NetBSD: if_bwi_sdio.c,v 1.1 2025/01/19 00:29:29 jmcneill Exp $ */ 2*c2ec63e8Sjmcneill 3*c2ec63e8Sjmcneill /*- 4*c2ec63e8Sjmcneill * Copyright (c) 2025 Jared McNeill <jmcneill@invisible.ca> 5*c2ec63e8Sjmcneill * All rights reserved. 6*c2ec63e8Sjmcneill * 7*c2ec63e8Sjmcneill * Redistribution and use in source and binary forms, with or without 8*c2ec63e8Sjmcneill * modification, are permitted provided that the following conditions 9*c2ec63e8Sjmcneill * are met: 10*c2ec63e8Sjmcneill * 1. Redistributions of source code must retain the above copyright 11*c2ec63e8Sjmcneill * notice, this list of conditions and the following disclaimer. 12*c2ec63e8Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 13*c2ec63e8Sjmcneill * notice, this list of conditions and the following disclaimer in the 14*c2ec63e8Sjmcneill * documentation and/or other materials provided with the distribution. 15*c2ec63e8Sjmcneill * 16*c2ec63e8Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17*c2ec63e8Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18*c2ec63e8Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19*c2ec63e8Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20*c2ec63e8Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21*c2ec63e8Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22*c2ec63e8Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23*c2ec63e8Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24*c2ec63e8Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25*c2ec63e8Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26*c2ec63e8Sjmcneill * POSSIBILITY OF SUCH DAMAGE. 27*c2ec63e8Sjmcneill */ 28*c2ec63e8Sjmcneill 29*c2ec63e8Sjmcneill #include <sys/cdefs.h> 30*c2ec63e8Sjmcneill 31*c2ec63e8Sjmcneill __KERNEL_RCSID(0, "$NetBSD: if_bwi_sdio.c,v 1.1 2025/01/19 00:29:29 jmcneill Exp $"); 32*c2ec63e8Sjmcneill 33*c2ec63e8Sjmcneill #include <sys/param.h> 34*c2ec63e8Sjmcneill #include <sys/bus.h> 35*c2ec63e8Sjmcneill #include <sys/device.h> 36*c2ec63e8Sjmcneill #include <sys/mutex.h> 37*c2ec63e8Sjmcneill #include <sys/systm.h> 38*c2ec63e8Sjmcneill 39*c2ec63e8Sjmcneill #include <net/if.h> 40*c2ec63e8Sjmcneill #include <net/if_dl.h> 41*c2ec63e8Sjmcneill #include <net/if_ether.h> 42*c2ec63e8Sjmcneill #include <net/if_media.h> 43*c2ec63e8Sjmcneill 44*c2ec63e8Sjmcneill #include <netinet/in.h> 45*c2ec63e8Sjmcneill 46*c2ec63e8Sjmcneill #include <net80211/ieee80211_node.h> 47*c2ec63e8Sjmcneill #include <net80211/ieee80211_amrr.h> 48*c2ec63e8Sjmcneill #include <net80211/ieee80211_radiotap.h> 49*c2ec63e8Sjmcneill #include <net80211/ieee80211_var.h> 50*c2ec63e8Sjmcneill 51*c2ec63e8Sjmcneill #include <dev/ic/bwireg.h> 52*c2ec63e8Sjmcneill #include <dev/ic/bwivar.h> 53*c2ec63e8Sjmcneill 54*c2ec63e8Sjmcneill #include <dev/pcmcia/pcmciareg.h> 55*c2ec63e8Sjmcneill 56*c2ec63e8Sjmcneill #include <dev/sdmmc/sdmmcdevs.h> 57*c2ec63e8Sjmcneill #include <dev/sdmmc/sdmmcvar.h> 58*c2ec63e8Sjmcneill 59*c2ec63e8Sjmcneill #define BWI_SDIO_FUNC1_SBADDRLOW 0x1000a 60*c2ec63e8Sjmcneill #define BWI_SDIO_FUNC1_SBADDRMID 0x1000b 61*c2ec63e8Sjmcneill #define BWI_SDIO_FUNC1_SBADDRHI 0x1000c 62*c2ec63e8Sjmcneill 63*c2ec63e8Sjmcneill #define BWI_CISTPL_VENDOR 0x80 64*c2ec63e8Sjmcneill #define BWI_VENDOR_SROMREV 0 65*c2ec63e8Sjmcneill #define BWI_VENDOR_ID 1 66*c2ec63e8Sjmcneill #define BWI_VENDOR_BOARDREV 2 67*c2ec63e8Sjmcneill #define BWI_VENDOR_PA 3 68*c2ec63e8Sjmcneill #define BWI_VENDOR_OEMNAME 4 69*c2ec63e8Sjmcneill #define BWI_VENDOR_CCODE 5 70*c2ec63e8Sjmcneill #define BWI_VENDOR_ANTENNA 6 71*c2ec63e8Sjmcneill #define BWI_VENDOR_ANTGAIN 7 72*c2ec63e8Sjmcneill #define BWI_VENDOR_BFLAGS 8 73*c2ec63e8Sjmcneill #define BWI_VENDOR_LEDS 9 74*c2ec63e8Sjmcneill 75*c2ec63e8Sjmcneill #define BWI_SDIO_REG_OFFSET(ssc, reg) \ 76*c2ec63e8Sjmcneill ((reg) | ((ssc)->sc_sel_regwin & 0x7000)) 77*c2ec63e8Sjmcneill 78*c2ec63e8Sjmcneill #define BWI_SDIO_REG_32BIT_ACCESS 0x8000 79*c2ec63e8Sjmcneill 80*c2ec63e8Sjmcneill static const struct bwi_sdio_product { 81*c2ec63e8Sjmcneill uint16_t vendor; 82*c2ec63e8Sjmcneill uint16_t product; 83*c2ec63e8Sjmcneill } bwi_sdio_products[] = { 84*c2ec63e8Sjmcneill { SDMMC_VENDOR_BROADCOM, SDMMC_PRODUCT_BROADCOM_NINTENDO_WII }, 85*c2ec63e8Sjmcneill }; 86*c2ec63e8Sjmcneill 87*c2ec63e8Sjmcneill struct bwi_sdio_sprom { 88*c2ec63e8Sjmcneill uint16_t pa_params[3]; 89*c2ec63e8Sjmcneill uint16_t board_vendor; 90*c2ec63e8Sjmcneill uint16_t card_flags; 91*c2ec63e8Sjmcneill uint8_t srom_rev; 92*c2ec63e8Sjmcneill uint8_t board_rev; 93*c2ec63e8Sjmcneill uint8_t idle_tssi; 94*c2ec63e8Sjmcneill uint8_t max_txpwr; 95*c2ec63e8Sjmcneill uint8_t country_code; 96*c2ec63e8Sjmcneill uint8_t ant_avail; 97*c2ec63e8Sjmcneill uint8_t ant_gain; 98*c2ec63e8Sjmcneill uint8_t gpio[4]; 99*c2ec63e8Sjmcneill }; 100*c2ec63e8Sjmcneill 101*c2ec63e8Sjmcneill struct bwi_sdio_softc { 102*c2ec63e8Sjmcneill struct bwi_softc sc_base; 103*c2ec63e8Sjmcneill 104*c2ec63e8Sjmcneill struct sdmmc_function *sc_sf; 105*c2ec63e8Sjmcneill struct bwi_sdio_sprom sc_sprom; 106*c2ec63e8Sjmcneill uint32_t sc_sel_regwin; 107*c2ec63e8Sjmcneill kmutex_t sc_lock; 108*c2ec63e8Sjmcneill }; 109*c2ec63e8Sjmcneill 110*c2ec63e8Sjmcneill static int bwi_sdio_match(device_t, cfdata_t, void *); 111*c2ec63e8Sjmcneill static void bwi_sdio_attach(device_t, device_t, void *); 112*c2ec63e8Sjmcneill 113*c2ec63e8Sjmcneill static void bwi_sdio_parse_cis(struct bwi_sdio_softc *); 114*c2ec63e8Sjmcneill 115*c2ec63e8Sjmcneill static int bwi_sdio_intr(void *); 116*c2ec63e8Sjmcneill 117*c2ec63e8Sjmcneill static void bwi_sdio_conf_write(void *, uint32_t, uint32_t); 118*c2ec63e8Sjmcneill static uint32_t bwi_sdio_conf_read(void *, uint32_t); 119*c2ec63e8Sjmcneill static void bwi_sdio_reg_write_2(void *, uint32_t, uint16_t); 120*c2ec63e8Sjmcneill static uint16_t bwi_sdio_reg_read_2(void *, uint32_t); 121*c2ec63e8Sjmcneill static void bwi_sdio_reg_write_4(void *, uint32_t, uint32_t); 122*c2ec63e8Sjmcneill static uint32_t bwi_sdio_reg_read_4(void *, uint32_t); 123*c2ec63e8Sjmcneill static void bwi_sdio_reg_write_multi_4(void *, uint32_t, const uint32_t *, 124*c2ec63e8Sjmcneill size_t); 125*c2ec63e8Sjmcneill static void bwi_sdio_reg_read_multi_4(void *, uint32_t, uint32_t *, 126*c2ec63e8Sjmcneill size_t); 127*c2ec63e8Sjmcneill 128*c2ec63e8Sjmcneill CFATTACH_DECL_NEW(bwi_sdio, sizeof(struct bwi_sdio_softc), 129*c2ec63e8Sjmcneill bwi_sdio_match, bwi_sdio_attach, NULL, NULL); 130*c2ec63e8Sjmcneill 131*c2ec63e8Sjmcneill static int 132*c2ec63e8Sjmcneill bwi_sdio_match(device_t parent, cfdata_t cf, void *aux) 133*c2ec63e8Sjmcneill { 134*c2ec63e8Sjmcneill struct sdmmc_attach_args * const saa = aux; 135*c2ec63e8Sjmcneill struct sdmmc_function *sf = saa->sf; 136*c2ec63e8Sjmcneill struct sdmmc_cis *cis; 137*c2ec63e8Sjmcneill u_int n; 138*c2ec63e8Sjmcneill 139*c2ec63e8Sjmcneill if (sf == NULL) { 140*c2ec63e8Sjmcneill return 0; 141*c2ec63e8Sjmcneill } 142*c2ec63e8Sjmcneill cis = &sf->sc->sc_fn0->cis; 143*c2ec63e8Sjmcneill 144*c2ec63e8Sjmcneill for (n = 0; n < __arraycount(bwi_sdio_products); n++) { 145*c2ec63e8Sjmcneill const struct bwi_sdio_product *bsp = &bwi_sdio_products[n]; 146*c2ec63e8Sjmcneill 147*c2ec63e8Sjmcneill if (bsp->vendor == cis->manufacturer && 148*c2ec63e8Sjmcneill bsp->product == cis->product) { 149*c2ec63e8Sjmcneill return 1; 150*c2ec63e8Sjmcneill } 151*c2ec63e8Sjmcneill } 152*c2ec63e8Sjmcneill 153*c2ec63e8Sjmcneill return 0; 154*c2ec63e8Sjmcneill } 155*c2ec63e8Sjmcneill 156*c2ec63e8Sjmcneill static void 157*c2ec63e8Sjmcneill bwi_sdio_attach(device_t parent, device_t self, void *aux) 158*c2ec63e8Sjmcneill { 159*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = device_private(self); 160*c2ec63e8Sjmcneill struct bwi_softc * const sc = &ssc->sc_base; 161*c2ec63e8Sjmcneill struct sdmmc_attach_args * const saa = aux; 162*c2ec63e8Sjmcneill struct sdmmc_function *sf = saa->sf; 163*c2ec63e8Sjmcneill struct sdmmc_cis *cis = &sf->sc->sc_fn0->cis; 164*c2ec63e8Sjmcneill int error; 165*c2ec63e8Sjmcneill void *ih; 166*c2ec63e8Sjmcneill 167*c2ec63e8Sjmcneill aprint_naive("\n"); 168*c2ec63e8Sjmcneill aprint_normal(": Broadcom Wireless\n"); 169*c2ec63e8Sjmcneill 170*c2ec63e8Sjmcneill sc->sc_dev = self; 171*c2ec63e8Sjmcneill sc->sc_flags = BWI_F_SDIO | BWI_F_PIO; 172*c2ec63e8Sjmcneill sc->sc_conf_write = bwi_sdio_conf_write; 173*c2ec63e8Sjmcneill sc->sc_conf_read = bwi_sdio_conf_read; 174*c2ec63e8Sjmcneill sc->sc_reg_write_multi_4 = bwi_sdio_reg_write_multi_4; 175*c2ec63e8Sjmcneill sc->sc_reg_read_multi_4 = bwi_sdio_reg_read_multi_4; 176*c2ec63e8Sjmcneill sc->sc_reg_write_2 = bwi_sdio_reg_write_2; 177*c2ec63e8Sjmcneill sc->sc_reg_read_2 = bwi_sdio_reg_read_2; 178*c2ec63e8Sjmcneill sc->sc_reg_write_4 = bwi_sdio_reg_write_4; 179*c2ec63e8Sjmcneill sc->sc_reg_read_4 = bwi_sdio_reg_read_4; 180*c2ec63e8Sjmcneill sc->sc_pci_revid = 0; /* XXX can this come from CIS? */ 181*c2ec63e8Sjmcneill sc->sc_pci_did = cis->product; 182*c2ec63e8Sjmcneill sc->sc_pci_subvid = cis->manufacturer; 183*c2ec63e8Sjmcneill sc->sc_pci_subdid = cis->product; 184*c2ec63e8Sjmcneill 185*c2ec63e8Sjmcneill ssc->sc_sf = sf; 186*c2ec63e8Sjmcneill mutex_init(&ssc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 187*c2ec63e8Sjmcneill 188*c2ec63e8Sjmcneill sdmmc_io_set_blocklen(ssc->sc_sf, 64); 189*c2ec63e8Sjmcneill if (sdmmc_io_function_enable(ssc->sc_sf) != 0) { 190*c2ec63e8Sjmcneill aprint_error_dev(self, "couldn't enable function\n"); 191*c2ec63e8Sjmcneill return; 192*c2ec63e8Sjmcneill } 193*c2ec63e8Sjmcneill 194*c2ec63e8Sjmcneill bwi_sdio_parse_cis(ssc); 195*c2ec63e8Sjmcneill 196*c2ec63e8Sjmcneill ih = sdmmc_intr_establish(parent, bwi_sdio_intr, ssc, 197*c2ec63e8Sjmcneill device_xname(self)); 198*c2ec63e8Sjmcneill if (ih == NULL) { 199*c2ec63e8Sjmcneill aprint_error_dev(self, "couldn't establish interrupt\n"); 200*c2ec63e8Sjmcneill return; 201*c2ec63e8Sjmcneill } 202*c2ec63e8Sjmcneill 203*c2ec63e8Sjmcneill error = bwi_attach(sc); 204*c2ec63e8Sjmcneill if (error != 0) { 205*c2ec63e8Sjmcneill sdmmc_intr_disestablish(ih); 206*c2ec63e8Sjmcneill return; 207*c2ec63e8Sjmcneill } 208*c2ec63e8Sjmcneill 209*c2ec63e8Sjmcneill sdmmc_intr_enable(ssc->sc_sf); 210*c2ec63e8Sjmcneill } 211*c2ec63e8Sjmcneill 212*c2ec63e8Sjmcneill static void 213*c2ec63e8Sjmcneill bwi_sdio_parse_cis(struct bwi_sdio_softc *ssc) 214*c2ec63e8Sjmcneill { 215*c2ec63e8Sjmcneill struct sdmmc_function *sf0 = ssc->sc_sf->sc->sc_fn0; 216*c2ec63e8Sjmcneill struct bwi_sdio_sprom *sprom = &ssc->sc_sprom; 217*c2ec63e8Sjmcneill uint32_t reg; 218*c2ec63e8Sjmcneill uint8_t tplcode, tpllen; 219*c2ec63e8Sjmcneill 220*c2ec63e8Sjmcneill reg = sdmmc_cisptr(ssc->sc_sf); 221*c2ec63e8Sjmcneill for (;;) { 222*c2ec63e8Sjmcneill tplcode = sdmmc_io_read_1(sf0, reg++); 223*c2ec63e8Sjmcneill if (tplcode == PCMCIA_CISTPL_NULL) { 224*c2ec63e8Sjmcneill continue; 225*c2ec63e8Sjmcneill } 226*c2ec63e8Sjmcneill tpllen = sdmmc_io_read_1(sf0, reg++); 227*c2ec63e8Sjmcneill if (tplcode == PCMCIA_CISTPL_END || tpllen == 0) { 228*c2ec63e8Sjmcneill break; 229*c2ec63e8Sjmcneill } 230*c2ec63e8Sjmcneill if (tplcode != BWI_CISTPL_VENDOR) { 231*c2ec63e8Sjmcneill reg += tpllen; 232*c2ec63e8Sjmcneill continue; 233*c2ec63e8Sjmcneill } 234*c2ec63e8Sjmcneill 235*c2ec63e8Sjmcneill switch (sdmmc_io_read_1(sf0, reg)) { 236*c2ec63e8Sjmcneill case BWI_VENDOR_SROMREV: 237*c2ec63e8Sjmcneill sprom->srom_rev = sdmmc_io_read_1(sf0, reg + 1); 238*c2ec63e8Sjmcneill break; 239*c2ec63e8Sjmcneill case BWI_VENDOR_ID: 240*c2ec63e8Sjmcneill sprom->board_vendor = 241*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 1) | 242*c2ec63e8Sjmcneill ((uint16_t)sdmmc_io_read_1(sf0, reg + 2) << 8); 243*c2ec63e8Sjmcneill break; 244*c2ec63e8Sjmcneill case BWI_VENDOR_BOARDREV: 245*c2ec63e8Sjmcneill sprom->board_rev = 246*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 1); 247*c2ec63e8Sjmcneill break; 248*c2ec63e8Sjmcneill case BWI_VENDOR_PA: 249*c2ec63e8Sjmcneill sprom->pa_params[0] = 250*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 1) | 251*c2ec63e8Sjmcneill ((uint16_t)sdmmc_io_read_1(sf0, reg + 2) << 8); 252*c2ec63e8Sjmcneill sprom->pa_params[1] = 253*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 3) | 254*c2ec63e8Sjmcneill ((uint16_t)sdmmc_io_read_1(sf0, reg + 4) << 8); 255*c2ec63e8Sjmcneill sprom->pa_params[2] = 256*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 5) | 257*c2ec63e8Sjmcneill ((uint16_t)sdmmc_io_read_1(sf0, reg + 6) << 8); 258*c2ec63e8Sjmcneill sprom->idle_tssi = 259*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 7); 260*c2ec63e8Sjmcneill sprom->max_txpwr = 261*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 8); 262*c2ec63e8Sjmcneill break; 263*c2ec63e8Sjmcneill case BWI_VENDOR_CCODE: 264*c2ec63e8Sjmcneill sprom->country_code = 265*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 1); 266*c2ec63e8Sjmcneill break; 267*c2ec63e8Sjmcneill case BWI_VENDOR_ANTGAIN: 268*c2ec63e8Sjmcneill sprom->ant_gain = sdmmc_io_read_1(sf0, reg + 1); 269*c2ec63e8Sjmcneill break; 270*c2ec63e8Sjmcneill case BWI_VENDOR_BFLAGS: 271*c2ec63e8Sjmcneill sprom->card_flags = 272*c2ec63e8Sjmcneill sdmmc_io_read_1(sf0, reg + 1) | 273*c2ec63e8Sjmcneill ((uint16_t)sdmmc_io_read_1(sf0, reg + 2) << 8); 274*c2ec63e8Sjmcneill break; 275*c2ec63e8Sjmcneill case BWI_VENDOR_LEDS: 276*c2ec63e8Sjmcneill sprom->gpio[0] = sdmmc_io_read_1(sf0, reg + 1); 277*c2ec63e8Sjmcneill sprom->gpio[1] = sdmmc_io_read_1(sf0, reg + 2); 278*c2ec63e8Sjmcneill sprom->gpio[2] = sdmmc_io_read_1(sf0, reg + 3); 279*c2ec63e8Sjmcneill sprom->gpio[3] = sdmmc_io_read_1(sf0, reg + 4); 280*c2ec63e8Sjmcneill break; 281*c2ec63e8Sjmcneill } 282*c2ec63e8Sjmcneill 283*c2ec63e8Sjmcneill reg += tpllen; 284*c2ec63e8Sjmcneill } 285*c2ec63e8Sjmcneill } 286*c2ec63e8Sjmcneill 287*c2ec63e8Sjmcneill static int 288*c2ec63e8Sjmcneill bwi_sdio_intr(void *priv) 289*c2ec63e8Sjmcneill { 290*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 291*c2ec63e8Sjmcneill 292*c2ec63e8Sjmcneill bwi_intr(&ssc->sc_base); 293*c2ec63e8Sjmcneill 294*c2ec63e8Sjmcneill return 1; 295*c2ec63e8Sjmcneill } 296*c2ec63e8Sjmcneill 297*c2ec63e8Sjmcneill static void 298*c2ec63e8Sjmcneill bwi_sdio_conf_write(void *priv, uint32_t reg, uint32_t val) 299*c2ec63e8Sjmcneill { 300*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 301*c2ec63e8Sjmcneill 302*c2ec63e8Sjmcneill KASSERT(reg == BWI_PCIR_SEL_REGWIN); 303*c2ec63e8Sjmcneill 304*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 305*c2ec63e8Sjmcneill if (reg == BWI_PCIR_SEL_REGWIN && ssc->sc_sel_regwin != val) { 306*c2ec63e8Sjmcneill sdmmc_io_write_1(ssc->sc_sf, BWI_SDIO_FUNC1_SBADDRLOW, 307*c2ec63e8Sjmcneill (val >> 8) & 0x80); 308*c2ec63e8Sjmcneill sdmmc_io_write_1(ssc->sc_sf, BWI_SDIO_FUNC1_SBADDRMID, 309*c2ec63e8Sjmcneill (val >> 16) & 0xff); 310*c2ec63e8Sjmcneill sdmmc_io_write_1(ssc->sc_sf, BWI_SDIO_FUNC1_SBADDRHI, 311*c2ec63e8Sjmcneill (val >> 24) & 0xff); 312*c2ec63e8Sjmcneill ssc->sc_sel_regwin = val; 313*c2ec63e8Sjmcneill } 314*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 315*c2ec63e8Sjmcneill } 316*c2ec63e8Sjmcneill 317*c2ec63e8Sjmcneill static uint32_t 318*c2ec63e8Sjmcneill bwi_sdio_conf_read(void *priv, uint32_t reg) 319*c2ec63e8Sjmcneill { 320*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 321*c2ec63e8Sjmcneill 322*c2ec63e8Sjmcneill KASSERT(reg == BWI_PCIR_SEL_REGWIN); 323*c2ec63e8Sjmcneill 324*c2ec63e8Sjmcneill if (reg == BWI_PCIR_SEL_REGWIN) { 325*c2ec63e8Sjmcneill return ssc->sc_sel_regwin; 326*c2ec63e8Sjmcneill } else { 327*c2ec63e8Sjmcneill return 0; 328*c2ec63e8Sjmcneill } 329*c2ec63e8Sjmcneill } 330*c2ec63e8Sjmcneill 331*c2ec63e8Sjmcneill static void 332*c2ec63e8Sjmcneill bwi_sdio_reg_write_multi_4(void *priv, uint32_t reg, const uint32_t *datap, 333*c2ec63e8Sjmcneill size_t count) 334*c2ec63e8Sjmcneill { 335*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 336*c2ec63e8Sjmcneill 337*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 338*c2ec63e8Sjmcneill sdmmc_io_write_multi_1(ssc->sc_sf, 339*c2ec63e8Sjmcneill BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS, 340*c2ec63e8Sjmcneill (uint8_t *)__UNCONST(datap), count * sizeof(uint32_t)); 341*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 342*c2ec63e8Sjmcneill } 343*c2ec63e8Sjmcneill 344*c2ec63e8Sjmcneill static void 345*c2ec63e8Sjmcneill bwi_sdio_reg_read_multi_4(void *priv, uint32_t reg, uint32_t *datap, 346*c2ec63e8Sjmcneill size_t count) 347*c2ec63e8Sjmcneill { 348*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 349*c2ec63e8Sjmcneill 350*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 351*c2ec63e8Sjmcneill sdmmc_io_read_multi_1(ssc->sc_sf, 352*c2ec63e8Sjmcneill BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS, 353*c2ec63e8Sjmcneill (uint8_t *)datap, count * sizeof(uint32_t)); 354*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 355*c2ec63e8Sjmcneill } 356*c2ec63e8Sjmcneill 357*c2ec63e8Sjmcneill static void 358*c2ec63e8Sjmcneill bwi_sdio_reg_write_2(void *priv, uint32_t reg, uint16_t val) 359*c2ec63e8Sjmcneill { 360*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 361*c2ec63e8Sjmcneill 362*c2ec63e8Sjmcneill val = htole16(val); 363*c2ec63e8Sjmcneill 364*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 365*c2ec63e8Sjmcneill sdmmc_io_write_2(ssc->sc_sf, BWI_SDIO_REG_OFFSET(ssc, reg), val); 366*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 367*c2ec63e8Sjmcneill } 368*c2ec63e8Sjmcneill 369*c2ec63e8Sjmcneill static uint16_t 370*c2ec63e8Sjmcneill bwi_sdio_reg_read_sprom(struct bwi_sdio_softc *ssc, uint32_t reg) 371*c2ec63e8Sjmcneill { 372*c2ec63e8Sjmcneill struct bwi_sdio_sprom *sprom = &ssc->sc_sprom; 373*c2ec63e8Sjmcneill struct sdmmc_cis *cis = &ssc->sc_sf->cis; 374*c2ec63e8Sjmcneill 375*c2ec63e8Sjmcneill switch (reg) { 376*c2ec63e8Sjmcneill case BWI_SPROM_11BG_EADDR ... BWI_SPROM_11BG_EADDR + 4: 377*c2ec63e8Sjmcneill return *(uint16_t *)&cis->lan_nid[reg - BWI_SPROM_11BG_EADDR]; 378*c2ec63e8Sjmcneill case BWI_SPROM_11A_EADDR ... BWI_SPROM_11A_EADDR + 4: 379*c2ec63e8Sjmcneill return *(uint16_t *)&cis->lan_nid[reg - BWI_SPROM_11A_EADDR]; 380*c2ec63e8Sjmcneill case BWI_SPROM_CARD_INFO: 381*c2ec63e8Sjmcneill return (uint16_t)sprom->country_code << 8; 382*c2ec63e8Sjmcneill case BWI_SPROM_PA_PARAM_11BG ... BWI_SPROM_PA_PARAM_11BG + 4: 383*c2ec63e8Sjmcneill return sprom->pa_params[(reg - BWI_SPROM_PA_PARAM_11BG) / 2]; 384*c2ec63e8Sjmcneill case BWI_SPROM_PA_PARAM_11A ... BWI_SPROM_PA_PARAM_11A + 4: 385*c2ec63e8Sjmcneill return sprom->pa_params[(reg - BWI_SPROM_PA_PARAM_11A) / 2]; 386*c2ec63e8Sjmcneill case BWI_SPROM_GPIO01: 387*c2ec63e8Sjmcneill return sprom->gpio[0] | ((uint16_t)sprom->gpio[1] << 8); 388*c2ec63e8Sjmcneill case BWI_SPROM_GPIO23: 389*c2ec63e8Sjmcneill return sprom->gpio[2] | ((uint16_t)sprom->gpio[3] << 8); 390*c2ec63e8Sjmcneill case BWI_SPROM_MAX_TXPWR: 391*c2ec63e8Sjmcneill return sprom->max_txpwr | ((uint16_t)sprom->max_txpwr << 8); 392*c2ec63e8Sjmcneill case BWI_SPROM_IDLE_TSSI: 393*c2ec63e8Sjmcneill return sprom->idle_tssi | ((uint16_t)sprom->idle_tssi << 8); 394*c2ec63e8Sjmcneill case BWI_SPROM_CARD_FLAGS: 395*c2ec63e8Sjmcneill return sprom->card_flags; 396*c2ec63e8Sjmcneill case BWI_SPROM_ANT_GAIN: 397*c2ec63e8Sjmcneill return sprom->ant_gain | ((uint16_t)sprom->ant_gain << 8); 398*c2ec63e8Sjmcneill default: 399*c2ec63e8Sjmcneill return 0xffff; 400*c2ec63e8Sjmcneill } 401*c2ec63e8Sjmcneill } 402*c2ec63e8Sjmcneill 403*c2ec63e8Sjmcneill static uint16_t 404*c2ec63e8Sjmcneill bwi_sdio_reg_read_2(void *priv, uint32_t reg) 405*c2ec63e8Sjmcneill { 406*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 407*c2ec63e8Sjmcneill uint16_t val; 408*c2ec63e8Sjmcneill 409*c2ec63e8Sjmcneill /* Emulate SPROM reads */ 410*c2ec63e8Sjmcneill if (reg >= BWI_SPROM_START && 411*c2ec63e8Sjmcneill reg <= BWI_SPROM_START + BWI_SPROM_ANT_GAIN) { 412*c2ec63e8Sjmcneill return bwi_sdio_reg_read_sprom(ssc, reg - BWI_SPROM_START); 413*c2ec63e8Sjmcneill } 414*c2ec63e8Sjmcneill 415*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 416*c2ec63e8Sjmcneill val = sdmmc_io_read_2(ssc->sc_sf, BWI_SDIO_REG_OFFSET(ssc, reg)); 417*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 418*c2ec63e8Sjmcneill 419*c2ec63e8Sjmcneill val = le16toh(val); 420*c2ec63e8Sjmcneill 421*c2ec63e8Sjmcneill return val; 422*c2ec63e8Sjmcneill } 423*c2ec63e8Sjmcneill 424*c2ec63e8Sjmcneill static void 425*c2ec63e8Sjmcneill bwi_sdio_reg_write_4(void *priv, uint32_t reg, uint32_t val) 426*c2ec63e8Sjmcneill { 427*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 428*c2ec63e8Sjmcneill 429*c2ec63e8Sjmcneill val = htole32(val); 430*c2ec63e8Sjmcneill 431*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 432*c2ec63e8Sjmcneill sdmmc_io_write_4(ssc->sc_sf, 433*c2ec63e8Sjmcneill BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS, val); 434*c2ec63e8Sjmcneill /* SDIO cards require a read after a 32-bit write */ 435*c2ec63e8Sjmcneill sdmmc_io_read_4(ssc->sc_sf, 0); 436*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 437*c2ec63e8Sjmcneill } 438*c2ec63e8Sjmcneill 439*c2ec63e8Sjmcneill static uint32_t 440*c2ec63e8Sjmcneill bwi_sdio_reg_read_4(void *priv, uint32_t reg) 441*c2ec63e8Sjmcneill { 442*c2ec63e8Sjmcneill struct bwi_sdio_softc * const ssc = priv; 443*c2ec63e8Sjmcneill uint32_t val; 444*c2ec63e8Sjmcneill 445*c2ec63e8Sjmcneill mutex_enter(&ssc->sc_lock); 446*c2ec63e8Sjmcneill val = sdmmc_io_read_4(ssc->sc_sf, 447*c2ec63e8Sjmcneill BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS); 448*c2ec63e8Sjmcneill mutex_exit(&ssc->sc_lock); 449*c2ec63e8Sjmcneill 450*c2ec63e8Sjmcneill val = le32toh(val); 451*c2ec63e8Sjmcneill 452*c2ec63e8Sjmcneill return val; 453*c2ec63e8Sjmcneill } 454