1 2 /* 3 * Matrox G200, G400 and G450. 4 * Written by Philippe Anel <xigh@free.fr> 5 * 6 * 2006-08-07 : Minor fix to allow the G200 cards to work fine. YDSTORG is now initialized. 7 * : Also support for 16 and 24 bit modes is added. 8 * : by Leonardo Valencia <leoval@anixcorp.com> 9 */ 10 11 #include "u.h" 12 #include "../port/lib.h" 13 #include "mem.h" 14 #include "dat.h" 15 #include "fns.h" 16 #include "io.h" 17 #include "../port/error.h" 18 19 #define Image IMAGE 20 #include <draw.h> 21 #include <memdraw.h> 22 #include <cursor.h> 23 #include "screen.h" 24 25 enum { 26 MATROX = 0x102B, 27 MGA550 = 0x2527, 28 MGA4xx = 0x0525, 29 MGA200 = 0x0521, 30 31 FCOL = 0x1c24, 32 FXRIGHT = 0x1cac, 33 FXLEFT = 0x1ca8, 34 YDST = 0x1c90, 35 YLEN = 0x1c5c, 36 DWGCTL = 0x1c00, 37 DWG_TRAP = 0x04, 38 DWG_BITBLT = 0x08, 39 DWG_ILOAD = 0x09, 40 DWG_LINEAR = 0x0080, 41 DWG_SOLID = 0x0800, 42 DWG_ARZERO = 0x1000, 43 DWG_SGNZERO = 0x2000, 44 DWG_SHIFTZERO = 0x4000, 45 DWG_REPLACE = 0x000C0000, 46 DWG_BFCOL = 0x04000000, 47 SRCORG = 0x2cb4, 48 PITCH = 0x1c8c, 49 DSTORG = 0x2cb8, 50 YDSTORG = 0x1c94, 51 PLNWRT = 0x1c1c, 52 ZORG = 0x1c0c, 53 MACCESS = 0x1c04, 54 STATUS = 0x1e14, 55 FXBNDRY = 0x1C84, 56 CXBNDRY = 0x1C80, 57 YTOP = 0x1C98, 58 YBOT = 0x1C9C, 59 YDSTLEN = 0x1C88, 60 AR0 = 0x1C60, 61 AR1 = 0x1C64, 62 AR2 = 0x1C68, 63 AR3 = 0x1C6C, 64 AR4 = 0x1C70, 65 AR5 = 0x1C74, 66 SGN = 0x1C58, 67 SGN_LEFT = 1, 68 SGN_UP = 4, 69 70 GO = 0x0100, 71 FIFOSTATUS = 0x1E10, 72 CACHEFLUSH = 0x1FFF, 73 74 CRTCEXTIDX = 0x1FDE, /* CRTC Extension Index */ 75 CRTCEXTDATA = 0x1FDF, /* CRTC Extension Data */ 76 77 FILL_OPERAND = 0x800c7804, 78 }; 79 80 static Pcidev * 81 mgapcimatch(void) 82 { 83 Pcidev *p; 84 85 p = pcimatch(nil, MATROX, MGA4xx); 86 if(p == nil) 87 p = pcimatch(nil, MATROX, MGA550); 88 if(p == nil) 89 p = pcimatch(nil, MATROX, MGA200); 90 return p; 91 } 92 93 94 static void 95 mgawrite8(VGAscr *scr, int index, uchar val) 96 { 97 ((uchar*)scr->mmio)[index] = val; 98 } 99 100 static uchar 101 mgaread8(VGAscr *scr, int index) 102 { 103 return ((uchar*)scr->mmio)[index]; 104 } 105 106 static uchar 107 crtcextset(VGAscr *scr, int index, uchar set, uchar clr) 108 { 109 uchar tmp; 110 111 mgawrite8(scr, CRTCEXTIDX, index); 112 tmp = mgaread8(scr, CRTCEXTDATA); 113 mgawrite8(scr, CRTCEXTIDX, index); 114 mgawrite8(scr, CRTCEXTDATA, (tmp & ~clr) | set); 115 116 return tmp; 117 } 118 119 static void 120 mga4xxenable(VGAscr* scr) 121 { 122 Pcidev *pci; 123 int size; 124 int i, n, k; 125 uchar *p; 126 uchar x[16]; 127 uchar crtcext3; 128 129 if(scr->mmio) 130 return; 131 132 pci = mgapcimatch(); 133 if(pci == nil) 134 return; 135 136 scr->mmio = vmap(pci->mem[1].bar&~0x0F, 16*1024); 137 if(scr->mmio == nil) 138 return; 139 140 addvgaseg("mga4xxmmio", pci->mem[1].bar&~0x0F, pci->mem[1].size); 141 142 /* need to map frame buffer here too, so vga can find memory size */ 143 if(pci->did == MGA4xx || pci->did == MGA550) 144 size = 32*MB; 145 else 146 size = 8*MB; 147 vgalinearaddr(scr, pci->mem[0].bar&~0x0F, size); 148 149 if(scr->paddr){ 150 151 /* Find out how much memory is here, some multiple of 2 MB */ 152 153 /* First Set MGA Mode ... */ 154 crtcext3 = crtcextset(scr, 3, 0x80, 0x00); 155 156 p = scr->vaddr; 157 n = (size / MB) / 2; 158 for(i = 0; i < n; i++){ 159 k = (2*i+1)*MB; 160 p[k] = 0; 161 p[k] = i+1; 162 *((uchar*)scr->mmio + CACHEFLUSH) = 0; 163 x[i] = p[k]; 164 } 165 for(i = 1; i < n; i++) 166 if(x[i] != i+1) 167 break; 168 scr->apsize = 2*i*MB; /* sketchy */ 169 addvgaseg("mga4xxscreen", scr->paddr, scr->apsize); 170 crtcextset(scr, 3, crtcext3, 0xff); 171 } 172 } 173 174 enum{ 175 Index = 0x00, /* Index */ 176 Data = 0x0A, /* Data */ 177 178 Cxlsb = 0x0C, /* Cursor X LSB */ 179 Cxmsb = 0x0D, /* Cursor X MSB */ 180 Cylsb = 0x0E, /* Cursor Y LSB */ 181 Cymsb = 0x0F, /* Cursor Y MSB */ 182 183 Icuradrl = 0x04, /* Cursor Base Address Low */ 184 Icuradrh = 0x05, /* Cursor Base Address High */ 185 Icctl = 0x06, /* Indirect Cursor Control */ 186 }; 187 188 static void 189 dac4xxdisable(VGAscr *scr) 190 { 191 uchar *dac4xx; 192 193 if(scr->mmio == 0) 194 return; 195 196 dac4xx = (uchar*)scr->mmio+0x3C00; 197 198 *(dac4xx+Index) = Icctl; 199 *(dac4xx+Data) = 0x00; 200 } 201 202 static void 203 dac4xxload(VGAscr *scr, Cursor *curs) 204 { 205 int y; 206 uchar *p; 207 uchar *dac4xx; 208 209 if(scr->mmio == 0) 210 return; 211 212 dac4xx = (uchar*)scr->mmio+0x3C00; 213 214 dac4xxdisable(scr); 215 216 p = (uchar*)scr->storage; 217 for(y = 0; y < 64; y++){ 218 *p++ = 0; *p++ = 0; *p++ = 0; 219 *p++ = 0; *p++ = 0; *p++ = 0; 220 if(y < 16){ 221 *p++ = curs->set[1+y*2]; 222 *p++ = curs->set[y*2]; 223 } else{ 224 *p++ = 0; *p++ = 0; 225 } 226 227 *p++ = 0; *p++ = 0; *p++ = 0; 228 *p++ = 0; *p++ = 0; *p++ = 0; 229 if(y < 16){ 230 *p++ = curs->set[1+y*2]|curs->clr[1+2*y]; 231 *p++ = curs->set[y*2]|curs->clr[2*y]; 232 } else{ 233 *p++ = 0; *p++ = 0; 234 } 235 } 236 scr->offset.x = 64 + curs->offset.x; 237 scr->offset.y = 64 + curs->offset.y; 238 239 *(dac4xx+Index) = Icctl; 240 *(dac4xx+Data) = 0x03; 241 } 242 243 static int 244 dac4xxmove(VGAscr *scr, Point p) 245 { 246 int x, y; 247 uchar *dac4xx; 248 249 if(scr->mmio == 0) 250 return 1; 251 252 dac4xx = (uchar*)scr->mmio + 0x3C00; 253 254 x = p.x + scr->offset.x; 255 y = p.y + scr->offset.y; 256 257 *(dac4xx+Cxlsb) = x & 0xFF; 258 *(dac4xx+Cxmsb) = (x>>8) & 0x0F; 259 260 *(dac4xx+Cylsb) = y & 0xFF; 261 *(dac4xx+Cymsb) = (y>>8) & 0x0F; 262 263 return 0; 264 } 265 266 static void 267 dac4xxenable(VGAscr *scr) 268 { 269 uchar *dac4xx; 270 ulong storage; 271 272 if(scr->mmio == 0) 273 return; 274 dac4xx = (uchar*)scr->mmio+0x3C00; 275 276 dac4xxdisable(scr); 277 278 storage = (scr->apsize-4096)&~0x3ff; 279 280 *(dac4xx+Index) = Icuradrl; 281 *(dac4xx+Data) = 0xff & (storage >> 10); 282 *(dac4xx+Index) = Icuradrh; 283 *(dac4xx+Data) = 0xff & (storage >> 18); 284 285 scr->storage = (ulong)scr->vaddr + storage; 286 287 /* Show X11-Like Cursor */ 288 *(dac4xx+Index) = Icctl; 289 *(dac4xx+Data) = 0x03; 290 291 /* Cursor Color 0 : White */ 292 *(dac4xx+Index) = 0x08; 293 *(dac4xx+Data) = 0xff; 294 *(dac4xx+Index) = 0x09; 295 *(dac4xx+Data) = 0xff; 296 *(dac4xx+Index) = 0x0a; 297 *(dac4xx+Data) = 0xff; 298 299 /* Cursor Color 1 : Black */ 300 *(dac4xx+Index) = 0x0c; 301 *(dac4xx+Data) = 0x00; 302 *(dac4xx+Index) = 0x0d; 303 *(dac4xx+Data) = 0x00; 304 *(dac4xx+Index) = 0x0e; 305 *(dac4xx+Data) = 0x00; 306 307 /* Cursor Color 2 : Red */ 308 *(dac4xx+Index) = 0x10; 309 *(dac4xx+Data) = 0xff; 310 *(dac4xx+Index) = 0x11; 311 *(dac4xx+Data) = 0x00; 312 *(dac4xx+Index) = 0x12; 313 *(dac4xx+Data) = 0x00; 314 315 /* 316 * Load, locate and enable the 317 * 64x64 cursor in X11 mode. 318 */ 319 dac4xxload(scr, &arrow); 320 dac4xxmove(scr, ZP); 321 } 322 323 static void 324 mga4xxblank(VGAscr *scr, int blank) 325 { 326 char *cp; 327 uchar *mga; 328 uchar seq1, crtcext1; 329 330 /* blank = 0 -> turn screen on */ 331 /* blank = 1 -> turn screen off */ 332 333 if(scr->mmio == 0) 334 return; 335 mga = (uchar*)scr->mmio; 336 337 if(blank == 0){ 338 seq1 = 0x00; 339 crtcext1 = 0x00; 340 } else { 341 seq1 = 0x20; 342 crtcext1 = 0x10; /* Default value ... : standby */ 343 cp = getconf("*dpms"); 344 if(cp){ 345 if(cistrcmp(cp, "standby") == 0) 346 crtcext1 = 0x10; 347 else if(cistrcmp(cp, "suspend") == 0) 348 crtcext1 = 0x20; 349 else if(cistrcmp(cp, "off") == 0) 350 crtcext1 = 0x30; 351 } 352 } 353 354 *(mga + 0x1fc4) = 1; 355 seq1 |= *(mga + 0x1fc5) & ~0x20; 356 *(mga + 0x1fc5) = seq1; 357 358 *(mga + 0x1fde) = 1; 359 crtcext1 |= *(mga + 0x1fdf) & ~0x30; 360 *(mga + 0x1fdf) = crtcext1; 361 } 362 363 static void 364 mgawrite32(uchar *mga, ulong reg, ulong val) 365 { 366 *((ulong*)(&mga[reg])) = val; 367 } 368 369 static ulong 370 mgaread32(uchar *mga, ulong reg) 371 { 372 return *((ulong*)(&mga[reg])); 373 } 374 375 static void 376 mga_fifo(uchar *mga, uchar n) 377 { 378 ulong t; 379 380 #define Timeout 100 381 for (t = 0; t < Timeout; t++) 382 if ((mgaread32(mga, FIFOSTATUS) & 0xff) >= n) 383 break; 384 if (t >= Timeout) 385 print("mga4xx: fifo timeout"); 386 } 387 388 static int 389 mga4xxfill(VGAscr *scr, Rectangle r, ulong color) 390 { 391 uchar *mga; 392 393 if(scr->mmio == 0) 394 return 0; 395 mga = (uchar*)scr->mmio; 396 397 mga_fifo(mga, 7); 398 mgawrite32(mga, DWGCTL, 0); 399 mgawrite32(mga, FCOL, color); 400 mgawrite32(mga, FXLEFT, r.min.x); 401 mgawrite32(mga, FXRIGHT, r.max.x); 402 mgawrite32(mga, YDST, r.min.y); 403 mgawrite32(mga, YLEN, Dy(r)); 404 mgawrite32(mga, DWGCTL + GO, FILL_OPERAND); 405 406 while(mgaread32(mga, STATUS) & 0x00010000) 407 ; 408 409 return 1; 410 } 411 412 static int 413 mga4xxscroll(VGAscr *scr, Rectangle dr, Rectangle sr) 414 { 415 uchar * mga; 416 int pitch; 417 int width, height; 418 ulong start, end, sgn; 419 Point sp, dp; 420 421 if(scr->mmio == 0) 422 return 0; 423 mga = (uchar*)scr->mmio; 424 425 assert(Dx(sr) == Dx(dr) && Dy(sr) == Dy(dr)); 426 427 sp = sr.min; 428 dp = dr.min; 429 if(eqpt(sp, dp)) 430 return 1; 431 432 pitch = Dx(scr->gscreen->r); 433 width = Dx(sr); 434 height = Dy(sr); 435 sgn = 0; 436 437 if(dp.y > sp.y && dp.y < sp.y + height){ 438 sp.y += height - 1; 439 dp.y += height - 1; 440 sgn |= SGN_UP; 441 } 442 443 width--; 444 start = end = sp.x + (sp.y * pitch); 445 446 if(dp.x > sp.x && dp.x < sp.x + width){ 447 start += width; 448 sgn |= SGN_LEFT; 449 } 450 else 451 end += width; 452 453 mga_fifo(mga, 8); 454 mgawrite32(mga, DWGCTL, 0); 455 mgawrite32(mga, SGN, sgn); 456 mgawrite32(mga, AR5, sgn & SGN_UP ? -pitch : pitch); 457 mgawrite32(mga, AR0, end); 458 mgawrite32(mga, AR3, start); 459 mgawrite32(mga, FXBNDRY, ((dp.x + width) << 16) | dp.x); 460 mgawrite32(mga, YDSTLEN, (dp.y << 16) | height); 461 mgawrite32(mga, DWGCTL + GO, DWG_BITBLT | DWG_SHIFTZERO | DWG_BFCOL | DWG_REPLACE); 462 463 while(mgaread32(mga, STATUS) & 0x00010000) 464 ; 465 466 return 1; 467 } 468 469 static void 470 mga4xxdrawinit(VGAscr *scr) 471 { 472 uchar *mga; 473 474 if(scr->mmio == 0) 475 return; 476 477 mga = (uchar*)scr->mmio; 478 479 mgawrite32(mga, SRCORG, 0); 480 mgawrite32(mga, DSTORG, 0); 481 mgawrite32(mga, YDSTORG, 0); 482 mgawrite32(mga, ZORG, 0); 483 mgawrite32(mga, PLNWRT, ~0); 484 mgawrite32(mga, FCOL, 0xffff0000); 485 mgawrite32(mga, CXBNDRY, 0xFFFF0000); 486 mgawrite32(mga, YTOP, 0); 487 mgawrite32(mga, YBOT, 0x01FFFFFF); 488 mgawrite32(mga, PITCH, Dx(scr->gscreen->r) & ((1 << 13) - 1)); 489 switch(scr->gscreen->depth){ 490 case 8: 491 mgawrite32(mga, MACCESS, 0); 492 break; 493 case 16: 494 mgawrite32(mga, MACCESS, 1); 495 break; 496 case 24: 497 mgawrite32(mga, MACCESS, 3); 498 break; 499 case 32: 500 mgawrite32(mga, MACCESS, 2); 501 break; 502 default: 503 return; /* depth not supported ! */ 504 } 505 scr->fill = mga4xxfill; 506 scr->scroll = mga4xxscroll; 507 scr->blank = mga4xxblank; 508 } 509 510 VGAdev vgamga4xxdev = { 511 "mga4xx", 512 mga4xxenable, /* enable */ 513 0, /* disable */ 514 0, /* page */ 515 0, /* linear */ 516 mga4xxdrawinit, 517 }; 518 519 VGAcur vgamga4xxcur = { 520 "mga4xxhwgc", 521 dac4xxenable, 522 dac4xxdisable, 523 dac4xxload, 524 dac4xxmove, 525 }; 526