xref: /netbsd-src/sys/arch/i386/pci/opti82c700.c (revision 06be8101a16cc95f40783b3cb7afd12112103a9a)
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