1 /* $NetBSD: if_bwfm_sdio.c,v 1.2 2018/03/11 00:17:28 khorben 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_txdata(struct bwfm_softc *, struct mbuf *); 91 int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t); 92 int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *); 93 94 struct bwfm_bus_ops bwfm_sdio_bus_ops = { 95 .bs_init = NULL, 96 .bs_stop = NULL, 97 .bs_txdata = bwfm_sdio_txdata, 98 .bs_txctl = bwfm_sdio_txctl, 99 .bs_rxctl = bwfm_sdio_rxctl, 100 }; 101 102 struct bwfm_buscore_ops bwfm_sdio_buscore_ops = { 103 .bc_read = bwfm_sdio_buscore_read, 104 .bc_write = bwfm_sdio_buscore_write, 105 .bc_prepare = bwfm_sdio_buscore_prepare, 106 .bc_reset = NULL, 107 .bc_setup = NULL, 108 .bc_activate = bwfm_sdio_buscore_activate, 109 }; 110 111 CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc), 112 bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL); 113 114 int 115 bwfm_sdio_match(device_t parent, cfdata_t match, void *aux) 116 { 117 struct sdmmc_attach_args *saa = aux; 118 struct sdmmc_function *sf = saa->sf; 119 struct sdmmc_cis *cis; 120 121 /* Not SDIO. */ 122 if (sf == NULL) 123 return 0; 124 125 /* Look for Broadcom 433[04]. */ 126 cis = &sf->sc->sc_fn0->cis; 127 if (cis->manufacturer != 0x02d0 || (cis->product != 0x4330 && 128 cis->product != 0x4334)) 129 return 0; 130 131 /* We need both functions, but ... */ 132 if (sf->sc->sc_function_count <= 1) 133 return 0; 134 135 /* ... only attach for one. */ 136 if (sf->number != 1) 137 return 0; 138 139 return 1; 140 } 141 142 void 143 bwfm_sdio_attach(device_t parent, device_t self, void *aux) 144 { 145 struct bwfm_sdio_softc *sc = device_private(self); 146 struct sdmmc_attach_args *saa = aux; 147 struct sdmmc_function *sf = saa->sf; 148 struct bwfm_core *core; 149 150 aprint_naive("\n"); 151 152 sc->sc_sf = malloc((sf->sc->sc_function_count + 1) * 153 sizeof(struct sdmmc_function *), M_DEVBUF, M_WAITOK); 154 155 /* Copy all function pointers. */ 156 SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) { 157 sc->sc_sf[sf->number] = sf; 158 } 159 sf = saa->sf; 160 161 /* 162 * TODO: set block size to 64 for func 1, 512 for func 2. 163 * We might need to work on the SDMMC stack to be able to set 164 * a block size per function. Currently the IO code uses the 165 * SDHC controller's maximum block length. 166 */ 167 168 /* Enable Function 1. */ 169 if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) { 170 aprint_error_dev(self, "cannot enable function 1\n"); 171 goto err; 172 } 173 174 DPRINTFN(2, ("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc), 175 bwfm_sdio_read_4(sc, 0x18000000))); 176 177 /* Force PLL off */ 178 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 179 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | 180 BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); 181 182 sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops; 183 if (bwfm_chip_attach(&sc->sc_sc) != 0) { 184 aprint_error_dev(self, "cannot attach chip\n"); 185 goto err; 186 } 187 188 /* TODO: drive strength */ 189 190 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL, 191 bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL) | 192 BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET); 193 194 core = bwfm_chip_get_pmu(&sc->sc_sc); 195 bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL, 196 bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) | 197 (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD << 198 BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT)); 199 200 sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops; 201 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; 202 bwfm_attach(&sc->sc_sc); 203 204 return; 205 206 err: 207 free(sc->sc_sf, M_DEVBUF); 208 } 209 210 int 211 bwfm_sdio_detach(struct device *self, int flags) 212 { 213 struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self; 214 215 bwfm_detach(&sc->sc_sc, flags); 216 217 free(sc->sc_sf, M_DEVBUF); 218 219 return 0; 220 } 221 222 void 223 bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t bar0) 224 { 225 if (sc->sc_bar0 == bar0) 226 return; 227 228 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW, 229 (bar0 >> 8) & 0x80); 230 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID, 231 (bar0 >> 16) & 0xff); 232 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH, 233 (bar0 >> 24) & 0xff); 234 sc->sc_bar0 = bar0; 235 } 236 237 uint8_t 238 bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr) 239 { 240 struct sdmmc_function *sf; 241 uint8_t rv; 242 243 /* 244 * figure out how to read the register based on address range 245 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 246 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 247 * The rest: function 1 silicon backplane core registers 248 */ 249 if ((addr & ~0x7ff) == 0) 250 sf = sc->sc_sf[0]; 251 else 252 sf = sc->sc_sf[1]; 253 254 rv = sdmmc_io_read_1(sf, addr); 255 return rv; 256 } 257 258 uint32_t 259 bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr) 260 { 261 struct sdmmc_function *sf; 262 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; 263 uint32_t rv; 264 265 bwfm_sdio_backplane(sc, bar0); 266 267 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; 268 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; 269 270 /* 271 * figure out how to read the register based on address range 272 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 273 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 274 * The rest: function 1 silicon backplane core registers 275 */ 276 if ((addr & ~0x7ff) == 0) 277 sf = sc->sc_sf[0]; 278 else 279 sf = sc->sc_sf[1]; 280 281 rv = sdmmc_io_read_4(sf, addr); 282 return rv; 283 } 284 285 void 286 bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data) 287 { 288 struct sdmmc_function *sf; 289 290 /* 291 * figure out how to read the register based on address range 292 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 293 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 294 * The rest: function 1 silicon backplane core registers 295 */ 296 if ((addr & ~0x7ff) == 0) 297 sf = sc->sc_sf[0]; 298 else 299 sf = sc->sc_sf[1]; 300 301 sdmmc_io_write_1(sf, addr, data); 302 } 303 304 void 305 bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data) 306 { 307 struct sdmmc_function *sf; 308 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; 309 310 bwfm_sdio_backplane(sc, bar0); 311 312 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; 313 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; 314 315 /* 316 * figure out how to read the register based on address range 317 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 318 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 319 * The rest: function 1 silicon backplane core registers 320 */ 321 if ((addr & ~0x7ff) == 0) 322 sf = sc->sc_sf[0]; 323 else 324 sf = sc->sc_sf[1]; 325 326 sdmmc_io_write_4(sf, addr, data); 327 } 328 329 uint32_t 330 bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 331 { 332 struct bwfm_sdio_softc *sc = (void *)bwfm; 333 uint32_t val; 334 335 val = bwfm_sdio_read_4(sc, reg); 336 /* TODO: Workaround for 4335/4339 */ 337 338 return val; 339 } 340 341 void 342 bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 343 { 344 struct bwfm_sdio_softc *sc = (void *)bwfm; 345 bwfm_sdio_write_4(sc, reg, val); 346 } 347 348 int 349 bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm) 350 { 351 struct bwfm_sdio_softc *sc = (void *)bwfm; 352 uint8_t clkval, clkset, clkmask; 353 int i; 354 355 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ | 356 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF; 357 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); 358 359 clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL | 360 BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL; 361 clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); 362 363 if ((clkval & ~clkmask) != clkset) { 364 printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc), 365 clkset, clkval); 366 return 1; 367 } 368 369 for (i = 1000; i > 0; i--) { 370 clkval = bwfm_sdio_read_1(sc, 371 BWFM_SDIO_FUNC1_CHIPCLKCSR); 372 if (clkval & clkmask) 373 break; 374 } 375 if (i == 0) { 376 printf("%s: timeout on ALPAV wait, clkval 0x%02x\n", 377 DEVNAME(sc), clkval); 378 return 1; 379 } 380 381 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | 382 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP; 383 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); 384 delay(65); 385 386 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0); 387 388 return 0; 389 } 390 391 void 392 bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 393 { 394 struct bwfm_sdio_softc *sc = (void *)bwfm; 395 struct bwfm_core *core; 396 397 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); 398 bwfm_sdio_buscore_write(&sc->sc_sc, 399 core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF); 400 401 #if notyet 402 if (rstvec) 403 bwfm_sdio_ram_write(&sc->sc_sc, 0, &rstvec, sizeof(rstvec)); 404 #endif 405 } 406 407 int 408 bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 409 { 410 #ifdef BWFM_DEBUG 411 struct bwfm_sdio_softc *sc = (void *)bwfm; 412 #endif 413 int ret = 1; 414 415 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 416 417 return ret; 418 } 419 420 int 421 bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) 422 { 423 #ifdef BWFM_DEBUG 424 struct bwfm_sdio_softc *sc = (void *)bwfm; 425 #endif 426 int ret = 1; 427 428 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 429 430 return ret; 431 } 432 433 int 434 bwfm_sdio_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len) 435 { 436 #ifdef BWFM_DEBUG 437 struct bwfm_sdio_softc *sc = (void *)bwfm; 438 #endif 439 int ret = 1; 440 441 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 442 443 return ret; 444 } 445