xref: /openbsd/sys/dev/pci/agp_intel.c (revision 404b540a)
1 /*	$OpenBSD: agp_intel.c,v 1.15 2009/05/10 16:57:44 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 	bus_addr_t		 isc_apaddr;
57 	bus_size_t		 isc_apsize;
58 	u_int			 aperture_mask;
59 	enum {
60 		CHIP_INTEL,
61 		CHIP_I443,
62 		CHIP_I840,
63 		CHIP_I845,
64 		CHIP_I850,
65 		CHIP_I865
66 	}			 chiptype;
67 };
68 
69 
70 void	agp_intel_attach(struct device *, struct device *, void *);
71 int	agp_intel_probe(struct device *, void *, void *);
72 bus_size_t agp_intel_get_aperture(void *);
73 int	agp_intel_set_aperture(void *, bus_size_t);
74 void	agp_intel_bind_page(void *, bus_addr_t, paddr_t, int);
75 void	agp_intel_unbind_page(void *, bus_addr_t);
76 void	agp_intel_flush_tlb(void *);
77 
78 struct cfattach intelagp_ca = {
79 	sizeof(struct agp_intel_softc), agp_intel_probe, agp_intel_attach
80 };
81 
82 struct cfdriver intelagp_cd = {
83 	NULL, "intelagp", DV_DULL
84 };
85 
86 const struct agp_methods agp_intel_methods = {
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 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE,
167 	    PCI_MAPREG_TYPE_MEM, &isc->isc_apaddr, NULL, NULL) != 0) {
168 		printf(": can't get aperture info\n");
169 		return;
170 	}
171 
172 	/* Determine maximum supported aperture size. */
173 	value = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE);
174 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, APSIZE_MASK);
175 	isc->aperture_mask = pci_conf_read(pa->pa_pc, pa->pa_tag,
176 		AGP_INTEL_APSIZE) & APSIZE_MASK;
177 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, value);
178 	isc->isc_apsize = agp_intel_get_aperture(isc);
179 
180 	for (;;) {
181 		gatt = agp_alloc_gatt(pa->pa_dmat, isc->isc_apsize);
182 		if (gatt != NULL)
183 			break;
184 
185 		/*
186 		 * almost certainly error allocating contigious dma memory
187 		 * so reduce aperture so that the gatt size reduces.
188 		 */
189 		isc->isc_apsize /= 2;
190 		if (agp_intel_set_aperture(isc, isc->isc_apsize)) {
191 			printf(": failed to set aperture\n");
192 			return;
193 		}
194 	}
195 	isc->gatt = gatt;
196 
197 	/* Install the gatt. */
198 	pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ATTBASE,
199 	    gatt->ag_physical);
200 
201 	/* Enable the GLTB and setup the control register. */
202 	switch (isc->chiptype) {
203 	case CHIP_I443:
204 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
205 		    AGPCTRL_AGPRSE | AGPCTRL_GTLB);
206 		break;
207 	default:
208 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
209 		    pci_conf_read(isc->isc_pc, isc->isc_tag,
210 		    AGP_INTEL_AGPCTRL) | AGPCTRL_GTLB);
211 	}
212 
213 	/* Enable things, clear errors etc. */
214 	switch (isc->chiptype) {
215 	case CHIP_I845:
216 	case CHIP_I865:
217 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG);
218 		reg |= MCHCFG_AAGN;
219 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG, reg);
220 		break;
221 	case CHIP_I840:
222 	case CHIP_I850:
223 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD);
224 		reg |= AGPCMD_AGPEN;
225 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD,
226 		    reg);
227 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG);
228 		reg |= MCHCFG_AAGN;
229 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG,
230 		    reg);
231 		break;
232 	default:
233 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG);
234 		reg &= ~NBXCFG_APAE;
235 		reg |=  NBXCFG_AAGN;
236 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG, reg);
237 	}
238 
239 	/* Clear Error status */
240 	switch (isc->chiptype) {
241 	case CHIP_I840:
242 		pci_conf_write(pa->pa_pc, pa->pa_tag,
243 		    AGP_INTEL_I8XX_ERRSTS, 0xc000);
244 		break;
245 	case CHIP_I845:
246 	case CHIP_I850:
247 	case CHIP_I865:
248 		pci_conf_write(isc->isc_pc, isc->isc_tag,
249 		    AGP_INTEL_I8XX_ERRSTS, 0x00ff);
250 		break;
251 
252 	default:
253 		pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ERRSTS, 0x70);
254 	}
255 
256 	isc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_intel_methods,
257 	    isc->isc_apaddr, isc->isc_apsize, &isc->dev);
258 	return;
259 }
260 
261 #if 0
262 int
263 agp_intel_detach(struct agp_softc *sc)
264 {
265 	int error;
266 	pcireg_t reg;
267 	struct agp_intel_softc *isc = sc->sc_chipc;
268 
269 	error = agp_generic_detach(sc);
270 	if (error)
271 		return (error);
272 
273 	/* XXX i845/i855PM/i840/i850E */
274 	reg = pci_conf_read(sc->sc_pc, sc->sc_tag, AGP_INTEL_NBXCFG);
275 	reg &= ~(1 << 9);
276 	printf("%s: set NBXCFG to %x\n", __FUNCTION__, reg);
277 	pci_conf_write(sc->sc_pc, sc->sc_tag, AGP_INTEL_NBXCFG, reg);
278 	pci_conf_write(sc->sc_pc, sc->sc_tag, AGP_INTEL_ATTBASE, 0);
279 	AGP_SET_APERTURE(sc, isc->initial_aperture);
280 	agp_free_gatt(sc, isc->gatt);
281 
282 	return (0);
283 }
284 #endif
285 
286 bus_size_t
287 agp_intel_get_aperture(void *sc)
288 {
289 	struct agp_intel_softc *isc = sc;
290 	bus_size_t apsize;
291 
292 	apsize = pci_conf_read(isc->isc_pc, isc->isc_tag,
293 	    AGP_INTEL_APSIZE) & isc->aperture_mask;
294 
295 	/*
296 	 * The size is determined by the number of low bits of
297 	 * register APBASE which are forced to zero. The low 22 bits
298 	 * are always forced to zero and each zero bit in the apsize
299 	 * field just read forces the corresponding bit in the 27:22
300 	 * to be zero. We calculate the aperture size accordingly.
301 	 */
302 	return ((((apsize ^ isc->aperture_mask) << 22) | ((1 << 22) - 1)) + 1);
303 }
304 
305 int
306 agp_intel_set_aperture(void *sc, bus_size_t aperture)
307 {
308 	struct agp_intel_softc *isc = sc;
309 	bus_size_t apsize;
310 
311 	/*
312 	 * Reverse the magic from get_aperture.
313 	 */
314 	apsize = ((aperture - 1) >> 22) ^ isc->aperture_mask;
315 
316 	/*
317 	 * Double check for sanity.
318 	 */
319 	if ((((apsize ^ isc->aperture_mask) << 22) |
320 	    ((1 << 22) - 1)) + 1 != aperture)
321 		return (EINVAL);
322 
323 	pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_APSIZE, apsize);
324 
325 	return (0);
326 }
327 
328 void
329 agp_intel_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags)
330 {
331 	struct agp_intel_softc *isc = sc;
332 
333 	isc->gatt->ag_virtual[(offset - isc->isc_apaddr) >> AGP_PAGE_SHIFT] =
334 	    physical | 0x17;
335 }
336 
337 void
338 agp_intel_unbind_page(void *sc, bus_size_t offset)
339 {
340 	struct agp_intel_softc *isc = sc;
341 
342 	isc->gatt->ag_virtual[(offset - isc->isc_apaddr) >> AGP_PAGE_SHIFT] = 0;
343 }
344 
345 void
346 agp_intel_flush_tlb(void *sc)
347 {
348 	struct agp_intel_softc *isc = sc;
349 	pcireg_t reg;
350 
351 	switch (isc->chiptype) {
352 	case CHIP_I865:
353 	case CHIP_I850:
354 	case CHIP_I845:
355 	case CHIP_I840:
356 	case CHIP_I443:
357 		reg = pci_conf_read(isc->isc_pc, isc->isc_tag,
358 		    AGP_INTEL_AGPCTRL);
359 		reg &= ~AGPCTRL_GTLB;
360 		pci_conf_write(isc->isc_pc, isc->isc_tag,
361 		    AGP_INTEL_AGPCTRL, reg);
362 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
363 		    reg | AGPCTRL_GTLB);
364 		break;
365 	default: /* XXX */
366 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
367 		    0x2200);
368 		pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL,
369 		    0x2280);
370 	}
371 }
372