Sun Sep 1 05:51:45 2019 UTC ()
From OpenBSD:
- All the missing pieces (firmware load, chip setup, protocol handling)
TX queue and interrupt handling via sdmmc_task.
Fix locking.
Fix packet parsing.
Add parser for original firmware config files.


(mlelstv)
diff -r1.3 -r1.4 src/sys/dev/sdmmc/if_bwfm_sdio.c
diff -r0 -r1.1 src/sys/dev/sdmmc/if_bwfm_sdio.h

cvs diff -r1.3 -r1.4 src/sys/dev/sdmmc/if_bwfm_sdio.c (expand / switch to unified diff)

--- src/sys/dev/sdmmc/if_bwfm_sdio.c 2018/05/11 07:41:11 1.3
+++ src/sys/dev/sdmmc/if_bwfm_sdio.c 2019/09/01 05:51:45 1.4
@@ -1,244 +1,583 @@ @@ -1,244 +1,583 @@
1/* $NetBSD: if_bwfm_sdio.c,v 1.3 2018/05/11 07:41:11 maya Exp $ */ 1/* $NetBSD: if_bwfm_sdio.c,v 1.4 2019/09/01 05:51:45 mlelstv Exp $ */
2/* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */ 2/* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */
3/* 3/*
4 * Copyright (c) 2010-2016 Broadcom Corporation 4 * Copyright (c) 2010-2016 Broadcom Corporation
5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
6 * 6 *
7 * Permission to use, copy, modify, and/or distribute this software for any 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 8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies. 9 * copyright notice and this permission notice appear in all copies.
10 * 10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 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 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */ 18 */
19 19
20#include <sys/param.h> 20#include <sys/param.h>
21#include <sys/systm.h> 21#include <sys/systm.h>
22#include <sys/buf.h> 22#include <sys/buf.h>
 23#include <sys/endian.h>
23#include <sys/kernel.h> 24#include <sys/kernel.h>
24#include <sys/malloc.h> 25#include <sys/malloc.h>
25#include <sys/device.h> 26#include <sys/device.h>
26#include <sys/queue.h> 27#include <sys/queue.h>
27#include <sys/socket.h> 28#include <sys/socket.h>
28#include <sys/mutex.h> 29#include <sys/mutex.h>
29#include <sys/workqueue.h> 
30#include <sys/pcq.h> 
31 30
32#include <net/bpf.h> 31#include <net/bpf.h>
33#include <net/if.h> 32#include <net/if.h>
34#include <net/if_dl.h> 33#include <net/if_dl.h>
35#include <net/if_media.h> 34#include <net/if_media.h>
36#include <net/if_ether.h> 35#include <net/if_ether.h>
37 36
38#include <netinet/in.h> 37#include <netinet/in.h>
39 38
 39#include <dev/firmload.h>
 40
40#include <net80211/ieee80211_var.h> 41#include <net80211/ieee80211_var.h>
41 42
 43#include <dev/sdmmc/sdmmcdevs.h>
42#include <dev/sdmmc/sdmmcvar.h> 44#include <dev/sdmmc/sdmmcvar.h>
43 45
44#include <dev/ic/bwfmvar.h> 46#include <dev/ic/bwfmvar.h>
45#include <dev/ic/bwfmreg.h> 47#include <dev/ic/bwfmreg.h>
46 48#include <dev/sdmmc/if_bwfm_sdio.h>
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 49
55#ifdef BWFM_DEBUG 50#ifdef BWFM_DEBUG
56#define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 51#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) 52#define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
58static int bwfm_debug = 2; 53static int bwfm_debug = 2;
59#else 54#else
60#define DPRINTF(x) do { ; } while (0) 55#define DPRINTF(x) do { ; } while (0)
61#define DPRINTFN(n, x) do { ; } while (0) 56#define DPRINTFN(n, x) do { ; } while (0)
62#endif 57#endif
63 58
64#define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev) 59#define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev)
65 60
 61enum bwfm_sdio_clkstate {
 62 CLK_NONE,
 63 CLK_SDONLY,
 64 CLK_PENDING,
 65 CLK_AVAIL
 66};
 67
66struct bwfm_sdio_softc { 68struct bwfm_sdio_softc {
67 struct bwfm_softc sc_sc; 69 struct bwfm_softc sc_sc;
 70 kmutex_t sc_lock;
 71 kmutex_t sc_intr_lock;
 72
 73 bool sc_bwfm_attached;
 74
68 struct sdmmc_function **sc_sf; 75 struct sdmmc_function **sc_sf;
69 uint32_t sc_bar0; 76 size_t sc_sf_size;
 77
 78 uint32_t sc_bar0;
 79 enum bwfm_sdio_clkstate sc_clkstate;
 80 bool sc_sr_enabled;
 81 bool sc_alp_only;
 82 bool sc_sleeping;
 83
 84 struct sdmmc_task sc_task;
 85 bool sc_task_queued;
 86
 87 uint8_t sc_tx_seq;
 88 uint8_t sc_tx_max_seq;
 89 int sc_tx_count;
 90 MBUFQ_HEAD() sc_tx_queue;
 91
 92 struct mbuf *sc_rxctl_queue;
 93 kcondvar_t sc_rxctl_cv;
 94
 95 void *sc_ih;
 96 struct bwfm_core *sc_cc;
 97
 98 char *sc_bounce_buf;
 99 size_t sc_bounce_size;
 100
 101 uint32_t sc_console_addr;
 102 char *sc_console_buf;
 103 size_t sc_console_buf_size;
 104 uint32_t sc_console_readidx;
70}; 105};
71 106
72int bwfm_sdio_match(device_t, cfdata_t, void *); 107int bwfm_sdio_match(device_t, cfdata_t, void *);
73void bwfm_sdio_attach(device_t, struct device *, void *); 108void bwfm_sdio_attach(device_t, struct device *, void *);
74int bwfm_sdio_detach(device_t, int); 109int bwfm_sdio_detach(device_t, int);
75 110void bwfm_sdio_attachhook(device_t);
76void bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t); 111
77uint8_t bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t); 112void bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t);
78uint32_t bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t); 113uint8_t bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t);
79void bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t, 114uint32_t bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t);
 115void bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t,
80 uint8_t); 116 uint8_t);
81void bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t, 117void bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t,
 118 uint32_t);
 119
 120uint32_t bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t);
 121void bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t,
82 uint32_t); 122 uint32_t);
83 123
84uint32_t bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t); 124uint32_t bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t);
85void bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t, 125void bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t,
86 uint32_t); 126 uint32_t);
87int bwfm_sdio_buscore_prepare(struct bwfm_softc *); 127int bwfm_sdio_buscore_prepare(struct bwfm_softc *);
88void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t); 128void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
89 129
90int bwfm_sdio_txcheck(struct bwfm_softc *); 130int bwfm_sdio_buf_read(struct bwfm_sdio_softc *,
91int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf *); 131 struct sdmmc_function *, uint32_t, char *, size_t);
92int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t); 132int bwfm_sdio_buf_write(struct bwfm_sdio_softc *,
93int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *); 133 struct sdmmc_function *, uint32_t, char *, size_t);
 134
 135struct mbuf *bwfm_sdio_newbuf(void);
 136void bwfm_qput(struct mbuf **, struct mbuf *);
 137struct mbuf *bwfm_qget(struct mbuf **);
 138
 139uint32_t bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *,
 140 uint32_t, char *, size_t, int);
 141uint32_t bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *,
 142 char *, size_t, int);
 143
 144int bwfm_sdio_intr(void *);
 145void bwfm_sdio_task(void *);
 146void bwfm_sdio_task1(struct bwfm_sdio_softc *);
 147
 148int bwfm_nvram_convert(u_char *, size_t, size_t *);
 149int bwfm_sdio_load_microcode(struct bwfm_sdio_softc *,
 150 u_char *, size_t, u_char *, size_t);
 151void bwfm_sdio_clkctl(struct bwfm_sdio_softc *,
 152 enum bwfm_sdio_clkstate, bool);
 153void bwfm_sdio_htclk(struct bwfm_sdio_softc *, bool, bool);
 154
 155int bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *, bool, bool);
 156void bwfm_sdio_readshared(struct bwfm_sdio_softc *);
 157
 158int bwfm_sdio_txcheck(struct bwfm_softc *);
 159int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf **);
 160int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t);
 161int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *);
 162
 163int bwfm_sdio_tx_ok(struct bwfm_sdio_softc *);
 164void bwfm_sdio_tx_frames(struct bwfm_sdio_softc *);
 165void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *,
 166 struct mbuf *);
 167void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *,
 168 struct mbuf *);
 169
 170void bwfm_sdio_rx_frames(struct bwfm_sdio_softc *);
 171void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *,
 172 uint16_t *, int, uint16_t *);
 173
 174#ifdef BWFM_DEBUG
 175void bwfm_sdio_debug_console(struct bwfm_sdio_softc *);
 176#endif
94 177
95struct bwfm_bus_ops bwfm_sdio_bus_ops = { 178struct bwfm_bus_ops bwfm_sdio_bus_ops = {
96 .bs_init = NULL, 179 .bs_init = NULL,
97 .bs_stop = NULL, 180 .bs_stop = NULL,
98 .bs_txcheck = bwfm_sdio_txcheck, 181 .bs_txcheck = bwfm_sdio_txcheck,
99 .bs_txdata = bwfm_sdio_txdata, 182 .bs_txdata = bwfm_sdio_txdata,
100 .bs_txctl = bwfm_sdio_txctl, 183 .bs_txctl = bwfm_sdio_txctl,
101 .bs_rxctl = bwfm_sdio_rxctl, 184 .bs_rxctl = bwfm_sdio_rxctl,
102}; 185};
103 186
104struct bwfm_buscore_ops bwfm_sdio_buscore_ops = { 187struct bwfm_buscore_ops bwfm_sdio_buscore_ops = {
105 .bc_read = bwfm_sdio_buscore_read, 188 .bc_read = bwfm_sdio_buscore_read,
106 .bc_write = bwfm_sdio_buscore_write, 189 .bc_write = bwfm_sdio_buscore_write,
107 .bc_prepare = bwfm_sdio_buscore_prepare, 190 .bc_prepare = bwfm_sdio_buscore_prepare,
108 .bc_reset = NULL, 191 .bc_reset = NULL,
109 .bc_setup = NULL, 192 .bc_setup = NULL,
110 .bc_activate = bwfm_sdio_buscore_activate, 193 .bc_activate = bwfm_sdio_buscore_activate,
111}; 194};
112 195
113CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc), 196CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc),
114 bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL); 197 bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL);
115 198
 199static const struct bwfm_sdio_product {
 200 uint32_t manufacturer;
 201 uint32_t product;
 202 const char *cisinfo[4];
 203} bwfm_sdio_products[] = {
 204 {
 205 SDMMC_VENDOR_BROADCOM,
 206 SDMMC_PRODUCT_BROADCOM_BCM4330,
 207 SDMMC_CIS_BROADCOM_BCM4330
 208 },
 209 {
 210 SDMMC_VENDOR_BROADCOM,
 211 SDMMC_PRODUCT_BROADCOM_BCM4334,
 212 SDMMC_CIS_BROADCOM_BCM4334
 213 },
 214 {
 215 SDMMC_VENDOR_BROADCOM,
 216 SDMMC_PRODUCT_BROADCOM_BCM43143,
 217 SDMMC_CIS_BROADCOM_BCM43143
 218 },
 219 {
 220 SDMMC_VENDOR_BROADCOM,
 221 SDMMC_PRODUCT_BROADCOM_BCM43430,
 222 SDMMC_CIS_BROADCOM_BCM43430
 223 },
 224};
 225
