1 /* $OpenBSD: i82365_isasubr.c,v 1.26 2021/03/07 06:17:03 jsg Exp $ */ 2 /* $NetBSD: i82365_isasubr.c,v 1.1 1998/06/07 18:28:31 sommerfe Exp $ */ 3 4 /* 5 * Copyright (c) 1998 Bill Sommerfeld. All rights reserved. 6 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Marc Horowitz. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/extent.h> 39 #include <sys/malloc.h> 40 41 #include <machine/bus.h> 42 #include <machine/intr.h> 43 44 #include <dev/isa/isareg.h> 45 #include <dev/isa/isavar.h> 46 47 #include <dev/pcmcia/pcmciareg.h> 48 #include <dev/pcmcia/pcmciavar.h> 49 #include <dev/pcmcia/pcmciachip.h> 50 51 #include <dev/ic/i82365reg.h> 52 #include <dev/ic/i82365var.h> 53 #include <dev/isa/i82365_isavar.h> 54 55 /***************************************************************************** 56 * Configurable parameters. 57 *****************************************************************************/ 58 59 /* 60 * Default I/O allocation range. If both are set to non-zero, these 61 * values will be used instead. Otherwise, the code attempts to probe 62 * the bus width. 63 */ 64 65 #ifndef PCIC_ISA_ALLOC_IOBASE 66 #define PCIC_ISA_ALLOC_IOBASE 0 67 #endif 68 69 #ifndef PCIC_ISA_ALLOC_IOSIZE 70 #define PCIC_ISA_ALLOC_IOSIZE 0 71 #endif 72 73 int pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE; 74 int pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE; 75 76 /* 77 * I am well aware that some of later irqs below are not for real, but there 78 * is a way to deal with that in the search loop. For beauty's sake I want 79 * this list to be a permutation of 0..15. 80 */ 81 char pcic_isa_intr_list[] = { 82 3, 4, 14, 9, 5, 12, 10, 11, 15, 13, 7, 1, 6, 2, 0, 8 83 }; 84 85 struct pcic_ranges pcic_isa_addr[] = { 86 { 0x340, 0x030 }, 87 { 0x300, 0x030 }, 88 { 0x390, 0x020 }, 89 { 0x400, 0xbff }, 90 { 0, 0 }, /* terminator */ 91 }; 92 93 94 /***************************************************************************** 95 * End of configurable parameters. 96 *****************************************************************************/ 97 98 #ifdef PCICISADEBUG 99 int pcicsubr_debug = 1 /* XXX */ ; 100 #define DPRINTF(arg) if (pcicsubr_debug) printf arg; 101 #else 102 #define DPRINTF(arg) 103 #endif 104 105 static int pcic_intr_seen; 106 107 void 108 pcic_isa_bus_width_probe(struct pcic_softc *sc, bus_space_tag_t iot, 109 bus_space_handle_t ioh, bus_addr_t base, u_int32_t length) 110 { 111 bus_space_handle_t ioh_high; 112 int i, iobuswidth, tmp1, tmp2; 113 114 /* 115 * figure out how wide the isa bus is. Do this by checking if the 116 * pcic controller is mirrored 0x400 above where we expect it to be. 117 * 118 * XXX some hardware doesn't seem to grok addresses in 0x400 119 * range-- apparently missing a bit or more of address lines. 120 * (e.g. CIRRUS_PD672X with Linksys EthernetCard ne2000 clone 121 * in TI TravelMate 5000 -- not clear which is at fault) 122 * 123 * Add a kludge to detect 10 bit wide buses and deal with them, 124 * and also a config file option to override the probe. 125 */ 126 iobuswidth = 12; 127 128 /* Map i/o space. */ 129 if (bus_space_map(iot, base + 0x400, length, 0, &ioh_high)) { 130 printf("%s: can't map high i/o space\n", sc->dev.dv_xname); 131 return; 132 } 133 134 for (i = 0; i < PCIC_NSLOTS; i++) { 135 if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) { 136 /* 137 * read the ident flags from the normal space and 138 * from the mirror, and compare them 139 */ 140 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, 141 sc->handle[i].sock + PCIC_IDENT); 142 tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA); 143 144 bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX, 145 sc->handle[i].sock + PCIC_IDENT); 146 tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA); 147 148 if (tmp1 == tmp2) 149 iobuswidth = 10; 150 } 151 } 152 153 bus_space_unmap(iot, ioh_high, length); 154 155 sc->ranges = pcic_isa_addr; 156 if (iobuswidth == 10) { 157 sc->iobase = 0x000; 158 sc->iosize = 0x400; 159 } else { 160 sc->iobase = 0x0000; 161 sc->iosize = 0x1000; 162 } 163 164 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (probed)\n", 165 sc->dev.dv_xname, (long) sc->iobase, 166 (long) sc->iobase + sc->iosize)); 167 168 if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) { 169 sc->iobase = pcic_isa_alloc_iobase; 170 sc->iosize = pcic_isa_alloc_iosize; 171 172 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx " 173 "(config override)\n", sc->dev.dv_xname, (long) sc->iobase, 174 (long) sc->iobase + sc->iosize)); 175 } 176 } 177 178 179 void * 180 pcic_isa_chip_intr_establish(pcmcia_chipset_handle_t pch, 181 struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg, 182 char *xname) 183 { 184 struct pcic_handle *h = (struct pcic_handle *)pch; 185 struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent); 186 isa_chipset_tag_t ic = sc->intr_est; 187 int irq, ist, reg; 188 189 if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL) 190 ist = IST_LEVEL; 191 else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE) 192 ist = IST_PULSE; 193 else 194 ist = IST_EDGE; 195 196 irq = pcic_intr_find(sc, ist); 197 if (!irq) 198 return (NULL); 199 200 h->ih_irq = irq; 201 reg = pcic_read(h, PCIC_INTR); 202 reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE); 203 pcic_write(h, PCIC_INTR, reg | irq); 204 205 return isa_intr_establish(ic, irq, ist, ipl, fct, arg, 206 h->pcmcia->dv_xname); 207 } 208 209 void 210 pcic_isa_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 211 { 212 struct pcic_handle *h = (struct pcic_handle *) pch; 213 struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent); 214 isa_chipset_tag_t ic = sc->intr_est; 215 int reg; 216 217 h->ih_irq = 0; 218 219 isa_intr_disestablish(ic, ih); 220 221 reg = pcic_read(h, PCIC_INTR); 222 reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE); 223 pcic_write(h, PCIC_INTR, reg); 224 } 225 226 const char * 227 pcic_isa_chip_intr_string(pcmcia_chipset_handle_t pch, void *ih) 228 { 229 struct pcic_handle *h = (struct pcic_handle *)pch; 230 static char irqstr[64]; 231 232 if (ih == NULL) 233 snprintf(irqstr, sizeof(irqstr), "couldn't establish interrupt"); 234 else 235 snprintf(irqstr, sizeof(irqstr), "irq %d", h->ih_irq); 236 return (irqstr); 237 } 238 239 int 240 pcic_intr_probe(void *v) 241 { 242 pcic_intr_seen = 1; 243 return (1); 244 } 245 246 /* 247 * Try to find a working interrupt, first by searching for a unique 248 * irq that is known to work, verified by tickling the pcic, then 249 * by searching for a shareable irq known to work. If the pcic does 250 * not allow tickling we then fallback to the same strategy but without 251 * tickling just assuming the first usable irq found works. 252 */ 253 int 254 pcic_intr_find(struct pcic_softc *sc, int ist) 255 { 256 struct pcic_handle *ph = &sc->handle[0]; 257 isa_chipset_tag_t ic = sc->intr_est; 258 int i, tickle, check, irq, chosen_irq = 0, csc_touched = 0; 259 void *ih; 260 u_int8_t saved_csc_intr; 261 262 /* 263 * First time, look for entirely free interrupts, last 264 * time accept shareable ones. 265 */ 266 for (tickle = 1; tickle >= 0; tickle--) { 267 if (tickle) 268 /* 269 * Remember card status change interrupt 270 * configuration. 271 */ 272 saved_csc_intr = pcic_read(ph, PCIC_CSC_INTR); 273 274 for (check = 2; check; check--) { 275 276 /* Walk over all possible interrupts. */ 277 for (i = 0; i < 16; i++) { 278 irq = pcic_isa_intr_list[i]; 279 280 if (((1 << irq) & 281 PCIC_CSC_INTR_IRQ_VALIDMASK) == 0) 282 continue; 283 284 if (isa_intr_check(ic, irq, ist) < check) 285 continue; 286 287 if (!tickle) { 288 chosen_irq = irq; 289 goto out; 290 } 291 292 /* 293 * Prepare for an interrupt tickle. 294 * As this can be called from an 295 * IPL_TTY context (the card status 296 * change interrupt) we need to do 297 * higher. 298 */ 299 ih = isa_intr_establish(ic, irq, ist, 300 IPL_VM | IPL_MPSAFE, pcic_intr_probe, 301 0, sc->dev.dv_xname); 302 if (ih == NULL) 303 continue; 304 pcic_intr_seen = 0; 305 pcic_write(ph, PCIC_CSC_INTR, 306 (saved_csc_intr & ~PCIC_CSC_INTR_IRQ_MASK) 307 | PCIC_CSC_INTR_CD_ENABLE 308 | (irq << PCIC_CSC_INTR_IRQ_SHIFT)); 309 csc_touched = 1; 310 311 /* Teehee, you tickle me! ;-) */ 312 pcic_write(ph, PCIC_CARD_DETECT, 313 pcic_read(ph, PCIC_CARD_DETECT) | 314 PCIC_CARD_DETECT_SW_INTR); 315 316 /* 317 * Delay for 10 ms and then shut the 318 * probe off. That should be plenty 319 * of time for the interrupt to be 320 * handled. 321 */ 322 delay(10000); 323 324 /* Acknowledge the interrupt. */ 325 pcic_read(ph, PCIC_CSC); 326 327 isa_intr_disestablish(ic, ih); 328 329 if (pcic_intr_seen) { 330 chosen_irq = irq; 331 goto out; 332 } 333 } 334 } 335 } 336 337 out: 338 if (csc_touched) 339 /* Restore card detection bit. */ 340 pcic_write(ph, PCIC_CSC_INTR, saved_csc_intr); 341 return (chosen_irq); 342 } 343