1 /* $OpenBSD: agp_intel.c,v 1.26 2024/05/24 06:02:53 jsg Exp $ */ 2 /* $NetBSD: agp_intel.c,v 1.3 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_intel.c,v 1.4 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_intel_softc { 45 struct device dev; 46 struct agp_softc *agpdev; 47 struct agp_gatt *gatt; 48 pci_chipset_tag_t isc_pc; 49 pcitag_t isc_tag; 50 bus_addr_t isc_apaddr; 51 bus_size_t isc_apsize; 52 u_int aperture_mask; 53 enum { 54 CHIP_INTEL, 55 CHIP_I443, 56 CHIP_I840, 57 CHIP_I845, 58 CHIP_I850, 59 CHIP_I865 60 } chiptype; 61 /* registers saved during a suspend/resume cycle. */ 62 pcireg_t savectrl; 63 pcireg_t savecmd; 64 pcireg_t savecfg; 65 }; 66 67 68 void agp_intel_attach(struct device *, struct device *, void *); 69 int agp_intel_activate(struct device *, int); 70 void agp_intel_save(struct agp_intel_softc *); 71 void agp_intel_restore(struct agp_intel_softc *); 72 int agp_intel_probe(struct device *, void *, void *); 73 bus_size_t agp_intel_get_aperture(void *); 74 int agp_intel_set_aperture(void *, bus_size_t); 75 void agp_intel_bind_page(void *, bus_addr_t, paddr_t, int); 76 void agp_intel_unbind_page(void *, bus_addr_t); 77 void agp_intel_flush_tlb(void *); 78 79 const struct cfattach intelagp_ca = { 80 sizeof(struct agp_intel_softc), agp_intel_probe, agp_intel_attach, 81 NULL, agp_intel_activate 82 }; 83 84 struct cfdriver intelagp_cd = { 85 NULL, "intelagp", DV_DULL 86 }; 87 88 const struct agp_methods agp_intel_methods = { 89 agp_intel_bind_page, 90 agp_intel_unbind_page, 91 agp_intel_flush_tlb, 92 /* default enable and memory routines */ 93 }; 94 95 int 96 agp_intel_probe(struct device *parent, void *match, void *aux) 97 { 98 struct agp_attach_args *aa = aux; 99 struct pci_attach_args *pa = aa->aa_pa; 100 101 /* Must be a pchb */ 102 if (agpbus_probe(aa) == 0) 103 return (0); 104 105 switch (PCI_PRODUCT(pa->pa_id)) { 106 case PCI_PRODUCT_INTEL_82443LX: 107 case PCI_PRODUCT_INTEL_82443BX: 108 case PCI_PRODUCT_INTEL_82440BX: 109 case PCI_PRODUCT_INTEL_82440BX_AGP: 110 case PCI_PRODUCT_INTEL_82815_HB: 111 case PCI_PRODUCT_INTEL_82820_HB: 112 case PCI_PRODUCT_INTEL_82830M_HB: 113 case PCI_PRODUCT_INTEL_82840_HB: 114 case PCI_PRODUCT_INTEL_82845_HB: 115 case PCI_PRODUCT_INTEL_82845G_HB: 116 case PCI_PRODUCT_INTEL_82850_HB: 117 case PCI_PRODUCT_INTEL_82855PM_HB: 118 case PCI_PRODUCT_INTEL_82855GM_HB: 119 case PCI_PRODUCT_INTEL_82860_HB: 120 case PCI_PRODUCT_INTEL_82865G_HB: 121 case PCI_PRODUCT_INTEL_82875P_HB: 122 return (1); 123 } 124 125 return (0); 126 } 127 128 void 129 agp_intel_attach(struct device *parent, struct device *self, void *aux) 130 { 131 struct agp_intel_softc *isc = (struct agp_intel_softc *)self; 132 struct agp_attach_args *aa = aux; 133 struct pci_attach_args *pa = aa->aa_pa; 134 struct agp_gatt *gatt; 135 pcireg_t reg; 136 u_int32_t value; 137 138 isc->isc_pc = pa->pa_pc; 139 isc->isc_tag = pa->pa_tag; 140 141 switch (PCI_PRODUCT(pa->pa_id)) { 142 case PCI_PRODUCT_INTEL_82443LX: 143 case PCI_PRODUCT_INTEL_82443BX: 144 case PCI_PRODUCT_INTEL_82440BX: 145 case PCI_PRODUCT_INTEL_82440BX_AGP: 146 isc->chiptype = CHIP_I443; 147 break; 148 case PCI_PRODUCT_INTEL_82830M_HB: 149 case PCI_PRODUCT_INTEL_82840_HB: 150 isc->chiptype = CHIP_I840; 151 break; 152 case PCI_PRODUCT_INTEL_82845_HB: 153 case PCI_PRODUCT_INTEL_82845G_HB: 154 case PCI_PRODUCT_INTEL_82855PM_HB: 155 isc->chiptype = CHIP_I845; 156 break; 157 case PCI_PRODUCT_INTEL_82850_HB: 158 isc->chiptype = CHIP_I850; 159 break; 160 case PCI_PRODUCT_INTEL_82865G_HB: 161 case PCI_PRODUCT_INTEL_82875P_HB: 162 isc->chiptype = CHIP_I865; 163 break; 164 default: 165 isc->chiptype = CHIP_INTEL; 166 break; 167 } 168 169 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE, 170 PCI_MAPREG_TYPE_MEM, &isc->isc_apaddr, NULL, NULL) != 0) { 171 printf(": can't get aperture info\n"); 172 return; 173 } 174 175 /* Determine maximum supported aperture size. */ 176 value = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE); 177 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, APSIZE_MASK); 178 isc->aperture_mask = pci_conf_read(pa->pa_pc, pa->pa_tag, 179 AGP_INTEL_APSIZE) & APSIZE_MASK; 180 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, value); 181 isc->isc_apsize = agp_intel_get_aperture(isc); 182 183 for (;;) { 184 gatt = agp_alloc_gatt(pa->pa_dmat, isc->isc_apsize); 185 if (gatt != NULL) 186 break; 187 188 /* 189 * almost certainly error allocating contiguous dma memory 190 * so reduce aperture so that the gatt size reduces. 191 */ 192 isc->isc_apsize /= 2; 193 if (agp_intel_set_aperture(isc, isc->isc_apsize)) { 194 printf(": failed to set aperture\n"); 195 return; 196 } 197 } 198 isc->gatt = gatt; 199 200 /* Install the gatt. */ 201 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ATTBASE, 202 gatt->ag_physical); 203 204 /* Enable the GLTB and setup the control register. */ 205 switch (isc->chiptype) { 206 case CHIP_I443: 207 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 208 AGPCTRL_AGPRSE | AGPCTRL_GTLB); 209 break; 210 default: 211 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 212 pci_conf_read(isc->isc_pc, isc->isc_tag, 213 AGP_INTEL_AGPCTRL) | AGPCTRL_GTLB); 214 break; 215 } 216 217 /* Enable things, clear errors etc. */ 218 switch (isc->chiptype) { 219 case CHIP_I845: 220 case CHIP_I865: 221 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG); 222 reg |= MCHCFG_AAGN; 223 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG, reg); 224 break; 225 case CHIP_I840: 226 case CHIP_I850: 227 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD); 228 reg |= AGPCMD_AGPEN; 229 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD, 230 reg); 231 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG); 232 reg |= MCHCFG_AAGN; 233 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG, 234 reg); 235 break; 236 default: 237 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG); 238 reg &= ~NBXCFG_APAE; 239 reg |= NBXCFG_AAGN; 240 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG, reg); 241 break; 242 } 243 244 /* Clear Error status */ 245 switch (isc->chiptype) { 246 case CHIP_I840: 247 pci_conf_write(pa->pa_pc, pa->pa_tag, 248 AGP_INTEL_I8XX_ERRSTS, 0xc000); 249 break; 250 case CHIP_I845: 251 case CHIP_I850: 252 case CHIP_I865: 253 pci_conf_write(isc->isc_pc, isc->isc_tag, 254 AGP_INTEL_I8XX_ERRSTS, 0x00ff); 255 break; 256 257 default: 258 reg = pci_conf_read(isc->isc_pc, isc->isc_tag, 259 AGP_INTEL_ERRCMD); 260 pci_conf_write(isc->isc_pc, isc->isc_tag, 261 AGP_INTEL_ERRCMD, reg); 262 } 263 264 isc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_intel_methods, 265 isc->isc_apaddr, isc->isc_apsize, &isc->dev); 266 return; 267 } 268 269 int 270 agp_intel_activate(struct device *arg, int act) 271 { 272 struct agp_intel_softc *isc = (struct agp_intel_softc *)arg; 273 274 switch (act) { 275 case DVACT_SUSPEND: 276 agp_intel_save(isc); 277 break; 278 case DVACT_RESUME: 279 agp_intel_restore(isc); 280 break; 281 } 282 283 return (0); 284 } 285 286 void 287 agp_intel_save(struct agp_intel_softc *isc) 288 { 289 290 if (isc->chiptype != CHIP_I443) { 291 isc->savectrl = pci_conf_read(isc->isc_pc, isc->isc_tag, 292 AGP_INTEL_AGPCTRL); 293 } 294 295 switch (isc->chiptype) { 296 case CHIP_I845: 297 case CHIP_I865: 298 isc->savecmd = pci_conf_read(isc->isc_pc, isc->isc_tag, 299 AGP_I840_MCHCFG); 300 301 break; 302 case CHIP_I840: 303 case CHIP_I850: 304 isc->savecmd = pci_conf_read(isc->isc_pc, isc->isc_tag, 305 AGP_INTEL_AGPCMD); 306 isc->savecfg = pci_conf_read(isc->isc_pc, isc->isc_tag, 307 AGP_I840_MCHCFG); 308 309 break; 310 default: 311 isc->savecfg = pci_conf_read(isc->isc_pc, isc->isc_tag, 312 AGP_INTEL_NBXCFG); 313 break; 314 } 315 } 316 317 void 318 agp_intel_restore(struct agp_intel_softc *isc) 319 { 320 pcireg_t tmp; 321 /* 322 * reset size now just in case, if it worked before then sanity 323 * checking will not fail 324 */ 325 (void)agp_intel_set_aperture(isc, isc->isc_apsize); 326 327 /* Install the gatt. */ 328 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_ATTBASE, 329 isc->gatt->ag_physical); 330 331 /* Enable the GLTB and setup the control register. */ 332 switch (isc->chiptype) { 333 case CHIP_I443: 334 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 335 AGPCTRL_AGPRSE | AGPCTRL_GTLB); 336 break; 337 default: 338 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 339 isc->savectrl); 340 break; 341 } 342 343 /* Enable things, clear errors etc. */ 344 switch (isc->chiptype) { 345 case CHIP_I845: 346 case CHIP_I865: 347 pci_conf_write(isc->isc_pc, isc->isc_tag, 348 AGP_I840_MCHCFG, isc->savecmd); 349 break; 350 case CHIP_I840: 351 case CHIP_I850: 352 pci_conf_write(isc->isc_pc, isc->isc_tag, 353 AGP_INTEL_AGPCMD, isc->savecmd); 354 pci_conf_write(isc->isc_pc, isc->isc_tag, 355 AGP_I840_MCHCFG, isc->savecfg); 356 break; 357 default: 358 pci_conf_write(isc->isc_pc, isc->isc_tag, 359 AGP_INTEL_NBXCFG, isc->savecfg); 360 break; 361 } 362 363 /* Clear Error status */ 364 switch (isc->chiptype) { 365 case CHIP_I840: 366 pci_conf_write(isc->isc_pc, isc->isc_tag, 367 AGP_INTEL_I8XX_ERRSTS, 0xc000); 368 break; 369 case CHIP_I845: 370 case CHIP_I850: 371 case CHIP_I865: 372 pci_conf_write(isc->isc_pc, isc->isc_tag, 373 AGP_INTEL_I8XX_ERRSTS, 0x00ff); 374 break; 375 default: 376 tmp = pci_conf_read(isc->isc_pc, isc->isc_tag, 377 AGP_INTEL_ERRCMD); 378 pci_conf_write(isc->isc_pc, isc->isc_tag, 379 AGP_INTEL_ERRCMD, tmp); 380 break; 381 } 382 } 383 384 bus_size_t 385 agp_intel_get_aperture(void *sc) 386 { 387 struct agp_intel_softc *isc = sc; 388 bus_size_t apsize; 389 390 apsize = pci_conf_read(isc->isc_pc, isc->isc_tag, 391 AGP_INTEL_APSIZE) & isc->aperture_mask; 392 393 /* 394 * The size is determined by the number of low bits of 395 * register APBASE which are forced to zero. The low 22 bits 396 * are always forced to zero and each zero bit in the apsize 397 * field just read forces the corresponding bit in the 27:22 398 * to be zero. We calculate the aperture size accordingly. 399 */ 400 return ((((apsize ^ isc->aperture_mask) << 22) | ((1 << 22) - 1)) + 1); 401 } 402 403 int 404 agp_intel_set_aperture(void *sc, bus_size_t aperture) 405 { 406 struct agp_intel_softc *isc = sc; 407 bus_size_t apsize; 408 409 /* 410 * Reverse the magic from get_aperture. 411 */ 412 apsize = ((aperture - 1) >> 22) ^ isc->aperture_mask; 413 414 /* 415 * Double check for sanity. 416 */ 417 if ((((apsize ^ isc->aperture_mask) << 22) | 418 ((1 << 22) - 1)) + 1 != aperture) 419 return (EINVAL); 420 421 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_APSIZE, apsize); 422 423 return (0); 424 } 425 426 void 427 agp_intel_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 428 { 429 struct agp_intel_softc *isc = sc; 430 431 isc->gatt->ag_virtual[(offset - isc->isc_apaddr) >> AGP_PAGE_SHIFT] = 432 physical | 0x17; 433 } 434 435 void 436 agp_intel_unbind_page(void *sc, bus_size_t offset) 437 { 438 struct agp_intel_softc *isc = sc; 439 440 isc->gatt->ag_virtual[(offset - isc->isc_apaddr) >> AGP_PAGE_SHIFT] = 0; 441 } 442 443 void 444 agp_intel_flush_tlb(void *sc) 445 { 446 struct agp_intel_softc *isc = sc; 447 pcireg_t reg; 448 449 switch (isc->chiptype) { 450 case CHIP_I865: 451 case CHIP_I850: 452 case CHIP_I845: 453 case CHIP_I840: 454 case CHIP_I443: 455 reg = pci_conf_read(isc->isc_pc, isc->isc_tag, 456 AGP_INTEL_AGPCTRL); 457 reg &= ~AGPCTRL_GTLB; 458 pci_conf_write(isc->isc_pc, isc->isc_tag, 459 AGP_INTEL_AGPCTRL, reg); 460 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 461 reg | AGPCTRL_GTLB); 462 break; 463 default: /* XXX */ 464 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 465 0x2200); 466 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 467 0x2280); 468 break; 469 } 470 } 471