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
47 int
siba_probe(device_t dev)48 siba_probe(device_t dev)
49 {
50 device_set_desc(dev, "SIBA BHND bus");
51 return (BUS_PROBE_DEFAULT);
52 }
53
54 int
siba_attach(device_t dev)55 siba_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
125 cleanup:
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
134 int
siba_detach(device_t dev)135 siba_detach(device_t dev)
136 {
137 return (bhnd_generic_detach(dev));
138 }
139
140 int
siba_resume(device_t dev)141 siba_resume(device_t dev)
142 {
143 return (bhnd_generic_resume(dev));
144 }
145
146 int
siba_suspend(device_t dev)147 siba_suspend(device_t dev)
148 {
149 return (bhnd_generic_suspend(dev));
150 }
151
152 static int
siba_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)153 siba_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
191 static int
siba_write_ivar(device_t dev,device_t child,int index,uintptr_t value)192 siba_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
209 static struct resource_list *
siba_get_resource_list(device_t dev,device_t child)210 siba_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
216 static device_t
siba_find_hostb_device(device_t dev)217 siba_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
225 static int
siba_reset_core(device_t dev,device_t child,uint16_t flags)226 siba_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
244 static int
siba_suspend_core(device_t dev,device_t child)245 siba_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
264 static u_int
siba_get_port_count(device_t dev,device_t child,bhnd_port_type type)265 siba_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
278 static u_int
siba_get_region_count(device_t dev,device_t child,bhnd_port_type type,u_int port)279 siba_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
296 static int
siba_get_port_rid(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num)297 siba_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
316 static int
siba_decode_port_rid(device_t dev,device_t child,int type,int rid,bhnd_port_type * port_type,u_int * port_num,u_int * region_num)317 siba_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
347 static int
siba_get_region_addr(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num,bhnd_addr_t * addr,bhnd_size_t * size)348 siba_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 */
379 static int
siba_register_addrspaces(device_t dev,struct siba_devinfo * di,struct resource * r)380 siba_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
431 static struct bhnd_devinfo *
siba_alloc_bhnd_dinfo(device_t dev)432 siba_alloc_bhnd_dinfo(device_t dev)
433 {
434 struct siba_devinfo *dinfo = siba_alloc_dinfo(dev);
435 return ((struct bhnd_devinfo *)dinfo);
436 }
437
438 static void
siba_free_bhnd_dinfo(device_t dev,struct bhnd_devinfo * dinfo)439 siba_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 */
452 int
siba_add_children(device_t dev,const struct bhnd_chipid * chipid)453 siba_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
608 cleanup:
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
618 static 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
646 DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
647
648 MODULE_VERSION(siba, 1);
649 MODULE_DEPEND(siba, bhnd, 1, 1, 1);
650