1/* $NetBSD: necpb.c,v 1.37 2011/07/01 19:28:00 dyoung Exp $ */ 2 3/*- 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. 35 * Copyright (c) 1994 Charles M. Hannum. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by Charles M. Hannum. 48 * 4. The name of the author may not be used to endorse or promote products 49 * derived from this software without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 52 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 53 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 54 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 55 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 56 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 60 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 */ 62 63#include <sys/cdefs.h> 64__KERNEL_RCSID(0, "$NetBSD: necpb.c,v 1.37 2011/07/01 19:28:00 dyoung Exp $"); 65 66#include "opt_pci.h" 67 68#include <sys/types.h> 69#include <sys/param.h> 70#include <sys/time.h> 71#include <sys/systm.h> 72#include <sys/errno.h> 73#include <sys/device.h> 74#include <sys/malloc.h> 75#include <sys/extent.h> 76 77#include <uvm/uvm_extern.h> 78 79#define _ARC_BUS_DMA_PRIVATE 80#include <sys/bus.h> 81 82#include <machine/pio.h> 83 84#include <machine/autoconf.h> 85#include <machine/cpu.h> 86#include <machine/platform.h> 87 88#include <mips/cache.h> 89 90#include <dev/pci/pcivar.h> 91#include <dev/pci/pcireg.h> 92#include <dev/pci/pcidevs.h> 93#ifdef PCI_NETBSD_CONFIGURE 94#include <dev/pci/pciconf.h> 95#endif 96 97#include <arc/jazz/rd94.h> 98#include <arc/pci/necpbvar.h> 99 100#include "ioconf.h" 101 102static int necpbmatch(struct device *, struct cfdata *, void *); 103static void necpbattach(struct device *, struct device *, void *); 104 105static void necpb_attach_hook(struct device *, struct device *, 106 struct pcibus_attach_args *); 107static int necpb_bus_maxdevs(pci_chipset_tag_t, int); 108static pcitag_t necpb_make_tag(pci_chipset_tag_t, int, int, int); 109static void necpb_decompose_tag(pci_chipset_tag_t, pcitag_t, int *, 110 int *, int *); 111static pcireg_t necpb_conf_read(pci_chipset_tag_t, pcitag_t, int); 112static void necpb_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); 113static int necpb_intr_map(const struct pci_attach_args *, 114 pci_intr_handle_t *); 115static const char *necpb_intr_string(pci_chipset_tag_t, pci_intr_handle_t); 116static void *necpb_intr_establish(pci_chipset_tag_t, pci_intr_handle_t, 117 int, int (*func)(void *), void *); 118static void necpb_intr_disestablish(pci_chipset_tag_t, void *); 119#ifdef PCI_NETBSD_CONFIGURE 120static void necpb_conf_interrupt(pci_chipset_tag_t, int, int, int, int, 121 int *); 122static int necpb_conf_hook(pci_chipset_tag_t, int, int, int, pcireg_t); 123#endif 124 125static uint32_t necpb_intr(uint32_t, struct clockframe *); 126 127 128CFATTACH_DECL_NEW(necpb, sizeof(struct necpb_softc), 129 necpbmatch, necpbattach, NULL, NULL); 130 131static struct necpb_intrhand *necpb_inttbl[4]; 132 133/* There can be only one. */ 134int necpbfound; 135struct necpb_context necpb_main_context; 136static long necpb_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(10) / sizeof(long)]; 137static long necpb_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(10) / sizeof(long)]; 138 139static int 140necpbmatch(device_t parent, cfdata_t cf, void *aux) 141{ 142 struct confargs *ca = aux; 143 144 if (strcmp(ca->ca_name, necpb_cd.cd_name) != 0) 145 return 0; 146 147 if (necpbfound) 148 return 0; 149 150 return 1; 151} 152 153/* 154 * Set up the chipset's function pointers. 155 */ 156void 157necpb_init(struct necpb_context *ncp) 158{ 159 pci_chipset_tag_t pc; 160#ifndef PCI_NETBSD_CONFIGURE 161 pcitag_t tag; 162 pcireg_t id, class, csr; 163 u_int dev; 164#endif 165 166 if (ncp->nc_initialized) 167 return; 168 169 arc_large_bus_space_init(&ncp->nc_memt, "necpcimem", 170 RD94_P_PCI_MEM, 0, RD94_S_PCI_MEM); 171 arc_bus_space_init_extent(&ncp->nc_memt, (void *)necpb_mem_ex_storage, 172 sizeof(necpb_mem_ex_storage)); 173 174 arc_bus_space_init(&ncp->nc_iot, "necpciio", 175 RD94_P_PCI_IO, RD94_V_PCI_IO, 0, RD94_S_PCI_IO); 176 arc_bus_space_init_extent(&ncp->nc_iot, (void *)necpb_io_ex_storage, 177 sizeof(necpb_io_ex_storage)); 178 179 jazz_bus_dma_tag_init(&ncp->nc_dmat); 180 181 pc = &ncp->nc_pc; 182 pc->pc_attach_hook = necpb_attach_hook; 183 pc->pc_bus_maxdevs = necpb_bus_maxdevs; 184 pc->pc_make_tag = necpb_make_tag; 185 pc->pc_decompose_tag = necpb_decompose_tag; 186 pc->pc_conf_read = necpb_conf_read; 187 pc->pc_conf_write = necpb_conf_write; 188 pc->pc_intr_map = necpb_intr_map; 189 pc->pc_intr_string = necpb_intr_string; 190 pc->pc_intr_establish = necpb_intr_establish; 191 pc->pc_intr_disestablish = necpb_intr_disestablish; 192#ifdef PCI_NETBSD_CONFIGURE 193 pc->pc_conf_interrupt = necpb_conf_interrupt; 194 pc->pc_conf_hook = necpb_conf_hook; 195#endif 196 197#ifndef PCI_NETBSD_CONFIGURE 198 /* 199 * XXX: 200 * NEC's firmware does not configure PCI devices completely. 201 * We need to disable expansion ROM and enable mem/io/busmaster 202 * bits here. 203 */ 204 for (dev = 3; dev <= 5; dev++) { 205 tag = necpb_make_tag(pc, 0, dev, 0); 206 id = necpb_conf_read(pc, tag, PCI_ID_REG); 207 208 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 209 continue; 210 211 class = necpb_conf_read(pc, tag, PCI_CLASS_REG); 212 csr = necpb_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 213 if (PCI_CLASS(class) != PCI_CLASS_BRIDGE || 214 PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_PCI) { 215 csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; 216 necpb_conf_write(pc, tag, PCI_MAPREG_ROM, 0); 217 } 218 csr |= PCI_COMMAND_MASTER_ENABLE; 219 necpb_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); 220 } 221#endif 222 223 ncp->nc_initialized = 1; 224} 225 226static void 227necpbattach(device_t parent, device_t self, void *aux) 228{ 229 struct necpb_softc *sc = device_private(self); 230 struct pcibus_attach_args pba; 231 pci_chipset_tag_t pc; 232 int i; 233 234 sc->sc_dev = self; 235 236 necpbfound = 1; 237 238 aprint_normal("\n"); 239 240 sc->sc_ncp = &necpb_main_context; 241 necpb_init(sc->sc_ncp); 242 243 pc = &sc->sc_ncp->nc_pc; 244#ifdef PCI_NETBSD_CONFIGURE 245 pc->pc_ioext = extent_create("necpbio", 0x00100000, 0x01ffffff, 246 NULL, 0, EX_NOWAIT); 247 pc->pc_memext = extent_create("necpbmem", 0x08000000, 0x3fffffff, 248 NULL, 0, EX_NOWAIT); 249 pci_configure_bus(pc, pc->pc_ioext, pc->pc_memext, NULL, 0, 250 mips_cache_info.mci_dcache_align); 251#endif 252 253 out32(RD94_SYS_PCI_INTMASK, 0xf); 254 255 for (i = 0; i < 4; i++) 256 necpb_inttbl[i] = NULL; 257 258 (*platform->set_intr)(MIPS_INT_MASK_2, necpb_intr, ARC_INTPRI_PCIISA); 259 260 pba.pba_iot = &sc->sc_ncp->nc_iot; 261 pba.pba_memt = &sc->sc_ncp->nc_memt; 262 pba.pba_dmat = &sc->sc_ncp->nc_dmat; 263 pba.pba_dmat64 = NULL; 264 pba.pba_pc = pc; 265 pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY; 266 pba.pba_bus = 0; 267 pba.pba_bridgetag = NULL; 268 269 config_found_ia(self, "pcibus", &pba, pcibusprint); 270} 271 272static void 273necpb_attach_hook(struct device *parent, struct device *self, 274 struct pcibus_attach_args *pba) 275{ 276} 277 278static int 279necpb_bus_maxdevs(pci_chipset_tag_t pc, int busno) 280{ 281 282 return 32; 283} 284 285static pcitag_t 286necpb_make_tag(pci_chipset_tag_t pc, int bus, int device, int function) 287{ 288 pcitag_t tag; 289 290 if (bus >= 256 || device >= 32 || function >= 8) 291 panic("%s: bad request", __func__); 292 293 tag = 0x80000000 | (bus << 16) | (device << 11) | (function << 8); 294 return tag; 295} 296 297static void 298necpb_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, 299 int *fp) 300{ 301 302 if (bp != NULL) 303 *bp = (tag >> 16) & 0xff; 304 if (dp != NULL) 305 *dp = (tag >> 11) & 0x1f; 306 if (fp != NULL) 307 *fp = (tag >> 8) & 0x07; 308} 309 310static pcireg_t 311necpb_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 312{ 313 pcireg_t data; 314 int s; 315 316 s = splhigh(); 317 out32(RD94_SYS_PCI_CONFADDR, tag | reg); 318 data = in32(RD94_SYS_PCI_CONFDATA); 319 out32(RD94_SYS_PCI_CONFADDR, 0); 320 splx(s); 321 322 return data; 323} 324 325static void 326necpb_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 327{ 328 int s; 329 330 s = splhigh(); 331 out32(RD94_SYS_PCI_CONFADDR, tag | reg); 332 out32(RD94_SYS_PCI_CONFDATA, data); 333 out32(RD94_SYS_PCI_CONFADDR, 0); 334 splx(s); 335} 336 337static int 338necpb_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 339{ 340 pci_chipset_tag_t pc = pa->pa_pc; 341 pcitag_t intrtag = pa->pa_intrtag; 342 int pin = pa->pa_intrpin; 343 int bus, dev; 344 345 if (pin == 0) { 346 /* No IRQ used. */ 347 *ihp = -1; 348 return 1; 349 } 350 351 if (pin > 4) { 352 printf("necpb_intr_map: bad interrupt pin %d\n", pin); 353 *ihp = -1; 354 return 1; 355 } 356 357 necpb_decompose_tag(pc, intrtag, &bus, &dev, NULL); 358 if (bus != 0) { 359 printf("necpb_intr_map: unknown bus %d\n", bus); 360 *ihp = -1; 361 return 1; 362 } 363 364 switch (dev) { 365 case 3: 366 *ihp = 3; 367 break; 368 case 4: 369 *ihp = 2; 370 break; 371 case 5: 372 *ihp = 1; 373 break; 374 default: 375 *ihp = -1; 376 return 1; 377 } 378 379 return 0; 380} 381 382static const char * 383necpb_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) 384{ 385 static char str[8]; 386 387 if (ih >= 4) 388 panic("%s: bogus handle %ld", __func__, ih); 389 sprintf(str, "int %c", 'A' + (int)ih); 390 return str; 391} 392 393static void * 394necpb_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, 395 int (*func)(void *), void *arg) 396{ 397 struct necpb_intrhand *n, *p; 398 uint32_t mask; 399 400 if (ih >= 4) 401 panic("%s: bogus handle", __func__); 402 403 n = malloc(sizeof(struct necpb_intrhand), M_DEVBUF, M_NOWAIT); 404 if (n == NULL) 405 panic("%s: can't malloc interrupt handle", __func__); 406 407 n->ih_func = func; 408 n->ih_arg = arg; 409 n->ih_next = NULL; 410 n->ih_intn = ih; 411 strlcpy(n->ih_evname, necpb_intr_string(pc, ih), sizeof(n->ih_evname)); 412 evcnt_attach_dynamic(&n->ih_evcnt, EVCNT_TYPE_INTR, NULL, "necpb", 413 n->ih_evname); 414 415 if (necpb_inttbl[ih] == NULL) { 416 necpb_inttbl[ih] = n; 417 mask = in32(RD94_SYS_PCI_INTMASK); 418 mask |= 1 << ih; 419 out32(RD94_SYS_PCI_INTMASK, mask); 420 } else { 421 p = necpb_inttbl[ih]; 422 while (p->ih_next != NULL) 423 p = p->ih_next; 424 p->ih_next = n; 425 } 426 427 return n; 428} 429 430static void 431necpb_intr_disestablish(pci_chipset_tag_t pc, void *cookie) 432{ 433 struct necpb_intrhand *n, *p, *q; 434 uint32_t mask; 435 436 n = cookie; 437 438 q = NULL; 439 p = necpb_inttbl[n->ih_intn]; 440 while (p != n) { 441 if (p == NULL) 442 panic("%s: broken intr table", __func__); 443 q = p; 444 p = p->ih_next; 445 } 446 447 if (q == NULL) { 448 necpb_inttbl[n->ih_intn] = n->ih_next; 449 if (n->ih_next == NULL) { 450 mask = in32(RD94_SYS_PCI_INTMASK); 451 mask &= ~(1 << n->ih_intn); 452 out32(RD94_SYS_PCI_INTMASK, mask); 453 } 454 } else 455 q->ih_next = n->ih_next; 456 457 evcnt_detach(&n->ih_evcnt); 458 459 free(n, M_DEVBUF); 460} 461 462/* 463 * Handle PCI/EISA interrupt. 464 */ 465static uint32_t 466necpb_intr(uint32_t mask, struct clockframe *cf) 467{ 468 uint32_t vector, stat; 469 struct necpb_intrhand *p; 470 int i, handled; 471 472 handled = 0; 473 vector = in32(RD94_SYS_INTSTAT2) & 0xffff; 474 475 if (vector == 0x4000) { 476 stat = in32(RD94_SYS_PCI_INTSTAT); 477 stat &= in32(RD94_SYS_PCI_INTMASK); 478 for (i = 0; i < 4; i++) { 479 if (stat & (1 << i)) { 480#if 0 481 printf("pint %d\n", i); 482#endif 483 p = necpb_inttbl[i]; 484 while (p != NULL) { 485 if ((*p->ih_func)(p->ih_arg)) { 486 p->ih_evcnt.ev_count++; 487 handled |= 1; 488 } 489 p = p->ih_next; 490 } 491 } 492 } 493 } else if (vector == 0x8000) { 494 printf("eisa_nmi\n"); 495 } else { 496 printf("eint %d\n", vector & 0xff); 497#if 0 498 if (eisa_intr(vector & 0xff)) { 499 handled |= 1; 500 } 501#endif 502 } 503 504 return handled ? MIPS_INT_MASK_2 : 0; 505} 506 507#ifdef PCI_NETBSD_CONFIGURE 508static void 509necpb_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int func, 510 int swiz, int *iline) 511{ 512 513 return; 514} 515 516static int 517necpb_conf_hook(pci_chipset_tag_t pc, int bus, int dev, int func, 518 pcireg_t id) 519{ 520 521 /* ignore bogus IDs */ 522 if (id == 0) 523 return 0; 524 525 /* don't configure bridges */ 526 if (bus == 0 && (dev == 1 || dev == 2)) 527 return 0; 528 529 return PCI_CONF_DEFAULT; 530} 531#endif 532