Index: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m =================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m +++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m @@ -65,15 +65,6 @@ } /** - * Return the preferred NVRAM data source. - * - * @param dev A bhnd(4) ChipCommon device. - */ -METHOD bhnd_nvram_src_t nvram_src { - device_t dev; -} - -/** * Write @p value with @p mask directly to the chipctrl register. * * @param dev A bhnd(4) ChipCommon device. @@ -103,7 +94,7 @@ } DEFAULT bhnd_chipc_generic_get_caps; /** - * Enable hardware access to the SPROM. + * Enable hardware access to the SPROM/OTP source. * * @param sc chipc driver state. * @@ -116,7 +107,7 @@ } /** - * Release hardware access to the SPROM. + * Release hardware access to the SPROM/OTP source. * * @param sc chipc driver state. */ Index: head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c +++ head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c @@ -48,12 +48,19 @@ #include "bhnd_nvram_if.h" -#include "chipc.h" +#include "chipcvar.h" +#include "chipc_private.h" + +#define CHIPC_VALID_SPROM_SRC(_src) \ + ((_src) == BHND_NVRAM_SRC_SPROM || (_src) == BHND_NVRAM_SRC_OTP) static void chipc_sprom_identify(driver_t *driver, device_t parent) { - if (bhnd_chipc_nvram_src(parent) != BHND_NVRAM_SRC_SPROM) + struct chipc_caps *caps; + + caps = BHND_CHIPC_GET_CAPS(parent); + if (!CHIPC_VALID_SPROM_SRC(caps->nvram_src)) return; if (device_find_child(parent, "bhnd_nvram", 0) != NULL) @@ -66,13 +73,15 @@ static int chipc_sprom_probe(device_t dev) { - device_t chipc; - int error; + struct chipc_caps *caps; + device_t chipc; + int error; chipc = device_get_parent(dev); + caps = BHND_CHIPC_GET_CAPS(chipc); - /* Only match on SPROM devices */ - if (BHND_CHIPC_NVRAM_SRC(chipc) != BHND_NVRAM_SRC_SPROM) + /* Only match on SPROM/OTP devices */ + if (!CHIPC_VALID_SPROM_SRC(caps->nvram_src)) return (ENXIO); /* Defer to default driver implementation */ @@ -85,16 +94,19 @@ static int chipc_sprom_attach(device_t dev) { - device_t chipc; - int error; + struct chipc_caps *caps; + device_t chipc; + int error; + + chipc = device_get_parent(dev); + caps = BHND_CHIPC_GET_CAPS(chipc); /* Request that ChipCommon enable access to SPROM hardware before * delegating attachment (and SPROM parsing) to the common driver */ - chipc = device_get_parent(dev); if ((error = BHND_CHIPC_ENABLE_SPROM(chipc))) return (error); - error = bhnd_sprom_attach(dev); + error = bhnd_sprom_attach(dev, caps->sprom_offset); BHND_CHIPC_DISABLE_SPROM(chipc); return (error); } Index: head/sys/dev/bhnd/cores/chipc/chipc.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.h +++ head/sys/dev/bhnd/cores/chipc/chipc.h @@ -37,15 +37,4 @@ #include "bhnd_chipc_if.h" -/** - * Query a ChipCommon device and return the preferred NVRAM data source. - * - * @param dev A bhnd(4) ChipCommon device. - */ -static inline bhnd_nvram_src_t -bhnd_chipc_nvram_src(device_t dev) -{ - return (BHND_CHIPC_NVRAM_SRC(dev)); -} - #endif /* _BHND_CORES_CHIPC_CHIPC_H_ */ Index: head/sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c +++ head/sys/dev/bhnd/cores/chipc/chipc.c @@ -91,10 +91,18 @@ /* Device quirks table */ static struct bhnd_device_quirk chipc_quirks[] = { - /* core revision quirks */ + /* HND OTP controller revisions */ + BHND_CORE_QUIRK (HWREV_EQ (12), CHIPC_QUIRK_OTP_HND), /* (?) */ + BHND_CORE_QUIRK (HWREV_EQ (17), CHIPC_QUIRK_OTP_HND), /* BCM4311 */ + BHND_CORE_QUIRK (HWREV_EQ (22), CHIPC_QUIRK_OTP_HND), /* BCM4312 */ + + /* IPX OTP controller revisions */ + BHND_CORE_QUIRK (HWREV_EQ (21), CHIPC_QUIRK_OTP_IPX), + BHND_CORE_QUIRK (HWREV_GTE(23), CHIPC_QUIRK_OTP_IPX), + BHND_CORE_QUIRK (HWREV_GTE(32), CHIPC_QUIRK_SUPPORTS_SPROM), BHND_CORE_QUIRK (HWREV_GTE(35), CHIPC_QUIRK_SUPPORTS_CAP_EXT), - BHND_CORE_QUIRK (HWREV_GTE(49), CHIPC_QUIRK_IPX_OTPLAYOUT_SIZE), + BHND_CORE_QUIRK (HWREV_GTE(49), CHIPC_QUIRK_IPX_OTPL_SIZE), /* 4706 variant quirks */ BHND_CORE_QUIRK (HWREV_EQ (38), CHIPC_QUIRK_4706_NFLASH), /* BCM5357? */ @@ -159,10 +167,11 @@ int type, int rid, struct resource *r, bool req_direct); +static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc, + struct chipc_caps *caps); static int chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps); -static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc); static bool chipc_should_enable_sprom( struct chipc_softc *sc); @@ -265,9 +274,6 @@ if (bootverbose) chipc_print_caps(sc->dev, &sc->caps); - /* Identify NVRAM source */ - sc->nvram_src = chipc_nvram_identify(sc); - /* Probe and attach children */ bus_generic_probe(dev); if ((error = bus_generic_attach(dev))) @@ -305,6 +311,60 @@ return (0); } +/** + * Determine the NVRAM data source for this device. + * + * The SPROM, OTP, and flash capability flags must be fully populated in + * @p caps. + * + * @param sc chipc driver state. + * @param caps capability flags to be used to derive NVRAM configuration. + */ +static bhnd_nvram_src +chipc_find_nvram_src(struct chipc_softc *sc, struct chipc_caps *caps) +{ + uint32_t otp_st, srom_ctrl; + + /* Very early devices vend SPROM/OTP/CIS (if at all) via the + * host bridge interface instead of ChipCommon. */ + if (!CHIPC_QUIRK(sc, SUPPORTS_SPROM)) + return (BHND_NVRAM_SRC_UNKNOWN); + + /* + * Later chipset revisions standardized the SPROM capability flags and + * register interfaces. + * + * We check for hardware presence in order of precedence. For example, + * SPROM is is always used in preference to internal OTP if found. + */ + if (caps->sprom) { + srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); + if (srom_ctrl & CHIPC_SRC_PRESENT) + return (BHND_NVRAM_SRC_SPROM); + } + + /* Check for programmed OTP H/W subregion (contains SROM data) */ + if (CHIPC_QUIRK(sc, SUPPORTS_OTP) && caps->otp_size > 0) { + /* TODO: need access to HND-OTP device */ + if (!CHIPC_QUIRK(sc, OTP_HND)) { + device_printf(sc->dev, + "NVRAM unavailable: unsupported OTP controller.\n"); + return (BHND_NVRAM_SRC_UNKNOWN); + } + + otp_st = bhnd_bus_read_4(sc->core, CHIPC_OTPST); + if (otp_st & CHIPC_OTPS_GUP_HW) + return (BHND_NVRAM_SRC_OTP); + } + + /* Check for flash */ + if (caps->flash_type != CHIPC_FLASH_NONE) + return (BHND_NVRAM_SRC_FLASH); + + /* No NVRAM hardware capability declared */ + return (BHND_NVRAM_SRC_UNKNOWN); +} + /* Read and parse chipc capabilities */ static int chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps) @@ -342,7 +402,7 @@ caps->aob = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_AOB); /* Fetch OTP size for later IPX controller revisions */ - if (CHIPC_QUIRK(sc, IPX_OTPLAYOUT_SIZE)) { + if (CHIPC_QUIRK(sc, IPX_OTPL_SIZE)) { regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT); caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE); } @@ -384,47 +444,26 @@ caps->flash_type = CHIPC_NFLASH_4706; } - return (0); -} -/** - * Determine the NVRAM data source for this device. - * - * @param sc chipc driver state. - */ -static bhnd_nvram_src_t -chipc_nvram_identify(struct chipc_softc *sc) -{ - uint32_t srom_ctrl; + /* Determine NVRAM source. Must occur after the SPROM/OTP/flash + * capability flags have been populated. */ + caps->nvram_src = chipc_find_nvram_src(sc, caps); + + /* Determine the SPROM offset within OTP (if any). SPROM-formatted + * data is placed within the OTP general use region. */ + caps->sprom_offset = 0; + if (caps->nvram_src == BHND_NVRAM_SRC_OTP) { + CHIPC_ASSERT_QUIRK(sc, OTP_IPX); - /* Very early devices vend SPROM/OTP/CIS (if at all) via the - * host bridge interface instead of ChipCommon. */ - if (!CHIPC_QUIRK(sc, SUPPORTS_SPROM)) - return (BHND_NVRAM_SRC_UNKNOWN); + /* Bit offset to GUP HW subregion containing SPROM data */ + regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT); + caps->sprom_offset = CHIPC_GET_BITS(regval, CHIPC_OTPL_GUP); - /* - * Later chipset revisions standardized the SPROM capability flags and - * register interfaces. - * - * We check for hardware presence in order of precedence. For example, - * SPROM is is always used in preference to internal OTP if found. - */ - if (CHIPC_CAP(sc, sprom)) { - srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); - if (srom_ctrl & CHIPC_SRC_PRESENT) - return (BHND_NVRAM_SRC_SPROM); + /* Convert to bytes */ + caps->sprom_offset /= 8; } - /* Check for OTP */ - if (CHIPC_CAP(sc, otp_size) != 0) - return (BHND_NVRAM_SRC_OTP); - - /* Check for flash */ - if (CHIPC_CAP(sc, flash_type) != CHIPC_FLASH_NONE) - return (BHND_NVRAM_SRC_FLASH); - - /* No NVRAM hardware capability declared */ - return (BHND_NVRAM_SRC_UNKNOWN); + return (0); } static int @@ -1284,13 +1323,6 @@ CHIPC_UNLOCK(sc); } -static bhnd_nvram_src_t -chipc_nvram_src(device_t dev) -{ - struct chipc_softc *sc = device_get_softc(dev); - return (sc->nvram_src); -} - static void chipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask) { @@ -1363,7 +1395,6 @@ DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource), /* ChipCommon interface */ - DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src), DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl), DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins), DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins), Index: head/sys/dev/bhnd/cores/chipc/chipcreg.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipcreg.h +++ head/sys/dev/bhnd/cores/chipc/chipcreg.h @@ -48,7 +48,7 @@ #define CHIPC_OTPST 0x10 /**< otp status */ #define CHIPC_OTPCTRL 0x14 /**< otp control */ #define CHIPC_OTPPROG 0x18 -#define CHIPC_OTPLAYOUT 0x1C /**< otp layout (rev >= 23) */ +#define CHIPC_OTPLAYOUT 0x1C /**< otp layout (IPX OTP) */ #define CHIPC_INTST 0x20 /**< interrupt status */ #define CHIPC_INTM 0x24 /**< interrupt mask */ @@ -339,7 +339,7 @@ #define CHIPC_OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ #define CHIPC_OTPS_RV_MASK 0x0fff0000 -/* Fields in the otpcontrol register in rev >= 21 */ +/* IPX OTP fields in the otpcontrol register */ #define CHIPC_OTPC_PROGSEL 0x00000001 #define CHIPC_OTPC_PCOUNT_MASK 0x0000000e #define CHIPC_OTPC_PCOUNT_SHIFT 1 @@ -350,7 +350,7 @@ #define CHIPC_OTPC_ODM 0x00000800 #define CHIPC_OTPC_PROGEN 0x80000000 -/* Fields in otpprog in rev >= 21 and HND OTP */ +/* Fields in otpprog in IPX OTP and HND OTP */ #define CHIPC_OTPP_COL_MASK 0x000000ff #define CHIPC_OTPP_COL_SHIFT 0 #define CHIPC_OTPP_ROW_MASK 0x0000ff00 @@ -366,6 +366,8 @@ /* otplayout */ #define CHIPC_OTPL_SIZE_MASK 0x0000f000 /* rev >= 49 */ #define CHIPC_OTPL_SIZE_SHIFT 12 +#define CHIPC_OTPL_GUP_MASK 0x00000FFF /* bit offset to general use region */ +#define CHIPC_OTPL_GUP_SHIFT 0 #define CHIPC_OTPL_CISFORMAT_NEW 0x80000000 /* rev >= 36 */ /* Opcodes for OTPP_OC field */ Index: head/sys/dev/bhnd/cores/chipc/chipcvar.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipcvar.h +++ head/sys/dev/bhnd/cores/chipc/chipcvar.h @@ -32,6 +32,9 @@ #ifndef _BHND_CORES_CHIPC_CHIPCVAR_H_ #define _BHND_CORES_CHIPC_CHIPCVAR_H_ +#include +#include + #include #include "chipc.h" @@ -67,8 +70,14 @@ uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */ chipc_flash flash_type; /**< Flash type */ + bhnd_nvram_src nvram_src; /**< identified NVRAM source */ + + bus_size_t sprom_offset; /**< Offset to SPROM data within + SPROM/OTP, 0 if unknown or not + present */ uint8_t otp_size; /**< OTP (row?) size, 0 if not present */ - uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI not present */ + uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI + not present */ uint8_t pll_type; /**< PLL type */ bool power_control; /**< Power control available */ @@ -158,9 +167,21 @@ /** Supports CHIPC_CAPABILITIES_EXT register */ CHIPC_QUIRK_SUPPORTS_CAP_EXT = (1<<6), + /** Supports HND or IPX OTP registers (CHIPC_OTPST, CHIPC_OTPCTRL, + * CHIPC_OTPPROG) */ + CHIPC_QUIRK_SUPPORTS_OTP = (1<<7), + + /** Supports HND OTP registers. */ + CHIPC_QUIRK_OTP_HND = (1<<8) | + CHIPC_QUIRK_SUPPORTS_OTP, + + /** Supports IPX OTP registers. */ + CHIPC_QUIRK_OTP_IPX = (1<<9) | + CHIPC_QUIRK_SUPPORTS_OTP, + /** OTP size is defined via CHIPC_OTPLAYOUT register in later * ChipCommon revisions using the 'IPX' OTP controller. */ - CHIPC_QUIRK_IPX_OTPLAYOUT_SIZE = (1<<7), + CHIPC_QUIRK_IPX_OTPL_SIZE = (1<<10) }; /** @@ -183,8 +204,6 @@ uint32_t quirks; /**< chipc quirk flags */ struct chipc_caps caps; /**< chipc capabilities */ - bhnd_nvram_src_t nvram_src; /**< identified NVRAM source */ - struct mtx mtx; /**< state mutex. */ size_t sprom_refcnt; /**< SPROM pin enable refcount */ struct rman mem_rman; /**< port memory manager */ Index: head/sys/dev/bhnd/nvram/bhnd_nvram.h =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram.h +++ head/sys/dev/bhnd/nvram/bhnd_nvram.h @@ -65,6 +65,6 @@ * is provided by a common platform NVRAM * device. */ -} bhnd_nvram_src_t; +} bhnd_nvram_src; #endif /* _BHND_NVRAM_BHND_NVRAM_H_ */ Index: head/sys/dev/bhnd/nvram/bhnd_sprom.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_sprom.c +++ head/sys/dev/bhnd/nvram/bhnd_sprom.c @@ -71,19 +71,33 @@ /* Quiet by default */ if (!bootverbose) device_quiet(dev); - device_set_desc(dev, "Broadcom SPROM/OTP"); + device_set_desc(dev, "SPROM/OTP"); /* Refuse wildcard attachments */ return (BUS_PROBE_NOWILDCARD); } +/* Default DEVICE_ATTACH() implementation; assumes a zero offset to the + * SPROM data */ +static int +bhnd_sprom_attach_meth(device_t dev) +{ + return (bhnd_sprom_attach(dev, 0)); +} + /** - * Default bhnd sprom driver implementation of DEVICE_ATTACH(). + * BHND SPROM device attach. + * + * This should be called from DEVICE_ATTACH() with the @p offset to the + * SPROM data. * - * Assumes sprom is mapped via YS_RES_MEMORY resource with RID 0. + * Assumes SPROM is mapped via SYS_RES_MEMORY resource with RID 0. + * + * @param dev BHND SPROM device. + * @param offset Offset to the SPROM data. */ int -bhnd_sprom_attach(device_t dev) +bhnd_sprom_attach(device_t dev, bus_size_t offset) { struct bhnd_sprom_softc *sc; int error; @@ -101,10 +115,8 @@ } /* Initialize SPROM shadow */ - if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, 0))) { - device_printf(dev, "unrecognized SPROM format\n"); + if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, offset))) goto failed; - } /* Initialize mutex */ SPROM_LOCK_INIT(sc); @@ -118,7 +130,7 @@ } /** - * Default bhnd sprom driver implementation of DEVICE_DETACH(). + * Default bhnd_sprom implementation of DEVICE_RESUME(). */ int bhnd_sprom_resume(device_t dev) @@ -127,7 +139,7 @@ } /** - * Default bhnd sprom driver implementation of DEVICE_DETACH(). + * Default bhnd sprom driver implementation of DEVICE_SUSPEND(). */ int bhnd_sprom_suspend(device_t dev) @@ -193,7 +205,7 @@ static device_method_t bhnd_sprom_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bhnd_sprom_probe), - DEVMETHOD(device_attach, bhnd_sprom_attach), + DEVMETHOD(device_attach, bhnd_sprom_attach_meth), DEVMETHOD(device_resume, bhnd_sprom_resume), DEVMETHOD(device_suspend, bhnd_sprom_suspend), DEVMETHOD(device_detach, bhnd_sprom_detach), Index: head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c +++ head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c @@ -465,7 +465,7 @@ } /* identification failed */ - device_printf(sc->dev, "unrecognized sprom format\n"); + device_printf(sc->dev, "unrecognized SPROM format\n"); return (EINVAL); } Index: head/sys/dev/bhnd/nvram/bhnd_spromvar.h =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_spromvar.h +++ head/sys/dev/bhnd/nvram/bhnd_spromvar.h @@ -38,7 +38,7 @@ struct bhnd_sprom; int bhnd_sprom_probe(device_t dev); -int bhnd_sprom_attach(device_t dev); +int bhnd_sprom_attach(device_t dev, bus_size_t offset); int bhnd_sprom_resume(device_t dev); int bhnd_sprom_suspend(device_t dev); int bhnd_sprom_detach(device_t dev);