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, 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 char msg[100]; 390 uint8 temp, size_outputs; 391 392 sprintf(msg, "CRTC: setting DPMS: "); 393 394 /* start synchronous reset: required before turning screen off! */ 395 ISASEQW(RESET, 0x01); 396 397 /* turn screen off */ 398 temp = ISASEQR(CLKMODE); 399 /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ 400 snooze(10); 401 402 if (display) 403 { 404 ISASEQW(CLKMODE, (temp & ~0x20)); 405 406 /* end synchronous reset if display should be enabled */ 407 ISASEQW(RESET, 0x03); 408 sprintf(msg, "%sdisplay on, ", msg); 409 } 410 else 411 { 412 ISASEQW(CLKMODE, (temp | 0x20)); 413 sprintf(msg, "%sdisplay off, ", msg); 414 } 415 416 temp = 0x00; 417 if (h) 418 { 419 sprintf(msg, "%shsync enabled, ", msg); 420 } 421 else 422 { 423 temp |= 0x10; 424 sprintf(msg, "%shsync disabled, ", msg); 425 } 426 if (v) 427 { 428 sprintf(msg, "%svsync enabled\n", msg); 429 } 430 else 431 { 432 temp |= 0x20; 433 sprintf(msg, "%svsync disabled\n", msg); 434 } 435 436 LOG(4, (msg)); 437 438 /* read panelsize and currently active outputs */ 439 size_outputs = nm_general_output_read(); 440 /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ 441 snooze(10); 442 443 if (si->ps.card_type < NM2200) 444 { 445 /* no full DPMS support */ 446 if (temp) 447 { 448 /* Turn panel plus backlight and external monitor's sync signals off */ 449 ISAGRPHW(PANELCTRL1, (size_outputs & 0xfc)); 450 } 451 else 452 { 453 /* restore 'previous' output device(s) */ 454 ISAGRPHW(PANELCTRL1, size_outputs); 455 } 456 } 457 else 458 { 459 if (temp) 460 { 461 /* Turn panel plus backlight off */ 462 ISAGRPHW(PANELCTRL1, (size_outputs & 0xfd)); 463 } 464 else 465 { 466 /* restore 'previous' panel situation */ 467 ISAGRPHW(PANELCTRL1, size_outputs); 468 } 469 470 /* if external monitor is active, update it's DPMS state */ 471 if (size_outputs & 0x01) 472 { 473 /* we have full DPMS support for external monitors */ 474 //fixme: checkout if so... 475 temp |= ((ISAGRPHR(ENSETRESET) & 0x0f) | 0x80); 476 /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ 477 snooze(10); 478 ISAGRPHW(ENSETRESET, temp); 479 480 snooze(10); 481 LOG(4,("CRTC: DPMS readback $%02x, programmed $%02x\n", ISAGRPHR(ENSETRESET), temp)); 482 } 483 } 484 485 return B_OK; 486 } 487 488 status_t nm_crtc_set_display_pitch() 489 { 490 uint32 offset; 491 492 LOG(4,("CRTC: setting card pitch (offset between lines)\n")); 493 494 /* figure out offset value hardware needs: same for all Neomagic cards */ 495 offset = si->fbc.bytes_per_row / 8; 496 497 LOG(2,("CRTC: offset register set to: $%04x\n", offset)); 498 499 /* program the card */ 500 ISACRTCW(PITCHL, (offset & 0xff)); 501 //fixme: test for max supported pitch if possible, 502 //not all bits below will be implemented. 503 //NM2160: confirmed b0 and b1 in register below to exist and work. 504 if (si->ps.card_type != NM2070) 505 ISAGRPHW(CRTC_PITCHE, ((offset & 0xff00) >> 8)); 506 507 return B_OK; 508 } 509 510 status_t nm_crtc_set_display_start(uint32 startadd,uint8 bpp) 511 { 512 uint8 val; 513 uint32 timeout = 0; 514 515 LOG(2,("CRTC: relative startadd: $%06x\n",startadd)); 516 LOG(2,("CRTC: frameRAM: $%08x\n",si->framebuffer)); 517 LOG(2,("CRTC: framebuffer: $%08x\n",si->fbc.frame_buffer)); 518 519 /* make sure we _just_ left retrace, because otherwise distortions might occur 520 * during our reprogramming (no double buffering) (verified on NM2160) */ 521 522 /* we might have no retraces during setmode! So: 523 * wait 25mS max. for retrace to occur (refresh > 40Hz) */ 524 //fixme? move this function to the kernel driver... is much 'faster'. 525 while ((!(ISARB(INSTAT1) & 0x08)) && (timeout < (25000/4))) 526 { 527 snooze(4); 528 timeout++; 529 } 530 /* now wait until retrace ends (with timeout) */ 531 timeout = 0; 532 while ((ISARB(INSTAT1) & 0x08) && (timeout < (25000/4))) 533 { 534 snooze(4); 535 timeout++; 536 } 537 538 /* set standard VGA registers */ 539 /* (startadress in 32bit words (b2 - b17) */ 540 ISACRTCW(FBSTADDH, ((startadd & 0x03fc00) >> 10)); 541 ISACRTCW(FBSTADDL, ((startadd & 0x0003fc) >> 2)); 542 543 /* set NM extended register */ 544 //fixme: NM2380 _must_ have one more bit (has >4Mb RAM)!! 545 //this is testable via virtualscreen in 640x480x8 mode... 546 //(b4 is >256Kb adresswrap bit, so that's already occupied) 547 val = ISAGRPHR(FBSTADDE); 548 /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ 549 snooze(10); 550 if (si->ps.card_type < NM2200) 551 /* extended bits: (b18-20) */ 552 ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x07) | (val & 0xf8))); 553 else 554 /* extended bits: (b18-21) */ 555 ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x0f) | (val & 0xf0))); 556 557 /* set byte adress: (b0 - 1): 558 * Neomagic cards work with _pixel_ offset here. */ 559 switch(bpp) 560 { 561 case 8: 562 ISAATBW(HORPIXPAN, (startadd & 0x00000003)); 563 break; 564 case 15: 565 case 16: 566 ISAATBW(HORPIXPAN, ((startadd & 0x00000002) >> 1)); 567 break; 568 case 24: 569 ISAATBW(HORPIXPAN, ((4 - (startadd & 0x00000003)) & 0x03)); 570 break; 571 } 572 573 return B_OK; 574 } 575 576 /* setup centering mode for current internal or simultaneous flatpanel mode */ 577 status_t nm_crtc_center(display_mode target, bool crt_only) 578 { 579 /* note: 580 * NM2070 apparantly doesn't support horizontal centering this way... */ 581 582 uint8 vcent1, vcent2, vcent3, vcent4, vcent5; 583 uint8 hcent1, hcent2, hcent3, hcent4, hcent5; 584 uint8 ctrl2, ctrl3; 585 586 /* preset no centering */ 587 uint16 hoffset = 0; 588 uint16 voffset = 0; 589 vcent1 = vcent2 = vcent3 = vcent4 = vcent5 = 0x00; 590 hcent1 = hcent2 = hcent3 = hcent4 = hcent5 = 0x00; 591 ctrl2 = ctrl3 = 0x00; 592 593 /* calculate offsets for centering if prudent */ 594 if (!crt_only) 595 { 596 if (target.timing.h_display < si->ps.panel_width) 597 { 598 hoffset = (si->ps.panel_width - target.timing.h_display); 599 /* adjust for register contraints: 600 * horizontal center granularity is 16 pixels */ 601 hoffset = ((hoffset >> 4) - 1); 602 /* turn on horizontal centering? */ 603 ctrl3 = 0x10; 604 } 605 606 if (target.timing.v_display < si->ps.panel_height) 607 { 608 voffset = (si->ps.panel_height - target.timing.v_display); 609 /* adjust for register contraints: 610 * vertical center granularity is 2 pixels */ 611 voffset = ((voffset >> 1) - 2); 612 /* turn on vertical centering? */ 613 ctrl2 = 0x01; 614 } 615 616 switch(target.timing.h_display) 617 { 618 case 640: 619 hcent1 = hoffset; 620 vcent3 = voffset; 621 break; 622 case 800: 623 hcent2 = hoffset; 624 switch(target.timing.v_display) 625 { 626 case 480: 627 //Linux fixme: check this out... 628 vcent3 = voffset; 629 break; 630 case 600: 631 vcent4 = voffset; 632 break; 633 } 634 break; 635 case 1024: 636 hcent5 = hoffset; 637 vcent5 = voffset; 638 break; 639 case 1280: 640 /* this mode equals the largest possible panel on the newest chip: 641 * so no centering needed here. */ 642 break; 643 default: 644 //fixme?: block non-standard modes? for now: not centered. 645 break; 646 } 647 } 648 649 /* now program the card's registers */ 650 ISAGRPHW(PANELVCENT1, vcent1); 651 ISAGRPHW(PANELVCENT2, vcent2); 652 ISAGRPHW(PANELVCENT3, vcent3); 653 if (si->ps.card_type > NM2070) 654 { 655 ISAGRPHW(PANELVCENT4, vcent4); 656 ISAGRPHW(PANELHCENT1, hcent1); 657 ISAGRPHW(PANELHCENT2, hcent2); 658 ISAGRPHW(PANELHCENT3, hcent3); 659 } 660 if (si->ps.card_type >= NM2160) 661 { 662 ISAGRPHW(PANELHCENT4, hcent4); 663 } 664 if (si->ps.card_type >= NM2200) 665 { 666 ISAGRPHW(PANELVCENT5, vcent5); 667 ISAGRPHW(PANELHCENT5, hcent5); 668 } 669 670 /* program panel control register 2: don't touch bit 3-5 */ 671 ctrl2 |= (ISAGRPHR(PANELCTRL2) & 0x38); 672 /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ 673 snooze(10); 674 ISAGRPHW(PANELCTRL2, ctrl2); 675 676 if (si->ps.card_type > NM2070) 677 { 678 /* program panel control register 3: don't touch bit 7-5 and bit 3-0 */ 679 ctrl3 |= (ISAGRPHR(PANELCTRL3) & 0xef); 680 /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ 681 snooze(10); 682 ISAGRPHW(PANELCTRL3, ctrl3); 683 } 684 685 return B_OK; 686 } 687 688 /* program panel modeline if needed */ 689 status_t nm_crtc_prg_panel() 690 { 691 status_t stat = B_ERROR; 692 693 /* only NM2070 requires this apparantly (because it's BIOS doesn't do it OK) */ 694 if (si->ps.card_type > NM2070) return B_OK; 695 696 switch(si->ps.panel_width) 697 { 698 case 640: 699 /* 640x480 panels are only used on NM2070 */ 700 ISACRTCW(PANEL_0x40, 0x5f); 701 ISACRTCW(PANEL_0x41, 0x50); 702 ISACRTCW(PANEL_0x42, 0x02); 703 ISACRTCW(PANEL_0x43, 0x55); 704 ISACRTCW(PANEL_0x44, 0x81); 705 ISACRTCW(PANEL_0x45, 0x0b); 706 ISACRTCW(PANEL_0x46, 0x2e); 707 ISACRTCW(PANEL_0x47, 0xea); 708 ISACRTCW(PANEL_0x48, 0x0c); 709 ISACRTCW(PANEL_0x49, 0xe7); 710 ISACRTCW(PANEL_0x4a, 0x04); 711 ISACRTCW(PANEL_0x4b, 0x2d); 712 ISACRTCW(PANEL_0x4c, 0x28); 713 ISACRTCW(PANEL_0x4d, 0x90); 714 ISACRTCW(PANEL_0x4e, 0x2b); 715 ISACRTCW(PANEL_0x4f, 0xa0); 716 stat = B_OK; 717 break; 718 case 800: 719 switch(si->ps.panel_height) 720 { 721 case 600: 722 /* 800x600 panels are used on all cards... */ 723 ISACRTCW(PANEL_0x40, 0x7f); 724 ISACRTCW(PANEL_0x41, 0x63); 725 ISACRTCW(PANEL_0x42, 0x02); 726 ISACRTCW(PANEL_0x43, 0x6c); 727 ISACRTCW(PANEL_0x44, 0x1c); 728 ISACRTCW(PANEL_0x45, 0x72); 729 ISACRTCW(PANEL_0x46, 0xe0); 730 ISACRTCW(PANEL_0x47, 0x58); 731 ISACRTCW(PANEL_0x48, 0x0c); 732 ISACRTCW(PANEL_0x49, 0x57); 733 ISACRTCW(PANEL_0x4a, 0x73); 734 ISACRTCW(PANEL_0x4b, 0x3d); 735 ISACRTCW(PANEL_0x4c, 0x31); 736 ISACRTCW(PANEL_0x4d, 0x01); 737 ISACRTCW(PANEL_0x4e, 0x36); 738 ISACRTCW(PANEL_0x4f, 0x1e); 739 if (si->ps.card_type > NM2070) 740 { 741 ISACRTCW(PANEL_0x50, 0x6b); 742 ISACRTCW(PANEL_0x51, 0x4f); 743 ISACRTCW(PANEL_0x52, 0x0e); 744 ISACRTCW(PANEL_0x53, 0x58); 745 ISACRTCW(PANEL_0x54, 0x88); 746 ISACRTCW(PANEL_0x55, 0x33); 747 ISACRTCW(PANEL_0x56, 0x27); 748 ISACRTCW(PANEL_0x57, 0x16); 749 ISACRTCW(PANEL_0x58, 0x2c); 750 ISACRTCW(PANEL_0x59, 0x94); 751 } 752 stat = B_OK; 753 break; 754 case 480: 755 /* ...while 800x480 widescreen panels are not used on NM2070. */ 756 ISACRTCW(PANEL_0x40, 0x7f); 757 ISACRTCW(PANEL_0x41, 0x63); 758 ISACRTCW(PANEL_0x42, 0x02); 759 ISACRTCW(PANEL_0x43, 0x6b); 760 ISACRTCW(PANEL_0x44, 0x1b); 761 ISACRTCW(PANEL_0x45, 0x72); 762 ISACRTCW(PANEL_0x46, 0xe0); 763 ISACRTCW(PANEL_0x47, 0x1c); 764 ISACRTCW(PANEL_0x48, 0x00); 765 ISACRTCW(PANEL_0x49, 0x57); 766 ISACRTCW(PANEL_0x4a, 0x73); 767 ISACRTCW(PANEL_0x4b, 0x3e); 768 ISACRTCW(PANEL_0x4c, 0x31); 769 ISACRTCW(PANEL_0x4d, 0x01); 770 ISACRTCW(PANEL_0x4e, 0x36); 771 ISACRTCW(PANEL_0x4f, 0x1e); 772 ISACRTCW(PANEL_0x50, 0x6b); 773 ISACRTCW(PANEL_0x51, 0x4f); 774 ISACRTCW(PANEL_0x52, 0x0e); 775 ISACRTCW(PANEL_0x53, 0x57); 776 ISACRTCW(PANEL_0x54, 0x87); 777 ISACRTCW(PANEL_0x55, 0x33); 778 ISACRTCW(PANEL_0x56, 0x27); 779 ISACRTCW(PANEL_0x57, 0x16); 780 ISACRTCW(PANEL_0x58, 0x2c); 781 ISACRTCW(PANEL_0x59, 0x94); 782 stat = B_OK; 783 break; 784 } 785 break; 786 case 1024: 787 switch(si->ps.panel_height) 788 { 789 case 768: 790 /* 1024x768 panels are only used on later cards 791 * (NM2097 and later ?) */ 792 ISACRTCW(PANEL_0x40, 0xa3); 793 ISACRTCW(PANEL_0x41, 0x7f); 794 ISACRTCW(PANEL_0x42, 0x06); 795 ISACRTCW(PANEL_0x43, 0x85); 796 ISACRTCW(PANEL_0x44, 0x96); 797 ISACRTCW(PANEL_0x45, 0x24); 798 ISACRTCW(PANEL_0x46, 0xe5); 799 ISACRTCW(PANEL_0x47, 0x02); 800 ISACRTCW(PANEL_0x48, 0x08); 801 ISACRTCW(PANEL_0x49, 0xff); 802 ISACRTCW(PANEL_0x4a, 0x25); 803 ISACRTCW(PANEL_0x4b, 0x4f); 804 ISACRTCW(PANEL_0x4c, 0x40); 805 ISACRTCW(PANEL_0x4d, 0x00); 806 ISACRTCW(PANEL_0x4e, 0x44); 807 ISACRTCW(PANEL_0x4f, 0x0c); 808 ISACRTCW(PANEL_0x50, 0x7a); 809 ISACRTCW(PANEL_0x51, 0x56); 810 ISACRTCW(PANEL_0x52, 0x00); 811 ISACRTCW(PANEL_0x53, 0x5d); 812 ISACRTCW(PANEL_0x54, 0x0e); 813 ISACRTCW(PANEL_0x55, 0x3b); 814 ISACRTCW(PANEL_0x56, 0x2b); 815 ISACRTCW(PANEL_0x57, 0x00); 816 ISACRTCW(PANEL_0x58, 0x2f); 817 ISACRTCW(PANEL_0x59, 0x18); 818 ISACRTCW(PANEL_0x60, 0x88); 819 ISACRTCW(PANEL_0x61, 0x63); 820 ISACRTCW(PANEL_0x62, 0x0b); 821 ISACRTCW(PANEL_0x63, 0x69); 822 ISACRTCW(PANEL_0x64, 0x1a); 823 stat = B_OK; 824 break; 825 case 480: 826 /* 1024x480 widescreen panels are only used on later cards 827 * (NM2097 and later ?) */ 828 ISACRTCW(PANEL_0x40, 0xa3); 829 ISACRTCW(PANEL_0x41, 0x7f); 830 ISACRTCW(PANEL_0x42, 0x1b); 831 ISACRTCW(PANEL_0x43, 0x89); 832 ISACRTCW(PANEL_0x44, 0x16); 833 ISACRTCW(PANEL_0x45, 0x0b); 834 ISACRTCW(PANEL_0x46, 0x2c); 835 ISACRTCW(PANEL_0x47, 0xe8); 836 ISACRTCW(PANEL_0x48, 0x0c); 837 ISACRTCW(PANEL_0x49, 0xe7); 838 ISACRTCW(PANEL_0x4a, 0x09); 839 ISACRTCW(PANEL_0x4b, 0x4f); 840 ISACRTCW(PANEL_0x4c, 0x40); 841 ISACRTCW(PANEL_0x4d, 0x00); 842 ISACRTCW(PANEL_0x4e, 0x44); 843 ISACRTCW(PANEL_0x4f, 0x0c); 844 ISACRTCW(PANEL_0x50, 0x7a); 845 ISACRTCW(PANEL_0x51, 0x56); 846 ISACRTCW(PANEL_0x52, 0x00); 847 ISACRTCW(PANEL_0x53, 0x5d); 848 ISACRTCW(PANEL_0x54, 0x0e); 849 ISACRTCW(PANEL_0x55, 0x3b); 850 ISACRTCW(PANEL_0x56, 0x2a); 851 ISACRTCW(PANEL_0x57, 0x00); 852 ISACRTCW(PANEL_0x58, 0x2f); 853 ISACRTCW(PANEL_0x59, 0x18); 854 ISACRTCW(PANEL_0x60, 0x88); 855 ISACRTCW(PANEL_0x61, 0x63); 856 ISACRTCW(PANEL_0x62, 0x0b); 857 ISACRTCW(PANEL_0x63, 0x69); 858 ISACRTCW(PANEL_0x64, 0x1a); 859 stat = B_OK; 860 break; 861 } 862 break; 863 case 1280: 864 /* no info available */ 865 break; 866 } 867 868 if (stat != B_OK) 869 LOG(2,("CRTC: unable to program panel: unknown modeline needed.\n")); 870 871 return stat; 872 } 873 874 status_t nm_crtc_cursor_init() 875 { 876 int i; 877 vuint32 * fb; 878 uint32 curadd, curreg; 879 880 /* the cursor is at the end of cardRAM */ 881 curadd = ((si->ps.memory_size * 1024) - si->ps.curmem_size); 882 883 /* set cursor bitmap adress on a 1kb boundary, and move the bits around 884 * so they get placed at the correct registerbits */ 885 curreg = (((curadd >> 10) & 0x000f) << 8); 886 curreg |= (((curadd >> 10) & 0x0ff0) >> 4); 887 /* NM2380 must have an extra bit for > 4Mb: assuming it to be on b12... */ 888 curreg |= ((curadd >> 10) & 0x1000); 889 890 if (si->ps.card_type < NM2200) 891 CR1W(CURADDRESS, curreg); 892 else 893 CR1W(22CURADDRESS, curreg); 894 895 /*set cursor colour*/ 896 if (si->ps.card_type < NM2200) 897 { 898 /* background is black */ 899 CR1W(CURBGCOLOR, 0x00000000); 900 /* foreground is white */ 901 CR1W(CURFGCOLOR, 0x00ffffff); 902 } 903 else 904 { 905 /* background is black */ 906 CR1W(22CURBGCOLOR, 0x00000000); 907 /* foreground is white */ 908 CR1W(22CURFGCOLOR, 0x00ffffff); 909 } 910 911 /* we must set a valid colordepth to get full RAM access on Neomagic cards: 912 * in old pre 8-bit color VGA modes some planemask is in effect apparantly, 913 * allowing access only to every 7th and 8th RAM byte across the entire RAM. */ 914 nm_crtc_depth(BPP8); 915 916 /* clear cursor: so we need full RAM access! */ 917 fb = ((vuint32 *)(((uint32)si->framebuffer) + curadd)); 918 for (i = 0; i < (1024/4); i++) 919 { 920 fb[i] = 0; 921 } 922 923 /* activate hardware cursor */ 924 nm_crtc_cursor_show(); 925 926 return B_OK; 927 } 928 929 status_t nm_crtc_cursor_show() 930 { 931 if (si->ps.card_type < NM2200) 932 { 933 CR1W(CURCTRL, 0x00000001); 934 } 935 else 936 { 937 CR1W(22CURCTRL, 0x00000001); 938 } 939 return B_OK; 940 } 941 942 status_t nm_crtc_cursor_hide() 943 { 944 //linux fixme: using this kills PCI(?) access sometimes, so use ISA access as below... 945 /* 946 if (si->ps.card_type < NM2200) 947 { 948 CR1W(CURCTRL, 0x00000000); 949 } 950 else 951 { 952 CR1W(22CURCTRL, 0x00000000); 953 } 954 */ 955 /* disable cursor */ 956 ISAGRPHW(CURCTRL,0x00); 957 958 return B_OK; 959 } 960 961 /*set up cursor shape*/ 962 status_t nm_crtc_cursor_define(uint8* andMask,uint8* xorMask) 963 { 964 uint8 y; 965 vuint8 * cursor; 966 967 /* get a pointer to the cursor: it's at the end of cardRAM */ 968 cursor = (vuint8*) si->framebuffer; 969 cursor += ((si->ps.memory_size * 1024) - si->ps.curmem_size); 970 971 /*draw the cursor*/ 972 for(y=0;y<16;y++) 973 { 974 cursor[y*16+8]=~*andMask++; 975 cursor[y*16+0]=*xorMask++; 976 cursor[y*16+9]=~*andMask++; 977 cursor[y*16+1]=*xorMask++; 978 } 979 980 //test.. only valid for <NM2200!! 981 /* { 982 float pclk; 983 uint8 n,m,x = 1; 984 n = ISAGRPHR(PLLC_NL); 985 m = ISAGRPHR(PLLC_M); 986 LOG(4,("CRTC: PLLSEL $%02x\n", ISARB(MISCR))); 987 LOG(4,("CRTC: PLLN $%02x\n", n)); 988 LOG(4,("CRTC: PLLM $%02x\n", m)); 989 990 if (n & 0x80) x = 2; 991 n &= 0x7f; 992 pclk = ((si->ps.f_ref * (n + 1)) / ((m + 1) * x)); 993 LOG(2,("CRTC: Pixelclock is %fMHz\n", pclk)); 994 nm_general_output_select(); 995 } 996 */ 997 return B_OK; 998 } 999 1000 /*position the cursor*/ 1001 status_t nm_crtc_cursor_position(uint16 x ,uint16 y) 1002 { 1003 //NM2160 is ok without this, still verify the rest..: 1004 /* make sure we are not in retrace, because the register(s) might get copied 1005 * during our reprogramming them (double buffering feature) */ 1006 /* fixme!? 1007 while (ACCR(STATUS) & 0x08) 1008 { 1009 snooze(4); 1010 } 1011 */ 1012 if (si->ps.card_type < NM2200) 1013 { 1014 CR1W(CURX, (uint32)x); 1015 CR1W(CURY, (uint32)y); 1016 } 1017 else 1018 { 1019 CR1W(22CURX, (uint32)x); 1020 CR1W(22CURY, (uint32)y); 1021 } 1022 1023 return B_OK; 1024 } 1025