xref: /netbsd-src/sys/dev/sdmmc/if_bwfm_sdio.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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@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