1 /* CTRC functionality */ 2 /* Author: 3 Rudolf Cornelissen 4/2003-1/2006 4 */ 5 6 #define MODULE_BIT 0x00040000 7 8 #include "nm_std.h" 9 10 /* Adjust passed parameters to a valid mode line */ 11 status_t nm_crtc_validate_timing( 12 uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, 13 uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt 14 ) 15 { 16 /* horizontal */ 17 /* make all parameters multiples of 8 */ 18 *hd_e &= 0xfff8; 19 *hs_s &= 0xfff8; 20 *hs_e &= 0xfff8; 21 *ht &= 0xfff8; 22 23 /* confine to required number of bits, taking logic into account */ 24 if (*hd_e > ((0xff - 2) << 3)) *hd_e = ((0xff - 2) << 3); 25 if (*hs_s > ((0xff - 1) << 3)) *hs_s = ((0xff - 1) << 3); 26 if (*hs_e > ( 0xff << 3)) *hs_e = ( 0xff << 3); 27 if (*ht > ((0xff + 5) << 3)) *ht = ((0xff + 5) << 3); 28 29 /* NOTE: keep horizontal timing at multiples of 8! */ 30 /* confine to a reasonable width */ 31 if (*hd_e < 640) *hd_e = 640; 32 if (*hd_e > si->ps.max_crtc_width) *hd_e = si->ps.max_crtc_width; 33 34 /* if hor. total does not leave room for a sensible sync pulse,*/ 35 /* increase it! */ 36 if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); 37 38 /* if hor. total does not adhere to max. blanking pulse width,*/ 39 /* decrease it! */ 40 if (*ht > (*hd_e + 0x1f8)) *ht = (*hd_e + 0x1f8); 41 42 /* make sure sync pulse is not during display */ 43 if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); 44 if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); 45 46 /* correct sync pulse if it is too long: 47 * there are only 5 bits available to save this in the card registers! */ 48 if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); 49 50 /*vertical*/ 51 /* confine to required number of bits, taking logic into account */ 52 if (si->ps.card_type < NM2200) 53 { 54 if (*vd_e > (0x3ff - 2)) *vd_e = (0x3ff - 2); 55 if (*vs_s > (0x3ff - 1)) *vs_s = (0x3ff - 1); 56 if (*vs_e > 0x3ff ) *vs_e = 0x3ff ; 57 if (*vt > (0x3ff + 2)) *vt = (0x3ff + 2); 58 } 59 else 60 { 61 if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); 62 if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); 63 if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; 64 if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); 65 } 66 67 /* confine to a reasonable height */ 68 if (*vd_e < 480) *vd_e = 480; 69 if (*vd_e > si->ps.max_crtc_height) *vd_e = si->ps.max_crtc_height; 70 71 /*if vertical total does not leave room for a sync pulse, increase it!*/ 72 if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3); 73 74 /* if vert. total does not adhere to max. blanking pulse width,*/ 75 /* decrease it! */ 76 if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff); 77 78 /* make sure sync pulse is not during display */ 79 if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); 80 if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); 81 82 /* correct sync pulse if it is too long: 83 * there are only 4 bits available to save this in the card registers! */ 84 if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); 85 86 return B_OK; 87 } 88 89 /* set a mode line */ 90 status_t nm_crtc_set_timing(display_mode target, bool crt_only) 91 { 92 uint8 temp; 93 94 uint32 htotal; /*total horizontal total VCLKs*/ 95 uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ 96 uint32 hsync_s; /*begin of horizontal sync pulse*/ 97 uint32 hsync_e; /*end of horizontal sync pulse*/ 98 uint32 hblnk_s; /*begin horizontal blanking*/ 99 uint32 hblnk_e; /*end horizontal blanking*/ 100 101 uint32 vtotal; /*total vertical total scanlines*/ 102 uint32 vdisp_e; /*end of vertical display*/ 103 uint32 vsync_s; /*begin of vertical sync pulse*/ 104 uint32 vsync_e; /*end of vertical sync pulse*/ 105 uint32 vblnk_s; /*begin vertical blanking*/ 106 uint32 vblnk_e; /*end vertical blanking*/ 107 108 uint32 linecomp; /*split screen and vdisp_e interrupt*/ 109 110 LOG(4,("CRTC: setting timing\n")); 111 112 /* modify visible sceensize if needed */ 113 /* (note that MOVE_CURSOR checks for a panning/scrolling mode itself, 114 * the display_mode as placed in si->dm may _not_ be modified!) */ 115 if (!crt_only) 116 { 117 if (target.timing.h_display > si->ps.panel_width) 118 { 119 target.timing.h_display = si->ps.panel_width; 120 LOG(4, 121 ("CRTC: req. width > panel width: setting panning mode\n")); 122 } 123 if (target.timing.v_display > si->ps.panel_height) 124 { 125 target.timing.v_display = si->ps.panel_height; 126 LOG(4, 127 ("CRTC: req. height > panel height: setting scrolling " 128 "mode\n")); 129 } 130 131 /* modify sync polarities 132 * (needed to maintain correct panel centering): 133 * both polarities must be negative (confirmed NM2160) */ 134 target.timing.flags &= ~(B_POSITIVE_HSYNC | B_POSITIVE_VSYNC); 135 } 136 137 /* Modify parameters as required by standard VGA */ 138 htotal = ((target.timing.h_total >> 3) - 5); 139 hdisp_e = ((target.timing.h_display >> 3) - 1); 140 hblnk_s = hdisp_e; 141 hblnk_e = (htotal + 0); /* this register differs from standard VGA! */ 142 /* (says + 4) */ 143 hsync_s = (target.timing.h_sync_start >> 3); 144 hsync_e = (target.timing.h_sync_end >> 3); 145 146 vtotal = target.timing.v_total - 2; 147 vdisp_e = target.timing.v_display - 1; 148 vblnk_s = vdisp_e; 149 vblnk_e = (vtotal + 1); 150 vsync_s = target.timing.v_sync_start;//-1; 151 vsync_e = target.timing.v_sync_end;//-1; 152 153 /* prevent memory adress counter from being reset */ 154 /* (linecomp may not occur) */ 155 linecomp = target.timing.v_display; 156 157 if (crt_only) 158 { 159 LOG(4,("CRTC: CRT only mode, setting full timing...\n")); 160 161 /* log the mode that will be set */ 162 LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e)); 163 LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e)); 164 165 /* actually program the card! */ 166 /* unlock CRTC registers at index 0-7 */ 167 temp = (ISACRTCR(VSYNCE) & 0x7f); 168 /* we need to wait a bit or the card will mess-up it's */ 169 /* register values.. */ 170 snooze(10); 171 ISACRTCW(VSYNCE, temp); 172 /* horizontal standard VGA regs */ 173 ISACRTCW(HTOTAL, (htotal & 0xff)); 174 ISACRTCW(HDISPE, (hdisp_e & 0xff)); 175 ISACRTCW(HBLANKS, (hblnk_s & 0xff)); 176 /* also unlock vertical retrace registers in advance */ 177 ISACRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); 178 ISACRTCW(HSYNCS, (hsync_s & 0xff)); 179 ISACRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); 180 181 /* vertical standard VGA regs */ 182 ISACRTCW(VTOTAL, (vtotal & 0xff)); 183 ISACRTCW(OVERFLOW, 184 ( 185 ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | 186 ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | 187 ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | 188 ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) 189 )); 190 ISACRTCW(PRROWSCN, 0x00); /* not used */ 191 ISACRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) 192 | ((linecomp & 0x200) >> (9 - 6)))); 193 ISACRTCW(VSYNCS, (vsync_s & 0xff)); 194 temp = (ISACRTCR(VSYNCE) & 0xf0); 195 /* we need to wait a bit or the card will mess-up it's */ 196 /* register values.. */ 197 snooze(10); 198 ISACRTCW(VSYNCE, (temp | (vsync_e & 0x0f))); 199 ISACRTCW(VDISPE, (vdisp_e & 0xff)); 200 ISACRTCW(VBLANKS, (vblnk_s & 0xff)); 201 ISACRTCW(VBLANKE, (vblnk_e & 0xff)); 202 //linux: (BIOSmode) 203 // regp->CRTC[23] = 0xC3; 204 ISACRTCW(LINECOMP, (linecomp & 0xff)); 205 206 /* horizontal - no extended regs available or needed on */ 207 /* NeoMagic chips */ 208 209 /* vertical - extended regs */ 210 //fixme: checkout if b2 or 3 should be switched! (linux contains error here) 211 //fixme: linecomp should also have an extra bit... testable by setting linecomp 212 //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest 213 //for screenorig reset visible on upper half of the screen or not at all.. 214 if (si->ps.card_type >= NM2200) 215 ISACRTCW(VEXT, 216 ( 217 ((vtotal & 0x400) >> (10 - 0)) | 218 ((vdisp_e & 0x400) >> (10 - 1)) | 219 ((vblnk_s & 0x400) >> (10 - 2)) | 220 ((vsync_s & 0x400) >> (10 - 3))/*| 221 ((linecomp&0x400)>>3)*/ 222 )); 223 } 224 else 225 { 226 LOG(4, 227 ("CRTC: internal flatpanel active, setting display region only\n")); 228 229 /* actually program the card! */ 230 /* unlock CRTC registers at index 0-7 */ 231 temp = (ISACRTCR(VSYNCE) & 0x7f); 232 /* we need to wait a bit or the card will mess-up it's */ 233 /* register values.. */ 234 snooze(10); 235 ISACRTCW(VSYNCE, temp); 236 /* horizontal standard VGA regs */ 237 ISACRTCW(HDISPE, (hdisp_e & 0xff)); 238 239 /* vertical standard VGA regs */ 240 temp = (ISACRTCR(OVERFLOW) & ~0x52); 241 /* we need to wait a bit or the card will mess-up it's */ 242 /* register values.. */ 243 snooze(10); 244 ISACRTCW(OVERFLOW, 245 ( 246 temp | 247 ((vdisp_e & 0x100) >> (8 - 1)) | 248 ((vdisp_e & 0x200) >> (9 - 6)) | 249 ((linecomp & 0x100) >> (8 - 4)) 250 )); 251 252 ISACRTCW(PRROWSCN, 0x00); /* not used */ 253 254 temp = (ISACRTCR(MAXSCLIN) & ~0x40); 255 /* we need to wait a bit or the card will mess-up it's */ 256 /* register values.. */ 257 snooze(10); 258 ISACRTCW(MAXSCLIN, (temp | ((linecomp & 0x200) >> (9 - 6)))); 259 260 ISACRTCW(VDISPE, (vdisp_e & 0xff)); 261 //linux:(BIOSmode) 262 // regp->CRTC[23] = 0xC3; 263 ISACRTCW(LINECOMP, (linecomp & 0xff)); 264 265 /* horizontal - no extended regs available or needed on */ 266 /* NeoMagic chips */ 267 268 /* vertical - extended regs */ 269 //fixme: linecomp should have an extra bit... testable by setting linecomp 270 //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest 271 //for screenorig reset visible on upper half of the screen or not at all.. 272 if (si->ps.card_type >= NM2200) 273 { 274 temp = (ISACRTCR(VEXT) & ~0x02); 275 /* we need to wait a bit or the card will mess-up it's */ 276 /* register values.. */ 277 snooze(10); 278 ISACRTCW(VEXT, 279 ( 280 temp | 281 ((vdisp_e & 0x400) >> (10 - 1))/*| 282 ((linecomp&0x400)>>3)*/ 283 )); 284 } 285 } 286 287 /* setup HSYNC & VSYNC polarity */ 288 LOG(2,("CRTC: sync polarity: ")); 289 temp = ISARB(MISCR); 290 if (target.timing.flags & B_POSITIVE_HSYNC) 291 { 292 LOG(2,("H:pos ")); 293 temp &= ~0x40; 294 } 295 else 296 { 297 LOG(2,("H:neg ")); 298 temp |= 0x40; 299 } 300 if (target.timing.flags & B_POSITIVE_VSYNC) 301 { 302 LOG(2,("V:pos ")); 303 temp &= ~0x80; 304 } 305 else 306 { 307 LOG(2,("V:neg ")); 308 temp |= 0x80; 309 } 310 /* we need to wait a bit or the card will mess-up it's register values.. */ 311 snooze(10); 312 ISAWB(MISCW, temp); 313 LOG(2,(", MISC reg readback: $%02x\n", ISARB(MISCR))); 314 315 /* program 'fixed' mode if needed */ 316 if (si->ps.card_type != NM2070) 317 { 318 uint8 width; 319 320 temp = ISAGRPHR(PANELCTRL1); 321 /* we need to wait a bit or the card will mess-up it's register values.. */ 322 snooze(10); 323 324 switch (target.timing.h_display) 325 { 326 case 1280: 327 width = (3 << 5); 328 break; 329 case 1024: 330 width = (2 << 5); 331 break; 332 case 800: 333 width = (1 << 5); 334 break; 335 case 640: 336 default: //fixme: non-std modes should be in between above modes?!? 337 width = (0 << 5); 338 break; 339 } 340 341 switch (si->ps.card_type) 342 { 343 case NM2090: 344 case NM2093: 345 case NM2097: 346 case NM2160: 347 //fixme: checkout b6???? 348 ISAGRPHW(PANELCTRL1, ((temp & ~0x20) | (width & 0x20))); 349 break; 350 default: 351 /* NM2200 and later */ 352 ISAGRPHW(PANELCTRL1, ((temp & ~0x60) | (width & 0x60))); 353 break; 354 } 355 } 356 357 return B_OK; 358 } 359 360 status_t nm_crtc_depth(int mode) 361 { 362 uint8 vid_delay = 0; 363 364 LOG(4,("CRTC: setting colordepth to be displayed\n")); 365 366 /* set VCLK scaling */ 367 switch(mode) 368 { 369 case BPP8: 370 vid_delay = 0x01; 371 break; 372 case BPP15: 373 vid_delay = 0x02; 374 break; 375 case BPP16: 376 vid_delay = 0x03; 377 break; 378 case BPP24: 379 vid_delay = 0x04; 380 break; 381 default: 382 LOG(4,("CRTC: colordepth not supported, aborting!\n")); 383 return B_ERROR; 384 break; 385 } 386 387 switch (si->ps.card_type) 388 { 389 case NM2070: 390 vid_delay |= (ISAGRPHR(COLDEPTH) & 0xf0); 391 break; 392 default: 393 vid_delay |= (ISAGRPHR(COLDEPTH) & 0x70); 394 break; 395 } 396 /* we need to wait a bit or the card will mess-up it's */ 397 /* register values.. (NM2160) */ 398 snooze(10); 399 ISAGRPHW(COLDEPTH, vid_delay); 400 401 snooze(10); 402 LOG(4,("CRTC: colordepth register readback $%02x\n", (ISAGRPHR(COLDEPTH)))); 403 404 return B_OK; 405 } 406 407 status_t nm_crtc_dpms(bool display, bool h, bool v) 408 { 409 char msg[100]; 410 const char* displayStatus; 411 const char* horizontalSync; 412 const char* verticalSync; 413 414 uint8 temp, size_outputs; 415 416 sprintf(msg, "CRTC: setting DPMS: "); 417 418 /* start synchronous reset: required before turning screen off! */ 419 ISASEQW(RESET, 0x01); 420 421 /* turn screen off */ 422 temp = ISASEQR(CLKMODE); 423 /* we need to wait a bit or the card will mess-up it's */ 424 /* register values.. (NM2160) */ 425 snooze(10); 426 427 if (display) 428 { 429 ISASEQW(CLKMODE, (temp & ~0x20)); 430 431 /* end synchronous reset if display should be enabled */ 432 ISASEQW(RESET, 0x03); 433 displayStatus = "on"; 434 } 435 else 436 { 437 ISASEQW(CLKMODE, (temp | 0x20)); 438 displayStatus = "off"; 439 } 440 441 temp = 0x00; 442 if (h) 443 { 444 horizontalSync = "enabled"; 445 } 446 else 447 { 448 temp |= 0x10; 449 horizontalSync = "disabled"; 450 } 451 if (v) 452 { 453 verticalSync = "enabled"; 454 } 455 else 456 { 457 temp |= 0x20; 458 verticalSync = "disabled"; 459 } 460 461 snprintf(msg, sizeof(msg), 462 "CRTC: setting DPMS: display %s, hsync %s, vsync %s\n", 463 displayStatus, horizontalSync, verticalSync); 464 LOG(4, (msg)); 465 466 /* read panelsize and currently active outputs */ 467 size_outputs = nm_general_output_read(); 468 /* we need to wait a bit or the card will mess-up it's register */ 469 /* values.. (NM2160) */ 470 snooze(10); 471 472 if (si->ps.card_type < NM2200) 473 { 474 /* no full DPMS support */ 475 if (temp) 476 { 477 /* Turn panel plus backlight and external monitor's */ 478 /* sync signals off */ 479 ISAGRPHW(PANELCTRL1, (size_outputs & 0xfc)); 480 } 481 else 482 { 483 /* restore 'previous' output device(s) */ 484 ISAGRPHW(PANELCTRL1, size_outputs); 485 } 486 } 487 else 488 { 489 if (temp) 490 { 491 /* Turn panel plus backlight off */ 492 ISAGRPHW(PANELCTRL1, (size_outputs & 0xfd)); 493 } 494 else 495 { 496 /* restore 'previous' panel situation */ 497 ISAGRPHW(PANELCTRL1, size_outputs); 498 } 499 500 /* if external monitor is active, update it's DPMS state */ 501 if (size_outputs & 0x01) 502 { 503 /* we have full DPMS support for external monitors */ 504 //fixme: checkout if so... 505 temp |= ((ISAGRPHR(ENSETRESET) & 0x0f) | 0x80); 506 /* we need to wait a bit or the card will mess-up it's */ 507 /* register values.. (NM2160) */ 508 snooze(10); 509 ISAGRPHW(ENSETRESET, temp); 510 511 snooze(10); 512 LOG(4,("CRTC: DPMS readback $%02x, programmed $%02x\n", 513 ISAGRPHR(ENSETRESET), temp)); 514 } 515 } 516 517 return B_OK; 518 } 519 520 status_t nm_crtc_set_display_pitch() 521 { 522 uint32 offset; 523 524 LOG(4,("CRTC: setting card pitch (offset between lines)\n")); 525 526 /* figure out offset value hardware needs: same for all Neomagic cards */ 527 offset = si->fbc.bytes_per_row / 8; 528 529 LOG(2,("CRTC: offset register set to: $%04x\n", offset)); 530 531 /* program the card */ 532 ISACRTCW(PITCHL, (offset & 0xff)); 533 //fixme: test for max supported pitch if possible, 534 //not all bits below will be implemented. 535 //NM2160: confirmed b0 and b1 in register below to exist and work. 536 if (si->ps.card_type != NM2070) 537 ISAGRPHW(CRTC_PITCHE, ((offset & 0xff00) >> 8)); 538 539 return B_OK; 540 } 541 542 status_t nm_crtc_set_display_start(uint32 startadd,uint8 bpp) 543 { 544 uint8 val; 545 uint32 timeout = 0; 546 547 LOG(2,("CRTC: relative startadd: $%06x\n",startadd)); 548 LOG(2,("CRTC: frameRAM: $%08x\n",si->framebuffer)); 549 LOG(2,("CRTC: framebuffer: $%08x\n",si->fbc.frame_buffer)); 550 551 /* make sure we _just_ left retrace, because otherwise distortions */ 552 /* might occur during our reprogramming (no double buffering) */ 553 /* (verified on NM2160) */ 554 555 /* we might have no retraces during setmode! So: 556 * wait 25mS max. for retrace to occur (refresh > 40Hz) */ 557 //fixme? move this function to the kernel driver... is much 'faster'. 558 while ((!(ISARB(INSTAT1) & 0x08)) && (timeout < (25000/4))) 559 { 560 snooze(4); 561 timeout++; 562 } 563 /* now wait until retrace ends (with timeout) */ 564 timeout = 0; 565 while ((ISARB(INSTAT1) & 0x08) && (timeout < (25000/4))) 566 { 567 snooze(4); 568 timeout++; 569 } 570 571 /* set standard VGA registers */ 572 /* (startadress in 32bit words (b2 - b17) */ 573 ISACRTCW(FBSTADDH, ((startadd & 0x03fc00) >> 10)); 574 ISACRTCW(FBSTADDL, ((startadd & 0x0003fc) >> 2)); 575 576 /* set NM extended register */ 577 //fixme: NM2380 _must_ have one more bit (has >4Mb RAM)!! 578 //this is testable via virtualscreen in 640x480x8 mode... 579 //(b4 is >256Kb adresswrap bit, so that's already occupied) 580 val = ISAGRPHR(FBSTADDE); 581 /* we need to wait a bit or the card will mess-up it's */ 582 /* register values.. (NM2160) */ 583 snooze(10); 584 if (si->ps.card_type < NM2200) 585 /* extended bits: (b18-20) */ 586 ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x07) | (val & 0xf8))); 587 else 588 /* extended bits: (b18-21) */ 589 ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x0f) | (val & 0xf0))); 590 591 /* set byte adress: (b0 - 1): 592 * Neomagic cards work with _pixel_ offset here. */ 593 switch(bpp) 594 { 595 case 8: 596 ISAATBW(HORPIXPAN, (startadd & 0x00000003)); 597 break; 598 case 15: 599 case 16: 600 ISAATBW(HORPIXPAN, ((startadd & 0x00000002) >> 1)); 601 break; 602 case 24: 603 ISAATBW(HORPIXPAN, ((4 - (startadd & 0x00000003)) & 0x03)); 604 break; 605 } 606 607 return B_OK; 608 } 609 610 /* setup centering mode for current internal or simultaneous */ 611 /* flatpanel mode */ 612 status_t nm_crtc_center(display_mode target, bool crt_only) 613 { 614 /* note: 615 * NM2070 apparantly doesn't support horizontal */ 616 /* centering this way... */ 617 618 uint8 vcent1, vcent2, vcent3, vcent4, vcent5; 619 uint8 hcent1, hcent2, hcent3, hcent4, hcent5; 620 uint8 ctrl2, ctrl3; 621 622 /* preset no centering */ 623 uint16 hoffset = 0; 624 uint16 voffset = 0; 625 vcent1 = vcent2 = vcent3 = vcent4 = vcent5 = 0x00; 626 hcent1 = hcent2 = hcent3 = hcent4 = hcent5 = 0x00; 627 ctrl2 = ctrl3 = 0x00; 628 629 /* calculate offsets for centering if prudent */ 630 if (!crt_only) 631 { 632 if (target.timing.h_display < si->ps.panel_width) 633 { 634 hoffset = (si->ps.panel_width - target.timing.h_display); 635 /* adjust for register contraints: 636 * horizontal center granularity is 16 pixels */ 637 hoffset = ((hoffset >> 4) - 1); 638 /* turn on horizontal centering? */ 639 ctrl3 = 0x10; 640 } 641 642 if (target.timing.v_display < si->ps.panel_height) 643 { 644 voffset = (si->ps.panel_height - target.timing.v_display); 645 /* adjust for register contraints: 646 * vertical center granularity is 2 pixels */ 647 voffset = ((voffset >> 1) - 2); 648 /* turn on vertical centering? */ 649 ctrl2 = 0x01; 650 } 651 652 switch(target.timing.h_display) 653 { 654 case 640: 655 hcent1 = hoffset; 656 vcent3 = voffset; 657 break; 658 case 800: 659 hcent2 = hoffset; 660 switch(target.timing.v_display) 661 { 662 case 480: 663 //Linux fixme: check this out... 664 vcent3 = voffset; 665 break; 666 case 600: 667 vcent4 = voffset; 668 break; 669 } 670 break; 671 case 1024: 672 hcent5 = hoffset; 673 vcent5 = voffset; 674 break; 675 case 1280: 676 /* this mode equals the largest possible panel on the * 677 * newest chip: so no centering needed here. */ 678 break; 679 default: 680 //fixme?: block non-standard modes? for now: not centered. 681 break; 682 } 683 } 684 685 /* now program the card's registers */ 686 ISAGRPHW(PANELVCENT1, vcent1); 687 ISAGRPHW(PANELVCENT2, vcent2); 688 ISAGRPHW(PANELVCENT3, vcent3); 689 if (si->ps.card_type > NM2070) 690 { 691 ISAGRPHW(PANELVCENT4, vcent4); 692 ISAGRPHW(PANELHCENT1, hcent1); 693 ISAGRPHW(PANELHCENT2, hcent2); 694 ISAGRPHW(PANELHCENT3, hcent3); 695 } 696 if (si->ps.card_type >= NM2160) 697 { 698 ISAGRPHW(PANELHCENT4, hcent4); 699 } 700 if (si->ps.card_type >= NM2200) 701 { 702 ISAGRPHW(PANELVCENT5, vcent5); 703 ISAGRPHW(PANELHCENT5, hcent5); 704 } 705 706 /* program panel control register 2: don't touch bit 3-5 */ 707 ctrl2 |= (ISAGRPHR(PANELCTRL2) & 0x38); 708 /* we need to wait a bit or the card will mess-up it's register */ 709 /* values.. (NM2160) */ 710 snooze(10); 711 ISAGRPHW(PANELCTRL2, ctrl2); 712 713 if (si->ps.card_type > NM2070) 714 { 715 /* program panel control register 3: don't touch bit 7-5 */ 716 /* and bit 3-0 */ 717 ctrl3 |= (ISAGRPHR(PANELCTRL3) & 0xef); 718 /* we need to wait a bit or the card will mess-up it's */ 719 /* register values.. (NM2160) */ 720 snooze(10); 721 ISAGRPHW(PANELCTRL3, ctrl3); 722 } 723 724 return B_OK; 725 } 726 727 /* program panel modeline if needed */ 728 status_t nm_crtc_prg_panel() 729 { 730 status_t stat = B_ERROR; 731 732 /* only NM2070 requires this apparantly */ 733 /* (because it's BIOS doesn't do it OK) */ 734 if (si->ps.card_type > NM2070) return B_OK; 735 736 switch(si->ps.panel_width) 737 { 738 case 640: 739 /* 640x480 panels are only used on NM2070 */ 740 ISACRTCW(PANEL_0x40, 0x5f); 741 ISACRTCW(PANEL_0x41, 0x50); 742 ISACRTCW(PANEL_0x42, 0x02); 743 ISACRTCW(PANEL_0x43, 0x55); 744 ISACRTCW(PANEL_0x44, 0x81); 745 ISACRTCW(PANEL_0x45, 0x0b); 746 ISACRTCW(PANEL_0x46, 0x2e); 747 ISACRTCW(PANEL_0x47, 0xea); 748 ISACRTCW(PANEL_0x48, 0x0c); 749 ISACRTCW(PANEL_0x49, 0xe7); 750 ISACRTCW(PANEL_0x4a, 0x04); 751 ISACRTCW(PANEL_0x4b, 0x2d); 752 ISACRTCW(PANEL_0x4c, 0x28); 753 ISACRTCW(PANEL_0x4d, 0x90); 754 ISACRTCW(PANEL_0x4e, 0x2b); 755 ISACRTCW(PANEL_0x4f, 0xa0); 756 stat = B_OK; 757 break; 758 case 800: 759 switch(si->ps.panel_height) 760 { 761 case 600: 762 /* 800x600 panels are used on all cards... */ 763 ISACRTCW(PANEL_0x40, 0x7f); 764 ISACRTCW(PANEL_0x41, 0x63); 765 ISACRTCW(PANEL_0x42, 0x02); 766 ISACRTCW(PANEL_0x43, 0x6c); 767 ISACRTCW(PANEL_0x44, 0x1c); 768 ISACRTCW(PANEL_0x45, 0x72); 769 ISACRTCW(PANEL_0x46, 0xe0); 770 ISACRTCW(PANEL_0x47, 0x58); 771 ISACRTCW(PANEL_0x48, 0x0c); 772 ISACRTCW(PANEL_0x49, 0x57); 773 ISACRTCW(PANEL_0x4a, 0x73); 774 ISACRTCW(PANEL_0x4b, 0x3d); 775 ISACRTCW(PANEL_0x4c, 0x31); 776 ISACRTCW(PANEL_0x4d, 0x01); 777 ISACRTCW(PANEL_0x4e, 0x36); 778 ISACRTCW(PANEL_0x4f, 0x1e); 779 if (si->ps.card_type > NM2070) 780 { 781 ISACRTCW(PANEL_0x50, 0x6b); 782 ISACRTCW(PANEL_0x51, 0x4f); 783 ISACRTCW(PANEL_0x52, 0x0e); 784 ISACRTCW(PANEL_0x53, 0x58); 785 ISACRTCW(PANEL_0x54, 0x88); 786 ISACRTCW(PANEL_0x55, 0x33); 787 ISACRTCW(PANEL_0x56, 0x27); 788 ISACRTCW(PANEL_0x57, 0x16); 789 ISACRTCW(PANEL_0x58, 0x2c); 790 ISACRTCW(PANEL_0x59, 0x94); 791 } 792 stat = B_OK; 793 break; 794 case 480: 795 /* ...while 800x480 widescreen panels are not used on NM2070. */ 796 ISACRTCW(PANEL_0x40, 0x7f); 797 ISACRTCW(PANEL_0x41, 0x63); 798 ISACRTCW(PANEL_0x42, 0x02); 799 ISACRTCW(PANEL_0x43, 0x6b); 800 ISACRTCW(PANEL_0x44, 0x1b); 801 ISACRTCW(PANEL_0x45, 0x72); 802 ISACRTCW(PANEL_0x46, 0xe0); 803 ISACRTCW(PANEL_0x47, 0x1c); 804 ISACRTCW(PANEL_0x48, 0x00); 805 ISACRTCW(PANEL_0x49, 0x57); 806 ISACRTCW(PANEL_0x4a, 0x73); 807 ISACRTCW(PANEL_0x4b, 0x3e); 808 ISACRTCW(PANEL_0x4c, 0x31); 809 ISACRTCW(PANEL_0x4d, 0x01); 810 ISACRTCW(PANEL_0x4e, 0x36); 811 ISACRTCW(PANEL_0x4f, 0x1e); 812 ISACRTCW(PANEL_0x50, 0x6b); 813 ISACRTCW(PANEL_0x51, 0x4f); 814 ISACRTCW(PANEL_0x52, 0x0e); 815 ISACRTCW(PANEL_0x53, 0x57); 816 ISACRTCW(PANEL_0x54, 0x87); 817 ISACRTCW(PANEL_0x55, 0x33); 818 ISACRTCW(PANEL_0x56, 0x27); 819 ISACRTCW(PANEL_0x57, 0x16); 820 ISACRTCW(PANEL_0x58, 0x2c); 821 ISACRTCW(PANEL_0x59, 0x94); 822 stat = B_OK; 823 break; 824 } 825 break; 826 case 1024: 827 switch(si->ps.panel_height) 828 { 829 case 768: 830 /* 1024x768 panels are only used on later cards 831 * (NM2097 and later ?) */ 832 ISACRTCW(PANEL_0x40, 0xa3); 833 ISACRTCW(PANEL_0x41, 0x7f); 834 ISACRTCW(PANEL_0x42, 0x06); 835 ISACRTCW(PANEL_0x43, 0x85); 836 ISACRTCW(PANEL_0x44, 0x96); 837 ISACRTCW(PANEL_0x45, 0x24); 838 ISACRTCW(PANEL_0x46, 0xe5); 839 ISACRTCW(PANEL_0x47, 0x02); 840 ISACRTCW(PANEL_0x48, 0x08); 841 ISACRTCW(PANEL_0x49, 0xff); 842 ISACRTCW(PANEL_0x4a, 0x25); 843 ISACRTCW(PANEL_0x4b, 0x4f); 844 ISACRTCW(PANEL_0x4c, 0x40); 845 ISACRTCW(PANEL_0x4d, 0x00); 846 ISACRTCW(PANEL_0x4e, 0x44); 847 ISACRTCW(PANEL_0x4f, 0x0c); 848 ISACRTCW(PANEL_0x50, 0x7a); 849 ISACRTCW(PANEL_0x51, 0x56); 850 ISACRTCW(PANEL_0x52, 0x00); 851 ISACRTCW(PANEL_0x53, 0x5d); 852 ISACRTCW(PANEL_0x54, 0x0e); 853 ISACRTCW(PANEL_0x55, 0x3b); 854 ISACRTCW(PANEL_0x56, 0x2b); 855 ISACRTCW(PANEL_0x57, 0x00); 856 ISACRTCW(PANEL_0x58, 0x2f); 857 ISACRTCW(PANEL_0x59, 0x18); 858 ISACRTCW(PANEL_0x60, 0x88); 859 ISACRTCW(PANEL_0x61, 0x63); 860 ISACRTCW(PANEL_0x62, 0x0b); 861 ISACRTCW(PANEL_0x63, 0x69); 862 ISACRTCW(PANEL_0x64, 0x1a); 863 stat = B_OK; 864 break; 865 case 480: 866 /* 1024x480 widescreen panels are only used on later cards 867 * (NM2097 and later ?) */ 868 ISACRTCW(PANEL_0x40, 0xa3); 869 ISACRTCW(PANEL_0x41, 0x7f); 870 ISACRTCW(PANEL_0x42, 0x1b); 871 ISACRTCW(PANEL_0x43, 0x89); 872 ISACRTCW(PANEL_0x44, 0x16); 873 ISACRTCW(PANEL_0x45, 0x0b); 874 ISACRTCW(PANEL_0x46, 0x2c); 875 ISACRTCW(PANEL_0x47, 0xe8); 876 ISACRTCW(PANEL_0x48, 0x0c); 877 ISACRTCW(PANEL_0x49, 0xe7); 878 ISACRTCW(PANEL_0x4a, 0x09); 879 ISACRTCW(PANEL_0x4b, 0x4f); 880 ISACRTCW(PANEL_0x4c, 0x40); 881 ISACRTCW(PANEL_0x4d, 0x00); 882 ISACRTCW(PANEL_0x4e, 0x44); 883 ISACRTCW(PANEL_0x4f, 0x0c); 884 ISACRTCW(PANEL_0x50, 0x7a); 885 ISACRTCW(PANEL_0x51, 0x56); 886 ISACRTCW(PANEL_0x52, 0x00); 887 ISACRTCW(PANEL_0x53, 0x5d); 888 ISACRTCW(PANEL_0x54, 0x0e); 889 ISACRTCW(PANEL_0x55, 0x3b); 890 ISACRTCW(PANEL_0x56, 0x2a); 891 ISACRTCW(PANEL_0x57, 0x00); 892 ISACRTCW(PANEL_0x58, 0x2f); 893 ISACRTCW(PANEL_0x59, 0x18); 894 ISACRTCW(PANEL_0x60, 0x88); 895 ISACRTCW(PANEL_0x61, 0x63); 896 ISACRTCW(PANEL_0x62, 0x0b); 897 ISACRTCW(PANEL_0x63, 0x69); 898 ISACRTCW(PANEL_0x64, 0x1a); 899 stat = B_OK; 900 break; 901 } 902 break; 903 case 1280: 904 /* no info available */ 905 break; 906 } 907 908 if (stat != B_OK) 909 LOG(2,("CRTC: unable to program panel: unknown modeline needed.\n")); 910 911 return stat; 912 } 913 914 status_t nm_crtc_cursor_init() 915 { 916 int i; 917 vuint32 * fb; 918 uint32 curadd, curreg; 919 920 /* the cursor is at the end of cardRAM */ 921 curadd = ((si->ps.memory_size * 1024) - si->ps.curmem_size); 922 923 /* set cursor bitmap adress on a 1kb boundary, and move the bits around 924 * so they get placed at the correct registerbits */ 925 curreg = (((curadd >> 10) & 0x000f) << 8); 926 curreg |= (((curadd >> 10) & 0x0ff0) >> 4); 927 /* NM2380 must have an extra bit for > 4Mb: assuming it to be on b12... */ 928 curreg |= ((curadd >> 10) & 0x1000); 929 930 if (si->ps.card_type < NM2200) 931 CR1W(CURADDRESS, curreg); 932 else 933 CR1W(22CURADDRESS, curreg); 934 935 /*set cursor colour*/ 936 if (si->ps.card_type < NM2200) 937 { 938 /* background is black */ 939 CR1W(CURBGCOLOR, 0x00000000); 940 /* foreground is white */ 941 CR1W(CURFGCOLOR, 0x00ffffff); 942 } 943 else 944 { 945 /* background is black */ 946 CR1W(22CURBGCOLOR, 0x00000000); 947 /* foreground is white */ 948 CR1W(22CURFGCOLOR, 0x00ffffff); 949 } 950 951 /* we must set a valid colordepth to get full RAM access on Neomagic cards: 952 * in old pre 8-bit color VGA modes some planemask is in effect apparantly, 953 * allowing access only to every 7th and 8th RAM byte across the 954 * entire RAM. */ 955 nm_crtc_depth(BPP8); 956 957 /* clear cursor: so we need full RAM access! */ 958 fb = ((vuint32 *)(((uintptr_t)si->framebuffer) + curadd)); 959 for (i = 0; i < (1024/4); i++) 960 { 961 fb[i] = 0; 962 } 963 964 /* activate hardware cursor */ 965 nm_crtc_cursor_show(); 966 967 return B_OK; 968 } 969 970 status_t nm_crtc_cursor_show() 971 { 972 if (si->ps.card_type < NM2200) 973 { 974 CR1W(CURCTRL, 0x00000001); 975 } 976 else 977 { 978 CR1W(22CURCTRL, 0x00000001); 979 } 980 return B_OK; 981 } 982 983 status_t nm_crtc_cursor_hide() 984 { 985 //linux fixme: using this kills PCI(?) access sometimes, 986 //so use ISA access as below... 987 /* 988 if (si->ps.card_type < NM2200) 989 { 990 CR1W(CURCTRL, 0x00000000); 991 } 992 else 993 { 994 CR1W(22CURCTRL, 0x00000000); 995 } 996 */ 997 /* disable cursor */ 998 ISAGRPHW(CURCTRL,0x00); 999 1000 return B_OK; 1001 } 1002 1003 /*set up cursor shape*/ 1004 status_t nm_crtc_cursor_define(uint8* andMask,uint8* xorMask) 1005 { 1006 uint8 y; 1007 vuint8 * cursor; 1008 1009 /* get a pointer to the cursor: it's at the end of cardRAM */ 1010 cursor = (vuint8*) si->framebuffer; 1011 cursor += ((si->ps.memory_size * 1024) - si->ps.curmem_size); 1012 1013 /*draw the cursor*/ 1014 for(y=0;y<16;y++) 1015 { 1016 cursor[y*16+8]=~*andMask++; 1017 cursor[y*16+0]=*xorMask++; 1018 cursor[y*16+9]=~*andMask++; 1019 cursor[y*16+1]=*xorMask++; 1020 } 1021 1022 //test.. only valid for <NM2200!! 1023 /* { 1024 float pclk; 1025 uint8 n,m,x = 1; 1026 n = ISAGRPHR(PLLC_NL); 1027 m = ISAGRPHR(PLLC_M); 1028 LOG(4,("CRTC: PLLSEL $%02x\n", ISARB(MISCR))); 1029 LOG(4,("CRTC: PLLN $%02x\n", n)); 1030 LOG(4,("CRTC: PLLM $%02x\n", m)); 1031 1032 if (n & 0x80) x = 2; 1033 n &= 0x7f; 1034 pclk = ((si->ps.f_ref * (n + 1)) / ((m + 1) * x)); 1035 LOG(2,("CRTC: Pixelclock is %fMHz\n", pclk)); 1036 nm_general_output_select(); 1037 } 1038 */ 1039 return B_OK; 1040 } 1041 1042 /*position the cursor*/ 1043 status_t nm_crtc_cursor_position(uint16 x ,uint16 y) 1044 { 1045 //NM2160 is ok without this, still verify the rest..: 1046 /* make sure we are not in retrace, because the register(s) might get copied 1047 * during our reprogramming them (double buffering feature) */ 1048 /* fixme!? 1049 while (ACCR(STATUS) & 0x08) 1050 { 1051 snooze(4); 1052 } 1053 */ 1054 if (si->ps.card_type < NM2200) 1055 { 1056 CR1W(CURX, (uint32)x); 1057 CR1W(CURY, (uint32)y); 1058 } 1059 else 1060 { 1061 CR1W(22CURX, (uint32)x); 1062 CR1W(22CURY, (uint32)y); 1063 } 1064 1065 return B_OK; 1066 } 1067