1 /* $OpenBSD: agp_via.c,v 1.14 2009/05/10 16:57:44 oga Exp $ */ 2 /* $NetBSD: agp_via.c,v 1.2 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_via.c,v 1.3 2001/07/05 21:28:47 jhb Exp $ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/proc.h> 38 #include <sys/conf.h> 39 #include <sys/device.h> 40 #include <sys/agpio.h> 41 42 #include <dev/pci/pcivar.h> 43 #include <dev/pci/pcireg.h> 44 #include <dev/pci/pcidevs.h> 45 #include <dev/pci/vga_pcivar.h> 46 #include <dev/pci/agpvar.h> 47 #include <dev/pci/agpreg.h> 48 49 #include <machine/bus.h> 50 51 void agp_via_attach(struct device *, struct device *, void *); 52 int agp_via_probe(struct device *, void *, void *); 53 bus_size_t agp_via_get_aperture(void *); 54 int agp_via_set_aperture(void *, bus_size_t); 55 void agp_via_bind_page(void *, bus_addr_t, paddr_t, int); 56 void agp_via_unbind_page(void *, bus_addr_t); 57 void agp_via_flush_tlb(void *); 58 59 const struct agp_methods agp_via_methods = { 60 agp_via_bind_page, 61 agp_via_unbind_page, 62 agp_via_flush_tlb, 63 }; 64 65 struct agp_via_softc { 66 struct device dev; 67 struct agp_softc *agpdev; 68 struct agp_gatt *gatt; 69 int *regs; 70 pci_chipset_tag_t vsc_pc; 71 pcitag_t vsc_tag; 72 bus_addr_t vsc_apaddr; 73 bus_size_t vsc_apsize; 74 }; 75 76 struct cfattach viaagp_ca = { 77 sizeof(struct agp_via_softc), agp_via_probe, agp_via_attach 78 }; 79 80 struct cfdriver viaagp_cd = { 81 NULL, "viaagp", DV_DULL 82 }; 83 84 #define REG_GARTCTRL 0 85 #define REG_APSIZE 1 86 #define REG_ATTBASE 2 87 88 int via_v2_regs[] = 89 { AGP_VIA_GARTCTRL, AGP_VIA_APSIZE, AGP_VIA_ATTBASE }; 90 int via_v3_regs[] = 91 { AGP3_VIA_GARTCTRL, AGP3_VIA_APSIZE, AGP3_VIA_ATTBASE }; 92 93 int 94 agp_via_probe(struct device *parent, void *match, void *aux) 95 { 96 struct agp_attach_args *aa = aux; 97 struct pci_attach_args *pa = aa->aa_pa; 98 99 /* Must be a pchb don't attach to iommu-style agp devs */ 100 if (agpbus_probe(aa) == 1 && 101 PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VIATECH && 102 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8M800_0 && 103 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8T890_0 && 104 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8HTB_0 && 105 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8HTB) 106 return (1); 107 return (0); 108 } 109 110 void 111 agp_via_attach(struct device *parent, struct device *self, void *aux) 112 { 113 struct agp_via_softc *vsc = (struct agp_via_softc *)self; 114 struct agp_attach_args *aa = aux; 115 struct pci_attach_args *pa = aa->aa_pa; 116 struct agp_gatt *gatt; 117 pcireg_t agpsel, capval; 118 119 vsc->vsc_pc = pa->pa_pc; 120 vsc->vsc_tag = pa->pa_tag; 121 pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, NULL, &capval); 122 123 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE, 124 PCI_MAPREG_TYPE_MEM, &vsc->vsc_apaddr, NULL, NULL) != 0) { 125 printf(": can't get aperture info\n"); 126 return; 127 } 128 129 if (AGP_CAPID_GET_MAJOR(capval) >= 3) { 130 agpsel = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_VIA_AGPSEL); 131 if ((agpsel & (1 << 1)) == 0) { 132 vsc->regs = via_v3_regs; 133 printf(": v3"); 134 } else { 135 vsc->regs = via_v2_regs; 136 printf(": v2 compat mode"); 137 } 138 } else { 139 vsc->regs = via_v2_regs; 140 printf(": v2"); 141 } 142 143 144 vsc->vsc_apsize = agp_via_get_aperture(vsc); 145 146 for (;;) { 147 gatt = agp_alloc_gatt(pa->pa_dmat, vsc->vsc_apsize); 148 if (gatt != NULL) 149 break; 150 151 /* 152 * Probably failed to alloc congigious memory. Try reducing the 153 * aperture so that the gatt size reduces. 154 */ 155 vsc->vsc_apsize /= 2; 156 if (agp_via_set_aperture(vsc, vsc->vsc_apsize)) { 157 printf(", can't set aperture size\n"); 158 return; 159 } 160 } 161 vsc->gatt = gatt; 162 163 if (vsc->regs == via_v2_regs) { 164 /* Install the gatt. */ 165 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE], 166 gatt->ag_physical | 3); 167 /* Enable the aperture. */ 168 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL], 169 0x0000000f); 170 } else { 171 pcireg_t gartctrl; 172 /* Install the gatt. */ 173 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE], 174 gatt->ag_physical); 175 /* Enable the aperture. */ 176 gartctrl = pci_conf_read(pa->pa_pc, pa->pa_tag, 177 vsc->regs[REG_ATTBASE]); 178 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL], 179 gartctrl | (3 << 7)); 180 } 181 vsc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_via_methods, 182 vsc->vsc_apaddr, vsc->vsc_apsize, &vsc->dev); 183 184 return; 185 } 186 187 #if 0 188 int 189 agp_via_detach(struct agp_softc *sc) 190 { 191 struct agp_via_softc *vsc = sc->sc_chipc; 192 int error; 193 194 error = agp_generic_detach(sc); 195 if (error) 196 return (error); 197 198 pci_conf_write(sc->as_pc, sc->as_tag, vsc->regs[REG_GARTCTRL], 0); 199 pci_conf_write(sc->as_pc, sc->as_tag, vsc->regs[REG_ATTBASE], 0); 200 AGP_SET_APERTURE(sc, vsc->initial_aperture); 201 agp_free_gatt(sc, vsc->gatt); 202 203 return (0); 204 } 205 #endif 206 207 bus_size_t 208 agp_via_get_aperture(void *sc) 209 { 210 struct agp_via_softc *vsc = sc; 211 bus_size_t apsize; 212 213 apsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 214 vsc->regs[REG_APSIZE]) & 0x1f; 215 216 /* 217 * The size is determined by the number of low bits of 218 * register APBASE which are forced to zero. The low 20 bits 219 * are always forced to zero and each zero bit in the apsize 220 * field just read forces the corresponding bit in the 27:20 221 * to be zero. We calculate the aperture size accordingly. 222 */ 223 return ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1); 224 } 225 226 int 227 agp_via_set_aperture(void *sc, bus_size_t aperture) 228 { 229 struct agp_via_softc *vsc = sc; 230 bus_size_t apsize; 231 pcireg_t reg; 232 233 /* 234 * Reverse the magic from get_aperture. 235 */ 236 apsize = ((aperture - 1) >> 20) ^ 0xff; 237 238 /* 239 * Double check for sanity. 240 */ 241 if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture) 242 return (EINVAL); 243 244 reg = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE]); 245 reg &= ~0xff; 246 reg |= apsize; 247 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE], reg); 248 249 return (0); 250 } 251 252 void 253 agp_via_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 254 { 255 struct agp_via_softc *vsc = sc; 256 257 vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 258 physical; 259 } 260 261 void 262 agp_via_unbind_page(void *sc, bus_addr_t offset) 263 { 264 struct agp_via_softc *vsc = sc; 265 266 vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 0; 267 } 268 269 void 270 agp_via_flush_tlb(void *sc) 271 { 272 struct agp_via_softc *vsc = sc; 273 pcireg_t gartctrl; 274 275 if (vsc->regs == via_v2_regs) { 276 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 277 vsc->regs[REG_GARTCTRL], 0x8f); 278 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 279 vsc->regs[REG_GARTCTRL], 0x0f); 280 } else { 281 gartctrl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 282 vsc->regs[REG_GARTCTRL]); 283 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 284 vsc->regs[REG_GARTCTRL], gartctrl & ~(1 << 7)); 285 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 286 vsc->regs[REG_GARTCTRL], gartctrl); 287 } 288 } 289