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