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