116int 226int
117bwfm_sdio_match(device_t parent, cfdata_t match, void *aux) 227bwfm_sdio_match(device_t parent, cfdata_t match, void *aux)
118{ 228{
119 struct sdmmc_attach_args *saa = aux; 229 struct sdmmc_attach_args *saa = aux;
120 struct sdmmc_function *sf = saa->sf; 230 struct sdmmc_function *sf = saa->sf;
121 struct sdmmc_cis *cis; 231 struct sdmmc_cis *cis;
 232 const struct bwfm_sdio_product *bsp;
 233 int i;
122 234
123 /* Not SDIO. */ 235 /* Not SDIO. */
124 if (sf == NULL) 236 if (sf == NULL)
125 return 0; 237 return 0;
126 238
127 /* Look for Broadcom 433[04]. */ 
128 cis = &sf->sc->sc_fn0->cis; 239 cis = &sf->sc->sc_fn0->cis;
129 if (cis->manufacturer != 0x02d0 || (cis->product != 0x4330 && 240 for (i = 0; i < __arraycount(bwfm_sdio_products); ++i) {
130 cis->product != 0x4334)) 241 bsp = &bwfm_sdio_products[i];
 242 if (cis->manufacturer == bsp->manufacturer &&
 243 cis->product == bsp->product)
 244 break;
 245 }
 246 if (i >= __arraycount(bwfm_sdio_products))
131 return 0; 247 return 0;
132 248
133 /* We need both functions, but ... */ 249 /* We need both functions, but ... */
134 if (sf->sc->sc_function_count <= 1) 250 if (sf->sc->sc_function_count <= 1)
135 return 0; 251 return 0;
136 252
137 /* ... only attach for one. */ 253 /* ... only attach for one. */
138 if (sf->number != 1) 254 if (sf->number != 1)
139 return 0; 255 return 0;
140 256
141 return 1; 257 return 1;
142} 258}
143 259
144void 260void
145bwfm_sdio_attach(device_t parent, device_t self, void *aux) 261bwfm_sdio_attach(device_t parent, device_t self, void *aux)
146{ 262{
147 struct bwfm_sdio_softc *sc = device_private(self); 263 struct bwfm_sdio_softc *sc = device_private(self);
148 struct sdmmc_attach_args *saa = aux; 264 struct sdmmc_attach_args *saa = aux;
149 struct sdmmc_function *sf = saa->sf; 265 struct sdmmc_function *sf = saa->sf;
150 struct bwfm_core *core; 266 struct bwfm_core *core;
 267 uint32_t reg;
 268
 269 sc->sc_sc.sc_dev = self;
151 270
152 aprint_naive("\n"); 271 aprint_naive("\n");
 272 aprint_normal("\n");
153 273
154 sc->sc_sf = malloc((sf->sc->sc_function_count + 1) * 274 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
155 sizeof(struct sdmmc_function *), M_DEVBUF, M_WAITOK); 275 cv_init(&sc->sc_rxctl_cv, "bwfmctl");
 276 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
 277
 278 sdmmc_init_task(&sc->sc_task, bwfm_sdio_task, sc);
 279 sc->sc_task_queued = false;
 280
 281 sc->sc_bounce_size = 64 * 1024;
 282 sc->sc_bounce_buf = kmem_alloc(sc->sc_bounce_size, KM_SLEEP);
 283 sc->sc_tx_seq = 0xff;
 284 MBUFQ_INIT(&sc->sc_tx_queue);
 285 sc->sc_rxctl_queue = NULL;
 286
 287 sc->sc_sf_size = (sf->sc->sc_function_count + 1)
 288 * sizeof(struct sdmmc_function *);
 289 sc->sc_sf = kmem_zalloc(sc->sc_sf_size, KM_SLEEP);
156 290
157 /* Copy all function pointers. */ 291 /* Copy all function pointers. */
158 SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) { 292 SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) {
159 sc->sc_sf[sf->number] = sf; 293 sc->sc_sf[sf->number] = sf;
160 } 294 }
161 sf = saa->sf; 
162 295
163 /* 296 sdmmc_io_set_blocklen(sc->sc_sf[1]->sc, sc->sc_sf[1], 64);
164 * TODO: set block size to 64 for func 1, 512 for func 2. 297 sdmmc_io_set_blocklen(sc->sc_sf[2]->sc, sc->sc_sf[2], 512);
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 298
170 /* Enable Function 1. */ 299 /* Enable Function 1. */
171 if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) { 300 if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) {
172 aprint_error_dev(self, "cannot enable function 1\n"); 301 printf("%s: cannot enable function 1\n", DEVNAME(sc));
173 goto err; 302 return;
174 } 303 }
175 304
176 DPRINTFN(2, ("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc), 305 DPRINTF(("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc),
177 bwfm_sdio_read_4(sc, 0x18000000))); 306 bwfm_sdio_read_4(sc, 0x18000000)));
178 307
179 /* Force PLL off */ 308 /* Force PLL off */
180 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 309 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
181 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | 310 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
182 BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); 311 BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ);
183 312
184 sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops; 313 sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops;
185 if (bwfm_chip_attach(&sc->sc_sc) != 0) { 314 if (bwfm_chip_attach(&sc->sc_sc) != 0) {
186 aprint_error_dev(self, "cannot attach chip\n"); 315 aprint_error_dev(self, "cannot attach chip\n");
187 goto err; 316 return;
 317 }
 318
 319 sc->sc_cc = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_CHIPCOMMON);
 320 if (sc->sc_cc == NULL) {
 321 aprint_error_dev(self, "cannot find chipcommon core\n");
 322 return;
 323 }
 324
 325 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
 326 if (core->co_rev >= 12) {
 327 reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR);
 328 if ((reg & BWFM_SDIO_FUNC1_SLEEPCSR_KSO) == 0) {
 329 reg |= BWFM_SDIO_FUNC1_SLEEPCSR_KSO;
 330 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR, reg);
 331 }
188 } 332 }
189 333
190 /* TODO: drive strength */ 334 /* TODO: drive strength */
191 335
192 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL, 336 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCTRL,
193 bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL) | 337 bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_CARDCTRL) |
194 BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET); 338 BWFM_SDIO_CCCR_CARDCTRL_WLANRESET);
195 339
196 core = bwfm_chip_get_pmu(&sc->sc_sc); 340 core = bwfm_chip_get_pmu(&sc->sc_sc);
197 bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL, 341 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) | 342 bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) |
199 (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD << 343 (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD <<
200 BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT)); 344 BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT));
201 345
 346 sdmmc_io_function_disable(sc->sc_sf[2]);
 347
 348 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
 349 sc->sc_clkstate = CLK_SDONLY;
 350
 351 config_mountroot(self, bwfm_sdio_attachhook);
 352}
 353
 354void
 355bwfm_sdio_attachhook(device_t self)
 356{
 357 struct bwfm_sdio_softc *sc = device_private(self);
 358 struct bwfm_softc *bwfm = &sc->sc_sc;
 359 firmware_handle_t fwh;
 360 const char *name, *nvname;
 361 u_char *ucode, *nvram;
 362 size_t size, nvlen, nvsize;
 363 uint32_t reg, clk;
 364 int error;
 365
 366 DPRINTF(("%s: chip 0x%08x rev %u\n", DEVNAME(sc),
 367 bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev));
 368 switch (bwfm->sc_chip.ch_chip) {
 369 case BRCM_CC_4330_CHIP_ID:
 370 name = "brcmfmac4330-sdio.bin";
 371 nvname = "brcmfmac4330-sdio.txt";
 372 break;
 373 case BRCM_CC_4334_CHIP_ID:
 374 name = "brcmfmac4334-sdio.bin";
 375 nvname = "brcmfmac4334-sdio.txt";
 376 break;
 377 case BRCM_CC_4345_CHIP_ID:
 378 name = "brcmfmac43455-sdio.bin";
 379 nvname = "brcmfmac43455-sdio.txt";
 380 break;
 381 case BRCM_CC_43340_CHIP_ID:
 382 name = "brcmfmac43340-sdio.bin";
 383 nvname = "brcmfmac43340-sdio.txt";
 384 break;
 385 case BRCM_CC_4335_CHIP_ID:
 386 if (bwfm->sc_chip.ch_chiprev < 2) {
 387 name = "brcmfmac4335-sdio.bin";
 388 nvname = "brcmfmac4335-sdio.txt";
 389 } else {
 390 name = "brcmfmac4339-sdio.bin";
 391 nvname = "brcmfmac4339-sdio.txt";
 392 }
 393 break;
 394 case BRCM_CC_4339_CHIP_ID:
 395 name = "brcmfmac4339-sdio.bin";
 396 nvname = "brcmfmac4339-sdio.txt";
 397 break;
 398 case BRCM_CC_43430_CHIP_ID:
 399 if (bwfm->sc_chip.ch_chiprev == 0) {
 400 name = "brcmfmac43430a0-sdio.bin";
 401 nvname = "brcmfmac43430a0-sdio.txt";
 402 } else {
 403 name = "brcmfmac43430-sdio.bin";
 404 nvname = "brcmfmac43430-sdio.txt";
 405 }
 406 break;
 407 case BRCM_CC_4356_CHIP_ID:
 408 name = "brcmfmac4356-sdio.bin";
 409 nvname = "brcmfmac4356-sdio.txt";
 410 break;
 411 default:
 412 printf("%s: unknown firmware for chip %s\n",
 413 DEVNAME(sc), bwfm->sc_chip.ch_name);
 414 goto err;
 415 }
 416
 417 if (firmware_open("if_bwfm", name, &fwh) != 0) {
 418 printf("%s: failed firmware_open of file %s\n",
 419 DEVNAME(sc), name);
 420 goto err;
 421 }
 422 size = firmware_get_size(fwh);
 423 ucode = firmware_malloc(size);
 424 if (ucode == NULL) {
 425 printf("%s: failed firmware_open of file %s\n",
 426 DEVNAME(sc), name);
 427 firmware_close(fwh);
 428 goto err;
 429 }
 430 error = firmware_read(fwh, 0, ucode, size);
 431 firmware_close(fwh);
 432 if (error != 0) {
 433 printf("%s: failed to read firmware (error %d)\n",
 434 DEVNAME(sc), error);
 435 goto err1;
 436 }
 437
 438 if (firmware_open("if_bwfm", nvname, &fwh) != 0) {
 439 printf("%s: failed firmware_open of file %s\n",
 440 DEVNAME(sc), nvname);
 441 goto err1;
 442 }
 443 nvlen = firmware_get_size(fwh);
 444 nvram = firmware_malloc(nvlen);
 445 if (nvram == NULL) {
 446 printf("%s: failed firmware_open of file %s\n",
 447 DEVNAME(sc), name);
 448 firmware_close(fwh);
 449 goto err1;
 450 }
 451 error = firmware_read(fwh, 0, nvram, nvlen);
 452 firmware_close(fwh);
 453 if (error != 0) {
 454 printf("%s: failed to read firmware (error %d)\n",
 455 DEVNAME(sc), error);
 456 goto err2;
 457 }
 458
 459 if (bwfm_nvram_convert(nvram, nvlen, &nvsize)) {
 460 printf("%s: failed to convert nvram\n", DEVNAME(sc));
 461 goto err2;
 462 }
 463
 464 sc->sc_alp_only = true;
 465 if (bwfm_sdio_load_microcode(sc, ucode, size, nvram, nvsize) != 0) {
 466 printf("%s: could not load microcode\n",
 467 DEVNAME(sc));
 468 goto err2;
 469 }
 470 sc->sc_alp_only = false;
 471
 472 firmware_free(nvram, nvlen);
 473 firmware_free(ucode, size);
 474
 475 bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
 476 if (sc->sc_clkstate != CLK_AVAIL) {
 477 printf("%s: could not access clock\n",
 478 DEVNAME(sc));
 479 goto err;
 480 }
 481
 482 clk = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
 483 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
 484 clk | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT);
 485
 486 bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOXDATA,
 487 SDPCM_PROT_VERSION << SDPCM_PROT_VERSION_SHIFT);
 488 if (sdmmc_io_function_enable(sc->sc_sf[2])) {
 489 printf("%s: cannot enable function 2\n", DEVNAME(sc));
 490 goto err;
 491 }
 492
 493 bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK,
 494 SDPCMD_INTSTATUS_HMB_SW_MASK | SDPCMD_INTSTATUS_CHIPACTIVE);
 495 bwfm_sdio_write_1(sc, BWFM_SDIO_WATERMARK, 8);
 496
 497 if (bwfm_chip_sr_capable(bwfm)) {
 498 reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL);
 499 reg |= BWFM_SDIO_FUNC1_WAKEUPCTRL_HTWAIT;
 500 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL, reg);
 501 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCAP,
 502 BWFM_SDIO_CCCR_CARDCAP_CMD14_SUPPORT |
 503 BWFM_SDIO_CCCR_CARDCAP_CMD14_EXT);
 504 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
 505 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT);
 506 sc->sc_sr_enabled = 1;
 507 } else {
 508 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk);
 509 }
 510
 511 sc->sc_ih = sdmmc_intr_establish(sc->sc_sc.sc_dev->dv_parent,
 512 bwfm_sdio_intr, sc, DEVNAME(sc));
 513 if (sc->sc_ih == NULL) {
 514 aprint_error_dev(self, "could not establish interrupt\n");
 515 bwfm_sdio_clkctl(sc, CLK_NONE, false);
 516 return;
 517 }
 518 sdmmc_intr_enable(sc->sc_sf[1]);
 519
