chipc.c revision 300015
1132744Skan/*-
290285Sobrien * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3169706Skan * All rights reserved.
418334Speter *
5132744Skan * Redistribution and use in source and binary forms, with or without
618334Speter * modification, are permitted provided that the following conditions
7132744Skan * are met:
818334Speter * 1. Redistributions of source code must retain the above copyright
918334Speter *    notice, this list of conditions and the following disclaimer,
1018334Speter *    without modification.
1118334Speter * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12132744Skan *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1318334Speter *    redistribution must be conditioned upon including a substantially
1418334Speter *    similar Disclaimer requirement for further binary redistribution.
1518334Speter *
1618334Speter * NO WARRANTY
1718334Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18132744Skan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19169706Skan * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20169706Skan * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2118334Speter * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2218334Speter * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2318334Speter * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2418334Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2518334Speter * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2618334Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2718334Speter * THE POSSIBILITY OF SUCH DAMAGES.
2818334Speter */
2918334Speter
3018334Speter#include <sys/cdefs.h>
3118334Speter__FBSDID("$FreeBSD: head/sys/dev/bhnd/cores/chipc/chipc.c 300015 2016-05-17 06:52:53Z adrian $");
3218334Speter
3390285Sobrien/*
3490285Sobrien * Broadcom ChipCommon driver.
3590285Sobrien *
3618334Speter * With the exception of some very early chipsets, the ChipCommon core
3750654Sobrien * has been included in all HND SoCs and chipsets based on the siba(4)
3850654Sobrien * and bcma(4) interconnects, providing a common interface to chipset
3950654Sobrien * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO,
4090285Sobrien * flash, etc.
4190285Sobrien */
4290285Sobrien
4390285Sobrien#include <sys/param.h>
44169706Skan#include <sys/kernel.h>
45132744Skan#include <sys/bus.h>
4690285Sobrien#include <sys/module.h>
47169706Skan#include <sys/systm.h>
48132744Skan
4990285Sobrien#include <machine/bus.h>
5090285Sobrien#include <sys/rman.h>
5190285Sobrien#include <machine/resource.h>
5290285Sobrien
5390285Sobrien#include <dev/bhnd/bhnd.h>
5490285Sobrien
5590285Sobrien#include "bhnd_nvram_if.h"
5690285Sobrien
5790285Sobrien#include "chipcreg.h"
5890285Sobrien#include "chipcvar.h"
5990285Sobrien
6090285Sobriendevclass_t bhnd_chipc_devclass;	/**< bhnd(4) chipcommon device class */
6190285Sobrien
6290285Sobrienstatic const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = {
6390285Sobrien	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
6490285Sobrien	{ -1, -1, 0 }
6590285Sobrien};
6690285Sobrien
6790285Sobrienstatic struct bhnd_device_quirk chipc_quirks[];
6890285Sobrienstatic struct bhnd_chip_quirk chipc_chip_quirks[];
6990285Sobrien
7090285Sobrien/* Supported device identifiers */
7190285Sobrienstatic const struct bhnd_device chipc_devices[] = {
7290285Sobrien	BHND_DEVICE(CC, "CC", chipc_quirks, chipc_chip_quirks),
7390285Sobrien	BHND_DEVICE_END
7490285Sobrien};
7590285Sobrien
7690285Sobrien
7790285Sobrien/* Device quirks table */
7890285Sobrienstatic struct bhnd_device_quirk chipc_quirks[] = {
7990285Sobrien	{ BHND_HWREV_GTE	(32),	CHIPC_QUIRK_SUPPORTS_SPROM },
80132744Skan	{ BHND_HWREV_GTE	(35),	CHIPC_QUIRK_SUPPORTS_NFLASH },
81117407Skan	BHND_DEVICE_QUIRK_END
82117407Skan};
83117407Skan
84117407Skan/* Chip-specific quirks table */
85117407Skanstatic struct bhnd_chip_quirk chipc_chip_quirks[] = {
86117407Skan	/* 4331 12x9 packages */
8750654Sobrien	{{ BHND_CHIP_IP(4331, 4331TN) },
8850654Sobrien		CHIPC_QUIRK_4331_GPIO2_5_MUX_SPROM
8990285Sobrien	},
9050654Sobrien	{{ BHND_CHIP_IP(4331, 4331TNA0) },
9118334Speter		CHIPC_QUIRK_4331_GPIO2_5_MUX_SPROM
9218334Speter	},
9318334Speter
9490285Sobrien	/* 4331 12x12 packages */
9518334Speter	{{ BHND_CHIP_IPR(4331, 4331TT, HWREV_GTE(1)) },
96169706Skan		CHIPC_QUIRK_4331_EXTPA2_MUX_SPROM
9718334Speter	},
98169706Skan
99169706Skan	/* 4331 (all packages/revisions) */
100169706Skan	{{ BHND_CHIP_ID(4331) },
101169706Skan		CHIPC_QUIRK_4331_EXTPA_MUX_SPROM
102132744Skan	},
10318334Speter
104169706Skan	/* 4360 family (all revs <= 2) */
105117407Skan	{{ BHND_CHIP_IR(4352, HWREV_LTE(2)) },
106117407Skan		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
107117407Skan	{{ BHND_CHIP_IR(43460, HWREV_LTE(2)) },
108117407Skan		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
109169706Skan	{{ BHND_CHIP_IR(43462, HWREV_LTE(2)) },
110117407Skan		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
111117407Skan	{{ BHND_CHIP_IR(43602, HWREV_LTE(2)) },
112117407Skan		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
113117407Skan
114117407Skan	BHND_CHIP_QUIRK_END
115117407Skan};
116169706Skan
117169706Skan/* quirk and capability flag convenience macros */
118117407Skan#define	CHIPC_QUIRK(_sc, _name)	\
11990285Sobrien    ((_sc)->quirks & CHIPC_QUIRK_ ## _name)
12090285Sobrien
12190285Sobrien#define CHIPC_CAP(_sc, _name)	\
12290285Sobrien    ((_sc)->caps & CHIPC_ ## _name)
12390285Sobrien
124117407Skan#define	CHIPC_ASSERT_QUIRK(_sc, name)	\
12518334Speter    KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
126169706Skan
127169706Skan#define	CHIPC_ASSERT_CAP(_sc, name)	\
12852295Sobrien    KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
129132744Skan
130132744Skanstatic bhnd_nvram_src_t	chipc_nvram_identify(struct chipc_softc *sc);
131132744Skanstatic int		chipc_sprom_init(struct chipc_softc *);
132132744Skanstatic int		chipc_enable_sprom_pins(struct chipc_softc *);
133132744Skanstatic int		chipc_disable_sprom_pins(struct chipc_softc *);
134132744Skan
135132744Skan
136132744Skanstatic int
137132744Skanchipc_probe(device_t dev)
138169706Skan{
139169706Skan	const struct bhnd_device *id;
140169706Skan
141169706Skan	id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0]));
142132744Skan	if (id == NULL)
143132744Skan		return (ENXIO);
14452295Sobrien
14552295Sobrien	bhnd_set_default_core_desc(dev);
14690285Sobrien	return (BUS_PROBE_DEFAULT);
14790285Sobrien}
148169706Skan
149169706Skanstatic int
15090285Sobrienchipc_attach(device_t dev)
151117407Skan{
15290285Sobrien	struct chipc_softc		*sc;
15390285Sobrien	bhnd_addr_t			 enum_addr;
15490285Sobrien	uint32_t			 ccid_reg;
15590285Sobrien	uint8_t				 chip_type;
15690285Sobrien	int				 error;
15790285Sobrien
158117407Skan	sc = device_get_softc(dev);
159169706Skan	sc->dev = dev;
160132744Skan	sc->quirks = bhnd_device_quirks(dev, chipc_devices,
161169706Skan	    sizeof(chipc_devices[0]));
162169706Skan
163169706Skan	CHIPC_LOCK_INIT(sc);
164169706Skan
165169706Skan	/* Allocate bus resources */
166169706Skan	memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
167169706Skan	if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
16890285Sobrien		return (error);
16952295Sobrien
170132744Skan	sc->core = sc->res[0];
171132744Skan
172132744Skan	/* Fetch our chipset identification data */
173132744Skan	ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
174132744Skan	chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS);
17590285Sobrien
17690285Sobrien	switch (chip_type) {
17790285Sobrien	case BHND_CHIPTYPE_SIBA:
178169706Skan		/* enumeration space starts at the ChipCommon register base. */
179132744Skan		enum_addr = rman_get_start(sc->core->res);
180132744Skan		break;
181132744Skan	case BHND_CHIPTYPE_BCMA:
182132744Skan	case BHND_CHIPTYPE_BCMA_ALT:
183132744Skan		enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR);
184132744Skan		break;
185169706Skan	default:
186169706Skan		device_printf(dev, "unsupported chip type %hhu\n", chip_type);
187169706Skan		error = ENODEV;
188132744Skan		goto cleanup;
189132744Skan	}
190132744Skan
191132744Skan	sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
192132744Skan
193132744Skan	/* Fetch capability and status register values */
194132744Skan	sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
195132744Skan	sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
196132744Skan
197132744Skan	/* Identify NVRAM source */
198132744Skan	sc->nvram_src = chipc_nvram_identify(sc);
199132744Skan
200132744Skan	/* Read NVRAM data */
201132744Skan	switch (sc->nvram_src) {
202132744Skan	case BHND_NVRAM_SRC_OTP:
203132744Skan		// TODO (requires access to OTP hardware)
204132744Skan		device_printf(sc->dev, "NVRAM-OTP unsupported\n");
205132744Skan		break;
206132744Skan
207132744Skan	case BHND_NVRAM_SRC_NFLASH:
208169706Skan		// TODO (requires access to NFLASH hardware)
209132744Skan		device_printf(sc->dev, "NVRAM-NFLASH unsupported\n");
210132744Skan		break;
211132744Skan
212132744Skan	case BHND_NVRAM_SRC_SPROM:
213132744Skan		if ((error = chipc_sprom_init(sc)))
21490285Sobrien			goto cleanup;
215132744Skan		break;
216132744Skan
217132744Skan	case BHND_NVRAM_SRC_UNKNOWN:
218132744Skan		/* Handled externally */
219169706Skan		break;
220169706Skan	}
221169706Skan
222169706Skan	return (0);
223169706Skan
22452295Sobriencleanup:
22590285Sobrien	bhnd_release_resources(dev, sc->rspec, sc->res);
22690285Sobrien	CHIPC_LOCK_DESTROY(sc);
22790285Sobrien	return (error);
22890285Sobrien}
22990285Sobrien
23090285Sobrienstatic int
231117407Skanchipc_detach(device_t dev)
232169706Skan{
233169706Skan	struct chipc_softc	*sc;
234117407Skan
235117407Skan	sc = device_get_softc(dev);
236169706Skan	bhnd_release_resources(dev, sc->rspec, sc->res);
237169706Skan	bhnd_sprom_fini(&sc->sprom);
238169706Skan
239169706Skan	CHIPC_LOCK_DESTROY(sc);
24096294Sobrien
241117407Skan	return (0);
242117407Skan}
24390285Sobrien
244132744Skanstatic int
245132744Skanchipc_suspend(device_t dev)
246132744Skan{
24790285Sobrien	return (0);
248117407Skan}
249117407Skan
250117407Skanstatic int
251117407Skanchipc_resume(device_t dev)
25250654Sobrien{
253117407Skan	return (0);
254117407Skan}
255117407Skan
256117407Skan/**
25750654Sobrien * Initialize local SPROM shadow, if required.
258146908Skan *
259146908Skan * @param sc chipc driver state.
260146908Skan */
261146908Skanstatic int
26218334Speterchipc_sprom_init(struct chipc_softc *sc)
26318334Speter{
26418334Speter	int	error;
26518334Speter
26618334Speter	KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM,
26718334Speter	    ("non-SPROM source (%u)\n", sc->nvram_src));
26818334Speter
26918334Speter	/* Enable access to the SPROM */
27018334Speter	CHIPC_LOCK(sc);
27118334Speter	if ((error = chipc_enable_sprom_pins(sc)))
27218334Speter		goto failed;
27350654Sobrien
27490285Sobrien	/* Initialize SPROM parser */
27590285Sobrien	error = bhnd_sprom_init(&sc->sprom, sc->core, CHIPC_SPROM_OTP);
27650654Sobrien	if (error) {
277169706Skan		device_printf(sc->dev, "SPROM identification failed: %d\n",
278169706Skan			error);
279169706Skan
280169706Skan		chipc_disable_sprom_pins(sc);
281169706Skan		goto failed;
282169706Skan	}
283169706Skan
284169706Skan	/* Drop access to the SPROM lines */
285169706Skan	if ((error = chipc_disable_sprom_pins(sc))) {
286169706Skan		bhnd_sprom_fini(&sc->sprom);
287169706Skan		goto failed;
288169706Skan	}
289169706Skan	CHIPC_UNLOCK(sc);
290169706Skan
291132744Skan	return (0);
292132744Skan
293169706Skanfailed:
294169706Skan	CHIPC_UNLOCK(sc);
295132744Skan	return (error);
29650654Sobrien}
29750654Sobrien
29850654Sobrien/**
299169706Skan * Determine the NVRAM data source for this device.
300132744Skan *
301132744Skan * @param sc chipc driver state.
302132744Skan */
303132744Skanstatic bhnd_nvram_src_t
304132744Skanchipc_nvram_identify(struct chipc_softc *sc)
305132744Skan{
306132744Skan	uint32_t		 srom_ctrl;
307132744Skan
308132744Skan	/* Very early devices vend SPROM/OTP/CIS (if at all) via the
309132744Skan	 * host bridge interface instead of ChipCommon. */
310132744Skan	if (!CHIPC_QUIRK(sc, SUPPORTS_SPROM))
311132744Skan		return (BHND_NVRAM_SRC_UNKNOWN);
31290285Sobrien
31390285Sobrien	/*
31490285Sobrien	 * Later chipset revisions standardized the SPROM capability flags and
31590285Sobrien	 * register interfaces.
316169706Skan	 *
317169706Skan	 * We check for hardware presence in order of precedence. For example,
318169706Skan	 * SPROM is is always used in preference to internal OTP if found.
319169706Skan	 */
320169706Skan	if (CHIPC_CAP(sc, CAP_SPROM)) {
321169706Skan		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
322169706Skan		if (srom_ctrl & CHIPC_SRC_PRESENT)
323169706Skan			return (BHND_NVRAM_SRC_SPROM);
32450654Sobrien	}
325169706Skan
32618334Speter	/* Check for OTP */
327117407Skan	if (CHIPC_CAP(sc, CAP_OTP_SIZE))
328117407Skan		return (BHND_NVRAM_SRC_OTP);
329117407Skan
330117407Skan	/*
331117407Skan	 * Finally, Northstar chipsets (and possibly other chipsets?) support
332132744Skan	 * external NAND flash.
333117407Skan	 */
334132744Skan	if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
335117407Skan		return (BHND_NVRAM_SRC_NFLASH);
336117407Skan
337117407Skan	/* No NVRAM hardware capability declared */
338117407Skan	return (BHND_NVRAM_SRC_UNKNOWN);
339132744Skan}
340132744Skan
341132744Skan
342117407Skan/**
343117407Skan * If required by this device, enable access to the SPROM.
344117407Skan *
345117407Skan * @param sc chipc driver state.
346117407Skan */
347117407Skanstatic int
348117407Skanchipc_enable_sprom_pins(struct chipc_softc *sc)
349117407Skan{
350117407Skan	uint32_t cctrl;
351117407Skan
352132744Skan	CHIPC_LOCK_ASSERT(sc, MA_OWNED);
353132744Skan
354117407Skan	/* Nothing to do? */
355117407Skan	if (!CHIPC_QUIRK(sc, MUX_SPROM))
356117407Skan		return (0);
357117407Skan
358117407Skan	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
359117407Skan
360117407Skan	/* 4331 devices */
361117407Skan	if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) {
362132744Skan		cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN;
363117407Skan
364117407Skan		if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM))
365117407Skan			cctrl &= ~CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5;
366117407Skan
367117407Skan		if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM))
368117407Skan			cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;
369132744Skan
370117407Skan		bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
371117407Skan		return (0);
372117407Skan	}
373117407Skan
374117407Skan	/* 4360 devices */
375117407Skan	if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
376117407Skan		/* Unimplemented */
377117407Skan	}
378117407Skan
379117407Skan	/* Refuse to proceed on unsupported devices with muxed SPROM pins */
380117407Skan	device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
381117407Skan	return (ENXIO);
382132744Skan}
383117407Skan
384132744Skan/**
385117407Skan * If required by this device, revert any GPIO/pin configuration applied
386117407Skan * to allow SPROM access.
387117407Skan *
388117407Skan * @param sc chipc driver state.
389117407Skan */
390148163Sobrienstatic int
391148163Sobrienchipc_disable_sprom_pins(struct chipc_softc *sc)
392117407Skan{
393117407Skan	uint32_t cctrl;
394132744Skan
395132744Skan	CHIPC_LOCK_ASSERT(sc, MA_OWNED);
396117407Skan
397117407Skan	/* Nothing to do? */
398169706Skan	if (!CHIPC_QUIRK(sc, MUX_SPROM))
399169706Skan		return (0);
400117407Skan
401117407Skan	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
402117407Skan
403117407Skan	/* 4331 devices */
404117407Skan	if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) {
405117407Skan		cctrl |= CHIPC_CCTRL4331_EXTPA_EN;
406117407Skan
407117407Skan		if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM))
408117407Skan			cctrl |= CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5;
409117407Skan
410117407Skan		if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM))
411132744Skan			cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;
412169706Skan
413117407Skan		bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
414117407Skan		return (0);
415117407Skan	}
416117407Skan
417117407Skan	/* 4360 devices */
418117407Skan	if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
419117407Skan		/* Unimplemented */
420117407Skan	}
421117407Skan
422117407Skan	/* Refuse to proceed on unsupported devices with muxed SPROM pins */
423117407Skan	device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
424117407Skan	return (ENXIO);
425117407Skan}
426117407Skan
427117407Skanstatic bhnd_nvram_src_t
428117407Skanchipc_nvram_src(device_t dev)
429117407Skan{
430117407Skan	struct chipc_softc *sc = device_get_softc(dev);
431117407Skan	return (sc->nvram_src);
432117407Skan}
433117407Skan
434117407Skanstatic int
435117407Skanchipc_nvram_getvar(device_t dev, const char *name, void *buf, size_t *len)
436117407Skan{
437117407Skan	struct chipc_softc	*sc;
438117407Skan	int			 error;
439117407Skan
440117407Skan	sc = device_get_softc(dev);
441117407Skan
442117407Skan	switch (sc->nvram_src) {
443117407Skan	case BHND_NVRAM_SRC_SPROM:
444117407Skan		CHIPC_LOCK(sc);
445117407Skan		error = bhnd_sprom_getvar(&sc->sprom, name, buf, len);
446117407Skan		CHIPC_UNLOCK(sc);
447117407Skan		return (error);
448117407Skan
449117407Skan	case BHND_NVRAM_SRC_OTP:
450117407Skan	case BHND_NVRAM_SRC_NFLASH:
451117407Skan		/* Currently unsupported */
452117407Skan		return (ENXIO);
453117407Skan
454148163Sobrien	case BHND_NVRAM_SRC_UNKNOWN:
455148163Sobrien		return (ENODEV);
456117407Skan	}
457117407Skan
458132744Skan	/* Unknown NVRAM source */
459132744Skan	return (ENODEV);
460132744Skan}
461132744Skan
462132744Skanstatic int
463117407Skanchipc_nvram_setvar(device_t dev, const char *name, const void *buf,
464117407Skan    size_t len)
465117407Skan{
466117407Skan	struct chipc_softc	*sc;
467117407Skan	int			 error;
468169706Skan
469169706Skan	sc = device_get_softc(dev);
470169706Skan
471169706Skan	switch (sc->nvram_src) {
472169706Skan	case BHND_NVRAM_SRC_SPROM:
473117407Skan		CHIPC_LOCK(sc);
474117407Skan		error = bhnd_sprom_setvar(&sc->sprom, name, buf, len);
475117407Skan		CHIPC_UNLOCK(sc);
47690285Sobrien		return (error);
47790285Sobrien
47890285Sobrien	case BHND_NVRAM_SRC_OTP:
47990285Sobrien	case BHND_NVRAM_SRC_NFLASH:
48090285Sobrien		/* Currently unsupported */
48190285Sobrien		return (ENXIO);
48290285Sobrien
48390285Sobrien	case BHND_NVRAM_SRC_UNKNOWN:
48490285Sobrien	default:
48590285Sobrien		return (ENODEV);
48690285Sobrien	}
48790285Sobrien
48890285Sobrien	/* Unknown NVRAM source */
489132744Skan	return (ENODEV);
490132744Skan}
491132744Skan
492132744Skanstatic void
493169706Skanchipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask)
49450654Sobrien{
49590285Sobrien	struct chipc_softc	*sc;
49690285Sobrien	uint32_t		 cctrl;
49790285Sobrien
498132744Skan	sc = device_get_softc(dev);
499169706Skan
500169706Skan	CHIPC_LOCK(sc);
50150654Sobrien
50250654Sobrien	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
50390285Sobrien	cctrl = (cctrl & ~mask) | (value | mask);
50450654Sobrien	bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
50550654Sobrien
50650654Sobrien	CHIPC_UNLOCK(sc);
50750654Sobrien}
50850654Sobrien
50950654Sobrienstatic device_method_t chipc_methods[] = {
51050654Sobrien	/* Device interface */
511132744Skan	DEVMETHOD(device_probe,			chipc_probe),
51250654Sobrien	DEVMETHOD(device_attach,		chipc_attach),
51350654Sobrien	DEVMETHOD(device_detach,		chipc_detach),
51450654Sobrien	DEVMETHOD(device_suspend,		chipc_suspend),
51550654Sobrien	DEVMETHOD(device_resume,		chipc_resume),
51650654Sobrien
51750654Sobrien	/* ChipCommon interface */
51850654Sobrien	DEVMETHOD(bhnd_chipc_nvram_src,		chipc_nvram_src),
51950654Sobrien	DEVMETHOD(bhnd_chipc_write_chipctrl,	chipc_write_chipctrl),
52050654Sobrien
52150654Sobrien	/* NVRAM interface */
52250654Sobrien	DEVMETHOD(bhnd_nvram_getvar,		chipc_nvram_getvar),
52350654Sobrien	DEVMETHOD(bhnd_nvram_setvar,		chipc_nvram_setvar),
52418334Speter
52518334Speter	DEVMETHOD_END
526169706Skan};
52718334Speter
528117407SkanDEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
529117407SkanDRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
530117407SkanMODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1);
531117407SkanMODULE_VERSION(bhnd_chipc, 1);
532117407Skan