1 /* $OpenBSD: agp_via.c,v 1.16 2010/08/07 19:31:23 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/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, AGP_VIA_AGPSEL); 137 if ((agpsel & (1 << 1)) == 0) { 138 vsc->regs = via_v3_regs; 139 printf(": v3"); 140 } else { 141 vsc->regs = via_v2_regs; 142 printf(": v2 compat mode"); 143 } 144 } else { 145 vsc->regs = via_v2_regs; 146 printf(": v2"); 147 } 148 149 150 vsc->vsc_apsize = agp_via_get_aperture(vsc); 151 152 for (;;) { 153 gatt = agp_alloc_gatt(pa->pa_dmat, vsc->vsc_apsize); 154 if (gatt != NULL) 155 break; 156 157 /* 158 * Probably failed to alloc congigious memory. Try reducing the 159 * aperture so that the gatt size reduces. 160 */ 161 vsc->vsc_apsize /= 2; 162 if (agp_via_set_aperture(vsc, vsc->vsc_apsize)) { 163 printf(", can't set aperture size\n"); 164 return; 165 } 166 } 167 vsc->gatt = gatt; 168 169 if (vsc->regs == via_v2_regs) { 170 /* Install the gatt. */ 171 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE], 172 gatt->ag_physical | 3); 173 /* Enable the aperture. */ 174 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL], 175 0x0000000f); 176 } else { 177 pcireg_t gartctrl; 178 /* Install the gatt. */ 179 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE], 180 gatt->ag_physical); 181 /* Enable the aperture. */ 182 gartctrl = pci_conf_read(pa->pa_pc, pa->pa_tag, 183 vsc->regs[REG_ATTBASE]); 184 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL], 185 gartctrl | (3 << 7)); 186 } 187 vsc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_via_methods, 188 vsc->vsc_apaddr, vsc->vsc_apsize, &vsc->dev); 189 190 return; 191 } 192 193 #if 0 194 int 195 agp_via_detach(struct agp_softc *sc) 196 { 197 struct agp_via_softc *vsc = sc->sc_chipc; 198 int error; 199 200 error = agp_generic_detach(sc); 201 if (error) 202 return (error); 203 204 pci_conf_write(sc->as_pc, sc->as_tag, vsc->regs[REG_GARTCTRL], 0); 205 pci_conf_write(sc->as_pc, sc->as_tag, vsc->regs[REG_ATTBASE], 0); 206 AGP_SET_APERTURE(sc, vsc->initial_aperture); 207 agp_free_gatt(sc, vsc->gatt); 208 209 return (0); 210 } 211 #endif 212 213 int 214 agp_via_activate(struct device *arg, int act) 215 { 216 struct agp_via_softc *vsc = (struct agp_via_softc *)arg; 217 218 switch (act) { 219 case DVACT_SUSPEND: 220 agp_via_save(vsc); 221 break; 222 case DVACT_RESUME: 223 agp_via_restore(vsc); 224 break; 225 } 226 227 return (0); 228 } 229 230 void 231 agp_via_save(struct agp_via_softc *vsc) 232 { 233 vsc->vsc_regapsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 234 vsc->regs[REG_APSIZE]); 235 vsc->vsc_regattbase = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 236 vsc->regs[REG_ATTBASE]); 237 vsc->vsc_reggartctl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 238 vsc->regs[REG_GARTCTRL]); 239 } 240 void 241 agp_via_restore(struct agp_via_softc *vsc) 242 { 243 244 /* aperture size */ 245 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE], 246 vsc->vsc_regapsize); 247 /* GATT address and enable */ 248 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_ATTBASE], 249 vsc->vsc_regattbase); 250 /* Turn it all back on. */ 251 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_GARTCTRL], 252 vsc->vsc_reggartctl); 253 /* flush the tlb, just in case */ 254 agp_via_flush_tlb(vsc); 255 } 256 257 bus_size_t 258 agp_via_get_aperture(void *sc) 259 { 260 struct agp_via_softc *vsc = sc; 261 bus_size_t apsize; 262 263 apsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 264 vsc->regs[REG_APSIZE]) & 0x1f; 265 266 /* 267 * The size is determined by the number of low bits of 268 * register APBASE which are forced to zero. The low 20 bits 269 * are always forced to zero and each zero bit in the apsize 270 * field just read forces the corresponding bit in the 27:20 271 * to be zero. We calculate the aperture size accordingly. 272 */ 273 return ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1); 274 } 275 276 int 277 agp_via_set_aperture(void *sc, bus_size_t aperture) 278 { 279 struct agp_via_softc *vsc = sc; 280 bus_size_t apsize; 281 pcireg_t reg; 282 283 /* 284 * Reverse the magic from get_aperture. 285 */ 286 apsize = ((aperture - 1) >> 20) ^ 0xff; 287 288 /* 289 * Double check for sanity. 290 */ 291 if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture) 292 return (EINVAL); 293 294 reg = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE]); 295 reg &= ~0xff; 296 reg |= apsize; 297 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE], reg); 298 299 return (0); 300 } 301 302 void 303 agp_via_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 304 { 305 struct agp_via_softc *vsc = sc; 306 307 vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 308 physical; 309 } 310 311 void 312 agp_via_unbind_page(void *sc, bus_addr_t offset) 313 { 314 struct agp_via_softc *vsc = sc; 315 316 vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 0; 317 } 318 319 void 320 agp_via_flush_tlb(void *sc) 321 { 322 struct agp_via_softc *vsc = sc; 323 pcireg_t gartctrl; 324 325 if (vsc->regs == via_v2_regs) { 326 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 327 vsc->regs[REG_GARTCTRL], 0x8f); 328 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 329 vsc->regs[REG_GARTCTRL], 0x0f); 330 } else { 331 gartctrl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 332 vsc->regs[REG_GARTCTRL]); 333 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 334 vsc->regs[REG_GARTCTRL], gartctrl & ~(1 << 7)); 335 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 336 vsc->regs[REG_GARTCTRL], gartctrl); 337 } 338 } 339