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