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