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