4879f12755738125081b831e1f86bb1a1bd364af
[dragonfly.git] / sys / dev / agp / agp_i810.c
1 /*-
2  * Copyright (c) 2000 Doug Rabson
3  * Copyright (c) 2000 Ruslan Ermilov
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *      $FreeBSD: src/sys/pci/agp_i810.c,v 1.1.2.5 2002/09/15 08:45:41 anholt Exp $
28  *      $DragonFly: src/sys/dev/agp/agp_i810.c,v 1.5 2004/01/20 05:04:03 dillon Exp $
29  */
30
31 /*
32  * Fixes for 830/845G support: David Dawes <dawes@xfree86.org>
33  */
34
35 #include "opt_bus.h"
36 #include "opt_pci.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/kernel.h>
42 #include <sys/bus.h>
43 #include <sys/lock.h>
44
45 #include <bus/pci/pcivar.h>
46 #include <bus/pci/pcireg.h>
47 #include "agppriv.h"
48 #include "agpreg.h"
49
50 #include <vm/vm.h>
51 #include <vm/vm_object.h>
52 #include <vm/vm_page.h>
53 #include <vm/vm_pageout.h>
54 #include <vm/pmap.h>
55
56 #include <machine/bus.h>
57 #include <machine/resource.h>
58 #include <sys/rman.h>
59
60 MALLOC_DECLARE(M_AGP);
61
62 #define READ1(off)      bus_space_read_1(sc->bst, sc->bsh, off)
63 #define READ4(off)      bus_space_read_4(sc->bst, sc->bsh, off)
64 #define WRITE4(off,v)   bus_space_write_4(sc->bst, sc->bsh, off, v)
65
66 #define CHIP_I810 0     /* i810/i815 */
67 #define CHIP_I830 1     /* i830/i845 */
68
69 struct agp_i810_softc {
70         struct agp_softc agp;
71         u_int32_t initial_aperture;     /* aperture size at startup */
72         struct agp_gatt *gatt;
73         int chiptype;                   /* i810-like or i830 */
74         u_int32_t dcache_size;          /* i810 only */
75         u_int32_t stolen;               /* number of i830/845 gtt entries for stolen memory */
76         device_t bdev;                  /* bridge device */
77         struct resource *regs;          /* memory mapped GC registers */
78         bus_space_tag_t bst;            /* bus_space tag */
79         bus_space_handle_t bsh;         /* bus_space handle */
80 };
81
82 static const char*
83 agp_i810_match(device_t dev)
84 {
85         if (pci_get_class(dev) != PCIC_DISPLAY
86             || pci_get_subclass(dev) != PCIS_DISPLAY_VGA)
87                 return NULL;
88
89         switch (pci_get_devid(dev)) {
90         case 0x71218086:
91                 return ("Intel 82810 (i810 GMCH) SVGA controller");
92
93         case 0x71238086:
94                 return ("Intel 82810-DC100 (i810-DC100 GMCH) SVGA controller");
95
96         case 0x71258086:
97                 return ("Intel 82810E (i810E GMCH) SVGA controller");
98
99         case 0x11328086:
100                 return ("Intel 82815 (i815 GMCH) SVGA controller");
101
102         case 0x35778086:
103                 return ("Intel 82830 (i830M GMCH) SVGA controller");
104
105         case 0x25628086:
106                 return ("Intel 82845 (i845 GMCH) SVGA controller");
107         };
108
109         return NULL;
110 }
111
112 /*
113  * Find bridge device.
114  */
115 static device_t
116 agp_i810_find_bridge(device_t dev)
117 {
118         device_t *children, child;
119         int nchildren, i;
120         u_int32_t devid;
121
122         /*
123          * Calculate bridge device's ID.
124          */
125         devid = pci_get_devid(dev);
126         switch (devid) {
127         case 0x71218086:
128         case 0x71238086:
129         case 0x71258086:
130                 devid -= 0x10000;
131                 break;
132
133         case 0x11328086:
134         case 0x35778086:
135         case 0x25628086:
136                 devid -= 0x20000;
137                 break;
138         };
139         if (device_get_children(device_get_parent(dev), &children, &nchildren))
140                 return 0;
141
142         for (i = 0; i < nchildren; i++) {
143                 child = children[i];
144
145                 if (pci_get_devid(child) == devid) {
146                         free(children, M_TEMP);
147                         return child;
148                 }
149         }
150         free(children, M_TEMP);
151         return 0;
152 }
153
154 static int
155 agp_i810_probe(device_t dev)
156 {
157         const char *desc;
158
159         desc = agp_i810_match(dev);
160         if (desc) {
161                 device_t bdev;
162                 u_int8_t smram;
163                 int devid = pci_get_devid(dev);
164
165                 bdev = agp_i810_find_bridge(dev);
166                 if (!bdev) {
167                         if (bootverbose)
168                                 printf("I810: can't find bridge device\n");
169                         return ENXIO;
170                 }
171
172                 /*
173                  * checking whether internal graphics device has been activated.
174                  */
175                 if ( (devid != 0x35778086 ) &&
176                      (devid != 0x25628086 ) ) {
177                         smram = pci_read_config(bdev, AGP_I810_SMRAM, 1);
178                         if ((smram & AGP_I810_SMRAM_GMS)
179                             == AGP_I810_SMRAM_GMS_DISABLED) {
180                                 if (bootverbose)
181                                         printf("I810: disabled, not probing\n");
182                                 return ENXIO;
183                         }
184                 } else {        /* I830MG */
185                         unsigned int gcc1;
186                         gcc1 = pci_read_config(bdev, AGP_I830_GCC1, 1);
187                         if ((gcc1 & AGP_I830_GCC1_DEV2) == AGP_I830_GCC1_DEV2_DISABLED) {
188                                 if (bootverbose)
189                                         printf("I830: disabled, not probing\n");
190                                         return ENXIO;
191                         }
192                 }
193
194                 device_verbose(dev);
195                 device_set_desc(dev, desc);
196                 return 0;
197         }
198
199         return ENXIO;
200 }
201
202 static int
203 agp_i810_attach(device_t dev)
204 {
205         struct agp_i810_softc *sc = device_get_softc(dev);
206         struct agp_gatt *gatt;
207         int error, rid;
208
209         sc->bdev = agp_i810_find_bridge(dev);
210         if (!sc->bdev)
211                 return ENOENT;
212
213         error = agp_generic_attach(dev);
214         if (error)
215                 return error;
216
217         switch (pci_get_devid(dev)) {
218         case 0x71218086:
219         case 0x71238086:
220         case 0x71258086:
221         case 0x11328086:
222                 sc->chiptype = CHIP_I810;
223                 break;
224         case 0x35778086:
225         case 0x25628086:
226                 sc->chiptype = CHIP_I830;
227                 break;
228         };
229
230         /* Same for i810 and i830 */
231         rid = AGP_I810_MMADR;
232         sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
233                                       0, ~0, 1, RF_ACTIVE);
234         if (!sc->regs) {
235                 agp_generic_detach(dev);
236                 return ENOMEM;
237         }
238         sc->bst = rman_get_bustag(sc->regs);
239         sc->bsh = rman_get_bushandle(sc->regs);
240
241         sc->initial_aperture = AGP_GET_APERTURE(dev);
242         if (sc->initial_aperture == 0) {
243                 device_printf(dev, "bad initial aperture size, disabling\n");
244                 return ENXIO;
245         }
246
247         gatt = malloc( sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
248         if (!gatt) {
249                 agp_generic_detach(dev);
250                 return ENOMEM;
251         }
252         sc->gatt = gatt;
253
254         gatt->ag_entries = AGP_GET_APERTURE(dev) >> AGP_PAGE_SHIFT;
255
256         if ( sc->chiptype == CHIP_I810 ) {
257                 /* Some i810s have on-chip memory called dcache */
258                 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED)
259                         sc->dcache_size = 4 * 1024 * 1024;
260                 else
261                         sc->dcache_size = 0;
262
263                 /* According to the specs the gatt on the i810 must be 64k */
264                 gatt->ag_virtual = contigmalloc( 64 * 1024, M_AGP, 0, 
265                                         0, ~0, PAGE_SIZE, 0);
266                 if (!gatt->ag_virtual) {
267                         if (bootverbose)
268                                 device_printf(dev, "contiguous allocation failed\n");
269                         free(gatt, M_AGP);
270                         agp_generic_detach(dev);
271                         return ENOMEM;
272                 }
273                 bzero(gatt->ag_virtual, gatt->ag_entries * sizeof(u_int32_t));
274         
275                 gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
276                 agp_flush_cache();
277                 /* Install the GATT. */
278                 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1);
279         } else {
280                 /* The i830 automatically initializes the 128k gatt on boot. */
281                 unsigned int gcc1, pgtblctl;
282                 
283                 gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 1);
284                 switch (gcc1 & AGP_I830_GCC1_GMS) {
285                         case AGP_I830_GCC1_GMS_STOLEN_512:
286                                 sc->stolen = (512 - 132) * 1024 / 4096;
287                                 break;
288                         case AGP_I830_GCC1_GMS_STOLEN_1024: 
289                                 sc->stolen = (1024 - 132) * 1024 / 4096;
290                                 break;
291                         case AGP_I830_GCC1_GMS_STOLEN_8192: 
292                                 sc->stolen = (8192 - 132) * 1024 / 4096;
293                                 break;
294                         default:
295                                 sc->stolen = 0;
296                                 device_printf(dev, "unknown memory configuration, disabling\n");
297                                 agp_generic_detach(dev);
298                                 return EINVAL;
299                 }
300                 if (sc->stolen > 0)
301                         device_printf(dev, "detected %dk stolen memory\n", sc->stolen * 4);
302                 device_printf(dev, "aperture size is %dM\n", sc->initial_aperture / 1024 / 1024);
303
304                 /* GATT address is already in there, make sure it's enabled */
305                 pgtblctl = READ4(AGP_I810_PGTBL_CTL);
306 #if 0
307                 device_printf(dev, "PGTBL_CTL is 0x%08x\n", pgtblctl);
308 #endif
309                 pgtblctl |= 1;
310                 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
311
312                 gatt->ag_physical = pgtblctl & ~1;
313         }
314
315         /*
316          * Make sure the chipset can see everything.
317          */
318         agp_flush_cache();
319
320         return 0;
321 }
322
323 static int
324 agp_i810_detach(device_t dev)
325 {
326         struct agp_i810_softc *sc = device_get_softc(dev);
327         int error;
328
329         error = agp_generic_detach(dev);
330         if (error)
331                 return error;
332
333         /* Clear the GATT base. */
334         if ( sc->chiptype == CHIP_I810 ) {
335                 WRITE4(AGP_I810_PGTBL_CTL, 0);
336         } else {
337                 unsigned int pgtblctl;
338                 pgtblctl = READ4(AGP_I810_PGTBL_CTL);
339                 pgtblctl &= ~1;
340                 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
341         }
342
343         /* Put the aperture back the way it started. */
344         AGP_SET_APERTURE(dev, sc->initial_aperture);
345
346         if ( sc->chiptype == CHIP_I810 ) {
347                 contigfree(sc->gatt->ag_virtual, 64 * 1024, M_AGP);
348         }
349         free(sc->gatt, M_AGP);
350
351         bus_release_resource(dev, SYS_RES_MEMORY,
352                              AGP_I810_MMADR, sc->regs);
353
354         return 0;
355 }
356
357 static u_int32_t
358 agp_i810_get_aperture(device_t dev)
359 {
360         struct agp_i810_softc *sc = device_get_softc(dev);
361
362         if ( sc->chiptype == CHIP_I810 ) {
363                 u_int16_t miscc;
364                 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
365                 if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32)
366                         return 32 * 1024 * 1024;
367                 else
368                         return 64 * 1024 * 1024;
369         } else {        /* I830 */
370                 unsigned int gcc1;
371
372                 gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 2);
373                 if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64)
374                         return 64 * 1024 * 1024;
375                 else
376                         return 128 * 1024 * 1024;
377         }
378 }
379
380 static int
381 agp_i810_set_aperture(device_t dev, u_int32_t aperture)
382 {
383         struct agp_i810_softc *sc = device_get_softc(dev);
384         u_int16_t miscc;
385
386         if ( sc->chiptype == CHIP_I810 ) {
387                 /*
388                  * Double check for sanity.
389                  */
390                 if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) {
391                         device_printf(dev, "bad aperture size %d\n", aperture);
392                         return EINVAL;
393                 }
394         
395                 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
396                 miscc &= ~AGP_I810_MISCC_WINSIZE;
397                 if (aperture == 32 * 1024 * 1024)
398                         miscc |= AGP_I810_MISCC_WINSIZE_32;
399                 else
400                         miscc |= AGP_I810_MISCC_WINSIZE_64;
401         
402                 pci_write_config(sc->bdev, AGP_I810_MISCC, miscc, 2);
403         } else {        /* I830 */
404                 unsigned int gcc1;
405
406                 if (aperture != 64 * 1024 * 1024 && aperture != 128 * 1024 * 1024) {
407                         device_printf(dev, "bad aperture size %d\n", aperture);
408                         return EINVAL;
409                 }
410                 gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 2);
411                 gcc1 &= ~AGP_I830_GCC1_GMASIZE;
412                 if (aperture == 64 * 1024 * 1024)
413                         gcc1 |= AGP_I830_GCC1_GMASIZE_64;
414                 else
415                         gcc1 |= AGP_I830_GCC1_GMASIZE_128;
416
417                 pci_write_config(sc->bdev, AGP_I830_GCC1, gcc1, 2);
418         }
419
420         return 0;
421 }
422
423 static int
424 agp_i810_bind_page(device_t dev, int offset, vm_offset_t physical)
425 {
426         struct agp_i810_softc *sc = device_get_softc(dev);
427
428         if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) {
429                 device_printf(dev, "failed: offset is 0x%08x, shift is %d, entries is %d\n", offset, AGP_PAGE_SHIFT, sc->gatt->ag_entries);
430                 return EINVAL;
431         }
432
433         if ( sc->chiptype == CHIP_I830 ) {
434                 if ( (offset >> AGP_PAGE_SHIFT) < sc->stolen ) {
435                         device_printf(dev, "trying to bind into stolen memory");
436                         return EINVAL;
437                 }
438         }
439
440         WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1);
441         return 0;
442 }
443
444 static int
445 agp_i810_unbind_page(device_t dev, int offset)
446 {
447         struct agp_i810_softc *sc = device_get_softc(dev);
448
449         if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
450                 return EINVAL;
451
452         if ( sc->chiptype == CHIP_I830 ) {
453                 if ( (offset >> AGP_PAGE_SHIFT) < sc->stolen ) {
454                         device_printf(dev, "trying to unbind from stolen memory");
455                         return EINVAL;
456                 }
457         }
458
459         WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0);
460         return 0;
461 }
462
463 /*
464  * Writing via memory mapped registers already flushes all TLBs.
465  */
466 static void
467 agp_i810_flush_tlb(device_t dev)
468 {
469 }
470
471 static int
472 agp_i810_enable(device_t dev, u_int32_t mode)
473 {
474
475         return 0;
476 }
477
478 static struct agp_memory *
479 agp_i810_alloc_memory(device_t dev, int type, vm_size_t size)
480 {
481         struct agp_i810_softc *sc = device_get_softc(dev);
482         struct agp_memory *mem;
483
484         if ((size & (AGP_PAGE_SIZE - 1)) != 0)
485                 return 0;
486
487         if (sc->agp.as_allocated + size > sc->agp.as_maxmem)
488                 return 0;
489
490         if (type == 1) {
491                 /*
492                  * Mapping local DRAM into GATT.
493                  */
494                 if ( sc->chiptype == CHIP_I830 )
495                         return 0;
496                 if (size != sc->dcache_size)
497                         return 0;
498         } else if (type == 2) {
499                 /*
500                  * Bogus mapping of a single page for the hardware cursor.
501                  */
502                 if (size != AGP_PAGE_SIZE)
503                         return 0;
504         }
505
506         mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
507         mem->am_id = sc->agp.as_nextid++;
508         mem->am_size = size;
509         mem->am_type = type;
510         if (type != 1)
511                 mem->am_obj = vm_object_allocate(OBJT_DEFAULT,
512                                                  atop(round_page(size)));
513         else
514                 mem->am_obj = 0;
515
516         if (type == 2) {
517                 /*
518                  * Allocate and wire down the page now so that we can
519                  * get its physical address.
520                  */
521                 vm_page_t m;
522                 m = vm_page_grab(mem->am_obj, 0, 
523                         VM_ALLOC_NORMAL|VM_ALLOC_ZERO|VM_ALLOC_RETRY);
524                 if ((m->flags & PG_ZERO) == 0)
525                         vm_page_zero_fill(m);
526                 vm_page_wire(m);
527                 mem->am_physical = VM_PAGE_TO_PHYS(m);
528                 vm_page_wakeup(m);
529         } else {
530                 mem->am_physical = 0;
531         }
532
533         mem->am_offset = 0;
534         mem->am_is_bound = 0;
535         TAILQ_INSERT_TAIL(&sc->agp.as_memory, mem, am_link);
536         sc->agp.as_allocated += size;
537
538         return mem;
539 }
540
541 static int
542 agp_i810_free_memory(device_t dev, struct agp_memory *mem)
543 {
544         struct agp_i810_softc *sc = device_get_softc(dev);
545
546         if (mem->am_is_bound)
547                 return EBUSY;
548
549         if (mem->am_type == 2) {
550                 /*
551                  * Unwire the page which we wired in alloc_memory.
552                  */
553                 vm_page_t m = vm_page_lookup(mem->am_obj, 0);
554                 vm_page_unwire(m, 0);
555         }
556
557         sc->agp.as_allocated -= mem->am_size;
558         TAILQ_REMOVE(&sc->agp.as_memory, mem, am_link);
559         if (mem->am_obj)
560                 vm_object_deallocate(mem->am_obj);
561         free(mem, M_AGP);
562         return 0;
563 }
564
565 static int
566 agp_i810_bind_memory(device_t dev, struct agp_memory *mem,
567                      vm_offset_t offset)
568 {
569         struct agp_i810_softc *sc = device_get_softc(dev);
570         vm_offset_t i;
571
572         if (mem->am_type != 1)
573                 return agp_generic_bind_memory(dev, mem, offset);
574
575         if ( sc->chiptype == CHIP_I830 )
576                 return EINVAL;
577
578         for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) {
579                 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4,
580                        i | 3);
581         }
582
583         return 0;
584 }
585
586 static int
587 agp_i810_unbind_memory(device_t dev, struct agp_memory *mem)
588 {
589         struct agp_i810_softc *sc = device_get_softc(dev);
590         vm_offset_t i;
591
592         if (mem->am_type != 1)
593                 return agp_generic_unbind_memory(dev, mem);
594
595         if ( sc->chiptype == CHIP_I830 )
596                 return EINVAL;
597
598         for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
599                 WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0);
600
601         return 0;
602 }
603
604 static device_method_t agp_i810_methods[] = {
605         /* Device interface */
606         DEVMETHOD(device_probe,         agp_i810_probe),
607         DEVMETHOD(device_attach,        agp_i810_attach),
608         DEVMETHOD(device_detach,        agp_i810_detach),
609         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
610         DEVMETHOD(device_suspend,       bus_generic_suspend),
611         DEVMETHOD(device_resume,        bus_generic_resume),
612
613         /* AGP interface */
614         DEVMETHOD(agp_get_aperture,     agp_i810_get_aperture),
615         DEVMETHOD(agp_set_aperture,     agp_i810_set_aperture),
616         DEVMETHOD(agp_bind_page,        agp_i810_bind_page),
617         DEVMETHOD(agp_unbind_page,      agp_i810_unbind_page),
618         DEVMETHOD(agp_flush_tlb,        agp_i810_flush_tlb),
619         DEVMETHOD(agp_enable,           agp_i810_enable),
620         DEVMETHOD(agp_alloc_memory,     agp_i810_alloc_memory),
621         DEVMETHOD(agp_free_memory,      agp_i810_free_memory),
622         DEVMETHOD(agp_bind_memory,      agp_i810_bind_memory),
623         DEVMETHOD(agp_unbind_memory,    agp_i810_unbind_memory),
624
625         { 0, 0 }
626 };
627
628 static driver_t agp_i810_driver = {
629         "agp",
630         agp_i810_methods,
631         sizeof(struct agp_i810_softc),
632 };
633
634 static devclass_t agp_devclass;
635
636 DRIVER_MODULE(agp_i810, pci, agp_i810_driver, agp_devclass, 0, 0);
637 MODULE_DEPEND(agp_i810, agp, 1, 1, 1);
638 MODULE_DEPEND(agp_i810, pci, 1, 1, 1);