obio.c revision 265999
1/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ 2 3/*- 4 * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/10/sys/mips/rt305x/obio.c 265999 2014-05-14 01:35:43Z ian $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/bus.h> 37#include <sys/interrupt.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/rman.h> 41#include <sys/malloc.h> 42 43#include <machine/bus.h> 44 45#include <mips/rt305x/rt305xreg.h> 46#include <mips/rt305x/obiovar.h> 47#include <mips/rt305x/rt305x_icvar.h> 48 49/* MIPS HW interrupts of IRQ/FIQ respectively */ 50#define RT305X_INTR 0 51#define RT305X_FAST_INTR 1 52 53/* Interrupt levels */ 54#define INTR_IRQ 0 55#define INTR_FIQ 1 56 57 58int irq_priorities[NIRQS] = { 59 INTR_IRQ, /* SYSCTL */ 60 INTR_FIQ, /* TIMER0 */ 61 INTR_FIQ, /* WDTIMER */ 62 INTR_IRQ, /* Illegal Access */ 63 INTR_IRQ, /* PCM */ 64 INTR_IRQ, /* UART */ 65 INTR_IRQ, /* GPIO */ 66 INTR_FIQ, /* GDMA */ 67 INTR_IRQ, /* NAND */ 68 INTR_IRQ, /* Perfomance Counter */ 69 INTR_IRQ, /* I2S */ 70 INTR_IRQ, /* unknown */ 71 INTR_IRQ, /* UARTLITE */ 72 INTR_IRQ, /* unknown */ 73 INTR_IRQ, /* unknown */ 74 INTR_IRQ, /* unknown */ 75 INTR_IRQ, /* unknown */ 76 INTR_IRQ, /* EtherNet Switch */ 77 INTR_FIQ, /* OTG */ 78 INTR_IRQ, /* unknown */ 79 INTR_IRQ, /* unknown */ 80 INTR_IRQ, /* unknown */ 81 INTR_IRQ, /* unknown */ 82 INTR_IRQ, /* unknown */ 83 INTR_IRQ, /* unknown */ 84 INTR_IRQ, /* unknown */ 85 INTR_IRQ, /* unknown */ 86 INTR_IRQ, /* unknown */ 87 INTR_IRQ, /* unknown */ 88 INTR_IRQ, /* unknown */ 89 INTR_IRQ, /* unknown */ 90 INTR_IRQ, /* unknown */ 91}; 92 93 94#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(INTCTL_BASE + (o))) 95#define REG_WRITE(o,v) (REG_READ(o)) = (v) 96 97static int obio_activate_resource(device_t, device_t, int, int, 98 struct resource *); 99static device_t obio_add_child(device_t, u_int, const char *, int); 100static struct resource * 101 obio_alloc_resource(device_t, device_t, int, int *, u_long, 102 u_long, u_long, u_int); 103static int obio_attach(device_t); 104static int obio_deactivate_resource(device_t, device_t, int, int, 105 struct resource *); 106static struct resource_list * 107 obio_get_resource_list(device_t, device_t); 108static void obio_add_res_child(device_t, const char *, int, long, int, int); 109static void obio_hinted_child(device_t, const char *, int); 110static int obio_intr(void *); 111static int obio_probe(device_t); 112static int obio_release_resource(device_t, device_t, int, int, 113 struct resource *); 114static int obio_setup_intr(device_t, device_t, struct resource *, int, 115 driver_filter_t *, driver_intr_t *, void *, void **); 116static int obio_teardown_intr(device_t, device_t, struct resource *, 117 void *); 118 119static void 120obio_mask_irq(void *source) 121{ 122 int irq; 123 uint32_t irqmask; 124 125 irq = (int)source; 126 irqmask = 1 << irq; 127 128 /* disable IRQ */ 129 rt305x_ic_set(IC_INT_DIS, irqmask); 130} 131 132static void 133obio_unmask_irq(void *source) 134{ 135 int irq; 136 uint32_t irqmask; 137 138 irq = (int)source; 139 irqmask = 1 << irq; 140 141 /* enable IRQ */ 142 rt305x_ic_set(IC_INT_ENA, irqmask); 143 144} 145 146 147static int 148obio_probe(device_t dev) 149{ 150 151 return (BUS_PROBE_NOWILDCARD); 152} 153 154static int 155obio_attach(device_t dev) 156{ 157 struct obio_softc *sc = device_get_softc(dev); 158 int rid; 159 160 sc->oba_mem_rman.rm_type = RMAN_ARRAY; 161 sc->oba_mem_rman.rm_descr = "OBIO memory"; 162 if (rman_init(&sc->oba_mem_rman) != 0 || 163 rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START, 164 OBIO_MEM_END) != 0) 165 panic("obio_attach: failed to set up I/O rman"); 166 167 sc->oba_irq_rman.rm_type = RMAN_ARRAY; 168 sc->oba_irq_rman.rm_descr = "OBIO IRQ"; 169 if (rman_init(&sc->oba_irq_rman) != 0 || 170 rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0) 171 panic("obio_attach: failed to set up IRQ rman"); 172 173 /* Hook up our interrupt handler. */ 174 if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 175 RT305X_INTR, RT305X_INTR, 1, 176 RF_SHAREABLE | RF_ACTIVE)) == NULL) { 177 device_printf(dev, "unable to allocate IRQ resource\n"); 178 return (ENXIO); 179 } 180 181 if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL, 182 sc, &sc->sc_ih))) { 183 device_printf(dev, 184 "WARNING: unable to register interrupt handler\n"); 185 return (ENXIO); 186 } 187 188 /* Hook up our FAST interrupt handler. */ 189 if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 190 RT305X_FAST_INTR, RT305X_FAST_INTR, 1, 191 RF_SHAREABLE | RF_ACTIVE)) == NULL) { 192 device_printf(dev, "unable to allocate IRQ resource\n"); 193 return (ENXIO); 194 } 195 196 if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr, 197 NULL, sc, &sc->sc_fast_ih))) { 198 device_printf(dev, 199 "WARNING: unable to register interrupt handler\n"); 200 return (ENXIO); 201 } 202 203 /* disable all interrupts */ 204 rt305x_ic_set(IC_INT_DIS, IC_INT_MASK|IC_LINE_GLOBAL); 205 206 bus_generic_probe(dev); 207 208 obio_add_res_child(dev, "rt305x_sysctl", 0, 209 SYSCTL_BASE, (SYSCTL_END - SYSCTL_BASE + 1), 210 IC_SYSCTL); 211 obio_add_res_child(dev, "rt305x_ic", 0, 212 INTCTL_BASE, (INTCTL_END - INTCTL_BASE + 1), 213 -1); 214#ifdef notyet 215 obio_add_res_child(dev, "timer",0, 216 TIMER_BASE, (TIMER_END - TIMER_BASE + 1), 217 IC_TIMER0); 218 obio_add_res_child(dev, "rt305x_memc", 0, 219 MEMCTRL_BASE, (MEMCTRL_END - MEMCTRL_BASE + 1), 220 -1); 221 obio_add_res_child(dev, "pcm", 0, 222 PCM_BASE, (PCM_END - PCM_BASE + 1), 223 IC_PCM); 224 obio_add_res_child(dev, "uart", 0, 225 UART_BASE, (UART_END - UART_BASE + 1), 226 IC_UART); 227#endif 228 obio_add_res_child(dev, "gpio", 0, 229 PIO_BASE, (PIO_END - PIO_BASE + 1), 230 IC_PIO); 231#ifdef notyet 232 obio_add_res_child(dev, "rt305x_dma", 0, 233 GDMA_BASE, (GDMA_END - GDMA_BASE + 1), 234 IC_DMA); 235 obio_add_res_child(dev, "rt305x_nandc", 0, 236 NANDFC_BASE, (NANDFC_END - NANDFC_BASE + 1), 237 IC_NAND); 238 obio_add_res_child(dev, "i2c", 0, 239 I2C_BASE, (I2C_END - I2C_BASE + 1), 240 -1); 241 obio_add_res_child(dev, "i2s", 0, 242 I2S_BASE, (I2S_END - I2S_BASE + 1), 243 IC_I2S); 244 obio_add_res_child(dev, "spi", 0, 245 SPI_BASE, (SPI_END - SPI_BASE + 1), 246 -1); 247#endif 248 obio_add_res_child(dev, "uart", 1, 249 UARTLITE_BASE, (UARTLITE_END - UARTLITE_BASE + 1), 250 IC_UARTLITE); 251 obio_add_res_child(dev, "cfi", 0, 252 FLASH_BASE, (FLASH_END - FLASH_BASE + 1), 253 -1); 254 obio_add_res_child(dev, "dotg", 0, 255 USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE + 1), 256 IC_OTG); 257 obio_add_res_child(dev, "switch", 0, 258 ETHSW_BASE, (ETHSW_END - ETHSW_BASE + 1), 259 IC_ETHSW); 260 261 bus_enumerate_hinted_children(dev); 262 bus_generic_attach(dev); 263 264 /* enable IC */ 265 rt305x_ic_set(IC_INT_ENA, IC_LINE_GLOBAL); 266 267 return (0); 268} 269 270static struct resource * 271obio_alloc_resource(device_t bus, device_t child, int type, int *rid, 272 u_long start, u_long end, u_long count, u_int flags) 273{ 274 struct obio_softc *sc = device_get_softc(bus); 275 struct obio_ivar *ivar = device_get_ivars(child); 276 struct resource *rv; 277 struct resource_list_entry *rle; 278 struct rman *rm; 279 int isdefault, needactivate, passthrough; 280 281 isdefault = (start == 0UL && end == ~0UL && count == 1); 282 needactivate = flags & RF_ACTIVE; 283 passthrough = (device_get_parent(child) != bus); 284 rle = NULL; 285 286 if (passthrough) 287 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, 288 rid, start, end, count, flags)); 289 290 /* 291 * If this is an allocation of the "default" range for a given RID, 292 * and we know what the resources for this device are (ie. they aren't 293 * maintained by a child bus), then work out the start/end values. 294 */ 295 if (isdefault) { 296 rle = resource_list_find(&ivar->resources, type, *rid); 297 if (rle == NULL) 298 return (NULL); 299 if (rle->res != NULL) { 300 panic("%s: resource entry is busy", __func__); 301 } 302 start = rle->start; 303 end = rle->end; 304 count = rle->count; 305 } 306 307 switch (type) { 308 case SYS_RES_IRQ: 309 rm = &sc->oba_irq_rman; 310 break; 311 case SYS_RES_MEMORY: 312 rm = &sc->oba_mem_rman; 313 break; 314 default: 315 printf("%s: unknown resource type %d\n", __func__, type); 316 return (0); 317 } 318 319 rv = rman_reserve_resource(rm, start, end, count, flags, child); 320 if (rv == 0) { 321 printf("%s: could not reserve resource\n", __func__); 322 return (0); 323 } 324 325 rman_set_rid(rv, *rid); 326 327 if (needactivate) { 328 if (bus_activate_resource(child, type, *rid, rv)) { 329 printf("%s: could not activate resource\n", __func__); 330 rman_release_resource(rv); 331 return (0); 332 } 333 } 334 335 return (rv); 336} 337 338static int 339obio_activate_resource(device_t bus, device_t child, int type, int rid, 340 struct resource *r) 341{ 342 343 /* 344 * If this is a memory resource, track the direct mapping 345 * in the uncached MIPS KSEG1 segment. 346 */ 347 if (type == SYS_RES_MEMORY) { 348 void *vaddr; 349 350 vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r)); 351 rman_set_virtual(r, vaddr); 352 rman_set_bustag(r, mips_bus_space_generic); 353 rman_set_bushandle(r, (bus_space_handle_t)vaddr); 354 } 355 356 return (rman_activate_resource(r)); 357} 358 359static int 360obio_deactivate_resource(device_t bus, device_t child, int type, int rid, 361 struct resource *r) 362{ 363 364 return (rman_deactivate_resource(r)); 365} 366 367static int 368obio_release_resource(device_t dev, device_t child, int type, 369 int rid, struct resource *r) 370{ 371 struct resource_list *rl; 372 struct resource_list_entry *rle; 373 374 rl = obio_get_resource_list(dev, child); 375 if (rl == NULL) 376 return (EINVAL); 377 rle = resource_list_find(rl, type, rid); 378 if (rle == NULL) 379 return (EINVAL); 380 rman_release_resource(r); 381 rle->res = NULL; 382 383 return (0); 384} 385 386static int 387obio_setup_intr(device_t dev, device_t child, struct resource *ires, 388 int flags, driver_filter_t *filt, driver_intr_t *handler, 389 void *arg, void **cookiep) 390{ 391 struct obio_softc *sc = device_get_softc(dev); 392 struct intr_event *event; 393 int irq, error, priority; 394 uint32_t irqmask; 395 396 irq = rman_get_start(ires); 397 398 if (irq >= NIRQS) 399 panic("%s: bad irq %d", __func__, irq); 400 401 event = sc->sc_eventstab[irq]; 402 if (event == NULL) { 403 error = intr_event_create(&event, (void *)irq, 0, irq, 404 obio_mask_irq, obio_unmask_irq, 405 NULL, NULL, "obio intr%d:", irq); 406 407 sc->sc_eventstab[irq] = event; 408 } 409 else 410 panic("obio: Can't share IRQs"); 411 412 intr_event_add_handler(event, device_get_nameunit(child), filt, 413 handler, arg, intr_priority(flags), flags, cookiep); 414 415 irqmask = 1 << irq; 416 priority = irq_priorities[irq]; 417 418 if (priority == INTR_FIQ) 419 rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask); 420 else 421 rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask); 422 423 /* enable */ 424 obio_unmask_irq((void*)irq); 425 426 return (0); 427} 428 429static int 430obio_teardown_intr(device_t dev, device_t child, struct resource *ires, 431 void *cookie) 432{ 433 struct obio_softc *sc = device_get_softc(dev); 434 int irq, result, priority; 435 uint32_t irqmask; 436 437 irq = rman_get_start(ires); 438 if (irq >= NIRQS) 439 panic("%s: bad irq %d", __func__, irq); 440 441 if (sc->sc_eventstab[irq] == NULL) 442 panic("Trying to teardown unoccupied IRQ"); 443 444 irqmask = (1 << irq); 445 priority = irq_priorities[irq]; 446 447 if (priority == INTR_FIQ) 448 rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask); 449 else 450 rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask); 451 452 /* disable */ 453 obio_mask_irq((void*)irq); 454 455 result = intr_event_remove_handler(cookie); 456 if (!result) { 457 sc->sc_eventstab[irq] = NULL; 458 } 459 460 return (result); 461} 462 463static int 464obio_intr(void *arg) 465{ 466 struct obio_softc *sc = arg; 467 struct intr_event *event; 468 uint32_t irqstat; 469 int irq; 470 471 irqstat = rt305x_ic_get(IC_IRQ0STAT); 472 irqstat |= rt305x_ic_get(IC_IRQ1STAT); 473 474 irq = 0; 475 while (irqstat != 0) { 476 if ((irqstat & 1) == 1) { 477 event = sc->sc_eventstab[irq]; 478 if (!event || TAILQ_EMPTY(&event->ie_handlers)) 479 continue; 480 481 /* TODO: pass frame as an argument*/ 482 /* TODO: log stray interrupt */ 483 intr_event_handle(event, NULL); 484 } 485 irq++; 486 irqstat >>= 1; 487 } 488 489 return (FILTER_HANDLED); 490} 491 492static void 493obio_add_res_child(device_t bus, const char *dname, int dunit, 494 long maddr, int msize, int irq) 495{ 496 device_t child; 497 int result; 498 499 child = BUS_ADD_CHILD(bus, 0, dname, dunit); 500 501 result = bus_set_resource(child, SYS_RES_MEMORY, 0, 502 maddr, msize); 503 if (result != 0) 504 device_printf(bus, "warning: bus_set_resource() failed\n"); 505 506 if (irq != -1) { 507 result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 508 if (result != 0) 509 device_printf(bus, 510 "warning: bus_set_resource() failed\n"); 511 } 512} 513 514static void 515obio_hinted_child(device_t bus, const char *dname, int dunit) 516{ 517 long maddr; 518 int msize; 519 int irq; 520 521 /* 522 * Set hard-wired resources for hinted child using 523 * specific RIDs. 524 */ 525 resource_long_value(dname, dunit, "maddr", &maddr); 526 resource_int_value(dname, dunit, "msize", &msize); 527 528 529 if (resource_int_value(dname, dunit, "irq", &irq) == 0) irq = -1; 530 531 obio_add_res_child(bus, dname, dunit, maddr, msize, irq); 532} 533 534static device_t 535obio_add_child(device_t bus, u_int order, const char *name, int unit) 536{ 537 device_t child; 538 struct obio_ivar *ivar; 539 540 ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO); 541 if (ivar == NULL) { 542 printf("Failed to allocate ivar\n"); 543 return (0); 544 } 545 resource_list_init(&ivar->resources); 546 547 child = device_add_child_ordered(bus, order, name, unit); 548 if (child == NULL) { 549 printf("Can't add child %s%d ordered\n", name, unit); 550 return (0); 551 } 552 553 device_set_ivars(child, ivar); 554 555 return (child); 556} 557 558/* 559 * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource 560 * Provides pointer to resource_list for these routines 561 */ 562static struct resource_list * 563obio_get_resource_list(device_t dev, device_t child) 564{ 565 struct obio_ivar *ivar; 566 567 ivar = device_get_ivars(child); 568 return (&(ivar->resources)); 569} 570 571static int 572obio_print_all_resources(device_t dev) 573{ 574 struct obio_ivar *ivar = device_get_ivars(dev); 575 struct resource_list *rl = &ivar->resources; 576 int retval = 0; 577 578 if (STAILQ_FIRST(rl)) 579 retval += printf(" at"); 580 581 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 582 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 583 584 return (retval); 585} 586 587static int 588obio_print_child(device_t bus, device_t child) 589{ 590 int retval = 0; 591 592 retval += bus_print_child_header(bus, child); 593 retval += obio_print_all_resources(child); 594 if (device_get_flags(child)) 595 retval += printf(" flags %#x", device_get_flags(child)); 596 retval += printf(" on %s\n", device_get_nameunit(bus)); 597 598 return (retval); 599} 600 601static device_method_t obio_methods[] = { 602 DEVMETHOD(bus_activate_resource, obio_activate_resource), 603 DEVMETHOD(bus_add_child, obio_add_child), 604 DEVMETHOD(bus_alloc_resource, obio_alloc_resource), 605 DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource), 606 DEVMETHOD(bus_get_resource_list, obio_get_resource_list), 607 DEVMETHOD(bus_hinted_child, obio_hinted_child), 608 DEVMETHOD(bus_print_child, obio_print_child), 609 DEVMETHOD(bus_release_resource, obio_release_resource), 610 DEVMETHOD(bus_setup_intr, obio_setup_intr), 611 DEVMETHOD(bus_teardown_intr, obio_teardown_intr), 612 DEVMETHOD(device_attach, obio_attach), 613 DEVMETHOD(device_probe, obio_probe), 614 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 615 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 616 617 {0, 0}, 618}; 619 620static driver_t obio_driver = { 621 "obio", 622 obio_methods, 623 sizeof(struct obio_softc), 624}; 625static devclass_t obio_devclass; 626 627DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0); 628