1 /* $OpenBSD: agp.c,v 1.51 2024/05/24 06:02:53 jsg Exp $ */ 2 /*- 3 * Copyright (c) 2000 Doug Rabson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/malloc.h> 33 34 #include <uvm/uvm_extern.h> 35 36 #include <dev/pci/pcivar.h> 37 38 #include <dev/pci/agpvar.h> 39 #include <dev/pci/agpreg.h> 40 41 void agp_attach(struct device *, struct device *, void *); 42 int agp_probe(struct device *, void *, void *); 43 44 int agpvga_match(struct pci_attach_args *); 45 46 int 47 agpdev_print(void *aux, const char *pnp) 48 { 49 if (pnp) { 50 printf("agp at %s", pnp); 51 } 52 return (UNCONF); 53 } 54 55 int 56 agpbus_probe(struct agp_attach_args *aa) 57 { 58 struct pci_attach_args *pa = aa->aa_pa; 59 60 if (strncmp(aa->aa_busname, "agp", 3) == 0 && 61 PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 62 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST) 63 return (1); 64 return (0); 65 } 66 67 /* 68 * Find the video card hanging off the agp bus XXX assumes only one bus 69 */ 70 int 71 agpvga_match(struct pci_attach_args *pa) 72 { 73 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY && 74 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA) { 75 if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, 76 NULL, NULL)) 77 return (1); 78 } 79 return (0); 80 } 81 82 struct device * 83 agp_attach_bus(struct pci_attach_args *pa, const struct agp_methods *methods, 84 bus_addr_t apaddr, bus_size_t apsize, struct device *dev) 85 { 86 struct agpbus_attach_args arg; 87 88 arg.aa_methods = methods; 89 arg.aa_pa = pa; 90 arg.aa_apaddr = apaddr; 91 arg.aa_apsize = apsize; 92 93 printf("\n"); /* newline from the driver that called us */ 94 return (config_found(dev, &arg, agpdev_print)); 95 } 96 97 int 98 agp_probe(struct device *parent, void *match, void *aux) 99 { 100 /* 101 * we don't do any checking here, driver we're attaching this 102 * interface to should have already done it. 103 */ 104 return (1); 105 } 106 107 void 108 agp_attach(struct device *parent, struct device *self, void *aux) 109 { 110 struct agpbus_attach_args *aa = aux; 111 struct pci_attach_args *pa = aa->aa_pa; 112 struct agp_softc *sc = (struct agp_softc *)self; 113 u_int memsize; 114 int i; 115 116 sc->sc_chipc = parent; 117 sc->sc_methods = aa->aa_methods; 118 sc->sc_apaddr = aa->aa_apaddr; 119 sc->sc_apsize = aa->aa_apsize; 120 121 static const int agp_max[][2] = { 122 {0, 0}, 123 {32, 4}, 124 {64, 28}, 125 {128, 96}, 126 {256, 204}, 127 {512, 440}, 128 {1024, 942}, 129 {2048, 1920}, 130 {4096, 3932} 131 }; 132 133 /* 134 * Work out an upper bound for agp memory allocation. This 135 * uses a heuristic table from the Linux driver. 136 */ 137 memsize = ptoa(physmem) >> 20; 138 139 for (i = 0; i < nitems(agp_max) && memsize > agp_max[i][0]; i++) 140 ; 141 if (i == nitems(agp_max)) 142 i = nitems(agp_max) - 1; 143 sc->sc_maxmem = agp_max[i][1] << 20; 144 145 sc->sc_pcitag = pa->pa_tag; 146 sc->sc_pc = pa->pa_pc; 147 sc->sc_id = pa->pa_id; 148 sc->sc_dmat = pa->pa_dmat; 149 sc->sc_memt = pa->pa_memt; 150 151 pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, 152 &sc->sc_capoff, NULL); 153 154 printf(": aperture at 0x%lx, size 0x%lx\n", (u_long)sc->sc_apaddr, 155 (u_long)sc->sc_apsize); 156 } 157 158 const struct cfattach agp_ca = { 159 sizeof(struct agp_softc), agp_probe, agp_attach, 160 NULL, NULL 161 }; 162 163 struct cfdriver agp_cd = { 164 NULL, "agp", DV_DULL 165 }; 166 167 struct agp_gatt * 168 agp_alloc_gatt(bus_dma_tag_t dmat, u_int32_t apsize) 169 { 170 struct agp_gatt *gatt; 171 u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 172 173 gatt = malloc(sizeof(*gatt), M_AGP, M_NOWAIT | M_ZERO); 174 if (!gatt) 175 return (NULL); 176 gatt->ag_entries = entries; 177 gatt->ag_size = entries * sizeof(u_int32_t); 178 179 if (agp_alloc_dmamem(dmat, gatt->ag_size, &gatt->ag_dmamap, 180 &gatt->ag_physical, &gatt->ag_dmaseg) != 0) { 181 free(gatt, M_AGP, sizeof *gatt); 182 return (NULL); 183 } 184 185 if (bus_dmamem_map(dmat, &gatt->ag_dmaseg, 1, gatt->ag_size, 186 (caddr_t *)&gatt->ag_virtual, BUS_DMA_NOWAIT) != 0) { 187 agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap, 188 &gatt->ag_dmaseg); 189 free(gatt, M_AGP, sizeof *gatt); 190 return (NULL); 191 } 192 193 agp_flush_cache(); 194 195 return (gatt); 196 } 197 198 void 199 agp_free_gatt(bus_dma_tag_t dmat, struct agp_gatt *gatt) 200 { 201 bus_dmamem_unmap(dmat, (caddr_t)gatt->ag_virtual, gatt->ag_size); 202 agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap, &gatt->ag_dmaseg); 203 free(gatt, M_AGP, sizeof *gatt); 204 } 205 206 int 207 agp_generic_enable(struct agp_softc *sc, u_int32_t mode) 208 { 209 struct pci_attach_args pa; 210 pcireg_t tstatus, mstatus, command; 211 int rq, sba, fw, rate, capoff; 212 213 if (pci_find_device(&pa, agpvga_match) == 0 || 214 pci_get_capability(pa.pa_pc, pa.pa_tag, PCI_CAP_AGP, 215 &capoff, NULL) == 0) { 216 printf("agp_generic_enable: not an AGP capable device\n"); 217 return (-1); 218 } 219 220 tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 221 sc->sc_capoff + AGP_STATUS); 222 /* display agp mode */ 223 mstatus = pci_conf_read(pa.pa_pc, pa.pa_tag, 224 capoff + AGP_STATUS); 225 226 /* Set RQ to the min of mode, tstatus and mstatus */ 227 rq = AGP_MODE_GET_RQ(mode); 228 if (AGP_MODE_GET_RQ(tstatus) < rq) 229 rq = AGP_MODE_GET_RQ(tstatus); 230 if (AGP_MODE_GET_RQ(mstatus) < rq) 231 rq = AGP_MODE_GET_RQ(mstatus); 232 233 /* Set SBA if all three can deal with SBA */ 234 sba = (AGP_MODE_GET_SBA(tstatus) 235 & AGP_MODE_GET_SBA(mstatus) 236 & AGP_MODE_GET_SBA(mode)); 237 238 /* Similar for FW */ 239 fw = (AGP_MODE_GET_FW(tstatus) 240 & AGP_MODE_GET_FW(mstatus) 241 & AGP_MODE_GET_FW(mode)); 242 243 /* Figure out the max rate */ 244 rate = (AGP_MODE_GET_RATE(tstatus) 245 & AGP_MODE_GET_RATE(mstatus) 246 & AGP_MODE_GET_RATE(mode)); 247 if (rate & AGP_MODE_RATE_4x) 248 rate = AGP_MODE_RATE_4x; 249 else if (rate & AGP_MODE_RATE_2x) 250 rate = AGP_MODE_RATE_2x; 251 else 252 rate = AGP_MODE_RATE_1x; 253 254 /* Construct the new mode word and tell the hardware */ 255 command = AGP_MODE_SET_RQ(0, rq); 256 command = AGP_MODE_SET_SBA(command, sba); 257 command = AGP_MODE_SET_FW(command, fw); 258 command = AGP_MODE_SET_RATE(command, rate); 259 command = AGP_MODE_SET_AGP(command, 1); 260 261 pci_conf_write(sc->sc_pc, sc->sc_pcitag, 262 sc->sc_capoff + AGP_COMMAND, command); 263 pci_conf_write(pa.pa_pc, pa.pa_tag, capoff + AGP_COMMAND, command); 264 return (0); 265 } 266 267 /* 268 * Allocates a single-segment block of zeroed, wired dma memory. 269 */ 270 int 271 agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t *mapp, 272 bus_addr_t *baddr, bus_dma_segment_t *seg) 273 { 274 int error, level = 0, nseg; 275 276 if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0, 277 seg, 1, &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0) 278 goto out; 279 level++; 280 281 if ((error = bus_dmamap_create(tag, size, nseg, size, 0, 282 BUS_DMA_NOWAIT, mapp)) != 0) 283 goto out; 284 level++; 285 286 if ((error = bus_dmamap_load_raw(tag, *mapp, seg, nseg, size, 287 BUS_DMA_NOWAIT)) != 0) 288 goto out; 289 290 *baddr = (*mapp)->dm_segs[0].ds_addr; 291 292 return (0); 293 out: 294 switch (level) { 295 case 2: 296 bus_dmamap_destroy(tag, *mapp); 297 /* FALLTHROUGH */ 298 case 1: 299 bus_dmamem_free(tag, seg, nseg); 300 break; 301 default: 302 break; 303 } 304 305 return (error); 306 } 307 308 void 309 agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map, 310 bus_dma_segment_t *seg) 311 { 312 bus_dmamap_unload(tag, map); 313 bus_dmamap_destroy(tag, map); 314 bus_dmamem_free(tag, seg, 1); 315 } 316 317 /* Implementation of the kernel api */ 318 319 void * 320 agp_find_device(int unit) 321 { 322 if (unit >= agp_cd.cd_ndevs || unit < 0) 323 return (NULL); 324 return (agp_cd.cd_devs[unit]); 325 } 326 327 enum agp_acquire_state 328 agp_state(void *dev) 329 { 330 struct agp_softc *sc = (struct agp_softc *) dev; 331 return (sc->sc_state); 332 } 333 334 void 335 agp_get_info(void *dev, struct agp_info *info) 336 { 337 struct agp_softc *sc = (struct agp_softc *)dev; 338 339 if (sc->sc_capoff != 0) 340 info->ai_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 341 AGP_STATUS + sc->sc_capoff); 342 else 343 info->ai_mode = 0; /* i810 doesn't have real AGP */ 344 info->ai_aperture_base = sc->sc_apaddr; 345 info->ai_aperture_size = sc->sc_apsize; 346 info->ai_memory_allowed = sc->sc_maxmem; 347 info->ai_memory_used = sc->sc_allocated; 348 info->ai_devid = sc->sc_id; 349 } 350 351 int 352 agp_acquire(void *dev) 353 { 354 struct agp_softc *sc = (struct agp_softc *)dev; 355 356 if (sc->sc_chipc == NULL) 357 return (EINVAL); 358 359 if (sc->sc_state != AGP_ACQUIRE_FREE) 360 return (EBUSY); 361 sc->sc_state = AGP_ACQUIRE_KERNEL; 362 363 return (0); 364 } 365 366 int 367 agp_release(void *dev) 368 { 369 struct agp_softc *sc = (struct agp_softc *)dev; 370 371 if (sc->sc_state == AGP_ACQUIRE_FREE) 372 return (0); 373 374 if (sc->sc_state != AGP_ACQUIRE_KERNEL) 375 return (EBUSY); 376 377 sc->sc_state = AGP_ACQUIRE_FREE; 378 return (0); 379 } 380 381 int 382 agp_enable(void *dev, u_int32_t mode) 383 { 384 struct agp_softc *sc = dev; 385 int ret; 386 387 if (sc->sc_methods->enable != NULL) { 388 ret = sc->sc_methods->enable(sc->sc_chipc, mode); 389 } else { 390 ret = agp_generic_enable(sc, mode); 391 } 392 return (ret); 393 } 394 395 paddr_t 396 agp_mmap(struct agp_softc *sc, off_t off, int prot) 397 { 398 if (sc->sc_chipc == NULL) 399 return (-1); 400 401 if (off >= sc->sc_apsize) 402 return (-1); 403 404 if (sc->sc_apaddr == 0) 405 return (-1); 406 407 return bus_space_mmap(sc->sc_memt, sc->sc_apaddr, off, prot, 0); 408 } 409