xref: /openbsd-src/sys/dev/pci/agp_intel.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpentBSD: agp_intel.c,v 1.1 2001/10/25 21:44:00 thorpej Exp $	*/
2 /*	$NetBSD: agp_intel.c,v 1.3 2001/09/15 00:25:00 thorpej Exp $	*/
3 
4 /*-
5  * Copyright (c) 2000 Doug Rabson
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *	$FreeBSD: src/sys/pci/agp_intel.c,v 1.4 2001/07/05 21:28:47 jhb Exp $
30  */
31 
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/proc.h>
39 #include <sys/agpio.h>
40 #include <sys/device.h>
41 #include <sys/agpio.h>
42 
43 
44 #include <dev/pci/pcivar.h>
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/vga_pcivar.h>
47 #include <dev/pci/agpvar.h>
48 #include <dev/pci/agpreg.h>
49 
50 #include <machine/bus.h>
51 
52 struct agp_intel_softc {
53 	u_int32_t	initial_aperture; /* aperture size at startup */
54 	struct agp_gatt *gatt;
55 };
56 
57 
58 static u_int32_t agp_intel_get_aperture(struct vga_pci_softc *);
59 static int agp_intel_set_aperture(struct vga_pci_softc *, u_int32_t);
60 static int agp_intel_bind_page(struct vga_pci_softc *, off_t, bus_addr_t);
61 static int agp_intel_unbind_page(struct vga_pci_softc *, off_t);
62 static void agp_intel_flush_tlb(struct vga_pci_softc *);
63 
64 struct agp_methods agp_intel_methods = {
65 	agp_intel_get_aperture,
66 	agp_intel_set_aperture,
67 	agp_intel_bind_page,
68 	agp_intel_unbind_page,
69 	agp_intel_flush_tlb,
70 	agp_generic_enable,
71 	agp_generic_alloc_memory,
72 	agp_generic_free_memory,
73 	agp_generic_bind_memory,
74 	agp_generic_unbind_memory,
75 };
76 
77 int
78 agp_intel_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa,
79 		 struct pci_attach_args *pchb_pa)
80 {
81 	struct agp_intel_softc *isc;
82 	struct agp_gatt *gatt;
83 	pcireg_t reg;
84 
85 	isc = malloc(sizeof *isc, M_DEVBUF, M_NOWAIT);
86 	if (isc == NULL) {
87 		printf(": can't allocate chipset-specific softc\n");
88 		return (ENOMEM);
89 	}
90 	memset(isc, 0, sizeof *isc);
91 
92 	sc->sc_methods = &agp_intel_methods;
93 	sc->sc_chipc = isc;
94 
95 	if (agp_map_aperture(sc) != 0) {
96 		printf(": can't map aperture\n");
97 		free(isc, M_DEVBUF);
98 		sc->sc_chipc = NULL;
99 		return (ENXIO);
100 	}
101 
102 	isc->initial_aperture = AGP_GET_APERTURE(sc);
103 
104 	for (;;) {
105 		gatt = agp_alloc_gatt(sc);
106 		if (gatt)
107 			break;
108 
109 		/*
110 		 * Probably contigmalloc failure. Try reducing the
111 		 * aperture so that the gatt size reduces.
112 		 */
113 		if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) {
114 			agp_generic_detach(sc);
115 			printf(": failed to set aperture\n");
116 			return (ENOMEM);
117 		}
118 	}
119 	isc->gatt = gatt;
120 
121 	/* Install the gatt. */
122 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_ATTBASE,
123 	    gatt->ag_physical);
124 
125 	/* Enable things, clear errors etc. */
126 	/* XXXfvdl get rid of the magic constants */
127 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL, 0x2280);
128 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG);
129 	reg &= ~(1 << 10);
130 	reg |=	(1 << 9);
131 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG, reg);
132 
133 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_STS);
134 	reg &= ~0x00ff0000;
135 	reg |= (7 << 16);
136 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_STS, reg);
137 
138 	return (0);
139 }
140 
141 #if 0
142 static int
143 agp_intel_detach(struct vga_pci_softc *sc)
144 {
145 	int error;
146 	pcireg_t reg;
147 	struct agp_intel_softc *isc = sc->sc_chipc;
148 
149 	error = agp_generic_detach(sc);
150 	if (error)
151 		return (error);
152 
153 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG);
154 	reg &= ~(1 << 9);
155 	printf("%s: set NBXCFG to %x\n", __FUNCTION__, reg);
156 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG, reg);
157 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_ATTBASE, 0);
158 	AGP_SET_APERTURE(sc, isc->initial_aperture);
159 	agp_free_gatt(sc, isc->gatt);
160 
161 	return (0);
162 }
163 #endif
164 
165 static u_int32_t
166 agp_intel_get_aperture(struct vga_pci_softc *sc)
167 {
168 	u_int32_t apsize;
169 
170 	apsize = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
171 	    AGP_INTEL_APSIZE) & 0x1f;
172 
173 	/*
174 	 * The size is determined by the number of low bits of
175 	 * register APBASE which are forced to zero. The low 22 bits
176 	 * are always forced to zero and each zero bit in the apsize
177 	 * field just read forces the corresponding bit in the 27:22
178 	 * to be zero. We calculate the aperture size accordingly.
179 	 */
180 	return ((((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1);
181 }
182 
183 static int
184 agp_intel_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture)
185 {
186 	u_int32_t apsize;
187 	pcireg_t reg;
188 
189 	/*
190 	 * Reverse the magic from get_aperture.
191 	 */
192 	apsize = ((aperture - 1) >> 22) ^ 0x1f;
193 
194 	/*
195 	 * Double check for sanity.
196 	 */
197 	if ((((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1 != aperture)
198 		return (EINVAL);
199 
200 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE);
201 	reg = (reg & 0xffffff00) | apsize;
202 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE, reg);
203 
204 	return (0);
205 }
206 
207 static int
208 agp_intel_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical)
209 {
210 	struct agp_intel_softc *isc = sc->sc_chipc;
211 
212 	if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
213 		return (EINVAL);
214 
215 	isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17;
216 	return (0);
217 }
218 
219 static int
220 agp_intel_unbind_page(struct vga_pci_softc *sc, off_t offset)
221 {
222 	struct agp_intel_softc *isc = sc->sc_chipc;
223 
224 	if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
225 		return (EINVAL);
226 
227 	isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
228 	return (0);
229 }
230 
231 static void
232 agp_intel_flush_tlb(struct vga_pci_softc *sc)
233 {
234 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL, 0x2200);
235 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL, 0x2280);
236 }
237