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