1 /* $OpenBSD: agp_via.c,v 1.23 2024/05/24 06:02:53 jsg 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/device.h> 35 36 #include <dev/pci/pcivar.h> 37 #include <dev/pci/pcireg.h> 38 #include <dev/pci/pcidevs.h> 39 #include <dev/pci/agpvar.h> 40 #include <dev/pci/agpreg.h> 41 42 #include <machine/bus.h> 43 44 struct agp_via_softc { 45 struct device dev; 46 struct agp_softc *agpdev; 47 struct agp_gatt *gatt; 48 int *regs; 49 pci_chipset_tag_t vsc_pc; 50 pcitag_t vsc_tag; 51 bus_addr_t vsc_apaddr; 52 bus_size_t vsc_apsize; 53 pcireg_t vsc_regapsize; 54 pcireg_t vsc_regattbase; 55 pcireg_t vsc_reggartctl; 56 }; 57 58 void agp_via_attach(struct device *, struct device *, void *); 59 int agp_via_activate(struct device *, int); 60 void agp_via_save(struct agp_via_softc *); 61 void agp_via_restore(struct agp_via_softc *); 62 int agp_via_probe(struct device *, void *, void *); 63 bus_size_t agp_via_get_aperture(void *); 64 int agp_via_set_aperture(void *, bus_size_t); 65 void agp_via_bind_page(void *, bus_addr_t, paddr_t, int); 66 void agp_via_unbind_page(void *, bus_addr_t); 67 void agp_via_flush_tlb(void *); 68 69 const struct agp_methods agp_via_methods = { 70 agp_via_bind_page, 71 agp_via_unbind_page, 72 agp_via_flush_tlb, 73 }; 74 75 const struct cfattach viaagp_ca = { 76 sizeof(struct agp_via_softc), agp_via_probe, agp_via_attach, 77 NULL, agp_via_activate 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, 131 AGP_VIA_AGPSEL_REG); 132 if ((agpsel & (1 << 9)) == 0) { 133 vsc->regs = via_v3_regs; 134 printf(": v3"); 135 } else { 136 vsc->regs = via_v2_regs; 137 printf(": v2 compat mode"); 138 } 139 } else { 140 vsc->regs = via_v2_regs; 141 printf(": v2"); 142 } 143 144 145 vsc->vsc_apsize = agp_via_get_aperture(vsc); 146 147 for (;;) { 148 gatt = agp_alloc_gatt(pa->pa_dmat, vsc->vsc_apsize); 149 if (gatt != NULL) 150 break; 151 152 /* 153 * Probably failed to alloc contiguous memory. Try reducing the 154 * aperture so that the gatt size reduces. 155 */ 156 vsc->vsc_apsize /= 2; 157 if (agp_via_set_aperture(vsc, vsc->vsc_apsize)) { 158 printf(", can't set aperture size\n"); 159 return; 160 } 161 } 162 vsc->gatt = gatt; 163 164 if (vsc->regs == via_v2_regs) { 165 /* Install the gatt. */ 166 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE], 167 gatt->ag_physical | 3); 168 /* Enable the aperture. */ 169 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL], 170 0x0000000f); 171 } else { 172 pcireg_t gartctrl; 173 /* Install the gatt. */ 174 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE], 175 gatt->ag_physical); 176 /* Enable the aperture. */ 177 gartctrl = pci_conf_read(pa->pa_pc, pa->pa_tag, 178 vsc->regs[REG_ATTBASE]); 179 pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL], 180 gartctrl | (3 << 7)); 181 } 182 vsc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_via_methods, 183 vsc->vsc_apaddr, vsc->vsc_apsize, &vsc->dev); 184 185 return; 186 } 187 188 int 189 agp_via_activate(struct device *arg, int act) 190 { 191 struct agp_via_softc *vsc = (struct agp_via_softc *)arg; 192 193 switch (act) { 194 case DVACT_SUSPEND: 195 agp_via_save(vsc); 196 break; 197 case DVACT_RESUME: 198 agp_via_restore(vsc); 199 break; 200 } 201 202 return (0); 203 } 204 205 void 206 agp_via_save(struct agp_via_softc *vsc) 207 { 208 vsc->vsc_regapsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 209 vsc->regs[REG_APSIZE]); 210 vsc->vsc_regattbase = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 211 vsc->regs[REG_ATTBASE]); 212 vsc->vsc_reggartctl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 213 vsc->regs[REG_GARTCTRL]); 214 } 215 void 216 agp_via_restore(struct agp_via_softc *vsc) 217 { 218 219 /* aperture size */ 220 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE], 221 vsc->vsc_regapsize); 222 /* GATT address and enable */ 223 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_ATTBASE], 224 vsc->vsc_regattbase); 225 /* Turn it all back on. */ 226 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_GARTCTRL], 227 vsc->vsc_reggartctl); 228 /* flush the tlb, just in case */ 229 agp_via_flush_tlb(vsc); 230 } 231 232 bus_size_t 233 agp_via_get_aperture(void *sc) 234 { 235 struct agp_via_softc *vsc = sc; 236 bus_size_t apsize; 237 238 apsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 239 vsc->regs[REG_APSIZE]) & 0x1f; 240 241 /* 242 * The size is determined by the number of low bits of 243 * register APBASE which are forced to zero. The low 20 bits 244 * are always forced to zero and each zero bit in the apsize 245 * field just read forces the corresponding bit in the 27:20 246 * to be zero. We calculate the aperture size accordingly. 247 */ 248 return ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1); 249 } 250 251 int 252 agp_via_set_aperture(void *sc, bus_size_t aperture) 253 { 254 struct agp_via_softc *vsc = sc; 255 bus_size_t apsize; 256 pcireg_t reg; 257 258 /* 259 * Reverse the magic from get_aperture. 260 */ 261 apsize = ((aperture - 1) >> 20) ^ 0xff; 262 263 /* 264 * Double check for sanity. 265 */ 266 if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture) 267 return (EINVAL); 268 269 reg = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE]); 270 reg &= ~0xff; 271 reg |= apsize; 272 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE], reg); 273 274 return (0); 275 } 276 277 void 278 agp_via_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 279 { 280 struct agp_via_softc *vsc = sc; 281 282 vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 283 physical; 284 } 285 286 void 287 agp_via_unbind_page(void *sc, bus_addr_t offset) 288 { 289 struct agp_via_softc *vsc = sc; 290 291 vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 0; 292 } 293 294 void 295 agp_via_flush_tlb(void *sc) 296 { 297 struct agp_via_softc *vsc = sc; 298 pcireg_t gartctrl; 299 300 if (vsc->regs == via_v2_regs) { 301 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 302 vsc->regs[REG_GARTCTRL], 0x8f); 303 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 304 vsc->regs[REG_GARTCTRL], 0x0f); 305 } else { 306 gartctrl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, 307 vsc->regs[REG_GARTCTRL]); 308 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 309 vsc->regs[REG_GARTCTRL], gartctrl & ~(1 << 7)); 310 pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, 311 vsc->regs[REG_GARTCTRL], gartctrl); 312 } 313 } 314