bhnd_subr.c revision 300548
1/*-
2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 *    redistribution must be conditioned upon including a substantially
14 *    similar Disclaimer requirement for further binary redistribution.
15 *
16 * NO WARRANTY
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/bhnd/bhnd_subr.c 300548 2016-05-24 01:12:19Z adrian $");
32
33#include <sys/types.h>
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/systm.h>
37
38#include <machine/bus.h>
39#include <sys/rman.h>
40#include <machine/resource.h>
41
42#include <dev/bhnd/cores/chipc/chipcreg.h>
43
44#include "nvram/bhnd_nvram.h"
45
46#include "bhnd_chipc_if.h"
47
48#include "bhnd_nvram_if.h"
49#include "bhnd_nvram_map.h"
50
51#include "bhndreg.h"
52#include "bhndvar.h"
53
54static device_t		find_nvram_child(device_t dev);
55
56/* BHND core device description table. */
57static const struct bhnd_core_desc {
58	uint16_t	 vendor;
59	uint16_t	 device;
60	bhnd_devclass_t	 class;
61	const char	*desc;
62} bhnd_core_descs[] = {
63	#define	BHND_CDESC(_mfg, _cid, _cls, _desc)		\
64	    { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid,	\
65		BHND_DEVCLASS_ ## _cls, _desc }
66
67	BHND_CDESC(BCM, CC,		CC,		"ChipCommon I/O Controller"),
68	BHND_CDESC(BCM, ILINE20,	OTHER,		"iLine20 HPNA"),
69	BHND_CDESC(BCM, SRAM,		RAM,		"SRAM"),
70	BHND_CDESC(BCM, SDRAM,		RAM,		"SDRAM"),
71	BHND_CDESC(BCM, PCI,		PCI,		"PCI Bridge"),
72	BHND_CDESC(BCM, MIPS,		CPU,		"MIPS Core"),
73	BHND_CDESC(BCM, ENET,		ENET_MAC,	"Fast Ethernet MAC"),
74	BHND_CDESC(BCM, CODEC,		OTHER,		"V.90 Modem Codec"),
75	BHND_CDESC(BCM, USB,		OTHER,		"USB 1.1 Device/Host Controller"),
76	BHND_CDESC(BCM, ADSL,		OTHER,		"ADSL Core"),
77	BHND_CDESC(BCM, ILINE100,	OTHER,		"iLine100 HPNA"),
78	BHND_CDESC(BCM, IPSEC,		OTHER,		"IPsec Accelerator"),
79	BHND_CDESC(BCM, UTOPIA,		OTHER,		"UTOPIA ATM Core"),
80	BHND_CDESC(BCM, PCMCIA,		PCCARD,		"PCMCIA Bridge"),
81	BHND_CDESC(BCM, SOCRAM,		RAM,		"Internal Memory"),
82	BHND_CDESC(BCM, MEMC,		MEMC,		"MEMC SDRAM Controller"),
83	BHND_CDESC(BCM, OFDM,		OTHER,		"OFDM PHY"),
84	BHND_CDESC(BCM, EXTIF,		OTHER,		"External Interface"),
85	BHND_CDESC(BCM, D11,		WLAN,		"802.11 MAC/PHY/Radio"),
86	BHND_CDESC(BCM, APHY,		WLAN_PHY,	"802.11a PHY"),
87	BHND_CDESC(BCM, BPHY,		WLAN_PHY,	"802.11b PHY"),
88	BHND_CDESC(BCM, GPHY,		WLAN_PHY,	"802.11g PHY"),
89	BHND_CDESC(BCM, MIPS33,		CPU,		"MIPS 3302 Core"),
90	BHND_CDESC(BCM, USB11H,		OTHER,		"USB 1.1 Host Controller"),
91	BHND_CDESC(BCM, USB11D,		OTHER,		"USB 1.1 Device Core"),
92	BHND_CDESC(BCM, USB20H,		OTHER,		"USB 2.0 Host Controller"),
93	BHND_CDESC(BCM, USB20D,		OTHER,		"USB 2.0 Device Core"),
94	BHND_CDESC(BCM, SDIOH,		OTHER,		"SDIO Host Controller"),
95	BHND_CDESC(BCM, ROBO,		OTHER,		"RoboSwitch"),
96	BHND_CDESC(BCM, ATA100,		OTHER,		"Parallel ATA Controller"),
97	BHND_CDESC(BCM, SATAXOR,	OTHER,		"SATA DMA/XOR Controller"),
98	BHND_CDESC(BCM, GIGETH,		ENET_MAC,	"Gigabit Ethernet MAC"),
99	BHND_CDESC(BCM, PCIE,		PCIE,		"PCIe Bridge"),
100	BHND_CDESC(BCM, NPHY,		WLAN_PHY,	"802.11n 2x2 PHY"),
101	BHND_CDESC(BCM, SRAMC,		MEMC,		"SRAM Controller"),
102	BHND_CDESC(BCM, MINIMAC,	OTHER,		"MINI MAC/PHY"),
103	BHND_CDESC(BCM, ARM11,		CPU,		"ARM1176 CPU"),
104	BHND_CDESC(BCM, ARM7S,		CPU,		"ARM7TDMI-S CPU"),
105	BHND_CDESC(BCM, LPPHY,		WLAN_PHY,	"802.11a/b/g PHY"),
106	BHND_CDESC(BCM, PMU,		PMU,		"PMU"),
107	BHND_CDESC(BCM, SSNPHY,		WLAN_PHY,	"802.11n Single-Stream PHY"),
108	BHND_CDESC(BCM, SDIOD,		OTHER,		"SDIO Device Core"),
109	BHND_CDESC(BCM, ARMCM3,		CPU,		"ARM Cortex-M3 CPU"),
110	BHND_CDESC(BCM, HTPHY,		WLAN_PHY,	"802.11n 4x4 PHY"),
111	BHND_CDESC(BCM, MIPS74K,	CPU,		"MIPS74k CPU"),
112	BHND_CDESC(BCM, GMAC,		ENET_MAC,	"Gigabit MAC core"),
113	BHND_CDESC(BCM, DMEMC,		MEMC,		"DDR1/DDR2 Memory Controller"),
114	BHND_CDESC(BCM, PCIERC,		OTHER,		"PCIe Root Complex"),
115	BHND_CDESC(BCM, OCP,		SOC_BRIDGE,	"OCP to OCP Bridge"),
116	BHND_CDESC(BCM, SC,		OTHER,		"Shared Common Core"),
117	BHND_CDESC(BCM, AHB,		SOC_BRIDGE,	"OCP to AHB Bridge"),
118	BHND_CDESC(BCM, SPIH,		OTHER,		"SPI Host Controller"),
119	BHND_CDESC(BCM, I2S,		OTHER,		"I2S Digital Audio Interface"),
120	BHND_CDESC(BCM, DMEMS,		MEMC,		"SDR/DDR1 Memory Controller"),
121	BHND_CDESC(BCM, UBUS_SHIM,	OTHER,		"BCM6362/UBUS WLAN SHIM"),
122	BHND_CDESC(BCM, PCIE2,		PCIE,		"PCIe Bridge (Gen2)"),
123
124	BHND_CDESC(ARM, APB_BRIDGE,	SOC_BRIDGE,	"BP135 AMBA3 AXI to APB Bridge"),
125	BHND_CDESC(ARM, PL301,		SOC_ROUTER,	"PL301 AMBA3 Interconnect"),
126	BHND_CDESC(ARM, EROM,		EROM,		"PL366 Device Enumeration ROM"),
127	BHND_CDESC(ARM, OOB_ROUTER,	OTHER,		"PL367 OOB Interrupt Router"),
128	BHND_CDESC(ARM, AXI_UNMAPPED,	OTHER,		"Unmapped Address Ranges"),
129
130	BHND_CDESC(BCM, 4706_CC,	CC,		"ChipCommon I/O Controller"),
131	BHND_CDESC(BCM, NS_PCIE2,	PCIE,		"PCIe Bridge (Gen2)"),
132	BHND_CDESC(BCM, NS_DMA,		OTHER,		"DMA engine"),
133	BHND_CDESC(BCM, NS_SDIO,	OTHER,		"SDIO 3.0 Host Controller"),
134	BHND_CDESC(BCM, NS_USB20H,	OTHER,		"USB 2.0 Host Controller"),
135	BHND_CDESC(BCM, NS_USB30H,	OTHER,		"USB 3.0 Host Controller"),
136	BHND_CDESC(BCM, NS_A9JTAG,	OTHER,		"ARM Cortex A9 JTAG Interface"),
137	BHND_CDESC(BCM, NS_DDR23_MEMC,	MEMC,		"Denali DDR2/DD3 Memory Controller"),
138	BHND_CDESC(BCM, NS_ROM,		NVRAM,		"System ROM"),
139	BHND_CDESC(BCM, NS_NAND,	NVRAM,		"NAND Flash Controller"),
140	BHND_CDESC(BCM, NS_QSPI,	NVRAM,		"QSPI Flash Controller"),
141	BHND_CDESC(BCM, NS_CC_B,	CC_B,		"ChipCommon B Auxiliary I/O Controller"),
142	BHND_CDESC(BCM, 4706_SOCRAM,	RAM,		"Internal Memory"),
143	BHND_CDESC(BCM, IHOST_ARMCA9,	CPU,		"ARM Cortex A9 CPU"),
144	BHND_CDESC(BCM, 4706_GMAC_CMN,	ENET,		"Gigabit MAC (Common)"),
145	BHND_CDESC(BCM, 4706_GMAC,	ENET_MAC,	"Gigabit MAC"),
146	BHND_CDESC(BCM, AMEMC,		MEMC,		"Denali DDR1/DDR2 Memory Controller"),
147#undef	BHND_CDESC
148
149	/* Derived from inspection of the BCM4331 cores that provide PrimeCell
150	 * IDs. Due to lack of documentation, the surmised device name/purpose
151	 * provided here may be incorrect. */
152	{ BHND_MFGID_ARM,	BHND_PRIMEID_EROM,	BHND_DEVCLASS_OTHER,
153	    "PL364 Device Enumeration ROM" },
154	{ BHND_MFGID_ARM,	BHND_PRIMEID_SWRAP,	BHND_DEVCLASS_OTHER,
155	    "PL368 Device Management Interface" },
156	{ BHND_MFGID_ARM,	BHND_PRIMEID_MWRAP,	BHND_DEVCLASS_OTHER,
157	    "PL369 Device Management Interface" },
158
159	{ 0, 0, 0, NULL }
160};
161
162/**
163 * Return the name for a given JEP106 manufacturer ID.
164 *
165 * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
166 * JEP106 continuation code.
167 */
168const char *
169bhnd_vendor_name(uint16_t vendor)
170{
171	switch (vendor) {
172	case BHND_MFGID_ARM:
173		return "ARM";
174	case BHND_MFGID_BCM:
175		return "Broadcom";
176	case BHND_MFGID_MIPS:
177		return "MIPS";
178	default:
179		return "unknown";
180	}
181}
182
183/**
184 * Return the name of a port type.
185 */
186const char *
187bhnd_port_type_name(bhnd_port_type port_type)
188{
189	switch (port_type) {
190	case BHND_PORT_DEVICE:
191		return ("device");
192	case BHND_PORT_BRIDGE:
193		return ("bridge");
194	case BHND_PORT_AGENT:
195		return ("agent");
196	default:
197		return "unknown";
198	}
199}
200
201
202static const struct bhnd_core_desc *
203bhnd_find_core_desc(uint16_t vendor, uint16_t device)
204{
205	for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
206		if (bhnd_core_descs[i].vendor != vendor)
207			continue;
208
209		if (bhnd_core_descs[i].device != device)
210			continue;
211
212		return (&bhnd_core_descs[i]);
213	}
214
215	return (NULL);
216}
217
218/**
219 * Return a human-readable name for a BHND core.
220 *
221 * @param vendor The core designer's JEDEC-106 Manufacturer ID
222 * @param device The core identifier.
223 */
224const char *
225bhnd_find_core_name(uint16_t vendor, uint16_t device)
226{
227	const struct bhnd_core_desc *desc;
228
229	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
230		return ("unknown");
231
232	return desc->desc;
233}
234
235/**
236 * Return the device class for a BHND core.
237 *
238 * @param vendor The core designer's JEDEC-106 Manufacturer ID
239 * @param device The core identifier.
240 */
241bhnd_devclass_t
242bhnd_find_core_class(uint16_t vendor, uint16_t device)
243{
244	const struct bhnd_core_desc *desc;
245
246	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
247		return (BHND_DEVCLASS_OTHER);
248
249	return desc->class;
250}
251
252/**
253 * Return a human-readable name for a BHND core.
254 *
255 * @param ci The core's info record.
256 */
257const char *
258bhnd_core_name(const struct bhnd_core_info *ci)
259{
260	return bhnd_find_core_name(ci->vendor, ci->device);
261}
262
263/**
264 * Return the device class for a BHND core.
265 *
266 * @param ci The core's info record.
267 */
268bhnd_devclass_t
269bhnd_core_class(const struct bhnd_core_info *ci)
270{
271	return bhnd_find_core_class(ci->vendor, ci->device);
272}
273
274/**
275 * Initialize a core info record with data from from a bhnd-attached @p dev.
276 *
277 * @param dev A bhnd device.
278 * @param core The record to be initialized.
279 */
280struct bhnd_core_info
281bhnd_get_core_info(device_t dev) {
282	return (struct bhnd_core_info) {
283		.vendor		= bhnd_get_vendor(dev),
284		.device		= bhnd_get_device(dev),
285		.hwrev		= bhnd_get_hwrev(dev),
286		.core_idx	= bhnd_get_core_index(dev),
287		.unit		= bhnd_get_core_unit(dev)
288	};
289}
290
291/**
292 * Find a @p class child device with @p unit on @p dev.
293 *
294 * @param parent The bhnd-compatible bus to be searched.
295 * @param class The device class to match on.
296 * @param unit The device unit number; specify -1 to return the first match
297 * regardless of unit number.
298 *
299 * @retval device_t if a matching child device is found.
300 * @retval NULL if no matching child device is found.
301 */
302device_t
303bhnd_find_child(device_t dev, bhnd_devclass_t class, int unit)
304{
305	struct bhnd_core_match md = {
306		.vendor = BHND_MFGID_INVALID,
307		.device = BHND_COREID_INVALID,
308		.hwrev.start = BHND_HWREV_INVALID,
309		.hwrev.end = BHND_HWREV_INVALID,
310		.class = class,
311		.unit = unit
312	};
313
314	return bhnd_match_child(dev, &md);
315}
316
317/**
318 * Find the first child device on @p dev that matches @p desc.
319 *
320 * @param parent The bhnd-compatible bus to be searched.
321 * @param desc A match descriptor.
322 *
323 * @retval device_t if a matching child device is found.
324 * @retval NULL if no matching child device is found.
325 */
326device_t
327bhnd_match_child(device_t dev, const struct bhnd_core_match *desc)
328{
329	device_t	*devlistp;
330	device_t	 match;
331	int		 devcnt;
332	int		 error;
333
334	error = device_get_children(dev, &devlistp, &devcnt);
335	if (error != 0)
336		return (NULL);
337
338	match = NULL;
339	for (int i = 0; i < devcnt; i++) {
340		device_t dev = devlistp[i];
341		if (bhnd_device_matches(dev, desc)) {
342			match = dev;
343			goto done;
344		}
345	}
346
347done:
348	free(devlistp, M_TEMP);
349	return match;
350}
351
352/**
353 * Walk up the bhnd device hierarchy to locate the root device
354 * to which the bhndb bridge is attached.
355 *
356 * This can be used from within bhnd host bridge drivers to locate the
357 * actual upstream host device.
358 *
359 * @param dev A bhnd device.
360 * @param bus_class The expected bus (e.g. "pci") to which the bridge root
361 * should be attached.
362 *
363 * @retval device_t if a matching parent device is found.
364 * @retval NULL @p dev is not attached via a bhndb bus
365 * @retval NULL no parent device is attached via @p bus_class.
366 */
367device_t
368bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
369{
370	devclass_t	bhndb_class;
371	device_t	parent;
372
373	KASSERT(device_get_devclass(device_get_parent(dev)) == bhnd_devclass,
374	   ("%s not a bhnd device", device_get_nameunit(dev)));
375
376	bhndb_class = devclass_find("bhndb");
377
378	/* Walk the device tree until we hit a bridge */
379	parent = dev;
380	while ((parent = device_get_parent(parent)) != NULL) {
381		if (device_get_devclass(parent) == bhndb_class)
382			break;
383	}
384
385	/* No bridge? */
386	if (parent == NULL)
387		return (NULL);
388
389	/* Search for a parent attached to the expected bus class */
390	while ((parent = device_get_parent(parent)) != NULL) {
391		device_t bus;
392
393		bus = device_get_parent(parent);
394		if (bus != NULL && device_get_devclass(bus) == bus_class)
395			return (parent);
396	}
397
398	/* Not found */
399	return (NULL);
400}
401
402/**
403 * Find the first core in @p cores that matches @p desc.
404 *
405 * @param cores The table to search.
406 * @param num_cores The length of @p cores.
407 * @param desc A match descriptor.
408 *
409 * @retval bhnd_core_info if a matching core is found.
410 * @retval NULL if no matching core is found.
411 */
412const struct bhnd_core_info *
413bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
414    const struct bhnd_core_match *desc)
415{
416	for (u_int i = 0; i < num_cores; i++) {
417		if (bhnd_core_matches(&cores[i], desc))
418			return &cores[i];
419	}
420
421	return (NULL);
422}
423
424
425/**
426 * Find the first core in @p cores with the given @p class.
427 *
428 * @param cores The table to search.
429 * @param num_cores The length of @p cores.
430 * @param desc A match descriptor.
431 *
432 * @retval bhnd_core_info if a matching core is found.
433 * @retval NULL if no matching core is found.
434 */
435const struct bhnd_core_info *
436bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
437    bhnd_devclass_t class)
438{
439	struct bhnd_core_match md = {
440		.vendor = BHND_MFGID_INVALID,
441		.device = BHND_COREID_INVALID,
442		.hwrev.start = BHND_HWREV_INVALID,
443		.hwrev.end = BHND_HWREV_INVALID,
444		.class = class,
445		.unit = -1
446	};
447
448	return bhnd_match_core(cores, num_cores, &md);
449}
450
451/**
452 * Return true if the @p core matches @p desc.
453 *
454 * @param core A bhnd core descriptor.
455 * @param desc A match descriptor to compare against @p core.
456 *
457 * @retval true if @p core matches @p match
458 * @retval false if @p core does not match @p match.
459 */
460bool
461bhnd_core_matches(const struct bhnd_core_info *core,
462    const struct bhnd_core_match *desc)
463{
464	if (desc->vendor != BHND_MFGID_INVALID &&
465	    desc->vendor != core->vendor)
466		return (false);
467
468	if (desc->device != BHND_COREID_INVALID &&
469	    desc->device != core->device)
470		return (false);
471
472	if (desc->unit != -1 && desc->unit != core->unit)
473		return (false);
474
475	if (!bhnd_hwrev_matches(core->hwrev, &desc->hwrev))
476		return (false);
477
478	if (desc->class != BHND_DEVCLASS_INVALID &&
479	    desc->class != bhnd_core_class(core))
480		return (false);
481
482	return true;
483}
484
485/**
486 * Return true if the @p chip matches @p desc.
487 *
488 * @param chip A bhnd chip identifier.
489 * @param board The bhnd board info, or NULL if unavailable.
490 * @param desc A match descriptor to compare against @p chip.
491 *
492 * @retval true if @p chip matches @p match
493 * @retval false if @p chip does not match @p match.
494 */
495bool
496bhnd_chip_matches(const struct bhnd_chipid *chip,
497    const struct bhnd_board_info *board,
498    const struct bhnd_chip_match *desc)
499{
500	/* Explicit wildcard match */
501	if (desc->match_any)
502		return (true);
503
504	/* If board_info is missing, but required, we cannot match. */
505	if (BHND_CHIP_MATCH_REQ_BOARD_INFO(desc) && board == NULL)
506		return (false);
507
508
509	/* Chip matching */
510	if (desc->match_id && chip->chip_id != desc->chip_id)
511		return (false);
512
513	if (desc->match_pkg && chip->chip_pkg != desc->chip_pkg)
514		return (false);
515
516	if (desc->match_rev &&
517	    !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
518		return (false);
519
520
521	/* Board info matching */
522	if (desc->match_srom_rev &&
523	    !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
524		return (false);
525
526	if (desc->match_bvendor && board->board_vendor != desc->board_vendor)
527		return (false);
528
529	if (desc->match_btype && board->board_type != desc->board_type)
530		return (false);
531
532	if (desc->match_brev &&
533	    !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
534		return (false);
535
536
537	return (true);
538}
539
540/**
541 * Return true if the @p hwrev matches @p desc.
542 *
543 * @param hwrev A bhnd hardware revision.
544 * @param desc A match descriptor to compare against @p core.
545 *
546 * @retval true if @p hwrev matches @p match
547 * @retval false if @p hwrev does not match @p match.
548 */
549bool
550bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
551{
552	if (desc->start != BHND_HWREV_INVALID &&
553	    desc->start > hwrev)
554		return false;
555
556	if (desc->end != BHND_HWREV_INVALID &&
557	    desc->end < hwrev)
558		return false;
559
560	return true;
561}
562
563/**
564 * Return true if the @p dev matches @p desc.
565 *
566 * @param dev A bhnd device.
567 * @param desc A match descriptor to compare against @p dev.
568 *
569 * @retval true if @p dev matches @p match
570 * @retval false if @p dev does not match @p match.
571 */
572bool
573bhnd_device_matches(device_t dev, const struct bhnd_core_match *desc)
574{
575	struct bhnd_core_info ci = {
576		.vendor = bhnd_get_vendor(dev),
577		.device = bhnd_get_device(dev),
578		.unit = bhnd_get_core_unit(dev),
579		.hwrev = bhnd_get_hwrev(dev)
580	};
581
582	return bhnd_core_matches(&ci, desc);
583}
584
585/**
586 * Search @p table for an entry matching @p dev.
587 *
588 * @param dev A bhnd device to match against @p table.
589 * @param table The device table to search.
590 * @param entry_size The @p table entry size, in bytes.
591 *
592 * @retval bhnd_device the first matching device, if any.
593 * @retval NULL if no matching device is found in @p table.
594 */
595const struct bhnd_device *
596bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
597    size_t entry_size)
598{
599	const struct bhnd_device	*entry;
600	device_t			 hostb, parent;
601
602	parent = device_get_parent(dev);
603	hostb = bhnd_find_hostb_device(parent);
604
605	for (entry = table; entry->desc != NULL; entry =
606	    (const struct bhnd_device *) ((const char *) entry + entry_size))
607	{
608		/* match core info */
609		if (!bhnd_device_matches(dev, &entry->core))
610			continue;
611
612		/* match device flags */
613		if (entry->device_flags & BHND_DF_HOSTB) {
614			if (dev != hostb)
615				continue;
616		}
617
618		/* device found */
619		return (entry);
620	}
621
622	/* not found */
623	return (NULL);
624}
625
626/**
627 * Scan @p table for all quirk flags applicable to @p dev's chip identifier
628 * (as returned by bhnd_get_chipid).
629 *
630 * @param dev A bhnd device.
631 * @param table The chip quirk table to search.
632 *
633 * @return returns all matching quirk flags.
634 */
635uint32_t
636bhnd_chip_quirks(device_t dev, const struct bhnd_chip_quirk *table)
637{
638	struct bhnd_board_info		 bi, *board;
639	const struct bhnd_chipid	*cid;
640	const struct bhnd_chip_quirk	*qent;
641	uint32_t			 quirks;
642	int				 error;
643	bool				 need_boardinfo;
644
645	cid = bhnd_get_chipid(dev);
646	quirks = 0;
647	need_boardinfo = 0;
648	board = NULL;
649
650	/* Determine whether quirk matching requires board_info; we want to
651	 * avoid fetching board_info for early devices (e.g. ChipCommon)
652	 * that are brought up prior to NVRAM being readable. */
653	for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) {
654		if (!BHND_CHIP_MATCH_REQ_BOARD_INFO(&qent->chip))
655			continue;
656
657		need_boardinfo = true;
658		break;
659	}
660
661	/* If required, fetch board info */
662	if (need_boardinfo) {
663		error = bhnd_read_board_info(dev, &bi);
664		if (!error) {
665			board = &bi;
666		} else {
667			device_printf(dev, "failed to read required board info "
668			    "during quirk matching: %d\n", error);
669		}
670	}
671
672	/* Apply all matching quirk flags */
673	for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) {
674		if (bhnd_chip_matches(cid, board, &qent->chip))
675			quirks |= qent->quirks;
676	}
677
678	return (quirks);
679}
680
681/**
682 * Scan @p table for all quirk flags applicable to @p dev.
683 *
684 * @param dev A bhnd device to match against @p table.
685 * @param table The device table to search.
686 * @param entry_size The @p table entry size, in bytes.
687 *
688 * @return returns all matching quirk flags.
689 */
690uint32_t
691bhnd_device_quirks(device_t dev, const struct bhnd_device *table,
692    size_t entry_size)
693{
694	const struct bhnd_device	*dent;
695	const struct bhnd_device_quirk	*qtable, *qent;
696	uint32_t			 quirks;
697	uint16_t			 hwrev;
698
699	hwrev = bhnd_get_hwrev(dev);
700	quirks = 0;
701
702	/* Find the quirk table */
703	if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL) {
704		/* This is almost certainly a (caller) implementation bug */
705		device_printf(dev, "quirk lookup did not match any device\n");
706		return (0);
707	}
708
709	/* Collect matching device quirk entries */
710	if ((qtable = dent->quirks_table) != NULL) {
711		for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
712			if (bhnd_hwrev_matches(hwrev, &qent->hwrev))
713				quirks |= qent->quirks;
714		}
715	}
716
717	/* Collect matching chip quirk entries */
718	if (dent->chip_quirks_table != NULL)
719		quirks |= bhnd_chip_quirks(dev, dent->chip_quirks_table);
720
721	return (quirks);
722}
723
724
725/**
726 * Allocate bhnd(4) resources defined in @p rs from a parent bus.
727 *
728 * @param dev The device requesting ownership of the resources.
729 * @param rs A standard bus resource specification. This will be updated
730 * with the allocated resource's RIDs.
731 * @param res On success, the allocated bhnd resources.
732 *
733 * @retval 0 success
734 * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
735 * 		    all allocated resources will be released and a regular
736 * 		    unix error code will be returned.
737 */
738int
739bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
740    struct bhnd_resource **res)
741{
742	/* Initialize output array */
743	for (u_int i = 0; rs[i].type != -1; i++)
744		res[i] = NULL;
745
746	for (u_int i = 0; rs[i].type != -1; i++) {
747		res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
748		    rs[i].flags);
749
750		/* Clean up all allocations on failure */
751		if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
752			bhnd_release_resources(dev, rs, res);
753			return (ENXIO);
754		}
755	}
756
757	return (0);
758};
759
760/**
761 * Release bhnd(4) resources defined in @p rs from a parent bus.
762 *
763 * @param dev The device that owns the resources.
764 * @param rs A standard bus resource specification previously initialized
765 * by @p bhnd_alloc_resources.
766 * @param res The bhnd resources to be released.
767 */
768void
769bhnd_release_resources(device_t dev, const struct resource_spec *rs,
770    struct bhnd_resource **res)
771{
772	for (u_int i = 0; rs[i].type != -1; i++) {
773		if (res[i] == NULL)
774			continue;
775
776		bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
777		res[i] = NULL;
778	}
779}
780
781/**
782 * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID
783 * register, returning its bhnd_chipid representation.
784 *
785 * @param idreg The CHIPC_ID register value.
786 * @param enum_addr The enumeration address to include in the result.
787 *
788 * @warning
789 * On early siba(4) devices, the ChipCommon core does not provide
790 * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
791 * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
792 * an invalid `ncores` value.
793 */
794struct bhnd_chipid
795bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
796{
797	struct bhnd_chipid result;
798
799	/* Fetch the basic chip info */
800	result.chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP);
801	result.chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG);
802	result.chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV);
803	result.chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
804	result.ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE);
805
806	result.enum_addr = enum_addr;
807
808	return (result);
809}
810
811/**
812 * Allocate the resource defined by @p rs via @p dev, use it
813 * to read the ChipCommon ID register relative to @p chipc_offset,
814 * then release the resource.
815 *
816 * @param dev The device owning @p rs.
817 * @param rs A resource spec that encompasses the ChipCommon register block.
818 * @param chipc_offset The offset of the ChipCommon registers within @p rs.
819 * @param[out] result the chip identification data.
820 *
821 * @retval 0 success
822 * @retval non-zero if the ChipCommon identification data could not be read.
823 */
824int
825bhnd_read_chipid(device_t dev, struct resource_spec *rs,
826    bus_size_t chipc_offset, struct bhnd_chipid *result)
827{
828	struct resource			*res;
829	uint32_t			 reg;
830	int				 error, rid, rtype;
831
832	/* Allocate the ChipCommon window resource and fetch the chipid data */
833	rid = rs->rid;
834	rtype = rs->type;
835	res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
836	if (res == NULL) {
837		device_printf(dev,
838		    "failed to allocate bhnd chipc resource\n");
839		return (ENXIO);
840	}
841
842	/* Fetch the basic chip info */
843	reg = bus_read_4(res, chipc_offset + CHIPC_ID);
844	*result = bhnd_parse_chipid(reg, 0x0);
845
846	/* Fetch the enum base address */
847	error = 0;
848	switch (result->chip_type) {
849	case BHND_CHIPTYPE_SIBA:
850		result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
851		break;
852	case BHND_CHIPTYPE_BCMA:
853	case BHND_CHIPTYPE_BCMA_ALT:
854		result->enum_addr = bus_read_4(res, chipc_offset +
855		    CHIPC_EROMPTR);
856		break;
857	case BHND_CHIPTYPE_UBUS:
858		device_printf(dev, "unsupported ubus/bcm63xx chip type");
859		error = ENODEV;
860		goto cleanup;
861	default:
862		device_printf(dev, "unknown chip type %hhu\n",
863		    result->chip_type);
864		error = ENODEV;
865		goto cleanup;
866	}
867
868cleanup:
869	/* Clean up */
870	bus_release_resource(dev, rtype, rid, res);
871	return (error);
872}
873
874/**
875 * Using the bhnd(4) bus-level core information and a custom core name,
876 * populate @p dev's device description.
877 *
878 * @param dev A bhnd-bus attached device.
879 * @param dev_name The core's name (e.g. "SDIO Device Core")
880 */
881void
882bhnd_set_custom_core_desc(device_t dev, const char *dev_name)
883{
884	const char *vendor_name;
885	char *desc;
886
887	vendor_name = bhnd_get_vendor_name(dev);
888	asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name,
889	    bhnd_get_hwrev(dev));
890
891	if (desc != NULL) {
892		device_set_desc_copy(dev, desc);
893		free(desc, M_BHND);
894	} else {
895		device_set_desc(dev, dev_name);
896	}
897}
898
899/**
900 * Using the bhnd(4) bus-level core information, populate @p dev's device
901 * description.
902 *
903 * @param dev A bhnd-bus attached device.
904 */
905void
906bhnd_set_default_core_desc(device_t dev)
907{
908	bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
909}
910
911/**
912 * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
913 *
914 * If a parent device is available, this implementation delegates the
915 * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
916 *
917 * If no parent device is available (i.e. on a the bus root), the hardware
918 * is assumed to be usable and false is returned.
919 */
920bool
921bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
922{
923	if (device_get_parent(dev) != NULL)
924		return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
925
926	return (false);
927}
928
929/**
930 * Helper function for implementing BHND_BUS_GET_CHIPID().
931 *
932 * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
933 * method on the parent of @p dev. If no parent exists, the implementation
934 * will panic.
935 */
936const struct bhnd_chipid *
937bhnd_bus_generic_get_chipid(device_t dev, device_t child)
938{
939	if (device_get_parent(dev) != NULL)
940		return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
941
942	panic("missing BHND_BUS_GET_CHIPID()");
943}
944
945/* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
946#define	BHND_GV(_dest, _name)	\
947	bhnd_nvram_getvar(child, BHND_NVAR_ ## _name, &_dest, sizeof(_dest))
948
949#define	REQ_BHND_GV(_dest, _name)		do {			\
950	if ((error = BHND_GV(_dest, _name))) {				\
951		device_printf(dev,					\
952		    "error reading " __STRING(_name) ": %d\n", error);	\
953		return (error);						\
954	}								\
955} while(0)
956
957#define	OPT_BHND_GV(_dest, _name, _default)	do {			\
958	if ((error = BHND_GV(_dest, _name))) {				\
959		if (error != ENOENT) {					\
960			device_printf(dev,				\
961			    "error reading "				\
962			       __STRING(_name) ": %d\n", error);	\
963			return (error);					\
964		}							\
965		_dest = _default;					\
966	}								\
967} while(0)
968
969/**
970 * Helper function for implementing BHND_BUS_READ_BOARDINFO().
971 *
972 * This implementation populates @p info with information from NVRAM,
973 * defaulting board_vendor and board_type fields to 0 if the
974 * requested variables cannot be found.
975 *
976 * This behavior is correct for most SoCs, but must be overridden on
977 * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
978 * result.
979 */
980int
981bhnd_bus_generic_read_board_info(device_t dev, device_t child,
982    struct bhnd_board_info *info)
983{
984	int	error;
985
986	OPT_BHND_GV(info->board_vendor,	BOARDVENDOR,	0);
987	OPT_BHND_GV(info->board_type,	BOARDTYPE,	0);	/* srom >= 2 */
988	REQ_BHND_GV(info->board_rev,	BOARDREV);
989	REQ_BHND_GV(info->board_srom_rev,SROMREV);
990	REQ_BHND_GV(info->board_flags,	BOARDFLAGS);
991	OPT_BHND_GV(info->board_flags2,	BOARDFLAGS2,	0);	/* srom >= 4 */
992	OPT_BHND_GV(info->board_flags3,	BOARDFLAGS3,	0);	/* srom >= 11 */
993
994	return (0);
995}
996
997#undef	BHND_GV
998#undef	BHND_GV_REQ
999#undef	BHND_GV_OPT
1000
1001
1002/**
1003 * Find an NVRAM child device on @p dev, if any.
1004 *
1005 * @retval device_t An NVRAM device.
1006 * @retval NULL If no NVRAM device is found.
1007 */
1008static device_t
1009find_nvram_child(device_t dev)
1010{
1011	device_t	chipc, nvram;
1012
1013	/* Look for a directly-attached NVRAM child */
1014	nvram = device_find_child(dev, "bhnd_nvram", 0);
1015	if (nvram != NULL)
1016		return (nvram);
1017
1018	/* Remaining checks are only applicable when searching a bhnd(4)
1019	 * bus. */
1020	if (device_get_devclass(dev) != bhnd_devclass)
1021		return (NULL);
1022
1023	/* Look for a ChipCommon-attached NVRAM device */
1024	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
1025		nvram = device_find_child(chipc, "bhnd_nvram", 0);
1026		if (nvram != NULL)
1027			return (nvram);
1028	}
1029
1030	/* Not found */
1031	return (NULL);
1032}
1033
1034/**
1035 * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
1036 *
1037 * This implementation searches @p dev for a usable NVRAM child device:
1038 * - The first child device implementing the bhnd_nvram devclass is
1039 *   returned, otherwise
1040 * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an
1041 *   attached NVRAM source.
1042 *
1043 * If no usable child device is found on @p dev, the request is delegated to
1044 * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
1045 */
1046int
1047bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
1048    void *buf, size_t *size)
1049{
1050	device_t	nvram;
1051	device_t	parent;
1052
1053	/* Try to find an NVRAM device applicable to @p child */
1054	if ((nvram = find_nvram_child(dev)) != NULL)
1055		return BHND_NVRAM_GETVAR(nvram, name, buf, size);
1056
1057	/* Try to delegate to parent */
1058	if ((parent = device_get_parent(dev)) == NULL)
1059		return (ENODEV);
1060
1061	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
1062	    name, buf, size));
1063}
1064
1065/**
1066 * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
1067 *
1068 * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
1069 * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
1070 * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
1071 */
1072struct bhnd_resource *
1073bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
1074	int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
1075	u_int flags)
1076{
1077	struct bhnd_resource	*br;
1078	struct resource		*res;
1079	int			 error;
1080
1081	br = NULL;
1082	res = NULL;
1083
1084	/* Allocate the real bus resource (without activating it) */
1085	res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
1086	    (flags & ~RF_ACTIVE));
1087	if (res == NULL)
1088		return (NULL);
1089
1090	/* Allocate our bhnd resource wrapper. */
1091	br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
1092	if (br == NULL)
1093		goto failed;
1094
1095	br->direct = false;
1096	br->res = res;
1097
1098	/* Attempt activation */
1099	if (flags & RF_ACTIVE) {
1100		error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
1101		if (error)
1102			goto failed;
1103	}
1104
1105	return (br);
1106
1107failed:
1108	if (res != NULL)
1109		BUS_RELEASE_RESOURCE(dev, child, type, *rid, res);
1110
1111	free(br, M_BHND);
1112	return (NULL);
1113}
1114
1115/**
1116 * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
1117 *
1118 * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
1119 * the backing resource to BUS_RELEASE_RESOURCE().
1120 */
1121int
1122bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
1123    int rid, struct bhnd_resource *r)
1124{
1125	int error;
1126
1127	if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res)))
1128		return (error);
1129
1130	free(r, M_BHND);
1131	return (0);
1132}
1133
1134
1135/**
1136 * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
1137 *
1138 * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1139 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1140 */
1141int
1142bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
1143    int rid, struct bhnd_resource *r)
1144{
1145	/* Try to delegate to the parent */
1146	if (device_get_parent(dev) != NULL)
1147		return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
1148		    child, type, rid, r));
1149
1150	return (EINVAL);
1151};
1152
1153/**
1154 * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
1155 *
1156 * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1157 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1158 */
1159int
1160bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
1161    int type, int rid, struct bhnd_resource *r)
1162{
1163	if (device_get_parent(dev) != NULL)
1164		return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
1165		    child, type, rid, r));
1166
1167	return (EINVAL);
1168};
1169