summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2021-02-26 12:34:00 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2021-02-26 12:34:00 +0000
commitc00e49c1fa6b8677b232e45cdc4bed28ee8acee4 (patch)
tree16fcca116a1724103dbfcdc7f1b026f07b654d46 /sys
parent178a87101bf8f0868f13066d96dd7df546f974c5 (diff)
Read and parse OTP on the BCM4378. There are quite a few firmware and
nvram files used for the different Apple devices. The device tree and the OTP hold the information which of those we will have to use. For now this information will simply be printed, but depending on how we choose to do the firmare distribution we could use it for loadfirmware().
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/bwfmreg.h6
-rw-r--r--sys/dev/pci/if_bwfm_pci.c134
2 files changed, 138 insertions, 2 deletions
diff --git a/sys/dev/ic/bwfmreg.h b/sys/dev/ic/bwfmreg.h
index ff0ffc12452..997caf5c3a5 100644
--- a/sys/dev/ic/bwfmreg.h
+++ b/sys/dev/ic/bwfmreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfmreg.h,v 1.20 2021/02/24 10:13:08 patrick Exp $ */
+/* $OpenBSD: bwfmreg.h,v 1.21 2021/02/26 12:33:59 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -90,6 +90,10 @@
#define BWFM_ARMCR4_BANKINFO_BSZ_MULT 8192
#define BWFM_ARMCR4_BANKPDA 0x004C
+/* GCI (OTP) registers */
+#define BWFM_OTP_SIZE 64
+#define BWFM_OTP_4378_BASE 0x1120
+
/* SOCRAM registers */
#define BWFM_SOCRAM_COREINFO 0x0000
#define BWFM_SOCRAM_COREINFO_SRBSZ_BASE 14
diff --git a/sys/dev/pci/if_bwfm_pci.c b/sys/dev/pci/if_bwfm_pci.c
index deb2bfa08e3..96f24c06247 100644
--- a/sys/dev/pci/if_bwfm_pci.c
+++ b/sys/dev/pci/if_bwfm_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bwfm_pci.c,v 1.50 2021/02/26 12:29:36 patrick Exp $ */
+/* $OpenBSD: if_bwfm_pci.c,v 1.51 2021/02/26 12:33:59 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
@@ -27,6 +27,11 @@
#include <sys/queue.h>
#include <sys/socket.h>
+#if defined(__HAVE_FDT)
+#include <machine/fdt.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
#if NBPFILTER > 0
#include <net/bpf.h>
#endif
@@ -197,6 +202,12 @@ int bwfm_pci_match(struct device *, void *, void *);
void bwfm_pci_attach(struct device *, struct device *, void *);
int bwfm_pci_detach(struct device *, int);
+#if defined(__HAVE_FDT)
+int bwfm_pci_read_otp(struct bwfm_pci_softc *);
+void bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t,
+ uint8_t, uint8_t *);
+#endif
+
int bwfm_pci_intr(void *);
void bwfm_pci_intr_enable(struct bwfm_pci_softc *);
void bwfm_pci_intr_disable(struct bwfm_pci_softc *);
@@ -410,6 +421,13 @@ bwfm_pci_preinit(struct bwfm_softc *bwfm)
return 1;
}
+#if defined(__HAVE_FDT)
+ if (bwfm_pci_read_otp(sc)) {
+ printf("%s: cannot read OTP\n", DEVNAME(sc));
+ return 1;
+ }
+#endif
+
bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh,
BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0);
@@ -807,6 +825,120 @@ bwfm_pci_detach(struct device *self, int flags)
return 0;
}
+#if defined(__HAVE_FDT)
+int
+bwfm_pci_read_otp(struct bwfm_pci_softc *sc)
+{
+ struct bwfm_softc *bwfm = (void *)sc;
+ struct bwfm_core *core;
+ uint8_t otp[BWFM_OTP_SIZE];
+ int i;
+
+ if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID)
+ return 0;
+
+ core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_GCI);
+ if (core == NULL)
+ return 1;
+
+ for (i = 0; i < (sizeof(otp) / sizeof(uint32_t)); i++)
+ ((uint32_t *)otp)[i] = bwfm_pci_buscore_read(bwfm,
+ core->co_base + BWFM_OTP_4378_BASE + i * sizeof(uint32_t));
+
+ for (i = 0; i < BWFM_OTP_SIZE - 1; ) {
+ if (otp[i + 0] == 0) {
+ i++;
+ continue;
+ }
+ if (i + otp[i + 1] > BWFM_OTP_SIZE)
+ break;
+ bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1],
+ &otp[i + 2]);
+ i += otp[i + 1];
+ }
+
+ return 0;
+}
+
+void
+bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size,
+ uint8_t *data)
+{
+ struct bwfm_softc *bwfm = (void *)sc;
+ char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = "";
+ char product[16] = "unknown";
+ int node, len;
+
+ switch (type) {
+ case 0x15: /* system vendor OTP */
+ DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc)));
+ if (size < sizeof(uint32_t))
+ return;
+ if (data[0] != 0x08 || data[1] != 0x00 ||
+ data[2] != 0x00 || data[3] != 0x00)
+ return;
+ size -= sizeof(uint32_t);
+ data += sizeof(uint32_t);
+ while (size) {
+ /* reached end */
+ if (data[0] == 0xff)
+ break;
+ for (len = 0; len < size; len++)
+ if (data[len] == 0x00 || data[len] == ' ' ||
+ data[len] == 0xff)
+ break;
+ if (len < 3 || len > 9) /* X=abcdef */
+ goto next;
+ if (data[1] != '=')
+ goto next;
+ /* NULL-terminate string */
+ if (data[len] == ' ')
+ data[len] = '\0';
+ switch (data[0]) {
+ case 's':
+ strlcpy(chiprev, &data[2], sizeof(chiprev));
+ break;
+ case 'M':
+ strlcpy(module, &data[2], sizeof(module));
+ break;
+ case 'm':
+ strlcpy(modrev, &data[2], sizeof(modrev));
+ break;
+ case 'V':
+ strlcpy(vendor, &data[2], sizeof(vendor));
+ break;
+ }
+next:
+ /* skip content */
+ data += len;
+ size -= len;
+ /* skip spacer tag */
+ if (size) {
+ data++;
+ size--;
+ }
+ }
+ snprintf(chip, sizeof(chip),
+ bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x",
+ bwfm->sc_chip.ch_chip);
+ node = OF_finddevice("/chosen");
+ if (node != -1)
+ OF_getprop(node, "module-wlan0", product, sizeof(product));
+ printf("%s: firmware C-%s%s%s/P-%s_M-%s_V-%s__m-%s\n",
+ DEVNAME(sc), chip,
+ *chiprev ? "__s-" : "", *chiprev ? chiprev : "",
+ product, module, vendor, modrev);
+ break;
+ case 0x80: /* Broadcom CIS */
+ DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc)));
+ break;
+ default:
+ DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc)));
+ break;
+ }
+}
+#endif
+
/* DMA code */
struct bwfm_pci_dmamem *
bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align)