1/*	$NetBSD: amd756.c,v 1.8 2008/04/28 20:23:24 martin Exp $	*/
2
3/*-
4 * Copyright (c) 1999, 2001 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 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1999, by UCHIYAMA Yasushi
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. The name of the developer may NOT be used to endorse or promote products
43 *    derived from this software without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58/*
59 * Support for the Advanced Micro Devices AMD756 Peripheral Bus Controller.
60 */
61
62#include <sys/cdefs.h>
63__KERNEL_RCSID(0, "$NetBSD: amd756.c,v 1.8 2008/04/28 20:23:24 martin Exp $");
64
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/device.h>
68#include <sys/malloc.h>
69
70#include <machine/intr.h>
71#include <sys/bus.h>
72
73#include <dev/pci/pcivar.h>
74#include <dev/pci/pcireg.h>
75#include <dev/pci/pcidevs.h>
76
77#include <i386/pci/pci_intr_fixup.h>
78#include <i386/pci/amd756reg.h>
79
80struct amd756_handle {
81	bus_space_tag_t ph_iot;
82	bus_space_handle_t ph_regs_ioh;
83	pci_chipset_tag_t ph_pc;
84	pcitag_t ph_tag;
85};
86
87int	amd756_getclink(pciintr_icu_handle_t, int, int *);
88int	amd756_get_intr(pciintr_icu_handle_t, int, int *);
89int	amd756_set_intr(pciintr_icu_handle_t, int, int);
90int	amd756_get_trigger(pciintr_icu_handle_t, int, int *);
91int	amd756_set_trigger(pciintr_icu_handle_t, int, int);
92#ifdef AMD756_DEBUG
93static void	amd756_pir_dump(struct amd756_handle *);
94#endif
95
96const struct pciintr_icu amd756_pci_icu = {
97	amd756_getclink,
98	amd756_get_intr,
99	amd756_set_intr,
100	amd756_get_trigger,
101	amd756_set_trigger,
102};
103
104
105int
106amd756_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 amd756_handle *ph;
110
111	ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT);
112	if (ph == NULL)
113		return (1);
114
115	ph->ph_iot = iot;
116	ph->ph_pc = pc;
117	ph->ph_tag = tag;
118
119	*ptagp = &amd756_pci_icu;
120	*phandp = ph;
121
122#ifdef AMD756_DEBUG
123	amd756_pir_dump(ph);
124#endif
125
126	return (0);
127}
128
129int
130amd756_getclink(pciintr_icu_handle_t v, int link, int *clinkp)
131{
132	if (AMD756_LEGAL_LINK(link - 1) == 0)
133		return (1);
134
135	*clinkp = link - 1;
136
137	return (0);
138}
139
140int
141amd756_get_intr(pciintr_icu_handle_t v, int clink, int *irqp)
142{
143	struct amd756_handle *ph = v;
144	pcireg_t reg;
145	int val;
146
147	if (AMD756_LEGAL_LINK(clink) == 0)
148		return (1);
149
150	reg = AMD756_GET_PIIRQSEL(ph);
151	val = (reg >> (4 * clink)) & 0x0f;
152	*irqp = (val == 0) ?
153	    X86_PCI_INTERRUPT_LINE_NO_CONNECTION : val;
154
155	return (0);
156}
157
158int
159amd756_set_intr(pciintr_icu_handle_t v, int clink, int irq)
160{
161	struct amd756_handle *ph = v;
162	int val;
163	pcireg_t reg;
164
165	if (AMD756_LEGAL_LINK(clink) == 0 || AMD756_LEGAL_IRQ(irq) == 0)
166		return (1);
167
168	reg = AMD756_GET_PIIRQSEL(ph);
169	amd756_get_intr(v, clink, &val);
170	reg &= ~(0x000f << (4 * clink));
171	reg |= irq << (4 * clink);
172	AMD756_SET_PIIRQSEL(ph, reg);
173
174	return (0);
175}
176
177int
178amd756_get_trigger(pciintr_icu_handle_t v, int irq, int *triggerp)
179{
180	struct amd756_handle *ph = v;
181	int i, pciirq;
182	pcireg_t reg;
183
184	if (AMD756_LEGAL_IRQ(irq) == 0)
185		return (1);
186
187	for (i = 0; i <= 3; i++) {
188		amd756_get_intr(v, i, &pciirq);
189		if (pciirq == irq) {
190			reg = AMD756_GET_EDGESEL(ph);
191			if (reg & (1 << i))
192				*triggerp = IST_EDGE;
193			else
194				*triggerp = IST_LEVEL;
195			break;
196		}
197	}
198
199	return (0);
200}
201
202int
203amd756_set_trigger(pciintr_icu_handle_t v, int irq, int trigger)
204{
205	struct amd756_handle *ph = v;
206	int i, pciirq;
207	pcireg_t reg;
208
209	if (AMD756_LEGAL_IRQ(irq) == 0)
210		return (1);
211
212	for (i = 0; i <= 3; i++) {
213		amd756_get_intr(v, i, &pciirq);
214		if (pciirq == irq) {
215			reg = AMD756_GET_PIIRQSEL(ph);
216			if (trigger == IST_LEVEL)
217				reg &= ~(1 << (4 * i));
218			else
219				reg |= 1 << (4 * i);
220			AMD756_SET_PIIRQSEL(ph, reg);
221			break;
222		}
223	}
224
225	return (0);
226}
227
228#ifdef AMD756_DEBUG
229static void
230amd756_pir_dump(struct amd756_handle *ph)
231{
232	int a, b;
233
234	printf ("AMD756 PCI INTERRUPT ROUTING REGISTERS:\n");
235
236	a = AMD756_GET_EDGESEL(ph);
237	b = AMD756_GET_PIIRQSEL(ph);
238
239	printf ("TRIGGER: %02x, ROUTING: %04x\n", a, b);
240}
241#endif
242