202 sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops; 520 sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops;
203 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; 521 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
204 bwfm_attach(&sc->sc_sc); 522 bwfm_attach(&sc->sc_sc);
 523 sc->sc_bwfm_attached = true;
205 524
206 return; 525 return;
207 526
 527err2:
 528 firmware_free(nvram, nvlen);
 529err1:
 530 firmware_free(ucode, size);
208err: 531err:
209 free(sc->sc_sf, M_DEVBUF); 532 return;
210} 533}
211 534
212int 535int
213bwfm_sdio_detach(struct device *self, int flags) 536bwfm_sdio_detach(struct device *self, int flags)
214{ 537{
215 struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self; 538 struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self;
216 539
217 bwfm_detach(&sc->sc_sc, flags); 540#ifdef BWFM_DEBUG
 541 bwfm_sdio_debug_console(sc);
 542#endif
 543
 544 if (sc->sc_ih) {
 545 sdmmc_intr_disable(sc->sc_sf[1]);
 546 sdmmc_intr_disestablish(sc->sc_ih);
 547 }
 548 if (sc->sc_bwfm_attached)
 549 bwfm_detach(&sc->sc_sc, flags);
218 550
219 free(sc->sc_sf, M_DEVBUF); 551 kmem_free(sc->sc_sf, sc->sc_sf_size);
 552 kmem_free(sc->sc_bounce_buf, sc->sc_bounce_size);
 553
 554 mutex_destroy(&sc->sc_intr_lock);
 555 cv_destroy(&sc->sc_rxctl_cv);
 556 mutex_destroy(&sc->sc_lock);
220 557
221 return 0; 558 return 0;
222} 559}
223 560
224void 561void
225bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t bar0) 562bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t addr)
226{ 563{
 564 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK;
 565
227 if (sc->sc_bar0 == bar0) 566 if (sc->sc_bar0 == bar0)
228 return; 567 return;
229 568
230 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW, 569 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW,
231 (bar0 >> 8) & 0x80); 570 (bar0 >> 8) & 0xff);
232 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID, 571 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID,
233 (bar0 >> 16) & 0xff); 572 (bar0 >> 16) & 0xff);
234 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH, 573 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH,
235 (bar0 >> 24) & 0xff); 574 (bar0 >> 24) & 0xff);
236 sc->sc_bar0 = bar0; 575 sc->sc_bar0 = bar0;
237} 576}
238 577
239uint8_t 578uint8_t
240bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr) 579bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr)
241{ 580{
242 struct sdmmc_function *sf; 581 struct sdmmc_function *sf;
243 uint8_t rv; 582 uint8_t rv;
244 583
@@ -251,30 +590,29 @@ bwfm_sdio_read_1(struct bwfm_sdio_softc  @@ -251,30 +590,29 @@ bwfm_sdio_read_1(struct bwfm_sdio_softc
251 if ((addr & ~0x7ff) == 0) 590 if ((addr & ~0x7ff) == 0)
252 sf = sc->sc_sf[0]; 591 sf = sc->sc_sf[0];
253 else 592 else
254 sf = sc->sc_sf[1]; 593 sf = sc->sc_sf[1];
255 594
256 rv = sdmmc_io_read_1(sf, addr); 595 rv = sdmmc_io_read_1(sf, addr);
257 return rv; 596 return rv;
258} 597}
259 598
260uint32_t 599uint32_t
261bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr) 600bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr)
262{ 601{
263 struct sdmmc_function *sf; 602 struct sdmmc_function *sf;
264 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; 
265 uint32_t rv; 603 uint32_t rv;
266 604
267 bwfm_sdio_backplane(sc, bar0); 605 bwfm_sdio_backplane(sc, addr);
268 606
269 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; 607 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
270 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; 608 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
271 609
272 /* 610 /*
273 * figure out how to read the register based on address range 611 * figure out how to read the register based on address range
274 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 612 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
275 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 613 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
276 * The rest: function 1 silicon backplane core registers 614 * The rest: function 1 silicon backplane core registers
277 */ 615 */
278 if ((addr & ~0x7ff) == 0) 616 if ((addr & ~0x7ff) == 0)
279 sf = sc->sc_sf[0]; 617 sf = sc->sc_sf[0];
280 else 618 else
@@ -297,159 +635,1186 @@ bwfm_sdio_write_1(struct bwfm_sdio_softc @@ -297,159 +635,1186 @@ bwfm_sdio_write_1(struct bwfm_sdio_softc
297 */ 635 */
298 if ((addr & ~0x7ff) == 0) 636 if ((addr & ~0x7ff) == 0)
299 sf = sc->sc_sf[0]; 637 sf = sc->sc_sf[0];
300 else 638 else
301 sf = sc->sc_sf[1]; 639 sf = sc->sc_sf[1];
302 640
303 sdmmc_io_write_1(sf, addr, data); 641 sdmmc_io_write_1(sf, addr, data);
304} 642}
305 643
306void 644void
307bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data) 645bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data)
308{ 646{
309 struct sdmmc_function *sf; 647 struct sdmmc_function *sf;
310 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; 
311 648
312 bwfm_sdio_backplane(sc, bar0); 649 bwfm_sdio_backplane(sc, addr);
313 650
314 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; 651 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
315 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; 652 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
316 653
317 /* 654 /*
318 * figure out how to read the register based on address range 655 * figure out how to read the register based on address range
319 * 0x00 ~ 0x7FF: function 0 CCCR and FBR 656 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
320 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers 657 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
321 * The rest: function 1 silicon backplane core registers 658 * The rest: function 1 silicon backplane core registers
322 */ 659 */
323 if ((addr & ~0x7ff) == 0) 660 if ((addr & ~0x7ff) == 0)
324 sf = sc->sc_sf[0]; 661 sf = sc->sc_sf[0];
325 else 662 else
326 sf = sc->sc_sf[1]; 663 sf = sc->sc_sf[1];
327 664
328 sdmmc_io_write_4(sf, addr, data); 665 sdmmc_io_write_4(sf, addr, data);
329} 666}
330 667
 668int
 669bwfm_sdio_buf_read(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
 670 uint32_t reg, char *data, size_t size)
 671{
 672 int err;
 673
 674 KASSERT(((vaddr_t)data & 0x3) == 0);
 675 KASSERT((size & 0x3) == 0);
 676
 677 if (sf == sc->sc_sf[1])
 678 err = sdmmc_io_read_region_1(sf, reg, data, size);
 679 else
 680 err = sdmmc_io_read_multi_1(sf, reg, data, size);
 681
 682 if (err)
 683 printf("%s: error %d\n", __func__, err);
 684
 685 return err;
 686}
 687
 688int
 689bwfm_sdio_buf_write(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
 690 uint32_t reg, char *data, size_t size)
 691{
 692 int err;
 693
 694 KASSERT(((vaddr_t)data & 0x3) == 0);
 695 KASSERT((size & 0x3) == 0);
 696
 697 err = sdmmc_io_write_region_1(sf, reg, data, size);
 698
 699 if (err)
 700 printf("%s: error %d\n", __func__, err);
 701
 702 return err;
 703}
 704
 705uint32_t
 706bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *sc, uint32_t reg,
 707 char *data, size_t left, int write)
 708{
 709 uint32_t sbaddr, sdaddr, off;
 710 size_t size;
 711 int err;
 712
 713 err = off = 0;
 714 while (left > 0) {
 715 sbaddr = reg + off;
 716 bwfm_sdio_backplane(sc, sbaddr);
 717
 718 sdaddr = sbaddr & BWFM_SDIO_SB_OFT_ADDR_MASK;
 719 size = ulmin(left, (BWFM_SDIO_SB_OFT_ADDR_PAGE - sdaddr));
 720 sdaddr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
 721
 722 if (write) {
 723 memcpy(sc->sc_bounce_buf, data + off, size);
 724 if (roundup(size, 4) != size)
 725 memset(sc->sc_bounce_buf + size, 0,
 726 roundup(size, 4) - size);
 727 err = bwfm_sdio_buf_write(sc, sc->sc_sf[1], sdaddr,
 728 sc->sc_bounce_buf, roundup(size, 4));
 729 } else {
 730 err = bwfm_sdio_buf_read(sc, sc->sc_sf[1], sdaddr,
 731 sc->sc_bounce_buf, roundup(size, 4));
 732 memcpy(data + off, sc->sc_bounce_buf, size);
 733 }
 734 if (err)
 735 break;
 736
 737 off += size;
 738 left -= size;
 739 }
 740
 741 return err;
 742}
 743
 744uint32_t
 745bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *sc,
 746 char *data, size_t size, int write)
 747{
 748 uint32_t addr;
 749 int err;
 750
 751 addr = sc->sc_cc->co_base;
 752 bwfm_sdio_backplane(sc, addr);
 753
 754 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
 755 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
 756
 757 if (write)
 758 err = bwfm_sdio_buf_write(sc, sc->sc_sf[2], addr, data, size);
 759 else
 760 err = bwfm_sdio_buf_read(sc, sc->sc_sf[2], addr, data, size);
 761
 762 return err;
 763}
 764
 765uint32_t
 766bwfm_sdio_dev_read(struct bwfm_sdio_softc *sc, uint32_t reg)
 767{
 768 struct bwfm_core *core;
 769 uint32_t val;
 770
 771 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
 772 val = bwfm_sdio_read_4(sc, core->co_base + reg);
 773 /* TODO: Workaround for 4335/4339 */
 774
 775 return val;
 776}
 777
 778void
 779bwfm_sdio_dev_write(struct bwfm_sdio_softc *sc, uint32_t reg, uint32_t val)
 780{
 781 struct bwfm_core *core;
 782
 783 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
 784 bwfm_sdio_write_4(sc, core->co_base + reg, val);
 785}
 786
