xref: /openbsd-src/sys/dev/pci/agp_intel.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: agp_intel.c,v 1.12 2008/11/09 15:11:19 oga 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 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/proc.h>
38 #include <sys/agpio.h>
39 #include <sys/device.h>
40 #include <sys/agpio.h>
41 
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/agpvar.h>
46 #include <dev/pci/agpreg.h>
47 
48 #include <machine/bus.h>
49 
50 struct agp_intel_softc {
51 	struct device		 dev;
52 	struct agp_softc	*agpdev;
53 	struct agp_gatt 	*gatt;
54 	pci_chipset_tag_t	 isc_pc;
55 	pcitag_t		 isc_tag;
56 	u_int			 aperture_mask;
57 	enum {
58 		CHIP_INTEL,
59 		CHIP_I443,
60 		CHIP_I840,
61 		CHIP_I845,
62 		CHIP_I850,
63 		CHIP_I865
64 	}			 chiptype;
65 	bus_size_t		 initial_aperture; /* startup aperture size */
66 };
67 
68 
69 void	agp_intel_attach(struct device *, struct device *, void *);
70 int	agp_intel_probe(struct device *, void *, void *);
71 bus_size_t agp_intel_get_aperture(void *);
72 int	agp_intel_set_aperture(void *, bus_size_t);
73 int	agp_intel_bind_page(void *, off_t, bus_addr_t);
74 int	agp_intel_unbind_page(void *, off_t);
75 void	agp_intel_flush_tlb(void *);
76 
77 struct cfattach intelagp_ca = {
78 	sizeof(struct agp_intel_softc), agp_intel_probe, agp_intel_attach
79 };
80 
81 struct cfdriver intelagp_cd = {
82 	NULL, "intelagp", DV_DULL
83 };
84 
85 const struct agp_methods agp_intel_methods = {
86 	agp_intel_get_aperture,
87 	agp_intel_bind_page,
88 	agp_intel_unbind_page,
89 	agp_intel_flush_tlb,
90 	/* default enable and memory routines */
91 };
92 
93 int
94 agp_intel_probe(struct device *parent, void *match, void *aux)
95 {
96 	struct agp_attach_args	*aa = aux;
97 	struct pci_attach_args	*pa = aa->aa_pa;
98 
99 	/* Must be a pchb */
100 	if (agpbus_probe(aa) == 0)
101 		return (0);
102 
103 	switch (PCI_PRODUCT(pa->pa_id)) {
104 	case PCI_PRODUCT_INTEL_82443LX:
105 	case PCI_PRODUCT_INTEL_82443BX:
106 	case PCI_PRODUCT_INTEL_82440BX:
107 	case PCI_PRODUCT_INTEL_82440BX_AGP:
108 	case PCI_PRODUCT_INTEL_82815_HB:
109 	case PCI_PRODUCT_INTEL_82820_HB:
110 	case PCI_PRODUCT_INTEL_82830M_HB:
111 	case PCI_PRODUCT_INTEL_82840_HB:
112 	case PCI_PRODUCT_INTEL_82845_HB:
113 	case PCI_PRODUCT_INTEL_82845G_HB:
114 	case PCI_PRODUCT_INTEL_82850_HB:
115 	case PCI_PRODUCT_INTEL_82855PM_HB:
116 	case PCI_PRODUCT_INTEL_82855GM_HB:
117 	case PCI_PRODUCT_INTEL_82860_HB:
118 	case PCI_PRODUCT_INTEL_82865G_HB:
119 	case PCI_PRODUCT_INTEL_82875P_HB:
120 		return (1);
121 	}
122 
123 	return (0);
124 }
125 
126 void
127 agp_intel_attach(struct device *parent, struct device *self, void *aux)
128 {
129 	struct agp_intel_softc	*isc = (struct agp_intel_softc *)self;
130 	struct agp_attach_args	*aa = aux;
131 	struct pci_attach_args	*pa = aa->aa_pa;
132 	struct agp_gatt		*gatt;
133 	pcireg_t		 reg;
134 	u_int32_t		 value;
135 
136 	isc->isc_pc = pa->pa_pc;
137 	isc->isc_tag = pa->pa_tag;
138 
139 	switch (PCI_PRODUCT(pa->pa_id)) {
140 	case PCI_PRODUCT_INTEL_82443LX:
141 	case PCI_PRODUCT_INTEL_82443BX:
142 	case PCI_PRODUCT_INTEL_82440BX:
143 	case PCI_PRODUCT_INTEL_82440BX_AGP:
144 		isc->chiptype = CHIP_I443;
145 		break;
146 	case PCI_PRODUCT_INTEL_82830M_HB:
147 	case PCI_PRODUCT_INTEL_82840_HB:
148 		isc->chiptype = CHIP_I840;
149 		break;
150 	case PCI_PRODUCT_INTEL_82845_HB:
151 	case PCI_PRODUCT_INTEL_82845G_HB:
152 	case PCI_PRODUCT_INTEL_82855PM_HB:
153 		isc->chiptype = CHIP_I845;
154 		break;
155 	case PCI_PRODUCT_INTEL_82850_HB:
156 		isc->chiptype = CHIP_I850;
157 		break;
158 	case PCI_PRODUCT_INTEL_82865G_HB:
159 	case PCI_PRODUCT_INTEL_82875P_HB:
160 		isc->chiptype = CHIP_I865;
161 		break;
162 	default:
163 		isc->chiptype = CHIP_INTEL;
164 	}
165 
166 	/* Determine maximum supported aperture size. */
167 	value = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE);
168 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, APSIZE_MASK);
169 	isc->aperture_mask = pci_conf_read(pa->pa_pc, pa->pa_tag,
170 		AGP_INTEL_APSIZE) & APSIZE_MASK;
171 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, value);
172 	isc->initial_aperture = agp_intel_get_aperture(isc);
173 
174 	for (;;) {
175 		bus_size_t size = agp_intel_get_aperture(isc);
176 		gatt = agp_alloc_gatt(pa->pa_dmat, size);
177 		if (gatt != NULL)
178 			break;
179 
180 		/*
181 		 * almost certainly error allocating contigious dma memory
182 		 * so reduce aperture so that the gatt size reduces.
183 		 */
184 		if (agp_intel_set_aperture(isc, size / 2)) {
185 			printf(": failed to set aperture\n");
186 			return;
187 		}
188 	}
189 	isc->gatt = gatt;
190 
191 	/* Install the gatt. */
192 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ATTBASE,
193 	    gatt->ag_physical);
194 
195 	/* Enable the GLTB and setup the control register. */
196 	switch (isc->chiptype) {
197 	case CHIP_I443:
198 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
199 		    AGPCTRL_AGPRSE | AGPCTRL_GTLB);
200 		break;
201 	default:
202 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
203 		    pci_conf_read(isc->isc_pc, isc->isc_tag,
204 		    AGP_INTEL_AGPCTRL) | AGPCTRL_GTLB);
205 	}
206 
207 	/* Enable things, clear errors etc. */
208 	switch (isc->chiptype) {
209 	case CHIP_I845:
210 	case CHIP_I865:
211 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG);
212 		reg |= MCHCFG_AAGN;
213 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG, reg);
214 		break;
215 	case CHIP_I840:
216 	case CHIP_I850:
217 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD);
218 		reg |= AGPCMD_AGPEN;
219 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD,
220 		    reg);
221 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG);
222 		reg |= MCHCFG_AAGN;
223 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG,
224 		    reg);
225 		break;
226 	default:
227 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG);
228 		reg &= ~NBXCFG_APAE;
229 		reg |=  NBXCFG_AAGN;
230 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG, reg);
231 	}
232 
233 	/* Clear Error status */
234 	switch (isc->chiptype) {
235 	case CHIP_I840:
236 		pci_conf_write(pa->pa_pc, pa->pa_tag,
237 		    AGP_INTEL_I8XX_ERRSTS, 0xc000);
238 		break;
239 	case CHIP_I845:
240 	case CHIP_I850:
241 	case CHIP_I865:
242 		pci_conf_write(isc->isc_pc, isc->isc_tag,
243 		    AGP_INTEL_I8XX_ERRSTS, 0x00ff);
244 		break;
245 
246 	default:
247 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ERRSTS, 0x70);
248 	}
249 
250 	isc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_intel_methods,
251 	    AGP_APBASE, PCI_MAPREG_TYPE_MEM, &isc->dev);
252 	return;
253 }
254 
255 #if 0
256 int
257 agp_intel_detach(struct agp_softc *sc)
258 {
259 	int error;
260 	pcireg_t reg;
261 	struct agp_intel_softc *isc = sc->sc_chipc;
262 
263 	error = agp_generic_detach(sc);
264 	if (error)
265 		return (error);
266 
267 	/* XXX i845/i855PM/i840/i850E */
268 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag, AGP_INTEL_NBXCFG);
269 	reg &= ~(1 << 9);
270 	printf("%s: set NBXCFG to %x\n", __FUNCTION__, reg);
271 	pci_conf_write(sc->sc_pc, sc->sc_tag, AGP_INTEL_NBXCFG, reg);
272 	pci_conf_write(sc->sc_pc, sc->sc_tag, AGP_INTEL_ATTBASE, 0);
273 	AGP_SET_APERTURE(sc, isc->initial_aperture);
274 	agp_free_gatt(sc, isc->gatt);
275 
276 	return (0);
277 }
278 #endif
279 
280 bus_size_t
281 agp_intel_get_aperture(void *sc)
282 {
283 	struct agp_intel_softc *isc = sc;
284 	bus_size_t apsize;
285 
286 	apsize = pci_conf_read(isc->isc_pc, isc->isc_tag,
287 	    AGP_INTEL_APSIZE) & isc->aperture_mask;
288 
289 	/*
290 	 * The size is determined by the number of low bits of
291 	 * register APBASE which are forced to zero. The low 22 bits
292 	 * are always forced to zero and each zero bit in the apsize
293 	 * field just read forces the corresponding bit in the 27:22
294 	 * to be zero. We calculate the aperture size accordingly.
295 	 */
296 	return ((((apsize ^ isc->aperture_mask) << 22) | ((1 << 22) - 1)) + 1);
297 }
298 
299 int
300 agp_intel_set_aperture(void *sc, bus_size_t aperture)
301 {
302 	struct agp_intel_softc *isc = sc;
303 	bus_size_t apsize;
304 
305 	/*
306 	 * Reverse the magic from get_aperture.
307 	 */
308 	apsize = ((aperture - 1) >> 22) ^ isc->aperture_mask;
309 
310 	/*
311 	 * Double check for sanity.
312 	 */
313 	if ((((apsize ^ isc->aperture_mask) << 22) |
314 	    ((1 << 22) - 1)) + 1 != aperture)
315 		return (EINVAL);
316 
317 	pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_APSIZE, apsize);
318 
319 	return (0);
320 }
321 
322 int
323 agp_intel_bind_page(void *sc, off_t offset, bus_addr_t physical)
324 {
325 	struct agp_intel_softc *isc = sc;
326 
327 	if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
328 		return (EINVAL);
329 
330 	isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17;
331 	return (0);
332 }
333 
334 int
335 agp_intel_unbind_page(void *sc, off_t offset)
336 {
337 	struct agp_intel_softc *isc = sc;
338 
339 	if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
340 		return (EINVAL);
341 
342 	isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
343 	return (0);
344 }
345 
346 void
347 agp_intel_flush_tlb(void *sc)
348 {
349 	struct agp_intel_softc *isc = sc;
350 	pcireg_t reg;
351 
352 	switch (isc->chiptype) {
353 	case CHIP_I865:
354 	case CHIP_I850:
355 	case CHIP_I845:
356 	case CHIP_I840:
357 	case CHIP_I443:
358 		reg = pci_conf_read(isc->isc_pc, isc->isc_tag,
359 		    AGP_INTEL_AGPCTRL);
360 		reg &= ~AGPCTRL_GTLB;
361 		pci_conf_write(isc->isc_pc, isc->isc_tag,
362 		    AGP_INTEL_AGPCTRL, reg);
363 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
364 		    reg | AGPCTRL_GTLB);
365 		break;
366 	default: /* XXX */
367 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
368 		    0x2200);
369 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
370 		    0x2280);
371 	}
372 }
373