chipc.c revision 296077
150397Sobrien/*- 2107590Sobrien * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 350397Sobrien * All rights reserved. 450397Sobrien * 590075Sobrien * Redistribution and use in source and binary forms, with or without 650397Sobrien * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions and the following disclaimer, 1090075Sobrien * without modification. 1150397Sobrien * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1290075Sobrien * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 1390075Sobrien * redistribution must be conditioned upon including a substantially 1490075Sobrien * similar Disclaimer requirement for further binary redistribution. 1590075Sobrien * 1650397Sobrien * NO WARRANTY 1750397Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1890075Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1990075Sobrien * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 2090075Sobrien * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 2150397Sobrien * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 2250397Sobrien * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2350397Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2450397Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2590075Sobrien * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2690075Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 2790075Sobrien * THE POSSIBILITY OF SUCH DAMAGES. 2850397Sobrien */ 2950397Sobrien 3050397Sobrien#include <sys/cdefs.h> 3190075Sobrien__FBSDID("$FreeBSD: head/sys/dev/bhnd/cores/chipc/chipc.c 296077 2016-02-26 03:34:08Z adrian $"); 3250397Sobrien 3352284Sobrien/* 3450397Sobrien * Broadcom ChipCommon driver. 3590075Sobrien * 3652284Sobrien * With the exception of some very early chipsets, the ChipCommon core 3790075Sobrien * has been included in all HND SoCs and chipsets based on the siba(4) 3890075Sobrien * and bcma(4) interconnects, providing a common interface to chipset 3950397Sobrien * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO, 4052284Sobrien * flash, etc. 4152284Sobrien */ 4290075Sobrien 4390075Sobrien#include <sys/param.h> 4452284Sobrien#include <sys/kernel.h> 4552284Sobrien#include <sys/bus.h> 4652284Sobrien#include <sys/module.h> 4752284Sobrien#include <sys/systm.h> 4852284Sobrien 4952284Sobrien#include <machine/bus.h> 5052284Sobrien#include <sys/rman.h> 5152284Sobrien#include <machine/resource.h> 5252284Sobrien 5352284Sobrien#include <dev/bhnd/bhnd.h> 5452284Sobrien 5552284Sobrien#include "chipcreg.h" 5652284Sobrien#include "chipcvar.h" 5790075Sobrien 5890075Sobriendevclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ 5990075Sobrien 6052284Sobrienstatic const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = { 6190075Sobrien { SYS_RES_MEMORY, 0, RF_ACTIVE }, 6290075Sobrien { -1, -1, 0 } 6390075Sobrien}; 6490075Sobrien 6590075Sobrien/* Supported device identifiers */ 6652284Sobrienstatic const struct chipc_device { 6752284Sobrien uint16_t device; 6852284Sobrien} chipc_devices[] = { 6952284Sobrien { BHND_COREID_CC }, 7090075Sobrien { BHND_COREID_INVALID } 7190075Sobrien}; 7252284Sobrien 7390075Sobrien/* Device quirks table */ 7452284Sobrienstatic struct bhnd_device_quirk chipc_quirks[] = { 7552284Sobrien BHND_QUIRK_HWREV_RANGE (0, 21, CHIPC_QUIRK_ALWAYS_HAS_SPROM), 7690075Sobrien BHND_QUIRK_HWREV_EQ (22, CHIPC_QUIRK_SPROM_CHECK_CST_R22), 7752284Sobrien BHND_QUIRK_HWREV_RANGE (23, 31, CHIPC_QUIRK_SPROM_CHECK_CST_R23), 7852284Sobrien BHND_QUIRK_HWREV_GTE (35, CHIPC_QUIRK_SUPPORTS_NFLASH), 7952284Sobrien BHND_QUIRK_HWREV_END 8052284Sobrien}; 8152284Sobrien 8252284Sobrien/* quirk and capability flag convenience macros */ 8352284Sobrien#define CHIPC_QUIRK(_sc, _name) \ 8490075Sobrien ((_sc)->quirks & CHIPC_QUIRK_ ## _name) 8590075Sobrien 8690075Sobrien#define CHIPC_CAP(_sc, _name) \ 8790075Sobrien ((_sc)->caps & CHIPC_ ## _name) 8850397Sobrien 8990075Sobrien#define CHIPC_ASSERT_QUIRK(_sc, name) \ 9090075Sobrien KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) 9190075Sobrien 9290075Sobrien#define CHIPC_ASSERT_CAP(_sc, name) \ 9390075Sobrien KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set")) 9490075Sobrien 9590075Sobrienstatic int 9690075Sobrienchipc_probe(device_t dev) 9790075Sobrien{ 9890075Sobrien const struct chipc_device *id; 9990075Sobrien 10090075Sobrien for (id = chipc_devices; id->device != BHND_COREID_INVALID; id++) 10190075Sobrien { 10290075Sobrien if (bhnd_get_vendor(dev) == BHND_MFGID_BCM && 10390075Sobrien bhnd_get_device(dev) == id->device) 10490075Sobrien { 10590075Sobrien bhnd_set_generic_core_desc(dev); 10690075Sobrien return (BUS_PROBE_DEFAULT); 10790075Sobrien } 10890075Sobrien } 10990075Sobrien 11090075Sobrien return (ENXIO); 11190075Sobrien} 11290075Sobrien 11350397Sobrienstatic int 11450397Sobrienchipc_attach(device_t dev) 11590075Sobrien{ 11650397Sobrien struct bhnd_device_quirk *dq; 11750397Sobrien struct chipc_softc *sc; 11850397Sobrien bhnd_addr_t enum_addr; 11952284Sobrien uint32_t ccid_reg; 12052284Sobrien uint8_t chip_type; 12152284Sobrien int error; 12252284Sobrien 12352284Sobrien sc = device_get_softc(dev); 12450397Sobrien sc->dev = dev; 12550397Sobrien 12690075Sobrien /* Allocate bus resources */ 12750397Sobrien memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec)); 12850397Sobrien if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res))) 12950397Sobrien return (error); 13050397Sobrien 13150397Sobrien sc->core = sc->res[0]; 13250397Sobrien 13350397Sobrien /* Fetch our chipset identification data */ 13450397Sobrien ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); 13550397Sobrien chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS); 13650397Sobrien 13790075Sobrien switch (chip_type) { 13850397Sobrien case BHND_CHIPTYPE_SIBA: 13990075Sobrien /* enumeration space starts at the ChipCommon register base. */ 14090075Sobrien enum_addr = rman_get_start(sc->core->res); 14190075Sobrien break; 14290075Sobrien case BHND_CHIPTYPE_BCMA: 14390075Sobrien case BHND_CHIPTYPE_BCMA_ALT: 14490075Sobrien enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR); 14590075Sobrien break; 14690075Sobrien default: 14790075Sobrien device_printf(dev, "unsupported chip type %hhu\n", chip_type); 14890075Sobrien error = ENODEV; 14990075Sobrien goto cleanup; 15090075Sobrien } 15190075Sobrien 15250397Sobrien sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr); 15390075Sobrien 15490075Sobrien /* Fetch capability and status register values */ 15550397Sobrien sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); 15650397Sobrien sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); 15750397Sobrien 15850397Sobrien /* Populate the set of applicable quirk flags */ 15950397Sobrien sc->quirks = 0; 16050397Sobrien for (dq = chipc_quirks; dq->quirks != 0; dq++) { 16150397Sobrien if (bhnd_hwrev_matches(bhnd_get_hwrev(dev), &dq->hwrev)) 16250397Sobrien sc->quirks |= dq->quirks; 16350397Sobrien }; 16450397Sobrien 16550397Sobrien // TODO 16690075Sobrien switch (bhnd_chipc_nvram_src(dev)) { 16790075Sobrien case BHND_NVRAM_SRC_CIS: 16890075Sobrien device_printf(dev, "NVRAM source: CIS\n"); 16990075Sobrien break; 17050397Sobrien case BHND_NVRAM_SRC_SPROM: 17150397Sobrien device_printf(dev, "NVRAM source: SPROM\n"); 17250397Sobrien break; 17390075Sobrien case BHND_NVRAM_SRC_OTP: 17450397Sobrien device_printf(dev, "NVRAM source: OTP\n"); 17550397Sobrien break; 17650397Sobrien case BHND_NVRAM_SRC_NFLASH: 17750397Sobrien device_printf(dev, "NVRAM source: NFLASH\n"); 17890075Sobrien break; 17990075Sobrien case BHND_NVRAM_SRC_NONE: 18090075Sobrien device_printf(dev, "NVRAM source: NONE\n"); 18190075Sobrien break; 18290075Sobrien } 18390075Sobrien 18490075Sobrien return (0); 18590075Sobrien 18690075Sobriencleanup: 18750397Sobrien bhnd_release_resources(dev, sc->rspec, sc->res); 18850397Sobrien return (error); 18950397Sobrien} 19050397Sobrien 19150397Sobrienstatic int 19250397Sobrienchipc_detach(device_t dev) 19352284Sobrien{ 19452284Sobrien struct chipc_softc *sc; 19590075Sobrien 19652284Sobrien sc = device_get_softc(dev); 19752284Sobrien bhnd_release_resources(dev, sc->rspec, sc->res); 19852284Sobrien 19952284Sobrien return (0); 20052284Sobrien} 20190075Sobrien 20252284Sobrienstatic int 20390075Sobrienchipc_suspend(device_t dev) 20490075Sobrien{ 20552284Sobrien return (0); 20690075Sobrien} 20752284Sobrien 20852284Sobrienstatic int 20990075Sobrienchipc_resume(device_t dev) 21090075Sobrien{ 21152284Sobrien return (0); 21252284Sobrien} 21352284Sobrien 21452284Sobrien/** 21552284Sobrien * Use device-specific ChipStatus flags to determine the preferred NVRAM 21652284Sobrien * data source. 21752284Sobrien */ 21852284Sobrienstatic bhnd_nvram_src_t 21952284Sobrienchipc_nvram_src_chipst(struct chipc_softc *sc) 22052284Sobrien{ 22152284Sobrien uint8_t nvram_sel; 22252284Sobrien 22352284Sobrien CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST); 22452284Sobrien 22590075Sobrien if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) { 22690075Sobrien // TODO: On these devices, the official driver code always 22752284Sobrien // assumes SPROM availability if CHIPC_CST_OTP_SEL is not 22852284Sobrien // set; we must review against the actual behavior of our 22952284Sobrien // BCM4312 hardware 23090075Sobrien nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22); 23190075Sobrien } else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) { 23290075Sobrien nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23); 23390075Sobrien } else { 23490075Sobrien panic("invalid CST OTP/SPROM chipc quirk flags"); 23590075Sobrien } 23690075Sobrien device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst); 23790075Sobrien 23890075Sobrien switch (nvram_sel) { 23990075Sobrien case CHIPC_CST_DEFCIS_SEL: 24090075Sobrien return (BHND_NVRAM_SRC_CIS); 24190075Sobrien 24290075Sobrien case CHIPC_CST_SPROM_SEL: 24390075Sobrien case CHIPC_CST_OTP_PWRDN: 24490075Sobrien return (BHND_NVRAM_SRC_SPROM); 24590075Sobrien 24690075Sobrien case CHIPC_CST_OTP_SEL: 24790075Sobrien return (BHND_NVRAM_SRC_OTP); 24890075Sobrien 24990075Sobrien default: 25090075Sobrien device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx", 25190075Sobrien nvram_sel); 25290075Sobrien return (BHND_NVRAM_SRC_NONE); 25390075Sobrien } 25490075Sobrien} 25590075Sobrien 25690075Sobrien/** 25790075Sobrien * Determine the preferred NVRAM data source. 25890075Sobrien */ 25990075Sobrienstatic bhnd_nvram_src_t 26090075Sobrienchipc_nvram_src(device_t dev) 26190075Sobrien{ 26290075Sobrien struct chipc_softc *sc; 26390075Sobrien uint32_t srom_ctrl; 26490075Sobrien 26590075Sobrien sc = device_get_softc(dev); 26690075Sobrien 26790075Sobrien /* Very early devices always included a SPROM */ 26890075Sobrien if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM)) 26990075Sobrien return (BHND_NVRAM_SRC_SPROM); 27090075Sobrien 27190075Sobrien /* Most other early devices require checking ChipStatus flags */ 27290075Sobrien if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST)) 27390075Sobrien return (chipc_nvram_src_chipst(sc)); 27490075Sobrien 27590075Sobrien /* 27690075Sobrien * Later chipset revisions standardized the NVRAM capability flags and 27790075Sobrien * register interfaces. 27890075Sobrien * 27990075Sobrien * We check for hardware presence in order of precedence. For example, 28090075Sobrien * SPROM is is always used in preference to internal OTP if found. 28190075Sobrien */ 28290075Sobrien if (CHIPC_CAP(sc, CAP_SPROM)) { 28390075Sobrien srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); 28490075Sobrien if (srom_ctrl & CHIPC_SRC_PRESENT) 28590075Sobrien return (BHND_NVRAM_SRC_SPROM); 28690075Sobrien } 28790075Sobrien 28890075Sobrien /* Check for OTP */ 28990075Sobrien if (CHIPC_CAP(sc, CAP_OTP_SIZE)) 29090075Sobrien return (BHND_NVRAM_SRC_OTP); 29190075Sobrien 29290075Sobrien /* 29390075Sobrien * Finally, Northstar chipsets (and possibly other chipsets?) support 29452284Sobrien * external NAND flash. 29552284Sobrien */ 29690075Sobrien if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH)) 29790075Sobrien return (BHND_NVRAM_SRC_NFLASH); 29890075Sobrien 29990075Sobrien /* No NVRAM hardware capability declared */ 30090075Sobrien return (BHND_NVRAM_SRC_NONE); 30190075Sobrien} 30290075Sobrien 30390075Sobrienstatic device_method_t chipc_methods[] = { 30490075Sobrien /* Device interface */ 30590075Sobrien DEVMETHOD(device_probe, chipc_probe), 30690075Sobrien DEVMETHOD(device_attach, chipc_attach), 30790075Sobrien DEVMETHOD(device_detach, chipc_detach), 30890075Sobrien DEVMETHOD(device_suspend, chipc_suspend), 30990075Sobrien DEVMETHOD(device_resume, chipc_resume), 31090075Sobrien 31190075Sobrien /* ChipCommon interface */ 31290075Sobrien DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src), 31390075Sobrien 31490075Sobrien DEVMETHOD_END 31590075Sobrien}; 31690075Sobrien 31790075SobrienDEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc)); 31852284SobrienDRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0); 31952284SobrienMODULE_VERSION(bhnd_chipc, 1); 32090075Sobrien