331uint32_t 787uint32_t
332bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 788bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
333{ 789{
334 struct bwfm_sdio_softc *sc = (void *)bwfm; 790 struct bwfm_sdio_softc *sc = (void *)bwfm;
335 uint32_t val; 791 uint32_t val;
336 792
 793 mutex_enter(&sc->sc_lock);
337 val = bwfm_sdio_read_4(sc, reg); 794 val = bwfm_sdio_read_4(sc, reg);
338 /* TODO: Workaround for 4335/4339 */ 795 /* TODO: Workaround for 4335/4339 */
 796 mutex_exit(&sc->sc_lock);
339 797
340 return val; 798 return val;
341} 799}
342 800
343void 801void
344bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 802bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
345{ 803{
346 struct bwfm_sdio_softc *sc = (void *)bwfm; 804 struct bwfm_sdio_softc *sc = (void *)bwfm;
 805
 806 mutex_enter(&sc->sc_lock);
347 bwfm_sdio_write_4(sc, reg, val); 807 bwfm_sdio_write_4(sc, reg, val);
 808 mutex_exit(&sc->sc_lock);
348} 809}
349 810
350int 811int
351bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm) 812bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm)
352{ 813{
353 struct bwfm_sdio_softc *sc = (void *)bwfm; 814 struct bwfm_sdio_softc *sc = (void *)bwfm;
354 uint8_t clkval, clkset, clkmask; 815 uint8_t clkval, clkset, clkmask;
355 int i; 816 int i, error = 0;
 817
 818 mutex_enter(&sc->sc_lock);
356 819
357 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ | 820 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ |
358 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF; 821 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF;
359 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); 822 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset);
360 823
361 clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL | 824 clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL |
362 BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL; 825 BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL;
363 clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); 826 clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
364 827
365 if ((clkval & ~clkmask) != clkset) { 828 if ((clkval & ~clkmask) != clkset) {
366 printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc), 829 printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc),
367 clkset, clkval); 830 clkset, clkval);
368 return 1; 831 error = 1;
 832 goto done;
369 } 833 }
370 834
371 for (i = 1000; i > 0; i--) { 835 for (i = 1000; i > 0; i--) {
372 clkval = bwfm_sdio_read_1(sc, 836 clkval = bwfm_sdio_read_1(sc,
373 BWFM_SDIO_FUNC1_CHIPCLKCSR); 837 BWFM_SDIO_FUNC1_CHIPCLKCSR);
374 if (clkval & clkmask) 838 if (clkval & clkmask)
375 break; 839 break;
376 } 840 }
377 if (i == 0) { 841 if (i == 0) {
378 printf("%s: timeout on ALPAV wait, clkval 0x%02x\n", 842 printf("%s: timeout on ALPAV wait, clkval 0x%02x\n",
379 DEVNAME(sc), clkval); 843 DEVNAME(sc), clkval);
380 return 1; 844 error = 1;
 845 goto done;
381 } 846 }
382 847
383 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | 848 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
384 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP; 849 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP;
385 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); 850 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset);
386 delay(65); 851 delay(65);
387 852
388 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0); 853 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0);
389 854
390 return 0; 855done:
 856 mutex_exit(&sc->sc_lock);
 857
 858 return error;
