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