1/* $NetBSD$ */ 2 3/*- 4 * Copyright (c) 2007 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD$"); 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/malloc.h> 34#include <sys/kernel.h> 35#include <sys/proc.h> 36#include <sys/conf.h> 37#include <sys/device.h> 38#include <sys/agpio.h> 39 40#include <dev/pci/pcivar.h> 41#include <dev/pci/pcireg.h> 42#include <dev/pci/agpvar.h> 43#include <dev/pci/agpreg.h> 44 45#include <sys/bus.h> 46 47static u_int32_t agp_apple_get_aperture(struct agp_softc *); 48static int agp_apple_set_aperture(struct agp_softc *, u_int32_t); 49static int agp_apple_bind_page(struct agp_softc *, off_t, bus_addr_t); 50static int agp_apple_unbind_page(struct agp_softc *, off_t); 51static void agp_apple_flush_tlb(struct agp_softc *); 52 53static struct agp_methods agp_apple_methods = { 54 agp_apple_get_aperture, 55 agp_apple_set_aperture, 56 agp_apple_bind_page, 57 agp_apple_unbind_page, 58 agp_apple_flush_tlb, 59 agp_generic_enable, 60 agp_generic_alloc_memory, 61 agp_generic_free_memory, 62 agp_generic_bind_memory, 63 agp_generic_unbind_memory, 64}; 65 66struct agp_apple_softc { 67 u_int32_t initial_aperture; /* aperture size at startup */ 68 struct agp_gatt *gatt; 69}; 70 71int 72agp_apple_attach(device_t parent, device_t self, void *aux) 73{ 74 struct pci_attach_args *pa = aux; 75 struct agp_softc *sc = device_private(self); 76 struct agp_apple_softc *asc; 77 struct agp_gatt *gatt; 78 79 asc = malloc(sizeof *asc, M_AGP, M_NOWAIT|M_ZERO); 80 if (asc == NULL) { 81 aprint_error(": can't allocate chipset-specific softc\n"); 82 return ENOMEM; 83 } 84 sc->as_chipc = asc; 85 sc->as_methods = &agp_apple_methods; 86 pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, &sc->as_capoff, 87 NULL); 88 89 sc->as_apaddr = 0; 90 sc->as_apsize = 8 * 1024 * 1024; 91 sc->as_apflags = 0; 92 sc->as_pc = pa->pa_pc; 93 sc->as_tag = pa->pa_tag; 94 sc->as_apt = pa->pa_memt; 95 96 asc->initial_aperture = sc->as_apsize; 97 98 for (;;) { 99 gatt = agp_alloc_gatt(sc); 100 if (gatt) 101 break; 102 sc->as_apsize = sc->as_apsize >> 1; 103 if (sc->as_apsize == 0) { 104 aprint_error(": can't set aperture size\n"); 105 return ENOMEM; 106 } 107 } 108 asc->gatt = gatt; 109 110 /* Install the gatt. */ 111 aprint_error("gatt: %08x %d MB\n", gatt->ag_physical, sc->as_apsize >> 20); 112 pci_conf_write(pa->pa_pc, pa->pa_tag, APPLE_UNINORTH_GART_BASE, 113 (gatt->ag_physical & 0xfffff000) | 114 (sc->as_apsize >> 22)); 115 116 /* Enable the aperture. */ 117 pci_conf_write(pa->pa_pc, pa->pa_tag, APPLE_UNINORTH_GART_CTRL, 118 APPLE_GART_EN); 119 pci_conf_write(pa->pa_pc, pa->pa_tag, APPLE_UNINORTH_GART_CTRL, 120 APPLE_GART_EN | APPLE_GART_INV); 121 pci_conf_write(pa->pa_pc, pa->pa_tag, APPLE_UNINORTH_GART_CTRL, 122 APPLE_GART_EN); 123 return 0; 124} 125 126static u_int32_t 127agp_apple_get_aperture(struct agp_softc *sc) 128{ 129#if 0 130 u_int32_t apsize = 0; 131 132 aprint_error("%s: ", __func__); 133 apsize = pci_conf_read(sc->as_pc, sc->as_tag, 134 APPLE_UNINORTH_GART_BASE) & 0x0000ffff; 135 aprint_error("%08x\n", apsize); 136 return (apsize << 22); 137#else 138 return sc->as_apsize; 139#endif 140} 141 142static int 143agp_apple_set_aperture(struct agp_softc *sc, u_int32_t aperture) 144{ 145 pcireg_t reg; 146 147 aprint_error("%s: %08x\n", __func__, aperture); 148 reg = pci_conf_read(sc->as_pc, sc->as_tag, APPLE_UNINORTH_GART_BASE) 149 & 0xfffff000; 150 reg |= ((aperture >> 22) & 0xfff); 151 pci_conf_write(sc->as_pc, sc->as_tag, APPLE_UNINORTH_GART_BASE, reg); 152 sc->as_apsize = aperture; 153 return 0; 154} 155 156static int 157agp_apple_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical) 158{ 159 struct agp_apple_softc *asc = sc->as_chipc; 160 161 if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) 162 return EINVAL; 163 164 asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = htole32(physical); 165 return 0; 166} 167 168static int 169agp_apple_unbind_page(struct agp_softc *sc, off_t offset) 170{ 171 struct agp_apple_softc *asc = sc->as_chipc; 172 173 if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) 174 return EINVAL; 175 176 asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 177 return 0; 178} 179 180static void 181agp_apple_flush_tlb(struct agp_softc *sc) 182{ 183 184 pci_conf_write(sc->as_pc, sc->as_tag, APPLE_UNINORTH_GART_CTRL, 185 APPLE_GART_EN); 186 pci_conf_write(sc->as_pc, sc->as_tag, APPLE_UNINORTH_GART_CTRL, 187 APPLE_GART_EN | APPLE_GART_INV); 188 pci_conf_write(sc->as_pc, sc->as_tag, APPLE_UNINORTH_GART_CTRL, 189 APPLE_GART_EN); 190} 191