xref: /openbsd/sys/arch/i386/pci/opti82c700.c (revision f4e70637)
1 /*	$OpenBSD: opti82c700.c,v 1.9 2023/01/30 10:49:05 jsg 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/malloc.h>
66 
67 #include <machine/intr.h>
68 #include <machine/bus.h>
69 
70 #include <dev/pci/pcivar.h>
71 
72 #include <i386/pci/pcibiosvar.h>
73 #include <i386/pci/opti82c700reg.h>
74 
75 #ifdef FIRESTARDEBUG
76 #define	DPRINTF(arg)	printf arg
77 #else
78 #define	DPRINTF(arg)
79 #endif
80 
81 int	opti82c700_getclink(pciintr_icu_handle_t, int, int *);
82 int	opti82c700_get_intr(pciintr_icu_handle_t, int, int *);
83 int	opti82c700_set_intr(pciintr_icu_handle_t, int, int);
84 int	opti82c700_get_trigger(pciintr_icu_handle_t, int, int *);
85 int	opti82c700_set_trigger(pciintr_icu_handle_t, int, int);
86 
87 const struct pciintr_icu opti82c700_pci_icu = {
88 	opti82c700_getclink,
89 	opti82c700_get_intr,
90 	opti82c700_set_intr,
91 	opti82c700_get_trigger,
92 	opti82c700_set_trigger,
93 };
94 
95 struct opti82c700_handle {
96 	pci_chipset_tag_t ph_pc;
97 	pcitag_t ph_tag;
98 };
99 
100 int	opti82c700_addr(int, int *, int *);
101 #ifdef FIRESTARDEBUG
102 void	opti82c700_pir_dump(struct opti82c700_handle *);
103 #endif
104 
105 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)106 opti82c700_init(pci_chipset_tag_t pc, bus_space_tag_t iot, pcitag_t tag,
107     pciintr_icu_tag_t *ptagp, pciintr_icu_handle_t *phandp)
108 {
109 	struct opti82c700_handle *ph;
110 
111 	ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT);
112 	if (ph == NULL)
113 		return (1);
114 
115 	ph->ph_pc = pc;
116 	ph->ph_tag = tag;
117 #ifdef FIRESTARDEBUG
118 	opti82c700_pir_dump(ph);
119 #endif
120 	*ptagp = &opti82c700_pci_icu;
121 	*phandp = ph;
122 	return (0);
123 }
124 
125 int
opti82c700_addr(int link,int * addrofs,int * ofs)126 opti82c700_addr(int link, int *addrofs, int *ofs)
127 {
128 	int regofs, src;
129 
130 	regofs = FIRESTAR_PIR_REGOFS(link);
131 	src = FIRESTAR_PIR_SELECTSRC(link);
132 
133 	switch (src) {
134 	case FIRESTAR_PIR_SELECT_NONE:
135 		return (1);
136 
137 	case FIRESTAR_PIR_SELECT_IRQ:
138 		if (regofs < 0 || regofs > 7)
139 			return (1);
140 		*addrofs = FIRESTAR_CFG_INTR_IRQ + (regofs >> 2);
141 		*ofs = (regofs & 3) << 3;
142 		break;
143 
144 	case FIRESTAR_PIR_SELECT_PIRQ:
145 		/* FALLTHROUGH */
146 	case FIRESTAR_PIR_SELECT_BRIDGE:
147 		if (regofs < 0 || regofs > 3)
148 			return (1);
149 		*addrofs = FIRESTAR_CFG_INTR_PIRQ;
150 		*ofs = regofs << 2;
151 		break;
152 
153 	default:
154 		return (1);
155 	}
156 
157 	return (0);
158 }
159 
160 int
opti82c700_getclink(pciintr_icu_handle_t v,int link,int * clinkp)161 opti82c700_getclink(pciintr_icu_handle_t v, int link, int *clinkp)
162 {
163 	DPRINTF(("FireStar link value 0x%x: ", link));
164 
165 	switch (FIRESTAR_PIR_SELECTSRC(link)) {
166 	default:
167 		DPRINTF(("bogus IRQ selection source\n"));
168 		return (1);
169 	case FIRESTAR_PIR_SELECT_NONE:
170 		DPRINTF(("No interrupt connection\n"));
171 		return (1);
172 	case FIRESTAR_PIR_SELECT_IRQ:
173 		DPRINTF(("FireStar IRQ pin"));
174 		break;
175 	case FIRESTAR_PIR_SELECT_PIRQ:
176 		DPRINTF(("FireStar PIO pin or Serial IRQ PIRQ#"));
177 		break;
178 	case FIRESTAR_PIR_SELECT_BRIDGE:
179 		DPRINTF(("FireBridge 1 INTx# pin"));
180 		break;
181 	}
182 
183 	DPRINTF((" REGOFST:%#x\n", FIRESTAR_PIR_REGOFS(link)));
184 	*clinkp = link;
185 
186 	return (0);
187 }
188 
189 int
opti82c700_get_intr(pciintr_icu_handle_t v,int clink,int * irqp)190 opti82c700_get_intr(pciintr_icu_handle_t v, int clink, int *irqp)
191 {
192 	struct opti82c700_handle *ph = v;
193 	pcireg_t reg;
194 	int val, addrofs, ofs;
195 
196 	if (opti82c700_addr(clink, &addrofs, &ofs))
197 		return (1);
198 
199 	reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
200 	val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
201 
202 	*irqp = (val == FIRESTAR_PIRQ_NONE) ?
203 	    I386_PCI_INTERRUPT_LINE_NO_CONNECTION : val;
204 
205 	return (0);
206 }
207 
208 int
opti82c700_set_intr(pciintr_icu_handle_t v,int clink,int irq)209 opti82c700_set_intr(pciintr_icu_handle_t v, int clink, int irq)
210 {
211 	struct opti82c700_handle *ph = v;
212 	int addrofs, ofs;
213 	pcireg_t reg;
214 
215 	if (FIRESTAR_LEGAL_IRQ(irq) == 0)
216 		return (1);
217 
218 	if (opti82c700_addr(clink, &addrofs, &ofs))
219 		return (1);
220 
221 	reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
222 	reg &= ~(FIRESTAR_CFG_PIRQ_MASK << ofs);
223 	reg |= (irq << ofs);
224 	pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg);
225 
226 	return (0);
227 }
228 
229 int
opti82c700_get_trigger(pciintr_icu_handle_t v,int irq,int * triggerp)230 opti82c700_get_trigger(pciintr_icu_handle_t v, int irq, int *triggerp)
231 {
232 	struct opti82c700_handle *ph = v;
233 	int i, val, addrofs, ofs;
234 	pcireg_t reg;
235 
236 	if (FIRESTAR_LEGAL_IRQ(irq) == 0) {
237 		/* ISA IRQ? */
238 		*triggerp = IST_EDGE;
239 		return (0);
240 	}
241 
242 	/*
243 	 * Search PCIDV1 registers.
244 	 */
245 	for (i = 0; i < 8; i++) {
246 		opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ,
247 		    i), &addrofs, &ofs);
248 		reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
249 		val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
250 		if (val != irq)
251 			continue;
252 		val = ((reg >> ofs) >> FIRESTAR_TRIGGER_SHIFT) &
253 		    FIRESTAR_TRIGGER_MASK;
254 		*triggerp = val ? IST_LEVEL : IST_EDGE;
255 		return (0);
256 	}
257 
258 	/*
259 	 * Search PIO PCIIRQ.
260 	 */
261 	for (i = 0; i < 4; i++) {
262 		opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ,
263 		    i), &addrofs, &ofs);
264 		reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
265 		val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
266 		if (val != irq)
267 			continue;
268 		*triggerp = IST_LEVEL;
269 		return (0);
270 	}
271 
272 	return (1);
273 }
274 
275 int
opti82c700_set_trigger(pciintr_icu_handle_t v,int irq,int trigger)276 opti82c700_set_trigger(pciintr_icu_handle_t v, int irq, int trigger)
277 {
278 	struct opti82c700_handle *ph = v;
279 	int i, val, addrofs, ofs;
280 	pcireg_t reg;
281 
282 	if (FIRESTAR_LEGAL_IRQ(irq) == 0) {
283 		/* ISA IRQ? */
284 		return ((trigger != IST_LEVEL) ? 0 : 1);
285 	}
286 
287 	/*
288 	 * Search PCIDV1 registers.
289 	 */
290 	for (i = 0; i < 8; i++) {
291 		opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ,
292 		    i), &addrofs, &ofs);
293 		reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
294 		val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
295 		if (val != irq)
296 			continue;
297 		if (trigger == IST_LEVEL)
298 			reg |= (FIRESTAR_TRIGGER_MASK <<
299 			    (FIRESTAR_TRIGGER_SHIFT + ofs));
300 		else
301 			reg &= ~(FIRESTAR_TRIGGER_MASK <<
302 			    (FIRESTAR_TRIGGER_SHIFT + ofs));
303 		pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg);
304 		return (0);
305 	}
306 
307 	/*
308 	 * Search PIO PCIIRQ.
309 	 */
310 	for (i = 0; i < 4; i++) {
311 		opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_PIRQ,
312 		    i), &addrofs, &ofs);
313 		reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
314 		val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
315 		if (val != irq)
316 			continue;
317 		return (trigger == IST_LEVEL ? 0 : 1);
318 	}
319 
320 	return (1);
321 }
322