391} 859}
392 860
393void 861void
394bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 862bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
395{ 863{
396 struct bwfm_sdio_softc *sc = (void *)bwfm; 864 struct bwfm_sdio_softc *sc = (void *)bwfm;
397 struct bwfm_core *core; 865 struct bwfm_core *core;
398 866
399 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); 867 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
400 bwfm_sdio_buscore_write(&sc->sc_sc, 868 bwfm_sdio_buscore_write(&sc->sc_sc,
401 core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF); 869 core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF);
402 870
403#if notyet 871 mutex_enter(&sc->sc_lock);
404 if (rstvec) 872 if (rstvec)
405 bwfm_sdio_ram_write(&sc->sc_sc, 0, &rstvec, sizeof(rstvec)); 873 bwfm_sdio_ram_read_write(sc, 0, (char *)&rstvec,
406#endif 874 sizeof(rstvec), 1);
 875 mutex_exit(&sc->sc_lock);
 876}
 877
 878struct mbuf *
 879bwfm_sdio_newbuf(void)
 880{
 881 struct mbuf *m;
 882
 883 MGETHDR(m, M_DONTWAIT, MT_DATA);
 884 if (m == NULL)
 885 return NULL;
 886
 887 MCLGET(m, M_DONTWAIT);
 888 if (!(m->m_flags & M_EXT)) {
 889 m_freem(m);
 890 return NULL;
 891 }
 892
 893 m->m_len = m->m_pkthdr.len = MCLBYTES;
 894 return m;
 895}
 896
 897struct mbuf *
 898bwfm_qget(struct mbuf **q)
 899{
 900 struct mbuf *m = NULL;
 901
 902 if (*q != NULL) {
 903 m = *q;
 904 *q = m->m_next;
 905 m->m_next = NULL;
 906 }
 907
 908 return m;
 909}
 910
 911void
 912bwfm_qput(struct mbuf **q, struct mbuf *m)
 913{
 914
 915 if (*q == NULL)
 916 *q = m;
 917 else
 918 m_cat(*q, m);
407} 919}
408 920
409int 921int
410bwfm_sdio_txcheck(struct bwfm_softc *bwfm, struct mbuf *m) 922bwfm_sdio_txcheck(struct bwfm_softc *bwfm)
411{ 923{
412 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 924 struct bwfm_sdio_softc *sc = (void *)bwfm;
 925 int error = 0;
413 926
414 return 0; 927 mutex_enter(&sc->sc_lock);
 928 if (sc->sc_tx_count >= 64)
 929 error = ENOBUFS;
 930 mutex_exit(&sc->sc_lock);
 931
 932 return error;
415} 933}
416 934
417 935
418int 936int
419bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 937bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf **mp)
420{ 938{
421#ifdef BWFM_DEBUG 
422 struct bwfm_sdio_softc *sc = (void *)bwfm; 939 struct bwfm_sdio_softc *sc = (void *)bwfm;
423#endif 
424 int ret = 1; 
425 940
426 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 941 if (sc->sc_tx_count >= 64) {
 942 printf("%s: tx count limit reached\n",DEVNAME(sc));
 943 return ENOBUFS;
 944 }
 945
 946 mutex_enter(&sc->sc_lock);
 947 sc->sc_tx_count++;
 948 MBUFQ_ENQUEUE(&sc->sc_tx_queue, *mp);
 949 mutex_exit(&sc->sc_lock);
427 950
428 return ret; 951 bwfm_sdio_intr(sc);
 952
 953 return 0;
429} 954}
430 955
431int 956int
432bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) 957bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len)
433{ 958{
434#ifdef BWFM_DEBUG 
435 struct bwfm_sdio_softc *sc = (void *)bwfm; 959 struct bwfm_sdio_softc *sc = (void *)bwfm;
 960 struct mbuf *m;
 961
 962 KASSERT(len <= MCLBYTES);
 963
 964 MGET(m, M_DONTWAIT, MT_CONTROL);
 965 if (m == NULL)
 966 goto fail;
 967 if (len > MLEN) {
 968 MCLGET(m, M_DONTWAIT);
 969 if (!(m->m_flags & M_EXT)) {
 970 m_freem(m);
 971 goto fail;
 972 }
 973 }
 974 memcpy(mtod(m, char *), buf, len);
 975 m->m_len = len;
 976
 977 mutex_enter(&sc->sc_lock);
 978 MBUFQ_ENQUEUE(&sc->sc_tx_queue, m);
 979 mutex_exit(&sc->sc_lock);
 980
 981 bwfm_sdio_intr(sc);
 982
 983 return 0;
 984
 985fail:
 986 return ENOBUFS;
 987}
 988
 989int
 990bwfm_nvram_convert(u_char *buf, size_t len, size_t *newlenp)
 991{
 992 u_char *src, *dst, *end = buf + len;
 993 bool skip = false;
 994 size_t count = 0, pad;
 995 uint32_t token;
 996
 997 for (src = buf, dst = buf; src != end; ++src) {
 998 if (*src == '\n') {
 999 if (count > 0)
 1000 *dst++ = '\0';
 1001 count = 0;
 1002 skip = false;
 1003 continue;
 1004 }
 1005 if (skip)
 1006 continue;
 1007 if (*src == '#' && count == 0) {
 1008 skip = true;
 1009 continue;
 1010 }
 1011 if (*src == '\r')
 1012 continue;
 1013 *dst++ = *src;
 1014 ++count;
 1015 }
 1016
 1017 count = dst - buf;
 1018 pad = roundup(count + 1, 4) - count;
 1019
 1020 if (count + pad + sizeof(token) > len)
 1021 return 1;
 1022
 1023 memset(dst, 0, pad);
 1024 count += pad;
 1025 dst += pad;
 1026
 1027 token = (count / 4) & 0xffff;
 1028 token |= ~token << 16;
 1029 token = htole32(token);
 1030
 1031 memcpy(dst, &token, sizeof(token));
 1032 count += sizeof(token);
 1033
 1034 *newlenp = count ;
 1035
 1036 return 0;
 1037}
 1038
 1039int
 1040bwfm_sdio_load_microcode(struct bwfm_sdio_softc *sc, u_char *ucode, size_t size,
 1041 u_char *nvram, size_t nvlen)
 1042{
 1043 struct bwfm_softc *bwfm = &sc->sc_sc;
 1044 char *verify = NULL;
 1045 int err = 0;
 1046
 1047 bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
 1048
 1049 DPRINTF(("ucode %zu bytes to 0x%08lx\n", size,
 1050 (u_long)bwfm->sc_chip.ch_rambase));
 1051 /* Upload firmware */
 1052 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase,
 1053 ucode, size, 1);
 1054 if (err)
 1055 goto out;
 1056
 1057 /* Verify firmware */
 1058 verify = kmem_zalloc(size, KM_SLEEP);
 1059 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase,
 1060 verify, size, 0);
 1061 if (err || memcmp(verify, ucode, size)) {
 1062 printf("%s: firmware verification failed\n",
 1063 DEVNAME(sc));
 1064 kmem_free(verify, size);
 1065 goto out;
 1066 }
 1067 kmem_free(verify, size);
 1068
 1069 DPRINTF(("nvram %zu bytes to 0x%08lx\n", nvlen,
 1070 (u_long)bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
 1071 - nvlen));
 1072 /* Upload nvram */
 1073 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase +
 1074 bwfm->sc_chip.ch_ramsize - nvlen, nvram, nvlen, 1);
 1075 if (err)
 1076 goto out;
 1077
 1078 /* Verify nvram */
 1079 verify = kmem_zalloc(nvlen, KM_SLEEP);
 1080 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase +
 1081 bwfm->sc_chip.ch_ramsize - nvlen, verify, nvlen, 0);
 1082 if (err || memcmp(verify, nvram, nvlen)) {
 1083 printf("%s: nvram verification failed\n",
 1084 DEVNAME(sc));
 1085 kmem_free(verify, nvlen);
 1086 goto out;
 1087 }
 1088 kmem_free(verify, nvlen);
 1089
 1090 DPRINTF(("Reset core 0x%08x\n", *(uint32_t *)ucode));
 1091 /* Load reset vector from firmware and kickstart core. */
 1092 bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
 1093
 1094out:
 1095 bwfm_sdio_clkctl(sc, CLK_SDONLY, false);
 1096 return err;
 1097}
 1098
 1099void
 1100bwfm_sdio_clkctl(struct bwfm_sdio_softc *sc, enum bwfm_sdio_clkstate newstate,
 1101 bool pendok)
 1102{
 1103 enum bwfm_sdio_clkstate oldstate;
 1104
 1105 oldstate = sc->sc_clkstate;
 1106 if (oldstate == newstate)
 1107 return;
 1108
 1109 switch (newstate) {
 1110 case CLK_AVAIL:
 1111 if (oldstate == CLK_NONE)
 1112 sc->sc_clkstate = CLK_SDONLY; /* XXX */
 1113 bwfm_sdio_htclk(sc, true, pendok);
 1114 break;
 1115 case CLK_SDONLY:
 1116 if (oldstate == CLK_NONE)
 1117 sc->sc_clkstate = newstate;
 1118 else if (oldstate == CLK_AVAIL)
 1119 bwfm_sdio_htclk(sc, false, false);
 1120 else
 1121 printf("%s: clkctl %d -> %d\n", DEVNAME(sc),
 1122 sc->sc_clkstate, newstate);
 1123 break;
 1124 case CLK_NONE:
 1125 if (oldstate == CLK_AVAIL)
 1126 bwfm_sdio_htclk(sc, false, false);
 1127 sc->sc_clkstate = newstate;
 1128 break;
 1129 default:
 1130 break;
 1131 }
 1132
 1133 DPRINTF(("%s: %d -> %d = %d\n", DEVNAME(sc), oldstate, newstate,
 1134 sc->sc_clkstate));
 1135}
 1136
 1137void
 1138bwfm_sdio_htclk(struct bwfm_sdio_softc *sc, bool on, bool pendok)
 1139{
 1140 uint32_t clkctl, devctl, req;
 1141 int i;
 1142
 1143 if (sc->sc_sr_enabled) {
 1144 if (on)
 1145 sc->sc_clkstate = CLK_AVAIL;
 1146 else
 1147 sc->sc_clkstate = CLK_SDONLY;
 1148 return;
 1149 }
 1150
 1151 if (on) {
 1152 if (sc->sc_alp_only)
 1153 req = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ;
 1154 else
 1155 req = BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL_REQ;
 1156 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, req);
 1157
 1158 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
 1159 if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only)
 1160 && pendok) {
 1161 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
 1162 devctl |= BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
 1163 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
 1164 sc->sc_clkstate = CLK_PENDING;
 1165 return;
 1166 } else if (sc->sc_clkstate == CLK_PENDING) {
 1167 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
 1168 devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
 1169 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
 1170 }
 1171
 1172 for (i = 0; i < 5000; i++) {
 1173 if (BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl,
 1174 sc->sc_alp_only))
 1175 break;
 1176 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR
 1177);
 1178 delay(1000);
 1179 }
 1180 if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only))
 1181{
 1182 printf("%s: HT avail timeout\n", DEVNAME(sc));
 1183 return;
 1184 }
 1185
 1186 sc->sc_clkstate = CLK_AVAIL;
 1187 } else {
 1188 if (sc->sc_clkstate == CLK_PENDING) {
 1189 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
 1190 devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
 1191 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
 1192 }
 1193 sc->sc_clkstate = CLK_SDONLY;
 1194 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
 1195 }
 1196}
 1197
 1198#if notyet
 1199int
 1200bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *sc, bool sleep, bool pendok)
 1201{
 1202 uint32_t clkctl;
 1203
 1204 if (sc->sleeping == sleep)
 1205 return 0;
 1206
 1207 if (sc->sc_sr_enabled) {
 1208 if (sleep) {
 1209 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
 1210 if ((clkctl & BWFM_SDIO_FUNC1_CHIPCLKCSR_CSR_MASK) == 0)
 1211 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ);
 1212 }
 1213 /* kso_ctrl(sc, sleep) */
 1214 }
 1215
 1216 if (sleep) {
 1217 if (!sc->sc_sr_enabled)
 1218 bwfm_sdio_clkctl(sc, CLK_NONE, pendok);
 1219 } else {
 1220 bwfm_sdio_clkctl(sc, CLK_AVAIL, pendok);
 1221 }
 1222
 1223 sc->sleeping = sleep;
 1224
 1225 return 0;
 1226}
436#endif 1227#endif
437 int ret = 1; 
438 1228
439 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 1229void
 1230bwfm_sdio_readshared(struct bwfm_sdio_softc *sc)
 1231{
 1232 struct bwfm_softc *bwfm = &sc->sc_sc;
 1233 struct bwfm_sdio_sdpcm sdpcm;
 1234 uint32_t addr, shaddr;
 1235 int err;
 1236
 1237 bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
 1238 if (sc->sc_clkstate != CLK_AVAIL)
 1239 return;
 1240
 1241 shaddr = bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4;
 1242 if (!bwfm->sc_chip.ch_rambase && sc->sc_sr_enabled)
 1243 shaddr -= bwfm->sc_chip.ch_srsize;
 1244
 1245 err = bwfm_sdio_ram_read_write(sc, shaddr, (char *)&addr,
 1246 sizeof(addr), 0);
 1247 if (err)
 1248 return;
440 1249
441 return ret; 1250 addr = le32toh(addr);
 1251 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff))
 1252 return;
 1253
 1254 err = bwfm_sdio_ram_read_write(sc, addr, (char *)&sdpcm,
 1255 sizeof(sdpcm), 0);
 1256 if (err)
 1257 return;
 1258
 1259 sc->sc_console_addr = le32toh(sdpcm.console_addr);
