xref: /openbsd-src/sys/dev/pci/agp_intel.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: agp_intel.c,v 1.23 2014/05/27 12:40:00 kettenis 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/device.h>
36 #include <sys/rwlock.h>
37 
38 #include <dev/pci/pcivar.h>
39 #include <dev/pci/pcireg.h>
40 #include <dev/pci/pcidevs.h>
41 #include <dev/pci/agpvar.h>
42 #include <dev/pci/agpreg.h>
43 
44 #include <machine/bus.h>
45 
46 struct agp_intel_softc {
47 	struct device		 dev;
48 	struct agp_softc	*agpdev;
49 	struct agp_gatt 	*gatt;
50 	pci_chipset_tag_t	 isc_pc;
51 	pcitag_t		 isc_tag;
52 	bus_addr_t		 isc_apaddr;
53 	bus_size_t		 isc_apsize;
54 	u_int			 aperture_mask;
55 	enum {
56 		CHIP_INTEL,
57 		CHIP_I443,
58 		CHIP_I840,
59 		CHIP_I845,
60 		CHIP_I850,
61 		CHIP_I865
62 	}			 chiptype;
63 	/* registers saved during a suspend/resume cycle. */
64 	pcireg_t		 savectrl;
65 	pcireg_t		 savecmd;
66 	pcireg_t		 savecfg;
67 };
68 
69 
70 void	agp_intel_attach(struct device *, struct device *, void *);
71 int	agp_intel_activate(struct device *, int);
72 void	agp_intel_save(struct agp_intel_softc *);
73 void	agp_intel_restore(struct agp_intel_softc *);
74 int	agp_intel_probe(struct device *, void *, void *);
75 bus_size_t agp_intel_get_aperture(void *);
76 int	agp_intel_set_aperture(void *, bus_size_t);
77 void	agp_intel_bind_page(void *, bus_addr_t, paddr_t, int);
78 void	agp_intel_unbind_page(void *, bus_addr_t);
79 void	agp_intel_flush_tlb(void *);
80 
81 struct cfattach intelagp_ca = {
82 	sizeof(struct agp_intel_softc), agp_intel_probe, agp_intel_attach,
83 	NULL, agp_intel_activate
84 };
85 
86 struct cfdriver intelagp_cd = {
87 	NULL, "intelagp", DV_DULL
88 };
89 
90 const struct agp_methods agp_intel_methods = {
91 	agp_intel_bind_page,
92 	agp_intel_unbind_page,
93 	agp_intel_flush_tlb,
94 	/* default enable and memory routines */
95 };
96 
97 int
98 agp_intel_probe(struct device *parent, void *match, void *aux)
99 {
100 	struct agp_attach_args	*aa = aux;
101 	struct pci_attach_args	*pa = aa->aa_pa;
102 
103 	/* Must be a pchb */
104 	if (agpbus_probe(aa) == 0)
105 		return (0);
106 
107 	switch (PCI_PRODUCT(pa->pa_id)) {
108 	case PCI_PRODUCT_INTEL_82443LX:
109 	case PCI_PRODUCT_INTEL_82443BX:
110 	case PCI_PRODUCT_INTEL_82440BX:
111 	case PCI_PRODUCT_INTEL_82440BX_AGP:
112 	case PCI_PRODUCT_INTEL_82815_HB:
113 	case PCI_PRODUCT_INTEL_82820_HB:
114 	case PCI_PRODUCT_INTEL_82830M_HB:
115 	case PCI_PRODUCT_INTEL_82840_HB:
116 	case PCI_PRODUCT_INTEL_82845_HB:
117 	case PCI_PRODUCT_INTEL_82845G_HB:
118 	case PCI_PRODUCT_INTEL_82850_HB:
119 	case PCI_PRODUCT_INTEL_82855PM_HB:
120 	case PCI_PRODUCT_INTEL_82855GM_HB:
121 	case PCI_PRODUCT_INTEL_82860_HB:
122 	case PCI_PRODUCT_INTEL_82865G_HB:
123 	case PCI_PRODUCT_INTEL_82875P_HB:
124 		return (1);
125 	}
126 
127 	return (0);
128 }
129 
130 void
131 agp_intel_attach(struct device *parent, struct device *self, void *aux)
132 {
133 	struct agp_intel_softc	*isc = (struct agp_intel_softc *)self;
134 	struct agp_attach_args	*aa = aux;
135 	struct pci_attach_args	*pa = aa->aa_pa;
136 	struct agp_gatt		*gatt;
137 	pcireg_t		 reg;
138 	u_int32_t		 value;
139 
140 	isc->isc_pc = pa->pa_pc;
141 	isc->isc_tag = pa->pa_tag;
142 
143 	switch (PCI_PRODUCT(pa->pa_id)) {
144 	case PCI_PRODUCT_INTEL_82443LX:
145 	case PCI_PRODUCT_INTEL_82443BX:
146 	case PCI_PRODUCT_INTEL_82440BX:
147 	case PCI_PRODUCT_INTEL_82440BX_AGP:
148 		isc->chiptype = CHIP_I443;
149 		break;
150 	case PCI_PRODUCT_INTEL_82830M_HB:
151 	case PCI_PRODUCT_INTEL_82840_HB:
152 		isc->chiptype = CHIP_I840;
153 		break;
154 	case PCI_PRODUCT_INTEL_82845_HB:
155 	case PCI_PRODUCT_INTEL_82845G_HB:
156 	case PCI_PRODUCT_INTEL_82855PM_HB:
157 		isc->chiptype = CHIP_I845;
158 		break;
159 	case PCI_PRODUCT_INTEL_82850_HB:
160 		isc->chiptype = CHIP_I850;
161 		break;
162 	case PCI_PRODUCT_INTEL_82865G_HB:
163 	case PCI_PRODUCT_INTEL_82875P_HB:
164 		isc->chiptype = CHIP_I865;
165 		break;
166 	default:
167 		isc->chiptype = CHIP_INTEL;
168 		break;
169 	}
170 
171 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE,
172 	    PCI_MAPREG_TYPE_MEM, &isc->isc_apaddr, NULL, NULL) != 0) {
173 		printf(": can't get aperture info\n");
174 		return;
175 	}
176 
177 	/* Determine maximum supported aperture size. */
178 	value = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE);
179 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, APSIZE_MASK);
180 	isc->aperture_mask = pci_conf_read(pa->pa_pc, pa->pa_tag,
181 		AGP_INTEL_APSIZE) & APSIZE_MASK;
182 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, value);
183 	isc->isc_apsize = agp_intel_get_aperture(isc);
184 
185 	for (;;) {
186 		gatt = agp_alloc_gatt(pa->pa_dmat, isc->isc_apsize);
187 		if (gatt != NULL)
188 			break;
189 
190 		/*
191 		 * almost certainly error allocating contigious dma memory
192 		 * so reduce aperture so that the gatt size reduces.
193 		 */
194 		isc->isc_apsize /= 2;
195 		if (agp_intel_set_aperture(isc, isc->isc_apsize)) {
196 			printf(": failed to set aperture\n");
197 			return;
198 		}
199 	}
200 	isc->gatt = gatt;
201 
202 	/* Install the gatt. */
203 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ATTBASE,
204 	    gatt->ag_physical);
205 
206 	/* Enable the GLTB and setup the control register. */
207 	switch (isc->chiptype) {
208 	case CHIP_I443:
209 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
210 		    AGPCTRL_AGPRSE | AGPCTRL_GTLB);
211 		break;
212 	default:
213 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
214 		    pci_conf_read(isc->isc_pc, isc->isc_tag,
215 		    AGP_INTEL_AGPCTRL) | AGPCTRL_GTLB);
216 		break;
217 	}
218 
219 	/* Enable things, clear errors etc. */
220 	switch (isc->chiptype) {
221 	case CHIP_I845:
222 	case CHIP_I865:
223 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG);
224 		reg |= MCHCFG_AAGN;
225 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG, reg);
226 		break;
227 	case CHIP_I840:
228 	case CHIP_I850:
229 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD);
230 		reg |= AGPCMD_AGPEN;
231 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD,
232 		    reg);
233 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG);
234 		reg |= MCHCFG_AAGN;
235 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG,
236 		    reg);
237 		break;
238 	default:
239 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG);
240 		reg &= ~NBXCFG_APAE;
241 		reg |=  NBXCFG_AAGN;
242 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG, reg);
243 		break;
244 	}
245 
246 	/* Clear Error status */
247 	switch (isc->chiptype) {
248 	case CHIP_I840:
249 		pci_conf_write(pa->pa_pc, pa->pa_tag,
250 		    AGP_INTEL_I8XX_ERRSTS, 0xc000);
251 		break;
252 	case CHIP_I845:
253 	case CHIP_I850:
254 	case CHIP_I865:
255 		pci_conf_write(isc->isc_pc, isc->isc_tag,
256 		    AGP_INTEL_I8XX_ERRSTS, 0x00ff);
257 		break;
258 
259 	default:
260 		reg = pci_conf_read(isc->isc_pc, isc->isc_tag,
261 		    AGP_INTEL_ERRCMD);
262 		pci_conf_write(isc->isc_pc, isc->isc_tag,
263 		    AGP_INTEL_ERRCMD, reg);
264 	}
265 
266 	isc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_intel_methods,
267 	    isc->isc_apaddr, isc->isc_apsize, &isc->dev);
268 	return;
269 }
270 
271 int
272 agp_intel_activate(struct device *arg, int act)
273 {
274 	struct agp_intel_softc *isc = (struct agp_intel_softc *)arg;
275 
276 	switch (act) {
277 	case DVACT_SUSPEND:
278 		agp_intel_save(isc);
279 		break;
280 	case DVACT_RESUME:
281 		agp_intel_restore(isc);
282 		break;
283 	}
284 
285 	return (0);
286 }
287 
288 void
289 agp_intel_save(struct agp_intel_softc *isc)
290 {
291 
292 	if (isc->chiptype != CHIP_I443) {
293 		isc->savectrl = pci_conf_read(isc->isc_pc, isc->isc_tag,
294 		    AGP_INTEL_AGPCTRL);
295 	}
296 
297 	switch (isc->chiptype) {
298 	case CHIP_I845:
299 	case CHIP_I865:
300 		isc->savecmd = pci_conf_read(isc->isc_pc, isc->isc_tag,
301 		    AGP_I840_MCHCFG);
302 
303 		break;
304 	case CHIP_I840:
305 	case CHIP_I850:
306 		isc->savecmd = pci_conf_read(isc->isc_pc, isc->isc_tag,
307 		    AGP_INTEL_AGPCMD);
308 		isc->savecfg = pci_conf_read(isc->isc_pc, isc->isc_tag,
309 		    AGP_I840_MCHCFG);
310 
311 		break;
312 	default:
313 		isc->savecfg = pci_conf_read(isc->isc_pc, isc->isc_tag,
314 		    AGP_INTEL_NBXCFG);
315 		break;
316 	}
317 }
318 
319 void
320 agp_intel_restore(struct agp_intel_softc *isc)
321 {
322 	pcireg_t	tmp;
323 	/*
324 	 * reset size now just in case, if it worked before then sanity
325 	 * checking will not fail
326 	 */
327 	(void)agp_intel_set_aperture(isc, isc->isc_apsize);
328 
329 	/* Install the gatt. */
330 	pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_ATTBASE,
331 	    isc->gatt->ag_physical);
332 
333 	/* Enable the GLTB and setup the control register. */
334 	switch (isc->chiptype) {
335 	case CHIP_I443:
336 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
337 		    AGPCTRL_AGPRSE | AGPCTRL_GTLB);
338 		break;
339 	default:
340 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
341 		    isc->savectrl);
342 		break;
343 	}
344 
345 	/* Enable things, clear errors etc. */
346 	switch (isc->chiptype) {
347 	case CHIP_I845:
348 	case CHIP_I865:
349 		pci_conf_write(isc->isc_pc, isc->isc_tag,
350 		    AGP_I840_MCHCFG, isc->savecmd);
351 		break;
352 	case CHIP_I840:
353 	case CHIP_I850:
354 		pci_conf_write(isc->isc_pc, isc->isc_tag,
355 		    AGP_INTEL_AGPCMD, isc->savecmd);
356 		pci_conf_write(isc->isc_pc, isc->isc_tag,
357 		    AGP_I840_MCHCFG, isc->savecfg);
358 		break;
359 	default:
360 		pci_conf_write(isc->isc_pc, isc->isc_tag,
361 		    AGP_INTEL_NBXCFG, isc->savecfg);
362 		break;
363 	}
364 
365 	/* Clear Error status */
366 	switch (isc->chiptype) {
367 	case CHIP_I840:
368 		pci_conf_write(isc->isc_pc, isc->isc_tag,
369 		    AGP_INTEL_I8XX_ERRSTS, 0xc000);
370 		break;
371 	case CHIP_I845:
372 	case CHIP_I850:
373 	case CHIP_I865:
374 		pci_conf_write(isc->isc_pc, isc->isc_tag,
375 		    AGP_INTEL_I8XX_ERRSTS, 0x00ff);
376 		break;
377 	default:
378 		tmp = pci_conf_read(isc->isc_pc, isc->isc_tag,
379 		    AGP_INTEL_ERRCMD);
380 		pci_conf_write(isc->isc_pc, isc->isc_tag,
381 		    AGP_INTEL_ERRCMD, tmp);
382 		break;
383 	}
384 }
385 
386 bus_size_t
387 agp_intel_get_aperture(void *sc)
388 {
389 	struct agp_intel_softc *isc = sc;
390 	bus_size_t apsize;
391 
392 	apsize = pci_conf_read(isc->isc_pc, isc->isc_tag,
393 	    AGP_INTEL_APSIZE) & isc->aperture_mask;
394 
395 	/*
396 	 * The size is determined by the number of low bits of
397 	 * register APBASE which are forced to zero. The low 22 bits
398 	 * are always forced to zero and each zero bit in the apsize
399 	 * field just read forces the corresponding bit in the 27:22
400 	 * to be zero. We calculate the aperture size accordingly.
401 	 */
402 	return ((((apsize ^ isc->aperture_mask) << 22) | ((1 << 22) - 1)) + 1);
403 }
404 
405 int
406 agp_intel_set_aperture(void *sc, bus_size_t aperture)
407 {
408 	struct agp_intel_softc *isc = sc;
409 	bus_size_t apsize;
410 
411 	/*
412 	 * Reverse the magic from get_aperture.
413 	 */
414 	apsize = ((aperture - 1) >> 22) ^ isc->aperture_mask;
415 
416 	/*
417 	 * Double check for sanity.
418 	 */
419 	if ((((apsize ^ isc->aperture_mask) << 22) |
420 	    ((1 << 22) - 1)) + 1 != aperture)
421 		return (EINVAL);
422 
423 	pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_APSIZE, apsize);
424 
425 	return (0);
426 }
427 
428 void
429 agp_intel_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags)
430 {
431 	struct agp_intel_softc *isc = sc;
432 
433 	isc->gatt->ag_virtual[(offset - isc->isc_apaddr) >> AGP_PAGE_SHIFT] =
434 	    physical | 0x17;
435 }
436 
437 void
438 agp_intel_unbind_page(void *sc, bus_size_t offset)
439 {
440 	struct agp_intel_softc *isc = sc;
441 
442 	isc->gatt->ag_virtual[(offset - isc->isc_apaddr) >> AGP_PAGE_SHIFT] = 0;
443 }
444 
445 void
446 agp_intel_flush_tlb(void *sc)
447 {
448 	struct agp_intel_softc *isc = sc;
449 	pcireg_t reg;
450 
451 	switch (isc->chiptype) {
452 	case CHIP_I865:
453 	case CHIP_I850:
454 	case CHIP_I845:
455 	case CHIP_I840:
456 	case CHIP_I443:
457 		reg = pci_conf_read(isc->isc_pc, isc->isc_tag,
458 		    AGP_INTEL_AGPCTRL);
459 		reg &= ~AGPCTRL_GTLB;
460 		pci_conf_write(isc->isc_pc, isc->isc_tag,
461 		    AGP_INTEL_AGPCTRL, reg);
462 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
463 		    reg | AGPCTRL_GTLB);
464 		break;
465 	default: /* XXX */
466 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
467 		    0x2200);
468 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
469 		    0x2280);
470 		break;
471 	}
472 }
473