1 /* $OpenBSD: opti82c700.c,v 1.8 2008/06/26 05:42:11 ray Exp $ */ 2 /* $NetBSD: opti82c700.c,v 1.2 2000/07/18 11:07:20 soda Exp $ */ 3 4 /*- 5 * Copyright (c) 1999 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1999, by UCHIYAMA Yasushi 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. The name of the developer may NOT be used to endorse or promote products 44 * derived from this software without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 */ 58 59 /* 60 * Support for the Opti 82c700 FireStar PCI-ISA bridge interrupt controller. 61 */ 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/device.h> 66 #include <sys/malloc.h> 67 68 #include <machine/intr.h> 69 #include <machine/bus.h> 70 71 #include <dev/pci/pcivar.h> 72 #include <dev/pci/pcireg.h> 73 #include <dev/pci/pcidevs.h> 74 75 #include <i386/pci/pcibiosvar.h> 76 #include <i386/pci/opti82c700reg.h> 77 78 #ifdef FIRESTARDEBUG 79 #define DPRINTF(arg) printf arg 80 #else 81 #define DPRINTF(arg) 82 #endif 83 84 int opti82c700_getclink(pciintr_icu_handle_t, int, int *); 85 int opti82c700_get_intr(pciintr_icu_handle_t, int, int *); 86 int opti82c700_set_intr(pciintr_icu_handle_t, int, int); 87 int opti82c700_get_trigger(pciintr_icu_handle_t, int, int *); 88 int opti82c700_set_trigger(pciintr_icu_handle_t, int, int); 89 90 const struct pciintr_icu opti82c700_pci_icu = { 91 opti82c700_getclink, 92 opti82c700_get_intr, 93 opti82c700_set_intr, 94 opti82c700_get_trigger, 95 opti82c700_set_trigger, 96 }; 97 98 struct opti82c700_handle { 99 pci_chipset_tag_t ph_pc; 100 pcitag_t ph_tag; 101 }; 102 103 int opti82c700_addr(int, int *, int *); 104 #ifdef FIRESTARDEBUG 105 void opti82c700_pir_dump(struct opti82c700_handle *); 106 #endif 107 108 int 109 opti82c700_init(pci_chipset_tag_t pc, bus_space_tag_t iot, pcitag_t tag, 110 pciintr_icu_tag_t *ptagp, pciintr_icu_handle_t *phandp) 111 { 112 struct opti82c700_handle *ph; 113 114 ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT); 115 if (ph == NULL) 116 return (1); 117 118 ph->ph_pc = pc; 119 ph->ph_tag = tag; 120 #ifdef FIRESTARDEBUG 121 opti82c700_pir_dump(ph); 122 #endif 123 *ptagp = &opti82c700_pci_icu; 124 *phandp = ph; 125 return (0); 126 } 127 128 int 129 opti82c700_addr(int link, int *addrofs, int *ofs) 130 { 131 int regofs, src; 132 133 regofs = FIRESTAR_PIR_REGOFS(link); 134 src = FIRESTAR_PIR_SELECTSRC(link); 135 136 switch (src) { 137 case FIRESTAR_PIR_SELECT_NONE: 138 return (1); 139 140 case FIRESTAR_PIR_SELECT_IRQ: 141 if (regofs < 0 || regofs > 7) 142 return (1); 143 *addrofs = FIRESTAR_CFG_INTR_IRQ + (regofs >> 2); 144 *ofs = (regofs & 3) << 3; 145 break; 146 147 case FIRESTAR_PIR_SELECT_PIRQ: 148 /* FALLTHROUGH */ 149 case FIRESTAR_PIR_SELECT_BRIDGE: 150 if (regofs < 0 || regofs > 3) 151 return (1); 152 *addrofs = FIRESTAR_CFG_INTR_PIRQ; 153 *ofs = regofs << 2; 154 break; 155 156 default: 157 return (1); 158 } 159 160 return (0); 161 } 162 163 int 164 opti82c700_getclink(pciintr_icu_handle_t v, int link, int *clinkp) 165 { 166 DPRINTF(("FireStar link value 0x%x: ", link)); 167 168 switch (FIRESTAR_PIR_SELECTSRC(link)) { 169 default: 170 DPRINTF(("bogus IRQ selection source\n")); 171 return (1); 172 case FIRESTAR_PIR_SELECT_NONE: 173 DPRINTF(("No interrupt connection\n")); 174 return (1); 175 case FIRESTAR_PIR_SELECT_IRQ: 176 DPRINTF(("FireStar IRQ pin")); 177 break; 178 case FIRESTAR_PIR_SELECT_PIRQ: 179 DPRINTF(("FireStar PIO pin or Serial IRQ PIRQ#")); 180 break; 181 case FIRESTAR_PIR_SELECT_BRIDGE: 182 DPRINTF(("FireBridge 1 INTx# pin")); 183 break; 184 } 185 186 DPRINTF((" REGOFST:%#x\n", FIRESTAR_PIR_REGOFS(link))); 187 *clinkp = link; 188 189 return (0); 190 } 191 192 int 193 opti82c700_get_intr(pciintr_icu_handle_t v, int clink, int *irqp) 194 { 195 struct opti82c700_handle *ph = v; 196 pcireg_t reg; 197 int val, addrofs, ofs; 198 199 if (opti82c700_addr(clink, &addrofs, &ofs)) 200 return (1); 201 202 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 203 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 204 205 *irqp = (val == FIRESTAR_PIRQ_NONE) ? 206 I386_PCI_INTERRUPT_LINE_NO_CONNECTION : val; 207 208 return (0); 209 } 210 211 int 212 opti82c700_set_intr(pciintr_icu_handle_t v, int clink, int irq) 213 { 214 struct opti82c700_handle *ph = v; 215 int addrofs, ofs; 216 pcireg_t reg; 217 218 if (FIRESTAR_LEGAL_IRQ(irq) == 0) 219 return (1); 220 221 if (opti82c700_addr(clink, &addrofs, &ofs)) 222 return (1); 223 224 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 225 reg &= ~(FIRESTAR_CFG_PIRQ_MASK << ofs); 226 reg |= (irq << ofs); 227 pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); 228 229 return (0); 230 } 231 232 int 233 opti82c700_get_trigger(pciintr_icu_handle_t v, int irq, int *triggerp) 234 { 235 struct opti82c700_handle *ph = v; 236 int i, val, addrofs, ofs; 237 pcireg_t reg; 238 239 if (FIRESTAR_LEGAL_IRQ(irq) == 0) { 240 /* ISA IRQ? */ 241 *triggerp = IST_EDGE; 242 return (0); 243 } 244 245 /* 246 * Search PCIDV1 registers. 247 */ 248 for (i = 0; i < 8; i++) { 249 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, 250 i), &addrofs, &ofs); 251 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 252 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 253 if (val != irq) 254 continue; 255 val = ((reg >> ofs) >> FIRESTAR_TRIGGER_SHIFT) & 256 FIRESTAR_TRIGGER_MASK; 257 *triggerp = val ? IST_LEVEL : IST_EDGE; 258 return (0); 259 } 260 261 /* 262 * Search PIO PCIIRQ. 263 */ 264 for (i = 0; i < 4; i++) { 265 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ, 266 i), &addrofs, &ofs); 267 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 268 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 269 if (val != irq) 270 continue; 271 *triggerp = IST_LEVEL; 272 return (0); 273 } 274 275 return (1); 276 } 277 278 int 279 opti82c700_set_trigger(pciintr_icu_handle_t v, int irq, int trigger) 280 { 281 struct opti82c700_handle *ph = v; 282 int i, val, addrofs, ofs; 283 pcireg_t reg; 284 285 if (FIRESTAR_LEGAL_IRQ(irq) == 0) { 286 /* ISA IRQ? */ 287 return ((trigger != IST_LEVEL) ? 0 : 1); 288 } 289 290 /* 291 * Search PCIDV1 registers. 292 */ 293 for (i = 0; i < 8; i++) { 294 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, 295 i), &addrofs, &ofs); 296 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 297 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 298 if (val != irq) 299 continue; 300 if (trigger == IST_LEVEL) 301 reg |= (FIRESTAR_TRIGGER_MASK << 302 (FIRESTAR_TRIGGER_SHIFT + ofs)); 303 else 304 reg &= ~(FIRESTAR_TRIGGER_MASK << 305 (FIRESTAR_TRIGGER_SHIFT + ofs)); 306 pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); 307 return (0); 308 } 309 310 /* 311 * Search PIO PCIIRQ. 312 */ 313 for (i = 0; i < 4; i++) { 314 opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ, 315 i), &addrofs, &ofs); 316 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); 317 val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; 318 if (val != irq) 319 continue; 320 return (trigger == IST_LEVEL ? 0 : 1); 321 } 322 323 return (1); 324 } 325