442} 1260}
443 1261
444int 1262int
445bwfm_sdio_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len) 1263bwfm_sdio_intr(void *v)
446{ 1264{
 1265 struct bwfm_sdio_softc *sc = (void *)v;
 1266
 1267 DPRINTF(("%s: sdio_intr\n", DEVNAME(sc)));
 1268
 1269 mutex_enter(&sc->sc_intr_lock);
 1270 if (!sc->sc_task_queued) {
 1271 sc->sc_task_queued = true;
 1272 sdmmc_add_task(sc->sc_sf[1]->sc, &sc->sc_task);
 1273 }
 1274 mutex_exit(&sc->sc_intr_lock);
 1275 return 1;
 1276}
 1277
 1278void
 1279bwfm_sdio_task(void *v)
 1280{
 1281 struct bwfm_sdio_softc *sc = (void *)v;
 1282
 1283 mutex_enter(&sc->sc_intr_lock);
 1284 while (sc->sc_task_queued) {
 1285 sc->sc_task_queued = false;
 1286 mutex_exit(&sc->sc_intr_lock);
 1287
 1288 mutex_enter(&sc->sc_lock);
 1289 bwfm_sdio_task1(sc);
447#ifdef BWFM_DEBUG 1290#ifdef BWFM_DEBUG
448 struct bwfm_sdio_softc *sc = (void *)bwfm; 1291 bwfm_sdio_debug_console(sc);
449#endif 1292#endif
450 int ret = 1; 1293 mutex_exit(&sc->sc_lock);
 1294
 1295 mutex_enter(&sc->sc_intr_lock);
 1296 }
 1297 mutex_exit(&sc->sc_intr_lock);
 1298}
 1299
 1300void
 1301bwfm_sdio_task1(struct bwfm_sdio_softc *sc)
 1302{
 1303 uint32_t clkctl, devctl, intstat, hostint;
 1304
 1305 if (!sc->sc_sr_enabled && sc->sc_clkstate == CLK_PENDING) {
 1306 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
 1307 if (BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(clkctl)) {
 1308 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
 1309 devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
 1310 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
 1311 sc->sc_clkstate = CLK_AVAIL;
 1312 }
 1313 }
 1314
 1315 intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS);
 1316 DPRINTF(("%s: intstat 0x%" PRIx32 "\n", DEVNAME(sc), intstat));
 1317 intstat &= (SDPCMD_INTSTATUS_HMB_SW_MASK|SDPCMD_INTSTATUS_CHIPACTIVE);
 1318 /* XXX fc state */
 1319 if (intstat)
 1320 bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, intstat);
 1321
 1322 if (intstat & SDPCMD_INTSTATUS_HMB_HOST_INT) {
 1323 hostint = bwfm_sdio_dev_read(sc, SDPCMD_TOHOSTMAILBOXDATA);
 1324 DPRINTF(("%s: hostint 0x%" PRIx32 "\n", DEVNAME(sc), hostint));
 1325 bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOX,
 1326 SDPCMD_TOSBMAILBOX_INT_ACK);
 1327 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED)
 1328 intstat |= SDPCMD_INTSTATUS_HMB_FRAME_IND;
 1329 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_DEVREADY ||
 1330 hostint & SDPCMD_TOHOSTMAILBOXDATA_FWREADY)
 1331 bwfm_sdio_readshared(sc);
 1332 }
 1333
 1334 /* FIXME: Might stall if we don't when not set. */
 1335 if (intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND)
 1336 bwfm_sdio_rx_frames(sc);
 1337
 1338 if (MBUFQ_FIRST(&sc->sc_tx_queue))
 1339 bwfm_sdio_tx_frames(sc);
 1340}
 1341
 1342int
 1343bwfm_sdio_tx_ok(struct bwfm_sdio_softc *sc)
 1344{
 1345 return (uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) != 0 &&
 1346 ((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) & 0x80) == 0;
 1347}
 1348
 1349void
 1350bwfm_sdio_tx_frames(struct bwfm_sdio_softc *sc)
 1351{
 1352 struct mbuf *m;
 1353 struct ifnet *ifp = sc->sc_sc.sc_ic.ic_ifp;
 1354 bool ifstart = false;
 1355 int i;
 1356
 1357 if (!bwfm_sdio_tx_ok(sc))
 1358 return;
 1359
 1360 i = uimin((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq), 32);
 1361 while (i--) {
 1362 MBUFQ_DEQUEUE(&sc->sc_tx_queue, m);
 1363 if (m == NULL)
 1364 break;
 1365
 1366 if (m->m_type == MT_CONTROL)
 1367 bwfm_sdio_tx_ctrlframe(sc, m);
 1368 else {
 1369 bwfm_sdio_tx_dataframe(sc, m);
 1370 ifp->if_opackets++;
 1371 ifstart = true;
 1372 }
 1373
 1374 m_freem(m);
 1375 }
 1376
 1377 if (ifstart) {
 1378 ifp->if_flags &= ~IFF_OACTIVE;
 1379 if_schedule_deferred_start(ifp);
 1380 }
 1381}
 1382
 1383void
 1384bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
 1385{
 1386 struct bwfm_sdio_hwhdr *hwhdr;
 1387 struct bwfm_sdio_swhdr *swhdr;
 1388 size_t len, roundto;
 1389
 1390 len = sizeof(*hwhdr) + sizeof(*swhdr) + m->m_len;
 1391
 1392 /* Zero-pad to either block-size or 4-byte alignment. */
 1393 if (len > 512 && (len % 512) != 0)
 1394 roundto = 512;
 1395 else
 1396 roundto = 4;
 1397
 1398 KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
 1399
 1400 hwhdr = (void *)sc->sc_bounce_buf;
 1401 hwhdr->frmlen = htole16(len);
 1402 hwhdr->cksum = htole16(~len);
 1403
 1404 swhdr = (void *)&hwhdr[1];
 1405 swhdr->seqnr = sc->sc_tx_seq++;
 1406 swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_CONTROL;
 1407 swhdr->nextlen = 0;
 1408 swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
 1409 swhdr->maxseqnr = 0;
 1410
 1411 m_copydata(m, 0, m->m_len, &swhdr[1]);
 1412
 1413 if (roundup(len, roundto) != len)
 1414 memset(sc->sc_bounce_buf + len, 0,
 1415 roundup(len, roundto) - len);
 1416
 1417 bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 1418 roundup(len, roundto), 1);
 1419}
 1420
 1421void
 1422bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
 1423{
 1424 struct bwfm_sdio_hwhdr *hwhdr;
 1425 struct bwfm_sdio_swhdr *swhdr;
 1426 struct bwfm_proto_bcdc_hdr *bcdc;
 1427 size_t len, roundto;
 1428
 1429 len = sizeof(*hwhdr) + sizeof(*swhdr) + sizeof(*bcdc)
 1430 + m->m_pkthdr.len;
 1431
 1432 /* Zero-pad to either block-size or 4-byte alignment. */
 1433 if (len > 512 && (len % 512) != 0)
 1434 roundto = 512;
 1435 else
 1436 roundto = 4;
 1437
 1438 KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
 1439
 1440 hwhdr = (void *)sc->sc_bounce_buf;
 1441 hwhdr->frmlen = htole16(len);
 1442 hwhdr->cksum = htole16(~len);
 1443
 1444 swhdr = (void *)&hwhdr[1];
 1445 swhdr->seqnr = sc->sc_tx_seq++;
 1446 swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_DATA;
 1447 swhdr->nextlen = 0;
 1448 swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
 1449 swhdr->maxseqnr = 0;
 1450
 1451 bcdc = (void *)&swhdr[1];
 1452 bcdc->data_offset = 0;
 1453 bcdc->priority = WME_AC_BE;
 1454 bcdc->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER);
 1455 bcdc->flags2 = 0;
 1456
 1457 m_copydata(m, 0, m->m_pkthdr.len, &bcdc[1]);
 1458
 1459 if (roundup(len, roundto) != len)
 1460 memset(sc->sc_bounce_buf + len, 0,
 1461 roundup(len, roundto) - len);
 1462
 1463 bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 1464 roundup(len, roundto), 1);
 1465
 1466 sc->sc_tx_count--;
 1467}
 1468
 1469int
 1470bwfm_sdio_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *lenp)
 1471{
 1472 struct bwfm_sdio_softc *sc = (void *)bwfm;
 1473 struct mbuf *m;
 1474 int err = 0;
 1475
 1476 mutex_enter(&sc->sc_lock);
 1477 while ((m = bwfm_qget(&sc->sc_rxctl_queue)) == NULL) {
 1478 err = cv_timedwait(&sc->sc_rxctl_cv, &sc->sc_lock,
 1479 mstohz(5000));
 1480 if (err == EWOULDBLOCK)
 1481 break;
 1482 }
 1483 mutex_exit(&sc->sc_lock);
 1484
 1485 if (err)
 1486 return 1;
 1487
 1488 if (m->m_len < *lenp) {
 1489 m_freem(m);
 1490 return 1;
 1491 }
 1492
 1493 *lenp = m->m_len;
 1494 m_copydata(m, 0, m->m_len, buf);
 1495 m_freem(m);
 1496 return 0;
 1497}
 1498
 1499void
 1500bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
 1501{
 1502 struct bwfm_sdio_hwhdr *hwhdr;
 1503 struct bwfm_sdio_swhdr *swhdr;
 1504 struct bwfm_proto_bcdc_hdr *bcdc;
 1505 uint16_t *sublen, nextlen = 0;
 1506 struct mbuf *m;
 1507 size_t flen, off, hoff;
 1508 char *data;
 1509 int nsub;
 1510
 1511 hwhdr = (struct bwfm_sdio_hwhdr *)sc->sc_bounce_buf;
 1512 swhdr = (struct bwfm_sdio_swhdr *)&hwhdr[1];
 1513 data = (char *)&swhdr[1];
 1514
 1515 for (;;) {
 1516 /* If we know the next size, just read ahead. */
 1517 if (nextlen) {
 1518 if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 1519 nextlen, 0))
 1520 break;
 1521 } else {
 1522 if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 1523 sizeof(*hwhdr) + sizeof(*swhdr), 0))
 1524 break;
 1525 }
 1526
 1527 hwhdr->frmlen = le16toh(hwhdr->frmlen);
 1528 hwhdr->cksum = le16toh(hwhdr->cksum);
 1529
 1530 if (hwhdr->frmlen == 0 && hwhdr->cksum == 0)
 1531 break;
 1532
 1533 if ((hwhdr->frmlen ^ hwhdr->cksum) != 0xffff) {
 1534 printf("%s: checksum error\n", DEVNAME(sc));
 1535 break;
 1536 }
 1537
 1538 if (hwhdr->frmlen < sizeof(*hwhdr) + sizeof(*swhdr)) {
 1539 printf("%s: length error\n", DEVNAME(sc));
 1540 break;
 1541 }
 1542
 1543 if (nextlen && hwhdr->frmlen > nextlen) {
 1544 printf("%s: read ahead length error (%u > %u)\n",
 1545 DEVNAME(sc), hwhdr->frmlen, nextlen);
 1546 break;
 1547 }
451 1548
452 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 1549 sc->sc_tx_max_seq = swhdr->maxseqnr;
453 1550
454 return ret; 1551 flen = hwhdr->frmlen - (sizeof(*hwhdr) + sizeof(*swhdr));
 1552 if (flen == 0) {
 1553 nextlen = swhdr->nextlen << 4;
 1554 continue;
 1555 }
 1556
 1557 if (!nextlen) {
 1558 KASSERT(roundup(flen, 4) <= sc->sc_bounce_size -
 1559 (sizeof(*hwhdr) + sizeof(*swhdr)));
 1560 if (bwfm_sdio_frame_read_write(sc, data,
 1561 roundup(flen, 4), 0))
 1562 break;
 1563 }
 1564
 1565 if (swhdr->dataoff < (sizeof(*hwhdr) + sizeof(*swhdr))) {
 1566 printf("%s: data offset %u in header\n",
 1567 DEVNAME(sc), swhdr->dataoff);
 1568 break;
 1569 }
 1570
 1571 off = swhdr->dataoff - (sizeof(*hwhdr) + sizeof(*swhdr));
 1572 if (off > flen) {
 1573 printf("%s: offset %zu beyond end %zu\n",
 1574 DEVNAME(sc), off, flen);
 1575 break;
 1576 }
 1577
 1578 switch (swhdr->chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
 1579 case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
 1580 m = bwfm_sdio_newbuf();
 1581 if (m == NULL)
 1582 break;
 1583 if (flen - off > m->m_len) {
 1584 printf("%s: ctl bigger than anticipated\n",
 1585 DEVNAME(sc));
 1586 m_freem(m);
 1587 break;
 1588 }
 1589 m->m_len = m->m_pkthdr.len = flen - off;
 1590 memcpy(mtod(m, char *), data + off, flen - off);
 1591 bwfm_qput(&sc->sc_rxctl_queue, m);
 1592 cv_broadcast(&sc->sc_rxctl_cv);
 1593 nextlen = swhdr->nextlen << 4;
 1594 break;
 1595 case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
 1596 case BWFM_SDIO_SWHDR_CHANNEL_DATA:
 1597 m = bwfm_sdio_newbuf();
 1598 if (m == NULL)
 1599 break;
 1600 if (flen - off > m->m_len) {
 1601 printf("%s: frame bigger than anticipated\n",
 1602 DEVNAME(sc));
 1603 m_freem(m);
 1604 break;
 1605 }
 1606 m->m_len = m->m_pkthdr.len = flen - off;
 1607 memcpy(mtod(m, char *), data + off, flen - off);
 1608 bcdc = mtod(m, struct bwfm_proto_bcdc_hdr *);
 1609 hoff = sizeof(*bcdc) + ((size_t)bcdc->data_offset << 2);
 1610 if (m->m_len < hoff) {
 1611 printf("%s: short bcdc packet %d < %zu\n",
 1612 DEVNAME(sc), m->m_len, hoff);
 1613 m_freem(m);
 1614 break;
 1615 }
 1616 m_adj(m, hoff);
 1617 bwfm_rx(&sc->sc_sc, m);
 1618 nextlen = swhdr->nextlen << 4;
 1619 break;
 1620 case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
 1621 if ((flen % sizeof(uint16_t)) != 0) {
 1622 printf("%s: odd length (%zu) glom table\n",
 1623 DEVNAME(sc), flen);
 1624 break;
 1625 }
 1626 nsub = flen / sizeof(uint16_t);
 1627 sublen = kmem_zalloc(nsub * sizeof(uint16_t), KM_SLEEP);
 1628 memcpy(sublen, data, nsub * sizeof(uint16_t));
 1629 bwfm_sdio_rx_glom(sc, sublen, nsub, &nextlen);
 1630 kmem_free(sublen, nsub * sizeof(uint16_t));
 1631 break;
 1632 default:
 1633 printf("%s: unknown channel\n", DEVNAME(sc));
 1634 break;
 1635 }
 1636 }
