xref: /openbsd-src/sys/dev/pci/agp_intel.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: agp_intel.c,v 1.11 2008/09/02 10:29:34 jsg 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/pcidevs.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 	struct pci_attach_args 	vga_pa; /* vga card */
56 	u_int			aperture_mask;
57 	int			chiptype;
58 #define	CHIP_INTEL	0x0
59 #define	CHIP_I443	0x1
60 #define	CHIP_I840	0x2
61 #define	CHIP_I845	0x3
62 #define	CHIP_I850	0x4
63 #define	CHIP_I865	0x5
64 };
65 
66 
67 int	agp_intel_vgamatch(struct pci_attach_args *);
68 u_int32_t agp_intel_get_aperture(struct agp_softc *);
69 int	agp_intel_set_aperture(struct agp_softc *, u_int32_t);
70 int	agp_intel_bind_page(struct agp_softc *, off_t, bus_addr_t);
71 int	agp_intel_unbind_page(struct agp_softc *, off_t);
72 void	agp_intel_flush_tlb(struct agp_softc *);
73 
74 struct agp_methods agp_intel_methods = {
75 	agp_intel_get_aperture,
76 	agp_intel_set_aperture,
77 	agp_intel_bind_page,
78 	agp_intel_unbind_page,
79 	agp_intel_flush_tlb,
80 	agp_generic_enable,
81 	agp_generic_alloc_memory,
82 	agp_generic_free_memory,
83 	agp_generic_bind_memory,
84 	agp_generic_unbind_memory,
85 };
86 
87 int
88 agp_intel_vgamatch(struct pci_attach_args *pa)
89 {
90 	switch (PCI_PRODUCT(pa->pa_id)) {
91 	case PCI_PRODUCT_INTEL_82443LX_AGP:
92 	case PCI_PRODUCT_INTEL_82443BX_AGP:
93 	case PCI_PRODUCT_INTEL_82440BX_AGP:
94 	case PCI_PRODUCT_INTEL_82840_AGP:
95 	case PCI_PRODUCT_INTEL_82845_AGP:
96 	case PCI_PRODUCT_INTEL_82845G_AGP:
97 	case PCI_PRODUCT_INTEL_82850_AGP:	/* i850/i860 */
98 	case PCI_PRODUCT_INTEL_82855PM_AGP:
99 	case PCI_PRODUCT_INTEL_82865G_AGP:
100 	case PCI_PRODUCT_INTEL_82875P_AGP:
101 		return (1);
102 	}
103 
104 	return (0);
105 }
106 
107 int
108 agp_intel_attach(struct agp_softc *sc, struct pci_attach_args *pa)
109 {
110 	struct agp_intel_softc *isc;
111 	struct agp_gatt *gatt;
112 	pcireg_t reg;
113 	u_int32_t value;
114 
115 	isc = malloc(sizeof *isc, M_AGP, M_NOWAIT | M_ZERO);
116 	if (isc == NULL) {
117 		printf("can't allocate chipset-specific softc\n");
118 		return (ENOMEM);
119 	}
120 
121 	sc->sc_methods = &agp_intel_methods;
122 	sc->sc_chipc = isc;
123 
124 	if (pci_find_device(&isc->vga_pa, agp_intel_vgamatch) == 0)
125 		isc->chiptype = CHIP_INTEL;
126 
127 	pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, &sc->sc_capoff,
128 	    NULL);
129 
130 	if (agp_map_aperture(pa, sc, AGP_APBASE, PCI_MAPREG_TYPE_MEM) != 0) {
131 		printf("can't map aperture\n");
132 		free(isc, M_AGP);
133 		sc->sc_chipc = NULL;
134 		return (ENXIO);
135 	}
136 
137 	switch (PCI_PRODUCT(isc->vga_pa.pa_id)) {
138 	case PCI_PRODUCT_INTEL_82443LX_AGP:
139 	case PCI_PRODUCT_INTEL_82443BX_AGP:
140 	case PCI_PRODUCT_INTEL_82440BX_AGP:
141 		isc->chiptype = CHIP_I443;
142 		break;
143 	case PCI_PRODUCT_INTEL_82840_AGP:
144 		isc->chiptype = CHIP_I840;
145 		break;
146 	case PCI_PRODUCT_INTEL_82845_AGP:
147 	case PCI_PRODUCT_INTEL_82845G_AGP:
148 	case PCI_PRODUCT_INTEL_82855PM_AGP:
149 		isc->chiptype = CHIP_I845;
150 		break;
151 	case PCI_PRODUCT_INTEL_82850_AGP:
152 		isc->chiptype = CHIP_I850;
153 		break;
154 	case PCI_PRODUCT_INTEL_82865G_AGP:
155 	case PCI_PRODUCT_INTEL_82875P_AGP:
156 		isc->chiptype = CHIP_I865;
157 		break;
158 	}
159 
160 	/* Determine maximum supported aperture size. */
161 	value = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE);
162 	pci_conf_write(sc->sc_pc, sc->sc_pcitag,
163 		AGP_INTEL_APSIZE, APSIZE_MASK);
164 	isc->aperture_mask = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
165 		AGP_INTEL_APSIZE) & APSIZE_MASK;
166 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE, value);
167 	isc->initial_aperture = AGP_GET_APERTURE(sc);
168 
169 	for (;;) {
170 		gatt = agp_alloc_gatt(sc);
171 		if (gatt)
172 			break;
173 
174 		/*
175 		 * Probably contigmalloc failure. Try reducing the
176 		 * aperture so that the gatt size reduces.
177 		 */
178 		if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) {
179 			agp_generic_detach(sc);
180 			printf("failed to set aperture\n");
181 			return (ENOMEM);
182 		}
183 	}
184 	isc->gatt = gatt;
185 
186 	/* Install the gatt. */
187 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_ATTBASE,
188 	    gatt->ag_physical);
189 
190 	/* Enable the GLTB and setup the control register. */
191 	switch (isc->chiptype) {
192 	case CHIP_I443:
193 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL,
194 		    AGPCTRL_AGPRSE | AGPCTRL_GTLB);
195 		break;
196 	default:
197 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL,
198 		    pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL)
199 			| AGPCTRL_GTLB);
200 	}
201 
202 	/* Enable things, clear errors etc. */
203 	switch (isc->chiptype) {
204 	case CHIP_I845:
205 	case CHIP_I865:
206 		reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_I840_MCHCFG);
207 		reg |= MCHCFG_AAGN;
208 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_I840_MCHCFG, reg);
209 		break;
210 	case CHIP_I840:
211 	case CHIP_I850:
212 		reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCMD);
213 		reg |= AGPCMD_AGPEN;
214 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCMD,
215 		    reg);
216 		reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_I840_MCHCFG);
217 		reg |= MCHCFG_AAGN;
218 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_I840_MCHCFG,
219 		    reg);
220 		break;
221 	default:
222 		reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG);
223 		reg &= ~NBXCFG_APAE;
224 		reg |=  NBXCFG_AAGN;
225 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG, reg);
226 	}
227 
228 	/* Clear Error status */
229 	switch (isc->chiptype) {
230 	case CHIP_I840:
231 		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
232 		    AGP_INTEL_I8XX_ERRSTS, 0xc000);
233 		break;
234 	case CHIP_I845:
235 	case CHIP_I850:
236 	case CHIP_I865:
237 		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
238 		    AGP_INTEL_I8XX_ERRSTS, 0x00ff);
239 		break;
240 
241 	default:
242 		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
243 		    AGP_INTEL_ERRSTS, 0x70);
244 	}
245 
246 	return (0);
247 }
248 
249 #if 0
250 int
251 agp_intel_detach(struct agp_softc *sc)
252 {
253 	int error;
254 	pcireg_t reg;
255 	struct agp_intel_softc *isc = sc->sc_chipc;
256 
257 	error = agp_generic_detach(sc);
258 	if (error)
259 		return (error);
260 
261 	/* XXX i845/i855PM/i840/i850E */
262 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG);
263 	reg &= ~(1 << 9);
264 	printf("%s: set NBXCFG to %x\n", __FUNCTION__, reg);
265 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG, reg);
266 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_ATTBASE, 0);
267 	AGP_SET_APERTURE(sc, isc->initial_aperture);
268 	agp_free_gatt(sc, isc->gatt);
269 
270 	return (0);
271 }
272 #endif
273 
274 u_int32_t
275 agp_intel_get_aperture(struct agp_softc *sc)
276 {
277 	struct agp_intel_softc *isc = sc->sc_chipc;
278 	u_int32_t apsize;
279 
280 	apsize = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
281 	    AGP_INTEL_APSIZE) & isc->aperture_mask;
282 
283 	/*
284 	 * The size is determined by the number of low bits of
285 	 * register APBASE which are forced to zero. The low 22 bits
286 	 * are always forced to zero and each zero bit in the apsize
287 	 * field just read forces the corresponding bit in the 27:22
288 	 * to be zero. We calculate the aperture size accordingly.
289 	 */
290 	return ((((apsize ^ isc->aperture_mask) << 22) | ((1 << 22) - 1)) + 1);
291 }
292 
293 int
294 agp_intel_set_aperture(struct agp_softc *sc, u_int32_t aperture)
295 {
296 	struct agp_intel_softc *isc = sc->sc_chipc;
297 	u_int32_t apsize;
298 
299 	/*
300 	 * Reverse the magic from get_aperture.
301 	 */
302 	apsize = ((aperture - 1) >> 22) ^ isc->aperture_mask;
303 
304 	/*
305 	 * Double check for sanity.
306 	 */
307 	if ((((apsize ^ isc->aperture_mask) << 22) |
308 	    ((1 << 22) - 1)) + 1 != aperture)
309 		return (EINVAL);
310 
311 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE, apsize);
312 
313 	return (0);
314 }
315 
316 int
317 agp_intel_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
318 {
319 	struct agp_intel_softc *isc = sc->sc_chipc;
320 
321 	if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
322 		return (EINVAL);
323 
324 	isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17;
325 	return (0);
326 }
327 
328 int
329 agp_intel_unbind_page(struct agp_softc *sc, off_t offset)
330 {
331 	struct agp_intel_softc *isc = sc->sc_chipc;
332 
333 	if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
334 		return (EINVAL);
335 
336 	isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
337 	return (0);
338 }
339 
340 void
341 agp_intel_flush_tlb(struct agp_softc *sc)
342 {
343 	struct agp_intel_softc *isc = sc->sc_chipc;
344 	pcireg_t reg;
345 
346 	switch (isc->chiptype) {
347 	case CHIP_I865:
348 	case CHIP_I850:
349 	case CHIP_I845:
350 	case CHIP_I840:
351 	case CHIP_I443:
352 		reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL);
353 		reg &= ~AGPCTRL_GTLB;
354 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL,
355 		    reg);
356 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL,
357 		    reg | AGPCTRL_GTLB);
358 		break;
359 	default: /* XXX */
360 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL,
361 		    0x2200);
362 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL,
363 		    0x2280);
364 	}
365 }
366