Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/sdmmc Add driver for Broadcom 802.11a/b/g/n/ac SDIO ...



details:   https://anonhg.NetBSD.org/src/rev/a8e35e3512ec
branches:  trunk
changeset: 827667:a8e35e3512ec
user:      khorben <khorben%NetBSD.org@localhost>
date:      Tue Nov 07 16:30:32 2017 +0000

description:
Add driver for Broadcom 802.11a/b/g/n/ac SDIO wireless devices, based on
the OpenBSD bwfm(4) driver.

I could not test this on any hardware yet, as it does not attach as-is on
my Raspberry PI 3.

diffstat:

 sys/dev/sdmmc/files.sdmmc    |    6 +-
 sys/dev/sdmmc/if_bwfm_sdio.c |  444 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 449 insertions(+), 1 deletions(-)

diffs (truncated from 465 to 300 lines):

diff -r 870b6d604217 -r a8e35e3512ec sys/dev/sdmmc/files.sdmmc
--- a/sys/dev/sdmmc/files.sdmmc Tue Nov 07 15:57:38 2017 +0000
+++ b/sys/dev/sdmmc/files.sdmmc Tue Nov 07 16:30:32 2017 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.sdmmc,v 1.4 2014/10/02 21:49:22 jmcneill Exp $
+#      $NetBSD: files.sdmmc,v 1.5 2017/11/07 16:30:32 khorben Exp $
 #      $OpenBSD: files.sdmmc,v 1.2 2006/06/01 21:53:41 uwe Exp $
 #
 # Config file and device description for machine-independent SD/MMC code.
@@ -21,3 +21,7 @@
 device sbt: btbus, bluetooth
 attach sbt at sdmmc
 file   dev/sdmmc/sbt.c                 sbt
