From: patrick Date: Fri, 26 Feb 2021 12:33:59 +0000 (+0000) Subject: Read and parse OTP on the BCM4378. There are quite a few firmware and X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ed6d4272d7266bb8145ca2309077cd2b21e76d74;p=openbsd 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(). --- 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 @@ -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 @@ -27,6 +27,11 @@ #include #include +#if defined(__HAVE_FDT) +#include +#include +#endif + #if NBPFILTER > 0 #include #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)