xref: /netbsd-src/sys/arch/i386/pci/opti82c700.c (revision f5b064ee385650bff4906d7abf18d635e842b8ee)
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
opti82c700_init(pci_chipset_tag_t pc,bus_space_tag_t iot,pcitag_t tag,pciintr_icu_tag_t * ptagp,pciintr_icu_handle_t * phandp)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
opti82c700_addr(int link,int * addrofs,int * ofs)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
opti82c700_getclink(pciintr_icu_handle_t v,int link,int * clinkp)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
opti82c700_get_intr(pciintr_icu_handle_t v,int clink,int * irqp)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
opti82c700_set_intr(pciintr_icu_handle_t v,int clink,int irq)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
opti82c700_get_trigger(pciintr_icu_handle_t v,int irq,int * triggerp)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
opti82c700_set_trigger(pciintr_icu_handle_t v,int irq,int trigger)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
opti82c700_pir_dump(struct opti82c700_handle * ph)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