1 /* $OpenBSD: vga_pci.c,v 1.44 2009/06/06 04:38:18 pirofti Exp $ */ 2 /* $NetBSD: vga_pci.c,v 1.3 1998/06/08 06:55:58 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 2001 Wasabi Systems, Inc. 6 * All rights reserved. 7 * 8 * Written by Frank van der Linden for Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed for the NetBSD Project by 21 * Wasabi Systems, Inc. 22 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 23 * or promote products derived from this software without specific prior 24 * written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /* 39 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 40 * All rights reserved. 41 * 42 * Author: Chris G. Demetriou 43 * 44 * Permission to use, copy, modify and distribute this software and 45 * its documentation is hereby granted, provided that both the copyright 46 * notice and this permission notice appear in all copies of the 47 * software, derivative works or modified versions, and any portions 48 * thereof, and that both notices appear in supporting documentation. 49 * 50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 52 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 53 * 54 * Carnegie Mellon requests users of this software to return to 55 * 56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 57 * School of Computer Science 58 * Carnegie Mellon University 59 * Pittsburgh PA 15213-3890 60 * 61 * any improvements or extensions that they make and grant Carnegie the 62 * rights to redistribute these changes. 63 */ 64 65 #include "vga.h" 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/kernel.h> 70 #include <sys/device.h> 71 #include <sys/malloc.h> 72 #include <sys/agpio.h> 73 74 #include <uvm/uvm.h> 75 76 #include <machine/bus.h> 77 78 #include <dev/pci/pcireg.h> 79 #include <dev/pci/pcivar.h> 80 #include <dev/pci/pcidevs.h> 81 82 #include <dev/pci/agpvar.h> 83 84 #include <dev/ic/mc6845reg.h> 85 #include <dev/ic/pcdisplayvar.h> 86 #include <dev/ic/vgareg.h> 87 #include <dev/ic/vgavar.h> 88 #include <dev/pci/vga_pcivar.h> 89 90 91 #include <dev/wscons/wsconsio.h> 92 #include <dev/wscons/wsdisplayvar.h> 93 94 #ifdef X86EMU 95 #include <machine/vga_post.h> 96 #endif 97 98 #ifdef VESAFB 99 #include <dev/vesa/vesabiosvar.h> 100 #endif 101 102 #include "intagp.h" 103 #include "drm.h" 104 105 int vga_pci_match(struct device *, void *, void *); 106 void vga_pci_attach(struct device *, struct device *, void *); 107 paddr_t vga_pci_mmap(void* v, off_t off, int prot); 108 void vga_pci_bar_init(struct vga_pci_softc *, struct pci_attach_args *); 109 110 #if NINTAGP > 0 111 int intagpsubmatch(struct device *, void *, void *); 112 int intagp_print(void *, const char *); 113 #endif 114 #if NDRM > 0 115 int drmsubmatch(struct device *, void *, void *); 116 int vga_drm_print(void *, const char *); 117 #endif 118 119 #ifdef VESAFB 120 int vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); 121 int vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); 122 #endif 123 124 125 /* 126 * Function pointers for wsconsctl parameter handling. 127 * XXX These should be per-softc, but right now we only attach 128 * XXX a single vga@pci instance, so this will do. 129 */ 130 int (*ws_get_param)(struct wsdisplay_param *); 131 int (*ws_set_param)(struct wsdisplay_param *); 132 133 134 struct cfattach vga_pci_ca = { 135 sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach, 136 }; 137 138 int 139 vga_pci_match(struct device *parent, void *match, void *aux) 140 { 141 struct pci_attach_args *pa = aux; 142 143 if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0) 144 return (0); 145 146 /* check whether it is disabled by firmware */ 147 if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) 148 & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)) 149 != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)) 150 return (0); 151 152 /* If it's the console, we have a winner! */ 153 if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA)) 154 return (1); 155 156 /* 157 * If we might match, make sure that the card actually looks OK. 158 */ 159 if (!vga_common_probe(pa->pa_iot, pa->pa_memt)) 160 return (0); 161 162 return (1); 163 } 164 165 void 166 vga_pci_attach(struct device *parent, struct device *self, void *aux) 167 { 168 struct pci_attach_args *pa = aux; 169 pcireg_t reg; 170 struct vga_pci_softc *sc = (struct vga_pci_softc *)self; 171 172 /* 173 * Enable bus master; X might need this for accelerated graphics. 174 */ 175 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 176 reg |= PCI_COMMAND_MASTER_ENABLE; 177 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg); 178 179 #ifdef VESAFB 180 if (vesabios_softc != NULL && vesabios_softc->sc_nmodes > 0) { 181 sc->sc_textmode = vesafb_get_mode(sc); 182 printf(", vesafb\n"); 183 vga_extended_attach(self, pa->pa_iot, pa->pa_memt, 184 WSDISPLAY_TYPE_PCIVGA, vga_pci_mmap); 185 return; 186 } 187 #endif 188 printf("\n"); 189 vga_common_attach(self, pa->pa_iot, pa->pa_memt, 190 WSDISPLAY_TYPE_PCIVGA); 191 192 vga_pci_bar_init(sc, pa); 193 194 #ifdef X86EMU 195 if ((sc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device, 196 pa->pa_function)) == NULL) 197 printf("couldn't set up vga POST handler\n"); 198 #endif 199 200 #if NINTAGP > 0 201 /* 202 * attach intagp here instead of pchb so it can share mappings 203 * with the DRM. 204 */ 205 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) { 206 config_found_sm(self, aux, intagp_print, intagpsubmatch); 207 208 } 209 #endif 210 211 #if NDRM > 0 212 config_found_sm(self, aux, NULL, drmsubmatch); 213 #endif 214 } 215 216 #if NINTAGP > 0 217 int 218 intagpsubmatch(struct device *parent, void *match, void *aux) 219 { 220 extern struct cfdriver intagp_cd; 221 struct cfdata *cf = match; 222 223 /* only allow intagp to attach */ 224 if (cf->cf_driver == &intagp_cd) 225 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 226 return (0); 227 } 228 229 int 230 intagp_print(void *vaa, const char *pnp) 231 { 232 if (pnp) 233 printf("intagp at %s", pnp); 234 return (UNCONF); 235 } 236 #endif 237 238 #if NDRM > 0 239 int 240 drmsubmatch(struct device *parent, void *match, void *aux) 241 { 242 struct cfdata *cf = match; 243 struct cfdriver *cd; 244 size_t len = 0; 245 char *sm; 246 247 cd = cf->cf_driver; 248 249 /* is this a *drm device? */ 250 len = strlen(cd->cd_name); 251 sm = cd->cd_name + len - 3; 252 if (strncmp(sm, "drm", 3) == 0) 253 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 254 255 return (0); 256 } 257 #endif 258 259 paddr_t 260 vga_pci_mmap(void *v, off_t off, int prot) 261 { 262 #ifdef VESAFB 263 struct vga_config *vc = (struct vga_config *)v; 264 struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; 265 266 if (sc->sc_mode == WSDISPLAYIO_MODE_DUMBFB) { 267 if (off < 0 || off > vesabios_softc->sc_size) 268 return (-1); 269 return atop(sc->sc_base + off); 270 } 271 #endif 272 return -1; 273 } 274 275 int 276 vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, 277 pci_chipset_tag_t pc, int bus, int device, int function) 278 { 279 return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0)); 280 } 281 282 int 283 vga_pci_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb) 284 { 285 int error = 0; 286 #ifdef VESAFB 287 struct vga_config *vc = (struct vga_config *)v; 288 struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; 289 struct wsdisplay_fbinfo *wdf; 290 struct wsdisplay_gfx_mode *gfxmode; 291 int mode; 292 #endif 293 294 switch (cmd) { 295 #ifdef VESAFB 296 case WSDISPLAYIO_SMODE: 297 mode = *(u_int *)addr; 298 switch (mode) { 299 case WSDISPLAYIO_MODE_EMUL: 300 /* back to text mode */ 301 vesafb_set_mode(sc, sc->sc_textmode); 302 sc->sc_mode = mode; 303 break; 304 case WSDISPLAYIO_MODE_DUMBFB: 305 if (sc->sc_gfxmode == -1) 306 return (-1); 307 vesafb_set_mode(sc, sc->sc_gfxmode); 308 sc->sc_mode = mode; 309 break; 310 default: 311 error = -1; 312 } 313 break; 314 case WSDISPLAYIO_GINFO: 315 if (sc->sc_gfxmode == -1) 316 return (-1); 317 wdf = (void *)addr; 318 wdf->height = sc->sc_height; 319 wdf->width = sc->sc_width; 320 wdf->depth = sc->sc_depth; 321 wdf->cmsize = 256; 322 break; 323 324 case WSDISPLAYIO_LINEBYTES: 325 if (sc->sc_gfxmode == -1) 326 return (-1); 327 *(u_int *)addr = sc->sc_linebytes; 328 break; 329 330 case WSDISPLAYIO_SVIDEO: 331 case WSDISPLAYIO_GVIDEO: 332 break; 333 case WSDISPLAYIO_GETCMAP: 334 if (sc->sc_depth == 8) 335 error = vesafb_getcmap(sc, 336 (struct wsdisplay_cmap *)addr); 337 break; 338 339 case WSDISPLAYIO_PUTCMAP: 340 if (sc->sc_depth == 8) 341 error = vesafb_putcmap(sc, 342 (struct wsdisplay_cmap *)addr); 343 break; 344 345 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 346 *(int *)addr = vesafb_get_supported_depth(sc); 347 break; 348 349 case WSDISPLAYIO_SETGFXMODE: 350 gfxmode = (struct wsdisplay_gfx_mode *)addr; 351 sc->sc_gfxmode = vesafb_find_mode(sc, gfxmode->width, 352 gfxmode->height, gfxmode->depth); 353 if (sc->sc_gfxmode == -1) 354 error = -1; 355 break; 356 357 #endif 358 case WSDISPLAYIO_GETPARAM: 359 if (ws_get_param != NULL) 360 return (*ws_get_param)((struct wsdisplay_param *)addr); 361 else 362 error = ENOTTY; 363 break; 364 case WSDISPLAYIO_SETPARAM: 365 if (ws_set_param != NULL) 366 return (*ws_set_param)((struct wsdisplay_param *)addr); 367 else 368 error = ENOTTY; 369 break; 370 default: 371 error = ENOTTY; 372 } 373 374 return (error); 375 } 376 377 #ifdef notyet 378 void 379 vga_pci_close(void *v) 380 { 381 } 382 #endif 383 384 /* 385 * Prepare dev->bars to be used for information. we do this at startup 386 * so we can do the whole array at once, dealing with 64-bit BARs correctly. 387 */ 388 void 389 vga_pci_bar_init(struct vga_pci_softc *dev, struct pci_attach_args *pa) 390 { 391 pcireg_t type; 392 int addr = PCI_MAPREG_START, i = 0; 393 memcpy(&dev->pa, pa, sizeof(dev->pa)); 394 395 while (i < VGA_PCI_MAX_BARS) { 396 dev->bars[i] = malloc(sizeof((*dev->bars[i])), M_DEVBUF, 397 M_NOWAIT | M_ZERO); 398 if (dev->bars[i] == NULL) { 399 return; 400 } 401 402 dev->bars[i]->addr = addr; 403 404 type = dev->bars[i]->maptype = pci_mapreg_type(pa->pa_pc, 405 pa->pa_tag, addr); 406 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, addr, 407 dev->bars[i]->maptype, &dev->bars[i]->base, 408 &dev->bars[i]->maxsize, &dev->bars[i]->flags) != 0) { 409 free(dev->bars[i], M_DEVBUF); 410 dev->bars[i] = NULL; 411 } 412 413 if (type == PCI_MAPREG_MEM_TYPE_64BIT) { 414 addr += 8; 415 i += 2; 416 } else { 417 addr+=4; 418 ++i; 419 } 420 } 421 } 422 423 /* 424 * Get the vga_pci_bar struct for the address in question. returns NULL if 425 * invalid BAR is passed. 426 */ 427 struct vga_pci_bar* 428 vga_pci_bar_info(struct vga_pci_softc *dev, int no) 429 { 430 if (dev == NULL || no >= VGA_PCI_MAX_BARS) 431 return (NULL); 432 return (dev->bars[no]); 433 } 434 435 /* 436 * map the BAR in question, returning the vga_pci_bar struct in case any more 437 * processing needs to be done. Returns NULL on failure. Can be called multiple 438 * times. 439 */ 440 struct vga_pci_bar* 441 vga_pci_bar_map(struct vga_pci_softc *dev, int addr, bus_size_t size, 442 int busflags) 443 { 444 struct vga_pci_bar *bar = NULL; 445 int i; 446 447 if (dev == NULL) 448 return (NULL); 449 450 for (i = 0; i < VGA_PCI_MAX_BARS; i++) { 451 if (dev->bars[i] && dev->bars[i]->addr == addr) { 452 bar = dev->bars[i]; 453 break; 454 } 455 } 456 if (bar == NULL) { 457 printf("vga_pci_bar_map: given invalid address 0x%x\n", addr); 458 return (NULL); 459 } 460 461 if (bar->mapped == 0) { 462 if (pci_mapreg_map(&dev->pa, bar->addr, bar->maptype, 463 bar->flags | busflags, &bar->bst, &bar->bsh, NULL, 464 &bar->size, size)) { 465 printf("vga_pci_bar_map: can't map bar 0x%x\n", addr); 466 return (NULL); 467 } 468 } 469 470 bar->mapped++; 471 return (bar); 472 } 473 474 /* 475 * "unmap" the BAR referred to by argument. If more than one place has mapped it 476 * we just decrement the reference counter so nothing untoward happens. 477 */ 478 void 479 vga_pci_bar_unmap(struct vga_pci_bar *bar) 480 { 481 if (bar != NULL && bar->mapped != 0) { 482 if (--bar->mapped == 0) 483 bus_space_unmap(bar->bst, bar->bsh, bar->size); 484 } 485 } 486