143809Sjkh 243809Sjkh/* 343809Sjkh Copyright 1999, Be Incorporated. All Rights Reserved. 487047Sru This file may be used under the terms of the Be Sample Code License. 543809Sjkh 643809Sjkh Other authors: 743809Sjkh Mark Watson, 843809Sjkh Apsed, 943809Sjkh Rudolf Cornelissen 11/2002-12/2015 1059674Ssheldonh*/ 1159674Ssheldonh 1259674Ssheldonh#define MODULE_BIT 0x00200000 1354949Ssheldonh 1443809Sjkh#include "acc_std.h" 1543809Sjkh 1650472Speter/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ 1743809Sjkhstatus_t SET_DISPLAY_MODE(display_mode *mode_to_set) 1843809Sjkh{ 1948290Sjseger /* BOUNDS WARNING: 2043809Sjkh * It's impossible to deviate whatever small amount in a display_mode if the lower 2143809Sjkh * and upper limits are the same! 2243809Sjkh * Besides: 2348785Siwasaki * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE 2448785Siwasaki * returns B_BAD_VALUE! 2548785Siwasaki * Which means PROPOSEMODE should not return that on anything except on 2643809Sjkh * deviations for: 2743809Sjkh * display_mode.virtual_width; 2867793Ssanpei * display_mode.virtual_height; 2943809Sjkh * display_mode.timing.h_display; 3048554Shosokawa * display_mode.timing.v_display; 3158979Siwasaki * So: 3284537Ssheldonh * We don't use bounds here by making sure bounds and target are the same struct! 3375181Sbmah * (See the call to PROPOSE_DISPLAY_MODE below) */ 3443809Sjkh display_mode /*bounds,*/ target; 3579825Sroam 3643809Sjkh uint8 colour_depth1 = 32; 3787047Sru uint32 startadd,startadd_right; 3876946Sdd// bool crt1, crt2, cross; 3988676Ssheldonh 4088676Ssheldonh /* Adjust mode to valid one and fail if invalid */ 4143809Sjkh target /*= bounds*/ = *mode_to_set; 4243809Sjkh /* show the mode bits */ 4343809Sjkh LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); 4443809Sjkh LOG(1, ("SETMODE: requested target pixelclock %ukHz\n", target.timing.pixel_clock)); 4543809Sjkh LOG(1, ("SETMODE: requested virtual_width %u, virtual_height %u\n", 4664749Sjhb target.virtual_width, target.virtual_height)); 4748880Sjkh 4843809Sjkh /* See BOUNDS WARNING above... */ 4948842Sjkh if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; 5048842Sjkh 5143809Sjkh /* make sure a possible 3D add-on will block rendering and re-initialize itself. 5245542Sdes * note: update in _this_ order only */ 5343809Sjkh /* SET_DISPLAY_MODE will reset this flag when it's done. */ 5443809Sjkh si->engine.threeD.mode_changing = true; 5587047Sru /* every 3D add-on will reset this bit-flag when it's done. */ 5657014Spaul si->engine.threeD.newmode = 0xffffffff; 5761961Sdillon /* every 3D clone needs to reclaim a slot. 5861961Sdillon * note: this also cleans up reserved channels for killed 3D clones.. */ 5961961Sdillon si->engine.threeD.clones = 0x00000000; 6061961Sdillon 6144990Sbrian /* disable interrupts using the kernel driver */ 6287047Sru head1_interrupt_enable(false); 6390957Scjc if (si->ps.secondary_head) head2_interrupt_enable(false); 6487047Sru 6566745Sdarrenr /* disable TVout if supported */ 6686856Sdarrenr if (si->ps.tvout) BT_stop_tvout(); 6766745Sdarrenr 6866745Sdarrenr /* turn off screen(s) _after_ TVout is disabled (if applicable) */ 6986856Sdarrenr head1_dpms(false, false, false, true); 7086856Sdarrenr if (si->ps.secondary_head) head2_dpms(false, false, false, true); 7186856Sdarrenr if (si->ps.tvout) BT_dpms(false); 7266745Sdarrenr 7366745Sdarrenr /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ 7486856Sdarrenr startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 7586856Sdarrenr 7686856Sdarrenr /* calculate and set new mode bytes_per_row */ 7787047Sru nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode); 7885219Sdarrenr 7986856Sdarrenr /*Perform the very long mode switch!*/ 8085219Sdarrenr if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ 8177154Sobrien { 8289808Scjc uint8 colour_depth2 = colour_depth1; 8349704Sobrien 8460977Swilko /* init display mode for secondary head */ 8560977Swilko display_mode target2 = target; 8651209Sdes 8760685Swollman LOG(1,("SETMODE: setting DUALHEAD mode\n")); 8849603Sdes 8949603Sdes /* validate flags for secondary TVout */ 9048687Speter //fixme: remove or block on autodetect fail. (is now shutoff) 9183677Sbrooks if ((0) && (target2.flags & TV_BITS)) 9283677Sbrooks { 9343809Sjkh target.flags &= ~TV_BITS;//still needed for some routines... 9443809Sjkh target2.flags &= ~TV_BITS; 9564677Ssheldonh LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); 9643809Sjkh } 9743809Sjkh 9843809Sjkh /* detect which connectors have a CRT connected */ 9943809Sjkh //fixme: 'hot-plugging' for analog monitors removed: remove code as well; 10043809Sjkh //or make it work with digital panels connected as well. 10143809Sjkh// crt1 = nv_dac_crt_connected(); 10277651Sbrian// crt2 = nv_dac2_crt_connected(); 10377651Sbrian /* connect outputs 'straight-through' */ 10477651Sbrian// if (crt1) 10577651Sbrian// { 10677651Sbrian /* connector1 is used as primary output */ 10743809Sjkh// cross = false; 10853665Salfred// } 10949110Sbrian// else 11049110Sbrian// { 11149110Sbrian// if (crt2) 11250193Sbrian /* connector2 is used as primary output */ 11349110Sbrian// cross = true; 11464471Sbrian// else 11549110Sbrian /* no CRT detected: assume connector1 is used as primary output */ 11674462Salfred// cross = false; 11743809Sjkh// } 11878905Sdd /* set output connectors assignment if possible */ 11958400Sbillf if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH) 12082831Srwatson /* invert output assignment in switch mode */ 12163980Seivind nv_general_head_select(true); 12278905Sdd else 12348697Ssheldonh nv_general_head_select(false); 12443809Sjkh 12543809Sjkh /* set the pixel clock PLL(s) */ 12643809Sjkh LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); 12743809Sjkh if (head1_set_pix_pll(target) == B_ERROR) 12843809Sjkh LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); 12943809Sjkh 13082191Skuriyama LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); 13143809Sjkh if (head2_set_pix_pll(target2) == B_ERROR) 13280515Smarkm LOG(8,("SETMODE: error setting pixel clock (DAC2)\n")); 13380515Smarkm 13480515Smarkm /*set the colour depth for CRTC1 and the DAC */ 13580515Smarkm switch(target.space) 13680515Smarkm { 13780515Smarkm case B_CMAP8: 13880515Smarkm colour_depth1 = 8; 13980515Smarkm head1_mode(BPP8, 1.0); 14080515Smarkm head1_depth(BPP8); 14180515Smarkm break; 14280515Smarkm case B_RGB15_LITTLE: 14343809Sjkh colour_depth1 = 16; 14480515Smarkm head1_mode(BPP15, 1.0); 14543809Sjkh head1_depth(BPP15); 14643809Sjkh break; 14774462Salfred case B_RGB16_LITTLE: 14874462Salfred colour_depth1 = 16; 14974462Salfred head1_mode(BPP16, 1.0); 15074462Salfred head1_depth(BPP16); 15174462Salfred break; 15274462Salfred case B_RGB32_LITTLE: 15374462Salfred colour_depth1 = 32; 15474462Salfred head1_mode(BPP32, 1.0); 15587047Sru head1_depth(BPP32); 15674462Salfred break; 15787047Sru } 15874462Salfred /*set the colour depth for CRTC2 and DAC2 */ 15974462Salfred switch(target2.space) 16043809Sjkh { 16165306Sobrien case B_CMAP8: 16243809Sjkh colour_depth2 = 8; 16343809Sjkh head2_mode(BPP8, 1.0); 16443809Sjkh head2_depth(BPP8); 16543809Sjkh break; 16643809Sjkh case B_RGB15_LITTLE: 16787047Sru colour_depth2 = 16; 16843809Sjkh head2_mode(BPP15, 1.0); 16963773Sasmodai head2_depth(BPP15); 17043809Sjkh break; 17158710Sdillon case B_RGB16_LITTLE: 17285114Salfred colour_depth2 = 16; 17385114Salfred head2_mode(BPP16, 1.0); 17463980Seivind head2_depth(BPP16); 17574462Salfred break; 17643809Sjkh case B_RGB32_LITTLE: 17743809Sjkh colour_depth2 = 32; 17843809Sjkh head2_mode(BPP32, 1.0); 17943809Sjkh head2_depth(BPP32); 18043809Sjkh break; 18143809Sjkh } 18243809Sjkh 18343809Sjkh /* check if we are doing interlaced TVout mode */ 18449393Seivind //fixme: we don't support interlaced mode? 18543809Sjkh si->interlaced_tv_mode = false; 18674949Sphk 18754683Sroberto /*set the display(s) pitches*/ 18854683Sroberto head1_set_display_pitch (); 18954683Sroberto //fixme: seperate for real dualhead modes: 19043809Sjkh //we need a secondary si->fbc! 19174462Salfred head2_set_display_pitch (); 19243809Sjkh 19343809Sjkh /*work out where the "right" screen starts*/ 19443809Sjkh startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3)); 19543809Sjkh 19643809Sjkh /* Tell card what memory to display */ 19743809Sjkh switch (target.flags & DUALHEAD_BITS) 19843809Sjkh { 19943809Sjkh case DUALHEAD_ON: 20043809Sjkh case DUALHEAD_SWITCH: 20143809Sjkh head1_set_display_start(startadd,colour_depth1); 20243809Sjkh head2_set_display_start(startadd_right,colour_depth2); 20343809Sjkh break; 20443809Sjkh case DUALHEAD_CLONE: 20543809Sjkh head1_set_display_start(startadd,colour_depth1); 20643809Sjkh head2_set_display_start(startadd,colour_depth2); 20743809Sjkh break; 20843809Sjkh } 20943809Sjkh 21043809Sjkh /* set the timing */ 21143809Sjkh head1_set_timing(target); 21243809Sjkh head2_set_timing(target2); 21343809Sjkh 21443809Sjkh /* TVout support: program TVout encoder and modify CRTC timing */ 21587047Sru if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2); 21643809Sjkh } 21743809Sjkh else /* single head mode */ 21843809Sjkh { 21943809Sjkh int colour_mode = BPP32; 22043809Sjkh 22143809Sjkh /* connect output */ 22243809Sjkh if (si->ps.secondary_head) 22343809Sjkh { 22443809Sjkh /* detect which connectors have a CRT connected */ 22543809Sjkh //fixme: 'hot-plugging' for analog monitors removed: remove code as well; 22643809Sjkh //or make it work with digital panels connected as well. 22743809Sjkh// crt1 = nv_dac_crt_connected(); 22843809Sjkh// crt2 = nv_dac2_crt_connected(); 22943809Sjkh /* connect outputs 'straight-through' */ 23080209Shm// if (crt1) 23143809Sjkh// { 23280209Shm /* connector1 is used as primary output */ 23343809Sjkh// cross = false; 23475920Sschweikh// } 23576592Sschweikh// else 23643809Sjkh// { 23743809Sjkh// if (crt2) 23843809Sjkh /* connector2 is used as primary output */ 23943809Sjkh// cross = true; 24043809Sjkh// else 24143809Sjkh /* no CRT detected: assume connector1 is used as primary output */ 24257398Sshin// cross = false; 24357398Sshin// } 24457398Sshin /* set output connectors assignment if possible */ 24567906Sume nv_general_head_select(false); 24687464Snsayer } 24757944Sshin 24857944Sshin switch(target.space) 24957944Sshin { 25057944Sshin case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; 25157398Sshin case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; 25257398Sshin case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; 25357398Sshin case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; 25457398Sshin default: 25557398Sshin LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); 25657398Sshin return B_ERROR; 25767906Sume } 25867906Sume 25957398Sshin /* set the pixel clock PLL */ 26057398Sshin if (head1_set_pix_pll(target) == B_ERROR) 26157398Sshin LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); 26274418Sume 26374418Sume /* set the colour depth for CRTC1 and the DAC */ 26478935Sume /* first set the colordepth */ 26557398Sshin head1_depth(colour_mode); 26657398Sshin /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */ 26778493Sume head1_mode(colour_mode,1.0); 26857944Sshin 26957944Sshin /* set the display pitch */ 27057944Sshin head1_set_display_pitch(); 27171632Sume 27257398Sshin /* tell the card what memory to display */ 27384421Sume head1_set_display_start(startadd,colour_depth1); 27484421Sume 27584421Sume /* set the timing */ 27684421Sume head1_set_timing(target); 27757398Sshin 27857944Sshin /* TVout support: program TVout encoder and modify CRTC timing */ 27957944Sshin if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target); 28057944Sshin 28157944Sshin //fixme: shut-off the videoPLL if it exists... 28257944Sshin } 28357944Sshin 28457944Sshin /* update driver's mode store */ 28557944Sshin si->dm = target; 28657944Sshin 28778475Sume /* update FIFO data fetching according to mode */ 28878475Sume nv_crtc_update_fifo(); 28978475Sume if (si->ps.secondary_head) nv_crtc2_update_fifo(); 29067906Sume 29158752Sshin /* set up acceleration for this mode */ 29267906Sume /* note: 29367906Sume * Maybe later we can forget about non-DMA mode (depends on 3D acceleration 29467906Sume * attempts). */ 29567906Sume if (!si->settings.block_acc) { 29667906Sume if (!si->settings.dma_acc) 29767906Sume nv_acc_init(); 29867906Sume else 29943809Sjkh nv_acc_init_dma(); 30043809Sjkh } 30143809Sjkh 30243809Sjkh /* set up overlay unit for this mode */ 30343809Sjkh nv_bes_init(); 30443809Sjkh 30543809Sjkh /* note freemem range */ 30643809Sjkh /* first free adress follows hardcursor and workspace */ 30743809Sjkh si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height; 30843809Sjkh if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048; 30943809Sjkh /* last free adress is end-of-ram minus max space needed for overlay bitmaps */ 31043809Sjkh //fixme possible: 31143809Sjkh //if overlay buffers are allocated subtract buffersize from mem_high; 31243809Sjkh //only allocate overlay buffers if 3D is not in use. (block overlay during 3D) 31343809Sjkh si->engine.threeD.mem_high = si->ps.memory_size - 1; 31443809Sjkh /* Keep some extra distance as a workaround for certain bugs (see 31543809Sjkh * DriverInterface.h for an explanation). */ 31643809Sjkh if (si->ps.card_arch < NV40A) 31787047Sru si->engine.threeD.mem_high -= PRE_NV40_OFFSET; 31843809Sjkh else 31987047Sru si->engine.threeD.mem_high -= NV40_PLUS_OFFSET; 32075708Sache 32175708Sache si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */ 32243809Sjkh 32376110Sdd /* restore screen(s) output state(s) */ 32443809Sjkh SET_DPMS_MODE(si->dpms_flags); 32543809Sjkh 32643809Sjkh /* enable interrupts using the kernel driver */ 32793853Sgshapiro //fixme: 32843809Sjkh //add head2 once we use one driver instance 'per head' (instead of 'per card') 32943809Sjkh head1_interrupt_enable(true); 33093853Sgshapiro 33193853Sgshapiro /* make sure a possible 3D add-on will re-initialize itself by signalling ready */ 33293853Sgshapiro si->engine.threeD.mode_changing = false; 33393314Sgshapiro 33493314Sgshapiro /* optimize memory-access if needed */ 33590808Sgshapiro// head1_mem_priority(colour_depth1); 33693314Sgshapiro 33793314Sgshapiro /* Tune RAM CAS-latency if needed. Must be done *here*! */ 33893314Sgshapiro nv_set_cas_latency(); 33974198Speter 34090808Sgshapiro LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0)); 34190808Sgshapiro 34290808Sgshapiro return B_OK; 34393314Sgshapiro} 34493853Sgshapiro 34593853Sgshapiro/* 34693853Sgshapiro Set which pixel of the virtual frame buffer will show up in the 34793853Sgshapiro top left corner of the display device. Used for page-flipping 34893853Sgshapiro games and virtual desktops. 34993853Sgshapiro*/ 35093853Sgshapirostatus_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { 35193853Sgshapiro uint8 colour_depth; 35293853Sgshapiro uint32 startadd,startadd_right; 35393853Sgshapiro 35493853Sgshapiro LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); 35593853Sgshapiro 35693853Sgshapiro /* nVidia cards support pixelprecise panning on both heads in all modes: 35793853Sgshapiro * No stepping granularity needed! */ 35851827Sbillf 35984730Sdes /* determine bits used for the colordepth */ 36087047Sru switch(si->dm.space) 36187047Sru { 36251038Scpiazza case B_CMAP8: 36343809Sjkh colour_depth=8; 36443809Sjkh break; 36573242Sjkh case B_RGB15_LITTLE: 36671121Sdes case B_RGB16_LITTLE: 36751290Sobrien colour_depth=16; 36843809Sjkh break; 36954642Sgallatin case B_RGB24_LITTLE: 37043809Sjkh colour_depth=24; 37164520Sjdp break; 37243809Sjkh case B_RGB32_LITTLE: 37343809Sjkh colour_depth=32; 37443809Sjkh break; 37543809Sjkh default: 37687047Sru return B_ERROR; 37743809Sjkh } 37892192Srwatson 37943809Sjkh /* do not run past end of display */ 38087047Sru switch (si->dm.flags & DUALHEAD_BITS) 38166634Sbrian { 38287047Sru case DUALHEAD_ON: 38367180Sjwd case DUALHEAD_SWITCH: 38471014Sdougb if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) 38587047Sru return B_ERROR; 38687047Sru break; 38787047Sru default: 38887047Sru if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) 38987047Sru return B_ERROR; 39043809Sjkh break; 39143809Sjkh } 39259674Ssheldonh if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) 39359674Ssheldonh return B_ERROR; 39443809Sjkh 39543809Sjkh /* everybody remember where we parked... */ 39659674Ssheldonh si->dm.h_display_start = h_display_start; 39787047Sru si->dm.v_display_start = v_display_start; 39887047Sru 39987047Sru /* actually set the registers */ 40087047Sru //fixme: seperate both heads: we need a secondary si->fbc! 40187047Sru startadd = v_display_start * si->fbc.bytes_per_row; 40287047Sru startadd += h_display_start * (colour_depth >> 3); 40387047Sru startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 40487047Sru startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); 40587047Sru 40687047Sru /* disable interrupts using the kernel driver */ 40787047Sru head1_interrupt_enable(false); 40887047Sru if (si->ps.secondary_head) head2_interrupt_enable(false); 40987047Sru 41087047Sru switch (si->dm.flags & DUALHEAD_BITS) 41187047Sru { 41287047Sru case DUALHEAD_ON: 41359674Ssheldonh case DUALHEAD_SWITCH: 414 head1_set_display_start(startadd,colour_depth); 415 head2_set_display_start(startadd_right,colour_depth); 416 break; 417 case DUALHEAD_OFF: 418 head1_set_display_start(startadd,colour_depth); 419 break; 420 case DUALHEAD_CLONE: 421 head1_set_display_start(startadd,colour_depth); 422 head2_set_display_start(startadd,colour_depth); 423 break; 424 } 425 426 //fixme: 427 //add head2 once we use one driver instance 'per head' (instead of 'per card') 428 head1_interrupt_enable(true); 429 430 return B_OK; 431} 432 433/* Set the indexed color palette */ 434void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { 435 int i; 436 uint8 *r,*g,*b; 437 438 /* Protect gamma correction when not in CMAP8 */ 439 if (si->dm.space != B_CMAP8) return; 440 441 r=si->color_data; 442 g=r+256; 443 b=g+256; 444 445 i=first; 446 while (count--) 447 { 448 r[i]=*color_data++; 449 g[i]=*color_data++; 450 b[i]=*color_data++; 451 i++; 452 } 453 head1_palette(r,g,b); 454 if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b); 455} 456 457/* Put the display into one of the Display Power Management modes. */ 458status_t SET_DPMS_MODE(uint32 dpms_flags) 459{ 460 bool display, h1h, h1v, h2h, h2v, do_p1, do_p2; 461 462 /* disable interrupts using the kernel driver */ 463 head1_interrupt_enable(false); 464 if (si->ps.secondary_head) head2_interrupt_enable(false); 465 466 LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags)); 467 468 /* note current DPMS state for our reference */ 469 si->dpms_flags = dpms_flags; 470 471 /* preset: DPMS for panels should be executed */ 472 do_p1 = do_p2 = true; 473 474 /* determine signals to send to head(s) */ 475 display = h1h = h1v = h2h = h2v = true; 476 switch(dpms_flags) 477 { 478 case B_DPMS_ON: /* H: on, V: on, display on */ 479 break; 480 case B_DPMS_STAND_BY: 481 display = h1h = h2h = false; 482 break; 483 case B_DPMS_SUSPEND: 484 display = h1v = h2v = false; 485 break; 486 case B_DPMS_OFF: /* H: off, V: off, display off */ 487 display = h1h = h1v = h2h = h2v = false; 488 break; 489 default: 490 LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags)); 491 //fixme: 492 //add head2 once we use one driver instance 'per head' (instead of 'per card') 493 head1_interrupt_enable(true); 494 495 return B_ERROR; 496 } 497 498 /* CRTC used for TVout needs specific DPMS programming */ 499 if (si->dm.flags & TV_BITS) 500 { 501 /* TV_PRIMARY tells us that the head to be used with TVout is the head that's 502 * actually assigned as being the primary head at powerup: 503 * so non dualhead-mode-dependant, and not 'fixed' CRTC1! */ 504 if (si->dm.flags & TV_PRIMARY) 505 { 506 LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n")); 507 508 if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH) 509 { 510 if (!(si->settings.vga_on_tv)) 511 { 512 /* block VGA output on head displaying on TV */ 513 /* Note: 514 * this specific sync setting is required: Vsync is used to keep TVout 515 * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs). 516 * This leaves Hsync only for shutting off the VGA screen. */ 517 h1h = false; 518 h1v = true; 519 /* block panel DPMS updates */ 520 do_p1 = false; 521 } 522 else 523 { 524 /* when concurrent VGA is used alongside TVout on a head, DPMS is safest 525 * applied this way: Vsync is needed for stopping TVout successfully when 526 * a (new) modeswitch occurs. 527 * (see routine BT_stop_tvout() in nv_brooktreetv.c) */ 528 /* Note: 529 * applying 'normal' DPMS here and forcing Vsync on in the above mentioned 530 * routine seems to not always be enough: sometimes image generation will 531 * not resume in that case. */ 532 h1h = display; 533 h1v = true; 534 } 535 } 536 else 537 { 538 if (!(si->settings.vga_on_tv)) 539 { 540 h2h = false; 541 h2v = true; 542 do_p2 = false; 543 } 544 else 545 { 546 h2h = display; 547 h2v = true; 548 } 549 } 550 } 551 else 552 { 553 LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n")); 554 555 if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH) 556 { 557 if (!(si->settings.vga_on_tv)) 558 { 559 h2h = false; 560 h2v = true; 561 do_p2 = false; 562 } 563 else 564 { 565 h2h = display; 566 h2v = true; 567 } 568 } 569 else 570 { 571 if (!(si->settings.vga_on_tv)) 572 { 573 h1h = false; 574 h1v = true; 575 do_p1 = false; 576 } 577 else 578 { 579 h1h = display; 580 h1v = true; 581 } 582 } 583 } 584 } 585 586 /* issue actual DPMS commands as far as applicable */ 587 head1_dpms(display, h1h, h1v, do_p1); 588 if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS)) 589 head2_dpms(display, h2h, h2v, do_p2); 590 if (si->dm.flags & TV_BITS) 591 BT_dpms(display); 592 593 //fixme: 594 //add head2 once we use one driver instance 'per head' (instead of 'per card') 595 head1_interrupt_enable(true); 596 597 return B_OK; 598} 599 600/* Report device DPMS capabilities */ 601uint32 DPMS_CAPABILITIES(void) 602{ 603 return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF); 604} 605 606/* Return the current DPMS mode */ 607uint32 DPMS_MODE(void) 608{ 609 return si->dpms_flags; 610} 611