1 /* $OpenBSD: piix.c,v 1.12 2023/01/30 10:49:05 jsg Exp $ */
2 /* $NetBSD: piix.c,v 1.1 1999/11/17 01:21:20 thorpej 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 Intel PIIX 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/piixreg.h>
74 #include <i386/pci/piixvar.h>
75
76 #ifdef PIIX_DEBUG
77 #define DPRINTF(arg) printf arg
78 #else
79 #define DPRINTF(arg)
80 #endif
81
82 int piix_getclink(pciintr_icu_handle_t, int, int *);
83 int piix_get_intr(pciintr_icu_handle_t, int, int *);
84 int piix_set_intr(pciintr_icu_handle_t, int, int);
85 #ifdef PIIX_DEBUG
86 void piix_pir_dump(struct piix_handle *);
87 #endif
88
89 const struct pciintr_icu piix_pci_icu = {
90 piix_getclink,
91 piix_get_intr,
92 piix_set_intr,
93 piix_get_trigger,
94 piix_set_trigger,
95 };
96
97 int
piix_init(pci_chipset_tag_t pc,bus_space_tag_t iot,pcitag_t tag,pciintr_icu_tag_t * ptagp,pciintr_icu_handle_t * phandp)98 piix_init(pci_chipset_tag_t pc, bus_space_tag_t iot, pcitag_t tag,
99 pciintr_icu_tag_t *ptagp, pciintr_icu_handle_t *phandp)
100 {
101 struct piix_handle *ph;
102
103 ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT);
104 if (ph == NULL)
105 return (1);
106
107 ph->ph_iot = iot;
108 ph->ph_pc = pc;
109 ph->ph_tag = tag;
110
111 if (bus_space_map(iot, PIIX_REG_ELCR, PIIX_REG_ELCR_SIZE, 0,
112 &ph->ph_elcr_ioh) != 0) {
113 free(ph, M_DEVBUF, sizeof *ph);
114 return (1);
115 }
116
117 #ifdef PIIX_DEBUG
118 piix_pir_dump(ph);
119 #endif
120 *ptagp = &piix_pci_icu;
121 *phandp = ph;
122 return (0);
123 }
124
125 int
piix_getclink(pciintr_icu_handle_t v,int link,int * clinkp)126 piix_getclink(pciintr_icu_handle_t v, int link, int *clinkp)
127 {
128 DPRINTF(("PIIX link value 0x%x: ", link));
129
130 /* Pattern 1: simple. */
131 if (PIIX_LEGAL_LINK(link - 1)) {
132 *clinkp = link - 1;
133 DPRINTF(("PIRQ %d (simple)\n", *clinkp));
134 return (0);
135 }
136
137 /* Pattern 2: configuration register offset */
138 if (link >= 0x60 && link <= 0x63) {
139 *clinkp = link - 0x60;
140 DPRINTF(("PIRQ %d (register offset)\n", *clinkp));
141 return (0);
142 }
143
144 /* Pattern 3: configuration register offset, PIRQE# - PIRQH# */
145 if (link >= 0x68 && link <= 0x6b) {
146 *clinkp = link - 0x64;
147 DPRINTF(("PIRQ %d (high register offset)\n", *clinkp));
148 return (0);
149 }
150
151 DPRINTF(("bogus IRQ selection source\n"));
152 return (1);
153 }
154
155 int
piix_get_intr(pciintr_icu_handle_t v,int clink,int * irqp)156 piix_get_intr(pciintr_icu_handle_t v, int clink, int *irqp)
157 {
158 struct piix_handle *ph = v;
159 int shift, off;
160 pcireg_t reg;
161
162 if (PIIX_LEGAL_LINK(clink) == 0)
163 return (1);
164
165 off = PIIX_CFG_PIRQ;
166 if (clink > 3) {
167 off += 8;
168 clink -= 4;
169 }
170
171 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, off);
172 shift = clink << 3;
173 if ((reg >> shift) & PIIX_CFG_PIRQ_NONE)
174 *irqp = I386_PCI_INTERRUPT_LINE_NO_CONNECTION;
175 else
176 *irqp = PIIX_PIRQ(reg, clink);
177
178 return (0);
179 }
180
181 int
piix_set_intr(pciintr_icu_handle_t v,int clink,int irq)182 piix_set_intr(pciintr_icu_handle_t v, int clink, int irq)
183 {
184 struct piix_handle *ph = v;
185 int shift, off;
186 pcireg_t reg;
187
188 if (PIIX_LEGAL_LINK(clink) == 0 || PIIX_LEGAL_IRQ(irq) == 0)
189 return (1);
190
191 off = PIIX_CFG_PIRQ;
192 if (clink > 3) {
193 off += 8;
194 clink -= 4;
195 }
196
197 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, off);
198 shift = clink << 3;
199 reg &= ~((PIIX_CFG_PIRQ_NONE | PIIX_CFG_PIRQ_MASK) << shift);
200 reg |= irq << shift;
201 pci_conf_write(ph->ph_pc, ph->ph_tag, off, reg);
202
203 return (0);
204 }
205
206 int
piix_get_trigger(pciintr_icu_handle_t v,int irq,int * triggerp)207 piix_get_trigger(pciintr_icu_handle_t v, int irq, int *triggerp)
208 {
209 struct piix_handle *ph = v;
210 int off, bit;
211 u_int8_t elcr;
212
213 if (PIIX_LEGAL_IRQ(irq) == 0)
214 return (1);
215
216 off = (irq > 7) ? 1 : 0;
217 bit = irq & 7;
218
219 elcr = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, off);
220 if (elcr & (1 << bit))
221 *triggerp = IST_LEVEL;
222 else
223 *triggerp = IST_EDGE;
224
225 return (0);
226 }
227
228 int
piix_set_trigger(pciintr_icu_handle_t v,int irq,int trigger)229 piix_set_trigger(pciintr_icu_handle_t v, int irq, int trigger)
230 {
231 struct piix_handle *ph = v;
232 int off, bit;
233 u_int8_t elcr;
234
235 if (PIIX_LEGAL_IRQ(irq) == 0)
236 return (1);
237
238 off = (irq > 7) ? 1 : 0;
239 bit = irq & 7;
240
241 elcr = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, off);
242 if (trigger == IST_LEVEL)
243 elcr |= (1 << bit);
244 else
245 elcr &= ~(1 << bit);
246 bus_space_write_1(ph->ph_iot, ph->ph_elcr_ioh, off, elcr);
247
248 return (0);
249 }
250
251 #ifdef PIIX_DEBUG
252 void
piix_pir_dump(struct piix_handle * ph)253 piix_pir_dump(struct piix_handle *ph)
254 {
255 int i, irq;
256 pcireg_t irqs = pci_conf_read(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ);
257 u_int8_t elcr[2];
258
259 elcr[0] = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, 0);
260 elcr[1] = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, 1);
261
262 for (i = 0; i < 8; i++) {
263 if (i == 4)
264 irqs = pci_conf_read(ph->ph_pc, ph->ph_tag,
265 PIIX_CFG_PIRQH);
266
267 irq = PIIX_PIRQ(irqs, i);
268 if (irq & PIIX_CFG_PIRQ_NONE)
269 printf("PIIX PIRQ %d: irq none (0x%x)\n", i, irq);
270 else
271 printf("PIIX PIRQ %d: irq %d\n", i, irq);
272 }
273
274 printf("PIIX irq:");
275 for (i = 0; i < 16; i++)
276 printf(" %2d", i);
277 printf("\n");
278 printf(" trigger:");
279 for (i = 0; i < 16; i++)
280 printf(" %c", (elcr[(i & 8) ? 1 : 0] & (1 << (i & 7))) ?
281 'L' : 'E');
282 printf("\n");
283 }
284 #endif /* PIIX_DEBUG */
285