+
+# Broadcom FullMAC SDIO wireless adapter
+attach bwfm at sdmmc with bwfm_sdio
+file   dev/sdmmc/if_bwfm_sdio.c        bwfm_sdio
diff -r 870b6d604217 -r a8e35e3512ec sys/dev/sdmmc/if_bwfm_sdio.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/sdmmc/if_bwfm_sdio.c      Tue Nov 07 16:30:32 2017 +0000
@@ -0,0 +1,444 @@
+/* $NetBSD: if_bwfm_sdio.c,v 1.1 2017/11/07 16:30:32 khorben Exp $ */
+/* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */
+/*
+ * Copyright (c) 2010-2016 Broadcom Corporation
+ * Copyright (c) 2016,2017 Patrick Wildt <patrick%blueri.se@localhost>
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/mutex.h>
+#include <sys/workqueue.h>
+#include <sys/pcq.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+
+#include <netinet/in.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/sdmmc/sdmmcvar.h>
+
+#include <dev/ic/bwfmvar.h>
+#include <dev/ic/bwfmreg.h>
+
+#define BWFM_SDIO_CCCR_BRCM_CARDCAP                    0xf0
+#define  BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT     0x02
+#define  BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT         0x04
+#define  BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC         0x08
+#define BWFM_SDIO_CCCR_BRCM_CARDCTRL                   0xf1
+#define  BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET                0x02
+#define BWFM_SDIO_CCCR_BRCM_SEPINT                     0xf2
+
+#ifdef BWFM_DEBUG
+#define DPRINTF(x)     do { if (bwfm_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
+static int bwfm_debug = 2;
+#else
+#define DPRINTF(x)     do { ; } while (0)
+#define DPRINTFN(n, x) do { ; } while (0)
+#endif
+
+#define DEVNAME(sc)    device_xname((sc)->sc_sc.sc_dev)
+
+struct bwfm_sdio_softc {
+       struct bwfm_softc         sc_sc;
+       struct sdmmc_function   **sc_sf;
+       uint32_t                  sc_bar0;
+};
+
+int             bwfm_sdio_match(device_t, cfdata_t, void *);
+void            bwfm_sdio_attach(device_t, struct device *, void *);
+int             bwfm_sdio_detach(device_t, int);
+
+uint8_t                 bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t);
+uint32_t        bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t);
+void            bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t,
+                    uint8_t);
+void            bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t,
+                    uint32_t);
+
+uint32_t        bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t);
+void            bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t,
+                    uint32_t);
+int             bwfm_sdio_buscore_prepare(struct bwfm_softc *);
+void            bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
+
+int             bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf *);
+int             bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t);
+int             bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *);
+
+struct bwfm_bus_ops bwfm_sdio_bus_ops = {
+       .bs_init = NULL,
+       .bs_stop = NULL,
+       .bs_txdata = bwfm_sdio_txdata,
+       .bs_txctl = bwfm_sdio_txctl,
+       .bs_rxctl = bwfm_sdio_rxctl,
+};
+
+struct bwfm_buscore_ops bwfm_sdio_buscore_ops = {
+       .bc_read = bwfm_sdio_buscore_read,
+       .bc_write = bwfm_sdio_buscore_write,
+       .bc_prepare = bwfm_sdio_buscore_prepare,
+       .bc_reset = NULL,
+       .bc_setup = NULL,
+       .bc_activate = bwfm_sdio_buscore_activate,
+};
+
+CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc),
+    bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL);
+
+int
+bwfm_sdio_match(device_t parent, cfdata_t match, void *aux)
+{
+       struct sdmmc_attach_args *saa = aux;
+       struct sdmmc_function *sf = saa->sf;
+       struct sdmmc_cis *cis;
+
+       /* Not SDIO. */
+       if (sf == NULL)
+               return 0;
+
+       /* Look for Broadcom 433[04]. */
+       cis = &sf->sc->sc_fn0->cis;
+       if (cis->manufacturer != 0x02d0 || (cis->product != 0x4330 &&
+           cis->product != 0x4334))
+               return 0;
+
+       /* We need both functions, but ... */
+       if (sf->sc->sc_function_count <= 1)
+               return 0;
+
+       /* ... only attach for one. */
+       if (sf->number != 1)
+               return 0;
+
+       return 1;
+}
+
+void
+bwfm_sdio_attach(device_t parent, device_t self, void *aux)
+{
+       struct bwfm_sdio_softc *sc = device_private(self);
+       struct sdmmc_attach_args *saa = aux;
+       struct sdmmc_function *sf = saa->sf;
+       struct bwfm_core *core;
+
+       aprint_naive("\n");
+
+       sc->sc_sf = malloc((sf->sc->sc_function_count + 1) *
+           sizeof(struct sdmmc_function *), M_DEVBUF, M_WAITOK);
+
+       /* Copy all function pointers. */
+       SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) {
+               sc->sc_sf[sf->number] = sf;
+       }
+       sf = saa->sf;
+
+       /*
+        * TODO: set block size to 64 for func 1, 512 for func 2.
+        * We might need to work on the SDMMC stack to be able to set
+        * a block size per function.  Currently the IO code uses the
+        * SDHC controller's maximum block length.
+        */
+
+       /* Enable Function 1. */
+       if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) {
+               aprint_error_dev(self, "cannot enable function 1\n");
+               goto err;
+       }
+
+       DPRINTFN(2, ("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc),
+           bwfm_sdio_read_4(sc, 0x18000000)));
+
+       /* Force PLL off */
+       bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
+           BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
+           BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ);
+
+       sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops;
+       if (bwfm_chip_attach(&sc->sc_sc) != 0) {
+               aprint_error_dev(self, "cannot attach chip\n");
+               goto err;
+       }
+
+       /* TODO: drive strength */
+
+       bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL,
+           bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL) |
+           BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET);
+
+       core = bwfm_chip_get_pmu(&sc->sc_sc);
+       bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL,
+           bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) |
+           (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD <<
+            BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT));
+
+       sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops;
+       sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
+       bwfm_attach(&sc->sc_sc);
+
+       return;
+
+err:
+       free(sc->sc_sf, M_DEVBUF);
+}
+
+int
+bwfm_sdio_detach(struct device *self, int flags)
+{
+       struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self;
+
+       bwfm_detach(&sc->sc_sc, flags);
+
+       free(sc->sc_sf, M_DEVBUF);
+
+       return 0;
+}
+
+uint8_t
+bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr)
+{
+       struct sdmmc_function *sf;
+       uint8_t rv;
+
+       /*
+        * figure out how to read the register based on address range
+        * 0x00 ~ 0x7FF: function 0 CCCR and FBR
+        * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
+        * The rest: function 1 silicon backplane core registers
+        */
+       if ((addr & ~0x7ff) == 0)
+               sf = sc->sc_sf[0];
+       else
+               sf = sc->sc_sf[1];
+
+       rv = sdmmc_io_read_1(sf, addr);
+       return rv;
+}
+
+uint32_t
+bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr)
+{
+       struct sdmmc_function *sf;
+       uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK;
+       uint32_t rv;
+
+       if (sc->sc_bar0 != bar0) {
+               bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW,
+                   (bar0 >>  8) & 0x80);
+               bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID,
+                   (bar0 >> 16) & 0xff);
+               bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH,
+                   (bar0 >> 24) & 0xff);
+               sc->sc_bar0 = bar0;
+       }
+
+       addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
+       addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
+
+       /*
+        * figure out how to read the register based on address range
+        * 0x00 ~ 0x7FF: function 0 CCCR and FBR
+        * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
+        * The rest: function 1 silicon backplane core registers
+        */
+       if ((addr & ~0x7ff) == 0)
+               sf = sc->sc_sf[0];
+       else
+               sf = sc->sc_sf[1];
+
+       rv = sdmmc_io_read_4(sf, addr);
+       return rv;
+}
+
+void
+bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data)
+{



Home | Main Index | Thread Index | Old Index