1 /* $NetBSD: if_bwfm_sdio.c,v 1.3 2018/05/11 07:41:11 maya Exp $ */ 2 /* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */ 3 /* 4 * Copyright (c) 2010-2016 Broadcom Corporation 5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/buf.h> 23 #include <sys/kernel.h> 24 #include <sys/malloc.h> 25 #include <sys/device.h> 26 #include <sys/queue.h> 27 #include <sys/socket.h> 28 #include <sys/mutex.h> 29 #include <sys/workqueue.h> 30 #include <sys/pcq.h> 31 32 #include <net/bpf.h> 33 #include <net/if.h> 34 #include <net/if_dl.h> 35 #include <net/if_media.h> 36 #include <net/if_ether.h> 37 38 #include <netinet/in.h> 39 40 #include <net80211/ieee80211_var.h> 41 42 #include <dev/sdmmc/sdmmcvar.h> 43 44 #include <dev/ic/bwfmvar.h> 45 #include <dev/ic/bwfmreg.h> 46 47 #define BWFM_SDIO_CCCR_BRCM_CARDCAP 0xf0 48 #define BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 49 #define BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 50 #define BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 51 #define BWFM_SDIO_CCCR_BRCM_CARDCTRL 0xf1 52 #define BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET 0x02 53 #define BWFM_SDIO_CCCR_BRCM_SEPINT 0xf2 54 55 #ifdef BWFM_DEBUG 56 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 57 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 58 static int bwfm_debug = 2; 59 #else 60 #define DPRINTF(x) do { ; } while (0) 61 #define DPRINTFN(n, x) do { ; } while (0) 62 #endif 63 64 #define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev) 65 66 struct bwfm_sdio_softc { 67 struct bwfm_softc sc_sc; 68 struct sdmmc_function **sc_sf; 69 uint32_t sc_bar0; 70 }; 71 72 int bwfm_sdio_match(device_t, cfdata_t, void *); 73 void bwfm_sdio_attach(device_t, struct device *, void *); 74 int bwfm_sdio_detach(device_t, int); 75 76 void bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t); 77 uint8_t bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t); 78 uint32_t bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t); 79 void bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t, 80 uint8_t); 81 void bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t, 82 uint32_t); 83 84 uint32_t bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t); 85 void bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t, 86 uint32_t); 87 int bwfm_sdio_buscore_prepare(struct bwfm_softc *); 88 void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t); 89 90 int bwfm_sdio_txcheck(struct bwfm_softc *); 91 int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf *); 92 int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t); 93 int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *); 94 95 struct bwfm_bus_ops bwfm_sdio_bus_ops = { 96 .bs_init = NULL, 97 .bs_stop = NULL, 98 .bs_txcheck = bwfm_sdio_txcheck, 99 .bs_txdata = bwfm_sdio_txdata, 100 .bs_txctl = bwfm_sdio_txctl, 101 .bs_rxctl = bwfm_sdio_rxctl, 102 }; 103 104 struct bwfm_buscore_ops bwfm_sdio_buscore_ops = { 105 .bc_read = bwfm_sdio_buscore_read, 106 .bc_write = bwfm_sdio_buscore_write, 107 .bc_prepare = bwfm_sdio_buscore_prepare, 108 .bc_reset = NULL, 109 .bc_setup = NULL, 110 .bc_activate = bwfm_sdio_buscore_activate, 111 }; 112 113 CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc), 114 bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL); 115 116 int 117 bwfm_sdio_match(device_t parent, cfdata_t match, void *aux) 118 { 119 struct sdmmc_attach_args *saa = aux; 120 struct sdmmc_function *sf = saa->sf; 121 struct sdmmc_cis *cis; 122 123 /* Not SDIO. */ 124 if (sf == NULL) 125 return 0; 126 127 /* Look for Broadcom 433[04]. */ 128 cis = &sf->sc->sc_fn0->cis; 129 if (cis->manufacturer != 0x02d0 || (cis->product != 0x4330 && 130 cis->product != 0x4334)) 131 return 0; 132 133 /* We need both functions, but ... */ 134 if (sf->sc->sc_function_count <= 1) 135 return 0; 136 137 /* ... only attach for one. */ 138 if (sf->number != 1) 139 return 0; 140 141 return 1; 142 } 143 144 void 145 bwfm_sdio_attach(device_t parent, device_t self, void *aux) 146 { 147 struct bwfm_sdio_softc *sc = device_private(self); 148 struct sdmmc_attach_args *saa = aux; 149 struct sdmmc_function *sf = saa->sf; 150 struct bwfm_core *core; 151 152 aprint_naive("\n"); 153 154 sc->sc_sf = malloc((sf->sc->sc_function_count + 1) * 155 sizeof(struct sdmmc_function *), M_DEVBUF, M_WAITOK); 156 157 /* Copy all function pointers. */ 158 SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) { 159 sc->sc_sf[sf->number] = sf; 160 } 161 sf = saa->sf; 162 163 /* 164 * TODO: set block size to 64 for func 1, 512 for func 2. 165 * We might need to work on the SDMMC stack to be able to set 166 * a block size per function. Currently the IO code uses the 167 * SDHC controller's maximum block length. 168 */ 169 170 /* Enable Function 1. */ 171 if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) { 172 aprint_error_dev(self, "cannot enable function 1\n"); 173 goto err; 174 } 175 176 DPRINTFN(2, ("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc), 177 bwfm_sdio_read_4(sc, 0x18000000))); 178 179 /* Force PLL off */ 180 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 181 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | 182 BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); 183 184 sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops; 185 if (bwfm_chip_attach(&sc->sc_sc) != 0) { 186 aprint_error_dev(self, "cannot attach chip\n"); 187 goto err; 188 } 189 190 /* TODO: drive strength */ 191 192 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL, 193 bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL) | 194 BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET); 195 196 core = bwfm_chip_get_pmu(&sc->sc_sc); 197 bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL, 198 bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) | 199 (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD << 200 BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT)); 201 202 sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops; 203 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; 204 bwfm_attach(&sc->sc_sc); 205 206 return; 207 208 err: 209 free(sc->sc_sf, M_DEVBUF); 210 } 211 212 int 213 bwfm_sdio_detach(struct device *self, int flags) 214 { 215 struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self; 216 217 bwfm_detach(&sc->sc_sc, flags); 218 219 free(sc->sc_sf, M_DEVBUF); 220 221 return 0; 222 } 223 224 void 225 bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t bar0) 226 { 227 if (sc->sc_bar0 == bar0) 228 return; 229 230 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW, 231 (bar0 >> 8) & 0x80); 232 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID, 233 (bar0 >> 16) & 0xff); 234 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH, 235 (bar0 >> 24) & 0xff); 236 sc->sc_bar0 = bar0; 237 } 238 239 uint8_t 240 bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr) 241 { 242 struct sdmmc_function *sf; 243 uint8_t rv; 244 245 /* 246 * figure out how to read the register based on address range 247 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 248 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 249 * The rest: function 1 silicon backplane core registers 250 */ 251 if ((addr & ~0x7ff) == 0) 252 sf = sc->sc_sf[0]; 253 else 254 sf = sc->sc_sf[1]; 255 256 rv = sdmmc_io_read_1(sf, addr); 257 return rv; 258 } 259 260 uint32_t 261 bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr) 262 { 263 struct sdmmc_function *sf; 264 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; 265 uint32_t rv; 266 267 bwfm_sdio_backplane(sc, bar0); 268 269 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; 270 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; 271 272 /* 273 * figure out how to read the register based on address range 274 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 275 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 276 * The rest: function 1 silicon backplane core registers 277 */ 278 if ((addr & ~0x7ff) == 0) 279 sf = sc->sc_sf[0]; 280 else 281 sf = sc->sc_sf[1]; 282 283 rv = sdmmc_io_read_4(sf, addr); 284 return rv; 285 } 286 287 void 288 bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data) 289 { 290 struct sdmmc_function *sf; 291 292 /* 293 * figure out how to read the register based on address range 294 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 295 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 296 * The rest: function 1 silicon backplane core registers 297 */ 298 if ((addr & ~0x7ff) == 0) 299 sf = sc->sc_sf[0]; 300 else 301 sf = sc->sc_sf[1]; 302 303 sdmmc_io_write_1(sf, addr, data); 304 } 305 306 void 307 bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data) 308 { 309 struct sdmmc_function *sf; 310 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; 311 312 bwfm_sdio_backplane(sc, bar0); 313 314 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; 315 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; 316 317 /* 318 * figure out how to read the register based on address range 319 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 320 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 321 * The rest: function 1 silicon backplane core registers 322 */ 323 if ((addr & ~0x7ff) == 0) 324 sf = sc->sc_sf[0]; 325 else 326 sf = sc->sc_sf[1]; 327 328 sdmmc_io_write_4(sf, addr, data); 329 } 330 331 uint32_t 332 bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 333 { 334 struct bwfm_sdio_softc *sc = (void *)bwfm; 335 uint32_t val; 336 337 val = bwfm_sdio_read_4(sc, reg); 338 /* TODO: Workaround for 4335/4339 */ 339 340 return val; 341 } 342 343 void 344 bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 345 { 346 struct bwfm_sdio_softc *sc = (void *)bwfm; 347 bwfm_sdio_write_4(sc, reg, val); 348 } 349 350 int 351 bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm) 352 { 353 struct bwfm_sdio_softc *sc = (void *)bwfm; 354 uint8_t clkval, clkset, clkmask; 355 int i; 356 357 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ | 358 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF; 359 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); 360 361 clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL | 362 BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL; 363 clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); 364 365 if ((clkval & ~clkmask) != clkset) { 366 printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc), 367 clkset, clkval); 368 return 1; 369 } 370 371 for (i = 1000; i > 0; i--) { 372 clkval = bwfm_sdio_read_1(sc, 373 BWFM_SDIO_FUNC1_CHIPCLKCSR); 374 if (clkval & clkmask) 375 break; 376 } 377 if (i == 0) { 378 printf("%s: timeout on ALPAV wait, clkval 0x%02x\n", 379 DEVNAME(sc), clkval); 380 return 1; 381 } 382 383 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | 384 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP; 385 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); 386 delay(65); 387 388 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0); 389 390 return 0; 391 } 392 393 void 394 bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 395 { 396 struct bwfm_sdio_softc *sc = (void *)bwfm; 397 struct bwfm_core *core; 398 399 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); 400 bwfm_sdio_buscore_write(&sc->sc_sc, 401 core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF); 402 403 #if notyet 404 if (rstvec) 405 bwfm_sdio_ram_write(&sc->sc_sc, 0, &rstvec, sizeof(rstvec)); 406 #endif 407 } 408 409 int 410 bwfm_sdio_txcheck(struct bwfm_softc *bwfm, struct mbuf *m) 411 { 412 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 413 414 return 0; 415 } 416 417 418 int 419 bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 420 { 421 #ifdef BWFM_DEBUG 422 struct bwfm_sdio_softc *sc = (void *)bwfm; 423 #endif 424 int ret = 1; 425 426 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 427 428 return ret; 429 } 430 431 int 432 bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) 433 { 434 #ifdef BWFM_DEBUG 435 struct bwfm_sdio_softc *sc = (void *)bwfm; 436 #endif 437 int ret = 1; 438 439 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 440 441 return ret; 442 } 443 444 int 445 bwfm_sdio_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len) 446 { 447 #ifdef BWFM_DEBUG 448 struct bwfm_sdio_softc *sc = (void *)bwfm; 449 #endif 450 int ret = 1; 451 452 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 453 454 return ret; 455 } 456