2 * Copyright (c) 2000 Doug Rabson
3 * Copyright (c) 2000 Ruslan Ermilov
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
39 #include <sys/mutex.h>
42 #include <pci/pcivar.h>
43 #include <pci/pcireg.h>
44 #include <pci/agppriv.h>
45 #include <pci/agpreg.h>
48 #include <vm/vm_object.h>
49 #include <vm/vm_page.h>
50 #include <vm/vm_pageout.h>
53 #include <machine/bus.h>
54 #include <machine/resource.h>
57 MALLOC_DECLARE(M_AGP);
59 #define READ1(off) bus_space_read_1(sc->bst, sc->bsh, off)
60 #define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
62 struct agp_i810_softc {
64 u_int32_t initial_aperture; /* aperture size at startup */
65 struct agp_gatt *gatt;
66 u_int32_t dcache_size;
67 device_t bdev; /* bridge device */
68 struct resource *regs; /* memory mapped GC registers */
69 bus_space_tag_t bst; /* bus_space tag */
70 bus_space_handle_t bsh; /* bus_space handle */
74 agp_i810_match(device_t dev)
76 if (pci_get_class(dev) != PCIC_DISPLAY
77 || pci_get_subclass(dev) != PCIS_DISPLAY_VGA)
80 switch (pci_get_devid(dev)) {
82 return ("Intel 82810 (i810 GMCH) SVGA controller");
85 return ("Intel 82810-DC100 (i810-DC100 GMCH) SVGA controller");
88 return ("Intel 82810E (i810E GMCH) SVGA controller");
91 return ("Intel 82815 (i815 GMCH) SVGA controller");
101 agp_i810_find_bridge(device_t dev)
103 device_t *children, child;
108 * Calculate bridge device's ID.
110 devid = pci_get_devid(dev);
122 if (device_get_children(device_get_parent(dev), &children, &nchildren))
125 for (i = 0; i < nchildren; i++) {
128 if (pci_get_devid(child) == devid) {
129 free(children, M_TEMP);
133 free(children, M_TEMP);
138 agp_i810_probe(device_t dev)
142 desc = agp_i810_match(dev);
147 bdev = agp_i810_find_bridge(dev);
150 printf("I810: can't find bridge device\n");
154 smram = pci_read_config(bdev, AGP_I810_SMRAM, 1);
155 if ((smram & AGP_I810_SMRAM_GMS)
156 == AGP_I810_SMRAM_GMS_DISABLED) {
158 printf("I810: disabled, not probing\n");
163 device_set_desc(dev, desc);
171 agp_i810_attach(device_t dev)
173 struct agp_i810_softc *sc = device_get_softc(dev);
174 struct agp_gatt *gatt;
177 sc->bdev = agp_i810_find_bridge(dev);
181 error = agp_generic_attach(dev);
185 rid = AGP_I810_MMADR;
186 sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
187 0, ~0, 1, RF_ACTIVE);
189 agp_generic_detach(dev);
192 sc->bst = rman_get_bustag(sc->regs);
193 sc->bsh = rman_get_bushandle(sc->regs);
195 sc->initial_aperture = AGP_GET_APERTURE(dev);
197 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED)
198 sc->dcache_size = 4 * 1024 * 1024;
203 gatt = agp_alloc_gatt(dev);
208 * Probably contigmalloc failure. Try reducing the
209 * aperture so that the gatt size reduces.
211 if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
212 agp_generic_detach(dev);
218 /* Install the GATT. */
219 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1);
222 * Make sure the chipset can see everything.
230 agp_i810_detach(device_t dev)
232 struct agp_i810_softc *sc = device_get_softc(dev);
235 error = agp_generic_detach(dev);
239 /* Clear the GATT base. */
240 WRITE4(AGP_I810_PGTBL_CTL, 0);
242 /* Put the aperture back the way it started. */
243 AGP_SET_APERTURE(dev, sc->initial_aperture);
245 agp_free_gatt(sc->gatt);
247 bus_release_resource(dev, SYS_RES_MEMORY,
248 AGP_I810_MMADR, sc->regs);
254 agp_i810_get_aperture(device_t dev)
256 struct agp_i810_softc *sc = device_get_softc(dev);
259 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
260 if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32)
261 return 32 * 1024 * 1024;
263 return 64 * 1024 * 1024;
267 agp_i810_set_aperture(device_t dev, u_int32_t aperture)
269 struct agp_i810_softc *sc = device_get_softc(dev);
273 * Double check for sanity.
275 if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) {
276 device_printf(dev, "bad aperture size %d\n", aperture);
280 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
281 miscc &= ~AGP_I810_MISCC_WINSIZE;
282 if (aperture == 32 * 1024 * 1024)
283 miscc |= AGP_I810_MISCC_WINSIZE_32;
285 miscc |= AGP_I810_MISCC_WINSIZE_64;
287 pci_write_config(sc->bdev, AGP_I810_MISCC, miscc, 2);
293 agp_i810_bind_page(device_t dev, int offset, vm_offset_t physical)
295 struct agp_i810_softc *sc = device_get_softc(dev);
297 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
300 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1);
305 agp_i810_unbind_page(device_t dev, int offset)
307 struct agp_i810_softc *sc = device_get_softc(dev);
309 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
312 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0);
317 * Writing via memory mapped registers already flushes all TLBs.
320 agp_i810_flush_tlb(device_t dev)
325 agp_i810_enable(device_t dev, u_int32_t mode)
331 static struct agp_memory *
332 agp_i810_alloc_memory(device_t dev, int type, vm_size_t size)
334 struct agp_i810_softc *sc = device_get_softc(dev);
335 struct agp_memory *mem;
337 if ((size & (AGP_PAGE_SIZE - 1)) != 0)
340 if (sc->agp.as_allocated + size > sc->agp.as_maxmem)
345 * Mapping local DRAM into GATT.
347 if (size != sc->dcache_size)
349 } else if (type == 2) {
351 * Bogus mapping of a single page for the hardware cursor.
353 if (size != AGP_PAGE_SIZE)
357 mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
358 mem->am_id = sc->agp.as_nextid++;
362 mem->am_obj = vm_object_allocate(OBJT_DEFAULT,
363 atop(round_page(size)));
369 * Allocate and wire down the page now so that we can
370 * get its physical address.
373 m = vm_page_grab(mem->am_obj, 0, VM_ALLOC_ZERO|VM_ALLOC_RETRY);
374 vm_page_lock_queues();
376 mem->am_physical = VM_PAGE_TO_PHYS(m);
378 vm_page_unlock_queues();
380 mem->am_physical = 0;
384 mem->am_is_bound = 0;
385 TAILQ_INSERT_TAIL(&sc->agp.as_memory, mem, am_link);
386 sc->agp.as_allocated += size;
392 agp_i810_free_memory(device_t dev, struct agp_memory *mem)
394 struct agp_i810_softc *sc = device_get_softc(dev);
396 if (mem->am_is_bound)
399 if (mem->am_type == 2) {
401 * Unwire the page which we wired in alloc_memory.
403 vm_page_t m = vm_page_lookup(mem->am_obj, 0);
404 vm_page_lock_queues();
405 vm_page_unwire(m, 0);
406 vm_page_unlock_queues();
409 sc->agp.as_allocated -= mem->am_size;
410 TAILQ_REMOVE(&sc->agp.as_memory, mem, am_link);
412 vm_object_deallocate(mem->am_obj);
418 agp_i810_bind_memory(device_t dev, struct agp_memory *mem,
421 struct agp_i810_softc *sc = device_get_softc(dev);
424 if (mem->am_type != 1)
425 return agp_generic_bind_memory(dev, mem, offset);
427 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) {
428 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4,
436 agp_i810_unbind_memory(device_t dev, struct agp_memory *mem)
438 struct agp_i810_softc *sc = device_get_softc(dev);
441 if (mem->am_type != 1)
442 return agp_generic_unbind_memory(dev, mem);
444 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
445 WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0);
450 static device_method_t agp_i810_methods[] = {
451 /* Device interface */
452 DEVMETHOD(device_probe, agp_i810_probe),
453 DEVMETHOD(device_attach, agp_i810_attach),
454 DEVMETHOD(device_detach, agp_i810_detach),
455 DEVMETHOD(device_shutdown, bus_generic_shutdown),
456 DEVMETHOD(device_suspend, bus_generic_suspend),
457 DEVMETHOD(device_resume, bus_generic_resume),
460 DEVMETHOD(agp_get_aperture, agp_i810_get_aperture),
461 DEVMETHOD(agp_set_aperture, agp_i810_set_aperture),
462 DEVMETHOD(agp_bind_page, agp_i810_bind_page),
463 DEVMETHOD(agp_unbind_page, agp_i810_unbind_page),
464 DEVMETHOD(agp_flush_tlb, agp_i810_flush_tlb),
465 DEVMETHOD(agp_enable, agp_i810_enable),
466 DEVMETHOD(agp_alloc_memory, agp_i810_alloc_memory),
467 DEVMETHOD(agp_free_memory, agp_i810_free_memory),
468 DEVMETHOD(agp_bind_memory, agp_i810_bind_memory),
469 DEVMETHOD(agp_unbind_memory, agp_i810_unbind_memory),
474 static driver_t agp_i810_driver = {
477 sizeof(struct agp_i810_softc),
480 static devclass_t agp_devclass;
482 DRIVER_MODULE(agp_i810, pci, agp_i810_driver, agp_devclass, 0, 0);