1 /* $OpenBSD: agp_intel.c,v 1.12 2008/11/09 15:11:19 oga 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/malloc.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/proc.h> 38 #include <sys/agpio.h> 39 #include <sys/device.h> 40 #include <sys/agpio.h> 41 42 #include <dev/pci/pcivar.h> 43 #include <dev/pci/pcireg.h> 44 #include <dev/pci/pcidevs.h> 45 #include <dev/pci/agpvar.h> 46 #include <dev/pci/agpreg.h> 47 48 #include <machine/bus.h> 49 50 struct agp_intel_softc { 51 struct device dev; 52 struct agp_softc *agpdev; 53 struct agp_gatt *gatt; 54 pci_chipset_tag_t isc_pc; 55 pcitag_t isc_tag; 56 u_int aperture_mask; 57 enum { 58 CHIP_INTEL, 59 CHIP_I443, 60 CHIP_I840, 61 CHIP_I845, 62 CHIP_I850, 63 CHIP_I865 64 } chiptype; 65 bus_size_t initial_aperture; /* startup aperture size */ 66 }; 67 68 69 void agp_intel_attach(struct device *, struct device *, void *); 70 int agp_intel_probe(struct device *, void *, void *); 71 bus_size_t agp_intel_get_aperture(void *); 72 int agp_intel_set_aperture(void *, bus_size_t); 73 int agp_intel_bind_page(void *, off_t, bus_addr_t); 74 int agp_intel_unbind_page(void *, off_t); 75 void agp_intel_flush_tlb(void *); 76 77 struct cfattach intelagp_ca = { 78 sizeof(struct agp_intel_softc), agp_intel_probe, agp_intel_attach 79 }; 80 81 struct cfdriver intelagp_cd = { 82 NULL, "intelagp", DV_DULL 83 }; 84 85 const struct agp_methods agp_intel_methods = { 86 agp_intel_get_aperture, 87 agp_intel_bind_page, 88 agp_intel_unbind_page, 89 agp_intel_flush_tlb, 90 /* default enable and memory routines */ 91 }; 92 93 int 94 agp_intel_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 */ 100 if (agpbus_probe(aa) == 0) 101 return (0); 102 103 switch (PCI_PRODUCT(pa->pa_id)) { 104 case PCI_PRODUCT_INTEL_82443LX: 105 case PCI_PRODUCT_INTEL_82443BX: 106 case PCI_PRODUCT_INTEL_82440BX: 107 case PCI_PRODUCT_INTEL_82440BX_AGP: 108 case PCI_PRODUCT_INTEL_82815_HB: 109 case PCI_PRODUCT_INTEL_82820_HB: 110 case PCI_PRODUCT_INTEL_82830M_HB: 111 case PCI_PRODUCT_INTEL_82840_HB: 112 case PCI_PRODUCT_INTEL_82845_HB: 113 case PCI_PRODUCT_INTEL_82845G_HB: 114 case PCI_PRODUCT_INTEL_82850_HB: 115 case PCI_PRODUCT_INTEL_82855PM_HB: 116 case PCI_PRODUCT_INTEL_82855GM_HB: 117 case PCI_PRODUCT_INTEL_82860_HB: 118 case PCI_PRODUCT_INTEL_82865G_HB: 119 case PCI_PRODUCT_INTEL_82875P_HB: 120 return (1); 121 } 122 123 return (0); 124 } 125 126 void 127 agp_intel_attach(struct device *parent, struct device *self, void *aux) 128 { 129 struct agp_intel_softc *isc = (struct agp_intel_softc *)self; 130 struct agp_attach_args *aa = aux; 131 struct pci_attach_args *pa = aa->aa_pa; 132 struct agp_gatt *gatt; 133 pcireg_t reg; 134 u_int32_t value; 135 136 isc->isc_pc = pa->pa_pc; 137 isc->isc_tag = pa->pa_tag; 138 139 switch (PCI_PRODUCT(pa->pa_id)) { 140 case PCI_PRODUCT_INTEL_82443LX: 141 case PCI_PRODUCT_INTEL_82443BX: 142 case PCI_PRODUCT_INTEL_82440BX: 143 case PCI_PRODUCT_INTEL_82440BX_AGP: 144 isc->chiptype = CHIP_I443; 145 break; 146 case PCI_PRODUCT_INTEL_82830M_HB: 147 case PCI_PRODUCT_INTEL_82840_HB: 148 isc->chiptype = CHIP_I840; 149 break; 150 case PCI_PRODUCT_INTEL_82845_HB: 151 case PCI_PRODUCT_INTEL_82845G_HB: 152 case PCI_PRODUCT_INTEL_82855PM_HB: 153 isc->chiptype = CHIP_I845; 154 break; 155 case PCI_PRODUCT_INTEL_82850_HB: 156 isc->chiptype = CHIP_I850; 157 break; 158 case PCI_PRODUCT_INTEL_82865G_HB: 159 case PCI_PRODUCT_INTEL_82875P_HB: 160 isc->chiptype = CHIP_I865; 161 break; 162 default: 163 isc->chiptype = CHIP_INTEL; 164 } 165 166 /* Determine maximum supported aperture size. */ 167 value = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE); 168 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, APSIZE_MASK); 169 isc->aperture_mask = pci_conf_read(pa->pa_pc, pa->pa_tag, 170 AGP_INTEL_APSIZE) & APSIZE_MASK; 171 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_APSIZE, value); 172 isc->initial_aperture = agp_intel_get_aperture(isc); 173 174 for (;;) { 175 bus_size_t size = agp_intel_get_aperture(isc); 176 gatt = agp_alloc_gatt(pa->pa_dmat, size); 177 if (gatt != NULL) 178 break; 179 180 /* 181 * almost certainly error allocating contigious dma memory 182 * so reduce aperture so that the gatt size reduces. 183 */ 184 if (agp_intel_set_aperture(isc, size / 2)) { 185 printf(": failed to set aperture\n"); 186 return; 187 } 188 } 189 isc->gatt = gatt; 190 191 /* Install the gatt. */ 192 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ATTBASE, 193 gatt->ag_physical); 194 195 /* Enable the GLTB and setup the control register. */ 196 switch (isc->chiptype) { 197 case CHIP_I443: 198 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 199 AGPCTRL_AGPRSE | AGPCTRL_GTLB); 200 break; 201 default: 202 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 203 pci_conf_read(isc->isc_pc, isc->isc_tag, 204 AGP_INTEL_AGPCTRL) | AGPCTRL_GTLB); 205 } 206 207 /* Enable things, clear errors etc. */ 208 switch (isc->chiptype) { 209 case CHIP_I845: 210 case CHIP_I865: 211 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG); 212 reg |= MCHCFG_AAGN; 213 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_I840_MCHCFG, reg); 214 break; 215 case CHIP_I840: 216 case CHIP_I850: 217 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD); 218 reg |= AGPCMD_AGPEN; 219 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_AGPCMD, 220 reg); 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, 224 reg); 225 break; 226 default: 227 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG); 228 reg &= ~NBXCFG_APAE; 229 reg |= NBXCFG_AAGN; 230 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_NBXCFG, reg); 231 } 232 233 /* Clear Error status */ 234 switch (isc->chiptype) { 235 case CHIP_I840: 236 pci_conf_write(pa->pa_pc, pa->pa_tag, 237 AGP_INTEL_I8XX_ERRSTS, 0xc000); 238 break; 239 case CHIP_I845: 240 case CHIP_I850: 241 case CHIP_I865: 242 pci_conf_write(isc->isc_pc, isc->isc_tag, 243 AGP_INTEL_I8XX_ERRSTS, 0x00ff); 244 break; 245 246 default: 247 pci_conf_write(pa->pa_pc, pa->pa_tag, AGP_INTEL_ERRSTS, 0x70); 248 } 249 250 isc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_intel_methods, 251 AGP_APBASE, PCI_MAPREG_TYPE_MEM, &isc->dev); 252 return; 253 } 254 255 #if 0 256 int 257 agp_intel_detach(struct agp_softc *sc) 258 { 259 int error; 260 pcireg_t reg; 261 struct agp_intel_softc *isc = sc->sc_chipc; 262 263 error = agp_generic_detach(sc); 264 if (error) 265 return (error); 266 267 /* XXX i845/i855PM/i840/i850E */ 268 reg = pci_conf_read(sc->sc_pc, sc->sc_tag, AGP_INTEL_NBXCFG); 269 reg &= ~(1 << 9); 270 printf("%s: set NBXCFG to %x\n", __FUNCTION__, reg); 271 pci_conf_write(sc->sc_pc, sc->sc_tag, AGP_INTEL_NBXCFG, reg); 272 pci_conf_write(sc->sc_pc, sc->sc_tag, AGP_INTEL_ATTBASE, 0); 273 AGP_SET_APERTURE(sc, isc->initial_aperture); 274 agp_free_gatt(sc, isc->gatt); 275 276 return (0); 277 } 278 #endif 279 280 bus_size_t 281 agp_intel_get_aperture(void *sc) 282 { 283 struct agp_intel_softc *isc = sc; 284 bus_size_t apsize; 285 286 apsize = pci_conf_read(isc->isc_pc, isc->isc_tag, 287 AGP_INTEL_APSIZE) & isc->aperture_mask; 288 289 /* 290 * The size is determined by the number of low bits of 291 * register APBASE which are forced to zero. The low 22 bits 292 * are always forced to zero and each zero bit in the apsize 293 * field just read forces the corresponding bit in the 27:22 294 * to be zero. We calculate the aperture size accordingly. 295 */ 296 return ((((apsize ^ isc->aperture_mask) << 22) | ((1 << 22) - 1)) + 1); 297 } 298 299 int 300 agp_intel_set_aperture(void *sc, bus_size_t aperture) 301 { 302 struct agp_intel_softc *isc = sc; 303 bus_size_t apsize; 304 305 /* 306 * Reverse the magic from get_aperture. 307 */ 308 apsize = ((aperture - 1) >> 22) ^ isc->aperture_mask; 309 310 /* 311 * Double check for sanity. 312 */ 313 if ((((apsize ^ isc->aperture_mask) << 22) | 314 ((1 << 22) - 1)) + 1 != aperture) 315 return (EINVAL); 316 317 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_APSIZE, apsize); 318 319 return (0); 320 } 321 322 int 323 agp_intel_bind_page(void *sc, off_t offset, bus_addr_t physical) 324 { 325 struct agp_intel_softc *isc = sc; 326 327 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) 328 return (EINVAL); 329 330 isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17; 331 return (0); 332 } 333 334 int 335 agp_intel_unbind_page(void *sc, off_t offset) 336 { 337 struct agp_intel_softc *isc = sc; 338 339 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) 340 return (EINVAL); 341 342 isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 343 return (0); 344 } 345 346 void 347 agp_intel_flush_tlb(void *sc) 348 { 349 struct agp_intel_softc *isc = sc; 350 pcireg_t reg; 351 352 switch (isc->chiptype) { 353 case CHIP_I865: 354 case CHIP_I850: 355 case CHIP_I845: 356 case CHIP_I840: 357 case CHIP_I443: 358 reg = pci_conf_read(isc->isc_pc, isc->isc_tag, 359 AGP_INTEL_AGPCTRL); 360 reg &= ~AGPCTRL_GTLB; 361 pci_conf_write(isc->isc_pc, isc->isc_tag, 362 AGP_INTEL_AGPCTRL, reg); 363 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 364 reg | AGPCTRL_GTLB); 365 break; 366 default: /* XXX */ 367 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 368 0x2200); 369 pci_conf_write(isc->isc_pc, isc->isc_tag, AGP_INTEL_AGPCTRL, 370 0x2280); 371 } 372 } 373