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 <dev/bhnd/cores/chipc/chipcreg.h>
43
44#include "sibareg.h"
45#include "sibavar.h"
46
47int
48siba_probe(device_t dev)
49{
50	device_set_desc(dev, "SIBA BHND bus");
51	return (BUS_PROBE_DEFAULT);
52}
53
54int
55siba_attach(device_t dev)
56{
57	struct siba_devinfo	*dinfo;
58	struct siba_softc	*sc;
59	device_t		*devs;
60	int			 ndevs;
61	int			 error;
62
63	sc = device_get_softc(dev);
64	sc->dev = dev;
65
66	/* Fetch references to the siba SIBA_CFG* blocks for all
67	 * registered devices */
68	if ((error = device_get_children(dev, &devs, &ndevs)))
69		return (error);
70
71	for (int i = 0; i < ndevs; i++) {
72		struct siba_addrspace	*addrspace;
73
74		dinfo = device_get_ivars(devs[i]);
75
76		KASSERT(!device_is_suspended(devs[i]),
77		    ("siba(4) stateful suspend handling requires that devices "
78		        "not be suspended before siba_attach()"));
79
80		/* Fetch the core register address space */
81		addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
82		if (addrspace == NULL) {
83			device_printf(dev,
84			    "missing device registers for core %d\n", i);
85			error = ENXIO;
86			goto cleanup;
87		}
88
89		/*
90		 * Map the per-core configuration blocks
91		 */
92		KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_MAX_CFG,
93		    ("config block count %u out of range",
94		        dinfo->core_id.num_cfg_blocks));
95
96		for (u_int cfgidx = 0; cfgidx < dinfo->core_id.num_cfg_blocks;
97		    cfgidx++)
98		{
99			rman_res_t	r_start, r_count, r_end;
100
101			/* Determine the config block's address range; configuration
102			 * blocks are allocated starting at SIBA_CFG0_OFFSET,
103			 * growing downwards. */
104			r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
105			r_start -= cfgidx * SIBA_CFG_SIZE;
106
107			r_count = SIBA_CFG_SIZE;
108			r_end = r_start + r_count - 1;
109
110			/* Allocate the config resource */
111			dinfo->cfg_rid[cfgidx] = 0;
112			dinfo->cfg[cfgidx] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
113			    SYS_RES_MEMORY, &dinfo->cfg_rid[cfgidx], r_start,
114			    r_end, r_count, RF_ACTIVE);
115
116			if (dinfo->cfg[cfgidx] == NULL) {
117			     device_printf(dev, "failed allocating CFG_%u for "
118			     "core %d\n", cfgidx, i);
119			     error = ENXIO;
120			     goto cleanup;
121			}
122		}
123	}
124
125cleanup:
126	free(devs, M_BHND);
127	if (error)
128		return (error);
129
130	/* Delegate remainder to standard bhnd method implementation */
131	return (bhnd_generic_attach(dev));
132}
133
134int
135siba_detach(device_t dev)
136{
137	return (bhnd_generic_detach(dev));
138}
139
140int
141siba_resume(device_t dev)
142{
143	return (bhnd_generic_resume(dev));
144}
145
146int
147siba_suspend(device_t dev)
148{
149	return (bhnd_generic_suspend(dev));
150}
151
152static int
153siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
154{
155	const struct siba_devinfo *dinfo;
156	const struct bhnd_core_info *cfg;
157
158	dinfo = device_get_ivars(child);
159	cfg = &dinfo->core_id.core_info;
160
161	switch (index) {
162	case BHND_IVAR_VENDOR:
163		*result = cfg->vendor;
164		return (0);
165	case BHND_IVAR_DEVICE:
166		*result = cfg->device;
167		return (0);
168	case BHND_IVAR_HWREV:
169		*result = cfg->hwrev;
170		return (0);
171	case BHND_IVAR_DEVICE_CLASS:
172		*result = bhnd_core_class(cfg);
173		return (0);
174	case BHND_IVAR_VENDOR_NAME:
175		*result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
176		return (0);
177	case BHND_IVAR_DEVICE_NAME:
178		*result = (uintptr_t) bhnd_core_name(cfg);
179		return (0);
180	case BHND_IVAR_CORE_INDEX:
181		*result = cfg->core_idx;
182		return (0);
183	case BHND_IVAR_CORE_UNIT:
184		*result = cfg->unit;
185		return (0);
186	default:
187		return (ENOENT);
188	}
189}
190
191static int
192siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
193{
194	switch (index) {
195	case BHND_IVAR_VENDOR:
196	case BHND_IVAR_DEVICE:
197	case BHND_IVAR_HWREV:
198	case BHND_IVAR_DEVICE_CLASS:
199	case BHND_IVAR_VENDOR_NAME:
200	case BHND_IVAR_DEVICE_NAME:
201	case BHND_IVAR_CORE_INDEX:
202	case BHND_IVAR_CORE_UNIT:
203		return (EINVAL);
204	default:
205		return (ENOENT);
206	}
207}
208
209static struct resource_list *
210siba_get_resource_list(device_t dev, device_t child)
211{
212	struct siba_devinfo *dinfo = device_get_ivars(child);
213	return (&dinfo->resources);
214}
215
216static device_t
217siba_find_hostb_device(device_t dev)
218{
219	struct siba_softc *sc = device_get_softc(dev);
220
221	/* This is set (or not) by the concrete siba driver subclass. */
222	return (sc->hostb_dev);
223}
224
225static int
226siba_reset_core(device_t dev, device_t child, uint16_t flags)
227{
228	struct siba_devinfo *dinfo;
229
230	if (device_get_parent(child) != dev)
231		BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags);
232
233	dinfo = device_get_ivars(child);
234
235	/* Can't reset the core without access to the CFG0 registers */
236	if (dinfo->cfg[0] == NULL)
237		return (ENODEV);
238
239	// TODO - perform reset
240
241	return (ENXIO);
242}
243
244static int
245siba_suspend_core(device_t dev, device_t child)
246{
247	struct siba_devinfo *dinfo;
248
249	if (device_get_parent(child) != dev)
250		BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child);
251
252	dinfo = device_get_ivars(child);
253
254	/* Can't suspend the core without access to the CFG0 registers */
255	if (dinfo->cfg[0] == NULL)
256		return (ENODEV);
257
258	// TODO - perform suspend
259
260	return (ENXIO);
261}
262
263
264static u_int
265siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
266{
267	struct siba_devinfo *dinfo;
268
269	/* delegate non-bus-attached devices to our parent */
270	if (device_get_parent(child) != dev)
271		return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
272		    type));
273
274	dinfo = device_get_ivars(child);
275	return (siba_addrspace_port_count(dinfo));
276}
277
278static u_int
279siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
280    u_int port)
281{
282	struct siba_devinfo	*dinfo;
283
284	/* delegate non-bus-attached devices to our parent */
285	if (device_get_parent(child) != dev)
286		return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
287		    type, port));
288
289	dinfo = device_get_ivars(child);
290	if (!siba_is_port_valid(dinfo, type, port))
291		return (0);
292
293	return (siba_addrspace_region_count(dinfo, port));
294}
295
296static int
297siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
298    u_int port_num, u_int region_num)
299{
300	struct siba_devinfo	*dinfo;
301	struct siba_addrspace	*addrspace;
302
303	/* delegate non-bus-attached devices to our parent */
304	if (device_get_parent(child) != dev)
305		return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
306		    port_type, port_num, region_num));
307
308	dinfo = device_get_ivars(child);
309	addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
310	if (addrspace == NULL)
311		return (-1);
312
313	return (addrspace->sa_rid);
314}
315
316static int
317siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
318    bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
319{
320	struct siba_devinfo	*dinfo;
321
322	/* delegate non-bus-attached devices to our parent */
323	if (device_get_parent(child) != dev)
324		return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
325		    type, rid, port_type, port_num, region_num));
326
327	dinfo = device_get_ivars(child);
328
329	/* Ports are always memory mapped */
330	if (type != SYS_RES_MEMORY)
331		return (EINVAL);
332
333	for (int i = 0; i < dinfo->core_id.num_addrspace; i++) {
334		if (dinfo->addrspace[i].sa_rid != rid)
335			continue;
336
337		*port_type = BHND_PORT_DEVICE;
338		*port_num = siba_addrspace_port(i);
339		*region_num = siba_addrspace_region(i);
340		return (0);
341	}
342
343	/* Not found */
344	return (ENOENT);
345}
346
347static int
348siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
349    u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
350{
351	struct siba_devinfo	*dinfo;
352	struct siba_addrspace	*addrspace;
353
354	/* delegate non-bus-attached devices to our parent */
355	if (device_get_parent(child) != dev) {
356		return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
357		    port_type, port_num, region_num, addr, size));
358	}
359
360	dinfo = device_get_ivars(child);
361	addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
362	if (addrspace == NULL)
363		return (ENOENT);
364
365	*addr = addrspace->sa_base;
366	*size = addrspace->sa_size - addrspace->sa_bus_reserved;
367	return (0);
368}
369
370
371/**
372 * Register all address space mappings for @p di.
373 *
374 * @param dev The siba bus device.
375 * @param di The device info instance on which to register all address
376 * space entries.
377 * @param r A resource mapping the enumeration table block for @p di.
378 */
379static int
380siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
381    struct resource *r)
382{
383	struct siba_core_id	*cid;
384	uint32_t		 addr;
385	uint32_t		 size;
386	int			 error;
387
388	cid = &di->core_id;
389
390
391	/* Register the device address space entries */
392	for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
393		uint32_t	adm;
394		u_int		adm_offset;
395		uint32_t	bus_reserved;
396
397		/* Determine the register offset */
398		adm_offset = siba_admatch_offset(i);
399		if (adm_offset == 0) {
400		    device_printf(dev, "addrspace %hhu is unsupported", i);
401		    return (ENODEV);
402		}
403
404		/* Fetch the address match register value */
405		adm = bus_read_4(r, adm_offset);
406
407		/* Parse the value */
408		if ((error = siba_parse_admatch(adm, &addr, &size))) {
409			device_printf(dev, "failed to decode address "
410			    " match register value 0x%x\n", adm);
411			return (error);
412		}
413
414		/* If this is the device's core/enumeration addrespace,
415		 * reserve the Sonics configuration register blocks for the
416		 * use of our bus. */
417		bus_reserved = 0;
418		if (i == SIBA_CORE_ADDRSPACE)
419			bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
420
421		/* Append the region info */
422		error = siba_append_dinfo_region(di, i, addr, size,
423		    bus_reserved);
424		if (error)
425			return (error);
426	}
427
428	return (0);
429}
430
431static struct bhnd_devinfo *
432siba_alloc_bhnd_dinfo(device_t dev)
433{
434	struct siba_devinfo *dinfo = siba_alloc_dinfo(dev);
435	return ((struct bhnd_devinfo *)dinfo);
436}
437
438static void
439siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
440{
441	siba_free_dinfo(dev, (struct siba_devinfo *)dinfo);
442}
443
444/**
445 * Scan the core table and add all valid discovered cores to
446 * the bus.
447 *
448 * @param dev The siba bus device.
449 * @param chipid The chip identifier, if the device does not provide a
450 * ChipCommon core. Should o NULL otherwise.
451 */
452int
453siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
454{
455	struct bhnd_chipid	 ccid;
456	struct bhnd_core_info	*cores;
457	struct siba_devinfo	*dinfo;
458	struct resource		*r;
459	int			 rid;
460	int			 error;
461
462	dinfo = NULL;
463	cores = NULL;
464	r = NULL;
465
466	/*
467	 * Try to determine the number of device cores via the ChipCommon
468	 * identification registers.
469	 *
470	 * A small number of very early devices do not include a ChipCommon
471	 * core, in which case our caller must supply the chip identification
472	 * information via a non-NULL chipid parameter.
473	 */
474	if (chipid == NULL) {
475		uint32_t	idhigh, ccreg;
476		uint16_t	vendor, device;
477		uint8_t		ccrev;
478
479		/* Map the first core's register block. If the ChipCommon core
480		 * exists, it will always be the first core. */
481		rid = 0;
482		r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
483		    SIBA_CORE_ADDR(0), SIBA_CORE_SIZE,
484		    SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1,
485		    RF_ACTIVE);
486
487		/* Identify the core */
488		idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
489		vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
490		device = SIBA_REG_GET(idhigh, IDH_DEVICE);
491		ccrev = SIBA_IDH_CORE_REV(idhigh);
492
493		if (vendor != OCP_VENDOR_BCM || device != BHND_COREID_CC) {
494			device_printf(dev,
495			    "cannot identify device: no chipcommon core "
496			    "found\n");
497			error = ENXIO;
498			goto cleanup;
499		}
500
501		/* Identify the chipset */
502		ccreg = bus_read_4(r, CHIPC_ID);
503		ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR);
504
505		if (!CHIPC_NCORES_MIN_HWREV(ccrev)) {
506			switch (ccid.chip_id) {
507			case BHND_CHIPID_BCM4306:
508				ccid.ncores = 6;
509				break;
510			case BHND_CHIPID_BCM4704:
511				ccid.ncores = 9;
512				break;
513			case BHND_CHIPID_BCM5365:
514				/*
515				* BCM5365 does support ID_NUMCORE in at least
516				* some of its revisions, but for unknown
517				* reasons, Broadcom's drivers always exclude
518				* the ChipCommon revision (0x5) used by BCM5365
519				* from the set of revisions supporting
520				* ID_NUMCORE, and instead supply a fixed value.
521				*
522				* Presumably, at least some of these devices
523				* shipped with a broken ID_NUMCORE value.
524				*/
525				ccid.ncores = 7;
526				break;
527			default:
528				device_printf(dev, "unable to determine core "
529				    "count for unrecognized chipset 0x%hx\n",
530				    ccid.chip_id);
531				error = ENXIO;
532				goto cleanup;
533			}
534		}
535
536		chipid = &ccid;
537		bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
538	}
539
540	/* Allocate our temporary core table and enumerate all cores */
541	cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
542	if (cores == NULL)
543		return (ENOMEM);
544
545	/* Add all cores. */
546	for (u_int i = 0; i < chipid->ncores; i++) {
547		struct siba_core_id	 cid;
548		device_t		 child;
549		uint32_t		 idhigh, idlow;
550		rman_res_t		 r_count, r_end, r_start;
551
552		/* Map the core's register block */
553		rid = 0;
554		r_start = SIBA_CORE_ADDR(i);
555		r_count = SIBA_CORE_SIZE;
556		r_end = r_start + SIBA_CORE_SIZE - 1;
557		r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
558		    r_end, r_count, RF_ACTIVE);
559		if (r == NULL) {
560			error = ENXIO;
561			goto cleanup;
562		}
563
564		/* Add the child device */
565		child = BUS_ADD_CHILD(dev, 0, NULL, -1);
566		if (child == NULL) {
567			error = ENXIO;
568			goto cleanup;
569		}
570
571		/* Read the core info */
572		idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
573		idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
574
575		cid = siba_parse_core_id(idhigh, idlow, i, 0);
576		cores[i] = cid.core_info;
577
578		/* Determine unit number */
579		for (u_int j = 0; j < i; j++) {
580			if (cores[j].vendor == cores[i].vendor &&
581			    cores[j].device == cores[i].device)
582				cores[i].unit++;
583		}
584
585		/* Initialize per-device bus info */
586		if ((dinfo = device_get_ivars(child)) == NULL) {
587			error = ENXIO;
588			goto cleanup;
589		}
590
591		if ((error = siba_init_dinfo(dev, dinfo, &cid)))
592			goto cleanup;
593
594		/* Register the core's address space(s). */
595		if ((error = siba_register_addrspaces(dev, dinfo, r)))
596			goto cleanup;
597
598		/* If pins are floating or the hardware is otherwise
599		 * unpopulated, the device shouldn't be used. */
600		if (bhnd_is_hw_disabled(child))
601			device_disable(child);
602
603		/* Release our resource */
604		bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
605		r = NULL;
606	}
607
608cleanup:
609	if (cores != NULL)
610		free(cores, M_BHND);
611
612	if (r != NULL)
613		bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
614
615	return (error);
616}
617
618static device_method_t siba_methods[] = {
619	/* Device interface */
620	DEVMETHOD(device_probe,			siba_probe),
621	DEVMETHOD(device_attach,		siba_attach),
622	DEVMETHOD(device_detach,		siba_detach),
623	DEVMETHOD(device_resume,		siba_resume),
624	DEVMETHOD(device_suspend,		siba_suspend),
625
626	/* Bus interface */
627	DEVMETHOD(bus_read_ivar,		siba_read_ivar),
628	DEVMETHOD(bus_write_ivar,		siba_write_ivar),
629	DEVMETHOD(bus_get_resource_list,	siba_get_resource_list),
630
631	/* BHND interface */
632	DEVMETHOD(bhnd_bus_find_hostb_device,	siba_find_hostb_device),
633	DEVMETHOD(bhnd_bus_alloc_devinfo,	siba_alloc_bhnd_dinfo),
634	DEVMETHOD(bhnd_bus_free_devinfo,	siba_free_bhnd_dinfo),
635	DEVMETHOD(bhnd_bus_reset_core,		siba_reset_core),
636	DEVMETHOD(bhnd_bus_suspend_core,	siba_suspend_core),
637	DEVMETHOD(bhnd_bus_get_port_count,	siba_get_port_count),
638	DEVMETHOD(bhnd_bus_get_region_count,	siba_get_region_count),
639	DEVMETHOD(bhnd_bus_get_port_rid,	siba_get_port_rid),
640	DEVMETHOD(bhnd_bus_decode_port_rid,	siba_decode_port_rid),
641	DEVMETHOD(bhnd_bus_get_region_addr,	siba_get_region_addr),
642
643	DEVMETHOD_END
644};
645
646DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
647
648MODULE_VERSION(siba, 1);
649MODULE_DEPEND(siba, bhnd, 1, 1, 1);
650