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