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