xref: /freebsd/sys/dev/bhnd/bcma/bcma.c (revision d96700a6da2afa88607fbd7405ade439424d10d9)
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$");
32 
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/systm.h>
39 
40 #include <machine/bus.h>
41 
42 #include "bcmavar.h"
43 
44 #include "bcma_eromreg.h"
45 #include "bcma_eromvar.h"
46 #include <dev/bhnd/bhnd_core.h>
47 
48 int
49 bcma_probe(device_t dev)
50 {
51 	device_set_desc(dev, "BCMA BHND bus");
52 	return (BUS_PROBE_DEFAULT);
53 }
54 
55 int
56 bcma_attach(device_t dev)
57 {
58 	struct bcma_devinfo	*dinfo;
59 	device_t		*devs, child;
60 	int			 ndevs;
61 	int			 error;
62 
63 
64 	if ((error = device_get_children(dev, &devs, &ndevs)))
65 		return (error);
66 
67 	/*
68 	 * Map our children's agent register block.
69 	 */
70 	for (int i = 0; i < ndevs; i++) {
71 		bhnd_addr_t	addr;
72 		bhnd_size_t	size;
73 		rman_res_t	r_start, r_count, r_end;
74 
75 		child = devs[i];
76 		dinfo = device_get_ivars(child);
77 
78 		KASSERT(!device_is_suspended(child),
79 		    ("bcma(4) stateful suspend handling requires that devices "
80 		        "not be suspended before bcma_attach()"));
81 
82 		/* Verify that the agent register block exists and is
83 		 * mappable */
84 		if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1)
85 			continue;
86 
87 		/* Fetch the address of the agent register block */
88 		error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0,
89 		    &addr, &size);
90 		if (error) {
91 			device_printf(dev, "failed fetching agent register "
92 			    "block address for core %d\n", i);
93 			goto cleanup;
94 		}
95 
96 		/* Allocate the resource */
97 		r_start = addr;
98 		r_count = size;
99 		r_end = r_start + r_count - 1;
100 
101 		dinfo->rid_agent = i + 1;
102 		dinfo->res_agent = BHND_BUS_ALLOC_RESOURCE(dev, dev,
103 		    SYS_RES_MEMORY, &dinfo->rid_agent, r_start, r_end, r_count,
104 		    RF_ACTIVE);
105 		if (dinfo->res_agent == NULL) {
106 			device_printf(dev, "failed allocating agent register "
107 			    "block for core %d\n", i);
108 			error = ENXIO;
109 			goto cleanup;
110 		}
111 	}
112 
113 cleanup:
114 	free(devs, M_BHND);
115 	if (error)
116 		return (error);
117 
118 	return (bhnd_generic_attach(dev));
119 }
120 
121 int
122 bcma_detach(device_t dev)
123 {
124 	return (bhnd_generic_detach(dev));
125 }
126 
127 static int
128 bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
129 {
130 	const struct bcma_devinfo *dinfo;
131 	const struct bhnd_core_info *ci;
132 
133 	dinfo = device_get_ivars(child);
134 	ci = &dinfo->corecfg->core_info;
135 
136 	switch (index) {
137 	case BHND_IVAR_VENDOR:
138 		*result = ci->vendor;
139 		return (0);
140 	case BHND_IVAR_DEVICE:
141 		*result = ci->device;
142 		return (0);
143 	case BHND_IVAR_HWREV:
144 		*result = ci->hwrev;
145 		return (0);
146 	case BHND_IVAR_DEVICE_CLASS:
147 		*result = bhnd_core_class(ci);
148 		return (0);
149 	case BHND_IVAR_VENDOR_NAME:
150 		*result = (uintptr_t) bhnd_vendor_name(ci->vendor);
151 		return (0);
152 	case BHND_IVAR_DEVICE_NAME:
153 		*result = (uintptr_t) bhnd_core_name(ci);
154 		return (0);
155 	case BHND_IVAR_CORE_INDEX:
156 		*result = ci->core_idx;
157 		return (0);
158 	case BHND_IVAR_CORE_UNIT:
159 		*result = ci->unit;
160 		return (0);
161 	default:
162 		return (ENOENT);
163 	}
164 }
165 
166 static int
167 bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
168 {
169 	switch (index) {
170 	case BHND_IVAR_VENDOR:
171 	case BHND_IVAR_DEVICE:
172 	case BHND_IVAR_HWREV:
173 	case BHND_IVAR_DEVICE_CLASS:
174 	case BHND_IVAR_VENDOR_NAME:
175 	case BHND_IVAR_DEVICE_NAME:
176 	case BHND_IVAR_CORE_INDEX:
177 	case BHND_IVAR_CORE_UNIT:
178 		return (EINVAL);
179 	default:
180 		return (ENOENT);
181 	}
182 }
183 
184 static struct resource_list *
185 bcma_get_resource_list(device_t dev, device_t child)
186 {
187 	struct bcma_devinfo *dinfo = device_get_ivars(child);
188 	return (&dinfo->resources);
189 }
190 
191 static device_t
192 bcma_find_hostb_device(device_t dev)
193 {
194 	struct bcma_softc *sc = device_get_softc(dev);
195 
196 	/* This is set (or not) by the concrete bcma driver subclass. */
197 	return (sc->hostb_dev);
198 }
199 
200 static int
201 bcma_reset_core(device_t dev, device_t child, uint16_t flags)
202 {
203 	struct bcma_devinfo *dinfo;
204 
205 	if (device_get_parent(child) != dev)
206 		BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags);
207 
208 	dinfo = device_get_ivars(child);
209 
210 	/* Can't reset the core without access to the agent registers */
211 	if (dinfo->res_agent == NULL)
212 		return (ENODEV);
213 
214 	/* Start reset */
215 	bhnd_bus_write_4(dinfo->res_agent, BHND_RESET_CF, BHND_RESET_CF_ENABLE);
216 	bhnd_bus_read_4(dinfo->res_agent, BHND_RESET_CF);
217 	DELAY(10);
218 
219 	/* Disable clock */
220 	bhnd_bus_write_4(dinfo->res_agent, BHND_CF, flags);
221 	bhnd_bus_read_4(dinfo->res_agent, BHND_CF);
222 	DELAY(10);
223 
224 	/* Enable clocks & force clock gating */
225 	bhnd_bus_write_4(dinfo->res_agent, BHND_CF, BHND_CF_CLOCK_EN |
226 	    BHND_CF_FGC | flags);
227 	bhnd_bus_read_4(dinfo->res_agent, BHND_CF);
228 	DELAY(10);
229 
230 	/* Complete reset */
231 	bhnd_bus_write_4(dinfo->res_agent, BHND_RESET_CF, 0);
232 	bhnd_bus_read_4(dinfo->res_agent, BHND_RESET_CF);
233 	DELAY(10);
234 
235 	/* Release force clock gating */
236 	bhnd_bus_write_4(dinfo->res_agent, BHND_CF, BHND_CF_CLOCK_EN | flags);
237 	bhnd_bus_read_4(dinfo->res_agent, BHND_CF);
238 	DELAY(10);
239 
240 	return (0);
241 }
242 
243 static int
244 bcma_suspend_core(device_t dev, device_t child)
245 {
246 	struct bcma_devinfo *dinfo;
247 
248 	if (device_get_parent(child) != dev)
249 		BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child);
250 
251 	dinfo = device_get_ivars(child);
252 
253 	/* Can't suspend the core without access to the agent registers */
254 	if (dinfo->res_agent == NULL)
255 		return (ENODEV);
256 
257 	// TODO - perform suspend
258 
259 	return (ENXIO);
260 }
261 
262 static uint32_t
263 bcma_read_config(device_t dev, device_t child, bus_size_t offset, u_int width)
264 {
265 	struct bcma_devinfo	*dinfo;
266 	struct bhnd_resource	*r;
267 
268 	/* Must be a directly attached child core */
269 	if (device_get_parent(child) != dev)
270 		return (UINT32_MAX);
271 
272 	/* Fetch the agent registers */
273 	dinfo = device_get_ivars(child);
274 	if ((r = dinfo->res_agent) == NULL)
275 		return (UINT32_MAX);
276 
277 	/* Verify bounds */
278 	if (offset > rman_get_size(r->res))
279 		return (UINT32_MAX);
280 
281 	if (rman_get_size(r->res) - offset < width)
282 		return (UINT32_MAX);
283 
284 	switch (width) {
285 	case 1:
286 		return (bhnd_bus_read_1(r, offset));
287 	case 2:
288 		return (bhnd_bus_read_2(r, offset));
289 	case 4:
290 		return (bhnd_bus_read_4(r, offset));
291 	default:
292 		return (UINT32_MAX);
293 	}
294 }
295 
296 static void
297 bcma_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val,
298     u_int width)
299 {
300 	struct bcma_devinfo	*dinfo;
301 	struct bhnd_resource	*r;
302 
303 	/* Must be a directly attached child core */
304 	if (device_get_parent(child) != dev)
305 		return;
306 
307 	/* Fetch the agent registers */
308 	dinfo = device_get_ivars(child);
309 	if ((r = dinfo->res_agent) == NULL)
310 		return;
311 
312 	/* Verify bounds */
313 	if (offset > rman_get_size(r->res))
314 		return;
315 
316 	if (rman_get_size(r->res) - offset < width)
317 		return;
318 
319 	switch (width) {
320 	case 1:
321 		bhnd_bus_write_1(r, offset, val);
322 		break;
323 	case 2:
324 		bhnd_bus_write_2(r, offset, val);
325 		break;
326 	case 4:
327 		bhnd_bus_write_4(r, offset, val);
328 		break;
329 	default:
330 		break;
331 	}
332 }
333 
334 static u_int
335 bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
336 {
337 	struct bcma_devinfo *dinfo;
338 
339 	/* delegate non-bus-attached devices to our parent */
340 	if (device_get_parent(child) != dev)
341 		return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
342 		    type));
343 
344 	dinfo = device_get_ivars(child);
345 	switch (type) {
346 	case BHND_PORT_DEVICE:
347 		return (dinfo->corecfg->num_dev_ports);
348 	case BHND_PORT_BRIDGE:
349 		return (dinfo->corecfg->num_bridge_ports);
350 	case BHND_PORT_AGENT:
351 		return (dinfo->corecfg->num_wrapper_ports);
352 	default:
353 		device_printf(dev, "%s: unknown type (%d)\n",
354 		    __func__,
355 		    type);
356 		return (0);
357 	}
358 }
359 
360 static u_int
361 bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type,
362     u_int port_num)
363 {
364 	struct bcma_devinfo	*dinfo;
365 	struct bcma_sport_list	*ports;
366 	struct bcma_sport	*port;
367 
368 	/* delegate non-bus-attached devices to our parent */
369 	if (device_get_parent(child) != dev)
370 		return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
371 		    type, port_num));
372 
373 	dinfo = device_get_ivars(child);
374 	ports = bcma_corecfg_get_port_list(dinfo->corecfg, type);
375 
376 	STAILQ_FOREACH(port, ports, sp_link) {
377 		if (port->sp_num == port_num)
378 			return (port->sp_num_maps);
379 	}
380 
381 	/* not found */
382 	return (0);
383 }
384 
385 static int
386 bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
387     u_int port_num, u_int region_num)
388 {
389 	struct bcma_devinfo	*dinfo;
390 	struct bcma_map		*map;
391 	struct bcma_sport_list	*ports;
392 	struct bcma_sport	*port;
393 
394 	dinfo = device_get_ivars(child);
395 	ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
396 
397 	STAILQ_FOREACH(port, ports, sp_link) {
398 		if (port->sp_num != port_num)
399 			continue;
400 
401 		STAILQ_FOREACH(map, &port->sp_maps, m_link)
402 			if (map->m_region_num == region_num)
403 				return map->m_rid;
404 	}
405 
406 	return -1;
407 }
408 
409 static int
410 bcma_decode_port_rid(device_t dev, device_t child, int type, int rid,
411     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
412 {
413 	struct bcma_devinfo	*dinfo;
414 	struct bcma_map		*map;
415 	struct bcma_sport_list	*ports;
416 	struct bcma_sport	*port;
417 
418 	dinfo = device_get_ivars(child);
419 
420 	/* Ports are always memory mapped */
421 	if (type != SYS_RES_MEMORY)
422 		return (EINVAL);
423 
424 	/* Starting with the most likely device list, search all three port
425 	 * lists */
426 	bhnd_port_type types[] = {
427 	    BHND_PORT_DEVICE,
428 	    BHND_PORT_AGENT,
429 	    BHND_PORT_BRIDGE
430 	};
431 
432 	for (int i = 0; i < nitems(types); i++) {
433 		ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]);
434 
435 		STAILQ_FOREACH(port, ports, sp_link) {
436 			STAILQ_FOREACH(map, &port->sp_maps, m_link) {
437 				if (map->m_rid != rid)
438 					continue;
439 
440 				*port_type = port->sp_type;
441 				*port_num = port->sp_num;
442 				*region_num = map->m_region_num;
443 				return (0);
444 			}
445 		}
446 	}
447 
448 	return (ENOENT);
449 }
450 
451 static int
452 bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
453     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
454 {
455 	struct bcma_devinfo	*dinfo;
456 	struct bcma_map		*map;
457 	struct bcma_sport_list	*ports;
458 	struct bcma_sport	*port;
459 
460 	dinfo = device_get_ivars(child);
461 	ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
462 
463 	/* Search the port list */
464 	STAILQ_FOREACH(port, ports, sp_link) {
465 		if (port->sp_num != port_num)
466 			continue;
467 
468 		STAILQ_FOREACH(map, &port->sp_maps, m_link) {
469 			if (map->m_region_num != region_num)
470 				continue;
471 
472 			/* Found! */
473 			*addr = map->m_base;
474 			*size = map->m_size;
475 			return (0);
476 		}
477 	}
478 
479 	return (ENOENT);
480 }
481 
482 static struct bhnd_devinfo *
483 bcma_alloc_bhnd_dinfo(device_t dev)
484 {
485 	struct bcma_devinfo *dinfo = bcma_alloc_dinfo(dev);
486 	return ((struct bhnd_devinfo *)dinfo);
487 }
488 
489 static void
490 bcma_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
491 {
492 	bcma_free_dinfo(dev, (struct bcma_devinfo *)dinfo);
493 }
494 
495 
496 static int
497 bcma_get_core_table(device_t dev, device_t child, struct bhnd_core_info **cores,
498     u_int *num_cores)
499 {
500 	struct bcma_softc		*sc;
501 	struct bcma_erom		 erom;
502 	const struct bhnd_chipid	*cid;
503 	struct resource			*r;
504 	int				 error;
505 	int				 rid;
506 
507 	sc = device_get_softc(dev);
508 
509 	/* Map the EROM table. */
510 	cid = BHND_BUS_GET_CHIPID(dev, dev);
511 	rid = 0;
512 	r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr,
513 	    cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE,
514 	    RF_ACTIVE);
515 	if (r == NULL) {
516 		device_printf(dev, "failed to allocate EROM resource\n");
517 		return (ENXIO);
518 	}
519 
520 	/* Enumerate all declared cores */
521 	if ((error = bcma_erom_open(&erom, r, BCMA_EROM_TABLE_START)))
522 		goto cleanup;
523 
524 	error = bcma_erom_get_core_info(&erom, cores, num_cores);
525 
526 cleanup:
527 	bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
528 	return (error);
529 }
530 
531 /**
532  * Scan a device enumeration ROM table, adding all valid discovered cores to
533  * the bus.
534  *
535  * @param bus The bcma bus.
536  * @param erom_res An active resource mapping the EROM core.
537  * @param erom_offset Base offset of the EROM core's register mapping.
538  */
539 int
540 bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offset)
541 {
542 	struct bcma_erom	 erom;
543 	struct bcma_corecfg	*corecfg;
544 	struct bcma_devinfo	*dinfo;
545 	device_t		 child;
546 	int			 error;
547 
548 	corecfg = NULL;
549 
550 	/* Initialize our reader */
551 	error = bcma_erom_open(&erom, erom_res, erom_offset);
552 	if (error)
553 		return (error);
554 
555 	/* Add all cores. */
556 	while (!error) {
557 		/* Parse next core */
558 		error = bcma_erom_parse_corecfg(&erom, &corecfg);
559 		if (error && error == ENOENT) {
560 			return (0);
561 		} else if (error) {
562 			goto failed;
563 		}
564 
565 		/* Add the child device */
566 		child = BUS_ADD_CHILD(bus, 0, NULL, -1);
567 		if (child == NULL) {
568 			error = ENXIO;
569 			goto failed;
570 		}
571 
572 		/* Initialize device ivars */
573 		dinfo = device_get_ivars(child);
574 		if ((error = bcma_init_dinfo(bus, dinfo, corecfg)))
575 			goto failed;
576 
577 		/* The dinfo instance now owns the corecfg value */
578 		corecfg = NULL;
579 
580 		/* If pins are floating or the hardware is otherwise
581 		 * unpopulated, the device shouldn't be used. */
582 		if (bhnd_is_hw_disabled(child))
583 			device_disable(child);
584 
585 		/* Issue bus callback for fully initialized child. */
586 		BHND_BUS_CHILD_ADDED(bus, child);
587 	}
588 
589 	/* Hit EOF parsing cores? */
590 	if (error == ENOENT)
591 		return (0);
592 
593 failed:
594 	if (corecfg != NULL)
595 		bcma_free_corecfg(corecfg);
596 
597 	return (error);
598 }
599 
600 
601 static device_method_t bcma_methods[] = {
602 	/* Device interface */
603 	DEVMETHOD(device_probe,			bcma_probe),
604 	DEVMETHOD(device_attach,		bcma_attach),
605 	DEVMETHOD(device_detach,		bcma_detach),
606 
607 	/* Bus interface */
608 	DEVMETHOD(bus_read_ivar,		bcma_read_ivar),
609 	DEVMETHOD(bus_write_ivar,		bcma_write_ivar),
610 	DEVMETHOD(bus_get_resource_list,	bcma_get_resource_list),
611 
612 	/* BHND interface */
613 	DEVMETHOD(bhnd_bus_find_hostb_device,	bcma_find_hostb_device),
614 	DEVMETHOD(bhnd_bus_alloc_devinfo,	bcma_alloc_bhnd_dinfo),
615 	DEVMETHOD(bhnd_bus_free_devinfo,	bcma_free_bhnd_dinfo),
616 	DEVMETHOD(bhnd_bus_get_core_table,	bcma_get_core_table),
617 	DEVMETHOD(bhnd_bus_reset_core,		bcma_reset_core),
618 	DEVMETHOD(bhnd_bus_suspend_core,	bcma_suspend_core),
619 	DEVMETHOD(bhnd_bus_read_config,		bcma_read_config),
620 	DEVMETHOD(bhnd_bus_write_config,	bcma_write_config),
621 	DEVMETHOD(bhnd_bus_get_port_count,	bcma_get_port_count),
622 	DEVMETHOD(bhnd_bus_get_region_count,	bcma_get_region_count),
623 	DEVMETHOD(bhnd_bus_get_port_rid,	bcma_get_port_rid),
624 	DEVMETHOD(bhnd_bus_decode_port_rid,	bcma_decode_port_rid),
625 	DEVMETHOD(bhnd_bus_get_region_addr,	bcma_get_region_addr),
626 
627 	DEVMETHOD_END
628 };
629 
630 DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver);
631 MODULE_VERSION(bcma, 1);
632 MODULE_DEPEND(bcma, bhnd, 1, 1, 1);
633