455} 1637}
 1638
 1639void
 1640bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub,
 1641 uint16_t *nextlen)
 1642{
 1643 struct bwfm_sdio_hwhdr hwhdr;
 1644 struct bwfm_sdio_swhdr swhdr;
 1645 struct bwfm_proto_bcdc_hdr *bcdc;
 1646 struct mbuf *m, *m0;
 1647 size_t flen, off, hoff;
 1648 int i;
 1649
 1650 if (nsub == 0)
 1651 return;
 1652
 1653 m0 = NULL;
 1654 for (i = 0; i < nsub; i++) {
 1655 m = bwfm_sdio_newbuf();
 1656 if (m == NULL) {
 1657 m_freem(m0);
 1658 return;
 1659 }
 1660 bwfm_qput(&m0, m);
 1661 if (le16toh(sublen[i]) > m->m_len) {
 1662 m_freem(m0);
 1663 return;
 1664 }
 1665 if (bwfm_sdio_frame_read_write(sc, mtod(m, char *),
 1666 le16toh(sublen[i]), 0)) {
 1667 m_freem(m0);
 1668 return;
 1669 }
 1670 m->m_len = m->m_pkthdr.len = le16toh(sublen[i]);
 1671 }
 1672
 1673 if (m0->m_len >= sizeof(hwhdr) + sizeof(swhdr)) {
 1674 m_copydata(m0, 0, sizeof(hwhdr), &hwhdr);
 1675 m_copydata(m0, sizeof(hwhdr), sizeof(swhdr), &swhdr);
 1676
 1677 /* TODO: Verify actual superframe header */
 1678
 1679 /* remove superframe header */
 1680 if (m0->m_len >= swhdr.dataoff)
 1681 m_adj(m0, swhdr.dataoff);
 1682 }
 1683
 1684 *nextlen = 0;
 1685 while ((m = bwfm_qget(&m0)) != NULL) {
 1686 if (m->m_len < sizeof(hwhdr) + sizeof(swhdr)) {
 1687 printf("%s: tiny mbuf %d < %zu\n", DEVNAME(sc),
 1688 m->m_len, sizeof(hwhdr) + sizeof(swhdr));
 1689 goto drop;
 1690 }
 1691
 1692 m_copydata(m, 0, sizeof(hwhdr), &hwhdr);
 1693 m_copydata(m, sizeof(hwhdr), sizeof(swhdr), &swhdr);
 1694
 1695 hwhdr.frmlen = le16toh(hwhdr.frmlen);
 1696 hwhdr.cksum = le16toh(hwhdr.cksum);
 1697
 1698 if (hwhdr.frmlen == 0 && hwhdr.cksum == 0)
 1699 goto drop;
 1700
 1701 if ((hwhdr.frmlen ^ hwhdr.cksum) != 0xffff) {
 1702 printf("%s: checksum error\n", DEVNAME(sc));
 1703 goto drop;
 1704 }
 1705
 1706
 1707 if (hwhdr.frmlen < sizeof(hwhdr) + sizeof(swhdr)) {
 1708 printf("%s: length error\n", DEVNAME(sc));
 1709 goto drop;
 1710 }
 1711
 1712 flen = hwhdr.frmlen - (sizeof(hwhdr) + sizeof(swhdr));
 1713 if (flen == 0)
 1714 goto drop;
 1715
 1716 if (hwhdr.frmlen > m->m_len) {
 1717 printf("%s: short mbuf %d < %zu\n",
 1718 DEVNAME(sc),m->m_len,flen);
 1719 goto drop;
 1720 }
 1721
 1722 if (swhdr.dataoff < (sizeof(hwhdr) + sizeof(swhdr))) {
 1723 printf("%s: data offset %u in header\n",
 1724 DEVNAME(sc), swhdr.dataoff);
 1725 goto drop;
 1726 }
 1727
 1728 off = swhdr.dataoff - (sizeof(hwhdr) + sizeof(swhdr));
 1729 if (off > flen) {
 1730 printf("%s: offset %zu beyond end %zu\n",
 1731 DEVNAME(sc), off, flen);
 1732 goto drop;
 1733 }
 1734
 1735 m_adj(m, (int)hwhdr.frmlen - m->m_len);
 1736 *nextlen = swhdr.nextlen << 4;
 1737
 1738 switch (swhdr.chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
 1739 case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
 1740 printf("%s: control channel not allowed in glom\n",
 1741 DEVNAME(sc));
 1742 goto drop;
 1743 case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
 1744 case BWFM_SDIO_SWHDR_CHANNEL_DATA:
 1745 m_adj(m, swhdr.dataoff);
 1746 bcdc = mtod(m, struct bwfm_proto_bcdc_hdr *);
 1747 hoff = sizeof(*bcdc) + ((size_t)bcdc->data_offset << 2);
 1748 if (m->m_len < hoff) {
 1749 printf("%s: short bcdc packet %d < %zu\n",
 1750 DEVNAME(sc), m->m_len, hoff);
 1751 m_freem(m);
 1752 break;
 1753 }
 1754 m_adj(m, hoff);
 1755 bwfm_rx(&sc->sc_sc, m);
 1756 break;
 1757 case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
 1758 printf("%s: glom not allowed in glom\n",
 1759 DEVNAME(sc));
 1760 goto drop;
 1761 default:
 1762 printf("%s: unknown channel\n", DEVNAME(sc));
 1763 goto drop;
 1764 }
 1765
 1766 continue;
 1767drop:
 1768 printf("rx dropped %p len %d\n",mtod(m, char *),m->m_pkthdr.len);
 1769 m_free(m);
 1770 }
 1771}
 1772
 1773#ifdef BWFM_DEBUG
 1774void
 1775bwfm_sdio_debug_console(struct bwfm_sdio_softc *sc)
 1776{
 1777 struct bwfm_sdio_console c;
 1778 uint32_t newidx;
 1779 int err;
 1780
 1781 if (!sc->sc_console_addr)
 1782 return;
 1783
 1784 err = bwfm_sdio_ram_read_write(sc, sc->sc_console_addr,
 1785 (char *)&c, sizeof(c), 0);
 1786 if (err)
 1787 return;
 1788
 1789 c.log_buf = le32toh(c.log_buf);
 1790 c.log_bufsz = le32toh(c.log_bufsz);
 1791 c.log_idx = le32toh(c.log_idx);
 1792
 1793 if (sc->sc_console_buf == NULL) {
 1794 sc->sc_console_buf = malloc(c.log_bufsz, M_DEVBUF,
 1795 M_WAITOK|M_ZERO);
 1796 sc->sc_console_buf_size = c.log_bufsz;
 1797 }
 1798
 1799 newidx = c.log_idx;
 1800 if (newidx >= sc->sc_console_buf_size)
 1801 return;
 1802
 1803 err = bwfm_sdio_ram_read_write(sc, c.log_buf, sc->sc_console_buf,
 1804 sc->sc_console_buf_size, 0);
 1805 if (err)
 1806 return;
 1807
 1808 if (newidx != sc->sc_console_readidx)
 1809 DPRINTFN(3, ("BWFM CONSOLE: "));
 1810 while (newidx != sc->sc_console_readidx) {
 1811 uint8_t ch = sc->sc_console_buf[sc->sc_console_readidx];
 1812 sc->sc_console_readidx++;
 1813 if (sc->sc_console_readidx == sc->sc_console_buf_size)
 1814 sc->sc_console_readidx = 0;
 1815 if (ch == '\r')
 1816 continue;
 1817 DPRINTFN(3, ("%c", ch));
 1818 }
 1819}
 1820#endif

File Added: src/sys/dev/sdmmc/if_bwfm_sdio.h
/*	$OpenBSD: if_bwfm_sdio.h,v 1.2 2018/05/19 10:43:10 patrick Exp $	*/
/*
 * Copyright (c) 2010-2016 Broadcom Corporation
 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Registers */
#define BWFM_SDIO_CCCR_CARDCAP			0xf0
#define  BWFM_SDIO_CCCR_CARDCAP_CMD14_SUPPORT		(1 << 1)
#define  BWFM_SDIO_CCCR_CARDCAP_CMD14_EXT		(1 << 2)
#define  BWFM_SDIO_CCCR_CARDCAP_CMD_NODEC		(1 << 3)
#define BWFM_SDIO_CCCR_CARDCTRL			0xf1
#define  BWFM_SDIO_CCCR_CARDCTRL_WLANRESET		(1 << 1)
#define BWFM_SDIO_CCCR_SEPINT			0xf2
#define  BWFM_SDIO_CCCR_SEPINT_MASK			0x01
#define  BWFM_SDIO_CCCR_SEPINT_OE			(1 << 1)
#define  BWFM_SDIO_CCCR_SEPINT_ACT_HI			(1 << 2)

