1 /* $OpenBSD: via82c586.c,v 1.9 2002/03/14 01:26:33 millert Exp $ */
2 /* $NetBSD: via82c586.c,v 1.2 2000/07/18 11:24:09 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 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*
42 * Copyright (c) 1999, by UCHIYAMA Yasushi
43 * All rights reserved.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. The name of the developer may NOT be used to endorse or promote products
51 * derived from this software without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 /*
67 * Support for the VIA 82c586 PCI-ISA bridge interrupt controller.
68 */
69
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/device.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/pcibiosvar.h>
82 #include <i386/pci/via82c586reg.h>
83 #include <i386/pci/piixvar.h>
84
85 int via82c586_getclink(pciintr_icu_handle_t, int, int *);
86 int via82c586_get_intr(pciintr_icu_handle_t, int, int *);
87 int via82c586_set_intr(pciintr_icu_handle_t, int, int);
88 int via82c586_get_trigger(pciintr_icu_handle_t, int, int *);
89 int via82c586_set_trigger(pciintr_icu_handle_t, int, int);
90
91 const struct pciintr_icu via82c586_pci_icu = {
92 via82c586_getclink,
93 via82c586_get_intr,
94 via82c586_set_intr,
95 via82c586_get_trigger,
96 via82c586_set_trigger,
97 };
98
99 const int vp3_cfg_trigger_shift[] = {
100 VP3_CFG_TRIGGER_SHIFT_PIRQA,
101 VP3_CFG_TRIGGER_SHIFT_PIRQB,
102 VP3_CFG_TRIGGER_SHIFT_PIRQC,
103 VP3_CFG_TRIGGER_SHIFT_PIRQD,
104 };
105
106 #define VP3_TRIGGER(reg, pirq) (((reg) >> vp3_cfg_trigger_shift[(pirq)]) & \
107 VP3_CFG_TRIGGER_MASK)
108
109 const int vp3_cfg_intr_shift[] = {
110 VP3_CFG_INTR_SHIFT_PIRQA,
111 VP3_CFG_INTR_SHIFT_PIRQB,
112 VP3_CFG_INTR_SHIFT_PIRQC,
113 VP3_CFG_INTR_SHIFT_PIRQD,
114 VP3_CFG_INTR_SHIFT_PIRQ0,
115 VP3_CFG_INTR_SHIFT_PIRQ1,
116 VP3_CFG_INTR_SHIFT_PIRQ2,
117 };
118
119 #define VP3_PIRQ(reg, pirq) (((reg) >> vp3_cfg_intr_shift[(pirq)]) & \
120 VP3_CFG_INTR_MASK)
121
122 int
via82c586_init(pc,iot,tag,ptagp,phandp)123 via82c586_init(pc, iot, tag, ptagp, phandp)
124 pci_chipset_tag_t pc;
125 bus_space_tag_t iot;
126 pcitag_t tag;
127 pciintr_icu_tag_t *ptagp;
128 pciintr_icu_handle_t *phandp;
129 {
130 pcireg_t reg;
131
132 if (piix_init(pc, iot, tag, ptagp, phandp) == 0) {
133 *ptagp = &via82c586_pci_icu;
134
135 /*
136 * Enable EISA ELCR.
137 */
138 reg = pci_conf_read(pc, tag, VP3_CFG_KBDMISCCTRL12_REG);
139 reg |= VP3_CFG_MISCCTRL2_EISA4D04D1PORT_ENABLE <<
140 VP3_CFG_MISCCTRL2_SHIFT;
141 pci_conf_write(pc, tag, VP3_CFG_KBDMISCCTRL12_REG, reg);
142
143 return (0);
144 }
145
146 return (1);
147 }
148
149 int
via82c586_getclink(v,link,clinkp)150 via82c586_getclink(v, link, clinkp)
151 pciintr_icu_handle_t v;
152 int link, *clinkp;
153 {
154
155 if (VP3_LEGAL_LINK(link - 1)) {
156 *clinkp = link - 1;
157 return (0);
158 }
159
160 return (1);
161 }
162
163 int
via82c586_get_intr(v,clink,irqp)164 via82c586_get_intr(v, clink, irqp)
165 pciintr_icu_handle_t v;
166 int clink, *irqp;
167 {
168 struct piix_handle *ph = v;
169 pcireg_t reg;
170 int val;
171
172 if (VP3_LEGAL_LINK(clink) == 0)
173 return (1);
174
175 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG);
176 val = VP3_PIRQ(reg, clink);
177 *irqp = (val == VP3_PIRQ_NONE)?
178 I386_PCI_INTERRUPT_LINE_NO_CONNECTION : val;
179
180 return (0);
181 }
182
183 int
via82c586_set_intr(v,clink,irq)184 via82c586_set_intr(v, clink, irq)
185 pciintr_icu_handle_t v;
186 int clink, irq;
187 {
188 struct piix_handle *ph = v;
189 int shift, val;
190 pcireg_t reg;
191
192 if (VP3_LEGAL_LINK(clink) == 0 || VP3_LEGAL_IRQ(irq) == 0)
193 return (1);
194
195 reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG);
196 via82c586_get_intr(v, clink, &val);
197 shift = vp3_cfg_intr_shift[clink];
198 reg &= ~(VP3_CFG_INTR_MASK << shift);
199 reg |= (irq << shift);
200 pci_conf_write(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG, reg);
201 if (via82c586_get_intr(v, clink, &val) != 0 ||
202 val != irq)
203 return (1);
204
205 return (0);
206 }
207
208 int
via82c586_get_trigger(v,irq,triggerp)209 via82c586_get_trigger(v, irq, triggerp)
210 pciintr_icu_handle_t v;
211 int irq, *triggerp;
212 {
213 struct piix_handle *ph = v;
214 int i, error, check_consistency, pciirq, pcitrigger = IST_NONE;
215 pcireg_t reg;
216
217 if (VP3_LEGAL_IRQ(irq) == 0)
218 return (1);
219
220 check_consistency = 0;
221 for (i = 0; i <= 3; i++) {
222 via82c586_get_intr(v, i, &pciirq);
223 if (pciirq == irq) {
224 reg = pci_conf_read(ph->ph_pc, ph->ph_tag,
225 VP3_CFG_PIRQ_REG);
226 if (VP3_TRIGGER(reg, i) == VP3_CFG_TRIGGER_EDGE)
227 pcitrigger = IST_EDGE;
228 else
229 pcitrigger = IST_LEVEL;
230 check_consistency = 1;
231 break;
232 }
233 }
234
235 error = piix_get_trigger(v, irq, triggerp);
236 if (error == 0 && check_consistency && pcitrigger != *triggerp)
237 return (1);
238 return (error);
239 }
240
241 int
via82c586_set_trigger(v,irq,trigger)242 via82c586_set_trigger(v, irq, trigger)
243 pciintr_icu_handle_t v;
244 int irq, trigger;
245 {
246 struct piix_handle *ph = v;
247 int i, pciirq, shift, testtrig;
248 pcireg_t reg;
249
250 if (VP3_LEGAL_IRQ(irq) == 0)
251 return (1);
252
253 for (i = 0; i <= 3; i++) {
254 via82c586_get_intr(v, i, &pciirq);
255 if (pciirq == irq) {
256 reg = pci_conf_read(ph->ph_pc, ph->ph_tag,
257 VP3_CFG_PIRQ_REG);
258 shift = vp3_cfg_trigger_shift[i];
259 /* XXX we only upgrade the trigger here */
260 if (trigger == IST_LEVEL)
261 reg &= ~(VP3_CFG_TRIGGER_MASK << shift);
262 pci_conf_write(ph->ph_pc, ph->ph_tag,
263 VP3_CFG_PIRQ_REG, reg);
264 break;
265 }
266 }
267
268 if (piix_set_trigger(v, irq, trigger) != 0 ||
269 via82c586_get_trigger(v, irq, &testtrig) != 0 ||
270 testtrig != trigger)
271 return (1);
272
273 return (0);
274 }
275