45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/bus.h> 49#include <sys/clock.h> 50#include <sys/endian.h> 51#include <sys/kernel.h> 52#include <sys/lock.h> 53#include <sys/module.h> 54#include <sys/mutex.h> 55#include <sys/resource.h> 56#include <sys/rman.h> 57 58#include <dev/ofw/ofw_bus.h> 59#include <dev/ofw/openfirm.h> 60 61#include <machine/bus.h> 62#include <machine/cpu.h> 63#include <machine/resource.h> 64 65#include <dev/pci/pcireg.h> 66#include <dev/pci/pcivar.h> 67#include <dev/uart/uart.h> 68#include <dev/uart/uart_cpu.h> 69#include <dev/uart/uart_bus.h> 70 71#include "clock_if.h" 72#include "uart_if.h" 73 74#define SBBC_PCI_BAR PCIR_BAR(0) 75#define SBBC_PCI_VENDOR 0x108e 76#define SBBC_PCI_PRODUCT 0xc416 77 78#define SBBC_REGS_OFFSET 0x800000 79#define SBBC_REGS_SIZE 0x6230 80#define SBBC_EPLD_OFFSET 0x8e0000 81#define SBBC_EPLD_SIZE 0x20 82#define SBBC_SRAM_OFFSET 0x900000 83#define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */ 84 85#define SBBC_PCI_INT_STATUS 0x2320 86#define SBBC_PCI_INT_ENABLE 0x2330 87#define SBBC_PCI_ENABLE_INT_A 0x11 88 89#define SBBC_EPLD_INTERRUPT 0x13 90#define SBBC_EPLD_INTERRUPT_ON 0x01 91 92#define SBBC_SRAM_CONS_IN 0x00000001 93#define SBBC_SRAM_CONS_OUT 0x00000002 94#define SBBC_SRAM_CONS_BRK 0x00000004 95#define SBBC_SRAM_CONS_SPACE_IN 0x00000008 96#define SBBC_SRAM_CONS_SPACE_OUT 0x00000010 97 98#define SBBC_TAG_KEY_SIZE 8 99#define SBBC_TAG_KEY_SCSOLIE "SCSOLIE" /* SC -> OS int. enable */ 100#define SBBC_TAG_KEY_SCSOLIR "SCSOLIR" /* SC -> OS int. reason */ 101#define SBBC_TAG_KEY_SOLCONS "SOLCONS" /* OS console buffer */ 102#define SBBC_TAG_KEY_SOLSCIE "SOLSCIE" /* OS -> SC int. enable */ 103#define SBBC_TAG_KEY_SOLSCIR "SOLSCIR" /* OS -> SC int. reason */ 104#define SBBC_TAG_KEY_TODDATA "TODDATA" /* OS TOD struct */ 105#define SBBC_TAG_OFF(x) offsetof(struct sbbc_sram_tag, x) 106 107struct sbbc_sram_tag { 108 char tag_key[SBBC_TAG_KEY_SIZE]; 109 uint32_t tag_size; 110 uint32_t tag_offset; 111} __packed; 112 113#define SBBC_TOC_MAGIC "TOCSRAM" 114#define SBBC_TOC_MAGIC_SIZE 8 115#define SBBC_TOC_TAGS_MAX 32 116#define SBBC_TOC_OFF(x) offsetof(struct sbbc_sram_toc, x) 117 118struct sbbc_sram_toc { 119 char toc_magic[SBBC_TOC_MAGIC_SIZE]; 120 uint8_t toc_reserved; 121 uint8_t toc_type; 122 uint16_t toc_version; 123 uint32_t toc_ntags; 124 struct sbbc_sram_tag toc_tag[SBBC_TOC_TAGS_MAX]; 125} __packed; 126 127#define SBBC_TOD_MAGIC 0x54443100 /* "TD1" */ 128#define SBBC_TOD_VERSION 1 129#define SBBC_TOD_OFF(x) offsetof(struct sbbc_sram_tod, x) 130 131struct sbbc_sram_tod { 132 uint32_t tod_magic; 133 uint32_t tod_version; 134 uint64_t tod_time; 135 uint64_t tod_skew; 136 uint32_t tod_reserved; 137 uint32_t tod_heartbeat; 138 uint32_t tod_timeout; 139} __packed; 140 141#define SBBC_CONS_MAGIC 0x434f4e00 /* "CON" */ 142#define SBBC_CONS_VERSION 1 143#define SBBC_CONS_OFF(x) offsetof(struct sbbc_sram_cons, x) 144 145struct sbbc_sram_cons { 146 uint32_t cons_magic; 147 uint32_t cons_version; 148 uint32_t cons_size; 149 150 uint32_t cons_in_begin; 151 uint32_t cons_in_end; 152 uint32_t cons_in_rdptr; 153 uint32_t cons_in_wrptr; 154 155 uint32_t cons_out_begin; 156 uint32_t cons_out_end; 157 uint32_t cons_out_rdptr; 158 uint32_t cons_out_wrptr; 159} __packed; 160 161struct sbbc_softc { 162 struct resource *sc_res; 163}; 164 165#define SBBC_READ_N(wdth, offs) \ 166 bus_space_read_ ## wdth((bst), (bsh), (offs)) 167#define SBBC_WRITE_N(wdth, offs, val) \ 168 bus_space_write_ ## wdth((bst), (bsh), (offs), (val)) 169 170#define SBBC_READ_1(offs) \ 171 SBBC_READ_N(1, (offs)) 172#define SBBC_READ_2(offs) \ 173 bswap16(SBBC_READ_N(2, (offs))) 174#define SBBC_READ_4(offs) \ 175 bswap32(SBBC_READ_N(4, (offs))) 176#define SBBC_READ_8(offs) \ 177 bswap64(SBBC_READ_N(8, (offs))) 178#define SBBC_WRITE_1(offs, val) \ 179 SBBC_WRITE_N(1, (offs), (val)) 180#define SBBC_WRITE_2(offs, val) \ 181 SBBC_WRITE_N(2, (offs), bswap16(val)) 182#define SBBC_WRITE_4(offs, val) \ 183 SBBC_WRITE_N(4, (offs), bswap32(val)) 184#define SBBC_WRITE_8(offs, val) \ 185 SBBC_WRITE_N(8, (offs), bswap64(val)) 186 187#define SBBC_REGS_READ_1(offs) \ 188 SBBC_READ_1((offs) + SBBC_REGS_OFFSET) 189#define SBBC_REGS_READ_2(offs) \ 190 SBBC_READ_2((offs) + SBBC_REGS_OFFSET) 191#define SBBC_REGS_READ_4(offs) \ 192 SBBC_READ_4((offs) + SBBC_REGS_OFFSET) 193#define SBBC_REGS_READ_8(offs) \ 194 SBBC_READ_8((offs) + SBBC_REGS_OFFSET) 195#define SBBC_REGS_WRITE_1(offs, val) \ 196 SBBC_WRITE_1((offs) + SBBC_REGS_OFFSET, (val)) 197#define SBBC_REGS_WRITE_2(offs, val) \ 198 SBBC_WRITE_2((offs) + SBBC_REGS_OFFSET, (val)) 199#define SBBC_REGS_WRITE_4(offs, val) \ 200 SBBC_WRITE_4((offs) + SBBC_REGS_OFFSET, (val)) 201#define SBBC_REGS_WRITE_8(offs, val) \ 202 SBBC_WRITE_8((offs) + SBBC_REGS_OFFSET, (val)) 203 204#define SBBC_EPLD_READ_1(offs) \ 205 SBBC_READ_1((offs) + SBBC_EPLD_OFFSET) 206#define SBBC_EPLD_READ_2(offs) \ 207 SBBC_READ_2((offs) + SBBC_EPLD_OFFSET) 208#define SBBC_EPLD_READ_4(offs) \ 209 SBBC_READ_4((offs) + SBBC_EPLD_OFFSET) 210#define SBBC_EPLD_READ_8(offs) \ 211 SBBC_READ_8((offs) + SBBC_EPLD_OFFSET) 212#define SBBC_EPLD_WRITE_1(offs, val) \ 213 SBBC_WRITE_1((offs) + SBBC_EPLD_OFFSET, (val)) 214#define SBBC_EPLD_WRITE_2(offs, val) \ 215 SBBC_WRITE_2((offs) + SBBC_EPLD_OFFSET, (val)) 216#define SBBC_EPLD_WRITE_4(offs, val) \ 217 SBBC_WRITE_4((offs) + SBBC_EPLD_OFFSET, (val)) 218#define SBBC_EPLD_WRITE_8(offs, val) \ 219 SBBC_WRITE_8((offs) + SBBC_EPLD_OFFSET, (val)) 220 221#define SBBC_SRAM_READ_1(offs) \ 222 SBBC_READ_1((offs) + SBBC_SRAM_OFFSET) 223#define SBBC_SRAM_READ_2(offs) \ 224 SBBC_READ_2((offs) + SBBC_SRAM_OFFSET) 225#define SBBC_SRAM_READ_4(offs) \ 226 SBBC_READ_4((offs) + SBBC_SRAM_OFFSET) 227#define SBBC_SRAM_READ_8(offs) \ 228 SBBC_READ_8((offs) + SBBC_SRAM_OFFSET) 229#define SBBC_SRAM_WRITE_1(offs, val) \ 230 SBBC_WRITE_1((offs) + SBBC_SRAM_OFFSET, (val)) 231#define SBBC_SRAM_WRITE_2(offs, val) \ 232 SBBC_WRITE_2((offs) + SBBC_SRAM_OFFSET, (val)) 233#define SBBC_SRAM_WRITE_4(offs, val) \ 234 SBBC_WRITE_4((offs) + SBBC_SRAM_OFFSET, (val)) 235#define SBBC_SRAM_WRITE_8(offs, val) \ 236 SBBC_WRITE_8((offs) + SBBC_SRAM_OFFSET, (val)) 237 238#define SUNW_SETCONSINPUT "SUNW,set-console-input" 239#define SUNW_SETCONSINPUT_CLNT "CON_CLNT" 240#define SUNW_SETCONSINPUT_OBP "CON_OBP" 241 242static u_int sbbc_console; 243 244static uint32_t sbbc_scsolie; 245static uint32_t sbbc_scsolir; 246static uint32_t sbbc_solcons; 247static uint32_t sbbc_solscie; 248static uint32_t sbbc_solscir; 249static uint32_t sbbc_toddata; 250 251/* 252 * internal helpers 253 */ 254static int sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh); 255static inline void sbbc_send_intr(bus_space_tag_t bst, 256 bus_space_handle_t bsh); 257static const char *sbbc_serengeti_set_console_input(char *new); 258 259/* 260 * SBBC PCI interface 261 */ 262static bus_activate_resource_t sbbc_bus_activate_resource; 263static bus_adjust_resource_t sbbc_bus_adjust_resource; 264static bus_deactivate_resource_t sbbc_bus_deactivate_resource; 265static bus_alloc_resource_t sbbc_bus_alloc_resource; 266static bus_release_resource_t sbbc_bus_release_resource; 267static bus_get_resource_list_t sbbc_bus_get_resource_list; 268static bus_setup_intr_t sbbc_bus_setup_intr; 269static bus_teardown_intr_t sbbc_bus_teardown_intr; 270 271static device_attach_t sbbc_pci_attach; 272static device_probe_t sbbc_pci_probe; 273 274static clock_gettime_t sbbc_tod_gettime; 275static clock_settime_t sbbc_tod_settime; 276 277static device_method_t sbbc_pci_methods[] = { 278 /* Device interface */ 279 DEVMETHOD(device_probe, sbbc_pci_probe), 280 DEVMETHOD(device_attach, sbbc_pci_attach), 281 282 DEVMETHOD(bus_alloc_resource, sbbc_bus_alloc_resource), 283 DEVMETHOD(bus_activate_resource,sbbc_bus_activate_resource), 284 DEVMETHOD(bus_deactivate_resource,sbbc_bus_deactivate_resource), 285 DEVMETHOD(bus_adjust_resource, sbbc_bus_adjust_resource), 286 DEVMETHOD(bus_release_resource, sbbc_bus_release_resource), 287 DEVMETHOD(bus_setup_intr, sbbc_bus_setup_intr), 288 DEVMETHOD(bus_teardown_intr, sbbc_bus_teardown_intr), 289 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 290 DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list), 291 292 /* clock interface */ 293 DEVMETHOD(clock_gettime, sbbc_tod_gettime), 294 DEVMETHOD(clock_settime, sbbc_tod_settime), 295 296 DEVMETHOD_END 297}; 298 299static devclass_t sbbc_devclass; 300 301DEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc)); 302DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL); 303 304static int 305sbbc_pci_probe(device_t dev) 306{ 307 308 if (pci_get_vendor(dev) == SBBC_PCI_VENDOR && 309 pci_get_device(dev) == SBBC_PCI_PRODUCT) { 310 device_set_desc(dev, "Sun BootBus controller"); 311 return (BUS_PROBE_DEFAULT); 312 } 313 return (ENXIO); 314} 315 316static int 317sbbc_pci_attach(device_t dev) 318{ 319 struct sbbc_softc *sc; 320 struct timespec ts; 321 device_t child; 322 bus_space_tag_t bst; 323 bus_space_handle_t bsh; 324 phandle_t node; 325 int error, rid; 326 uint32_t val; 327 328 /* Nothing to to if we're not the chosen one. */ 329 if ((node = OF_finddevice("/chosen")) == -1) { 330 device_printf(dev, "failed to find /chosen\n"); 331 return (ENXIO); 332 } 333 if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) { 334 device_printf(dev, "failed to get iosram\n"); 335 return (ENXIO); 336 } 337 if (node != ofw_bus_get_node(dev)) 338 return (0); 339 340 sc = device_get_softc(dev); 341 rid = SBBC_PCI_BAR; 342 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 343 RF_ACTIVE); 344 if (sc->sc_res == NULL) { 345 device_printf(dev, "failed to allocate resources\n"); 346 return (ENXIO); 347 } 348 bst = rman_get_bustag(sc->sc_res); 349 bsh = rman_get_bushandle(sc->sc_res); 350 if (sbbc_console != 0) { 351 /* Once again the interrupt pin isn't set. */ 352 if (pci_get_intpin(dev) == 0) 353 pci_set_intpin(dev, 1); 354 child = device_add_child(dev, NULL, -1); 355 if (child == NULL) 356 device_printf(dev, "failed to add UART device\n"); 357 error = bus_generic_attach(dev); 358 if (error != 0) 359 device_printf(dev, "failed to attach UART device\n"); 360 } else { 361 error = sbbc_parse_toc(bst, bsh); 362 if (error != 0) { 363 device_printf(dev, "failed to parse TOC\n"); 364 if (sbbc_console != 0) { 365 bus_release_resource(dev, SYS_RES_MEMORY, rid, 366 sc->sc_res); 367 return (error); 368 } 369 } 370 } 371 if (sbbc_toddata != 0) { 372 if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 373 SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC) 374 device_printf(dev, "invalid TOD magic %#x\n", val); 375 else if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 376 SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION) 377 device_printf(dev, "invalid TOD version %#x\n", val); 378 else { 379 clock_register(dev, 1000000); /* 1 sec. resolution */ 380 if (bootverbose) { 381 sbbc_tod_gettime(dev, &ts); 382 device_printf(dev, 383 "current time: %ld.%09ld\n", 384 (long)ts.tv_sec, ts.tv_nsec); 385 } 386 } 387 } 388 return (0); 389} 390 391/* 392 * Note that the bus methods don't pass-through the uart(4) requests but act 393 * as if they would come from sbbc(4) in order to avoid complications with 394 * pci(4) (actually, uart(4) isn't a real child but rather a function of 395 * sbbc(4) anyway). 396 */ 397 398static struct resource * 399sbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type, 400 int *rid, u_long start, u_long end, u_long count, u_int flags) 401{ 402 struct sbbc_softc *sc; 403 404 sc = device_get_softc(dev); 405 switch (type) { 406 case SYS_RES_IRQ: 407 return (bus_generic_alloc_resource(dev, dev, type, rid, start, 408 end, count, flags)); 409 case SYS_RES_MEMORY: 410 return (sc->sc_res); 411 default: 412 return (NULL); 413 } 414} 415 416static int 417sbbc_bus_activate_resource(device_t bus, device_t child, int type, int rid, 418 struct resource *res) 419{ 420 421 if (type == SYS_RES_MEMORY) 422 return (0); 423 return (bus_generic_activate_resource(bus, child, type, rid, res)); 424} 425 426static int 427sbbc_bus_deactivate_resource(device_t bus, device_t child, int type, int rid, 428 struct resource *res) 429{ 430 431 if (type == SYS_RES_MEMORY) 432 return (0); 433 return (bus_generic_deactivate_resource(bus, child, type, rid, res)); 434} 435 436static int 437sbbc_bus_adjust_resource(device_t bus __unused, device_t child __unused, 438 int type __unused, struct resource *res __unused, u_long start __unused, 439 u_long end __unused) 440{ 441 442 return (ENXIO); 443} 444 445static int 446sbbc_bus_release_resource(device_t dev, device_t child __unused, int type, 447 int rid, struct resource *res) 448{ 449 450 if (type == SYS_RES_IRQ) 451 return (bus_generic_release_resource(dev, dev, type, rid, 452 res)); 453 return (0); 454} 455 456static struct resource_list * 457sbbc_bus_get_resource_list(device_t dev, device_t child __unused) 458{ 459 460 return (bus_generic_get_resource_list(dev, dev)); 461} 462 463static int 464sbbc_bus_setup_intr(device_t dev, device_t child __unused, 465 struct resource *res, int flags, driver_filter_t *filt, 466 driver_intr_t *intr, void *arg, void **cookiep) 467{ 468 469 return (bus_generic_setup_intr(dev, dev, res, flags, filt, intr, arg, 470 cookiep)); 471} 472 473static int 474sbbc_bus_teardown_intr(device_t dev, device_t child __unused, 475 struct resource *res, void *cookie) 476{ 477 478 return (bus_generic_teardown_intr(dev, dev, res, cookie)); 479} 480 481/* 482 * internal helpers 483 */ 484static int 485sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh) 486{ 487 char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)]; 488 bus_size_t tag; 489 phandle_t node; 490 uint32_t off, sram_toc; 491 u_int i, tags; 492 493 if ((node = OF_finddevice("/chosen")) == -1) 494 return (ENXIO); 495 /* SRAM TOC offset defaults to 0. */ 496 if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0) 497 sram_toc = 0; 498 499 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc + 500 SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE); 501 buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0'; 502 if (strcmp(buf, SBBC_TOC_MAGIC) != 0) 503 return (ENXIO); 504 505 tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags)); 506 for (i = 0; i < tags; i++) { 507 tag = sram_toc + SBBC_TOC_OFF(toc_tag) + 508 i * sizeof(struct sbbc_sram_tag); 509 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag + 510 SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE); 511 buf[SBBC_TAG_KEY_SIZE - 1] = '\0'; 512 off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset)); 513 if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0) 514 sbbc_scsolie = off; 515 else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0) 516 sbbc_scsolir = off; 517 else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0) 518 sbbc_solcons = off; 519 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0) 520 sbbc_solscie = off; 521 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0) 522 sbbc_solscir = off; 523 else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0) 524 sbbc_toddata = off; 525 } 526 return (0); 527} 528 529static const char * 530sbbc_serengeti_set_console_input(char *new) 531{ 532 struct { 533 cell_t name; 534 cell_t nargs; 535 cell_t nreturns; 536 cell_t new; 537 cell_t old; 538 } args = { 539 (cell_t)SUNW_SETCONSINPUT, 540 1, 541 1, 542 }; 543 544 args.new = (cell_t)new; 545 if (ofw_entry(&args) == -1) 546 return (NULL); 547 return ((const char *)args.old); 548} 549 550static inline void 551sbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh) 552{ 553 554 SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON); 555 bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1, 556 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 557} 558 559/* 560 * TOD interface 561 */ 562static int 563sbbc_tod_gettime(device_t dev, struct timespec *ts) 564{ 565 struct sbbc_softc *sc; 566 bus_space_tag_t bst; 567 bus_space_handle_t bsh; 568 569 sc = device_get_softc(dev); 570 bst = rman_get_bustag(sc->sc_res); 571 bsh = rman_get_bushandle(sc->sc_res); 572 573 ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) + 574 SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew)); 575 ts->tv_nsec = 0; 576 return (0); 577} 578 579static int 580sbbc_tod_settime(device_t dev, struct timespec *ts) 581{ 582 struct sbbc_softc *sc; 583 bus_space_tag_t bst; 584 bus_space_handle_t bsh; 585 586 sc = device_get_softc(dev); 587 bst = rman_get_bustag(sc->sc_res); 588 bsh = rman_get_bushandle(sc->sc_res); 589 590 SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec - 591 SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time))); 592 return (0); 593} 594 595/* 596 * UART bus front-end 597 */ 598static device_probe_t sbbc_uart_sbbc_probe; 599 600static device_method_t sbbc_uart_sbbc_methods[] = { 601 /* Device interface */ 602 DEVMETHOD(device_probe, sbbc_uart_sbbc_probe), 603 DEVMETHOD(device_attach, uart_bus_attach), 604 DEVMETHOD(device_detach, uart_bus_detach), 605 606 DEVMETHOD_END 607}; 608 609DEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods, 610 sizeof(struct uart_softc)); 611DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL); 612 613static int 614sbbc_uart_sbbc_probe(device_t dev) 615{ 616 struct uart_softc *sc; 617 618 sc = device_get_softc(dev); 619 sc->sc_class = &uart_sbbc_class; 620 device_set_desc(dev, "Serengeti console"); 621 return (uart_bus_probe(dev, 0, 0, SBBC_PCI_BAR, 0)); 622} 623 624/* 625 * Low-level UART interface 626 */ 627static int sbbc_uart_probe(struct uart_bas *bas); 628static void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits, 629 int stopbits, int parity); 630static void sbbc_uart_term(struct uart_bas *bas); 631static void sbbc_uart_putc(struct uart_bas *bas, int c); 632static int sbbc_uart_rxready(struct uart_bas *bas); 633static int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx); 634 635static struct uart_ops sbbc_uart_ops = { 636 .probe = sbbc_uart_probe, 637 .init = sbbc_uart_init, 638 .term = sbbc_uart_term, 639 .putc = sbbc_uart_putc, 640 .rxready = sbbc_uart_rxready, 641 .getc = sbbc_uart_getc, 642}; 643 644static int 645sbbc_uart_probe(struct uart_bas *bas) 646{ 647 bus_space_tag_t bst; 648 bus_space_handle_t bsh; 649 int error; 650 651 sbbc_console = 1; 652 bst = bas->bst; 653 bsh = bas->bsh; 654 error = sbbc_parse_toc(bst, bsh); 655 if (error != 0) 656 return (error); 657 658 if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 || 659 sbbc_solscie == 0 || sbbc_solscir == 0) 660 return (ENXIO); 661 662 if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) != 663 SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons + 664 SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION) 665 return (ENXIO); 666 return (0); 667} 668 669static void 670sbbc_uart_init(struct uart_bas *bas, int baudrate __unused, 671 int databits __unused, int stopbits __unused, int parity __unused) 672{ 673 bus_space_tag_t bst; 674 bus_space_handle_t bsh; 675 676 bst = bas->bst; 677 bsh = bas->bsh; 678 679 /* Enable output to and space in from the SC interrupts. */ 680 SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) | 681 SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN); 682 uart_barrier(bas); 683 684 /* Take over the console input. */ 685 sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT); 686} 687 688static void 689sbbc_uart_term(struct uart_bas *bas __unused) 690{ 691 692 /* Give back the console input. */ 693 sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP); 694} 695 696static void 697sbbc_uart_putc(struct uart_bas *bas, int c) 698{ 699 bus_space_tag_t bst; 700 bus_space_handle_t bsh; 701 uint32_t wrptr; 702 703 bst = bas->bst; 704 bsh = bas->bsh; 705 706 wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 707 SBBC_CONS_OFF(cons_out_wrptr)); 708 SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c); 709 uart_barrier(bas); 710 if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons + 711 SBBC_CONS_OFF(cons_out_end))) 712 wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 713 SBBC_CONS_OFF(cons_out_begin)); 714 SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr), 715 wrptr); 716 uart_barrier(bas); 717 718 SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 719 SBBC_SRAM_CONS_OUT); 720 uart_barrier(bas); 721 sbbc_send_intr(bst, bsh); 722} 723 724static int 725sbbc_uart_rxready(struct uart_bas *bas) 726{ 727 bus_space_tag_t bst; 728 bus_space_handle_t bsh; 729 730 bst = bas->bst; 731 bsh = bas->bsh; 732 733 if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) == 734 SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr))) 735 return (0); 736 return (1); 737} 738 739static int 740sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 741{ 742 bus_space_tag_t bst; 743 bus_space_handle_t bsh; 744 int c; 745 uint32_t rdptr; 746 747 bst = bas->bst; 748 bsh = bas->bsh; 749 750 uart_lock(hwmtx); 751 752 while (sbbc_uart_rxready(bas) == 0) { 753 uart_unlock(hwmtx); 754 DELAY(4); 755 uart_lock(hwmtx); 756 } 757 758 rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)); 759 c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr); 760 uart_barrier(bas); 761 if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons + 762 SBBC_CONS_OFF(cons_in_end))) 763 rdptr = SBBC_SRAM_READ_4(sbbc_solcons + 764 SBBC_CONS_OFF(cons_in_begin)); 765 SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr), 766 rdptr); 767 uart_barrier(bas); 768 SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 769 SBBC_SRAM_CONS_SPACE_IN); 770 uart_barrier(bas); 771 sbbc_send_intr(bst, bsh); 772 773 uart_unlock(hwmtx); 774 return (c); 775} 776 777/* 778 * High-level UART interface 779 */ 780static int sbbc_uart_bus_attach(struct uart_softc *sc); 781static int sbbc_uart_bus_detach(struct uart_softc *sc); 782static int sbbc_uart_bus_flush(struct uart_softc *sc, int what); 783static int sbbc_uart_bus_getsig(struct uart_softc *sc); 784static int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, 785 intptr_t data); 786static int sbbc_uart_bus_ipend(struct uart_softc *sc); 787static int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate, 788 int databits, int stopbits, int parity); 789static int sbbc_uart_bus_probe(struct uart_softc *sc); 790static int sbbc_uart_bus_receive(struct uart_softc *sc); 791static int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig); 792static int sbbc_uart_bus_transmit(struct uart_softc *sc); 793 794static kobj_method_t sbbc_uart_methods[] = { 795 KOBJMETHOD(uart_attach, sbbc_uart_bus_attach), 796 KOBJMETHOD(uart_detach, sbbc_uart_bus_detach), 797 KOBJMETHOD(uart_flush, sbbc_uart_bus_flush), 798 KOBJMETHOD(uart_getsig, sbbc_uart_bus_getsig), 799 KOBJMETHOD(uart_ioctl, sbbc_uart_bus_ioctl), 800 KOBJMETHOD(uart_ipend, sbbc_uart_bus_ipend), 801 KOBJMETHOD(uart_param, sbbc_uart_bus_param), 802 KOBJMETHOD(uart_probe, sbbc_uart_bus_probe), 803 KOBJMETHOD(uart_receive, sbbc_uart_bus_receive), 804 KOBJMETHOD(uart_setsig, sbbc_uart_bus_setsig), 805 KOBJMETHOD(uart_transmit, sbbc_uart_bus_transmit), 806 807 DEVMETHOD_END 808}; 809 810struct uart_class uart_sbbc_class = { 811 "sbbc", 812 sbbc_uart_methods, 813 sizeof(struct uart_softc), 814 .uc_ops = &sbbc_uart_ops, 815 .uc_range = 1,
| 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/bus.h> 49#include <sys/clock.h> 50#include <sys/endian.h> 51#include <sys/kernel.h> 52#include <sys/lock.h> 53#include <sys/module.h> 54#include <sys/mutex.h> 55#include <sys/resource.h> 56#include <sys/rman.h> 57 58#include <dev/ofw/ofw_bus.h> 59#include <dev/ofw/openfirm.h> 60 61#include <machine/bus.h> 62#include <machine/cpu.h> 63#include <machine/resource.h> 64 65#include <dev/pci/pcireg.h> 66#include <dev/pci/pcivar.h> 67#include <dev/uart/uart.h> 68#include <dev/uart/uart_cpu.h> 69#include <dev/uart/uart_bus.h> 70 71#include "clock_if.h" 72#include "uart_if.h" 73 74#define SBBC_PCI_BAR PCIR_BAR(0) 75#define SBBC_PCI_VENDOR 0x108e 76#define SBBC_PCI_PRODUCT 0xc416 77 78#define SBBC_REGS_OFFSET 0x800000 79#define SBBC_REGS_SIZE 0x6230 80#define SBBC_EPLD_OFFSET 0x8e0000 81#define SBBC_EPLD_SIZE 0x20 82#define SBBC_SRAM_OFFSET 0x900000 83#define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */ 84 85#define SBBC_PCI_INT_STATUS 0x2320 86#define SBBC_PCI_INT_ENABLE 0x2330 87#define SBBC_PCI_ENABLE_INT_A 0x11 88 89#define SBBC_EPLD_INTERRUPT 0x13 90#define SBBC_EPLD_INTERRUPT_ON 0x01 91 92#define SBBC_SRAM_CONS_IN 0x00000001 93#define SBBC_SRAM_CONS_OUT 0x00000002 94#define SBBC_SRAM_CONS_BRK 0x00000004 95#define SBBC_SRAM_CONS_SPACE_IN 0x00000008 96#define SBBC_SRAM_CONS_SPACE_OUT 0x00000010 97 98#define SBBC_TAG_KEY_SIZE 8 99#define SBBC_TAG_KEY_SCSOLIE "SCSOLIE" /* SC -> OS int. enable */ 100#define SBBC_TAG_KEY_SCSOLIR "SCSOLIR" /* SC -> OS int. reason */ 101#define SBBC_TAG_KEY_SOLCONS "SOLCONS" /* OS console buffer */ 102#define SBBC_TAG_KEY_SOLSCIE "SOLSCIE" /* OS -> SC int. enable */ 103#define SBBC_TAG_KEY_SOLSCIR "SOLSCIR" /* OS -> SC int. reason */ 104#define SBBC_TAG_KEY_TODDATA "TODDATA" /* OS TOD struct */ 105#define SBBC_TAG_OFF(x) offsetof(struct sbbc_sram_tag, x) 106 107struct sbbc_sram_tag { 108 char tag_key[SBBC_TAG_KEY_SIZE]; 109 uint32_t tag_size; 110 uint32_t tag_offset; 111} __packed; 112 113#define SBBC_TOC_MAGIC "TOCSRAM" 114#define SBBC_TOC_MAGIC_SIZE 8 115#define SBBC_TOC_TAGS_MAX 32 116#define SBBC_TOC_OFF(x) offsetof(struct sbbc_sram_toc, x) 117 118struct sbbc_sram_toc { 119 char toc_magic[SBBC_TOC_MAGIC_SIZE]; 120 uint8_t toc_reserved; 121 uint8_t toc_type; 122 uint16_t toc_version; 123 uint32_t toc_ntags; 124 struct sbbc_sram_tag toc_tag[SBBC_TOC_TAGS_MAX]; 125} __packed; 126 127#define SBBC_TOD_MAGIC 0x54443100 /* "TD1" */ 128#define SBBC_TOD_VERSION 1 129#define SBBC_TOD_OFF(x) offsetof(struct sbbc_sram_tod, x) 130 131struct sbbc_sram_tod { 132 uint32_t tod_magic; 133 uint32_t tod_version; 134 uint64_t tod_time; 135 uint64_t tod_skew; 136 uint32_t tod_reserved; 137 uint32_t tod_heartbeat; 138 uint32_t tod_timeout; 139} __packed; 140 141#define SBBC_CONS_MAGIC 0x434f4e00 /* "CON" */ 142#define SBBC_CONS_VERSION 1 143#define SBBC_CONS_OFF(x) offsetof(struct sbbc_sram_cons, x) 144 145struct sbbc_sram_cons { 146 uint32_t cons_magic; 147 uint32_t cons_version; 148 uint32_t cons_size; 149 150 uint32_t cons_in_begin; 151 uint32_t cons_in_end; 152 uint32_t cons_in_rdptr; 153 uint32_t cons_in_wrptr; 154 155 uint32_t cons_out_begin; 156 uint32_t cons_out_end; 157 uint32_t cons_out_rdptr; 158 uint32_t cons_out_wrptr; 159} __packed; 160 161struct sbbc_softc { 162 struct resource *sc_res; 163}; 164 165#define SBBC_READ_N(wdth, offs) \ 166 bus_space_read_ ## wdth((bst), (bsh), (offs)) 167#define SBBC_WRITE_N(wdth, offs, val) \ 168 bus_space_write_ ## wdth((bst), (bsh), (offs), (val)) 169 170#define SBBC_READ_1(offs) \ 171 SBBC_READ_N(1, (offs)) 172#define SBBC_READ_2(offs) \ 173 bswap16(SBBC_READ_N(2, (offs))) 174#define SBBC_READ_4(offs) \ 175 bswap32(SBBC_READ_N(4, (offs))) 176#define SBBC_READ_8(offs) \ 177 bswap64(SBBC_READ_N(8, (offs))) 178#define SBBC_WRITE_1(offs, val) \ 179 SBBC_WRITE_N(1, (offs), (val)) 180#define SBBC_WRITE_2(offs, val) \ 181 SBBC_WRITE_N(2, (offs), bswap16(val)) 182#define SBBC_WRITE_4(offs, val) \ 183 SBBC_WRITE_N(4, (offs), bswap32(val)) 184#define SBBC_WRITE_8(offs, val) \ 185 SBBC_WRITE_N(8, (offs), bswap64(val)) 186 187#define SBBC_REGS_READ_1(offs) \ 188 SBBC_READ_1((offs) + SBBC_REGS_OFFSET) 189#define SBBC_REGS_READ_2(offs) \ 190 SBBC_READ_2((offs) + SBBC_REGS_OFFSET) 191#define SBBC_REGS_READ_4(offs) \ 192 SBBC_READ_4((offs) + SBBC_REGS_OFFSET) 193#define SBBC_REGS_READ_8(offs) \ 194 SBBC_READ_8((offs) + SBBC_REGS_OFFSET) 195#define SBBC_REGS_WRITE_1(offs, val) \ 196 SBBC_WRITE_1((offs) + SBBC_REGS_OFFSET, (val)) 197#define SBBC_REGS_WRITE_2(offs, val) \ 198 SBBC_WRITE_2((offs) + SBBC_REGS_OFFSET, (val)) 199#define SBBC_REGS_WRITE_4(offs, val) \ 200 SBBC_WRITE_4((offs) + SBBC_REGS_OFFSET, (val)) 201#define SBBC_REGS_WRITE_8(offs, val) \ 202 SBBC_WRITE_8((offs) + SBBC_REGS_OFFSET, (val)) 203 204#define SBBC_EPLD_READ_1(offs) \ 205 SBBC_READ_1((offs) + SBBC_EPLD_OFFSET) 206#define SBBC_EPLD_READ_2(offs) \ 207 SBBC_READ_2((offs) + SBBC_EPLD_OFFSET) 208#define SBBC_EPLD_READ_4(offs) \ 209 SBBC_READ_4((offs) + SBBC_EPLD_OFFSET) 210#define SBBC_EPLD_READ_8(offs) \ 211 SBBC_READ_8((offs) + SBBC_EPLD_OFFSET) 212#define SBBC_EPLD_WRITE_1(offs, val) \ 213 SBBC_WRITE_1((offs) + SBBC_EPLD_OFFSET, (val)) 214#define SBBC_EPLD_WRITE_2(offs, val) \ 215 SBBC_WRITE_2((offs) + SBBC_EPLD_OFFSET, (val)) 216#define SBBC_EPLD_WRITE_4(offs, val) \ 217 SBBC_WRITE_4((offs) + SBBC_EPLD_OFFSET, (val)) 218#define SBBC_EPLD_WRITE_8(offs, val) \ 219 SBBC_WRITE_8((offs) + SBBC_EPLD_OFFSET, (val)) 220 221#define SBBC_SRAM_READ_1(offs) \ 222 SBBC_READ_1((offs) + SBBC_SRAM_OFFSET) 223#define SBBC_SRAM_READ_2(offs) \ 224 SBBC_READ_2((offs) + SBBC_SRAM_OFFSET) 225#define SBBC_SRAM_READ_4(offs) \ 226 SBBC_READ_4((offs) + SBBC_SRAM_OFFSET) 227#define SBBC_SRAM_READ_8(offs) \ 228 SBBC_READ_8((offs) + SBBC_SRAM_OFFSET) 229#define SBBC_SRAM_WRITE_1(offs, val) \ 230 SBBC_WRITE_1((offs) + SBBC_SRAM_OFFSET, (val)) 231#define SBBC_SRAM_WRITE_2(offs, val) \ 232 SBBC_WRITE_2((offs) + SBBC_SRAM_OFFSET, (val)) 233#define SBBC_SRAM_WRITE_4(offs, val) \ 234 SBBC_WRITE_4((offs) + SBBC_SRAM_OFFSET, (val)) 235#define SBBC_SRAM_WRITE_8(offs, val) \ 236 SBBC_WRITE_8((offs) + SBBC_SRAM_OFFSET, (val)) 237 238#define SUNW_SETCONSINPUT "SUNW,set-console-input" 239#define SUNW_SETCONSINPUT_CLNT "CON_CLNT" 240#define SUNW_SETCONSINPUT_OBP "CON_OBP" 241 242static u_int sbbc_console; 243 244static uint32_t sbbc_scsolie; 245static uint32_t sbbc_scsolir; 246static uint32_t sbbc_solcons; 247static uint32_t sbbc_solscie; 248static uint32_t sbbc_solscir; 249static uint32_t sbbc_toddata; 250 251/* 252 * internal helpers 253 */ 254static int sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh); 255static inline void sbbc_send_intr(bus_space_tag_t bst, 256 bus_space_handle_t bsh); 257static const char *sbbc_serengeti_set_console_input(char *new); 258 259/* 260 * SBBC PCI interface 261 */ 262static bus_activate_resource_t sbbc_bus_activate_resource; 263static bus_adjust_resource_t sbbc_bus_adjust_resource; 264static bus_deactivate_resource_t sbbc_bus_deactivate_resource; 265static bus_alloc_resource_t sbbc_bus_alloc_resource; 266static bus_release_resource_t sbbc_bus_release_resource; 267static bus_get_resource_list_t sbbc_bus_get_resource_list; 268static bus_setup_intr_t sbbc_bus_setup_intr; 269static bus_teardown_intr_t sbbc_bus_teardown_intr; 270 271static device_attach_t sbbc_pci_attach; 272static device_probe_t sbbc_pci_probe; 273 274static clock_gettime_t sbbc_tod_gettime; 275static clock_settime_t sbbc_tod_settime; 276 277static device_method_t sbbc_pci_methods[] = { 278 /* Device interface */ 279 DEVMETHOD(device_probe, sbbc_pci_probe), 280 DEVMETHOD(device_attach, sbbc_pci_attach), 281 282 DEVMETHOD(bus_alloc_resource, sbbc_bus_alloc_resource), 283 DEVMETHOD(bus_activate_resource,sbbc_bus_activate_resource), 284 DEVMETHOD(bus_deactivate_resource,sbbc_bus_deactivate_resource), 285 DEVMETHOD(bus_adjust_resource, sbbc_bus_adjust_resource), 286 DEVMETHOD(bus_release_resource, sbbc_bus_release_resource), 287 DEVMETHOD(bus_setup_intr, sbbc_bus_setup_intr), 288 DEVMETHOD(bus_teardown_intr, sbbc_bus_teardown_intr), 289 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 290 DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list), 291 292 /* clock interface */ 293 DEVMETHOD(clock_gettime, sbbc_tod_gettime), 294 DEVMETHOD(clock_settime, sbbc_tod_settime), 295 296 DEVMETHOD_END 297}; 298 299static devclass_t sbbc_devclass; 300 301DEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc)); 302DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL); 303 304static int 305sbbc_pci_probe(device_t dev) 306{ 307 308 if (pci_get_vendor(dev) == SBBC_PCI_VENDOR && 309 pci_get_device(dev) == SBBC_PCI_PRODUCT) { 310 device_set_desc(dev, "Sun BootBus controller"); 311 return (BUS_PROBE_DEFAULT); 312 } 313 return (ENXIO); 314} 315 316static int 317sbbc_pci_attach(device_t dev) 318{ 319 struct sbbc_softc *sc; 320 struct timespec ts; 321 device_t child; 322 bus_space_tag_t bst; 323 bus_space_handle_t bsh; 324 phandle_t node; 325 int error, rid; 326 uint32_t val; 327 328 /* Nothing to to if we're not the chosen one. */ 329 if ((node = OF_finddevice("/chosen")) == -1) { 330 device_printf(dev, "failed to find /chosen\n"); 331 return (ENXIO); 332 } 333 if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) { 334 device_printf(dev, "failed to get iosram\n"); 335 return (ENXIO); 336 } 337 if (node != ofw_bus_get_node(dev)) 338 return (0); 339 340 sc = device_get_softc(dev); 341 rid = SBBC_PCI_BAR; 342 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 343 RF_ACTIVE); 344 if (sc->sc_res == NULL) { 345 device_printf(dev, "failed to allocate resources\n"); 346 return (ENXIO); 347 } 348 bst = rman_get_bustag(sc->sc_res); 349 bsh = rman_get_bushandle(sc->sc_res); 350 if (sbbc_console != 0) { 351 /* Once again the interrupt pin isn't set. */ 352 if (pci_get_intpin(dev) == 0) 353 pci_set_intpin(dev, 1); 354 child = device_add_child(dev, NULL, -1); 355 if (child == NULL) 356 device_printf(dev, "failed to add UART device\n"); 357 error = bus_generic_attach(dev); 358 if (error != 0) 359 device_printf(dev, "failed to attach UART device\n"); 360 } else { 361 error = sbbc_parse_toc(bst, bsh); 362 if (error != 0) { 363 device_printf(dev, "failed to parse TOC\n"); 364 if (sbbc_console != 0) { 365 bus_release_resource(dev, SYS_RES_MEMORY, rid, 366 sc->sc_res); 367 return (error); 368 } 369 } 370 } 371 if (sbbc_toddata != 0) { 372 if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 373 SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC) 374 device_printf(dev, "invalid TOD magic %#x\n", val); 375 else if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 376 SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION) 377 device_printf(dev, "invalid TOD version %#x\n", val); 378 else { 379 clock_register(dev, 1000000); /* 1 sec. resolution */ 380 if (bootverbose) { 381 sbbc_tod_gettime(dev, &ts); 382 device_printf(dev, 383 "current time: %ld.%09ld\n", 384 (long)ts.tv_sec, ts.tv_nsec); 385 } 386 } 387 } 388 return (0); 389} 390 391/* 392 * Note that the bus methods don't pass-through the uart(4) requests but act 393 * as if they would come from sbbc(4) in order to avoid complications with 394 * pci(4) (actually, uart(4) isn't a real child but rather a function of 395 * sbbc(4) anyway). 396 */ 397 398static struct resource * 399sbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type, 400 int *rid, u_long start, u_long end, u_long count, u_int flags) 401{ 402 struct sbbc_softc *sc; 403 404 sc = device_get_softc(dev); 405 switch (type) { 406 case SYS_RES_IRQ: 407 return (bus_generic_alloc_resource(dev, dev, type, rid, start, 408 end, count, flags)); 409 case SYS_RES_MEMORY: 410 return (sc->sc_res); 411 default: 412 return (NULL); 413 } 414} 415 416static int 417sbbc_bus_activate_resource(device_t bus, device_t child, int type, int rid, 418 struct resource *res) 419{ 420 421 if (type == SYS_RES_MEMORY) 422 return (0); 423 return (bus_generic_activate_resource(bus, child, type, rid, res)); 424} 425 426static int 427sbbc_bus_deactivate_resource(device_t bus, device_t child, int type, int rid, 428 struct resource *res) 429{ 430 431 if (type == SYS_RES_MEMORY) 432 return (0); 433 return (bus_generic_deactivate_resource(bus, child, type, rid, res)); 434} 435 436static int 437sbbc_bus_adjust_resource(device_t bus __unused, device_t child __unused, 438 int type __unused, struct resource *res __unused, u_long start __unused, 439 u_long end __unused) 440{ 441 442 return (ENXIO); 443} 444 445static int 446sbbc_bus_release_resource(device_t dev, device_t child __unused, int type, 447 int rid, struct resource *res) 448{ 449 450 if (type == SYS_RES_IRQ) 451 return (bus_generic_release_resource(dev, dev, type, rid, 452 res)); 453 return (0); 454} 455 456static struct resource_list * 457sbbc_bus_get_resource_list(device_t dev, device_t child __unused) 458{ 459 460 return (bus_generic_get_resource_list(dev, dev)); 461} 462 463static int 464sbbc_bus_setup_intr(device_t dev, device_t child __unused, 465 struct resource *res, int flags, driver_filter_t *filt, 466 driver_intr_t *intr, void *arg, void **cookiep) 467{ 468 469 return (bus_generic_setup_intr(dev, dev, res, flags, filt, intr, arg, 470 cookiep)); 471} 472 473static int 474sbbc_bus_teardown_intr(device_t dev, device_t child __unused, 475 struct resource *res, void *cookie) 476{ 477 478 return (bus_generic_teardown_intr(dev, dev, res, cookie)); 479} 480 481/* 482 * internal helpers 483 */ 484static int 485sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh) 486{ 487 char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)]; 488 bus_size_t tag; 489 phandle_t node; 490 uint32_t off, sram_toc; 491 u_int i, tags; 492 493 if ((node = OF_finddevice("/chosen")) == -1) 494 return (ENXIO); 495 /* SRAM TOC offset defaults to 0. */ 496 if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0) 497 sram_toc = 0; 498 499 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc + 500 SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE); 501 buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0'; 502 if (strcmp(buf, SBBC_TOC_MAGIC) != 0) 503 return (ENXIO); 504 505 tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags)); 506 for (i = 0; i < tags; i++) { 507 tag = sram_toc + SBBC_TOC_OFF(toc_tag) + 508 i * sizeof(struct sbbc_sram_tag); 509 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag + 510 SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE); 511 buf[SBBC_TAG_KEY_SIZE - 1] = '\0'; 512 off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset)); 513 if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0) 514 sbbc_scsolie = off; 515 else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0) 516 sbbc_scsolir = off; 517 else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0) 518 sbbc_solcons = off; 519 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0) 520 sbbc_solscie = off; 521 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0) 522 sbbc_solscir = off; 523 else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0) 524 sbbc_toddata = off; 525 } 526 return (0); 527} 528 529static const char * 530sbbc_serengeti_set_console_input(char *new) 531{ 532 struct { 533 cell_t name; 534 cell_t nargs; 535 cell_t nreturns; 536 cell_t new; 537 cell_t old; 538 } args = { 539 (cell_t)SUNW_SETCONSINPUT, 540 1, 541 1, 542 }; 543 544 args.new = (cell_t)new; 545 if (ofw_entry(&args) == -1) 546 return (NULL); 547 return ((const char *)args.old); 548} 549 550static inline void 551sbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh) 552{ 553 554 SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON); 555 bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1, 556 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 557} 558 559/* 560 * TOD interface 561 */ 562static int 563sbbc_tod_gettime(device_t dev, struct timespec *ts) 564{ 565 struct sbbc_softc *sc; 566 bus_space_tag_t bst; 567 bus_space_handle_t bsh; 568 569 sc = device_get_softc(dev); 570 bst = rman_get_bustag(sc->sc_res); 571 bsh = rman_get_bushandle(sc->sc_res); 572 573 ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) + 574 SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew)); 575 ts->tv_nsec = 0; 576 return (0); 577} 578 579static int 580sbbc_tod_settime(device_t dev, struct timespec *ts) 581{ 582 struct sbbc_softc *sc; 583 bus_space_tag_t bst; 584 bus_space_handle_t bsh; 585 586 sc = device_get_softc(dev); 587 bst = rman_get_bustag(sc->sc_res); 588 bsh = rman_get_bushandle(sc->sc_res); 589 590 SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec - 591 SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time))); 592 return (0); 593} 594 595/* 596 * UART bus front-end 597 */ 598static device_probe_t sbbc_uart_sbbc_probe; 599 600static device_method_t sbbc_uart_sbbc_methods[] = { 601 /* Device interface */ 602 DEVMETHOD(device_probe, sbbc_uart_sbbc_probe), 603 DEVMETHOD(device_attach, uart_bus_attach), 604 DEVMETHOD(device_detach, uart_bus_detach), 605 606 DEVMETHOD_END 607}; 608 609DEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods, 610 sizeof(struct uart_softc)); 611DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL); 612 613static int 614sbbc_uart_sbbc_probe(device_t dev) 615{ 616 struct uart_softc *sc; 617 618 sc = device_get_softc(dev); 619 sc->sc_class = &uart_sbbc_class; 620 device_set_desc(dev, "Serengeti console"); 621 return (uart_bus_probe(dev, 0, 0, SBBC_PCI_BAR, 0)); 622} 623 624/* 625 * Low-level UART interface 626 */ 627static int sbbc_uart_probe(struct uart_bas *bas); 628static void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits, 629 int stopbits, int parity); 630static void sbbc_uart_term(struct uart_bas *bas); 631static void sbbc_uart_putc(struct uart_bas *bas, int c); 632static int sbbc_uart_rxready(struct uart_bas *bas); 633static int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx); 634 635static struct uart_ops sbbc_uart_ops = { 636 .probe = sbbc_uart_probe, 637 .init = sbbc_uart_init, 638 .term = sbbc_uart_term, 639 .putc = sbbc_uart_putc, 640 .rxready = sbbc_uart_rxready, 641 .getc = sbbc_uart_getc, 642}; 643 644static int 645sbbc_uart_probe(struct uart_bas *bas) 646{ 647 bus_space_tag_t bst; 648 bus_space_handle_t bsh; 649 int error; 650 651 sbbc_console = 1; 652 bst = bas->bst; 653 bsh = bas->bsh; 654 error = sbbc_parse_toc(bst, bsh); 655 if (error != 0) 656 return (error); 657 658 if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 || 659 sbbc_solscie == 0 || sbbc_solscir == 0) 660 return (ENXIO); 661 662 if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) != 663 SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons + 664 SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION) 665 return (ENXIO); 666 return (0); 667} 668 669static void 670sbbc_uart_init(struct uart_bas *bas, int baudrate __unused, 671 int databits __unused, int stopbits __unused, int parity __unused) 672{ 673 bus_space_tag_t bst; 674 bus_space_handle_t bsh; 675 676 bst = bas->bst; 677 bsh = bas->bsh; 678 679 /* Enable output to and space in from the SC interrupts. */ 680 SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) | 681 SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN); 682 uart_barrier(bas); 683 684 /* Take over the console input. */ 685 sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT); 686} 687 688static void 689sbbc_uart_term(struct uart_bas *bas __unused) 690{ 691 692 /* Give back the console input. */ 693 sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP); 694} 695 696static void 697sbbc_uart_putc(struct uart_bas *bas, int c) 698{ 699 bus_space_tag_t bst; 700 bus_space_handle_t bsh; 701 uint32_t wrptr; 702 703 bst = bas->bst; 704 bsh = bas->bsh; 705 706 wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 707 SBBC_CONS_OFF(cons_out_wrptr)); 708 SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c); 709 uart_barrier(bas); 710 if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons + 711 SBBC_CONS_OFF(cons_out_end))) 712 wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 713 SBBC_CONS_OFF(cons_out_begin)); 714 SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr), 715 wrptr); 716 uart_barrier(bas); 717 718 SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 719 SBBC_SRAM_CONS_OUT); 720 uart_barrier(bas); 721 sbbc_send_intr(bst, bsh); 722} 723 724static int 725sbbc_uart_rxready(struct uart_bas *bas) 726{ 727 bus_space_tag_t bst; 728 bus_space_handle_t bsh; 729 730 bst = bas->bst; 731 bsh = bas->bsh; 732 733 if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) == 734 SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr))) 735 return (0); 736 return (1); 737} 738 739static int 740sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 741{ 742 bus_space_tag_t bst; 743 bus_space_handle_t bsh; 744 int c; 745 uint32_t rdptr; 746 747 bst = bas->bst; 748 bsh = bas->bsh; 749 750 uart_lock(hwmtx); 751 752 while (sbbc_uart_rxready(bas) == 0) { 753 uart_unlock(hwmtx); 754 DELAY(4); 755 uart_lock(hwmtx); 756 } 757 758 rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)); 759 c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr); 760 uart_barrier(bas); 761 if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons + 762 SBBC_CONS_OFF(cons_in_end))) 763 rdptr = SBBC_SRAM_READ_4(sbbc_solcons + 764 SBBC_CONS_OFF(cons_in_begin)); 765 SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr), 766 rdptr); 767 uart_barrier(bas); 768 SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 769 SBBC_SRAM_CONS_SPACE_IN); 770 uart_barrier(bas); 771 sbbc_send_intr(bst, bsh); 772 773 uart_unlock(hwmtx); 774 return (c); 775} 776 777/* 778 * High-level UART interface 779 */ 780static int sbbc_uart_bus_attach(struct uart_softc *sc); 781static int sbbc_uart_bus_detach(struct uart_softc *sc); 782static int sbbc_uart_bus_flush(struct uart_softc *sc, int what); 783static int sbbc_uart_bus_getsig(struct uart_softc *sc); 784static int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, 785 intptr_t data); 786static int sbbc_uart_bus_ipend(struct uart_softc *sc); 787static int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate, 788 int databits, int stopbits, int parity); 789static int sbbc_uart_bus_probe(struct uart_softc *sc); 790static int sbbc_uart_bus_receive(struct uart_softc *sc); 791static int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig); 792static int sbbc_uart_bus_transmit(struct uart_softc *sc); 793 794static kobj_method_t sbbc_uart_methods[] = { 795 KOBJMETHOD(uart_attach, sbbc_uart_bus_attach), 796 KOBJMETHOD(uart_detach, sbbc_uart_bus_detach), 797 KOBJMETHOD(uart_flush, sbbc_uart_bus_flush), 798 KOBJMETHOD(uart_getsig, sbbc_uart_bus_getsig), 799 KOBJMETHOD(uart_ioctl, sbbc_uart_bus_ioctl), 800 KOBJMETHOD(uart_ipend, sbbc_uart_bus_ipend), 801 KOBJMETHOD(uart_param, sbbc_uart_bus_param), 802 KOBJMETHOD(uart_probe, sbbc_uart_bus_probe), 803 KOBJMETHOD(uart_receive, sbbc_uart_bus_receive), 804 KOBJMETHOD(uart_setsig, sbbc_uart_bus_setsig), 805 KOBJMETHOD(uart_transmit, sbbc_uart_bus_transmit), 806 807 DEVMETHOD_END 808}; 809 810struct uart_class uart_sbbc_class = { 811 "sbbc", 812 sbbc_uart_methods, 813 sizeof(struct uart_softc), 814 .uc_ops = &sbbc_uart_ops, 815 .uc_range = 1,
|