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