Home | History | Annotate | Line # | Download | only in sdmmc
if_bwfm_sdio.c revision 1.2
      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 (at) 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