1/*-
2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
3 * Copyright (c) 2017 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by Landon Fuller
7 * under sponsorship from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer,
14 *    without modification.
15 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17 *    redistribution must be conditioned upon including a substantially
18 *    similar Disclaimer requirement for further binary redistribution.
19 *
20 * NO WARRANTY
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGES.
32 */
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39
40#include <machine/bus.h>
41
42#include <dev/bhnd/bhnd_eromvar.h>
43
44#include <dev/bhnd/cores/chipc/chipcreg.h>
45
46#include "sibareg.h"
47#include "sibavar.h"
48
49#include "siba_eromvar.h"
50
51struct siba_erom;
52struct siba_erom_io;
53
54static int			siba_eio_init(struct siba_erom_io *io,
55				    struct bhnd_erom_io *eio, u_int ncores);
56
57static uint32_t			siba_eio_read_4(struct siba_erom_io *io,
58				    u_int core_idx, bus_size_t offset);
59
60static int			siba_eio_read_core_id(struct siba_erom_io *io,
61				    u_int core_idx, int unit,
62				    struct siba_core_id *sid);
63
64static int			siba_eio_read_chipid(struct siba_erom_io *io,
65				    bus_addr_t enum_addr,
66				    struct bhnd_chipid *cid);
67
68/**
69 * SIBA EROM generic I/O context
70 */
71struct siba_erom_io {
72	struct bhnd_erom_io	*eio;		/**< erom I/O callbacks */
73	bhnd_addr_t		 base_addr;	/**< address of first core */
74	u_int			 ncores;	/**< core count */
75};
76
77/**
78 * SIBA EROM per-instance state.
79 */
80struct siba_erom {
81	struct bhnd_erom	obj;
82	struct siba_erom_io	io;	/**< i/o context */
83};
84
85#define	EROM_LOG(io, fmt, ...)	do {				\
86	printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__);	\
87} while(0)
88
89/* SIBA implementation of BHND_EROM_PROBE() */
90static int
91siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
92    const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
93{
94	struct siba_erom_io	io;
95	uint32_t		idreg;
96	int			error;
97
98	/* Initialize I/O context, assuming at least the first core is mapped */
99	if ((error = siba_eio_init(&io, eio, 1)))
100		return (error);
101
102	/* Try using the provided hint. */
103	if (hint != NULL) {
104		struct siba_core_id sid;
105
106		/* Validate bus type */
107		if (hint->chip_type != BHND_CHIPTYPE_SIBA)
108			return (ENXIO);
109
110		/*
111		 * Verify the first core's IDHIGH/IDLOW identification.
112		 *
113		 * The core must be a Broadcom core, but must *not* be
114		 * a chipcommon core; those shouldn't be hinted.
115		 *
116		 * The first core on EXTIF-equipped devices varies, but on the
117		 * BCM4710, it's a SDRAM core (0x803).
118		 */
119
120		if ((error = siba_eio_read_core_id(&io, 0, 0, &sid)))
121			return (error);
122
123		if (sid.core_info.vendor != BHND_MFGID_BCM)
124			return (ENXIO);
125
126		if (sid.core_info.device == BHND_COREID_CC)
127			return (EINVAL);
128
129		*cid = *hint;
130	} else {
131		/* Validate bus type */
132		idreg = siba_eio_read_4(&io, 0, CHIPC_ID);
133		if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
134			return (ENXIO);
135
136		/* Identify the chipset */
137		if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid)))
138			return (error);
139
140		/* Verify the chip type */
141		if (cid->chip_type != BHND_CHIPTYPE_SIBA)
142			return (ENXIO);
143	}
144
145	/*
146	 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
147	 * without triggering build failure due to -Wtype-limits
148	 *
149	 * if (cid.ncores > SIBA_MAX_CORES)
150	 *      return (EINVAL)
151	 */
152	_Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
153	    "ncores could result in over-read of backing resource");
154
155	return (0);
156}
157
158/* SIBA implementation of BHND_EROM_INIT() */
159static int
160siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
161    struct bhnd_erom_io *eio)
162{
163	struct siba_erom	*sc;
164	int			 error;
165
166	sc = (struct siba_erom *)erom;
167
168	/* Attempt to map the full core enumeration space */
169	error = bhnd_erom_io_map(eio, cid->enum_addr,
170	    cid->ncores * SIBA_CORE_SIZE);
171	if (error) {
172		printf("%s: failed to map %u cores: %d\n", __FUNCTION__,
173		    cid->ncores, error);
174		return (error);
175	}
176
177	/* Initialize I/O context */
178	return (siba_eio_init(&sc->io, eio, cid->ncores));
179}
180
181/* SIBA implementation of BHND_EROM_FINI() */
182static void
183siba_erom_fini(bhnd_erom_t *erom)
184{
185	struct siba_erom *sc = (struct siba_erom *)erom;
186
187	bhnd_erom_io_fini(sc->io.eio);
188}
189
190/* Initialize siba_erom resource I/O context */
191static int
192siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores)
193{
194	io->eio = eio;
195	io->ncores = ncores;
196	return (0);
197}
198
199/**
200 * Read a 32-bit value from @p offset relative to the base address of
201 * the given @p core_idx.
202 *
203 * @param io EROM I/O context.
204 * @param core_idx Core index.
205 * @param offset Core register offset.
206 */
207static uint32_t
208siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
209{
210	/* Sanity check core index and offset */
211	if (core_idx >= io->ncores)
212		panic("core index %u out of range (ncores=%u)", core_idx,
213		    io->ncores);
214
215	if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
216		panic("invalid core offset %#jx", (uintmax_t)offset);
217
218	/* Perform read */
219	return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset,
220	    4));
221}
222
223/**
224 * Read and parse identification registers for the given @p core_index.
225 *
226 * @param io EROM I/O context.
227 * @param core_idx The core index.
228 * @param unit The caller-specified unit number to be included in the return
229 * value.
230 * @param[out] sid On success, the parsed siba core id.
231 *
232 * @retval 0		success
233 * @retval non-zero     if reading or parsing the identification registers
234 *			otherwise fails, a regular unix error code will be
235 *			returned.
236 */
237static int
238siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit,
239    struct siba_core_id *sid)
240{
241	struct siba_admatch	admatch[SIBA_MAX_ADDRSPACE];
242	uint32_t		idhigh, idlow;
243	uint32_t		tpsflag;
244	uint16_t		ocp_vendor;
245	uint8_t			sonics_rev;
246	uint8_t			num_admatch;
247	uint8_t			num_admatch_en;
248	uint8_t			num_cfg;
249	bool			intr_en;
250	u_int			intr_flag;
251	int			error;
252
253	idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
254	idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
255	tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
256
257	ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
258	sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
259	num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
260	if (num_admatch > nitems(admatch)) {
261		printf("core%u: invalid admatch count %hhu\n", core_idx,
262		    num_admatch);
263		return (EINVAL);
264	}
265
266	/* Determine backplane interrupt distribution configuration */
267	intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0);
268	intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
269
270	/* Determine the number of sonics config register blocks */
271	num_cfg = SIBA_CFG_NUM_2_2;
272	if (sonics_rev >= SIBA_IDL_SBREV_2_3)
273		num_cfg = SIBA_CFG_NUM_2_3;
274
275	/* Parse all admatch descriptors */
276	num_admatch_en = 0;
277	for (uint8_t i = 0; i < num_admatch; i++) {
278		uint32_t	am_value;
279		u_int		am_offset;
280
281		KASSERT(i < nitems(admatch), ("invalid admatch index"));
282
283		/* Determine the register offset */
284		am_offset = siba_admatch_offset(i);
285		if (am_offset == 0) {
286			printf("core%u: addrspace %hhu is unsupported",
287			    core_idx, i);
288			return (ENODEV);
289		}
290
291		/* Read and parse the address match register */
292		am_value = siba_eio_read_4(io, core_idx, am_offset);
293		error = siba_parse_admatch(am_value, &admatch[num_admatch_en]);
294		if (error) {
295			printf("core%u: failed to decode admatch[%hhu] "
296			    "register value 0x%x\n", core_idx, i, am_value);
297			return (error);
298		}
299
300		/* Skip disabled entries */
301		if (!admatch[num_admatch_en].am_enabled)
302			continue;
303
304		/* Reject unsupported negative matches. These are not used on
305		 * any known devices */
306		if (admatch[num_admatch_en].am_negative) {
307			printf("core%u: unsupported negative admatch[%hhu] "
308			    "value 0x%x\n", core_idx, i, am_value);
309			return (ENXIO);
310		}
311
312		num_admatch_en++;
313	}
314
315	/* Populate the result */
316	*sid = (struct siba_core_id) {
317		.core_info	= {
318			.vendor	= siba_get_bhnd_mfgid(ocp_vendor),
319			.device	= SIBA_REG_GET(idhigh, IDH_DEVICE),
320			.hwrev	= SIBA_IDH_CORE_REV(idhigh),
321			.core_idx = core_idx,
322			.unit	= unit
323		},
324		.sonics_vendor	= ocp_vendor,
325		.sonics_rev	= sonics_rev,
326		.intr_en	= intr_en,
327		.intr_flag	= intr_flag,
328		.num_admatch	= num_admatch_en,
329		.num_cfg_blocks	= num_cfg
330	};
331	memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0]));
332
333	return (0);
334}
335
336/**
337 * Read and parse the SSB identification registers for the given @p core_index,
338 * returning the siba(4) core identification in @p sid.
339 *
340 * @param sc A siba EROM instance.
341 * @param core_idx The index of the core to be identified.
342 * @param[out] result On success, the parsed siba core id.
343 *
344 * @retval 0		success
345 * @retval non-zero     if reading or parsing the identification registers
346 *			otherwise fails, a regular unix error code will be
347 *			returned.
348 */
349int
350siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
351    struct siba_core_id *result)
352{
353	struct siba_core_id	sid;
354	int			error;
355
356	/* Fetch the core info, assuming a unit number of 0 */
357	if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid)))
358		return (error);
359
360	/* Scan preceding cores to determine the real unit number. */
361	for (u_int i = 0; i < core_idx; i++) {
362		struct siba_core_id prev;
363
364		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev)))
365			return (error);
366
367		/* Bump the unit number? */
368		if (sid.core_info.vendor == prev.core_info.vendor &&
369		    sid.core_info.device == prev.core_info.device)
370			sid.core_info.unit++;
371	}
372
373	*result = sid;
374	return (0);
375}
376
377/**
378 * Read and parse the chip identification register from the ChipCommon core.
379 *
380 * @param io EROM I/O context.
381 * @param enum_addr The physical address mapped by @p io.
382 * @param cid On success, the parsed chip identifier.
383 */
384static int
385siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
386    struct bhnd_chipid *cid)
387{
388	struct siba_core_id	ccid;
389	int			error;
390
391	/* Identify the chipcommon core */
392	if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
393		return (error);
394
395	if (ccid.core_info.vendor != BHND_MFGID_BCM ||
396	    ccid.core_info.device != BHND_COREID_CC)
397	{
398		if (bootverbose) {
399			EROM_LOG(io, "first core not chipcommon "
400			    "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
401			    ccid.core_info.device);
402		}
403		return (ENXIO);
404	}
405
406	/* Identify the chipset */
407	if ((error = bhnd_erom_read_chipid(io->eio, cid)))
408		return (error);
409
410	/* Do we need to fix up the core count? */
411	if (CHIPC_NCORES_MIN_HWREV(ccid.core_info.hwrev))
412		return (0);
413
414	switch (cid->chip_id) {
415	case BHND_CHIPID_BCM4306:
416		cid->ncores = 6;
417		break;
418	case BHND_CHIPID_BCM4704:
419		cid->ncores = 9;
420		break;
421	case BHND_CHIPID_BCM5365:
422		/*
423		* BCM5365 does support ID_NUMCORE in at least
424		* some of its revisions, but for unknown
425		* reasons, Broadcom's drivers always exclude
426		* the ChipCommon revision (0x5) used by BCM5365
427		* from the set of revisions supporting
428		* ID_NUMCORE, and instead supply a fixed value.
429		*
430		* Presumably, at least some of these devices
431		* shipped with a broken ID_NUMCORE value.
432		*/
433		cid->ncores = 7;
434		break;
435	default:
436		return (EINVAL);
437	}
438
439	return (0);
440}
441
442static int
443siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
444    struct bhnd_core_info *core)
445{
446	struct siba_erom	*sc;
447	struct bhnd_core_match	 imatch;
448	int			 error;
449
450	sc = (struct siba_erom *)erom;
451
452	/* We can't determine a core's unit number during the initial scan. */
453	imatch = *desc;
454	imatch.m.match.core_unit = 0;
455
456	/* Locate the first matching core */
457	for (u_int i = 0; i < sc->io.ncores; i++) {
458		struct siba_core_id	sid;
459		struct bhnd_core_info	ci;
460
461		/* Read the core info */
462		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
463			return (error);
464
465		ci = sid.core_info;
466
467		/* Check for initial match */
468		if (!bhnd_core_matches(&ci, &imatch))
469			continue;
470
471		/* Re-scan preceding cores to determine the unit number. */
472		for (u_int j = 0; j < i; j++) {
473			error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
474			if (error)
475				return (error);
476
477			/* Bump the unit number? */
478			if (sid.core_info.vendor == ci.vendor &&
479			    sid.core_info.device == ci.device)
480				ci.unit++;
481		}
482
483		/* Check for full match against now-valid unit number */
484		if (!bhnd_core_matches(&ci, desc))
485			continue;
486
487		/* Matching core found */
488		*core = ci;
489		return (0);
490	}
491
492	/* Not found */
493	return (ENOENT);
494}
495
496static int
497siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
498    bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
499    bhnd_addr_t *addr, bhnd_size_t *size)
500{
501	struct siba_erom	*sc;
502	struct bhnd_core_info	 core;
503	struct siba_core_id	 sid;
504	struct siba_admatch	 admatch;
505	uint32_t		 am;
506	u_int			 am_offset;
507	u_int			 addrspace, cfg;
508
509	int			 error;
510
511	sc = (struct siba_erom *)erom;
512
513	/* Locate the requested core */
514	if ((error = siba_erom_lookup_core(erom, desc, &core)))
515		return (error);
516
517	/* Fetch full siba core ident */
518	error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
519	if (error)
520		return (error);
521
522	/* Is port valid? */
523	if (!siba_is_port_valid(&sid, type, port))
524		return (ENOENT);
525
526	/* Is region valid? */
527	if (region >= siba_port_region_count(&sid, type, port))
528		return (ENOENT);
529
530	/* Is this a siba configuration region? If so, this is mapped to an
531	 * offset within the device0.0 port */
532	error = siba_cfg_index(&sid, type, port, region, &cfg);
533	if (!error) {
534		bhnd_addr_t	region_addr;
535		bhnd_addr_t	region_size;
536		bhnd_size_t	cfg_offset, cfg_size;
537
538		cfg_offset = SIBA_CFG_OFFSET(cfg);
539		cfg_size = SIBA_CFG_SIZE;
540
541		/* Fetch the device0.0 addr/size */
542		error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
543		    0, 0, NULL, &region_addr, &region_size);
544		if (error)
545			return (error);
546
547		/* Verify that our offset fits within the region */
548		if (region_size < cfg_size) {
549			printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
550			    bhnd_port_type_name(type), port, region, cfg_offset,
551			    bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
552
553			return (ENXIO);
554		}
555
556		if (BHND_ADDR_MAX - region_addr < cfg_offset) {
557			printf("%s%u.%u offset %ju would overflow %s0.0 addr "
558			    "%ju\n", bhnd_port_type_name(type), port, region,
559			    cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
560			    region_addr);
561
562			return (ENXIO);
563		}
564
565		if (info != NULL)
566			*info = core;
567
568		*addr = region_addr + cfg_offset;
569		*size = cfg_size;
570		return (0);
571	}
572
573	/*
574	 * Otherwise, must be a device port.
575	 *
576	 * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
577	 * bus drivers, we do not exclude the siba(4) configuration blocks from
578	 * the first device port.
579	 */
580	error = siba_addrspace_index(&sid, type, port, region, &addrspace);
581	if (error)
582		return (error);
583
584	/* Determine the register offset */
585	am_offset = siba_admatch_offset(addrspace);
586	if (am_offset == 0) {
587		printf("addrspace %u is unsupported", addrspace);
588		return (ENODEV);
589	}
590
591	/* Read and parse the address match register */
592	am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
593
594	if ((error = siba_parse_admatch(am, &admatch))) {
595		printf("failed to decode address match register value 0x%x\n",
596		    am);
597		return (error);
598	}
599
600	if (info != NULL)
601		*info = core;
602
603	*addr = admatch.am_base;
604	*size = admatch.am_size;
605
606	return (0);
607}
608
609/* BHND_EROM_GET_CORE_TABLE() */
610static int
611siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
612    u_int *num_cores)
613{
614	struct siba_erom	*sc;
615	struct bhnd_core_info	*out;
616	int			 error;
617
618	sc = (struct siba_erom *)erom;
619
620	/* Allocate our core array */
621	out = mallocarray(sc->io.ncores, sizeof(*out), M_BHND, M_NOWAIT);
622	if (out == NULL)
623		return (ENOMEM);
624
625	*cores = out;
626	*num_cores = sc->io.ncores;
627
628	/* Enumerate all cores. */
629	for (u_int i = 0; i < sc->io.ncores; i++) {
630		struct siba_core_id sid;
631
632		/* Read the core info */
633		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
634			return (error);
635
636		out[i] = sid.core_info;
637
638		/* Determine unit number */
639		for (u_int j = 0; j < i; j++) {
640			if (out[j].vendor == out[i].vendor &&
641			    out[j].device == out[i].device)
642				out[i].unit++;
643		}
644	}
645
646	return (0);
647}
648
649/* BHND_EROM_FREE_CORE_TABLE() */
650static void
651siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
652{
653	free(cores, M_BHND);
654}
655
656/* BHND_EROM_DUMP() */
657static int
658siba_erom_dump(bhnd_erom_t *erom)
659{
660	struct siba_erom	*sc;
661	int			 error;
662
663	sc = (struct siba_erom *)erom;
664
665	/* Enumerate all cores. */
666	for (u_int i = 0; i < sc->io.ncores; i++) {
667		uint32_t idhigh, idlow;
668		uint32_t nraddr;
669
670		idhigh = siba_eio_read_4(&sc->io, i,
671		    SB0_REG_ABS(SIBA_CFG0_IDHIGH));
672		idlow = siba_eio_read_4(&sc->io, i,
673		    SB0_REG_ABS(SIBA_CFG0_IDLOW));
674
675		printf("siba core %u:\n", i);
676		printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
677		printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
678		printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
679		printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
680
681		/* Enumerate the address match registers */
682		nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
683		printf("\tnraddr\t0x%04x\n", nraddr);
684
685		for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
686			struct siba_admatch	admatch;
687			uint32_t		am;
688			u_int			am_offset;
689
690			/* Determine the register offset */
691			am_offset = siba_admatch_offset(addrspace);
692			if (am_offset == 0) {
693				printf("addrspace %zu unsupported",
694				    addrspace);
695				break;
696			}
697
698			/* Read and parse the address match register */
699			am = siba_eio_read_4(&sc->io, i, am_offset);
700			if ((error = siba_parse_admatch(am, &admatch))) {
701				printf("failed to decode address match "
702				    "register value 0x%x\n", am);
703				continue;
704			}
705
706			printf("\taddrspace %zu\n", addrspace);
707			printf("\t\taddr: 0x%08x\n", admatch.am_base);
708			printf("\t\tsize: 0x%08x\n", admatch.am_size);
709		}
710	}
711
712	return (0);
713}
714
715static kobj_method_t siba_erom_methods[] = {
716	KOBJMETHOD(bhnd_erom_probe,		siba_erom_probe),
717	KOBJMETHOD(bhnd_erom_init,		siba_erom_init),
718	KOBJMETHOD(bhnd_erom_fini,		siba_erom_fini),
719	KOBJMETHOD(bhnd_erom_get_core_table,	siba_erom_get_core_table),
720	KOBJMETHOD(bhnd_erom_free_core_table,	siba_erom_free_core_table),
721	KOBJMETHOD(bhnd_erom_lookup_core,	siba_erom_lookup_core),
722	KOBJMETHOD(bhnd_erom_lookup_core_addr,	siba_erom_lookup_core_addr),
723	KOBJMETHOD(bhnd_erom_dump,		siba_erom_dump),
724
725	KOBJMETHOD_END
726};
727
728BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));
729