Annotation of sys/dev/pci/agp_amd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: agp_amd.c,v 1.3 2007/08/04 19:40:25 reyk Exp $ */
! 2: /* $NetBSD: agp_amd.c,v 1.6 2001/10/06 02:48:50 thorpej Exp $ */
! 3:
! 4:
! 5: /*-
! 6: * Copyright (c) 2000 Doug Rabson
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: *
! 30: * $FreeBSD: src/sys/pci/agp_amd.c,v 1.6 2001/07/05 21:28:46 jhb Exp $
! 31: */
! 32:
! 33:
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/malloc.h>
! 38: #include <sys/kernel.h>
! 39: #include <sys/lock.h>
! 40: #include <sys/proc.h>
! 41: #include <sys/conf.h>
! 42: #include <sys/device.h>
! 43: #include <sys/agpio.h>
! 44:
! 45: #include <dev/pci/pcivar.h>
! 46: #include <dev/pci/pcireg.h>
! 47: #include <dev/pci/vga_pcivar.h>
! 48: #include <dev/pci/agpvar.h>
! 49: #include <dev/pci/agpreg.h>
! 50:
! 51: #include <dev/pci/pcidevs.h>
! 52:
! 53: #define READ2(off) bus_space_read_2(asc->iot, asc->ioh, off)
! 54: #define READ4(off) bus_space_read_4(asc->iot, asc->ioh, off)
! 55: #define WRITE2(off,v) bus_space_write_2(asc->iot, asc->ioh, off, v)
! 56: #define WRITE4(off,v) bus_space_write_4(asc->iot, asc->ioh, off, v)
! 57:
! 58: struct agp_amd_gatt {
! 59: bus_dmamap_t ag_dmamap;
! 60: bus_dma_segment_t ag_dmaseg;
! 61: int ag_nseg;
! 62: u_int32_t ag_entries;
! 63: u_int32_t *ag_vdir; /* virtual address of page dir */
! 64: bus_addr_t ag_pdir; /* bus address of page dir */
! 65: u_int32_t *ag_virtual; /* virtual address of gatt */
! 66: bus_addr_t ag_physical; /* bus address of gatt */
! 67: size_t ag_size;
! 68: };
! 69:
! 70: struct agp_amd_softc {
! 71: u_int32_t initial_aperture; /* aperture size at startup */
! 72: struct agp_amd_gatt *gatt;
! 73: bus_space_handle_t ioh;
! 74: bus_space_tag_t iot;
! 75: };
! 76:
! 77: static u_int32_t agp_amd_get_aperture(struct vga_pci_softc *);
! 78: static int agp_amd_set_aperture(struct vga_pci_softc *, u_int32_t);
! 79: static int agp_amd_bind_page(struct vga_pci_softc *, off_t, bus_addr_t);
! 80: static int agp_amd_unbind_page(struct vga_pci_softc *, off_t);
! 81: static void agp_amd_flush_tlb(struct vga_pci_softc *);
! 82:
! 83:
! 84: struct agp_methods agp_amd_methods = {
! 85: agp_amd_get_aperture,
! 86: agp_amd_set_aperture,
! 87: agp_amd_bind_page,
! 88: agp_amd_unbind_page,
! 89: agp_amd_flush_tlb,
! 90: agp_generic_enable,
! 91: agp_generic_alloc_memory,
! 92: agp_generic_free_memory,
! 93: agp_generic_bind_memory,
! 94: agp_generic_unbind_memory,
! 95: };
! 96:
! 97:
! 98: static struct agp_amd_gatt *
! 99: agp_amd_alloc_gatt(struct vga_pci_softc *sc)
! 100: {
! 101: u_int32_t apsize = AGP_GET_APERTURE(sc);
! 102: u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
! 103: struct agp_amd_gatt *gatt;
! 104: int i, npages;
! 105: caddr_t vdir;
! 106:
! 107: gatt = malloc(sizeof(struct agp_amd_gatt), M_DEVBUF, M_NOWAIT);
! 108: if (!gatt)
! 109: return (0);
! 110:
! 111: if (agp_alloc_dmamem(sc->sc_dmat,
! 112: AGP_PAGE_SIZE + entries * sizeof(u_int32_t), 0,
! 113: &gatt->ag_dmamap, &vdir, &gatt->ag_pdir,
! 114: &gatt->ag_dmaseg, 1, &gatt->ag_nseg) != 0) {
! 115: printf("failed to allocate GATT\n");
! 116: free(gatt, M_DEVBUF);
! 117: return (NULL);
! 118: }
! 119:
! 120: gatt->ag_vdir = (u_int32_t *)vdir;
! 121: gatt->ag_entries = entries;
! 122: gatt->ag_virtual = (u_int32_t *)(vdir + AGP_PAGE_SIZE);
! 123: gatt->ag_physical = gatt->ag_pdir + AGP_PAGE_SIZE;
! 124: gatt->ag_size = AGP_PAGE_SIZE + entries * sizeof(u_int32_t);
! 125:
! 126: memset(gatt->ag_vdir, 0, AGP_PAGE_SIZE);
! 127: memset(gatt->ag_virtual, 0, entries * sizeof(u_int32_t));
! 128:
! 129: /*
! 130: * Map the pages of the GATT into the page directory.
! 131: */
! 132: npages = ((entries * sizeof(u_int32_t) + AGP_PAGE_SIZE - 1)
! 133: >> AGP_PAGE_SHIFT);
! 134:
! 135: for (i = 0; i < npages; i++)
! 136: gatt->ag_vdir[i] = (gatt->ag_physical + i * AGP_PAGE_SIZE) | 1;
! 137:
! 138: /*
! 139: * Make sure the chipset can see everything.
! 140: */
! 141: agp_flush_cache();
! 142:
! 143: return (gatt);
! 144: }
! 145:
! 146: #if 0
! 147: static void
! 148: agp_amd_free_gatt(struct vga_pci_softc *sc, struct agp_amd_gatt *gatt)
! 149: {
! 150: agp_free_dmamem(sc->sc_dmat, gatt->ag_size,
! 151: gatt->ag_dmamap, (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg,
! 152: gatt->ag_nseg);
! 153: free(gatt, M_DEVBUF);
! 154: }
! 155: #endif
! 156:
! 157: int
! 158: agp_amd_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa)
! 159: {
! 160: struct agp_amd_softc *asc;
! 161: struct agp_amd_gatt *gatt;
! 162: pcireg_t reg;
! 163: int error;
! 164:
! 165: asc = malloc(sizeof *asc, M_DEVBUF, M_NOWAIT);
! 166: if (asc == NULL) {
! 167: printf(": can't allocate softc\n");
! 168: /* agp_generic_detach(sc) */
! 169: return (ENOMEM);
! 170: }
! 171: memset(asc, 0, sizeof *asc);
! 172:
! 173: error = pci_mapreg_map(pchb_pa, AGP_AMD751_REGISTERS,
! 174: PCI_MAPREG_TYPE_MEM,0, &asc->iot, &asc->ioh, NULL, NULL, 0);
! 175: if (error != 0) {
! 176: printf(": can't map AGP registers\n");
! 177: agp_generic_detach(sc);
! 178: return (error);
! 179: }
! 180:
! 181: if (agp_map_aperture(sc, AGP_APBASE, PCI_MAPREG_TYPE_MEM) != 0) {
! 182: printf(": can't map aperture\n");
! 183: agp_generic_detach(sc);
! 184: free(asc, M_DEVBUF);
! 185: return (ENXIO);
! 186: }
! 187: sc->sc_methods = &agp_amd_methods;
! 188: sc->sc_chipc = asc;
! 189: asc->initial_aperture = AGP_GET_APERTURE(sc);
! 190:
! 191: for (;;) {
! 192: gatt = agp_amd_alloc_gatt(sc);
! 193: if (gatt)
! 194: break;
! 195:
! 196: /*
! 197: * Probably contigmalloc failure. Try reducing the
! 198: * aperture so that the gatt size reduces.
! 199: */
! 200: if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) {
! 201: printf(": can't set aperture\n");
! 202: return (ENOMEM);
! 203: }
! 204: }
! 205: asc->gatt = gatt;
! 206:
! 207: /* Install the gatt. */
! 208: WRITE4(AGP_AMD751_ATTBASE, gatt->ag_physical);
! 209:
! 210: /* Enable synchronisation between host and agp. */
! 211: reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL);
! 212: reg &= ~0x00ff00ff;
! 213: reg |= (AGP_AMD751_MODECTRL_SYNEN) | (AGP_AMD751_MODECTRL2_GPDCE << 16);
! 214: pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL, reg);
! 215: /* Enable the TLB and flush */
! 216: WRITE2(AGP_AMD751_STATUS,
! 217: READ2(AGP_AMD751_STATUS) | AGP_AMD751_STATUS_GCE);
! 218: AGP_FLUSH_TLB(sc);
! 219:
! 220: return (0);
! 221: }
! 222:
! 223: #if 0
! 224: static int
! 225: agp_amd_detach(struct vga_pci_softc *sc)
! 226: {
! 227: pcireg_t reg;
! 228: struct agp_amd_softc *asc = sc->sc_chipc;
! 229:
! 230: /* Disable the TLB.. */
! 231: WRITE2(AGP_AMD751_STATUS,
! 232: READ2(AGP_AMD751_STATUS) & ~AGP_AMD751_STATUS_GCE);
! 233:
! 234: /* Disable host-agp sync */
! 235: reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL);
! 236: reg &= 0xffffff00;
! 237: pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL, reg);
! 238:
! 239: /* Clear the GATT base */
! 240: WRITE4(AGP_AMD751_ATTBASE, 0);
! 241:
! 242: /* Put the aperture back the way it started. */
! 243: AGP_SET_APERTURE(sc, asc->initial_aperture);
! 244:
! 245: agp_amd_free_gatt(sc, asc->gatt);
! 246:
! 247: /* XXXfvdl no pci_mapreg_unmap */
! 248:
! 249: return (0);
! 250: }
! 251: #endif
! 252:
! 253: static u_int32_t
! 254: agp_amd_get_aperture(struct vga_pci_softc *sc)
! 255: {
! 256: int vas;
! 257:
! 258: vas = (pci_conf_read(sc->sc_pc, sc->sc_pcitag,
! 259: AGP_AMD751_APCTRL) & 0x06);
! 260: vas >>= 1;
! 261: /*
! 262: * The aperture size is equal to 32M<<vas.
! 263: */
! 264: return ((32 * 1024 * 1024) << vas);
! 265: }
! 266:
! 267: static int
! 268: agp_amd_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture)
! 269: {
! 270: int vas;
! 271: pcireg_t reg;
! 272:
! 273: /*
! 274: * Check for a power of two and make sure its within the
! 275: * programmable range.
! 276: */
! 277: if (aperture & (aperture - 1)
! 278: || aperture < 32*1024*1024
! 279: || aperture > 2U*1024*1024*1024)
! 280: return (EINVAL);
! 281:
! 282: vas = ffs(aperture / 32*1024*1024) - 1;
! 283:
! 284: reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_APCTRL);
! 285: reg = (reg & ~0x06) | (vas << 1);
! 286: pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_APCTRL, reg);
! 287:
! 288: return (0);
! 289: }
! 290:
! 291: static int
! 292: agp_amd_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical)
! 293: {
! 294: struct agp_amd_softc *asc = sc->sc_chipc;
! 295:
! 296: if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
! 297: return (EINVAL);
! 298:
! 299: asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
! 300: return (0);
! 301: }
! 302:
! 303: static int
! 304: agp_amd_unbind_page(struct vga_pci_softc *sc, off_t offset)
! 305: {
! 306: struct agp_amd_softc *asc = sc->sc_chipc;
! 307:
! 308: if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
! 309: return (EINVAL);
! 310:
! 311: asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
! 312: return (0);
! 313: }
! 314:
! 315: static void
! 316: agp_amd_flush_tlb(struct vga_pci_softc *sc)
! 317: {
! 318: struct agp_amd_softc *asc = sc->sc_chipc;
! 319:
! 320: /* Set the cache invalidate bit and wait for the chipset to clear */
! 321: WRITE4(AGP_AMD751_TLBCTRL, 1);
! 322: do {
! 323: DELAY(1);
! 324: } while (READ4(AGP_AMD751_TLBCTRL));
! 325: }
CVSweb