#define BWFM_SDIO_WATERMARK			0x10008
#define BWFM_SDIO_DEVICE_CTL			0x10009
#define  BWFM_SDIO_DEVICE_CTL_SETBUSY				0x01
#define  BWFM_SDIO_DEVICE_CTL_SPI_INTR_SYNC			0x02
#define  BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY			0x04
#define  BWFM_SDIO_DEVICE_CTL_PADS_ISO				0x08
#define  BWFM_SDIO_DEVICE_CTL_SB_RST_CTL			0x30
#define  BWFM_SDIO_DEVICE_CTL_RST_CORECTL			0x00
#define  BWFM_SDIO_DEVICE_CTL_RST_BPRESET			0x10
#define  BWFM_SDIO_DEVICE_CTL_RST_NOBPRESET			0x20
#define BWFM_SDIO_FUNC1_SBADDRLOW		0x1000A
#define BWFM_SDIO_FUNC1_SBADDRMID		0x1000B
#define BWFM_SDIO_FUNC1_SBADDRHIGH		0x1000C
#define BWFM_SDIO_FUNC1_CHIPCLKCSR		0x1000E
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP			0x01
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT			0x02
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ILP			0x04
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ		0x08
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL_REQ		0x10
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF		0x20
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL			0x40
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL			0x80
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_CSR_MASK			0x1F
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_AVBITS				\
		(BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL | \
		 BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL)
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_ALPAV(regval)			\
		((regval) & BWFM_SDIO_FUNC1_CHIPCLKCSR_AVBITS)
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(regval)			\
		(((regval) & BWFM_SDIO_FUNC1_CHIPCLKCSR_AVBITS) == BWFM_SDIO_FUNC1_CHIPCLKCSR_AVBITS)
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_ALPONLY(regval)			\
		(BWFM_SDIO_FUNC1_CHIPCLKCSR_ALPAV(regval) && \
		 !BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(regval))
#define  BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(regval, alponly) \
		(BWFM_SDIO_FUNC1_CHIPCLKCSR_ALPAV(regval) && \
		 (alponly ? 1 : BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(regval)))
#define BWFM_SDIO_FUNC1_SDIOPULLUP		0x1000F
#define BWFM_SDIO_FUNC1_WAKEUPCTRL		0x1001E
#define  BWFM_SDIO_FUNC1_WAKEUPCTRL_HTWAIT		(1 << 1)
#define BWFM_SDIO_FUNC1_SLEEPCSR		0x1001F
#define  BWFM_SDIO_FUNC1_SLEEPCSR_KSO		(1 << 0)
#define  BWFM_SDIO_FUNC1_SLEEPCSR_DEVON		(1 << 2)

#define BWFM_SDIO_SB_OFT_ADDR_PAGE		0x08000
#define BWFM_SDIO_SB_OFT_ADDR_MASK		0x07FFF
#define BWFM_SDIO_SB_ACCESS_2_4B_FLAG		0x08000

/* Protocol defines */
#define SDPCM_PROT_VERSION			4
#define SDPCM_PROT_VERSION_SHIFT		16
#define SDPCM_PROT_VERSION_MASK			0x00ff0000
#define SDPCM_SHARED_VERSION			0x0003
#define SDPCM_SHARED_VERSION_MASK		0x00FF
#define SDPCM_SHARED_ASSERT_BUILT		0x0100
#define SDPCM_SHARED_ASSERT			0x0200
#define SDPCM_SHARED_TRAP			0x0400

#define SDPCMD_INTSTATUS			0x020
#define  SDPCMD_INTSTATUS_SMB_SW0			(1 << 0) /* To SB Mail S/W interrupt 0 */
#define  SDPCMD_INTSTATUS_SMB_SW1			(1 << 1) /* To SB Mail S/W interrupt 1 */
#define  SDPCMD_INTSTATUS_SMB_SW2			(1 << 2) /* To SB Mail S/W interrupt 2 */
#define  SDPCMD_INTSTATUS_SMB_SW3			(1 << 3) /* To SB Mail S/W interrupt 3 */
#define  SDPCMD_INTSTATUS_SMB_SW_MASK			0x0000000f /* To SB Mail S/W interrupts mask */
#define  SDPCMD_INTSTATUS_SMB_SW_SHIFT			0	 /* To SB Mail S/W interrupts shift */
#define  SDPCMD_INTSTATUS_HMB_SW0			(1 << 4) /* To Host Mail S/W interrupt 0 */
#define  SDPCMD_INTSTATUS_HMB_SW1			(1 << 5) /* To Host Mail S/W interrupt 1 */
#define  SDPCMD_INTSTATUS_HMB_SW2			(1 << 6) /* To Host Mail S/W interrupt 2 */
#define  SDPCMD_INTSTATUS_HMB_SW3			(1 << 7) /* To Host Mail S/W interrupt 3 */
#define  SDPCMD_INTSTATUS_HMB_FC_STATE			SDPCMD_INTSTATUS_HMB_SW0
#define  SDPCMD_INTSTATUS_HMB_FC_CHANGE			SDPCMD_INTSTATUS_HMB_SW1
#define  SDPCMD_INTSTATUS_HMB_FRAME_IND			SDPCMD_INTSTATUS_HMB_SW2
#define  SDPCMD_INTSTATUS_HMB_HOST_INT			SDPCMD_INTSTATUS_HMB_SW3
#define  SDPCMD_INTSTATUS_HMB_SW_MASK			0x000000f0 /* To Host Mail S/W interrupts mask */
#define  SDPCMD_INTSTATUS_HMB_SW_SHIFT			4	 /* To Host Mail S/W interrupts shift */
#define  SDPCMD_INTSTATUS_WR_OOSYNC			(1 << 8) /* Write Frame Out Of Sync */
#define  SDPCMD_INTSTATUS_RD_OOSYNC			(1 << 9) /* Read Frame Out Of Sync */
#define  SDPCMD_INTSTATUS_PC				(1 << 10)/* descriptor error */
#define  SDPCMD_INTSTATUS_PD				(1 << 11)/* data error */
#define  SDPCMD_INTSTATUS_DE				(1 << 12)/* Descriptor protocol Error */
#define  SDPCMD_INTSTATUS_RU				(1 << 13)/* Receive descriptor Underflow */
#define  SDPCMD_INTSTATUS_RO				(1 << 14)/* Receive fifo Overflow */
#define  SDPCMD_INTSTATUS_XU				(1 << 15)/* Transmit fifo Underflow */
#define  SDPCMD_INTSTATUS_RI				(1 << 16)/* Receive Interrupt */
#define  SDPCMD_INTSTATUS_BUSPWR			(1 << 17)/* SDIO Bus Power Change (rev 9) */
#define  SDPCMD_INTSTATUS_XMTDATA_AVAIL			(1 << 23)/* bits in fifo */
#define  SDPCMD_INTSTATUS_XI				(1 << 24)/* Transmit Interrupt */
#define  SDPCMD_INTSTATUS_RF_TERM			(1 << 25)/* Read Frame Terminate */
#define  SDPCMD_INTSTATUS_WF_TERM			(1 << 26)/* Write Frame Terminate */
#define  SDPCMD_INTSTATUS_PCMCIA_XU			(1 << 27)/* PCMCIA Transmit FIFO Underflow */
#define  SDPCMD_INTSTATUS_SBINT				(1 << 28)/* sbintstatus Interrupt */
#define  SDPCMD_INTSTATUS_CHIPACTIVE			(1 << 29)/* chip from doze to active state */
#define  SDPCMD_INTSTATUS_SRESET			(1 << 30)/* CCCR RES interrupt */
#define  SDPCMD_INTSTATUS_IOE2				(1U << 31)/* CCCR IOE2 Bit Changed */
#define  SDPCMD_INTSTATUS_ERRORS			(SDPCMD_INTSTATUS_PC | \
							 SDPCMD_INTSTATUS_PD | \
							 SDPCMD_INTSTATUS_DE | \
							 SDPCMD_INTSTATUS_RU | \
							 SDPCMD_INTSTATUS_RO | \
							 SDPCMD_INTSTATUS_XU)
#define  SDPCMD_INTSTATUS_DMA				(SDPCMD_INTSTATUS_RI | \
							 SDPCMD_INTSTATUS_XI | \
							 SDPCMD_INTSTATUS_ERRORS)
#define SDPCMD_HOSTINTMASK			0x024
#define SDPCMD_INTMASK				0x028
#define SDPCMD_SBINTSTATUS			0x02c
#define SDPCMD_SBINTMASK			0x030
#define SDPCMD_FUNCTINTMASK			0x034
#define SDPCMD_TOSBMAILBOX			0x040
#define  SDPCMD_TOSBMAILBOX_NAK				(1 << 0)
#define  SDPCMD_TOSBMAILBOX_INT_ACK			(1 << 1)
#define  SDPCMD_TOSBMAILBOX_USE_OOB			(1 << 2)
#define  SDPCMD_TOSBMAILBOX_DEV_INT			(1 << 3)
#define SDPCMD_TOHOSTMAILBOX			0x044
#define SDPCMD_TOSBMAILBOXDATA			0x048
#define SDPCMD_TOHOSTMAILBOXDATA		0x04C
#define  SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED		(1 << 0)
#define  SDPCMD_TOHOSTMAILBOXDATA_DEVREADY		(1 << 1)
#define  SDPCMD_TOHOSTMAILBOXDATA_FC			(1 << 2)
#define  SDPCMD_TOHOSTMAILBOXDATA_FWREADY		(1 << 3)
#define  SDPCMD_TOHOSTMAILBOXDATA_FWHALT		(1 << 4)

struct bwfm_sdio_hwhdr {
	uint16_t frmlen;
	uint16_t cksum;
};

struct bwfm_sdio_hwexthdr {
	uint16_t pktlen;
	uint8_t res0;
	uint8_t flags;
	uint16_t res1;
	uint16_t padlen;
};

struct bwfm_sdio_swhdr {
	uint8_t seqnr;
	uint8_t chanflag; /* channel + flag */
#define BWFM_SDIO_SWHDR_CHANNEL_CONTROL		0x00
#define BWFM_SDIO_SWHDR_CHANNEL_EVENT		0x01
#define BWFM_SDIO_SWHDR_CHANNEL_DATA		0x02
#define BWFM_SDIO_SWHDR_CHANNEL_GLOM		0x03
#define BWFM_SDIO_SWHDR_CHANNEL_TEST		0x0F
#define BWFM_SDIO_SWHDR_CHANNEL_MASK		0x0F
	uint8_t nextlen;
	uint8_t dataoff;
	uint8_t flowctl;
	uint8_t maxseqnr;
	uint16_t res0;
};

struct bwfm_sdio_sdpcm {
	uint32_t flags;
	uint32_t trap_addr;
	uint32_t assert_exp_addr;
	uint32_t assert_file_addr;
	uint32_t assert_line;
	uint32_t console_addr;
	uint32_t msgtrace_addr;
	uint8_t tag[32];
	uint32_t brpt_addr;
};

struct bwfm_sdio_console {
	uint32_t vcons_in;
	uint32_t vcons_out;
	uint32_t log_buf;
	uint32_t log_bufsz;
	uint32_t log_idx;
};