1 /* $OpenBSD: i82365_cbus.c,v 1.7 2022/04/06 18:59:26 naddy Exp $ */ 2 /* $NetBSD: i82365_isa.c,v 1.11 1998/06/09 07:25:00 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Marc Horowitz. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Driver for PC-9801-102 & PC-9821X[AE]-E01 PC Card slot adapter 35 * based on OpenBSD:src/sys/dev/isa/i82365_isa{,subr}.c 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/device.h> 42 #include <sys/extent.h> 43 #include <sys/malloc.h> 44 45 #include <machine/board.h> /* PC_BASE */ 46 #include <machine/bus.h> 47 #include <machine/intr.h> 48 49 #include <arch/luna88k/cbus/cbusvar.h> 50 51 #include <dev/pcmcia/pcmciareg.h> 52 #include <dev/pcmcia/pcmciavar.h> 53 #include <dev/pcmcia/pcmciachip.h> 54 55 #include <dev/ic/i82365reg.h> 56 #include <dev/ic/i82365var.h> 57 58 #ifdef PCICCBUSDEBUG 59 #define DPRINTF(arg) printf arg; 60 #else 61 #define DPRINTF(arg) 62 #endif 63 64 /* 65 * XXX: 66 * The C-bus expects edge-triggered interrupts, but some PC Cards and 67 * the controller itself produce level-triggered interrupts. This causes 68 * spurious interrupts on C-bus. 69 * Then, we use CL-PD67XX 'pulse IRQ' feature in this driver. This seems 70 * to solve stray interrupts on C-bus. 71 * (BTW, all NEC genuine C-bus PC Card slot adapters use CL-PD67XX) 72 */ 73 74 /* Cirrus Logic CL-PD67XX Misc Control register */ 75 #define PCIC_CIRRUS_MISC_CTL_1 0x16 76 #define PCIC_CIRRUS_MISC_CTL_1_PULSE_MGMT_INTR 0x04 77 #define PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ 0x08 78 79 #define PCEXMEM_BASE PC_BASE 80 #define PCEXIO_BASE PC_BASE + 0x1000000 81 82 /* prototypes */ 83 void *pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t, 84 struct pcmcia_function *, int, int (*) (void *), void *, char *); 85 void pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t, void *); 86 const char *pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t, void *); 87 int pcic_cbus_intlevel_find(void); 88 int pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, 89 bus_size_t, bus_size_t, struct pcmcia_io_handle *); 90 void pcic_cbus_chip_io_free(pcmcia_chipset_handle_t, 91 struct pcmcia_io_handle *); 92 93 int pcic_cbus_probe(struct device *, void *, void *); 94 void pcic_cbus_attach(struct device *, struct device *, void *); 95 96 /* bus space tag for pcic_cbus */ 97 struct luna88k_bus_space_tag pcic_cbus_io_bst = { 98 .bs_stride_1 = 0, 99 .bs_stride_2 = 0, 100 .bs_stride_4 = 0, 101 .bs_stride_8 = 0, /* not used */ 102 .bs_offset = PCEXIO_BASE, 103 .bs_flags = TAG_LITTLE_ENDIAN 104 }; 105 106 struct luna88k_bus_space_tag pcic_cbus_mem_bst = { 107 .bs_stride_1 = 0, 108 .bs_stride_2 = 0, 109 .bs_stride_4 = 0, 110 .bs_stride_8 = 0, /* not used */ 111 .bs_offset = PCEXMEM_BASE, 112 .bs_flags = TAG_LITTLE_ENDIAN 113 }; 114 115 const struct cfattach pcic_cbus_ca = { 116 sizeof(struct pcic_softc), pcic_cbus_probe, pcic_cbus_attach 117 }; 118 119 static struct pcmcia_chip_functions pcic_cbus_functions = { 120 .mem_alloc = pcic_chip_mem_alloc, 121 .mem_free = pcic_chip_mem_free, 122 .mem_map = pcic_chip_mem_map, 123 .mem_unmap = pcic_chip_mem_unmap, 124 125 .io_alloc = pcic_cbus_chip_io_alloc, 126 .io_free = pcic_cbus_chip_io_free, 127 .io_map = pcic_chip_io_map, 128 .io_unmap = pcic_chip_io_unmap, 129 130 .intr_establish = pcic_cbus_chip_intr_establish, 131 .intr_disestablish = pcic_cbus_chip_intr_disestablish, 132 .intr_string = pcic_cbus_chip_intr_string, 133 134 .socket_enable = pcic_chip_socket_enable, 135 .socket_disable = pcic_chip_socket_disable, 136 }; 137 138 /* 139 * NEC PC-9801 architecture uses different IRQ notation from PC-AT 140 * architecture, so-called INT. The MI pcic(4) driver internally uses 141 * IRQ, so here is a table to convert INT to IRQ. 142 */ 143 static const int pcic_cbus_int2irq[NCBUSISR] = { 144 PCIC_INTR_IRQ3, /* INT 0 */ 145 PCIC_INTR_IRQ5, /* INT 1 */ 146 PCIC_INTR_IRQ_RESERVED6, /* INT 2 */ 147 PCIC_INTR_IRQ9, /* INT 3 */ 148 PCIC_INTR_IRQ10, /* INT 4(41) */ 149 PCIC_INTR_IRQ12, /* INT 5 */ 150 PCIC_INTR_IRQ_RESERVED13 /* INT 6 */ 151 }; 152 153 /* And, a table to convert IRQ to INT */ 154 static const int pcic_cbus_irq2int[] = { 155 -1, -1, -1, 0, -1, 1, 2, -1, /* IRQ 0- 7 */ 156 -1, 3, 4, -1, 5, 6, -1, -1 /* IRQ 8-15 */ 157 }; 158 159 struct pcic_ranges pcic_cbus_addr[] = { 160 { 0x340, 0x030 }, 161 { 0x300, 0x030 }, 162 { 0x390, 0x020 }, 163 { 0x400, 0xbff }, 164 { 0, 0}, /* terminator */ 165 }; 166 167 int 168 pcic_cbus_probe(parent, match, aux) 169 struct device *parent; 170 void *match, *aux; 171 { 172 struct cfdata *cf = match; 173 struct cbus_attach_args *caa = aux; 174 bus_space_tag_t iot = &pcic_cbus_io_bst; 175 bus_space_tag_t memt = &pcic_cbus_mem_bst; 176 bus_space_handle_t ioh, memh; 177 bus_size_t msize; 178 int val, found; 179 180 if (strcmp(caa->ca_name, cf->cf_driver->cd_name) != 0) 181 return (0); 182 183 SET_TAG_LITTLE_ENDIAN(iot); 184 SET_TAG_LITTLE_ENDIAN(memt); 185 186 caa->ca_iobase = cf->cf_iobase; 187 caa->ca_maddr = cf->cf_maddr; 188 caa->ca_msize = cf->cf_msize; 189 caa->ca_int = cf->cf_int; 190 191 /* Disallow wildcarded i/o address. */ 192 if (caa->ca_iobase == -1) 193 return (0); 194 195 if (bus_space_map(iot, caa->ca_iobase, PCIC_IOSIZE, 0, &ioh)) 196 return (0); 197 198 if (caa->ca_msize == -1) 199 msize = PCIC_MEMSIZE; 200 if (bus_space_map(memt, caa->ca_maddr, msize, 0, &memh)) 201 return (0); 202 203 found = 0; 204 205 /* 206 * this could be done with a loop, but it would violate the 207 * abstraction 208 */ 209 210 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA + PCIC_IDENT); 211 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA); 212 if (pcic_ident_ok(val)) 213 found++; 214 215 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB + PCIC_IDENT); 216 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA); 217 if (pcic_ident_ok(val)) 218 found++; 219 220 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA + PCIC_IDENT); 221 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA); 222 if (pcic_ident_ok(val)) 223 found++; 224 225 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB + PCIC_IDENT); 226 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA); 227 if (pcic_ident_ok(val)) 228 found++; 229 230 bus_space_unmap(iot, ioh, PCIC_IOSIZE); 231 bus_space_unmap(memt, memh, msize); 232 233 if (!found) 234 return (0); 235 caa->ca_iosize = PCIC_IOSIZE; 236 caa->ca_msize = msize; 237 return (1); 238 } 239 240 void 241 pcic_cbus_attach(parent, self, aux) 242 struct device *parent, *self; 243 void *aux; 244 { 245 struct pcic_softc *sc = (void *)self; 246 struct pcic_handle *h; 247 struct cbus_attach_args *caa = aux; 248 bus_space_tag_t iot = &pcic_cbus_io_bst; 249 bus_space_tag_t memt = &pcic_cbus_mem_bst; 250 bus_space_handle_t ioh; 251 bus_space_handle_t memh; 252 int intlevel, irq, i, reg; 253 254 SET_TAG_LITTLE_ENDIAN(iot); 255 SET_TAG_LITTLE_ENDIAN(memt); 256 257 /* Map i/o space. */ 258 if (bus_space_map(iot, caa->ca_iobase, caa->ca_iosize, 0, &ioh)) { 259 printf(": can't map i/o space\n"); 260 return; 261 } 262 263 /* Map mem space. */ 264 if (bus_space_map(memt, caa->ca_maddr, caa->ca_msize, 0, &memh)) { 265 printf(": can't map mem space\n"); 266 return; 267 } 268 269 sc->membase = caa->ca_maddr; 270 sc->subregionmask = (1 << (caa->ca_msize / PCIC_MEM_PAGESIZE)) - 1; 271 272 sc->intr_est = NULL; /* not used on luna88k */ 273 sc->pct = (pcmcia_chipset_tag_t)&pcic_cbus_functions; 274 275 sc->iot = iot; 276 sc->ioh = ioh; 277 sc->memt = memt; 278 sc->memh = memh; 279 280 printf("\n"); 281 282 pcic_attach(sc); 283 284 sc->ranges = pcic_cbus_addr; 285 sc->iobase = 0x0000; 286 sc->iosize = 0x1000; 287 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx\n", 288 sc->dev.dv_xname, (long) sc->iobase, 289 (long) sc->iobase + sc->iosize)); 290 291 pcic_attach_sockets(sc); 292 293 /* 294 * Allocate an INT. It will be used by both controllers. We could 295 * use two different interrupts, but interrupts are relatively 296 * scarce, shareable, and for PCIC controllers, very infrequent. 297 */ 298 intlevel = pcic_cbus_intlevel_find(); 299 if (intlevel == -1) { 300 printf("pcic_cbus_attach: no free int found\n"); 301 return; 302 } 303 304 irq = pcic_cbus_int2irq[intlevel]; 305 cbus_isrlink(pcic_intr, sc, intlevel, IPL_TTY, sc->dev.dv_xname); 306 sc->ih = (void *)pcic_intr; 307 sc->irq = irq; 308 309 if (irq) { 310 printf("%s: int %d (irq %d), ", sc->dev.dv_xname, 311 intlevel, irq); 312 313 /* Set up the pcic to interrupt on card detect. */ 314 for (i = 0; i < PCIC_NSLOTS; i++) { 315 h = &sc->handle[i]; 316 if (h->flags & PCIC_FLAG_SOCKETP) { 317 /* set 'pulse management interrupt' mode */ 318 reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1); 319 reg |= PCIC_CIRRUS_MISC_CTL_1_PULSE_MGMT_INTR; 320 pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg); 321 322 pcic_write(h, PCIC_CSC_INTR, 323 (sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) | 324 PCIC_CSC_INTR_CD_ENABLE); 325 } 326 } 327 } else 328 printf("%s: no int, ", sc->dev.dv_xname); 329 330 printf("polling enabled\n"); 331 if (sc->poll_established == 0) { 332 timeout_set(&sc->poll_timeout, pcic_poll_intr, sc); 333 timeout_add_msec(&sc->poll_timeout, 500); 334 sc->poll_established = 1; 335 } 336 } 337 338 void * 339 pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t pch, 340 struct pcmcia_function *pf, int ipl, int (*fcl)(void *), 341 void *arg, char *xname) 342 { 343 struct pcic_handle *h = (struct pcic_handle *)pch; 344 #ifdef PCICCBUSDEBUG 345 struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent); 346 #endif 347 int intlevel, irq, reg; 348 349 #ifdef PCICCBUSDEBUG 350 char buf[16]; 351 if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL) 352 strlcpy(buf, "LEVEL", sizeof(buf)); 353 else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE) 354 strlcpy(buf, "PULSE", sizeof(buf)); 355 else 356 strlcpy(buf, "EDGE", sizeof(buf)); 357 printf("pcic_cbus_chip_intr_establish: IST_%s\n", buf); 358 #endif 359 360 /* 361 * If the PC Card has level-triggered interrupt property, 362 * we use CL-PD67XX 'pulse IRQ' feature. 363 */ 364 if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL) { 365 reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1); 366 reg |= PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ; 367 pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg); 368 } 369 370 intlevel = pcic_cbus_intlevel_find(); 371 372 if (intlevel == -1) { 373 printf("pcic_cbus_chip_intr_establish: no int found\n"); 374 return (NULL); 375 } 376 377 irq = pcic_cbus_int2irq[intlevel]; 378 h->ih_irq = irq; 379 380 DPRINTF(("%s: pcic_cbus_chip_intr_establish int %d (irq %d)\n", 381 sc->dev.dv_xname, intlevel, h->ih_irq)); 382 383 cbus_isrlink(fcl, arg, intlevel, ipl, h->pcmcia->dv_xname); 384 385 reg = pcic_read(h, PCIC_INTR); 386 reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE); 387 pcic_write(h, PCIC_INTR, reg | irq); 388 389 return (void *)fcl; 390 } 391 392 void 393 pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 394 { 395 struct pcic_handle *h = (struct pcic_handle *)pch; 396 #ifdef PCICCBUSDEBUG 397 struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent); 398 #endif 399 int intlevel, reg; 400 401 intlevel = pcic_cbus_irq2int[h->ih_irq]; 402 403 DPRINTF(("%s: pcic_cbus_chip_intr_disestablish int %d (irq %d)\n", 404 sc->dev.dv_xname, intlevel, h->ih_irq)); 405 406 if (intlevel == -1) { 407 printf("pcic_cbus_chip_intr_disestablish: " 408 "strange int (irq = %d)\n", h->ih_irq); 409 return; 410 } 411 412 h->ih_irq = 0; 413 414 reg = pcic_read(h, PCIC_INTR); 415 reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE); 416 pcic_write(h, PCIC_INTR, reg); 417 418 cbus_isrunlink(ih, intlevel); 419 420 /* reset the 'pulse IRQ' mode */ 421 reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1); 422 reg &= ~PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ; 423 pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg); 424 } 425 426 const char * 427 pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t pch, void *ih) 428 { 429 struct pcic_handle *h = (struct pcic_handle *)pch; 430 static char irqstr[64]; 431 432 if (ih == NULL) 433 snprintf(irqstr, sizeof(irqstr), 434 "couldn't establish interrupt"); 435 else 436 snprintf(irqstr, sizeof(irqstr), "int %d (irq %d)", 437 pcic_cbus_irq2int[h->ih_irq], h->ih_irq); 438 return(irqstr); 439 } 440 441 /* 442 * Find a free and pcic-compliant INT level; searching from highest 443 * (=small number) to lowest. 444 */ 445 int 446 pcic_cbus_intlevel_find(void) 447 { 448 int intlevel, irq; 449 u_int8_t cbus_not_used = ~cbus_intr_registered(); 450 451 for (intlevel = 0; intlevel < NCBUSISR; intlevel++) 452 if (cbus_not_used & (1 << (6 - intlevel))) { 453 irq = pcic_cbus_int2irq[intlevel]; 454 if ((1 << irq) & PCIC_INTR_IRQ_VALIDMASK) 455 break; 456 } 457 458 if (intlevel == NCBUSISR) 459 intlevel = -1; /* not found */ 460 461 return intlevel; 462 } 463 464 /* 465 * LUNA specific pcic_cbus_chip_io_{alloc,free} 466 */ 467 int 468 pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 469 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp) 470 { 471 struct pcic_handle *h = (struct pcic_handle *) pch; 472 bus_space_tag_t iot; 473 bus_space_handle_t ioh; 474 bus_addr_t ioaddr, beg, fin; 475 int flags = 0; 476 struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent); 477 struct pcic_ranges *range; 478 479 /* 480 * Allocate some arbitrary I/O space. 481 */ 482 483 iot = sc->iot; 484 485 if (start) { 486 ioaddr = start; 487 if (bus_space_map(iot, start, size, 0, &ioh)) 488 return (1); 489 DPRINTF(("pcic_cbus_chip_io_alloc map port %lx+%lx\n", 490 (u_long)ioaddr, (u_long)size)); 491 } else if (sc->ranges) { 492 /* 493 * In this case, we know the "size" and "align" that 494 * we want. So we need to start walking down 495 * sc->ranges, searching for a similar space that 496 * is (1) large enough for the size and alignment 497 * (2) then we need to try to allocate 498 * (3) if it fails to allocate, we try next range. 499 * 500 * We must also check that the start/size of each 501 * allocation we are about to do is within the bounds 502 * of "sc->iobase" and "sc->iosize". 503 * (Some pcmcia controllers handle a 12 bits of addressing, 504 * but we want to use the same range structure) 505 */ 506 for (range = sc->ranges; range->start; range++) { 507 /* Potentially trim the range because of bounds. */ 508 beg = max(range->start, sc->iobase); 509 fin = min(range->start + range->len, 510 sc->iobase + sc->iosize); 511 512 /* Short-circuit easy cases. */ 513 if (fin < beg || fin - beg < size) 514 continue; 515 516 DPRINTF(("pcic_cbus_chip_io_alloc beg-fin %lx-%lx\n", 517 (u_long)beg, (u_long)fin)); 518 if (bus_space_map(iot, beg, size, 0, &ioh) == 0) { 519 ioaddr = beg; 520 break; 521 } 522 } 523 if (range->start == 0) 524 return (1); 525 DPRINTF(("pcic_cbus_chip_io_alloc alloc port %lx+%lx\n", 526 (u_long)ioaddr, (u_long)size)); 527 } else { 528 if (bus_space_map(iot, sc->iobase, size, 0, &ioh)) 529 return (1); 530 ioaddr = sc->iobase; 531 DPRINTF(("pcic_cbus_chip_io_alloc alloc port %lx+%lx\n", 532 (u_long)ioaddr, (u_long)size)); 533 } 534 535 pcihp->iot = iot; 536 pcihp->ioh = ioh; 537 pcihp->addr = ioaddr; 538 pcihp->size = size; 539 pcihp->flags = flags; 540 541 return (0); 542 } 543 544 void 545 pcic_cbus_chip_io_free(pcmcia_chipset_handle_t pch, 546 struct pcmcia_io_handle *pcihp) 547 { 548 bus_space_tag_t iot = pcihp->iot; 549 bus_space_handle_t ioh = pcihp->ioh; 550 bus_size_t size = pcihp->size; 551 552 bus_space_unmap(iot, ioh, size); 553 } 554