1 /* $NetBSD: opti82c700.c,v 1.2 2000/07/18 11:07:20 soda 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/param.h> 70 #include <sys/systm.h> 71 #include <sys/device.h> 72 #include <sys/malloc.h> 73 74 #include <machine/intr.h> 75 #include <machine/bus.h> 76 77 #include <dev/pci/pcivar.h> 78 #include <dev/pci/pcireg.h> 79 #include <dev/pci/pcidevs.h> 80 81 #include <i386/pci/pci_intr_fixup.h> 82 #include <i386/pci/opti82c700reg.h> 83 84 #ifdef FIRESTARDEBUG 85 #define DPRINTF(arg) printf arg 86 #else 87 #define DPRINTF(arg) 88 #endif 89 90 int opti82c700_getclink __P((pciintr_icu_handle_t, int, int *)); 91 int opti82c700_get_intr __P((pciintr_icu_handle_t, int, int *)); 92 int opti82c700_set_intr __P((pciintr_icu_handle_t, int, int)); 93 int opti82c700_get_trigger __P((pciintr_icu_handle_t, int, int *)); 94 int opti82c700_set_trigger __P((pciintr_icu_handle_t, int, int)); 95 96 const struct pciintr_icu opti82c700_pci_icu = { 97 opti82c700_getclink, 98 opti82c700_get_intr, 99 opti82c700_set_intr, 100 opti82c700_get_trigger, 101 opti82c700_set_trigger, 102 }; 103 104 struct opti82c700_handle { 105 pci_chipset_tag_t ph_pc; 106 pcitag_t ph_tag; 107 }; 108 109 int opti82c700_addr __P((int, int *, int *)); 110 #ifdef FIRESTARDEBUG 111 void opti82c700_pir_dump __P((struct opti82c700_handle *)); 112 #endif 113 114 int 115 opti82c700_init(pc, iot, tag, ptagp, phandp) 116 pci_chipset_tag_t pc; 117 bus_space_tag_t iot; 118 pcitag_t tag; 119 pciintr_icu_tag_t *ptagp; 120 pciintr_icu_handle_t *phandp; 121 { 122 struct opti82c700_handle *ph; 123 124 ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT); 125 if (ph == NULL) 126 return (1); 127 128 ph->ph_pc = pc; 129 ph->ph_tag = tag; 130 #ifdef FIRESTARDEBUG 131 opti82c700_pir_dump(ph); 132 #endif 133 *ptagp = &opti82c700_pci_icu; 134 *phandp = ph; 135 return (0); 136 } 137 138 int 139 opti82c700_addr(link, addrofs, ofs) 140 int link, *addrofs, *ofs; 141 { 142 int regofs, src; 143 144 regofs = FIRESTAR_PIR_REGOFS(link); 145 src = FIRESTAR_PIR_SELECTSRC(link); 146 147 switch (src) { 148 case FIRESTAR_PIR_SELECT_NONE: 149 return (1); 150 151 case FIRESTAR_PIR_SELECT_IRQ: 152 if (regofs < 0 || regofs > 7) 153 return (1); 154 *addrofs = FIRESTAR_CFG_INTR_IRQ + (regofs >> 2); 155 *ofs = (regofs & 3) << 3; 156 break; 157 158 case FIRESTAR_PIR_SELECT_PIRQ: 159 /* FALLTHROUGH */ 160 case FIRESTAR_PIR_SELECT_BRIDGE: 161 if (regofs < 0 || regofs > 3) 162 return (1); 163 *addrofs = FIRESTAR_CFG_INTR_PIRQ; 164 *ofs = regofs << 2; 165 break; 166 167 default: 168 return (1); 169 } 170 171 return (0); 172 } 173 174 int 175 opti82c700_getclink(v, link, clinkp) 176 pciintr_icu_handle_t v; 177 int link, *clinkp; 178 { 179 DPRINTF(("FireStar link value 0x%x: ", link)); 180 181 switch (FIRESTAR_PIR_SELECTSRC(link)) { 182 default: 183 DPRINTF(("bogus IRQ selection source\n")); 184 return (1); 185 case FIRESTAR_PIR_SELECT_NONE: 186 DPRINTF(("No interrupt connection\n")); 187 return (1); 188 case FIRESTAR_PIR_SELECT_IRQ: 189 DPRINTF(("FireStar IRQ pin")); 190 break; 191 case FIRESTAR_PIR_SELECT_PIRQ: 192 DPRINTF(("FireStar PIO pin or Serial IRQ PIRQ#")); 193 break; 194 case FIRESTAR_PIR_SELECT_BRIDGE: 195 DPRINTF(("FireBridge 1 INTx# pin")); 196 break; 197 } 198 199 DPRINTF((" REGOFST:%#x\n", FIRESTAR_PIR_REGOFS(link))); 200 *clinkp = link; 201 202 return (0); 203 } 204 205 int 206 opti82c700_get_intr(v, clink, irqp) 207 pciintr_icu_handle_t v; 208 int clink, *irqp; 209 { 210 struct opti82c700_handle *ph = v; 211 pcireg_t reg; 212 int val, addrofs, ofs; 213 214 if (opti82c700_addr(clink, &addrofs, &ofs)) 215 return (1); 216 217 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 218 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 219 220 *irqp = (val == FIRESTAR_PIRQ_NONE) ? 221 I386_PCI_INTERRUPT_LINE_NO_CONNECTION : val; 222 223 return (0); 224 } 225 226 int 227 opti82c700_set_intr(v, clink, irq) 228 pciintr_icu_handle_t v; 229 int clink, irq; 230 { 231 struct opti82c700_handle *ph = v; 232 int addrofs, ofs; 233 pcireg_t reg; 234 235 if (FIRESTAR_LEGAL_IRQ(irq) == 0) 236 return (1); 237 238 if (opti82c700_addr(clink, &addrofs, &ofs)) 239 return (1); 240 241 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 242 reg &= ~(FIRESTAR_CFG_PIRQ_MASK << ofs); 243 reg |= (irq << ofs); 244 pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); 245 246 return (0); 247 } 248 249 int 250 opti82c700_get_trigger(v, irq, triggerp) 251 pciintr_icu_handle_t v; 252 int irq, *triggerp; 253 { 254 struct opti82c700_handle *ph = v; 255 int i, val, addrofs, ofs; 256 pcireg_t reg; 257 258 if (FIRESTAR_LEGAL_IRQ(irq) == 0) { 259 /* ISA IRQ? */ 260 *triggerp = IST_EDGE; 261 return (0); 262 } 263 264 /* 265 * Search PCIDV1 registers. 266 */ 267 for (i = 0; i < 8; i++) { 268 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, 269 i), &addrofs, &ofs); 270 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 271 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 272 if (val != irq) 273 continue; 274 val = ((reg >> ofs) >> FIRESTAR_TRIGGER_SHIFT) & 275 FIRESTAR_TRIGGER_MASK; 276 *triggerp = val ? IST_LEVEL : IST_EDGE; 277 return (0); 278 } 279 280 /* 281 * Search PIO PCIIRQ. 282 */ 283 for (i = 0; i < 4; i++) { 284 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ, 285 i), &addrofs, &ofs); 286 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 287 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 288 if (val != irq) 289 continue; 290 *triggerp = IST_LEVEL; 291 return (0); 292 } 293 294 return (1); 295 } 296 297 int 298 opti82c700_set_trigger(v, irq, trigger) 299 pciintr_icu_handle_t v; 300 int irq, trigger; 301 { 302 struct opti82c700_handle *ph = v; 303 int i, val, addrofs, ofs; 304 pcireg_t reg; 305 306 if (FIRESTAR_LEGAL_IRQ(irq) == 0) { 307 /* ISA IRQ? */ 308 return ((trigger != IST_LEVEL) ? 0 : 1); 309 } 310 311 /* 312 * Search PCIDV1 registers. 313 */ 314 for (i = 0; i < 8; i++) { 315 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, 316 i), &addrofs, &ofs); 317 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 318 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 319 if (val != irq) 320 continue; 321 if (trigger == IST_LEVEL) 322 reg |= (FIRESTAR_TRIGGER_MASK << 323 (FIRESTAR_TRIGGER_SHIFT + ofs)); 324 else 325 reg &= ~(FIRESTAR_TRIGGER_MASK << 326 (FIRESTAR_TRIGGER_SHIFT + ofs)); 327 pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); 328 return (0); 329 } 330 331 /* 332 * Search PIO PCIIRQ. 333 */ 334 for (i = 0; i < 4; i++) { 335 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ, 336 i), &addrofs, &ofs); 337 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 338 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 339 if (val != irq) 340 continue; 341 return (trigger == IST_LEVEL ? 0 : 1); 342 } 343 344 return (1); 345 } 346 347 #ifdef FIRESTARDEBUG 348 void 349 opti82c700_pir_dump(ph) 350 struct opti82c700_handle *ph; 351 { 352 pcireg_t r; 353 pcitag_t tag = ph->ph_tag; 354 pci_chipset_tag_t pc = ph->ph_pc; 355 int i, j, k; 356 357 /* FireStar IRQ pin */ 358 printf("-FireStar IRQ pin-\n"); 359 for (i = j = k = 0; i < 8; i += 4) { 360 r = pci_conf_read(pc, tag, 0xb0 + i); 361 printf ("\t"); 362 for (j = 0; j < 4; j++, k++, r >>= 8) { 363 printf("[%d:%s-IRQ%2d] ", k, 364 (r & (FIRESTAR_TRIGGER_MASK << 365 FIRESTAR_TRIGGER_SHIFT)) ? "PCI" : "ISA", 366 r & FIRESTAR_CFG_PIRQ_MASK); 367 } 368 printf("\n"); 369 } 370 371 /* FireStar PIO pin or Serial IRQ PIRQ# */ 372 r = pci_conf_read(pc, tag, 0xb8); 373 printf("-FireStar PIO pin or Serial IRQ PIRQ#-\n\t"); 374 for (i = 0; i < 4; i++, r >>= 4) { 375 printf("[PCIIRQ%d# %d] ", i, r & FIRESTAR_CFG_PIRQ_MASK); 376 } 377 printf("\n"); 378 } 379 #endif /* FIRESTARDEBUG */ 380