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