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