1 /* $OpenBSD: vga_pci.c,v 1.39 2008/11/22 21:26:48 oga 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 VESAFB 95 #include <dev/vesa/vesabiosvar.h> 96 #endif 97 98 #include "intagp.h" 99 #include "drm.h" 100 101 int vga_pci_match(struct device *, void *, void *); 102 void vga_pci_attach(struct device *, struct device *, void *); 103 paddr_t vga_pci_mmap(void* v, off_t off, int prot); 104 void vga_pci_bar_init(struct vga_pci_softc *, struct pci_attach_args *); 105 106 #if NINTAGP > 0 107 int intagpsubmatch(struct device *, void *, void *); 108 int intagp_print(void *, const char *); 109 #endif 110 #if NDRM > 0 111 int drmsubmatch(struct device *, void *, void *); 112 int vga_drm_print(void *, const char *); 113 #endif 114 115 #ifdef VESAFB 116 int vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); 117 int vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); 118 #endif 119 120 struct cfattach vga_pci_ca = { 121 sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach, 122 }; 123 124 int 125 vga_pci_match(struct device *parent, void *match, void *aux) 126 { 127 struct pci_attach_args *pa = aux; 128 129 if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0) 130 return (0); 131 132 /* check whether it is disabled by firmware */ 133 if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) 134 & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)) 135 != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)) 136 return (0); 137 138 /* If it's the console, we have a winner! */ 139 if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA)) 140 return (1); 141 142 /* 143 * If we might match, make sure that the card actually looks OK. 144 */ 145 if (!vga_common_probe(pa->pa_iot, pa->pa_memt)) 146 return (0); 147 148 return (1); 149 } 150 151 void 152 vga_pci_attach(struct device *parent, struct device *self, void *aux) 153 { 154 struct pci_attach_args *pa = aux; 155 pcireg_t reg; 156 struct vga_pci_softc *sc = (struct vga_pci_softc *)self; 157 158 /* 159 * Enable bus master; X might need this for accelerated graphics. 160 */ 161 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 162 reg |= PCI_COMMAND_MASTER_ENABLE; 163 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg); 164 165 #ifdef VESAFB 166 if (vesabios_softc != NULL && vesabios_softc->sc_nmodes > 0) { 167 sc->sc_textmode = vesafb_get_mode(sc); 168 printf(", vesafb\n"); 169 vga_extended_attach(self, pa->pa_iot, pa->pa_memt, 170 WSDISPLAY_TYPE_PCIVGA, vga_pci_mmap); 171 return; 172 } 173 #endif 174 printf("\n"); 175 vga_common_attach(self, pa->pa_iot, pa->pa_memt, 176 WSDISPLAY_TYPE_PCIVGA); 177 178 vga_pci_bar_init(sc, pa); 179 180 #if NINTAGP > 0 181 /* 182 * attach intagp here instead of pchb so it can share mappings 183 * with the DRM. 184 */ 185 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) { 186 config_found_sm(self, aux, intagp_print, intagpsubmatch); 187 188 } 189 #endif 190 191 #if NDRM > 0 192 config_found_sm(self, aux, NULL, drmsubmatch); 193 #endif 194 } 195 196 #if NINTAGP > 0 197 int 198 intagpsubmatch(struct device *parent, void *match, void *aux) 199 { 200 extern struct cfdriver intagp_cd; 201 struct cfdata *cf = match; 202 203 /* only allow intagp to attach */ 204 if (cf->cf_driver == &intagp_cd) 205 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 206 return (0); 207 } 208 209 int 210 intagp_print(void *vaa, const char *pnp) 211 { 212 if (pnp) 213 printf("intagp at %s", pnp); 214 return (UNCONF); 215 } 216 #endif 217 218 #if NDRM > 0 219 int 220 drmsubmatch(struct device *parent, void *match, void *aux) 221 { 222 struct cfdata *cf = match; 223 struct cfdriver *cd; 224 size_t len = 0; 225 char *sm; 226 227 cd = cf->cf_driver; 228 229 /* is this a *drm device? */ 230 len = strlen(cd->cd_name); 231 sm = cd->cd_name + len - 3; 232 if (strncmp(sm, "drm", 3) == 0) 233 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 234 235 return (0); 236 } 237 #endif 238 239 paddr_t 240 vga_pci_mmap(void *v, off_t off, int prot) 241 { 242 #ifdef VESAFB 243 struct vga_config *vc = (struct vga_config *)v; 244 struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; 245 246 if (sc->sc_mode == WSDISPLAYIO_MODE_DUMBFB) { 247 if (off < 0 || off > vesabios_softc->sc_size) 248 return (-1); 249 return atop(sc->sc_base + off); 250 } 251 #endif 252 return -1; 253 } 254 255 int 256 vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, 257 pci_chipset_tag_t pc, int bus, int device, int function) 258 { 259 return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0)); 260 } 261 262 int 263 vga_pci_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb) 264 { 265 int error = 0; 266 #ifdef VESAFB 267 struct vga_config *vc = (struct vga_config *)v; 268 struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; 269 struct wsdisplay_fbinfo *wdf; 270 struct wsdisplay_gfx_mode *gfxmode; 271 int mode; 272 #endif 273 274 switch (cmd) { 275 #ifdef VESAFB 276 case WSDISPLAYIO_SMODE: 277 mode = *(u_int *)addr; 278 switch (mode) { 279 case WSDISPLAYIO_MODE_EMUL: 280 /* back to text mode */ 281 vesafb_set_mode(sc, sc->sc_textmode); 282 sc->sc_mode = mode; 283 break; 284 case WSDISPLAYIO_MODE_DUMBFB: 285 if (sc->sc_gfxmode == -1) 286 return (-1); 287 vesafb_set_mode(sc, sc->sc_gfxmode); 288 sc->sc_mode = mode; 289 break; 290 default: 291 error = -1; 292 } 293 break; 294 case WSDISPLAYIO_GINFO: 295 if (sc->sc_gfxmode == -1) 296 return (-1); 297 wdf = (void *)addr; 298 wdf->height = sc->sc_height; 299 wdf->width = sc->sc_width; 300 wdf->depth = sc->sc_depth; 301 wdf->cmsize = 256; 302 break; 303 304 case WSDISPLAYIO_LINEBYTES: 305 if (sc->sc_gfxmode == -1) 306 return (-1); 307 *(u_int *)addr = sc->sc_linebytes; 308 break; 309 310 case WSDISPLAYIO_SVIDEO: 311 case WSDISPLAYIO_GVIDEO: 312 break; 313 case WSDISPLAYIO_GETCMAP: 314 if (sc->sc_depth == 8) 315 error = vesafb_getcmap(sc, 316 (struct wsdisplay_cmap *)addr); 317 break; 318 319 case WSDISPLAYIO_PUTCMAP: 320 if (sc->sc_depth == 8) 321 error = vesafb_putcmap(sc, 322 (struct wsdisplay_cmap *)addr); 323 break; 324 325 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 326 *(int *)addr = vesafb_get_supported_depth(sc); 327 break; 328 329 case WSDISPLAYIO_SETGFXMODE: 330 gfxmode = (struct wsdisplay_gfx_mode *)addr; 331 sc->sc_gfxmode = vesafb_find_mode(sc, gfxmode->width, 332 gfxmode->height, gfxmode->depth); 333 if (sc->sc_gfxmode == -1) 334 error = -1; 335 break; 336 337 #endif 338 default: 339 error = ENOTTY; 340 } 341 342 return (error); 343 } 344 345 #ifdef notyet 346 void 347 vga_pci_close(void *v) 348 { 349 } 350 #endif 351 352 /* 353 * Prepare dev->bars to be used for information. we do this at startup 354 * so we can do the whole array at once, dealing with 64-bit BARs correctly. 355 */ 356 void 357 vga_pci_bar_init(struct vga_pci_softc *dev, struct pci_attach_args *pa) 358 { 359 pcireg_t type; 360 int addr = PCI_MAPREG_START, i = 0; 361 memcpy(&dev->pa, pa, sizeof(dev->pa)); 362 363 while (i < VGA_PCI_MAX_BARS) { 364 dev->bars[i] = malloc(sizeof((*dev->bars[i])), M_DEVBUF, 365 M_NOWAIT | M_ZERO); 366 if (dev->bars[i] == NULL) { 367 return; 368 } 369 370 dev->bars[i]->addr = addr; 371 372 type = dev->bars[i]->maptype = pci_mapreg_type(pa->pa_pc, 373 pa->pa_tag, addr); 374 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, addr, 375 dev->bars[i]->maptype, &dev->bars[i]->base, 376 &dev->bars[i]->maxsize, &dev->bars[i]->flags) != 0) { 377 free(dev->bars[i], M_DEVBUF); 378 dev->bars[i] = NULL; 379 } 380 381 if (type == PCI_MAPREG_MEM_TYPE_64BIT) { 382 addr += 8; 383 i += 2; 384 } else { 385 addr+=4; 386 ++i; 387 } 388 } 389 } 390 391 /* 392 * Get the vga_pci_bar struct for the address in question. returns NULL if 393 * invalid BAR is passed. 394 */ 395 struct vga_pci_bar* 396 vga_pci_bar_info(struct vga_pci_softc *dev, int no) 397 { 398 if (dev == NULL || no > VGA_PCI_MAX_BARS) 399 return (NULL); 400 return (dev->bars[no]); 401 } 402 403 /* 404 * map the BAR in question, returning the vga_pci_bar struct in case any more 405 * processing needs to be done. Returns NULL on failure. Can be called multiple 406 * times. 407 */ 408 struct vga_pci_bar* 409 vga_pci_bar_map(struct vga_pci_softc *dev, int addr, bus_size_t size, 410 int busflags) 411 { 412 struct vga_pci_bar *bar = NULL; 413 int i; 414 415 if (dev == NULL) 416 return (NULL); 417 418 for (i = 0; i < VGA_PCI_MAX_BARS; i++) { 419 if (dev->bars[i] && dev->bars[i]->addr == addr) { 420 bar = dev->bars[i]; 421 break; 422 } 423 } 424 if (bar == NULL) { 425 printf("vga_pci_bar_map: given invalid address 0x%x\n", addr); 426 return (NULL); 427 } 428 429 if (bar->mapped == 0) { 430 if (pci_mapreg_map(&dev->pa, bar->addr, bar->maptype, 431 bar->flags | busflags, &bar->bst, &bar->bsh, NULL, 432 &bar->size, size)) { 433 printf("vga_pci_bar_map: can't map bar 0x%x\n", addr); 434 return (NULL); 435 } 436 } 437 438 bar->mapped++; 439 return (bar); 440 } 441 442 /* 443 * "unmap" the BAR referred to by argument. If more than one place has mapped it 444 * we just decrement the reference counter so nothing untoward happens. 445 */ 446 void 447 vga_pci_bar_unmap(struct vga_pci_bar *bar) 448 { 449 if (bar != NULL && bar->mapped != 0) { 450 if (--bar->mapped == 0) 451 bus_space_unmap(bar->bst, bar->bsh, bar->size); 452 } 453 } 454