1237742Simp/*- 2237742Simp * Copyright (c) 2007 Bruce M. Simpson. 3237742Simp * All rights reserved. 4237742Simp * 5237742Simp * Redistribution and use in source and binary forms, with or without 6237742Simp * modification, are permitted provided that the following conditions 7237742Simp * are met: 8237742Simp * 1. Redistributions of source code must retain the above copyright 9237742Simp * notice, this list of conditions and the following disclaimer. 10237742Simp * 2. Redistributions in binary form must reproduce the above copyright 11237742Simp * notice, this list of conditions and the following disclaimer in the 12237742Simp * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/kernel.h> 34#include <sys/module.h> 35#include <sys/rman.h> 36#include <sys/malloc.h> 37 38#include <machine/bus.h> 39 40#include <dev/siba/siba_ids.h> 41#include <dev/siba/sibareg.h> 42#include <dev/siba/sibavar.h> 43 44/* 45 * TODO: De-mipsify this code. 46 * TODO: cpu clock calculation. -> move to siba_cc instance 47 * TODO: Hardwire IRQs for attached cores on siba at probe time. 48 * TODO: Support detach. 49 * TODO: Power management. 50 * TODO: code cleanup. 51 * TODO: Support deployments of siba other than as a system bus. 52 */ 53 54#ifndef MIPS_MEM_RID 55#define MIPS_MEM_RID 0x20 56#endif 57 58extern int rman_debug; 59 60static struct rman mem_rman; /* XXX move to softc */ 61 62static int siba_debug = 1; 63static const char descfmt[] = "Sonics SiliconBackplane rev %s"; 64#define SIBA_DEVDESCLEN sizeof(descfmt) + 8 65 66/* 67 * Device identifiers and descriptions. 68 */ 69static struct siba_devid siba_devids[] = { 70 { SIBA_VID_BROADCOM, SIBA_DEVID_CHIPCOMMON, SIBA_REV_ANY, 71 "ChipCommon" }, 72 { SIBA_VID_BROADCOM, SIBA_DEVID_SDRAM, SIBA_REV_ANY, 73 "SDRAM controller" }, 74 { SIBA_VID_BROADCOM, SIBA_DEVID_PCI, SIBA_REV_ANY, 75 "PCI host interface" }, 76 { SIBA_VID_BROADCOM, SIBA_DEVID_MIPS, SIBA_REV_ANY, 77 "MIPS core" }, 78 { SIBA_VID_BROADCOM, SIBA_DEVID_ETHERNET, SIBA_REV_ANY, 79 "Ethernet core" }, 80 { SIBA_VID_BROADCOM, SIBA_DEVID_USB11_HOSTDEV, SIBA_REV_ANY, 81 "USB host controller" }, 82 { SIBA_VID_BROADCOM, SIBA_DEVID_IPSEC, SIBA_REV_ANY, 83 "IPSEC accelerator" }, 84 { SIBA_VID_BROADCOM, SIBA_DEVID_SDRAMDDR, SIBA_REV_ANY, 85 "SDRAM/DDR controller" }, 86 { SIBA_VID_BROADCOM, SIBA_DEVID_MIPS_3302, SIBA_REV_ANY, 87 "MIPS 3302 core" }, 88 { 0, 0, 0, NULL } 89}; 90 91static int siba_activate_resource(device_t, device_t, int, int, 92 struct resource *); 93static device_t siba_add_child(device_t, u_int, const char *, int); 94static struct resource * 95 siba_alloc_resource(device_t, device_t, int, int *, u_long, 96 u_long, u_long, u_int); 97static int siba_attach(device_t); 98#ifdef notyet 99static void siba_destroy_devinfo(struct siba_devinfo *); 100#endif 101static struct siba_devid * 102 siba_dev_match(uint16_t, uint16_t, uint8_t); 103static struct resource_list * 104 siba_get_reslist(device_t, device_t); 105static uint8_t siba_getirq(uint16_t); 106static int siba_print_all_resources(device_t dev); 107static int siba_print_child(device_t, device_t); 108static int siba_probe(device_t); 109static void siba_probe_nomatch(device_t, device_t); 110int siba_read_ivar(device_t, device_t, int, uintptr_t *); 111static struct siba_devinfo * 112 siba_setup_devinfo(device_t, uint8_t); 113int siba_write_ivar(device_t, device_t, int, uintptr_t); 114uint8_t siba_getncores(device_t, uint16_t); 115 116/* 117 * On the Sentry5, the system bus IRQs are the same as the 118 * MIPS IRQs. Particular cores are hardwired to certain IRQ lines. 119 */ 120static uint8_t 121siba_getirq(uint16_t devid) 122{ 123 uint8_t irq; 124 125 switch (devid) { 126 case SIBA_DEVID_CHIPCOMMON: 127 irq = 0; 128 break; 129 case SIBA_DEVID_ETHERNET: 130 irq = 1; 131 break; 132 case SIBA_DEVID_IPSEC: 133 irq = 2; 134 break; 135 case SIBA_DEVID_USB11_HOSTDEV: 136 irq = 3; 137 break; 138 case SIBA_DEVID_PCI: 139 irq = 4; 140 break; 141#if 0 142 /* 143 * 5 is reserved for the MIPS on-chip timer interrupt; 144 * it is hard-wired by the tick driver. 145 */ 146 case SIBA_DEVID_MIPS: 147 case SIBA_DEVID_MIPS_3302: 148 irq = 5; 149 break; 150#endif 151 default: 152 irq = 0xFF; /* this core does not need an irq */ 153 break; 154 } 155 156 return (irq); 157} 158 159static int 160siba_probe(device_t dev) 161{ 162 struct siba_softc *sc = device_get_softc(dev); 163 uint32_t idlo, idhi; 164 uint16_t ccid; 165 int rid; 166 167 sc->siba_dev = dev; 168 169 //rman_debug = 1; /* XXX */ 170 171 /* 172 * Map the ChipCommon register set using the hints the kernel 173 * was compiled with. 174 */ 175 rid = MIPS_MEM_RID; 176 sc->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 177 RF_ACTIVE); 178 if (sc->siba_mem_res == NULL) { 179 device_printf(dev, "unable to allocate probe aperture\n"); 180 return (ENXIO); 181 } 182 sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res); 183 sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res); 184 sc->siba_maddr = rman_get_start(sc->siba_mem_res); 185 sc->siba_msize = rman_get_size(sc->siba_mem_res); 186 187 if (siba_debug) { 188 device_printf(dev, "start %08x len %08x\n", 189 sc->siba_maddr, sc->siba_msize); 190 } 191 192 idlo = siba_mips_read_4(sc, 0, SIBA_IDLOW); 193 idhi = siba_mips_read_4(sc, 0, SIBA_IDHIGH); 194 ccid = ((idhi & 0x8ff0) >> 4); 195 if (siba_debug) { 196 device_printf(dev, "idlo = %08x\n", idlo); 197 device_printf(dev, "idhi = %08x\n", idhi); 198 device_printf(dev, " chipcore id = %08x\n", ccid); 199 } 200 201 /* 202 * For now, check that the first core is the ChipCommon core. 203 */ 204 if (ccid != SIBA_DEVID_CHIPCOMMON) { 205 if (siba_debug) 206 device_printf(dev, "first core is not ChipCommon\n"); 207 return (ENXIO); 208 } 209 210 /* 211 * Determine backplane revision and set description string. 212 */ 213 uint32_t rev; 214 char *revp; 215 char descbuf[SIBA_DEVDESCLEN]; 216 217 rev = idlo & 0xF0000000; 218 revp = "unknown"; 219 if (rev == 0x00000000) 220 revp = "2.2"; 221 else if (rev == 0x10000000) 222 revp = "2.3"; 223 224 (void)snprintf(descbuf, sizeof(descbuf), descfmt, revp); 225 device_set_desc_copy(dev, descbuf); 226 227 /* 228 * Determine how many cores are present on this siba bus, so 229 * that we may map them all. 230 */ 231 uint32_t ccidreg; 232 uint16_t cc_id; 233 uint16_t cc_rev; 234 235 ccidreg = siba_mips_read_4(sc, 0, SIBA_CC_CHIPID); 236 cc_id = (ccidreg & SIBA_CC_IDMASK); 237 cc_rev = (ccidreg & SIBA_CC_REVMASK) >> SIBA_CC_REVSHIFT; 238 if (siba_debug) { 239 device_printf(dev, "ccid = %08x, cc_id = %04x, cc_rev = %04x\n", 240 ccidreg, cc_id, cc_rev); 241 } 242 243 sc->siba_ncores = siba_getncores(dev, cc_id); 244 if (siba_debug) { 245 device_printf(dev, "%d cores detected.\n", sc->siba_ncores); 246 } 247 248 /* 249 * Now we know how many cores are on this siba, release the 250 * mapping and allocate a new mapping spanning all cores on the bus. 251 */ 252 rid = MIPS_MEM_RID; 253 int result; 254 result = bus_release_resource(dev, SYS_RES_MEMORY, rid, 255 sc->siba_mem_res); 256 if (result != 0) { 257 device_printf(dev, "error %d releasing resource\n", result); 258 return (ENXIO); 259 } 260 261 uint32_t total; 262 total = sc->siba_ncores * SIBA_CORE_LEN; 263 264 /* XXX Don't allocate the entire window until we 265 * enumerate the bus. Once the bus has been enumerated, 266 * and instance variables/children instantiated + populated, 267 * release the resource so children may attach. 268 */ 269 sc->siba_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 270 sc->siba_maddr, sc->siba_maddr + total - 1, total, RF_ACTIVE); 271 if (sc->siba_mem_res == NULL) { 272 device_printf(dev, "unable to allocate entire aperture\n"); 273 return (ENXIO); 274 } 275 sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res); 276 sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res); 277 sc->siba_maddr = rman_get_start(sc->siba_mem_res); 278 sc->siba_msize = rman_get_size(sc->siba_mem_res); 279 280 if (siba_debug) { 281 device_printf(dev, "after remapping: start %08x len %08x\n", 282 sc->siba_maddr, sc->siba_msize); 283 } 284 bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->siba_maddr, 285 sc->siba_msize); 286 287 /* 288 * We need a manager for the space we claim on nexus to 289 * satisfy requests from children. 290 * We need to keep the source reservation we took because 291 * otherwise it may be claimed elsewhere. 292 * XXX move to softc 293 */ 294 mem_rman.rm_start = sc->siba_maddr; 295 mem_rman.rm_end = sc->siba_maddr + sc->siba_msize - 1; 296 mem_rman.rm_type = RMAN_ARRAY; 297 mem_rman.rm_descr = "SiBa I/O memory addresses"; 298 if (rman_init(&mem_rman) != 0 || 299 rman_manage_region(&mem_rman, mem_rman.rm_start, 300 mem_rman.rm_end) != 0) { 301 panic("%s: mem_rman", __func__); 302 } 303 304 return (0); 305} 306 307static int 308siba_attach(device_t dev) 309{ 310 struct siba_softc *sc = device_get_softc(dev); 311 struct siba_devinfo *sdi; 312 device_t child; 313 int idx; 314 315 if (siba_debug) 316 printf("%s: entry\n", __func__); 317 318 bus_generic_probe(dev); 319 320 /* 321 * Now that all bus space is mapped and visible to the CPU, 322 * enumerate its children. 323 * NB: only one core may be mapped at any time if the siba bus 324 * is the child of a PCI or PCMCIA bus. 325 */ 326 for (idx = 0; idx < sc->siba_ncores; idx++) { 327 sdi = siba_setup_devinfo(dev, idx); 328 child = device_add_child(dev, NULL, -1); 329 if (child == NULL) 330 panic("%s: device_add_child() failed\n", __func__); 331 device_set_ivars(child, sdi); 332 } 333 334 return (bus_generic_attach(dev)); 335} 336 337static struct siba_devid * 338siba_dev_match(uint16_t vid, uint16_t devid, uint8_t rev) 339{ 340 size_t i, bound; 341 struct siba_devid *sd; 342 343 bound = sizeof(siba_devids) / sizeof(struct siba_devid); 344 sd = &siba_devids[0]; 345 for (i = 0; i < bound; i++, sd++) { 346 if (((vid == SIBA_VID_ANY) || (vid == sd->sd_vendor)) && 347 ((devid == SIBA_DEVID_ANY) || (devid == sd->sd_device)) && 348 ((rev == SIBA_REV_ANY) || (rev == sd->sd_rev) || 349 (sd->sd_rev == SIBA_REV_ANY))) 350 break; 351 } 352 if (i == bound) 353 sd = NULL; 354 355 return (sd); 356} 357 358static int 359siba_print_child(device_t bus, device_t child) 360{ 361 int retval = 0; 362 363 retval += bus_print_child_header(bus, child); 364 retval += siba_print_all_resources(child); 365 if (device_get_flags(child)) 366 retval += printf(" flags %#x", device_get_flags(child)); 367 retval += printf(" on %s\n", device_get_nameunit(bus)); 368 369 return (retval); 370} 371 372static struct resource * 373siba_alloc_resource(device_t bus, device_t child, int type, int *rid, 374 u_long start, u_long end, u_long count, u_int flags) 375{ 376 struct resource *rv; 377 struct resource_list *rl; 378 struct resource_list_entry *rle; 379 int isdefault, needactivate; 380 381#if 0 382 if (siba_debug) 383 printf("%s: entry\n", __func__); 384#endif 385 386 isdefault = (start == 0UL && end == ~0UL && count == 1); 387 needactivate = flags & RF_ACTIVE; 388 rl = BUS_GET_RESOURCE_LIST(bus, child); 389 rle = NULL; 390 391 if (isdefault) { 392 rle = resource_list_find(rl, type, *rid); 393 if (rle == NULL) 394 return (NULL); 395 if (rle->res != NULL) 396 panic("%s: resource entry is busy", __func__); 397 start = rle->start; 398 end = rle->end; 399 count = rle->count; 400 } 401 402 /* 403 * If the request is for a resource which we manage, 404 * attempt to satisfy the allocation ourselves. 405 */ 406 if (type == SYS_RES_MEMORY && 407 start >= mem_rman.rm_start && end <= mem_rman.rm_end) { 408 409 rv = rman_reserve_resource(&mem_rman, start, end, count, 410 flags, child); 411 if (rv == 0) { 412 printf("%s: could not reserve resource\n", __func__); 413 return (0); 414 } 415 416 rman_set_rid(rv, *rid); 417 418 if (needactivate) { 419 if (bus_activate_resource(child, type, *rid, rv)) { 420 printf("%s: could not activate resource\n", 421 __func__); 422 rman_release_resource(rv); 423 return (0); 424 } 425 } 426 427 return (rv); 428 } 429 430 /* 431 * Pass the request to the parent, usually MIPS nexus. 432 */ 433 if (siba_debug) 434 printf("%s: proxying request to parent\n", __func__); 435 return (resource_list_alloc(rl, bus, child, type, rid, 436 start, end, count, flags)); 437} 438 439/* 440 * The parent bus is responsible for resource activation; in the 441 * case of MIPS, this boils down to setting the virtual address and 442 * bus handle by mapping the physical address into KSEG1. 443 */ 444static int 445siba_activate_resource(device_t bus, device_t child, int type, int rid, 446 struct resource *r) 447{ 448 449 return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, 450 rid, r)); 451} 452 453static struct siba_devinfo * 454siba_setup_devinfo(device_t dev, uint8_t idx) 455{ 456 struct siba_softc *sc = device_get_softc(dev); 457 struct siba_devinfo *sdi; 458 uint32_t idlo, idhi, rev; 459 uint16_t vendorid, devid; 460 bus_addr_t baseaddr; 461 462 sdi = malloc(sizeof(*sdi), M_DEVBUF, M_WAITOK | M_ZERO); 463 resource_list_init(&sdi->sdi_rl); 464 465 idlo = siba_mips_read_4(sc, idx, SIBA_IDLOW); 466 idhi = siba_mips_read_4(sc, idx, SIBA_IDHIGH); 467 468 vendorid = (idhi & SIBA_IDHIGH_VENDORMASK) >> 469 SIBA_IDHIGH_VENDOR_SHIFT; 470 devid = ((idhi & 0x8ff0) >> 4); 471 rev = (idhi & SIBA_IDHIGH_REVLO); 472 rev |= (idhi & SIBA_IDHIGH_REVHI) >> SIBA_IDHIGH_REVHI_SHIFT; 473 474 sdi->sdi_vid = vendorid; 475 sdi->sdi_devid = devid; 476 sdi->sdi_rev = rev; 477 sdi->sdi_idx = idx; 478 sdi->sdi_irq = siba_getirq(devid); 479 480 /* 481 * Determine memory window on bus and irq if one is needed. 482 */ 483 baseaddr = sc->siba_maddr + (idx * SIBA_CORE_LEN); 484 resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, 485 MIPS_MEM_RID, /* XXX */ 486 baseaddr, baseaddr + SIBA_CORE_LEN - 1, SIBA_CORE_LEN); 487 488 if (sdi->sdi_irq != 0xff) { 489 resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, 490 0, sdi->sdi_irq, sdi->sdi_irq, 1); 491 } 492 493 return (sdi); 494} 495 496#ifdef notyet 497static void 498siba_destroy_devinfo(struct siba_devinfo *sdi) 499{ 500 501 resource_list_free(&sdi->sdi_rl); 502 free(sdi, M_DEVBUF); 503} 504#endif 505 506/* XXX is this needed? */ 507static device_t 508siba_add_child(device_t dev, u_int order, const char *name, int unit) 509{ 510#if 1 511 512 device_printf(dev, "%s: entry\n", __func__); 513 return (NULL); 514#else 515 device_t child; 516 struct siba_devinfo *sdi; 517 518 child = device_add_child_ordered(dev, order, name, unit); 519 if (child == NULL) 520 return (NULL); 521 522 sdi = malloc(sizeof(struct siba_devinfo), M_DEVBUF, M_NOWAIT|M_ZERO); 523 if (sdi == NULL) 524 return (NULL); 525 526 device_set_ivars(child, sdi); 527 return (child); 528#endif 529} 530 531int 532siba_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 533{ 534 struct siba_devinfo *sdi; 535 536 sdi = device_get_ivars(child); 537 538 switch (which) { 539 case SIBA_IVAR_VENDOR: 540 *result = sdi->sdi_vid; 541 break; 542 case SIBA_IVAR_DEVICE: 543 *result = sdi->sdi_devid; 544 break; 545 case SIBA_IVAR_REVID: 546 *result = sdi->sdi_rev; 547 break; 548 case SIBA_IVAR_CORE_INDEX: 549 *result = sdi->sdi_idx; 550 break; 551 default: 552 return (ENOENT); 553 } 554 555 return (0); 556} 557 558int 559siba_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 560{ 561 562 return (EINVAL); 563} 564 565static void 566siba_probe_nomatch(device_t dev, device_t child) 567{ 568 569 /* 570 * Announce devices which weren't attached after we probed the bus. 571 */ 572 if (siba_debug) { 573 struct siba_devid *sd; 574 575 sd = siba_dev_match(siba_get_vendor(child), 576 siba_get_device(child), SIBA_REV_ANY); 577 if (sd != NULL && sd->sd_desc != NULL) { 578 device_printf(dev, "<%s> " 579 "at device %d (no driver attached)\n", 580 sd->sd_desc, siba_get_core_index(child)); 581 } else { 582 device_printf(dev, "<0x%04x, 0x%04x> " 583 "at device %d (no driver attached)\n", 584 siba_get_vendor(child), siba_get_device(child), 585 siba_get_core_index(child)); 586 } 587 } 588} 589 590static int 591siba_print_all_resources(device_t dev) 592{ 593 struct siba_devinfo *sdi = device_get_ivars(dev); 594 struct resource_list *rl = &sdi->sdi_rl; 595 int retval = 0; 596 597 if (STAILQ_FIRST(rl)) 598 retval += printf(" at"); 599 600 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 601 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 602 603 return (retval); 604} 605 606static struct resource_list * 607siba_get_reslist(device_t dev, device_t child) 608{ 609 struct siba_devinfo *sdi = device_get_ivars(child); 610 611 return (&sdi->sdi_rl); 612} 613 614static device_method_t siba_methods[] = { 615 /* Device interface */ 616 DEVMETHOD(device_attach, siba_attach), 617 DEVMETHOD(device_detach, bus_generic_detach), 618 DEVMETHOD(device_probe, siba_probe), 619 DEVMETHOD(device_resume, bus_generic_resume), 620 DEVMETHOD(device_shutdown, bus_generic_shutdown), 621 DEVMETHOD(device_suspend, bus_generic_suspend), 622 623 /* Bus interface */ 624 DEVMETHOD(bus_activate_resource,siba_activate_resource), 625 DEVMETHOD(bus_add_child, siba_add_child), 626 DEVMETHOD(bus_alloc_resource, siba_alloc_resource), 627 DEVMETHOD(bus_get_resource_list,siba_get_reslist), 628 DEVMETHOD(bus_print_child, siba_print_child), 629 DEVMETHOD(bus_probe_nomatch, siba_probe_nomatch), 630 DEVMETHOD(bus_read_ivar, siba_read_ivar), 631 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 632 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 633 DEVMETHOD(bus_write_ivar, siba_write_ivar), 634 635 DEVMETHOD_END 636}; 637 638static driver_t siba_driver = { 639 "siba", 640 siba_methods, 641 sizeof(struct siba_softc), 642}; 643static devclass_t siba_devclass; 644 645DRIVER_MODULE(siba, nexus, siba_driver, siba_devclass, 0, 0); 646