xref: /freebsd/sys/dev/bhnd/siba/siba_subr.c (revision 4ad7e9b01a7a6b2059e17869220ad48740da4e5d)
1*4ad7e9b0SAdrian Chadd /*-
2*4ad7e9b0SAdrian Chadd  * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3*4ad7e9b0SAdrian Chadd  * All rights reserved.
4*4ad7e9b0SAdrian Chadd  *
5*4ad7e9b0SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6*4ad7e9b0SAdrian Chadd  * modification, are permitted provided that the following conditions
7*4ad7e9b0SAdrian Chadd  * are met:
8*4ad7e9b0SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9*4ad7e9b0SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
10*4ad7e9b0SAdrian Chadd  *    without modification.
11*4ad7e9b0SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12*4ad7e9b0SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13*4ad7e9b0SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
14*4ad7e9b0SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
15*4ad7e9b0SAdrian Chadd  *
16*4ad7e9b0SAdrian Chadd  * NO WARRANTY
17*4ad7e9b0SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*4ad7e9b0SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*4ad7e9b0SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20*4ad7e9b0SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21*4ad7e9b0SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22*4ad7e9b0SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*4ad7e9b0SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*4ad7e9b0SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*4ad7e9b0SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*4ad7e9b0SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27*4ad7e9b0SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
28*4ad7e9b0SAdrian Chadd  */
29*4ad7e9b0SAdrian Chadd 
30*4ad7e9b0SAdrian Chadd #include <sys/cdefs.h>
31*4ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$");
32*4ad7e9b0SAdrian Chadd 
33*4ad7e9b0SAdrian Chadd #include <sys/param.h>
34*4ad7e9b0SAdrian Chadd #include <sys/bus.h>
35*4ad7e9b0SAdrian Chadd #include <sys/kernel.h>
36*4ad7e9b0SAdrian Chadd #include <sys/limits.h>
37*4ad7e9b0SAdrian Chadd #include <sys/systm.h>
38*4ad7e9b0SAdrian Chadd 
39*4ad7e9b0SAdrian Chadd #include <machine/bus.h>
40*4ad7e9b0SAdrian Chadd #include <machine/resource.h>
41*4ad7e9b0SAdrian Chadd 
42*4ad7e9b0SAdrian Chadd #include <dev/bhnd/bhndvar.h>
43*4ad7e9b0SAdrian Chadd 
44*4ad7e9b0SAdrian Chadd #include "sibareg.h"
45*4ad7e9b0SAdrian Chadd #include "sibavar.h"
46*4ad7e9b0SAdrian Chadd 
47*4ad7e9b0SAdrian Chadd /**
48*4ad7e9b0SAdrian Chadd  * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
49*4ad7e9b0SAdrian Chadd  * code.
50*4ad7e9b0SAdrian Chadd  *
51*4ad7e9b0SAdrian Chadd  * @param ocp_vendor An OCP vendor code.
52*4ad7e9b0SAdrian Chadd  * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
53*4ad7e9b0SAdrian Chadd  * BHND_MFGID_INVALID if the OCP vendor is unknown.
54*4ad7e9b0SAdrian Chadd  */
55*4ad7e9b0SAdrian Chadd uint16_t
56*4ad7e9b0SAdrian Chadd siba_get_bhnd_mfgid(uint16_t ocp_vendor)
57*4ad7e9b0SAdrian Chadd {
58*4ad7e9b0SAdrian Chadd 	switch (ocp_vendor) {
59*4ad7e9b0SAdrian Chadd 	case OCP_VENDOR_BCM:
60*4ad7e9b0SAdrian Chadd 		return (BHND_MFGID_BCM);
61*4ad7e9b0SAdrian Chadd 	default:
62*4ad7e9b0SAdrian Chadd 		return (BHND_MFGID_INVALID);
63*4ad7e9b0SAdrian Chadd 	}
64*4ad7e9b0SAdrian Chadd }
65*4ad7e9b0SAdrian Chadd 
66*4ad7e9b0SAdrian Chadd /**
67*4ad7e9b0SAdrian Chadd  * Parse the SIBA_IDH_* fields from the per-core identification
68*4ad7e9b0SAdrian Chadd  * registers, returning a siba_core_id representation.
69*4ad7e9b0SAdrian Chadd  *
70*4ad7e9b0SAdrian Chadd  * @param idhigh The SIBA_R0_IDHIGH register.
71*4ad7e9b0SAdrian Chadd  * @param idlow The SIBA_R0_IDLOW register.
72*4ad7e9b0SAdrian Chadd  * @param core_id The core id (index) to include in the result.
73*4ad7e9b0SAdrian Chadd  * @param unit The unit number to include in the result.
74*4ad7e9b0SAdrian Chadd  */
75*4ad7e9b0SAdrian Chadd struct siba_core_id
76*4ad7e9b0SAdrian Chadd siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
77*4ad7e9b0SAdrian Chadd {
78*4ad7e9b0SAdrian Chadd 
79*4ad7e9b0SAdrian Chadd 	uint16_t	ocp_vendor;
80*4ad7e9b0SAdrian Chadd 	uint8_t		sonics_rev;
81*4ad7e9b0SAdrian Chadd 	uint8_t		num_addrspace;
82*4ad7e9b0SAdrian Chadd 	uint8_t		num_cfg;
83*4ad7e9b0SAdrian Chadd 
84*4ad7e9b0SAdrian Chadd 	ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
85*4ad7e9b0SAdrian Chadd 	sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
86*4ad7e9b0SAdrian Chadd 	num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
87*4ad7e9b0SAdrian Chadd 
88*4ad7e9b0SAdrian Chadd 	/* Determine the number of sonics config register blocks */
89*4ad7e9b0SAdrian Chadd 	num_cfg = SIBA_CFG_NUM_2_2;
90*4ad7e9b0SAdrian Chadd 	if (sonics_rev >= SIBA_IDL_SBREV_2_3)
91*4ad7e9b0SAdrian Chadd 		num_cfg = SIBA_CFG_NUM_2_3;
92*4ad7e9b0SAdrian Chadd 
93*4ad7e9b0SAdrian Chadd 	return (struct siba_core_id) {
94*4ad7e9b0SAdrian Chadd 		.core_info	= {
95*4ad7e9b0SAdrian Chadd 			.vendor	= siba_get_bhnd_mfgid(ocp_vendor),
96*4ad7e9b0SAdrian Chadd 			.device	= SIBA_REG_GET(idhigh, IDH_DEVICE),
97*4ad7e9b0SAdrian Chadd 			.hwrev	= SIBA_IDH_CORE_REV(idhigh),
98*4ad7e9b0SAdrian Chadd 			.core_idx = core_idx,
99*4ad7e9b0SAdrian Chadd 			.unit	= unit
100*4ad7e9b0SAdrian Chadd 		},
101*4ad7e9b0SAdrian Chadd 		.sonics_vendor	= ocp_vendor,
102*4ad7e9b0SAdrian Chadd 		.sonics_rev	= sonics_rev,
103*4ad7e9b0SAdrian Chadd 		.num_addrspace	= num_addrspace,
104*4ad7e9b0SAdrian Chadd 		.num_cfg_blocks	= num_cfg
105*4ad7e9b0SAdrian Chadd 	};
106*4ad7e9b0SAdrian Chadd }
107*4ad7e9b0SAdrian Chadd 
108*4ad7e9b0SAdrian Chadd /**
109*4ad7e9b0SAdrian Chadd  * Initialize new port descriptor.
110*4ad7e9b0SAdrian Chadd  *
111*4ad7e9b0SAdrian Chadd  * @param port_num Port number.
112*4ad7e9b0SAdrian Chadd  * @param port_type Port type.
113*4ad7e9b0SAdrian Chadd  */
114*4ad7e9b0SAdrian Chadd static void
115*4ad7e9b0SAdrian Chadd siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num)
116*4ad7e9b0SAdrian Chadd {
117*4ad7e9b0SAdrian Chadd 	port->sp_num = port_num;
118*4ad7e9b0SAdrian Chadd 	port->sp_type = port_type;
119*4ad7e9b0SAdrian Chadd 	port->sp_num_addrs = 0;
120*4ad7e9b0SAdrian Chadd 	STAILQ_INIT(&port->sp_addrs);
121*4ad7e9b0SAdrian Chadd }
122*4ad7e9b0SAdrian Chadd 
123*4ad7e9b0SAdrian Chadd /**
124*4ad7e9b0SAdrian Chadd  * Deallocate all resources associated with the given port descriptor.
125*4ad7e9b0SAdrian Chadd  *
126*4ad7e9b0SAdrian Chadd  * @param port Port descriptor to be deallocated.
127*4ad7e9b0SAdrian Chadd  */
128*4ad7e9b0SAdrian Chadd static void
129*4ad7e9b0SAdrian Chadd siba_release_port(struct siba_port *port) {
130*4ad7e9b0SAdrian Chadd 	struct siba_addrspace *as, *as_next;
131*4ad7e9b0SAdrian Chadd 
132*4ad7e9b0SAdrian Chadd 	STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) {
133*4ad7e9b0SAdrian Chadd 		free(as, M_BHND);
134*4ad7e9b0SAdrian Chadd 	}
135*4ad7e9b0SAdrian Chadd }
136*4ad7e9b0SAdrian Chadd 
137*4ad7e9b0SAdrian Chadd /**
138*4ad7e9b0SAdrian Chadd  * Allocate and initialize new device info structure, copying the
139*4ad7e9b0SAdrian Chadd  * provided core id.
140*4ad7e9b0SAdrian Chadd  *
141*4ad7e9b0SAdrian Chadd  * @param dev The requesting bus device.
142*4ad7e9b0SAdrian Chadd  * @param core Device core info.
143*4ad7e9b0SAdrian Chadd  */
144*4ad7e9b0SAdrian Chadd struct siba_devinfo *
145*4ad7e9b0SAdrian Chadd siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id)
146*4ad7e9b0SAdrian Chadd {
147*4ad7e9b0SAdrian Chadd 	struct siba_devinfo *dinfo;
148*4ad7e9b0SAdrian Chadd 
149*4ad7e9b0SAdrian Chadd 	dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT);
150*4ad7e9b0SAdrian Chadd 	if (dinfo == NULL)
151*4ad7e9b0SAdrian Chadd 		return NULL;
152*4ad7e9b0SAdrian Chadd 
153*4ad7e9b0SAdrian Chadd 	dinfo->core_id = *core_id;
154*4ad7e9b0SAdrian Chadd 
155*4ad7e9b0SAdrian Chadd 	for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
156*4ad7e9b0SAdrian Chadd 		dinfo->cfg[i] = NULL;
157*4ad7e9b0SAdrian Chadd 		dinfo->cfg_rid[i] = -1;
158*4ad7e9b0SAdrian Chadd 	}
159*4ad7e9b0SAdrian Chadd 
160*4ad7e9b0SAdrian Chadd 	siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0);
161*4ad7e9b0SAdrian Chadd 	resource_list_init(&dinfo->resources);
162*4ad7e9b0SAdrian Chadd 
163*4ad7e9b0SAdrian Chadd 	return dinfo;
164*4ad7e9b0SAdrian Chadd }
165*4ad7e9b0SAdrian Chadd 
166*4ad7e9b0SAdrian Chadd /**
167*4ad7e9b0SAdrian Chadd  * Return the @p dinfo port instance for @p type, or NULL.
168*4ad7e9b0SAdrian Chadd  *
169*4ad7e9b0SAdrian Chadd  * @param dinfo The siba device info.
170*4ad7e9b0SAdrian Chadd  * @param type The requested port type.
171*4ad7e9b0SAdrian Chadd  *
172*4ad7e9b0SAdrian Chadd  * @retval siba_port If @p port_type and @p port_num are defined on @p dinfo.
173*4ad7e9b0SAdrian Chadd  * @retval NULL If the requested port is not defined on @p dinfo.
174*4ad7e9b0SAdrian Chadd  */
175*4ad7e9b0SAdrian Chadd struct siba_port *
176*4ad7e9b0SAdrian Chadd siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type,
177*4ad7e9b0SAdrian Chadd     u_int port_num)
178*4ad7e9b0SAdrian Chadd {
179*4ad7e9b0SAdrian Chadd 	/* We only define a single port for any given type. */
180*4ad7e9b0SAdrian Chadd 	if (port_num != 0)
181*4ad7e9b0SAdrian Chadd 		return (NULL);
182*4ad7e9b0SAdrian Chadd 
183*4ad7e9b0SAdrian Chadd 	switch (port_type) {
184*4ad7e9b0SAdrian Chadd 	case BHND_PORT_DEVICE:
185*4ad7e9b0SAdrian Chadd 		return (&dinfo->device_port);
186*4ad7e9b0SAdrian Chadd 	case BHND_PORT_BRIDGE:
187*4ad7e9b0SAdrian Chadd 		return (NULL);
188*4ad7e9b0SAdrian Chadd 	case BHND_PORT_AGENT:
189*4ad7e9b0SAdrian Chadd 		return (NULL);
190*4ad7e9b0SAdrian Chadd 	}
191*4ad7e9b0SAdrian Chadd }
192*4ad7e9b0SAdrian Chadd 
193*4ad7e9b0SAdrian Chadd 
194*4ad7e9b0SAdrian Chadd /**
195*4ad7e9b0SAdrian Chadd  * Find an address space with @p sid on @p port.
196*4ad7e9b0SAdrian Chadd  *
197*4ad7e9b0SAdrian Chadd  * @param port The port to search for a matching address space.
198*4ad7e9b0SAdrian Chadd  * @param sid The siba-assigned address space ID to search for.
199*4ad7e9b0SAdrian Chadd  */
200*4ad7e9b0SAdrian Chadd struct siba_addrspace *
201*4ad7e9b0SAdrian Chadd siba_find_port_addrspace(struct siba_port *port, uint8_t sid)
202*4ad7e9b0SAdrian Chadd {
203*4ad7e9b0SAdrian Chadd 	struct siba_addrspace	*addrspace;
204*4ad7e9b0SAdrian Chadd 
205*4ad7e9b0SAdrian Chadd 	STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
206*4ad7e9b0SAdrian Chadd 		if (addrspace->sa_sid == sid)
207*4ad7e9b0SAdrian Chadd 			return (addrspace);
208*4ad7e9b0SAdrian Chadd 	}
209*4ad7e9b0SAdrian Chadd 
210*4ad7e9b0SAdrian Chadd 	/* not found */
211*4ad7e9b0SAdrian Chadd 	return (NULL);
212*4ad7e9b0SAdrian Chadd }
213*4ad7e9b0SAdrian Chadd 
214*4ad7e9b0SAdrian Chadd /**
215*4ad7e9b0SAdrian Chadd  * Append a new address space entry to @p port_num of type @p port_type
216*4ad7e9b0SAdrian Chadd  * in @p dinfo.
217*4ad7e9b0SAdrian Chadd  *
218*4ad7e9b0SAdrian Chadd  * The range will also be registered in @p dinfo resource list.
219*4ad7e9b0SAdrian Chadd  *
220*4ad7e9b0SAdrian Chadd  * @param dinfo The device info entry to update.
221*4ad7e9b0SAdrian Chadd  * @param port_type The port type.
222*4ad7e9b0SAdrian Chadd  * @param port_num The port number.
223*4ad7e9b0SAdrian Chadd  * @param region_num The region index number.
224*4ad7e9b0SAdrian Chadd  * @param sid The siba-assigned core-unique address space identifier.
225*4ad7e9b0SAdrian Chadd  * @param base The mapping's base address.
226*4ad7e9b0SAdrian Chadd  * @param size The mapping size.
227*4ad7e9b0SAdrian Chadd  * @param bus_reserved Number of bytes to reserve in @p size for bus use
228*4ad7e9b0SAdrian Chadd  * when registering the resource list entry. This is used to reserve bus
229*4ad7e9b0SAdrian Chadd  * access to the core's SIBA_CFG* register blocks.
230*4ad7e9b0SAdrian Chadd  *
231*4ad7e9b0SAdrian Chadd  * @retval 0 success
232*4ad7e9b0SAdrian Chadd  * @retval non-zero An error occurred appending the entry.
233*4ad7e9b0SAdrian Chadd  */
234*4ad7e9b0SAdrian Chadd int
235*4ad7e9b0SAdrian Chadd siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
236*4ad7e9b0SAdrian Chadd     u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size,
237*4ad7e9b0SAdrian Chadd     uint32_t bus_reserved)
238*4ad7e9b0SAdrian Chadd {
239*4ad7e9b0SAdrian Chadd 	struct siba_addrspace	*sa;
240*4ad7e9b0SAdrian Chadd 	struct siba_port	*port;
241*4ad7e9b0SAdrian Chadd 
242*4ad7e9b0SAdrian Chadd 	/* Verify that base + size will not overflow */
243*4ad7e9b0SAdrian Chadd 	if (UINT32_MAX - size < base)
244*4ad7e9b0SAdrian Chadd 		return (ERANGE);
245*4ad7e9b0SAdrian Chadd 
246*4ad7e9b0SAdrian Chadd 	/* Must not be 0-length */
247*4ad7e9b0SAdrian Chadd 	if (size == 0)
248*4ad7e9b0SAdrian Chadd 		return (EINVAL);
249*4ad7e9b0SAdrian Chadd 
250*4ad7e9b0SAdrian Chadd 	/* Determine target port */
251*4ad7e9b0SAdrian Chadd 	port = siba_dinfo_get_port(dinfo, port_type, port_num);
252*4ad7e9b0SAdrian Chadd 	if (port == NULL)
253*4ad7e9b0SAdrian Chadd 		return (EINVAL);
254*4ad7e9b0SAdrian Chadd 
255*4ad7e9b0SAdrian Chadd 	/* Allocate new addrspace entry */
256*4ad7e9b0SAdrian Chadd 	sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO);
257*4ad7e9b0SAdrian Chadd 	if (sa == NULL)
258*4ad7e9b0SAdrian Chadd 		return (ENOMEM);
259*4ad7e9b0SAdrian Chadd 
260*4ad7e9b0SAdrian Chadd 	sa->sa_base = base;
261*4ad7e9b0SAdrian Chadd 	sa->sa_size = size;
262*4ad7e9b0SAdrian Chadd 	sa->sa_sid = sid;
263*4ad7e9b0SAdrian Chadd 	sa->sa_region_num = region_num;
264*4ad7e9b0SAdrian Chadd 
265*4ad7e9b0SAdrian Chadd 	/* Populate the resource list */
266*4ad7e9b0SAdrian Chadd 	size -= bus_reserved;
267*4ad7e9b0SAdrian Chadd 	sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
268*4ad7e9b0SAdrian Chadd 	    base, base + size - 1, size);
269*4ad7e9b0SAdrian Chadd 
270*4ad7e9b0SAdrian Chadd 	/* Append to target port */
271*4ad7e9b0SAdrian Chadd 	STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
272*4ad7e9b0SAdrian Chadd 	port->sp_num_addrs++;
273*4ad7e9b0SAdrian Chadd 
274*4ad7e9b0SAdrian Chadd 	return (0);
275*4ad7e9b0SAdrian Chadd }
276*4ad7e9b0SAdrian Chadd 
277*4ad7e9b0SAdrian Chadd /**
278*4ad7e9b0SAdrian Chadd  * Deallocate the given device info structure and any associated resources.
279*4ad7e9b0SAdrian Chadd  *
280*4ad7e9b0SAdrian Chadd  * @param dev The requesting bus device.
281*4ad7e9b0SAdrian Chadd  * @param dinfo Device info to be deallocated.
282*4ad7e9b0SAdrian Chadd  */
283*4ad7e9b0SAdrian Chadd void
284*4ad7e9b0SAdrian Chadd siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo)
285*4ad7e9b0SAdrian Chadd {
286*4ad7e9b0SAdrian Chadd 	siba_release_port(&dinfo->device_port);
287*4ad7e9b0SAdrian Chadd 
288*4ad7e9b0SAdrian Chadd 	resource_list_free(&dinfo->resources);
289*4ad7e9b0SAdrian Chadd 
290*4ad7e9b0SAdrian Chadd 	/* Free all mapped configuration blocks */
291*4ad7e9b0SAdrian Chadd 	for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
292*4ad7e9b0SAdrian Chadd 		if (dinfo->cfg[i] == NULL)
293*4ad7e9b0SAdrian Chadd 			continue;
294*4ad7e9b0SAdrian Chadd 
295*4ad7e9b0SAdrian Chadd 		bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
296*4ad7e9b0SAdrian Chadd 		    dinfo->cfg[i]);
297*4ad7e9b0SAdrian Chadd 
298*4ad7e9b0SAdrian Chadd 		dinfo->cfg[i] = NULL;
299*4ad7e9b0SAdrian Chadd 		dinfo->cfg_rid[i] = -1;
300*4ad7e9b0SAdrian Chadd 	}
301*4ad7e9b0SAdrian Chadd 
302*4ad7e9b0SAdrian Chadd 	free(dinfo, M_BHND);
303*4ad7e9b0SAdrian Chadd }
304*4ad7e9b0SAdrian Chadd 
305*4ad7e9b0SAdrian Chadd /**
306*4ad7e9b0SAdrian Chadd  * Return the core-enumeration-relative offset for the @p addrspace
307*4ad7e9b0SAdrian Chadd  * SIBA_R0_ADMATCH* register.
308*4ad7e9b0SAdrian Chadd  *
309*4ad7e9b0SAdrian Chadd  * @param addrspace The address space index.
310*4ad7e9b0SAdrian Chadd  *
311*4ad7e9b0SAdrian Chadd  * @retval non-zero success
312*4ad7e9b0SAdrian Chadd  * @retval 0 the given @p addrspace index is not supported.
313*4ad7e9b0SAdrian Chadd  */
314*4ad7e9b0SAdrian Chadd u_int
315*4ad7e9b0SAdrian Chadd siba_admatch_offset(uint8_t addrspace)
316*4ad7e9b0SAdrian Chadd {
317*4ad7e9b0SAdrian Chadd 	switch (addrspace) {
318*4ad7e9b0SAdrian Chadd 	case 0:
319*4ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
320*4ad7e9b0SAdrian Chadd 	case 1:
321*4ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
322*4ad7e9b0SAdrian Chadd 	case 2:
323*4ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
324*4ad7e9b0SAdrian Chadd 	case 3:
325*4ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
326*4ad7e9b0SAdrian Chadd 	default:
327*4ad7e9b0SAdrian Chadd 		return (0);
328*4ad7e9b0SAdrian Chadd 	}
329*4ad7e9b0SAdrian Chadd }
330*4ad7e9b0SAdrian Chadd 
331*4ad7e9b0SAdrian Chadd /**
332*4ad7e9b0SAdrian Chadd  * Parse a SIBA_R0_ADMATCH* register.
333*4ad7e9b0SAdrian Chadd  *
334*4ad7e9b0SAdrian Chadd  * @param addrspace The address space index.
335*4ad7e9b0SAdrian Chadd  * @param am The address match register value to be parsed.
336*4ad7e9b0SAdrian Chadd  * @param[out] addr The parsed address.
337*4ad7e9b0SAdrian Chadd  * @param[out] size The parsed size.
338*4ad7e9b0SAdrian Chadd  *
339*4ad7e9b0SAdrian Chadd  * @retval 0 success
340*4ad7e9b0SAdrian Chadd  * @retval non-zero a parse error occured.
341*4ad7e9b0SAdrian Chadd  */
342*4ad7e9b0SAdrian Chadd int
343*4ad7e9b0SAdrian Chadd siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
344*4ad7e9b0SAdrian Chadd {
345*4ad7e9b0SAdrian Chadd 	u_int		am_type;
346*4ad7e9b0SAdrian Chadd 
347*4ad7e9b0SAdrian Chadd 	/* Negative encoding is not supported. This is not used on any
348*4ad7e9b0SAdrian Chadd 	 * currently known devices*/
349*4ad7e9b0SAdrian Chadd 	if (am & SIBA_AM_ADNEG)
350*4ad7e9b0SAdrian Chadd 		return (EINVAL);
351*4ad7e9b0SAdrian Chadd 
352*4ad7e9b0SAdrian Chadd 	/* Extract the base address and size */
353*4ad7e9b0SAdrian Chadd 	am_type = SIBA_REG_GET(am, AM_TYPE);
354*4ad7e9b0SAdrian Chadd 	switch (am_type) {
355*4ad7e9b0SAdrian Chadd 	case 0:
356*4ad7e9b0SAdrian Chadd 		*addr = am & SIBA_AM_BASE0_MASK;
357*4ad7e9b0SAdrian Chadd 		*size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
358*4ad7e9b0SAdrian Chadd 		break;
359*4ad7e9b0SAdrian Chadd 	case 1:
360*4ad7e9b0SAdrian Chadd 		*addr = am & SIBA_AM_BASE1_MASK;
361*4ad7e9b0SAdrian Chadd 		*size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
362*4ad7e9b0SAdrian Chadd 		break;
363*4ad7e9b0SAdrian Chadd 	case 2:
364*4ad7e9b0SAdrian Chadd 		*addr = am & SIBA_AM_BASE2_MASK;
365*4ad7e9b0SAdrian Chadd 		*size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
366*4ad7e9b0SAdrian Chadd 		break;
367*4ad7e9b0SAdrian Chadd 	default:
368*4ad7e9b0SAdrian Chadd 		return (EINVAL);
369*4ad7e9b0SAdrian Chadd 	}
370*4ad7e9b0SAdrian Chadd 
371*4ad7e9b0SAdrian Chadd 	return (0);
372*4ad7e9b0SAdrian Chadd }