bhnd_subr.c revision 299996
1119026Sume/*-
266776Skris * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
355163Sshin * All rights reserved.
455163Sshin *
555163Sshin * Redistribution and use in source and binary forms, with or without
662632Skris * modification, are permitted provided that the following conditions
755163Sshin * are met:
855163Sshin * 1. Redistributions of source code must retain the above copyright
955163Sshin *    notice, this list of conditions and the following disclaimer,
1055163Sshin *    without modification.
1155163Sshin * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1255163Sshin *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1355163Sshin *    redistribution must be conditioned upon including a substantially
1455163Sshin *    similar Disclaimer requirement for further binary redistribution.
1555163Sshin *
1655163Sshin * NO WARRANTY
1755163Sshin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1862632Skris * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1955163Sshin * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2055163Sshin * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2155163Sshin * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2255163Sshin * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2355163Sshin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2455163Sshin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2555163Sshin * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2655163Sshin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2755163Sshin * THE POSSIBILITY OF SUCH DAMAGES.
2855163Sshin */
2955163Sshin
3055163Sshin#include <sys/cdefs.h>
3155163Sshin__FBSDID("$FreeBSD: head/sys/dev/bhnd/bhnd_subr.c 299996 2016-05-17 00:23:46Z adrian $");
3255163Sshin
3355163Sshin#include <sys/types.h>
3455163Sshin#include <sys/param.h>
35203387Sume#include <sys/bus.h>
3662632Skris#include <sys/systm.h>
37118909Sume
3855163Sshin#include <machine/bus.h>
3962632Skris#include <sys/rman.h>
4055163Sshin#include <machine/resource.h>
41203387Sume
4255163Sshin#include <dev/bhnd/cores/chipc/chipcreg.h>
4355163Sshin
4455163Sshin#include "nvram/bhnd_nvram.h"
45203387Sume
46222861Shrs#include "bhnd_chipc_if.h"
4755163Sshin
48203387Sume#include "bhnd_nvram_if.h"
49203387Sume#include "bhnd_nvram_map.h"
5055163Sshin
5155163Sshin#include "bhndreg.h"
5255163Sshin#include "bhndvar.h"
5355163Sshin
5455163Sshinstatic device_t		find_nvram_child(device_t dev);
5555163Sshin
56253970Shrs/* BHND core device description table. */
5755163Sshinstatic const struct bhnd_core_desc {
5855163Sshin	uint16_t	 vendor;
5955163Sshin	uint16_t	 device;
6066776Skris	bhnd_devclass_t	 class;
61118916Sume	const char	*desc;
62118916Sume} bhnd_core_descs[] = {
63118916Sume	#define	BHND_CDESC(_mfg, _cid, _cls, _desc)		\
64118664Sume	    { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid,	\
6555163Sshin		BHND_DEVCLASS_ ## _cls, _desc }
6655163Sshin
67222732Shrs	BHND_CDESC(BCM, CC,		CC,		"ChipCommon I/O Controller"),
68222732Shrs	BHND_CDESC(BCM, ILINE20,	OTHER,		"iLine20 HPNA"),
69222732Shrs	BHND_CDESC(BCM, SRAM,		RAM,		"SRAM"),
70253970Shrs	BHND_CDESC(BCM, SDRAM,		RAM,		"SDRAM"),
71118664Sume	BHND_CDESC(BCM, PCI,		PCI,		"PCI Bridge"),
72118664Sume	BHND_CDESC(BCM, MIPS,		CPU,		"MIPS Core"),
73118664Sume	BHND_CDESC(BCM, ENET,		ENET_MAC,	"Fast Ethernet MAC"),
74197141Shrs	BHND_CDESC(BCM, CODEC,		OTHER,		"V.90 Modem Codec"),
7566776Skris	BHND_CDESC(BCM, USB,		OTHER,		"USB 1.1 Device/Host Controller"),
7666776Skris	BHND_CDESC(BCM, ADSL,		OTHER,		"ADSL Core"),
77225520Shrs	BHND_CDESC(BCM, ILINE100,	OTHER,		"iLine100 HPNA"),
78118664Sume	BHND_CDESC(BCM, IPSEC,		OTHER,		"IPsec Accelerator"),
79222732Shrs	BHND_CDESC(BCM, UTOPIA,		OTHER,		"UTOPIA ATM Core"),
80222732Shrs	BHND_CDESC(BCM, PCMCIA,		PCCARD,		"PCMCIA Bridge"),
8155163Sshin	BHND_CDESC(BCM, SOCRAM,		RAM,		"Internal Memory"),
82147150Ssuz	BHND_CDESC(BCM, MEMC,		MEMC,		"MEMC SDRAM Controller"),
8362632Skris	BHND_CDESC(BCM, OFDM,		OTHER,		"OFDM PHY"),
8462632Skris	BHND_CDESC(BCM, EXTIF,		OTHER,		"External Interface"),
8562632Skris	BHND_CDESC(BCM, D11,		WLAN,		"802.11 MAC/PHY/Radio"),
8655163Sshin	BHND_CDESC(BCM, APHY,		WLAN_PHY,	"802.11a PHY"),
87118664Sume	BHND_CDESC(BCM, BPHY,		WLAN_PHY,	"802.11b PHY"),
88118910Sume	BHND_CDESC(BCM, GPHY,		WLAN_PHY,	"802.11g PHY"),
89118664Sume	BHND_CDESC(BCM, MIPS33,		CPU,		"MIPS 3302 Core"),
90118664Sume	BHND_CDESC(BCM, USB11H,		OTHER,		"USB 1.1 Host Controller"),
91118664Sume	BHND_CDESC(BCM, USB11D,		OTHER,		"USB 1.1 Device Core"),
9255163Sshin	BHND_CDESC(BCM, USB20H,		OTHER,		"USB 2.0 Host Controller"),
9355163Sshin	BHND_CDESC(BCM, USB20D,		OTHER,		"USB 2.0 Device Core"),
9455163Sshin	BHND_CDESC(BCM, SDIOH,		OTHER,		"SDIO Host Controller"),
95222732Shrs	BHND_CDESC(BCM, ROBO,		OTHER,		"RoboSwitch"),
96222732Shrs	BHND_CDESC(BCM, ATA100,		OTHER,		"Parallel ATA Controller"),
97124526Sume	BHND_CDESC(BCM, SATAXOR,	OTHER,		"SATA DMA/XOR Controller"),
9855163Sshin	BHND_CDESC(BCM, GIGETH,		ENET_MAC,	"Gigabit Ethernet MAC"),
99222732Shrs	BHND_CDESC(BCM, PCIE,		PCIE,		"PCIe Bridge"),
100124526Sume	BHND_CDESC(BCM, NPHY,		WLAN_PHY,	"802.11n 2x2 PHY"),
10155163Sshin	BHND_CDESC(BCM, SRAMC,		MEMC,		"SRAM Controller"),
10262632Skris	BHND_CDESC(BCM, MINIMAC,	OTHER,		"MINI MAC/PHY"),
103173412Skevlo	BHND_CDESC(BCM, ARM11,		CPU,		"ARM1176 CPU"),
10462632Skris	BHND_CDESC(BCM, ARM7S,		CPU,		"ARM7TDMI-S CPU"),
105222732Shrs	BHND_CDESC(BCM, LPPHY,		WLAN_PHY,	"802.11a/b/g PHY"),
106173412Skevlo	BHND_CDESC(BCM, PMU,		PMU,		"PMU"),
107253970Shrs	BHND_CDESC(BCM, SSNPHY,		WLAN_PHY,	"802.11n Single-Stream PHY"),
10855163Sshin	BHND_CDESC(BCM, SDIOD,		OTHER,		"SDIO Device Core"),
109124526Sume	BHND_CDESC(BCM, ARMCM3,		CPU,		"ARM Cortex-M3 CPU"),
110173412Skevlo	BHND_CDESC(BCM, HTPHY,		WLAN_PHY,	"802.11n 4x4 PHY"),
111124526Sume	BHND_CDESC(BCM, MIPS74K,	CPU,		"MIPS74k CPU"),
112222732Shrs	BHND_CDESC(BCM, GMAC,		ENET_MAC,	"Gigabit MAC core"),
11355163Sshin	BHND_CDESC(BCM, DMEMC,		MEMC,		"DDR1/DDR2 Memory Controller"),
11455163Sshin	BHND_CDESC(BCM, PCIERC,		OTHER,		"PCIe Root Complex"),
115124524Sume	BHND_CDESC(BCM, OCP,		SOC_BRIDGE,	"OCP to OCP Bridge"),
11655163Sshin	BHND_CDESC(BCM, SC,		OTHER,		"Shared Common Core"),
117118909Sume	BHND_CDESC(BCM, AHB,		SOC_BRIDGE,	"OCP to AHB Bridge"),
118253970Shrs	BHND_CDESC(BCM, SPIH,		OTHER,		"SPI Host Controller"),
119204407Suqs	BHND_CDESC(BCM, I2S,		OTHER,		"I2S Digital Audio Interface"),
120118916Sume	BHND_CDESC(BCM, DMEMS,		MEMC,		"SDR/DDR1 Memory Controller"),
121118916Sume	BHND_CDESC(BCM, UBUS_SHIM,	OTHER,		"BCM6362/UBUS WLAN SHIM"),
122118916Sume	BHND_CDESC(BCM, PCIE2,		PCIE,		"PCIe Bridge (Gen2)"),
123118909Sume
124118909Sume	BHND_CDESC(ARM, APB_BRIDGE,	SOC_BRIDGE,	"BP135 AMBA3 AXI to APB Bridge"),
125118909Sume	BHND_CDESC(ARM, PL301,		SOC_ROUTER,	"PL301 AMBA3 Interconnect"),
126118916Sume	BHND_CDESC(ARM, EROM,		EROM,		"PL366 Device Enumeration ROM"),
127118909Sume	BHND_CDESC(ARM, OOB_ROUTER,	OTHER,		"PL367 OOB Interrupt Router"),
128222848Shrs	BHND_CDESC(ARM, AXI_UNMAPPED,	OTHER,		"Unmapped Address Ranges"),
12955163Sshin
130222732Shrs	BHND_CDESC(BCM, 4706_CC,	CC,		"ChipCommon I/O Controller"),
131222732Shrs	BHND_CDESC(BCM, NS_PCIE2,	PCIE,		"PCIe Bridge (Gen2)"),
132225520Shrs	BHND_CDESC(BCM, NS_DMA,		OTHER,		"DMA engine"),
133222732Shrs	BHND_CDESC(BCM, NS_SDIO,	OTHER,		"SDIO 3.0 Host Controller"),
134222732Shrs	BHND_CDESC(BCM, NS_USB20H,	OTHER,		"USB 2.0 Host Controller"),
135225520Shrs	BHND_CDESC(BCM, NS_USB30H,	OTHER,		"USB 3.0 Host Controller"),
136222732Shrs	BHND_CDESC(BCM, NS_A9JTAG,	OTHER,		"ARM Cortex A9 JTAG Interface"),
137222732Shrs	BHND_CDESC(BCM, NS_DDR23_MEMC,	MEMC,		"Denali DDR2/DD3 Memory Controller"),
138222732Shrs	BHND_CDESC(BCM, NS_ROM,		NVRAM,		"System ROM"),
139222848Shrs	BHND_CDESC(BCM, NS_NAND,	NVRAM,		"NAND Flash Controller"),
140222848Shrs	BHND_CDESC(BCM, NS_QSPI,	NVRAM,		"QSPI Flash Controller"),
14155163Sshin	BHND_CDESC(BCM, NS_CC_B,	CC_B,		"ChipCommon B Auxiliary I/O Controller"),
14266776Skris	BHND_CDESC(BCM, 4706_SOCRAM,	RAM,		"Internal Memory"),
14366776Skris	BHND_CDESC(BCM, IHOST_ARMCA9,	CPU,		"ARM Cortex A9 CPU"),
14466776Skris	BHND_CDESC(BCM, 4706_GMAC_CMN,	ENET,		"Gigabit MAC (Common)"),
14566776Skris	BHND_CDESC(BCM, 4706_GMAC,	ENET_MAC,	"Gigabit MAC"),
14666776Skris	BHND_CDESC(BCM, AMEMC,		MEMC,		"Denali DDR1/DDR2 Memory Controller"),
147225520Shrs#undef	BHND_CDESC
14866776Skris
14966776Skris	/* Derived from inspection of the BCM4331 cores that provide PrimeCell
150225520Shrs	 * IDs. Due to lack of documentation, the surmised device name/purpose
15166776Skris	 * provided here may be incorrect. */
15266776Skris	{ BHND_MFGID_ARM,	BHND_PRIMEID_EROM,	BHND_DEVCLASS_OTHER,
15366776Skris	    "PL364 Device Enumeration ROM" },
15466776Skris	{ BHND_MFGID_ARM,	BHND_PRIMEID_SWRAP,	BHND_DEVCLASS_OTHER,
155124525Sume	    "PL368 Device Management Interface" },
156124525Sume	{ BHND_MFGID_ARM,	BHND_PRIMEID_MWRAP,	BHND_DEVCLASS_OTHER,
157124525Sume	    "PL369 Device Management Interface" },
15866776Skris
15966776Skris	{ 0, 0, 0, NULL }
16066776Skris};
16166776Skris
16266776Skris/**
16366776Skris * Return the name for a given JEP106 manufacturer ID.
164118661Sume *
165118661Sume * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
166118661Sume * JEP106 continuation code.
167225520Shrs */
168222732Shrsconst char *
169222732Shrsbhnd_vendor_name(uint16_t vendor)
170222732Shrs{
171222732Shrs	switch (vendor) {
172222732Shrs	case BHND_MFGID_ARM:
173225520Shrs		return "ARM";
174225520Shrs	case BHND_MFGID_BCM:
175225520Shrs		return "Broadcom";
17666776Skris	case BHND_MFGID_MIPS:
177222732Shrs		return "MIPS";
178222732Shrs	default:
17955163Sshin		return "unknown";
18055163Sshin	}
18155163Sshin}
18255163Sshin
18366776Skris/**
184119026Sume * Return the name of a port type.
185222732Shrs */
186222732Shrsconst char *
18766776Skrisbhnd_port_type_name(bhnd_port_type port_type)
18855163Sshin{
189253970Shrs	switch (port_type) {
190253995Shrs	case BHND_PORT_DEVICE:
191253995Shrs		return ("device");
192253970Shrs	case BHND_PORT_BRIDGE:
19355163Sshin		return ("bridge");
194225520Shrs	case BHND_PORT_AGENT:
195225520Shrs		return ("agent");
196225520Shrs	default:
197225520Shrs		return "unknown";
198225520Shrs	}
19955163Sshin}
200225520Shrs
20155163Sshin
20255163Sshinstatic const struct bhnd_core_desc *
203118664Sumebhnd_find_core_desc(uint16_t vendor, uint16_t device)
204222848Shrs{
20555163Sshin	for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
206222848Shrs		if (bhnd_core_descs[i].vendor != vendor)
20755163Sshin			continue;
20855163Sshin
20955163Sshin		if (bhnd_core_descs[i].device != device)
21055163Sshin			continue;
21155163Sshin
21255163Sshin		return (&bhnd_core_descs[i]);
21355163Sshin	}
214118661Sume
215118661Sume	return (NULL);
216118661Sume}
217118661Sume
218222732Shrs/**
219222732Shrs * Return a human-readable name for a BHND core.
220222732Shrs *
221222732Shrs * @param vendor The core designer's JEDEC-106 Manufacturer ID
222222732Shrs * @param device The core identifier.
223222732Shrs */
224222732Shrsconst char *
225222732Shrsbhnd_find_core_name(uint16_t vendor, uint16_t device)
22662632Skris{
227118664Sume	const struct bhnd_core_desc *desc;
22855163Sshin
22962632Skris	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
23055163Sshin		return ("unknown");
231225520Shrs
232124525Sume	return desc->desc;
233124525Sume}
234124525Sume
235124525Sume/**
236124525Sume * Return the device class for a BHND core.
237124525Sume *
238124525Sume * @param vendor The core designer's JEDEC-106 Manufacturer ID
239225520Shrs * @param device The core identifier.
24055163Sshin */
241124526Sumebhnd_devclass_t
24255163Sshinbhnd_find_core_class(uint16_t vendor, uint16_t device)
243118910Sume{
244124526Sume	const struct bhnd_core_desc *desc;
24555163Sshin
246118914Sume	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
247118914Sume		return (BHND_DEVCLASS_OTHER);
248118914Sume
24962632Skris	return desc->class;
25062632Skris}
25162632Skris
25262632Skris/**
25362632Skris * Return a human-readable name for a BHND core.
25466776Skris *
255118914Sume * @param ci The core's info record.
256118914Sume */
25766776Skrisconst char *
258118916Sumebhnd_core_name(const struct bhnd_core_info *ci)
259118916Sume{
260118916Sume	return bhnd_find_core_name(ci->vendor, ci->device);
261118916Sume}
26278064Sume
263118916Sume/**
264118916Sume * Return the device class for a BHND core.
265118916Sume *
266118916Sume * @param ci The core's info record.
267118916Sume */
268118916Sumebhnd_devclass_t
26978064Sumebhnd_core_class(const struct bhnd_core_info *ci)
270118914Sume{
271118914Sume	return bhnd_find_core_class(ci->vendor, ci->device);
27278064Sume}
273118916Sume
274118916Sume/**
275118916Sume * Initialize a core info record with data from from a bhnd-attached @p dev.
276118916Sume *
27778064Sume * @param dev A bhnd device.
27878064Sume * @param core The record to be initialized.
279118916Sume */
28062632Skrisstruct bhnd_core_info
281118916Sumebhnd_get_core_info(device_t dev) {
282118909Sume	return (struct bhnd_core_info) {
283118909Sume		.vendor		= bhnd_get_vendor(dev),
284222732Shrs		.device		= bhnd_get_device(dev),
285222732Shrs		.hwrev		= bhnd_get_hwrev(dev),
286118909Sume		.core_idx	= bhnd_get_core_index(dev),
287118909Sume		.unit		= bhnd_get_core_unit(dev)
288222732Shrs	};
289222732Shrs}
290118909Sume
291118916Sume/**
292118909Sume * Find a @p class child device with @p unit on @p dev.
29355163Sshin *
29466776Skris * @param parent The bhnd-compatible bus to be searched.
295118914Sume * @param class The device class to match on.
296147161Ssuz * @param unit The device unit number; specify -1 to return the first match
297118914Sume * regardless of unit number.
29866776Skris *
299119026Sume * @retval device_t if a matching child device is found.
300119026Sume * @retval NULL if no matching child device is found.
301119026Sume */
30266776Skrisdevice_t
303118914Sumebhnd_find_child(device_t dev, bhnd_devclass_t class, int unit)
304118914Sume{
305118914Sume	struct bhnd_core_match md = {
30666776Skris		.vendor = BHND_MFGID_INVALID,
30755163Sshin		.device = BHND_COREID_INVALID,
30855163Sshin		.hwrev.start = BHND_HWREV_INVALID,
30955163Sshin		.hwrev.end = BHND_HWREV_INVALID,
31055163Sshin		.class = class,
31166776Skris		.unit = unit
312118914Sume	};
313118914Sume
314118914Sume	return bhnd_match_child(dev, &md);
31566776Skris}
31666776Skris
31755163Sshin/**
31855163Sshin * Find the first child device on @p dev that matches @p desc.
31955163Sshin *
32055163Sshin * @param parent The bhnd-compatible bus to be searched.
32155163Sshin * @param desc A match descriptor.
32255163Sshin *
32355163Sshin * @retval device_t if a matching child device is found.
324118660Sume * @retval NULL if no matching child device is found.
325118664Sume */
326118664Sumedevice_t
32755163Sshinbhnd_match_child(device_t dev, const struct bhnd_core_match *desc)
32855163Sshin{
32955163Sshin	device_t	*devlistp;
33055163Sshin	device_t	 match;
33155163Sshin	int		 devcnt;
332118916Sume	int		 error;
333118909Sume
334118909Sume	error = device_get_children(dev, &devlistp, &devcnt);
335118909Sume	if (error != 0)
336118916Sume		return (NULL);
33755163Sshin
33855163Sshin	match = NULL;
33955163Sshin	for (int i = 0; i < devcnt; i++) {
340118916Sume		device_t dev = devlistp[i];
341118909Sume		if (bhnd_device_matches(dev, desc)) {
342118916Sume			match = dev;
343118909Sume			goto done;
344124526Sume		}
34555163Sshin	}
34655163Sshin
34755163Sshindone:
34855163Sshin	free(devlistp, M_TEMP);
349124526Sume	return match;
350118664Sume}
35155163Sshin
35255163Sshin/**
35355163Sshin * Find the first core in @p cores that matches @p desc.
35455163Sshin *
35555163Sshin * @param cores The table to search.
35655163Sshin * @param num_cores The length of @p cores.
35755163Sshin * @param desc A match descriptor.
35855163Sshin *
35955163Sshin * @retval bhnd_core_info if a matching core is found.
36055163Sshin * @retval NULL if no matching core is found.
361222732Shrs */
36255163Sshinconst struct bhnd_core_info *
36355163Sshinbhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
36455163Sshin    const struct bhnd_core_match *desc)
36555163Sshin{
36655163Sshin	for (u_int i = 0; i < num_cores; i++) {
36755163Sshin		if (bhnd_core_matches(&cores[i], desc))
368118916Sume			return &cores[i];
369253970Shrs	}
370118916Sume
371118909Sume	return (NULL);
372118916Sume}
37378064Sume
37455163Sshin
375118660Sume/**
376118664Sume * Find the first core in @p cores with the given @p class.
37755163Sshin *
37855163Sshin * @param cores The table to search.
37955163Sshin * @param num_cores The length of @p cores.
38055163Sshin * @param desc A match descriptor.
38155163Sshin *
382118916Sume * @retval bhnd_core_info if a matching core is found.
383118916Sume * @retval NULL if no matching core is found.
384118916Sume */
385118909Sumeconst struct bhnd_core_info *
386118916Sumebhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
38778064Sume    bhnd_devclass_t class)
388118916Sume{
389118916Sume	struct bhnd_core_match md = {
390118916Sume		.vendor = BHND_MFGID_INVALID,
391118909Sume		.device = BHND_COREID_INVALID,
392118916Sume		.hwrev.start = BHND_HWREV_INVALID,
39355163Sshin		.hwrev.end = BHND_HWREV_INVALID,
39455163Sshin		.class = class,
39555163Sshin		.unit = -1
39655163Sshin	};
397222732Shrs
39855163Sshin	return bhnd_match_core(cores, num_cores, &md);
39955163Sshin}
400119026Sume
40155163Sshin/**
40255163Sshin * Return true if the @p core matches @p desc.
403222732Shrs *
40455163Sshin * @param core A bhnd core descriptor.
40555163Sshin * @param desc A match descriptor to compare against @p core.
40655163Sshin *
40755163Sshin * @retval true if @p core matches @p match
408118660Sume * @retval false if @p core does not match @p match.
409118664Sume */
410222732Shrsbool
41155163Sshinbhnd_core_matches(const struct bhnd_core_info *core,
41255163Sshin    const struct bhnd_core_match *desc)
413118660Sume{
414118664Sume	if (desc->vendor != BHND_MFGID_INVALID &&
41562632Skris	    desc->vendor != core->vendor)
416222732Shrs		return (false);
41755163Sshin
41855163Sshin	if (desc->device != BHND_COREID_INVALID &&
419225520Shrs	    desc->device != core->device)
420225520Shrs		return (false);
421225520Shrs
422225520Shrs	if (desc->unit != -1 && desc->unit != core->unit)
423225520Shrs		return (false);
424225520Shrs
425225520Shrs	if (!bhnd_hwrev_matches(core->hwrev, &desc->hwrev))
426225520Shrs		return (false);
427225520Shrs
428225520Shrs	if (desc->class != BHND_DEVCLASS_INVALID &&
429225520Shrs	    desc->class != bhnd_core_class(core))
430225520Shrs		return (false);
431225520Shrs
432225520Shrs	return true;
433225520Shrs}
434225520Shrs
435225520Shrs/**
436225520Shrs * Return true if the @p chip matches @p desc.
437225520Shrs *
438225520Shrs * @param chip A bhnd chip identifier.
439225520Shrs * @param board The bhnd board info, or NULL if unavailable.
440225520Shrs * @param desc A match descriptor to compare against @p chip.
441225520Shrs *
442225520Shrs * @retval true if @p chip matches @p match
443225520Shrs * @retval false if @p chip does not match @p match.
444225520Shrs */
445222732Shrsbool
446118660Sumebhnd_chip_matches(const struct bhnd_chipid *chip,
44762632Skris    const struct bhnd_board_info *board,
448222732Shrs    const struct bhnd_chip_match *desc)
44955163Sshin{
450222732Shrs	/* Explicit wildcard match */
451222732Shrs	if (desc->match_any)
452222861Shrs		return (true);
453222861Shrs
454222861Shrs	/* If board_info is missing, but required, we cannot match. */
455222732Shrs	if (BHND_CHIP_MATCH_REQ_BOARD_INFO(desc) && board == NULL)
45655163Sshin		return (false);
45755163Sshin
458222732Shrs
45955163Sshin	/* Chip matching */
46055163Sshin	if (desc->match_id && chip->chip_id != desc->chip_id)
461119026Sume		return (false);
462119026Sume
463222732Shrs	if (desc->match_pkg && chip->chip_pkg != desc->chip_pkg)
464119026Sume		return (false);
465119026Sume
466119026Sume	if (desc->match_rev &&
467222732Shrs	    !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
468119026Sume		return (false);
469119026Sume
47055163Sshin
47155163Sshin	/* Board info matching */
47255163Sshin	if (desc->match_srom_rev &&
47355163Sshin	    !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
474222732Shrs		return (false);
475222732Shrs
476222732Shrs	if (desc->match_bvendor && board->board_vendor != desc->board_vendor)
47755163Sshin		return (false);
47855163Sshin
47955163Sshin	if (desc->match_btype && board->board_type != desc->board_type)
48055163Sshin		return (false);
481222732Shrs
48255163Sshin	if (desc->match_brev &&
48355163Sshin	    !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
48455163Sshin		return (false);
485222732Shrs
48655163Sshin
487222732Shrs	return (true);
48855163Sshin}
489222732Shrs
49055163Sshin/**
491222732Shrs * Return true if the @p hwrev matches @p desc.
49255163Sshin *
493222732Shrs * @param hwrev A bhnd hardware revision.
49455163Sshin * @param desc A match descriptor to compare against @p core.
495222732Shrs *
496222732Shrs * @retval true if @p hwrev matches @p match
49755163Sshin * @retval false if @p hwrev does not match @p match.
498118664Sume */
499222732Shrsbool
500222732Shrsbhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
501222732Shrs{
50255163Sshin	if (desc->start != BHND_HWREV_INVALID &&
50355163Sshin	    desc->start > hwrev)
504119026Sume		return false;
505124524Sume
506119026Sume	if (desc->end != BHND_HWREV_INVALID &&
507222732Shrs	    desc->end < hwrev)
508119026Sume		return false;
509222732Shrs
510222732Shrs	return true;
511222732Shrs}
512119026Sume
513222732Shrs/**
514119026Sume * Return true if the @p dev matches @p desc.
515119026Sume *
516119026Sume * @param dev A bhnd device.
517119026Sume * @param desc A match descriptor to compare against @p dev.
518119026Sume *
51962632Skris * @retval true if @p dev matches @p match
52062632Skris * @retval false if @p dev does not match @p match.
52162632Skris */
52262632Skrisbool
52362632Skrisbhnd_device_matches(device_t dev, const struct bhnd_core_match *desc)
52462632Skris{
52562632Skris	struct bhnd_core_info ci = {
52662632Skris		.vendor = bhnd_get_vendor(dev),
527222732Shrs		.device = bhnd_get_device(dev),
52862632Skris		.unit = bhnd_get_core_unit(dev),
52962632Skris		.hwrev = bhnd_get_hwrev(dev)
53062632Skris	};
53162632Skris
53262632Skris	return bhnd_core_matches(&ci, desc);
53362632Skris}
53462632Skris
53562632Skris/**
53662632Skris * Search @p table for an entry matching @p dev.
53762632Skris *
53862632Skris * @param dev A bhnd device to match against @p table.
53962632Skris * @param table The device table to search.
54062632Skris * @param entry_size The @p table entry size, in bytes.
541222732Shrs *
542222732Shrs * @retval bhnd_device the first matching device, if any.
54362632Skris * @retval NULL if no matching device is found in @p table.
54462632Skris */
54562632Skrisconst struct bhnd_device *
546222861Shrsbhnd_device_lookup(device_t dev, const struct bhnd_device *table,
547222861Shrs    size_t entry_size)
548222861Shrs{
549222861Shrs	const struct bhnd_device	*entry;
550222861Shrs	device_t			 hostb, parent;
551222861Shrs
552222861Shrs	parent = device_get_parent(dev);
553222861Shrs	hostb = bhnd_find_hostb_device(parent);
554222861Shrs
555222861Shrs	for (entry = table; entry->desc != NULL; entry =
556222861Shrs	    (const struct bhnd_device *) ((const char *) entry + entry_size))
557222861Shrs	{
558222861Shrs		/* match core info */
55955163Sshin		if (!bhnd_device_matches(dev, &entry->core))
56055163Sshin			continue;
56155163Sshin
56255163Sshin		/* match device flags */
56355163Sshin		if (entry->device_flags & BHND_DF_HOSTB) {
564222732Shrs			if (dev != hostb)
56555163Sshin				continue;
566222732Shrs		}
567222732Shrs
568222732Shrs		/* device found */
56955163Sshin		return (entry);
57055163Sshin	}
57155163Sshin
572222732Shrs	/* not found */
57355163Sshin	return (NULL);
574118664Sume}
575118664Sume
57655163Sshin/**
57755163Sshin * Scan @p table for all quirk flags applicable to @p dev's chip identifier
578222732Shrs * (as returned by bhnd_get_chipid).
579118660Sume *
580118664Sume * @param dev A bhnd device.
581222732Shrs * @param table The chip quirk table to search.
58255163Sshin *
58355163Sshin * @return returns all matching quirk flags.
584222732Shrs */
58555163Sshinuint32_t
58655163Sshinbhnd_chip_quirks(device_t dev, const struct bhnd_chip_quirk *table)
58755163Sshin{
588118660Sume	struct bhnd_board_info		 bi, *board;
589222732Shrs	const struct bhnd_chipid	*cid;
590222732Shrs	const struct bhnd_chip_quirk	*qent;
59155163Sshin	uint32_t			 quirks;
592222732Shrs	int				 error;
59355163Sshin	bool				 need_boardinfo;
59455163Sshin
59555163Sshin	cid = bhnd_get_chipid(dev);
59655163Sshin	quirks = 0;
59755163Sshin	need_boardinfo = 0;
59855163Sshin	board = NULL;
59955163Sshin
60055163Sshin	/* Determine whether quirk matching requires board_info; we want to
60155163Sshin	 * avoid fetching board_info for early devices (e.g. ChipCommon)
60255163Sshin	 * that are brought up prior to NVRAM being readable. */
60355163Sshin	for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) {
604222732Shrs		if (!BHND_CHIP_MATCH_REQ_BOARD_INFO(&qent->chip))
60555163Sshin			continue;
606222732Shrs
60755163Sshin		need_boardinfo = true;
60855163Sshin		break;
609253970Shrs	}
610124524Sume
61155163Sshin	/* If required, fetch board info */
612253970Shrs	if (need_boardinfo) {
613253970Shrs		error = bhnd_read_board_info(dev, &bi);
614222732Shrs		if (!error) {
615222861Shrs			board = &bi;
616222732Shrs		} else {
61755163Sshin			device_printf(dev, "failed to read required board info "
61855163Sshin			    "during quirk matching: %d\n", error);
619253970Shrs		}
62055163Sshin	}
62155163Sshin
62255163Sshin	/* Apply all matching quirk flags */
623222732Shrs	for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) {
624253970Shrs		if (bhnd_chip_matches(cid, board, &qent->chip))
625222861Shrs			quirks |= qent->quirks;
626222861Shrs	}
62755163Sshin
628222861Shrs	return (quirks);
629222861Shrs}
630222861Shrs
631222861Shrs/**
632222861Shrs * Scan @p table for all quirk flags applicable to @p dev.
633222861Shrs *
634222861Shrs * @param dev A bhnd device to match against @p table.
635222861Shrs * @param table The device table to search.
636222861Shrs * @param entry_size The @p table entry size, in bytes.
637222861Shrs *
638222861Shrs * @return returns all matching quirk flags.
639222861Shrs */
640222732Shrsuint32_t
641222732Shrsbhnd_device_quirks(device_t dev, const struct bhnd_device *table,
64255163Sshin    size_t entry_size)
64355163Sshin{
64455163Sshin	const struct bhnd_device	*dent;
645222732Shrs	const struct bhnd_device_quirk	*qtable, *qent;
64655163Sshin	uint32_t			 quirks;
647222732Shrs	uint16_t			 hwrev;
64855163Sshin
649222732Shrs	hwrev = bhnd_get_hwrev(dev);
65055163Sshin	quirks = 0;
651222732Shrs
65255163Sshin	/* Find the quirk table */
65355163Sshin	if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL) {
65455163Sshin		/* This is almost certainly a (caller) implementation bug */
655222732Shrs		device_printf(dev, "quirk lookup did not match any device\n");
65655163Sshin		return (0);
65755163Sshin	}
658222732Shrs
65955163Sshin	/* Collect matching device quirk entries */
660222732Shrs	if ((qtable = dent->quirks_table) != NULL) {
661118660Sume		for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
662118664Sume			if (bhnd_hwrev_matches(hwrev, &qent->hwrev))
663118664Sume				quirks |= qent->quirks;
664222732Shrs		}
665222732Shrs	}
66655163Sshin
667222732Shrs	/* Collect matching chip quirk entries */
668222732Shrs	if (dent->chip_quirks_table != NULL)
669222732Shrs		quirks |= bhnd_chip_quirks(dev, dent->chip_quirks_table);
670222732Shrs
67155163Sshin	return (quirks);
672222732Shrs}
673222732Shrs
67455163Sshin
675222732Shrs/**
67655163Sshin * Allocate bhnd(4) resources defined in @p rs from a parent bus.
67755163Sshin *
678118661Sume * @param dev The device requesting ownership of the resources.
679118661Sume * @param rs A standard bus resource specification. This will be updated
680118661Sume * with the allocated resource's RIDs.
681118661Sume * @param res On success, the allocated bhnd resources.
682118661Sume *
683222732Shrs * @retval 0 success
684118661Sume * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
68555163Sshin * 		    all allocated resources will be released and a regular
686222732Shrs * 		    unix error code will be returned.
68755163Sshin */
68855163Sshinint
68955163Sshinbhnd_alloc_resources(device_t dev, struct resource_spec *rs,
690222732Shrs    struct bhnd_resource **res)
691222732Shrs{
69255163Sshin	/* Initialize output array */
69355163Sshin	for (u_int i = 0; rs[i].type != -1; i++)
694222732Shrs		res[i] = NULL;
695222732Shrs
69655163Sshin	for (u_int i = 0; rs[i].type != -1; i++) {
697118660Sume		res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
698118664Sume		    rs[i].flags);
699222732Shrs
700222732Shrs		/* Clean up all allocations on failure */
701222732Shrs		if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
70255163Sshin			bhnd_release_resources(dev, rs, res);
70355163Sshin			return (ENXIO);
70455163Sshin		}
705222732Shrs	}
706222732Shrs
707222732Shrs	return (0);
708222732Shrs};
709222732Shrs
710222861Shrs/**
711222861Shrs * Release bhnd(4) resources defined in @p rs from a parent bus.
712222732Shrs *
713222861Shrs * @param dev The device that owns the resources.
714222861Shrs * @param rs A standard bus resource specification previously initialized
715222861Shrs * by @p bhnd_alloc_resources.
716222861Shrs * @param res The bhnd resources to be released.
717253970Shrs */
718222861Shrsvoid
719222861Shrsbhnd_release_resources(device_t dev, const struct resource_spec *rs,
720222861Shrs    struct bhnd_resource **res)
721222861Shrs{
722222861Shrs	for (u_int i = 0; rs[i].type != -1; i++) {
723222861Shrs		if (res[i] == NULL)
724222861Shrs			continue;
725222861Shrs
726222861Shrs		bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
727222861Shrs		res[i] = NULL;
728222861Shrs	}
729222732Shrs}
730222732Shrs
731222732Shrs/**
732222732Shrs * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID
73355163Sshin * register, returning its bhnd_chipid representation.
734253970Shrs *
735222732Shrs * @param idreg The CHIPC_ID register value.
73655163Sshin * @param enum_addr The enumeration address to include in the result.
73755163Sshin *
738253970Shrs * @warning
739118660Sume * On early siba(4) devices, the ChipCommon core does not provide
740222732Shrs * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
741253970Shrs * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
74255163Sshin * an invalid `ncores` value.
743253970Shrs */
74455163Sshinstruct bhnd_chipid
745253970Shrsbhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
74655163Sshin{
747222861Shrs	struct bhnd_chipid result;
748253970Shrs
749222861Shrs	/* Fetch the basic chip info */
750222861Shrs	result.chip_id = CHIPC_GET_ATTR(idreg, ID_CHIP);
75155163Sshin	result.chip_pkg = CHIPC_GET_ATTR(idreg, ID_PKG);
752222732Shrs	result.chip_rev = CHIPC_GET_ATTR(idreg, ID_REV);
75355163Sshin	result.chip_type = CHIPC_GET_ATTR(idreg, ID_BUS);
75455163Sshin	result.ncores = CHIPC_GET_ATTR(idreg, ID_NUMCORE);
75555163Sshin
756222732Shrs	result.enum_addr = enum_addr;
75755163Sshin
75862632Skris	return (result);
75962632Skris}
76055163Sshin
761253970Shrs/**
76255163Sshin * Allocate the resource defined by @p rs via @p dev, use it
763222732Shrs * to read the ChipCommon ID register relative to @p chipc_offset,
76455163Sshin * then release the resource.
765222732Shrs *
76655163Sshin * @param dev The device owning @p rs.
76755163Sshin * @param rs A resource spec that encompasses the ChipCommon register block.
768222732Shrs * @param chipc_offset The offset of the ChipCommon registers within @p rs.
769222732Shrs * @param[out] result the chip identification data.
770222732Shrs *
771118664Sume * @retval 0 success
772222732Shrs * @retval non-zero if the ChipCommon identification data could not be read.
77355163Sshin */
77455163Sshinint
77555163Sshinbhnd_read_chipid(device_t dev, struct resource_spec *rs,
776118664Sume    bus_size_t chipc_offset, struct bhnd_chipid *result)
777222732Shrs{
77855163Sshin	struct resource			*res;
77955163Sshin	uint32_t			 reg;
780222732Shrs	int				 error, rid, rtype;
78155163Sshin
78255163Sshin	/* Allocate the ChipCommon window resource and fetch the chipid data */
78362632Skris	rid = rs->rid;
78455163Sshin	rtype = rs->type;
78562632Skris	res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
786180824Sache	if (res == NULL) {
78762632Skris		device_printf(dev,
788222732Shrs		    "failed to allocate bhnd chipc resource\n");
789253970Shrs		return (ENXIO);
79055163Sshin	}
79155163Sshin
792222732Shrs	/* Fetch the basic chip info */
793222732Shrs	reg = bus_read_4(res, chipc_offset + CHIPC_ID);
79478064Sume	*result = bhnd_parse_chipid(reg, 0x0);
79578064Sume
79678064Sume	/* Fetch the enum base address */
79778064Sume	error = 0;
798147150Ssuz	switch (result->chip_type) {
79978064Sume	case BHND_CHIPTYPE_SIBA:
80078064Sume		result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
80178064Sume		break;
802222732Shrs	case BHND_CHIPTYPE_BCMA:
80378064Sume	case BHND_CHIPTYPE_BCMA_ALT:
80455163Sshin		result->enum_addr = bus_read_4(res, chipc_offset +
80555163Sshin		    CHIPC_EROMPTR);
806118660Sume		break;
807118664Sume	case BHND_CHIPTYPE_UBUS:
808222732Shrs		device_printf(dev, "unsupported ubus/bcm63xx chip type");
80955163Sshin		error = ENODEV;
81055163Sshin		goto cleanup;
81155163Sshin	default:
81255163Sshin		device_printf(dev, "unknown chip type %hhu\n",
813253970Shrs		    result->chip_type);
814222732Shrs		error = ENODEV;
815118660Sume		goto cleanup;
816222732Shrs	}
817118664Sume
818253970Shrscleanup:
819253970Shrs	/* Clean up */
82055163Sshin	bus_release_resource(dev, rtype, rid, res);
821222861Shrs	return (error);
822253970Shrs}
823222861Shrs
824222861Shrs/**
82555163Sshin * Using the bhnd(4) bus-level core information and a custom core name,
82655163Sshin * populate @p dev's device description.
82755163Sshin *
82855163Sshin * @param dev A bhnd-bus attached device.
82955163Sshin * @param dev_name The core's name (e.g. "SDIO Device Core")
83055163Sshin */
83162632Skrisvoid
83255163Sshinbhnd_set_custom_core_desc(device_t dev, const char *dev_name)
833124526Sume{
83455163Sshin	const char *vendor_name;
835204407Suqs	char *desc;
83655163Sshin
83755163Sshin	vendor_name = bhnd_get_vendor_name(dev);
83855163Sshin	asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name,
839124526Sume	    bhnd_get_hwrev(dev));
84055163Sshin
84155163Sshin	if (desc != NULL) {
842222732Shrs		device_set_desc_copy(dev, desc);
84355163Sshin		free(desc, M_BHND);
844222732Shrs	} else {
845222732Shrs		device_set_desc(dev, dev_name);
846222732Shrs	}
847222732Shrs}
848222732Shrs
849222732Shrs/**
850222732Shrs * Using the bhnd(4) bus-level core information, populate @p dev's device
851222732Shrs * description.
852222732Shrs *
853222732Shrs * @param dev A bhnd-bus attached device.
854222732Shrs */
85555163Sshinvoid
85655163Sshinbhnd_set_default_core_desc(device_t dev)
85755163Sshin{
85855163Sshin	bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
85955163Sshin}
86055163Sshin
86155163Sshin/**
86255163Sshin * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
86355163Sshin *
86455163Sshin * If a parent device is available, this implementation delegates the
86555163Sshin * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
86655163Sshin *
86755163Sshin * If no parent device is available (i.e. on a the bus root), the hardware
86855163Sshin * is assumed to be usable and false is returned.
86955163Sshin */
87055163Sshinbool
87166776Skrisbhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
87266776Skris{
87355163Sshin	if (device_get_parent(dev) != NULL)
87455163Sshin		return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
87555163Sshin
87666776Skris	return (false);
877119026Sume}
878119026Sume
879119026Sume/**
880119026Sume * Helper function for implementing BHND_BUS_GET_CHIPID().
881124524Sume *
88266776Skris * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
883119026Sume * method on the parent of @p dev. If no parent exists, the implementation
884119026Sume * will panic.
885119026Sume */
886204407Suqsconst struct bhnd_chipid *
887230357Seadlerbhnd_bus_generic_get_chipid(device_t dev, device_t child)
888203387Sume{
88966776Skris	if (device_get_parent(dev) != NULL)
890119026Sume		return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
891119026Sume
892119026Sume	panic("missing BHND_BUS_GET_CHIPID()");
893119026Sume}
894119026Sume
895119026Sume/* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
896119026Sume#define	BHND_GV(_dest, _name)	\
897119026Sume	bhnd_nvram_getvar(child, BHND_NVAR_ ## _name, &_dest, sizeof(_dest))
898119026Sume
89966776Skris#define	REQ_BHND_GV(_dest, _name)		do {			\
900222732Shrs	if ((error = BHND_GV(_dest, _name))) {				\
90166776Skris		device_printf(dev,					\
902203387Sume		    "error reading " __STRING(_name) ": %d\n", error);	\
903222732Shrs		return (error);						\
904222732Shrs	}								\
905203387Sume} while(0)
906203387Sume
90766776Skris#define	OPT_BHND_GV(_dest, _name, _default)	do {			\
90866776Skris	if ((error = BHND_GV(_dest, _name))) {				\
90966776Skris		if (error != ENOENT) {					\
91066776Skris			device_printf(dev,				\
91166776Skris			    "error reading "				\
91266776Skris			       __STRING(_name) ": %d\n", error);	\
91366776Skris			return (error);					\
91466776Skris		}							\
91566776Skris		_dest = _default;					\
91666776Skris	}								\
91766776Skris} while(0)
91866776Skris
91966776Skris/**
92066776Skris * Helper function for implementing BHND_BUS_READ_BOARDINFO().
921119026Sume *
922119026Sume * This implementation populates @p info with information from NVRAM,
923119026Sume * defaulting board_vendor and board_type fields to 0 if the
924119026Sume * requested variables cannot be found.
925119026Sume *
926119026Sume * This behavior is correct for most SoCs, but must be overridden on
927119026Sume * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
928119026Sume * result.
92966776Skris */
93066776Skrisint
931203387Sumebhnd_bus_generic_read_board_info(device_t dev, device_t child,
932203387Sume    struct bhnd_board_info *info)
933203387Sume{
934203387Sume	int	error;
935203387Sume
936203387Sume	OPT_BHND_GV(info->board_vendor,	BOARDVENDOR,	0);
937203387Sume	OPT_BHND_GV(info->board_type,	BOARDTYPE,	0);	/* srom >= 2 */
938203387Sume	REQ_BHND_GV(info->board_rev,	BOARDREV);
939222732Shrs	REQ_BHND_GV(info->board_srom_rev,SROMREV);
940222732Shrs	REQ_BHND_GV(info->board_flags,	BOARDFLAGS);
941222732Shrs	OPT_BHND_GV(info->board_flags2,	BOARDFLAGS2,	0);	/* srom >= 4 */
942203387Sume	OPT_BHND_GV(info->board_flags3,	BOARDFLAGS3,	0);	/* srom >= 11 */
943203387Sume
944203387Sume	return (0);
945203387Sume}
946203387Sume
947203387Sume#undef	BHND_GV
948203387Sume#undef	BHND_GV_REQ
949119026Sume#undef	BHND_GV_OPT
950119026Sume
951222732Shrs
952222732Shrs/**
953119026Sume * Find an NVRAM child device on @p dev, if any.
954119026Sume *
955222732Shrs * @retval device_t An NVRAM device.
956222732Shrs * @retval NULL If no NVRAM device is found.
957222732Shrs */
958222732Shrsstatic device_t
959119026Sumefind_nvram_child(device_t dev)
960119026Sume{
961222732Shrs	device_t	chipc, nvram;
962222732Shrs
963222732Shrs	/* Look for a directly-attached NVRAM child */
964222732Shrs	nvram = device_find_child(dev, "bhnd_nvram", 0);
965119026Sume	if (nvram != NULL)
96666776Skris		return (nvram);
96766776Skris
968119026Sume	/* Remaining checks are only applicable when searching a bhnd(4)
969119026Sume	 * bus. */
970222732Shrs	if (device_get_devclass(dev) != bhnd_devclass)
971222732Shrs		return (NULL);
972222732Shrs
973222732Shrs	/* Look for a ChipCommon device */
974119026Sume	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
975119026Sume		bhnd_nvram_src_t src;
97666776Skris
977119026Sume		/* Query the NVRAM source and determine whether it's
978119026Sume		 * accessible via the ChipCommon device */
979222732Shrs		src = BHND_CHIPC_NVRAM_SRC(chipc);
980222732Shrs		if (BHND_NVRAM_SRC_CC(src))
981119026Sume			return (chipc);
98266776Skris	}
983203387Sume
984203387Sume	/* Not found */
98566776Skris	return (NULL);
986222732Shrs}
98766776Skris
988/**
989 * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
990 *
991 * This implementation searches @p dev for a usable NVRAM child device:
992 * - The first child device implementing the bhnd_nvram devclass is
993 *   returned, otherwise
994 * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an
995 *   attached NVRAM source.
996 *
997 * If no usable child device is found on @p dev, the request is delegated to
998 * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
999 */
1000int
1001bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
1002    void *buf, size_t *size)
1003{
1004	device_t	nvram;
1005	device_t	parent;
1006
1007	/* Try to find an NVRAM device applicable to @p child */
1008	if ((nvram = find_nvram_child(dev)) != NULL)
1009		return BHND_NVRAM_GETVAR(nvram, name, buf, size);
1010
1011	/* Try to delegate to parent */
1012	if ((parent = device_get_parent(dev)) == NULL)
1013		return (ENODEV);
1014
1015	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
1016	    name, buf, size));
1017}
1018
1019/**
1020 * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
1021 *
1022 * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
1023 * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
1024 * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
1025 */
1026struct bhnd_resource *
1027bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
1028	int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
1029	u_int flags)
1030{
1031	struct bhnd_resource	*br;
1032	struct resource		*res;
1033	int			 error;
1034
1035	br = NULL;
1036	res = NULL;
1037
1038	/* Allocate the real bus resource (without activating it) */
1039	res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
1040	    (flags & ~RF_ACTIVE));
1041	if (res == NULL)
1042		return (NULL);
1043
1044	/* Allocate our bhnd resource wrapper. */
1045	br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
1046	if (br == NULL)
1047		goto failed;
1048
1049	br->direct = false;
1050	br->res = res;
1051
1052	/* Attempt activation */
1053	if (flags & RF_ACTIVE) {
1054		error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
1055		if (error)
1056			goto failed;
1057	}
1058
1059	return (br);
1060
1061failed:
1062	if (res != NULL)
1063		BUS_RELEASE_RESOURCE(dev, child, type, *rid, res);
1064
1065	free(br, M_BHND);
1066	return (NULL);
1067}
1068
1069/**
1070 * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
1071 *
1072 * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
1073 * the backing resource to BUS_RELEASE_RESOURCE().
1074 */
1075int
1076bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
1077    int rid, struct bhnd_resource *r)
1078{
1079	int error;
1080
1081	if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res)))
1082		return (error);
1083
1084	free(r, M_BHND);
1085	return (0);
1086}
1087
1088
1089/**
1090 * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
1091 *
1092 * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1093 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1094 */
1095int
1096bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
1097    int rid, struct bhnd_resource *r)
1098{
1099	/* Try to delegate to the parent */
1100	if (device_get_parent(dev) != NULL)
1101		return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
1102		    child, type, rid, r));
1103
1104	return (EINVAL);
1105};
1106
1107/**
1108 * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
1109 *
1110 * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1111 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1112 */
1113int
1114bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
1115    int type, int rid, struct bhnd_resource *r)
1116{
1117	if (device_get_parent(dev) != NULL)
1118		return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
1119		    child, type, rid, r));
1120
1121	return (EINVAL);
1122};
1123