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