1 /* $NetBSD: opti82c700.c,v 1.3 2001/11/15 07:03:33 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 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) 1999, by UCHIYAMA Yasushi 42 * 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. The name of the developer may NOT be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /* 66 * Support for the Opti 82c700 FireStar PCI-ISA bridge interrupt controller. 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: opti82c700.c,v 1.3 2001/11/15 07:03:33 lukem Exp $"); 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/device.h> 75 #include <sys/malloc.h> 76 77 #include <machine/intr.h> 78 #include <machine/bus.h> 79 80 #include <dev/pci/pcivar.h> 81 #include <dev/pci/pcireg.h> 82 #include <dev/pci/pcidevs.h> 83 84 #include <i386/pci/pci_intr_fixup.h> 85 #include <i386/pci/opti82c700reg.h> 86 87 #ifdef FIRESTARDEBUG 88 #define DPRINTF(arg) printf arg 89 #else 90 #define DPRINTF(arg) 91 #endif 92 93 int opti82c700_getclink __P((pciintr_icu_handle_t, int, int *)); 94 int opti82c700_get_intr __P((pciintr_icu_handle_t, int, int *)); 95 int opti82c700_set_intr __P((pciintr_icu_handle_t, int, int)); 96 int opti82c700_get_trigger __P((pciintr_icu_handle_t, int, int *)); 97 int opti82c700_set_trigger __P((pciintr_icu_handle_t, int, int)); 98 99 const struct pciintr_icu opti82c700_pci_icu = { 100 opti82c700_getclink, 101 opti82c700_get_intr, 102 opti82c700_set_intr, 103 opti82c700_get_trigger, 104 opti82c700_set_trigger, 105 }; 106 107 struct opti82c700_handle { 108 pci_chipset_tag_t ph_pc; 109 pcitag_t ph_tag; 110 }; 111 112 int opti82c700_addr __P((int, int *, int *)); 113 #ifdef FIRESTARDEBUG 114 void opti82c700_pir_dump __P((struct opti82c700_handle *)); 115 #endif 116 117 int 118 opti82c700_init(pc, iot, tag, ptagp, phandp) 119 pci_chipset_tag_t pc; 120 bus_space_tag_t iot; 121 pcitag_t tag; 122 pciintr_icu_tag_t *ptagp; 123 pciintr_icu_handle_t *phandp; 124 { 125 struct opti82c700_handle *ph; 126 127 ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT); 128 if (ph == NULL) 129 return (1); 130 131 ph->ph_pc = pc; 132 ph->ph_tag = tag; 133 #ifdef FIRESTARDEBUG 134 opti82c700_pir_dump(ph); 135 #endif 136 *ptagp = &opti82c700_pci_icu; 137 *phandp = ph; 138 return (0); 139 } 140 141 int 142 opti82c700_addr(link, addrofs, ofs) 143 int link, *addrofs, *ofs; 144 { 145 int regofs, src; 146 147 regofs = FIRESTAR_PIR_REGOFS(link); 148 src = FIRESTAR_PIR_SELECTSRC(link); 149 150 switch (src) { 151 case FIRESTAR_PIR_SELECT_NONE: 152 return (1); 153 154 case FIRESTAR_PIR_SELECT_IRQ: 155 if (regofs < 0 || regofs > 7) 156 return (1); 157 *addrofs = FIRESTAR_CFG_INTR_IRQ + (regofs >> 2); 158 *ofs = (regofs & 3) << 3; 159 break; 160 161 case FIRESTAR_PIR_SELECT_PIRQ: 162 /* FALLTHROUGH */ 163 case FIRESTAR_PIR_SELECT_BRIDGE: 164 if (regofs < 0 || regofs > 3) 165 return (1); 166 *addrofs = FIRESTAR_CFG_INTR_PIRQ; 167 *ofs = regofs << 2; 168 break; 169 170 default: 171 return (1); 172 } 173 174 return (0); 175 } 176 177 int 178 opti82c700_getclink(v, link, clinkp) 179 pciintr_icu_handle_t v; 180 int link, *clinkp; 181 { 182 DPRINTF(("FireStar link value 0x%x: ", link)); 183 184 switch (FIRESTAR_PIR_SELECTSRC(link)) { 185 default: 186 DPRINTF(("bogus IRQ selection source\n")); 187 return (1); 188 case FIRESTAR_PIR_SELECT_NONE: 189 DPRINTF(("No interrupt connection\n")); 190 return (1); 191 case FIRESTAR_PIR_SELECT_IRQ: 192 DPRINTF(("FireStar IRQ pin")); 193 break; 194 case FIRESTAR_PIR_SELECT_PIRQ: 195 DPRINTF(("FireStar PIO pin or Serial IRQ PIRQ#")); 196 break; 197 case FIRESTAR_PIR_SELECT_BRIDGE: 198 DPRINTF(("FireBridge 1 INTx# pin")); 199 break; 200 } 201 202 DPRINTF((" REGOFST:%#x\n", FIRESTAR_PIR_REGOFS(link))); 203 *clinkp = link; 204 205 return (0); 206 } 207 208 int 209 opti82c700_get_intr(v, clink, irqp) 210 pciintr_icu_handle_t v; 211 int clink, *irqp; 212 { 213 struct opti82c700_handle *ph = v; 214 pcireg_t reg; 215 int val, addrofs, ofs; 216 217 if (opti82c700_addr(clink, &addrofs, &ofs)) 218 return (1); 219 220 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 221 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 222 223 *irqp = (val == FIRESTAR_PIRQ_NONE) ? 224 I386_PCI_INTERRUPT_LINE_NO_CONNECTION : val; 225 226 return (0); 227 } 228 229 int 230 opti82c700_set_intr(v, clink, irq) 231 pciintr_icu_handle_t v; 232 int clink, irq; 233 { 234 struct opti82c700_handle *ph = v; 235 int addrofs, ofs; 236 pcireg_t reg; 237 238 if (FIRESTAR_LEGAL_IRQ(irq) == 0) 239 return (1); 240 241 if (opti82c700_addr(clink, &addrofs, &ofs)) 242 return (1); 243 244 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 245 reg &= ~(FIRESTAR_CFG_PIRQ_MASK << ofs); 246 reg |= (irq << ofs); 247 pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); 248 249 return (0); 250 } 251 252 int 253 opti82c700_get_trigger(v, irq, triggerp) 254 pciintr_icu_handle_t v; 255 int irq, *triggerp; 256 { 257 struct opti82c700_handle *ph = v; 258 int i, val, addrofs, ofs; 259 pcireg_t reg; 260 261 if (FIRESTAR_LEGAL_IRQ(irq) == 0) { 262 /* ISA IRQ? */ 263 *triggerp = IST_EDGE; 264 return (0); 265 } 266 267 /* 268 * Search PCIDV1 registers. 269 */ 270 for (i = 0; i < 8; i++) { 271 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, 272 i), &addrofs, &ofs); 273 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 274 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 275 if (val != irq) 276 continue; 277 val = ((reg >> ofs) >> FIRESTAR_TRIGGER_SHIFT) & 278 FIRESTAR_TRIGGER_MASK; 279 *triggerp = val ? IST_LEVEL : IST_EDGE; 280 return (0); 281 } 282 283 /* 284 * Search PIO PCIIRQ. 285 */ 286 for (i = 0; i < 4; i++) { 287 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ, 288 i), &addrofs, &ofs); 289 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 290 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 291 if (val != irq) 292 continue; 293 *triggerp = IST_LEVEL; 294 return (0); 295 } 296 297 return (1); 298 } 299 300 int 301 opti82c700_set_trigger(v, irq, trigger) 302 pciintr_icu_handle_t v; 303 int irq, trigger; 304 { 305 struct opti82c700_handle *ph = v; 306 int i, val, addrofs, ofs; 307 pcireg_t reg; 308 309 if (FIRESTAR_LEGAL_IRQ(irq) == 0) { 310 /* ISA IRQ? */ 311 return ((trigger != IST_LEVEL) ? 0 : 1); 312 } 313 314 /* 315 * Search PCIDV1 registers. 316 */ 317 for (i = 0; i < 8; i++) { 318 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, 319 i), &addrofs, &ofs); 320 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 321 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 322 if (val != irq) 323 continue; 324 if (trigger == IST_LEVEL) 325 reg |= (FIRESTAR_TRIGGER_MASK << 326 (FIRESTAR_TRIGGER_SHIFT + ofs)); 327 else 328 reg &= ~(FIRESTAR_TRIGGER_MASK << 329 (FIRESTAR_TRIGGER_SHIFT + ofs)); 330 pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); 331 return (0); 332 } 333 334 /* 335 * Search PIO PCIIRQ. 336 */ 337 for (i = 0; i < 4; i++) { 338 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ, 339 i), &addrofs, &ofs); 340 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 341 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 342 if (val != irq) 343 continue; 344 return (trigger == IST_LEVEL ? 0 : 1); 345 } 346 347 return (1); 348 } 349 350 #ifdef FIRESTARDEBUG 351 void 352 opti82c700_pir_dump(ph) 353 struct opti82c700_handle *ph; 354 { 355 pcireg_t r; 356 pcitag_t tag = ph->ph_tag; 357 pci_chipset_tag_t pc = ph->ph_pc; 358 int i, j, k; 359 360 /* FireStar IRQ pin */ 361 printf("-FireStar IRQ pin-\n"); 362 for (i = j = k = 0; i < 8; i += 4) { 363 r = pci_conf_read(pc, tag, 0xb0 + i); 364 printf ("\t"); 365 for (j = 0; j < 4; j++, k++, r >>= 8) { 366 printf("[%d:%s-IRQ%2d] ", k, 367 (r & (FIRESTAR_TRIGGER_MASK << 368 FIRESTAR_TRIGGER_SHIFT)) ? "PCI" : "ISA", 369 r & FIRESTAR_CFG_PIRQ_MASK); 370 } 371 printf("\n"); 372 } 373 374 /* FireStar PIO pin or Serial IRQ PIRQ# */ 375 r = pci_conf_read(pc, tag, 0xb8); 376 printf("-FireStar PIO pin or Serial IRQ PIRQ#-\n\t"); 377 for (i = 0; i < 4; i++, r >>= 4) { 378 printf("[PCIIRQ%d# %d] ", i, r & FIRESTAR_CFG_PIRQ_MASK); 379 } 380 printf("\n"); 381 } 382 #endif /* FIRESTARDEBUG */ 383