1 /* CTRC functionality */ 2 /* Author: 3 Rudolf Cornelissen 11/2002-4/2004 4 */ 5 6 #define MODULE_BIT 0x00040000 7 8 #include "nv_std.h" 9 10 /*Adjust passed parameters to a valid mode line*/ 11 status_t nv_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 > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3); 25 if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3); 26 if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3); 27 if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 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 (si->ps.card_type > NV04) 33 { 34 if (*hd_e > 2048) *hd_e = 2048; 35 } 36 else 37 { 38 if (*hd_e > 1920) *hd_e = 1920; 39 } 40 41 /* if hor. total does not leave room for a sensible sync pulse, increase it! */ 42 if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); 43 44 /* make sure sync pulse is not during display */ 45 if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); 46 if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); 47 48 /* correct sync pulse if it is too long: 49 * there are only 5 bits available to save this in the card registers! */ 50 if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); 51 52 /*vertical*/ 53 /* confine to required number of bits, taking logic into account */ 54 //fixme if needed: on GeForce cards there are 12 instead of 11 bits... 55 if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); 56 if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); 57 if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; 58 if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); 59 60 /* confine to a reasonable height */ 61 if (*vd_e < 480) *vd_e = 480; 62 if (si->ps.card_type > NV04) 63 { 64 if (*vd_e > 1536) *vd_e = 1536; 65 } 66 else 67 { 68 if (*vd_e > 1440) *vd_e = 1440; 69 } 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 /* make sure sync pulse is not during display */ 75 if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); 76 if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); 77 78 /* correct sync pulse if it is too long: 79 * there are only 4 bits available to save this in the card registers! */ 80 if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); 81 82 return B_OK; 83 } 84 85 /*set a mode line - inputs are in pixels*/ 86 status_t nv_crtc_set_timing(display_mode target) 87 { 88 uint8 temp; 89 90 uint32 htotal; /*total horizontal total VCLKs*/ 91 uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ 92 uint32 hsync_s; /*begin of horizontal sync pulse*/ 93 uint32 hsync_e; /*end of horizontal sync pulse*/ 94 uint32 hblnk_s; /*begin horizontal blanking*/ 95 uint32 hblnk_e; /*end horizontal blanking*/ 96 97 uint32 vtotal; /*total vertical total scanlines*/ 98 uint32 vdisp_e; /*end of vertical display*/ 99 uint32 vsync_s; /*begin of vertical sync pulse*/ 100 uint32 vsync_e; /*end of vertical sync pulse*/ 101 uint32 vblnk_s; /*begin vertical blanking*/ 102 uint32 vblnk_e; /*end vertical blanking*/ 103 104 uint32 linecomp; /*split screen and vdisp_e interrupt*/ 105 106 LOG(4,("CRTC: setting timing\n")); 107 108 /* setup fixed modeline for flatpanel if connected and active */ 109 if (si->ps.tmds1_active) 110 { 111 LOG(2,("CRTC: DFP active: tuning modeline\n")); 112 113 /* horizontal timing */ 114 //fixme (?): maybe we need real modeline calculations here... 115 //testing (640x480): total = 135% is too much, 120% to small... 116 target.timing.h_total = target.timing.h_display + 160;//128 117 target.timing.h_sync_start = target.timing.h_total - 144;//112 118 target.timing.h_sync_end = target.timing.h_total - 48;//16 119 120 /* vertical timing */ 121 target.timing.v_total = target.timing.v_display + 6; 122 target.timing.v_sync_start = target.timing.v_total - 3; 123 target.timing.v_sync_end = target.timing.v_total - 2; 124 125 /* disable GPU scaling testmode so automatic scaling will be done */ 126 DACW(FP_DEBUG1, 0); 127 } 128 129 /* Modify parameters as required by standard VGA */ 130 htotal = ((target.timing.h_total >> 3) - 5); 131 hdisp_e = ((target.timing.h_display >> 3) - 1); 132 hblnk_s = hdisp_e; 133 hblnk_e = (htotal + 4);//0; 134 hsync_s = (target.timing.h_sync_start >> 3); 135 hsync_e = (target.timing.h_sync_end >> 3); 136 137 vtotal = target.timing.v_total - 2; 138 vdisp_e = target.timing.v_display - 1; 139 vblnk_s = vdisp_e; 140 vblnk_e = (vtotal + 1); 141 vsync_s = target.timing.v_sync_start;//-1; 142 vsync_e = target.timing.v_sync_end;//-1; 143 144 /* prevent memory adress counter from being reset (linecomp may not occur) */ 145 linecomp = target.timing.v_display; 146 147 /* enable access to CRTC1 on dualhead cards */ 148 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 149 150 /* Note for laptop and DVI flatpanels: 151 * CRTC timing has a seperate set of registers from flatpanel timing. 152 * The flatpanel timing registers have scaling registers that are used to match 153 * these two modelines. */ 154 { 155 LOG(4,("CRTC: Setting full timing...\n")); 156 157 /* log the mode that will be set */ 158 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)); 159 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)); 160 161 /* actually program the card! */ 162 /* unlock CRTC registers at index 0-7 */ 163 CRTCW(VSYNCE, (CRTCR(VSYNCE) & 0x7f)); 164 /* horizontal standard VGA regs */ 165 CRTCW(HTOTAL, (htotal & 0xff)); 166 CRTCW(HDISPE, (hdisp_e & 0xff)); 167 CRTCW(HBLANKS, (hblnk_s & 0xff)); 168 /* also unlock vertical retrace registers in advance */ 169 CRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); 170 CRTCW(HSYNCS, (hsync_s & 0xff)); 171 CRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); 172 173 /* vertical standard VGA regs */ 174 CRTCW(VTOTAL, (vtotal & 0xff)); 175 CRTCW(OVERFLOW, 176 ( 177 ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | 178 ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | 179 ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | 180 ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) 181 )); 182 CRTCW(PRROWSCN, 0x00); /* not used */ 183 CRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)))); 184 CRTCW(VSYNCS, (vsync_s & 0xff)); 185 CRTCW(VSYNCE, ((CRTCR(VSYNCE) & 0xf0) | (vsync_e & 0x0f))); 186 CRTCW(VDISPE, (vdisp_e & 0xff)); 187 CRTCW(VBLANKS, (vblnk_s & 0xff)); 188 CRTCW(VBLANKE, (vblnk_e & 0xff)); 189 CRTCW(LINECOMP, (linecomp & 0xff)); 190 191 /* horizontal extended regs */ 192 //fixme: we reset bit4. is this correct?? 193 CRTCW(HEB, (CRTCR(HEB) & 0xe0) | 194 ( 195 ((htotal & 0x100) >> (8 - 0)) | 196 ((hdisp_e & 0x100) >> (8 - 1)) | 197 ((hblnk_s & 0x100) >> (8 - 2)) | 198 ((hsync_s & 0x100) >> (8 - 3)) 199 )); 200 201 /* (mostly) vertical extended regs */ 202 CRTCW(LSR, 203 ( 204 ((vtotal & 0x400) >> (10 - 0)) | 205 ((vdisp_e & 0x400) >> (10 - 1)) | 206 ((vsync_s & 0x400) >> (10 - 2)) | 207 ((vblnk_s & 0x400) >> (10 - 3)) | 208 ((hblnk_e & 0x040) >> (6 - 4)) 209 //fixme: we still miss one linecomp bit!?! is this it?? 210 //| ((linecomp & 0x400) >> 3) 211 )); 212 213 /* more vertical extended regs (on GeForce cards only) */ 214 if (si->ps.card_arch >= NV10A) 215 { 216 CRTCW(EXTRA, 217 ( 218 ((vtotal & 0x800) >> (11 - 0)) | 219 ((vdisp_e & 0x800) >> (11 - 2)) | 220 ((vsync_s & 0x800) >> (11 - 4)) | 221 ((vblnk_s & 0x800) >> (11 - 6)) 222 //fixme: do we miss another linecomp bit!?! 223 )); 224 } 225 226 /* setup 'large screen' mode */ 227 if (target.timing.h_display >= 1280) 228 CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xfb)); 229 else 230 CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x04)); 231 232 /* setup HSYNC & VSYNC polarity */ 233 LOG(2,("CRTC: sync polarity: ")); 234 temp = NV_REG8(NV8_MISCR); 235 if (target.timing.flags & B_POSITIVE_HSYNC) 236 { 237 LOG(2,("H:pos ")); 238 temp &= ~0x40; 239 } 240 else 241 { 242 LOG(2,("H:neg ")); 243 temp |= 0x40; 244 } 245 if (target.timing.flags & B_POSITIVE_VSYNC) 246 { 247 LOG(2,("V:pos ")); 248 temp &= ~0x80; 249 } 250 else 251 { 252 LOG(2,("V:neg ")); 253 temp |= 0x80; 254 } 255 NV_REG8(NV8_MISCW) = temp; 256 257 LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR))); 258 } 259 260 /* always disable interlaced operation */ 261 /* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */ 262 CRTCW(INTERLACE, 0xff); 263 264 /* setup flatpanel if connected and active */ 265 if (si->ps.tmds1_active) 266 { 267 uint32 iscale_x, iscale_y; 268 269 /* powerup both LVDS (laptop panellink) and TMDS (DVI panellink) transmitters */ 270 //fixme: remove once DPMS confirmed OK! 271 // DACW(FP_DEBUG0, (DACR(FP_DEBUG0) & 0xcfffffff)); 272 273 /* calculate inverse scaling factors used by hardware in 20.12 format */ 274 iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.panel1_width); 275 iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.panel1_height); 276 277 /* unblock flatpanel timing programming (or something like that..) */ 278 CRTCW(FP_HTIMING, 0); 279 CRTCW(FP_VTIMING, 0); 280 LOG(2,("CRTC: FP_HTIMING reg readback: $%02x\n", CRTCR(FP_HTIMING))); 281 LOG(2,("CRTC: FP_VTIMING reg readback: $%02x\n", CRTCR(FP_VTIMING))); 282 283 /* enable full width visibility on flatpanel */ 284 DACW(FP_HVALID_S, 0); 285 DACW(FP_HVALID_E, (si->ps.panel1_width - 1)); 286 /* enable full height visibility on flatpanel */ 287 DACW(FP_VVALID_S, 0); 288 DACW(FP_VVALID_E, (si->ps.panel1_height - 1)); 289 290 /* nVidia cards support upscaling except on ??? */ 291 /* NV11 cards can upscale after all! */ 292 if (0)//si->ps.card_type == NV11) 293 { 294 /* disable last fetched line limiting */ 295 DACW(FP_DEBUG2, 0x00000000); 296 /* inform panel to scale if needed */ 297 if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12))) 298 { 299 LOG(2,("CRTC: DFP needs to do scaling\n")); 300 DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) | 0x00000100)); 301 } 302 else 303 { 304 LOG(2,("CRTC: no scaling for DFP needed\n")); 305 DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff)); 306 } 307 } 308 else 309 { 310 float dm_aspect; 311 312 LOG(2,("CRTC: GPU scales for DFP if needed\n")); 313 314 /* calculate display mode aspect */ 315 dm_aspect = (target.timing.h_display / ((float)target.timing.v_display)); 316 317 /* limit last fetched line if vertical scaling is done */ 318 if (iscale_y != (1 << 12)) 319 DACW(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16))); 320 else 321 DACW(FP_DEBUG2, 0x00000000); 322 323 /* inform panel not to scale */ 324 DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff)); 325 326 /* GPU scaling is automatically setup by hardware, so only modify this 327 * scalingfactor for non 4:3 (1.33) aspect panels; 328 * let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */ 329 330 /* correct for widescreen panels relative to mode... 331 * (so if panel is more widescreen than mode being set) */ 332 /* BTW: known widescreen panels: 333 * 1280 x 800 (1.60), 334 * 1440 x 900 (1.60), 335 * 1680 x 1050 (1.60). */ 336 /* known 4:3 aspect non-standard resolution panels: 337 * 1400 x 1050 (1.33). */ 338 /* NOTE: 339 * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ 340 if ((iscale_x != (1 << 12)) && (si->ps.panel1_aspect > (dm_aspect + 0.10))) 341 { 342 uint16 diff; 343 344 LOG(2,("CRTC: (relative) widescreen panel: tuning horizontal scaling\n")); 345 346 /* X-scaling should be the same as Y-scaling */ 347 iscale_x = iscale_y; 348 /* enable testmode (b12) and program modified X-scaling factor */ 349 DACW(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12))); 350 /* center/cut-off left and right side of screen */ 351 diff = ((si->ps.panel1_width - 352 (target.timing.h_display * ((1 << 12) / ((float)iscale_x)))) 353 / 2); 354 DACW(FP_HVALID_S, diff); 355 DACW(FP_HVALID_E, ((si->ps.panel1_width - diff) - 1)); 356 } 357 /* correct for portrait panels... */ 358 /* NOTE: 359 * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ 360 if ((iscale_y != (1 << 12)) && (si->ps.panel1_aspect < (dm_aspect - 0.10))) 361 { 362 LOG(2,("CRTC: (relative) portrait panel: should tune vertical scaling\n")); 363 /* fixme: implement if this kind of portrait panels exist on nVidia... */ 364 } 365 } 366 367 /* do some logging.. */ 368 LOG(2,("CRTC: FP_HVALID_S reg readback: $%08x\n", DACR(FP_HVALID_S))); 369 LOG(2,("CRTC: FP_HVALID_E reg readback: $%08x\n", DACR(FP_HVALID_E))); 370 LOG(2,("CRTC: FP_VVALID_S reg readback: $%08x\n", DACR(FP_VVALID_S))); 371 LOG(2,("CRTC: FP_VVALID_E reg readback: $%08x\n", DACR(FP_VVALID_E))); 372 LOG(2,("CRTC: FP_DEBUG0 reg readback: $%08x\n", DACR(FP_DEBUG0))); 373 LOG(2,("CRTC: FP_DEBUG1 reg readback: $%08x\n", DACR(FP_DEBUG1))); 374 LOG(2,("CRTC: FP_DEBUG2 reg readback: $%08x\n", DACR(FP_DEBUG2))); 375 LOG(2,("CRTC: FP_DEBUG3 reg readback: $%08x\n", DACR(FP_DEBUG3))); 376 LOG(2,("CRTC: FP_TG_CTRL reg readback: $%08x\n", DACR(FP_TG_CTRL))); 377 } 378 379 return B_OK; 380 } 381 382 status_t nv_crtc_depth(int mode) 383 { 384 uint8 viddelay = 0; 385 uint32 genctrl = 0; 386 387 /* set VCLK scaling */ 388 switch(mode) 389 { 390 case BPP8: 391 viddelay = 0x01; 392 /* genctrl b4 & b5 reset: 'direct mode' */ 393 genctrl = 0x00101100; 394 break; 395 case BPP15: 396 viddelay = 0x02; 397 /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 398 genctrl = 0x00100130; 399 break; 400 case BPP16: 401 viddelay = 0x02; 402 /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 403 genctrl = 0x00101130; 404 break; 405 case BPP24: 406 viddelay = 0x03; 407 /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 408 genctrl = 0x00100130; 409 break; 410 case BPP32: 411 viddelay = 0x03; 412 /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 413 genctrl = 0x00101130; 414 break; 415 } 416 /* enable access to CRTC1 on dualhead cards */ 417 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 418 419 CRTCW(PIXEL, ((CRTCR(PIXEL) & 0xfc) | viddelay)); 420 DACW(GENCTRL, genctrl); 421 422 return B_OK; 423 } 424 425 status_t nv_crtc_dpms(bool display, bool h, bool v) 426 { 427 uint8 temp; 428 429 LOG(4,("CRTC: setting DPMS: ")); 430 431 /* enable access to CRTC1 (and SEQUENCER1) on dualhead cards */ 432 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 433 434 /* start synchronous reset: required before turning screen off! */ 435 SEQW(RESET, 0x01); 436 437 /* turn screen off */ 438 temp = SEQR(CLKMODE); 439 if (display) 440 { 441 SEQW(CLKMODE, (temp & ~0x20)); 442 443 /* end synchronous reset if display should be enabled */ 444 SEQW(RESET, 0x03); 445 446 /* powerup both LVDS (laptop panellink) and TMDS (DVI panellink) transmitters */ 447 if (si->ps.tmds1_active) DACW(FP_DEBUG0, (DACR(FP_DEBUG0) & 0xcfffffff)); 448 449 LOG(4,("display on, ")); 450 } 451 else 452 { 453 SEQW(CLKMODE, (temp | 0x20)); 454 455 /* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink) transmitters */ 456 if (si->ps.tmds1_active) DACW(FP_DEBUG0, (DACR(FP_DEBUG0) | 0x30000000)); 457 458 LOG(4,("display off, ")); 459 } 460 461 if (h) 462 { 463 CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0x7f)); 464 LOG(4,("hsync enabled, ")); 465 } 466 else 467 { 468 CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x80)); 469 LOG(4,("hsync disabled, ")); 470 } 471 if (v) 472 { 473 CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xbf)); 474 LOG(4,("vsync enabled\n")); 475 } 476 else 477 { 478 CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x40)); 479 LOG(4,("vsync disabled\n")); 480 } 481 482 return B_OK; 483 } 484 485 status_t nv_crtc_dpms_fetch(bool *display, bool *h, bool *v) 486 { 487 /* enable access to CRTC1 (and SEQUENCER1) on dualhead cards */ 488 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 489 490 *display = !(SEQR(CLKMODE) & 0x20); 491 *h = !(CRTCR(REPAINT1) & 0x80); 492 *v = !(CRTCR(REPAINT1) & 0x40); 493 494 LOG(4,("CTRC: fetched DPMS state:")); 495 if (display) LOG(4,("display on, ")); 496 else LOG(4,("display off, ")); 497 if (h) LOG(4,("hsync enabled, ")); 498 else LOG(4,("hsync disabled, ")); 499 if (v) LOG(4,("vsync enabled\n")); 500 else LOG(4,("vsync disabled\n")); 501 502 return B_OK; 503 } 504 505 status_t nv_crtc_set_display_pitch() 506 { 507 uint32 offset; 508 509 LOG(4,("CRTC: setting card pitch (offset between lines)\n")); 510 511 /* figure out offset value hardware needs */ 512 offset = si->fbc.bytes_per_row / 8; 513 514 LOG(2,("CRTC: offset register set to: $%04x\n", offset)); 515 516 /* enable access to CRTC1 on dualhead cards */ 517 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 518 519 /* program the card */ 520 CRTCW(PITCHL, (offset & 0x00ff)); 521 CRTCW(REPAINT0, ((CRTCR(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3))); 522 523 return B_OK; 524 } 525 526 status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp) 527 { 528 uint8 temp; 529 uint32 timeout = 0; 530 531 LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp)); 532 533 LOG(2,("CRTC: startadd: $%08x\n", startadd)); 534 LOG(2,("CRTC: frameRAM: $%08x\n", si->framebuffer)); 535 LOG(2,("CRTC: framebuffer: $%08x\n", si->fbc.frame_buffer)); 536 537 /* we might have no retraces during setmode! */ 538 /* wait 25mS max. for retrace to occur (refresh > 40Hz) */ 539 while (((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) && 540 (timeout < (25000/10))) 541 { 542 /* don't snooze much longer or retrace might get missed! */ 543 snooze(10); 544 timeout++; 545 } 546 547 /* enable access to CRTC1 on dualhead cards */ 548 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 549 550 if (si->ps.card_arch == NV04A) 551 { 552 /* upto 32Mb RAM adressing: must be used this way on pre-NV10! */ 553 554 /* set standard registers */ 555 /* (NVidia: startadress in 32bit words (b2 - b17) */ 556 CRTCW(FBSTADDL, ((startadd & 0x000003fc) >> 2)); 557 CRTCW(FBSTADDH, ((startadd & 0x0003fc00) >> 10)); 558 559 /* set extended registers */ 560 /* NV4 extended bits: (b18-22) */ 561 temp = (CRTCR(REPAINT0) & 0xe0); 562 CRTCW(REPAINT0, (temp | ((startadd & 0x007c0000) >> 18))); 563 /* NV4 extended bits: (b23-24) */ 564 temp = (CRTCR(HEB) & 0x9f); 565 CRTCW(HEB, (temp | ((startadd & 0x01800000) >> 18))); 566 } 567 else 568 { 569 /* upto 4Gb RAM adressing: must be used on NV10 and later! */ 570 /* NOTE: 571 * While this register also exists on pre-NV10 cards, it will 572 * wrap-around at 16Mb boundaries!! */ 573 574 /* 30bit adress in 32bit words */ 575 NV_REG32(NV32_NV10FBSTADD32) = (startadd & 0xfffffffc); 576 } 577 578 /* set NV4/NV10 byte adress: (b0 - 1) */ 579 ATBW(HORPIXPAN, ((startadd & 0x00000003) << 1)); 580 581 return B_OK; 582 } 583 584 status_t nv_crtc_cursor_init() 585 { 586 int i; 587 uint32 * fb; 588 /* cursor bitmap will be stored at the start of the framebuffer */ 589 const uint32 curadd = 0; 590 591 /* enable access to CRTC1 on dualhead cards */ 592 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 593 594 /* set cursor bitmap adress ... */ 595 if ((si->ps.card_arch == NV04A) || (si->ps.laptop)) 596 { 597 /* must be used this way on pre-NV10 and on all 'Go' cards! */ 598 599 /* cursorbitmap must start on 2Kbyte boundary: */ 600 /* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */ 601 CRTCW(CURCTL0, ((curadd & 0x0001f800) >> 9)); 602 /* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */ 603 CRTCW(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80)); 604 /* set adress bit24-31 */ 605 CRTCW(CURCTL2, ((curadd & 0xff000000) >> 24)); 606 } 607 else 608 { 609 /* upto 4Gb RAM adressing: 610 * can be used on NV10 and later (except for 'Go' cards)! */ 611 /* NOTE: 612 * This register does not exist on pre-NV10 and 'Go' cards. */ 613 614 /* cursorbitmap must still start on 2Kbyte boundary: */ 615 NV_REG32(NV32_NV10CURADD32) = (curadd & 0xfffff800); 616 } 617 618 /* set cursor colour: not needed because of direct nature of cursor bitmap. */ 619 620 /*clear cursor*/ 621 fb = (uint32 *) si->framebuffer + curadd; 622 for (i=0;i<(2048/4);i++) 623 { 624 fb[i]=0; 625 } 626 627 /* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */ 628 NV_REG32(NV32_CURCONF) = 0x02000100; 629 630 /* activate hardware cursor */ 631 nv_crtc_cursor_show(); 632 633 return B_OK; 634 } 635 636 status_t nv_crtc_cursor_show() 637 { 638 LOG(4,("CRTC: enabling cursor\n")); 639 640 /* enable access to CRTC1 on dualhead cards */ 641 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 642 643 /* b0 = 1 enables cursor */ 644 CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01)); 645 646 return B_OK; 647 } 648 649 status_t nv_crtc_cursor_hide() 650 { 651 LOG(4,("CRTC: disabling cursor\n")); 652 653 /* enable access to CRTC1 on dualhead cards */ 654 if (si->ps.secondary_head) CRTCW(OWNER, 0x00); 655 656 /* b0 = 0 disables cursor */ 657 CRTCW(CURCTL0, (CRTCR(CURCTL0) & 0xfe)); 658 659 return B_OK; 660 } 661 662 /*set up cursor shape*/ 663 status_t nv_crtc_cursor_define(uint8* andMask,uint8* xorMask) 664 { 665 int x, y; 666 uint8 b; 667 uint16 *cursor; 668 uint16 pixel; 669 670 /* get a pointer to the cursor */ 671 cursor = (uint16*) si->framebuffer; 672 673 /* draw the cursor */ 674 /* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */ 675 for (y = 0; y < 16; y++) 676 { 677 b = 0x80; 678 for (x = 0; x < 8; x++) 679 { 680 /* preset transparant */ 681 pixel = 0x0000; 682 /* set white if requested */ 683 if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; 684 /* set black if requested */ 685 if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; 686 /* set invert if requested */ 687 if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; 688 /* place the pixel in the bitmap */ 689 cursor[x + (y * 32)] = pixel; 690 b >>= 1; 691 } 692 xorMask++; 693 andMask++; 694 b = 0x80; 695 for (; x < 16; x++) 696 { 697 /* preset transparant */ 698 pixel = 0x0000; 699 /* set white if requested */ 700 if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; 701 /* set black if requested */ 702 if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; 703 /* set invert if requested */ 704 if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; 705 /* place the pixel in the bitmap */ 706 cursor[x + (y * 32)] = pixel; 707 b >>= 1; 708 } 709 xorMask++; 710 andMask++; 711 } 712 713 return B_OK; 714 } 715 716 /* position the cursor */ 717 status_t nv_crtc_cursor_position(uint16 x, uint16 y) 718 { 719 uint16 yhigh; 720 721 /* make sure we are beyond the first line of the cursorbitmap being drawn during 722 * updating the position to prevent distortions: no double buffering feature */ 723 /* Note: 724 * we need to return as quick as possible or some apps will exhibit lagging.. */ 725 726 /* read the old cursor Y position */ 727 yhigh = ((DACR(CURPOS) & 0x0fff0000) >> 16); 728 /* make sure we will wait until we are below both the old and new Y position: 729 * visible cursorbitmap drawing needs to be done at least... */ 730 if (y > yhigh) yhigh = y; 731 732 if (yhigh < (si->dm.timing.v_display - 16)) 733 { 734 /* we have vertical lines below old and new cursorposition to spare. So we 735 * update the cursor postion 'mid-screen', but below that area. */ 736 while (((uint16)(NV_REG32(NV32_RASTER) & 0x000007ff)) < (yhigh + 16)) 737 { 738 snooze(10); 739 } 740 } 741 else 742 { 743 /* no room to spare, just wait for retrace (is relatively slow) */ 744 while ((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) 745 { 746 /* don't snooze much longer or retrace might get missed! */ 747 snooze(10); 748 } 749 } 750 751 /* update cursorposition */ 752 DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16))); 753 754 return B_OK; 755 } 756