xref: /freebsd/sys/dev/bhnd/siba/siba_erom.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1664a7497SLandon J. Fuller /*-
2664a7497SLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
389294a78SLandon J. Fuller  * Copyright (c) 2017 The FreeBSD Foundation
4664a7497SLandon J. Fuller  * All rights reserved.
5664a7497SLandon J. Fuller  *
689294a78SLandon J. Fuller  * Portions of this software were developed by Landon Fuller
789294a78SLandon J. Fuller  * under sponsorship from the FreeBSD Foundation.
889294a78SLandon J. Fuller  *
9664a7497SLandon J. Fuller  * Redistribution and use in source and binary forms, with or without
10664a7497SLandon J. Fuller  * modification, are permitted provided that the following conditions
11664a7497SLandon J. Fuller  * are met:
12664a7497SLandon J. Fuller  * 1. Redistributions of source code must retain the above copyright
13664a7497SLandon J. Fuller  *    notice, this list of conditions and the following disclaimer,
14664a7497SLandon J. Fuller  *    without modification.
15664a7497SLandon J. Fuller  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16664a7497SLandon J. Fuller  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17664a7497SLandon J. Fuller  *    redistribution must be conditioned upon including a substantially
18664a7497SLandon J. Fuller  *    similar Disclaimer requirement for further binary redistribution.
19664a7497SLandon J. Fuller  *
20664a7497SLandon J. Fuller  * NO WARRANTY
21664a7497SLandon J. Fuller  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22664a7497SLandon J. Fuller  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23664a7497SLandon J. Fuller  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24664a7497SLandon J. Fuller  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25664a7497SLandon J. Fuller  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26664a7497SLandon J. Fuller  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27664a7497SLandon J. Fuller  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28664a7497SLandon J. Fuller  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29664a7497SLandon J. Fuller  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30664a7497SLandon J. Fuller  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31664a7497SLandon J. Fuller  * THE POSSIBILITY OF SUCH DAMAGES.
32664a7497SLandon J. Fuller  */
33664a7497SLandon J. Fuller 
34664a7497SLandon J. Fuller #include <sys/param.h>
35664a7497SLandon J. Fuller #include <sys/bus.h>
36664a7497SLandon J. Fuller #include <sys/kernel.h>
37664a7497SLandon J. Fuller #include <sys/malloc.h>
38664a7497SLandon J. Fuller #include <sys/module.h>
39664a7497SLandon J. Fuller 
40664a7497SLandon J. Fuller #include <machine/bus.h>
41664a7497SLandon J. Fuller 
42*f3524ec8SLandon J. Fuller #include <dev/bhnd/bhnd_eromvar.h>
43664a7497SLandon J. Fuller 
44664a7497SLandon J. Fuller #include <dev/bhnd/cores/chipc/chipcreg.h>
45664a7497SLandon J. Fuller 
46664a7497SLandon J. Fuller #include "sibareg.h"
47664a7497SLandon J. Fuller #include "sibavar.h"
48664a7497SLandon J. Fuller 
497c7c726bSLandon J. Fuller #include "siba_eromvar.h"
507c7c726bSLandon J. Fuller 
51664a7497SLandon J. Fuller struct siba_erom;
52111d7cb2SLandon J. Fuller struct siba_erom_io;
53664a7497SLandon J. Fuller 
54111d7cb2SLandon J. Fuller static int			siba_eio_init(struct siba_erom_io *io,
5589294a78SLandon J. Fuller 				    struct bhnd_erom_io *eio, u_int ncores);
56111d7cb2SLandon J. Fuller 
57111d7cb2SLandon J. Fuller static uint32_t			siba_eio_read_4(struct siba_erom_io *io,
58111d7cb2SLandon J. Fuller 				    u_int core_idx, bus_size_t offset);
59111d7cb2SLandon J. Fuller 
607c7c726bSLandon J. Fuller static int			siba_eio_read_core_id(struct siba_erom_io *io,
617c7c726bSLandon J. Fuller 				    u_int core_idx, int unit,
627c7c726bSLandon J. Fuller 				    struct siba_core_id *sid);
63111d7cb2SLandon J. Fuller 
64111d7cb2SLandon J. Fuller static int			siba_eio_read_chipid(struct siba_erom_io *io,
65111d7cb2SLandon J. Fuller 				    bus_addr_t enum_addr,
66111d7cb2SLandon J. Fuller 				    struct bhnd_chipid *cid);
67111d7cb2SLandon J. Fuller 
68111d7cb2SLandon J. Fuller /**
69111d7cb2SLandon J. Fuller  * SIBA EROM generic I/O context
70111d7cb2SLandon J. Fuller  */
71111d7cb2SLandon J. Fuller struct siba_erom_io {
7289294a78SLandon J. Fuller 	struct bhnd_erom_io	*eio;		/**< erom I/O callbacks */
7389294a78SLandon J. Fuller 	bhnd_addr_t		 base_addr;	/**< address of first core */
74664a7497SLandon J. Fuller 	u_int			 ncores;	/**< core count */
75664a7497SLandon J. Fuller };
76664a7497SLandon J. Fuller 
77111d7cb2SLandon J. Fuller /**
78111d7cb2SLandon J. Fuller  * SIBA EROM per-instance state.
79111d7cb2SLandon J. Fuller  */
80111d7cb2SLandon J. Fuller struct siba_erom {
81111d7cb2SLandon J. Fuller 	struct bhnd_erom	obj;
82111d7cb2SLandon J. Fuller 	struct siba_erom_io	io;	/**< i/o context */
83111d7cb2SLandon J. Fuller };
84111d7cb2SLandon J. Fuller 
85111d7cb2SLandon J. Fuller #define	EROM_LOG(io, fmt, ...)	do {				\
86664a7497SLandon J. Fuller 	printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__);	\
87664a7497SLandon J. Fuller } while(0)
88664a7497SLandon J. Fuller 
8989294a78SLandon J. Fuller /* SIBA implementation of BHND_EROM_PROBE() */
90664a7497SLandon J. Fuller static int
siba_erom_probe(bhnd_erom_class_t * cls,struct bhnd_erom_io * eio,const struct bhnd_chipid * hint,struct bhnd_chipid * cid)9189294a78SLandon J. Fuller siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
9289294a78SLandon J. Fuller     const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
93664a7497SLandon J. Fuller {
9489294a78SLandon J. Fuller 	struct siba_erom_io	io;
95664a7497SLandon J. Fuller 	uint32_t		idreg;
96664a7497SLandon J. Fuller 	int			error;
97664a7497SLandon J. Fuller 
9889294a78SLandon J. Fuller 	/* Initialize I/O context, assuming at least the first core is mapped */
9989294a78SLandon J. Fuller 	if ((error = siba_eio_init(&io, eio, 1)))
10089294a78SLandon J. Fuller 		return (error);
10189294a78SLandon J. Fuller 
102111d7cb2SLandon J. Fuller 	/* Try using the provided hint. */
103111d7cb2SLandon J. Fuller 	if (hint != NULL) {
104111d7cb2SLandon J. Fuller 		struct siba_core_id sid;
105111d7cb2SLandon J. Fuller 
106111d7cb2SLandon J. Fuller 		/* Validate bus type */
107111d7cb2SLandon J. Fuller 		if (hint->chip_type != BHND_CHIPTYPE_SIBA)
108111d7cb2SLandon J. Fuller 			return (ENXIO);
109111d7cb2SLandon J. Fuller 
110111d7cb2SLandon J. Fuller 		/*
111111d7cb2SLandon J. Fuller 		 * Verify the first core's IDHIGH/IDLOW identification.
112111d7cb2SLandon J. Fuller 		 *
113111d7cb2SLandon J. Fuller 		 * The core must be a Broadcom core, but must *not* be
114111d7cb2SLandon J. Fuller 		 * a chipcommon core; those shouldn't be hinted.
115111d7cb2SLandon J. Fuller 		 *
116111d7cb2SLandon J. Fuller 		 * The first core on EXTIF-equipped devices varies, but on the
117111d7cb2SLandon J. Fuller 		 * BCM4710, it's a SDRAM core (0x803).
118111d7cb2SLandon J. Fuller 		 */
119111d7cb2SLandon J. Fuller 
1207c7c726bSLandon J. Fuller 		if ((error = siba_eio_read_core_id(&io, 0, 0, &sid)))
1217c7c726bSLandon J. Fuller 			return (error);
122111d7cb2SLandon J. Fuller 
123111d7cb2SLandon J. Fuller 		if (sid.core_info.vendor != BHND_MFGID_BCM)
124111d7cb2SLandon J. Fuller 			return (ENXIO);
125111d7cb2SLandon J. Fuller 
126111d7cb2SLandon J. Fuller 		if (sid.core_info.device == BHND_COREID_CC)
127111d7cb2SLandon J. Fuller 			return (EINVAL);
128111d7cb2SLandon J. Fuller 
129111d7cb2SLandon J. Fuller 		*cid = *hint;
130111d7cb2SLandon J. Fuller 	} else {
131111d7cb2SLandon J. Fuller 		/* Validate bus type */
13289294a78SLandon J. Fuller 		idreg = siba_eio_read_4(&io, 0, CHIPC_ID);
133111d7cb2SLandon J. Fuller 		if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
134111d7cb2SLandon J. Fuller 			return (ENXIO);
135664a7497SLandon J. Fuller 
136664a7497SLandon J. Fuller 		/* Identify the chipset */
13789294a78SLandon J. Fuller 		if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid)))
138664a7497SLandon J. Fuller 			return (error);
139664a7497SLandon J. Fuller 
140664a7497SLandon J. Fuller 		/* Verify the chip type */
141111d7cb2SLandon J. Fuller 		if (cid->chip_type != BHND_CHIPTYPE_SIBA)
142664a7497SLandon J. Fuller 			return (ENXIO);
143111d7cb2SLandon J. Fuller 	}
144664a7497SLandon J. Fuller 
145664a7497SLandon J. Fuller 	/*
146664a7497SLandon J. Fuller 	 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
147664a7497SLandon J. Fuller 	 * without triggering build failure due to -Wtype-limits
148664a7497SLandon J. Fuller 	 *
149664a7497SLandon J. Fuller 	 * if (cid.ncores > SIBA_MAX_CORES)
150664a7497SLandon J. Fuller 	 *      return (EINVAL)
151664a7497SLandon J. Fuller 	 */
152111d7cb2SLandon J. Fuller 	_Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
153664a7497SLandon J. Fuller 	    "ncores could result in over-read of backing resource");
154664a7497SLandon J. Fuller 
155664a7497SLandon J. Fuller 	return (0);
156664a7497SLandon J. Fuller }
157664a7497SLandon J. Fuller 
158111d7cb2SLandon J. Fuller /* SIBA implementation of BHND_EROM_INIT() */
159664a7497SLandon J. Fuller static int
siba_erom_init(bhnd_erom_t * erom,const struct bhnd_chipid * cid,struct bhnd_erom_io * eio)160111d7cb2SLandon J. Fuller siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
16189294a78SLandon J. Fuller     struct bhnd_erom_io *eio)
162664a7497SLandon J. Fuller {
163111d7cb2SLandon J. Fuller 	struct siba_erom	*sc;
164111d7cb2SLandon J. Fuller 	int			 error;
165664a7497SLandon J. Fuller 
166111d7cb2SLandon J. Fuller 	sc = (struct siba_erom *)erom;
167664a7497SLandon J. Fuller 
16889294a78SLandon J. Fuller 	/* Attempt to map the full core enumeration space */
16989294a78SLandon J. Fuller 	error = bhnd_erom_io_map(eio, cid->enum_addr,
17089294a78SLandon J. Fuller 	    cid->ncores * SIBA_CORE_SIZE);
17189294a78SLandon J. Fuller 	if (error) {
17289294a78SLandon J. Fuller 		printf("%s: failed to map %u cores: %d\n", __FUNCTION__,
17389294a78SLandon J. Fuller 		    cid->ncores, error);
174111d7cb2SLandon J. Fuller 		return (error);
175664a7497SLandon J. Fuller 	}
176664a7497SLandon J. Fuller 
177111d7cb2SLandon J. Fuller 	/* Initialize I/O context */
17889294a78SLandon J. Fuller 	return (siba_eio_init(&sc->io, eio, cid->ncores));
179111d7cb2SLandon J. Fuller }
180111d7cb2SLandon J. Fuller 
181111d7cb2SLandon J. Fuller /* SIBA implementation of BHND_EROM_FINI() */
182664a7497SLandon J. Fuller static void
siba_erom_fini(bhnd_erom_t * erom)183664a7497SLandon J. Fuller siba_erom_fini(bhnd_erom_t *erom)
184664a7497SLandon J. Fuller {
185664a7497SLandon J. Fuller 	struct siba_erom *sc = (struct siba_erom *)erom;
186664a7497SLandon J. Fuller 
18789294a78SLandon J. Fuller 	bhnd_erom_io_fini(sc->io.eio);
188664a7497SLandon J. Fuller }
189664a7497SLandon J. Fuller 
190111d7cb2SLandon J. Fuller /* Initialize siba_erom resource I/O context */
191111d7cb2SLandon J. Fuller static int
siba_eio_init(struct siba_erom_io * io,struct bhnd_erom_io * eio,u_int ncores)19289294a78SLandon J. Fuller siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores)
193111d7cb2SLandon J. Fuller {
19489294a78SLandon J. Fuller 	io->eio = eio;
195111d7cb2SLandon J. Fuller 	io->ncores = ncores;
196111d7cb2SLandon J. Fuller 	return (0);
197111d7cb2SLandon J. Fuller }
198111d7cb2SLandon J. Fuller 
199111d7cb2SLandon J. Fuller /**
200111d7cb2SLandon J. Fuller  * Read a 32-bit value from @p offset relative to the base address of
201111d7cb2SLandon J. Fuller  * the given @p core_idx.
202111d7cb2SLandon J. Fuller  *
203111d7cb2SLandon J. Fuller  * @param io EROM I/O context.
204111d7cb2SLandon J. Fuller  * @param core_idx Core index.
205111d7cb2SLandon J. Fuller  * @param offset Core register offset.
206111d7cb2SLandon J. Fuller  */
207111d7cb2SLandon J. Fuller static uint32_t
siba_eio_read_4(struct siba_erom_io * io,u_int core_idx,bus_size_t offset)208111d7cb2SLandon J. Fuller siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
209111d7cb2SLandon J. Fuller {
210111d7cb2SLandon J. Fuller 	/* Sanity check core index and offset */
211111d7cb2SLandon J. Fuller 	if (core_idx >= io->ncores)
212111d7cb2SLandon J. Fuller 		panic("core index %u out of range (ncores=%u)", core_idx,
213111d7cb2SLandon J. Fuller 		    io->ncores);
214111d7cb2SLandon J. Fuller 
215111d7cb2SLandon J. Fuller 	if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
216111d7cb2SLandon J. Fuller 		panic("invalid core offset %#jx", (uintmax_t)offset);
217111d7cb2SLandon J. Fuller 
218111d7cb2SLandon J. Fuller 	/* Perform read */
21989294a78SLandon J. Fuller 	return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset,
22089294a78SLandon J. Fuller 	    4));
221111d7cb2SLandon J. Fuller }
222111d7cb2SLandon J. Fuller 
223111d7cb2SLandon J. Fuller /**
224111d7cb2SLandon J. Fuller  * Read and parse identification registers for the given @p core_index.
225111d7cb2SLandon J. Fuller  *
226111d7cb2SLandon J. Fuller  * @param io EROM I/O context.
227111d7cb2SLandon J. Fuller  * @param core_idx The core index.
228111d7cb2SLandon J. Fuller  * @param unit The caller-specified unit number to be included in the return
229111d7cb2SLandon J. Fuller  * value.
2307c7c726bSLandon J. Fuller  * @param[out] sid On success, the parsed siba core id.
2317c7c726bSLandon J. Fuller  *
2327c7c726bSLandon J. Fuller  * @retval 0		success
2337c7c726bSLandon J. Fuller  * @retval non-zero     if reading or parsing the identification registers
2347c7c726bSLandon J. Fuller  *			otherwise fails, a regular unix error code will be
2357c7c726bSLandon J. Fuller  *			returned.
236111d7cb2SLandon J. Fuller  */
2377c7c726bSLandon J. Fuller static int
siba_eio_read_core_id(struct siba_erom_io * io,u_int core_idx,int unit,struct siba_core_id * sid)2387c7c726bSLandon J. Fuller siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit,
2397c7c726bSLandon J. Fuller     struct siba_core_id *sid)
240111d7cb2SLandon J. Fuller {
2417c7c726bSLandon J. Fuller 	struct siba_admatch	admatch[SIBA_MAX_ADDRSPACE];
242111d7cb2SLandon J. Fuller 	uint32_t		idhigh, idlow;
2437c7c726bSLandon J. Fuller 	uint32_t		tpsflag;
2447c7c726bSLandon J. Fuller 	uint16_t		ocp_vendor;
2457c7c726bSLandon J. Fuller 	uint8_t			sonics_rev;
2467c7c726bSLandon J. Fuller 	uint8_t			num_admatch;
2477c7c726bSLandon J. Fuller 	uint8_t			num_admatch_en;
2487c7c726bSLandon J. Fuller 	uint8_t			num_cfg;
2497c7c726bSLandon J. Fuller 	bool			intr_en;
2507c7c726bSLandon J. Fuller 	u_int			intr_flag;
2517c7c726bSLandon J. Fuller 	int			error;
252111d7cb2SLandon J. Fuller 
253111d7cb2SLandon J. Fuller 	idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
254111d7cb2SLandon J. Fuller 	idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
2557c7c726bSLandon J. Fuller 	tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
256111d7cb2SLandon J. Fuller 
2577c7c726bSLandon J. Fuller 	ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
2587c7c726bSLandon J. Fuller 	sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
2597c7c726bSLandon J. Fuller 	num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
2607c7c726bSLandon J. Fuller 	if (num_admatch > nitems(admatch)) {
2617c7c726bSLandon J. Fuller 		printf("core%u: invalid admatch count %hhu\n", core_idx,
2627c7c726bSLandon J. Fuller 		    num_admatch);
2637c7c726bSLandon J. Fuller 		return (EINVAL);
2647c7c726bSLandon J. Fuller 	}
2657c7c726bSLandon J. Fuller 
2667c7c726bSLandon J. Fuller 	/* Determine backplane interrupt distribution configuration */
2677c7c726bSLandon J. Fuller 	intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0);
2687c7c726bSLandon J. Fuller 	intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
2697c7c726bSLandon J. Fuller 
2707c7c726bSLandon J. Fuller 	/* Determine the number of sonics config register blocks */
2717c7c726bSLandon J. Fuller 	num_cfg = SIBA_CFG_NUM_2_2;
2727c7c726bSLandon J. Fuller 	if (sonics_rev >= SIBA_IDL_SBREV_2_3)
2737c7c726bSLandon J. Fuller 		num_cfg = SIBA_CFG_NUM_2_3;
2747c7c726bSLandon J. Fuller 
2757c7c726bSLandon J. Fuller 	/* Parse all admatch descriptors */
2767c7c726bSLandon J. Fuller 	num_admatch_en = 0;
2777c7c726bSLandon J. Fuller 	for (uint8_t i = 0; i < num_admatch; i++) {
2787c7c726bSLandon J. Fuller 		uint32_t	am_value;
2797c7c726bSLandon J. Fuller 		u_int		am_offset;
2807c7c726bSLandon J. Fuller 
2817c7c726bSLandon J. Fuller 		KASSERT(i < nitems(admatch), ("invalid admatch index"));
2827c7c726bSLandon J. Fuller 
2837c7c726bSLandon J. Fuller 		/* Determine the register offset */
2847c7c726bSLandon J. Fuller 		am_offset = siba_admatch_offset(i);
2857c7c726bSLandon J. Fuller 		if (am_offset == 0) {
2867c7c726bSLandon J. Fuller 			printf("core%u: addrspace %hhu is unsupported",
2877c7c726bSLandon J. Fuller 			    core_idx, i);
2887c7c726bSLandon J. Fuller 			return (ENODEV);
2897c7c726bSLandon J. Fuller 		}
2907c7c726bSLandon J. Fuller 
2917c7c726bSLandon J. Fuller 		/* Read and parse the address match register */
2927c7c726bSLandon J. Fuller 		am_value = siba_eio_read_4(io, core_idx, am_offset);
2937c7c726bSLandon J. Fuller 		error = siba_parse_admatch(am_value, &admatch[num_admatch_en]);
2947c7c726bSLandon J. Fuller 		if (error) {
2957c7c726bSLandon J. Fuller 			printf("core%u: failed to decode admatch[%hhu] "
2967c7c726bSLandon J. Fuller 			    "register value 0x%x\n", core_idx, i, am_value);
2977c7c726bSLandon J. Fuller 			return (error);
2987c7c726bSLandon J. Fuller 		}
2997c7c726bSLandon J. Fuller 
3007c7c726bSLandon J. Fuller 		/* Skip disabled entries */
3017c7c726bSLandon J. Fuller 		if (!admatch[num_admatch_en].am_enabled)
3027c7c726bSLandon J. Fuller 			continue;
3037c7c726bSLandon J. Fuller 
3047c7c726bSLandon J. Fuller 		/* Reject unsupported negative matches. These are not used on
3057c7c726bSLandon J. Fuller 		 * any known devices */
3067c7c726bSLandon J. Fuller 		if (admatch[num_admatch_en].am_negative) {
3077c7c726bSLandon J. Fuller 			printf("core%u: unsupported negative admatch[%hhu] "
3087c7c726bSLandon J. Fuller 			    "value 0x%x\n", core_idx, i, am_value);
3097c7c726bSLandon J. Fuller 			return (ENXIO);
3107c7c726bSLandon J. Fuller 		}
3117c7c726bSLandon J. Fuller 
3127c7c726bSLandon J. Fuller 		num_admatch_en++;
3137c7c726bSLandon J. Fuller 	}
3147c7c726bSLandon J. Fuller 
3157c7c726bSLandon J. Fuller 	/* Populate the result */
3167c7c726bSLandon J. Fuller 	*sid = (struct siba_core_id) {
3177c7c726bSLandon J. Fuller 		.core_info	= {
3187c7c726bSLandon J. Fuller 			.vendor	= siba_get_bhnd_mfgid(ocp_vendor),
3197c7c726bSLandon J. Fuller 			.device	= SIBA_REG_GET(idhigh, IDH_DEVICE),
3207c7c726bSLandon J. Fuller 			.hwrev	= SIBA_IDH_CORE_REV(idhigh),
3217c7c726bSLandon J. Fuller 			.core_idx = core_idx,
3227c7c726bSLandon J. Fuller 			.unit	= unit
3237c7c726bSLandon J. Fuller 		},
3247c7c726bSLandon J. Fuller 		.sonics_vendor	= ocp_vendor,
3257c7c726bSLandon J. Fuller 		.sonics_rev	= sonics_rev,
3267c7c726bSLandon J. Fuller 		.intr_en	= intr_en,
3277c7c726bSLandon J. Fuller 		.intr_flag	= intr_flag,
3287c7c726bSLandon J. Fuller 		.num_admatch	= num_admatch_en,
3297c7c726bSLandon J. Fuller 		.num_cfg_blocks	= num_cfg
3307c7c726bSLandon J. Fuller 	};
3317c7c726bSLandon J. Fuller 	memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0]));
3327c7c726bSLandon J. Fuller 
3337c7c726bSLandon J. Fuller 	return (0);
3347c7c726bSLandon J. Fuller }
3357c7c726bSLandon J. Fuller 
3367c7c726bSLandon J. Fuller /**
3377c7c726bSLandon J. Fuller  * Read and parse the SSB identification registers for the given @p core_index,
3387c7c726bSLandon J. Fuller  * returning the siba(4) core identification in @p sid.
3397c7c726bSLandon J. Fuller  *
3407c7c726bSLandon J. Fuller  * @param sc A siba EROM instance.
3417c7c726bSLandon J. Fuller  * @param core_idx The index of the core to be identified.
3427c7c726bSLandon J. Fuller  * @param[out] result On success, the parsed siba core id.
3437c7c726bSLandon J. Fuller  *
3447c7c726bSLandon J. Fuller  * @retval 0		success
3457c7c726bSLandon J. Fuller  * @retval non-zero     if reading or parsing the identification registers
3467c7c726bSLandon J. Fuller  *			otherwise fails, a regular unix error code will be
3477c7c726bSLandon J. Fuller  *			returned.
3487c7c726bSLandon J. Fuller  */
3497c7c726bSLandon J. Fuller int
siba_erom_get_core_id(struct siba_erom * sc,u_int core_idx,struct siba_core_id * result)3507c7c726bSLandon J. Fuller siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
3517c7c726bSLandon J. Fuller     struct siba_core_id *result)
3527c7c726bSLandon J. Fuller {
3537c7c726bSLandon J. Fuller 	struct siba_core_id	sid;
3547c7c726bSLandon J. Fuller 	int			error;
3557c7c726bSLandon J. Fuller 
3567c7c726bSLandon J. Fuller 	/* Fetch the core info, assuming a unit number of 0 */
3577c7c726bSLandon J. Fuller 	if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid)))
3587c7c726bSLandon J. Fuller 		return (error);
3597c7c726bSLandon J. Fuller 
3607c7c726bSLandon J. Fuller 	/* Scan preceding cores to determine the real unit number. */
3617c7c726bSLandon J. Fuller 	for (u_int i = 0; i < core_idx; i++) {
3627c7c726bSLandon J. Fuller 		struct siba_core_id prev;
3637c7c726bSLandon J. Fuller 
3647c7c726bSLandon J. Fuller 		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev)))
3657c7c726bSLandon J. Fuller 			return (error);
3667c7c726bSLandon J. Fuller 
3677c7c726bSLandon J. Fuller 		/* Bump the unit number? */
3687c7c726bSLandon J. Fuller 		if (sid.core_info.vendor == prev.core_info.vendor &&
3697c7c726bSLandon J. Fuller 		    sid.core_info.device == prev.core_info.device)
3707c7c726bSLandon J. Fuller 			sid.core_info.unit++;
3717c7c726bSLandon J. Fuller 	}
3727c7c726bSLandon J. Fuller 
3737c7c726bSLandon J. Fuller 	*result = sid;
3747c7c726bSLandon J. Fuller 	return (0);
375111d7cb2SLandon J. Fuller }
376111d7cb2SLandon J. Fuller 
377111d7cb2SLandon J. Fuller /**
378111d7cb2SLandon J. Fuller  * Read and parse the chip identification register from the ChipCommon core.
379111d7cb2SLandon J. Fuller  *
380111d7cb2SLandon J. Fuller  * @param io EROM I/O context.
381111d7cb2SLandon J. Fuller  * @param enum_addr The physical address mapped by @p io.
382111d7cb2SLandon J. Fuller  * @param cid On success, the parsed chip identifier.
383111d7cb2SLandon J. Fuller  */
384111d7cb2SLandon J. Fuller static int
siba_eio_read_chipid(struct siba_erom_io * io,bus_addr_t enum_addr,struct bhnd_chipid * cid)385111d7cb2SLandon J. Fuller siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
386111d7cb2SLandon J. Fuller     struct bhnd_chipid *cid)
387111d7cb2SLandon J. Fuller {
388111d7cb2SLandon J. Fuller 	struct siba_core_id	ccid;
3897c7c726bSLandon J. Fuller 	int			error;
390111d7cb2SLandon J. Fuller 
391111d7cb2SLandon J. Fuller 	/* Identify the chipcommon core */
3927c7c726bSLandon J. Fuller 	if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
3937c7c726bSLandon J. Fuller 		return (error);
3947c7c726bSLandon J. Fuller 
395111d7cb2SLandon J. Fuller 	if (ccid.core_info.vendor != BHND_MFGID_BCM ||
396111d7cb2SLandon J. Fuller 	    ccid.core_info.device != BHND_COREID_CC)
397111d7cb2SLandon J. Fuller 	{
398111d7cb2SLandon J. Fuller 		if (bootverbose) {
399111d7cb2SLandon J. Fuller 			EROM_LOG(io, "first core not chipcommon "
400111d7cb2SLandon J. Fuller 			    "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
401111d7cb2SLandon J. Fuller 			    ccid.core_info.device);
402111d7cb2SLandon J. Fuller 		}
403111d7cb2SLandon J. Fuller 		return (ENXIO);
404111d7cb2SLandon J. Fuller 	}
405111d7cb2SLandon J. Fuller 
406111d7cb2SLandon J. Fuller 	/* Identify the chipset */
407*f3524ec8SLandon J. Fuller 	if ((error = bhnd_erom_read_chipid(io->eio, cid)))
408*f3524ec8SLandon J. Fuller 		return (error);
409111d7cb2SLandon J. Fuller 
410*f3524ec8SLandon J. Fuller 	/* Do we need to fix up the core count? */
411*f3524ec8SLandon J. Fuller 	if (CHIPC_NCORES_MIN_HWREV(ccid.core_info.hwrev))
412*f3524ec8SLandon J. Fuller 		return (0);
413*f3524ec8SLandon J. Fuller 
414*f3524ec8SLandon J. Fuller 	switch (cid->chip_id) {
415*f3524ec8SLandon J. Fuller 	case BHND_CHIPID_BCM4306:
416*f3524ec8SLandon J. Fuller 		cid->ncores = 6;
417*f3524ec8SLandon J. Fuller 		break;
418*f3524ec8SLandon J. Fuller 	case BHND_CHIPID_BCM4704:
419*f3524ec8SLandon J. Fuller 		cid->ncores = 9;
420*f3524ec8SLandon J. Fuller 		break;
421*f3524ec8SLandon J. Fuller 	case BHND_CHIPID_BCM5365:
422*f3524ec8SLandon J. Fuller 		/*
423*f3524ec8SLandon J. Fuller 		* BCM5365 does support ID_NUMCORE in at least
424*f3524ec8SLandon J. Fuller 		* some of its revisions, but for unknown
425*f3524ec8SLandon J. Fuller 		* reasons, Broadcom's drivers always exclude
426*f3524ec8SLandon J. Fuller 		* the ChipCommon revision (0x5) used by BCM5365
427*f3524ec8SLandon J. Fuller 		* from the set of revisions supporting
428*f3524ec8SLandon J. Fuller 		* ID_NUMCORE, and instead supply a fixed value.
429*f3524ec8SLandon J. Fuller 		*
430*f3524ec8SLandon J. Fuller 		* Presumably, at least some of these devices
431*f3524ec8SLandon J. Fuller 		* shipped with a broken ID_NUMCORE value.
432*f3524ec8SLandon J. Fuller 		*/
433*f3524ec8SLandon J. Fuller 		cid->ncores = 7;
434*f3524ec8SLandon J. Fuller 		break;
435*f3524ec8SLandon J. Fuller 	default:
436*f3524ec8SLandon J. Fuller 		return (EINVAL);
437*f3524ec8SLandon J. Fuller 	}
438*f3524ec8SLandon J. Fuller 
439*f3524ec8SLandon J. Fuller 	return (0);
440111d7cb2SLandon J. Fuller }
441111d7cb2SLandon J. Fuller 
442664a7497SLandon J. Fuller static int
siba_erom_lookup_core(bhnd_erom_t * erom,const struct bhnd_core_match * desc,struct bhnd_core_info * core)443664a7497SLandon J. Fuller siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
444664a7497SLandon J. Fuller     struct bhnd_core_info *core)
445664a7497SLandon J. Fuller {
446664a7497SLandon J. Fuller 	struct siba_erom	*sc;
447664a7497SLandon J. Fuller 	struct bhnd_core_match	 imatch;
4487c7c726bSLandon J. Fuller 	int			 error;
449664a7497SLandon J. Fuller 
450664a7497SLandon J. Fuller 	sc = (struct siba_erom *)erom;
451664a7497SLandon J. Fuller 
452664a7497SLandon J. Fuller 	/* We can't determine a core's unit number during the initial scan. */
453664a7497SLandon J. Fuller 	imatch = *desc;
454664a7497SLandon J. Fuller 	imatch.m.match.core_unit = 0;
455664a7497SLandon J. Fuller 
456664a7497SLandon J. Fuller 	/* Locate the first matching core */
457111d7cb2SLandon J. Fuller 	for (u_int i = 0; i < sc->io.ncores; i++) {
458664a7497SLandon J. Fuller 		struct siba_core_id	sid;
459664a7497SLandon J. Fuller 		struct bhnd_core_info	ci;
460664a7497SLandon J. Fuller 
461664a7497SLandon J. Fuller 		/* Read the core info */
4627c7c726bSLandon J. Fuller 		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
4637c7c726bSLandon J. Fuller 			return (error);
4647c7c726bSLandon J. Fuller 
465664a7497SLandon J. Fuller 		ci = sid.core_info;
466664a7497SLandon J. Fuller 
467664a7497SLandon J. Fuller 		/* Check for initial match */
468664a7497SLandon J. Fuller 		if (!bhnd_core_matches(&ci, &imatch))
469664a7497SLandon J. Fuller 			continue;
470664a7497SLandon J. Fuller 
471664a7497SLandon J. Fuller 		/* Re-scan preceding cores to determine the unit number. */
472664a7497SLandon J. Fuller 		for (u_int j = 0; j < i; j++) {
4737c7c726bSLandon J. Fuller 			error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
4747c7c726bSLandon J. Fuller 			if (error)
4757c7c726bSLandon J. Fuller 				return (error);
476664a7497SLandon J. Fuller 
477664a7497SLandon J. Fuller 			/* Bump the unit number? */
478664a7497SLandon J. Fuller 			if (sid.core_info.vendor == ci.vendor &&
479664a7497SLandon J. Fuller 			    sid.core_info.device == ci.device)
480664a7497SLandon J. Fuller 				ci.unit++;
481664a7497SLandon J. Fuller 		}
482664a7497SLandon J. Fuller 
483664a7497SLandon J. Fuller 		/* Check for full match against now-valid unit number */
484664a7497SLandon J. Fuller 		if (!bhnd_core_matches(&ci, desc))
485664a7497SLandon J. Fuller 			continue;
486664a7497SLandon J. Fuller 
487664a7497SLandon J. Fuller 		/* Matching core found */
488664a7497SLandon J. Fuller 		*core = ci;
489664a7497SLandon J. Fuller 		return (0);
490664a7497SLandon J. Fuller 	}
491664a7497SLandon J. Fuller 
492664a7497SLandon J. Fuller 	/* Not found */
493664a7497SLandon J. Fuller 	return (ENOENT);
494664a7497SLandon J. Fuller }
495664a7497SLandon J. Fuller 
496664a7497SLandon J. Fuller static int
siba_erom_lookup_core_addr(bhnd_erom_t * erom,const struct bhnd_core_match * desc,bhnd_port_type type,u_int port,u_int region,struct bhnd_core_info * info,bhnd_addr_t * addr,bhnd_size_t * size)497664a7497SLandon J. Fuller siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
498664a7497SLandon J. Fuller     bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
499664a7497SLandon J. Fuller     bhnd_addr_t *addr, bhnd_size_t *size)
500664a7497SLandon J. Fuller {
501664a7497SLandon J. Fuller 	struct siba_erom	*sc;
502664a7497SLandon J. Fuller 	struct bhnd_core_info	 core;
503664a7497SLandon J. Fuller 	struct siba_core_id	 sid;
5047c7c726bSLandon J. Fuller 	struct siba_admatch	 admatch;
5057c7c726bSLandon J. Fuller 	uint32_t		 am;
506664a7497SLandon J. Fuller 	u_int			 am_offset;
507caeff9a3SLandon J. Fuller 	u_int			 addrspace, cfg;
508caeff9a3SLandon J. Fuller 
509664a7497SLandon J. Fuller 	int			 error;
510664a7497SLandon J. Fuller 
511664a7497SLandon J. Fuller 	sc = (struct siba_erom *)erom;
512664a7497SLandon J. Fuller 
513664a7497SLandon J. Fuller 	/* Locate the requested core */
514664a7497SLandon J. Fuller 	if ((error = siba_erom_lookup_core(erom, desc, &core)))
515664a7497SLandon J. Fuller 		return (error);
516664a7497SLandon J. Fuller 
517664a7497SLandon J. Fuller 	/* Fetch full siba core ident */
5187c7c726bSLandon J. Fuller 	error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
5197c7c726bSLandon J. Fuller 	if (error)
5207c7c726bSLandon J. Fuller 		return (error);
521664a7497SLandon J. Fuller 
522664a7497SLandon J. Fuller 	/* Is port valid? */
523caeff9a3SLandon J. Fuller 	if (!siba_is_port_valid(&sid, type, port))
524664a7497SLandon J. Fuller 		return (ENOENT);
525664a7497SLandon J. Fuller 
526664a7497SLandon J. Fuller 	/* Is region valid? */
527caeff9a3SLandon J. Fuller 	if (region >= siba_port_region_count(&sid, type, port))
528664a7497SLandon J. Fuller 		return (ENOENT);
529664a7497SLandon J. Fuller 
530caeff9a3SLandon J. Fuller 	/* Is this a siba configuration region? If so, this is mapped to an
531caeff9a3SLandon J. Fuller 	 * offset within the device0.0 port */
532caeff9a3SLandon J. Fuller 	error = siba_cfg_index(&sid, type, port, region, &cfg);
533caeff9a3SLandon J. Fuller 	if (!error) {
534caeff9a3SLandon J. Fuller 		bhnd_addr_t	region_addr;
535caeff9a3SLandon J. Fuller 		bhnd_addr_t	region_size;
536caeff9a3SLandon J. Fuller 		bhnd_size_t	cfg_offset, cfg_size;
537caeff9a3SLandon J. Fuller 
538caeff9a3SLandon J. Fuller 		cfg_offset = SIBA_CFG_OFFSET(cfg);
539caeff9a3SLandon J. Fuller 		cfg_size = SIBA_CFG_SIZE;
540caeff9a3SLandon J. Fuller 
541caeff9a3SLandon J. Fuller 		/* Fetch the device0.0 addr/size */
542caeff9a3SLandon J. Fuller 		error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
543caeff9a3SLandon J. Fuller 		    0, 0, NULL, &region_addr, &region_size);
544caeff9a3SLandon J. Fuller 		if (error)
545caeff9a3SLandon J. Fuller 			return (error);
546caeff9a3SLandon J. Fuller 
547caeff9a3SLandon J. Fuller 		/* Verify that our offset fits within the region */
548caeff9a3SLandon J. Fuller 		if (region_size < cfg_size) {
549caeff9a3SLandon J. Fuller 			printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
550caeff9a3SLandon J. Fuller 			    bhnd_port_type_name(type), port, region, cfg_offset,
551caeff9a3SLandon J. Fuller 			    bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
552caeff9a3SLandon J. Fuller 
553caeff9a3SLandon J. Fuller 			return (ENXIO);
554caeff9a3SLandon J. Fuller 		}
555caeff9a3SLandon J. Fuller 
556caeff9a3SLandon J. Fuller 		if (BHND_ADDR_MAX - region_addr < cfg_offset) {
557caeff9a3SLandon J. Fuller 			printf("%s%u.%u offset %ju would overflow %s0.0 addr "
558caeff9a3SLandon J. Fuller 			    "%ju\n", bhnd_port_type_name(type), port, region,
559caeff9a3SLandon J. Fuller 			    cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
560caeff9a3SLandon J. Fuller 			    region_addr);
561caeff9a3SLandon J. Fuller 
562caeff9a3SLandon J. Fuller 			return (ENXIO);
563caeff9a3SLandon J. Fuller 		}
564caeff9a3SLandon J. Fuller 
565caeff9a3SLandon J. Fuller 		if (info != NULL)
566caeff9a3SLandon J. Fuller 			*info = core;
567caeff9a3SLandon J. Fuller 
568caeff9a3SLandon J. Fuller 		*addr = region_addr + cfg_offset;
569caeff9a3SLandon J. Fuller 		*size = cfg_size;
570caeff9a3SLandon J. Fuller 		return (0);
571caeff9a3SLandon J. Fuller 	}
572caeff9a3SLandon J. Fuller 
573caeff9a3SLandon J. Fuller 	/*
574caeff9a3SLandon J. Fuller 	 * Otherwise, must be a device port.
575caeff9a3SLandon J. Fuller 	 *
576caeff9a3SLandon J. Fuller 	 * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
577caeff9a3SLandon J. Fuller 	 * bus drivers, we do not exclude the siba(4) configuration blocks from
578caeff9a3SLandon J. Fuller 	 * the first device port.
579caeff9a3SLandon J. Fuller 	 */
580caeff9a3SLandon J. Fuller 	error = siba_addrspace_index(&sid, type, port, region, &addrspace);
581664a7497SLandon J. Fuller 	if (error)
582664a7497SLandon J. Fuller 		return (error);
583664a7497SLandon J. Fuller 
584664a7497SLandon J. Fuller 	/* Determine the register offset */
585664a7497SLandon J. Fuller 	am_offset = siba_admatch_offset(addrspace);
586664a7497SLandon J. Fuller 	if (am_offset == 0) {
587664a7497SLandon J. Fuller 		printf("addrspace %u is unsupported", addrspace);
588664a7497SLandon J. Fuller 		return (ENODEV);
589664a7497SLandon J. Fuller 	}
590664a7497SLandon J. Fuller 
591664a7497SLandon J. Fuller 	/* Read and parse the address match register */
592111d7cb2SLandon J. Fuller 	am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
593664a7497SLandon J. Fuller 
5947c7c726bSLandon J. Fuller 	if ((error = siba_parse_admatch(am, &admatch))) {
595664a7497SLandon J. Fuller 		printf("failed to decode address match register value 0x%x\n",
596664a7497SLandon J. Fuller 		    am);
597664a7497SLandon J. Fuller 		return (error);
598664a7497SLandon J. Fuller 	}
599664a7497SLandon J. Fuller 
600664a7497SLandon J. Fuller 	if (info != NULL)
601664a7497SLandon J. Fuller 		*info = core;
602664a7497SLandon J. Fuller 
6037c7c726bSLandon J. Fuller 	*addr = admatch.am_base;
6047c7c726bSLandon J. Fuller 	*size = admatch.am_size;
605664a7497SLandon J. Fuller 
606664a7497SLandon J. Fuller 	return (0);
607664a7497SLandon J. Fuller }
608664a7497SLandon J. Fuller 
609664a7497SLandon J. Fuller /* BHND_EROM_GET_CORE_TABLE() */
610664a7497SLandon J. Fuller static int
siba_erom_get_core_table(bhnd_erom_t * erom,struct bhnd_core_info ** cores,u_int * num_cores)611664a7497SLandon J. Fuller siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
612664a7497SLandon J. Fuller     u_int *num_cores)
613664a7497SLandon J. Fuller {
614664a7497SLandon J. Fuller 	struct siba_erom	*sc;
615664a7497SLandon J. Fuller 	struct bhnd_core_info	*out;
6167c7c726bSLandon J. Fuller 	int			 error;
617664a7497SLandon J. Fuller 
618664a7497SLandon J. Fuller 	sc = (struct siba_erom *)erom;
619664a7497SLandon J. Fuller 
620664a7497SLandon J. Fuller 	/* Allocate our core array */
62192e1020aSPedro F. Giffuni 	out = mallocarray(sc->io.ncores, sizeof(*out), M_BHND, M_NOWAIT);
622664a7497SLandon J. Fuller 	if (out == NULL)
623664a7497SLandon J. Fuller 		return (ENOMEM);
624664a7497SLandon J. Fuller 
625664a7497SLandon J. Fuller 	*cores = out;
626111d7cb2SLandon J. Fuller 	*num_cores = sc->io.ncores;
627664a7497SLandon J. Fuller 
628664a7497SLandon J. Fuller 	/* Enumerate all cores. */
629111d7cb2SLandon J. Fuller 	for (u_int i = 0; i < sc->io.ncores; i++) {
630664a7497SLandon J. Fuller 		struct siba_core_id sid;
631664a7497SLandon J. Fuller 
632664a7497SLandon J. Fuller 		/* Read the core info */
6337c7c726bSLandon J. Fuller 		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
6347c7c726bSLandon J. Fuller 			return (error);
6357c7c726bSLandon J. Fuller 
636664a7497SLandon J. Fuller 		out[i] = sid.core_info;
637664a7497SLandon J. Fuller 
638664a7497SLandon J. Fuller 		/* Determine unit number */
639664a7497SLandon J. Fuller 		for (u_int j = 0; j < i; j++) {
640664a7497SLandon J. Fuller 			if (out[j].vendor == out[i].vendor &&
641664a7497SLandon J. Fuller 			    out[j].device == out[i].device)
642664a7497SLandon J. Fuller 				out[i].unit++;
643664a7497SLandon J. Fuller 		}
644664a7497SLandon J. Fuller 	}
645664a7497SLandon J. Fuller 
646664a7497SLandon J. Fuller 	return (0);
647664a7497SLandon J. Fuller }
648664a7497SLandon J. Fuller 
649664a7497SLandon J. Fuller /* BHND_EROM_FREE_CORE_TABLE() */
650664a7497SLandon J. Fuller static void
siba_erom_free_core_table(bhnd_erom_t * erom,struct bhnd_core_info * cores)651664a7497SLandon J. Fuller siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
652664a7497SLandon J. Fuller {
653664a7497SLandon J. Fuller 	free(cores, M_BHND);
654664a7497SLandon J. Fuller }
655664a7497SLandon J. Fuller 
656eb23aa80SLandon J. Fuller /* BHND_EROM_DUMP() */
657eb23aa80SLandon J. Fuller static int
siba_erom_dump(bhnd_erom_t * erom)658eb23aa80SLandon J. Fuller siba_erom_dump(bhnd_erom_t *erom)
659eb23aa80SLandon J. Fuller {
660eb23aa80SLandon J. Fuller 	struct siba_erom	*sc;
661eb23aa80SLandon J. Fuller 	int			 error;
662eb23aa80SLandon J. Fuller 
663eb23aa80SLandon J. Fuller 	sc = (struct siba_erom *)erom;
664eb23aa80SLandon J. Fuller 
665eb23aa80SLandon J. Fuller 	/* Enumerate all cores. */
666eb23aa80SLandon J. Fuller 	for (u_int i = 0; i < sc->io.ncores; i++) {
667eb23aa80SLandon J. Fuller 		uint32_t idhigh, idlow;
668eb23aa80SLandon J. Fuller 		uint32_t nraddr;
669eb23aa80SLandon J. Fuller 
670eb23aa80SLandon J. Fuller 		idhigh = siba_eio_read_4(&sc->io, i,
671eb23aa80SLandon J. Fuller 		    SB0_REG_ABS(SIBA_CFG0_IDHIGH));
672eb23aa80SLandon J. Fuller 		idlow = siba_eio_read_4(&sc->io, i,
673eb23aa80SLandon J. Fuller 		    SB0_REG_ABS(SIBA_CFG0_IDLOW));
674eb23aa80SLandon J. Fuller 
675eb23aa80SLandon J. Fuller 		printf("siba core %u:\n", i);
676eb23aa80SLandon J. Fuller 		printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
677eb23aa80SLandon J. Fuller 		printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
678eb23aa80SLandon J. Fuller 		printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
679eb23aa80SLandon J. Fuller 		printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
680eb23aa80SLandon J. Fuller 
681eb23aa80SLandon J. Fuller 		/* Enumerate the address match registers */
682eb23aa80SLandon J. Fuller 		nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
683eb23aa80SLandon J. Fuller 		printf("\tnraddr\t0x%04x\n", nraddr);
684eb23aa80SLandon J. Fuller 
685eb23aa80SLandon J. Fuller 		for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
6867c7c726bSLandon J. Fuller 			struct siba_admatch	admatch;
6877c7c726bSLandon J. Fuller 			uint32_t		am;
688eb23aa80SLandon J. Fuller 			u_int			am_offset;
689eb23aa80SLandon J. Fuller 
690eb23aa80SLandon J. Fuller 			/* Determine the register offset */
691eb23aa80SLandon J. Fuller 			am_offset = siba_admatch_offset(addrspace);
692eb23aa80SLandon J. Fuller 			if (am_offset == 0) {
693eb23aa80SLandon J. Fuller 				printf("addrspace %zu unsupported",
694eb23aa80SLandon J. Fuller 				    addrspace);
695eb23aa80SLandon J. Fuller 				break;
696eb23aa80SLandon J. Fuller 			}
697eb23aa80SLandon J. Fuller 
698eb23aa80SLandon J. Fuller 			/* Read and parse the address match register */
699eb23aa80SLandon J. Fuller 			am = siba_eio_read_4(&sc->io, i, am_offset);
7007c7c726bSLandon J. Fuller 			if ((error = siba_parse_admatch(am, &admatch))) {
701eb23aa80SLandon J. Fuller 				printf("failed to decode address match "
702eb23aa80SLandon J. Fuller 				    "register value 0x%x\n", am);
703eb23aa80SLandon J. Fuller 				continue;
704eb23aa80SLandon J. Fuller 			}
705eb23aa80SLandon J. Fuller 
706eb23aa80SLandon J. Fuller 			printf("\taddrspace %zu\n", addrspace);
7077c7c726bSLandon J. Fuller 			printf("\t\taddr: 0x%08x\n", admatch.am_base);
7087c7c726bSLandon J. Fuller 			printf("\t\tsize: 0x%08x\n", admatch.am_size);
709eb23aa80SLandon J. Fuller 		}
710eb23aa80SLandon J. Fuller 	}
711eb23aa80SLandon J. Fuller 
712eb23aa80SLandon J. Fuller 	return (0);
713eb23aa80SLandon J. Fuller }
714eb23aa80SLandon J. Fuller 
715664a7497SLandon J. Fuller static kobj_method_t siba_erom_methods[] = {
716111d7cb2SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_probe,		siba_erom_probe),
717664a7497SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_init,		siba_erom_init),
718664a7497SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_fini,		siba_erom_fini),
719664a7497SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_get_core_table,	siba_erom_get_core_table),
720664a7497SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_free_core_table,	siba_erom_free_core_table),
721664a7497SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_lookup_core,	siba_erom_lookup_core),
722664a7497SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_lookup_core_addr,	siba_erom_lookup_core_addr),
723eb23aa80SLandon J. Fuller 	KOBJMETHOD(bhnd_erom_dump,		siba_erom_dump),
724664a7497SLandon J. Fuller 
725664a7497SLandon J. Fuller 	KOBJMETHOD_END
726664a7497SLandon J. Fuller };
727664a7497SLandon J. Fuller 
728664a7497SLandon J. Fuller BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));
729