108705d96Sshatty 208705d96Sshatty /* 308705d96Sshatty Copyright 1999, Be Incorporated. All Rights Reserved. 408705d96Sshatty This file may be used under the terms of the Be Sample Code License. 508705d96Sshatty 608705d96Sshatty Other authors: 708705d96Sshatty Mark Watson, 808705d96Sshatty Apsed, 9*69ca2102SRudolf Cornelissen Rudolf Cornelissen 11/2002-6/2008 1008705d96Sshatty */ 1108705d96Sshatty 1208705d96Sshatty #define MODULE_BIT 0x00200000 1308705d96Sshatty 1408705d96Sshatty #include "acc_std.h" 1508705d96Sshatty 1608705d96Sshatty /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ 1708705d96Sshatty status_t SET_DISPLAY_MODE(display_mode *mode_to_set) 1808705d96Sshatty { 1908705d96Sshatty /* BOUNDS WARNING: 2008705d96Sshatty * It's impossible to deviate whatever small amount in a display_mode if the lower 2108705d96Sshatty * and upper limits are the same! 2208705d96Sshatty * Besides: 2308705d96Sshatty * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE 2408705d96Sshatty * returns B_BAD_VALUE! 2508705d96Sshatty * Which means PROPOSEMODE should not return that on anything except on 2608705d96Sshatty * deviations for: 2708705d96Sshatty * display_mode.virtual_width; 2808705d96Sshatty * display_mode.virtual_height; 2908705d96Sshatty * display_mode.timing.h_display; 3008705d96Sshatty * display_mode.timing.v_display; 3108705d96Sshatty * So: 3208705d96Sshatty * We don't use bounds here by making sure bounds and target are the same struct! 3308705d96Sshatty * (See the call to PROPOSE_DISPLAY_MODE below) */ 3408705d96Sshatty display_mode /*bounds,*/ target; 3508705d96Sshatty 3608705d96Sshatty uint8 colour_depth1 = 32; 3708705d96Sshatty uint32 startadd,startadd_right; 3830f76422SRudolf Cornelissen // bool crt1, crt2, cross; 3908705d96Sshatty 4008705d96Sshatty /* Adjust mode to valid one and fail if invalid */ 4108705d96Sshatty target /*= bounds*/ = *mode_to_set; 4208705d96Sshatty /* show the mode bits */ 4308705d96Sshatty LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); 4408705d96Sshatty LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock)); 4508705d96Sshatty LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n", 4608705d96Sshatty target.virtual_width, target.virtual_height)); 4708705d96Sshatty 4808705d96Sshatty /* See BOUNDS WARNING above... */ 4908705d96Sshatty if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; 5008705d96Sshatty 51c9c0c72bSRudolf Cornelissen /* make sure a possible 3D add-on will block rendering and re-initialize itself. 52c9c0c72bSRudolf Cornelissen * note: update in _this_ order only */ 53c9c0c72bSRudolf Cornelissen /* SET_DISPLAY_MODE will reset this flag when it's done. */ 5421545d00SRudolf Cornelissen si->engine.threeD.mode_changing = true; 5521545d00SRudolf Cornelissen /* every 3D add-on will reset this bit-flag when it's done. */ 5621545d00SRudolf Cornelissen si->engine.threeD.newmode = 0xffffffff; 5721545d00SRudolf Cornelissen /* every 3D clone needs to reclaim a slot. 5821545d00SRudolf Cornelissen * note: this also cleans up reserved channels for killed 3D clones.. */ 5921545d00SRudolf Cornelissen si->engine.threeD.clones = 0x00000000; 60afb207acSRudolf Cornelissen 6108705d96Sshatty /* disable interrupts using the kernel driver */ 62155a2ad0SRudolf Cornelissen head1_interrupt_enable(false); 63155a2ad0SRudolf Cornelissen if (si->ps.secondary_head) head2_interrupt_enable(false); 6408705d96Sshatty 650703480cSRudolf Cornelissen /* disable TVout if supported */ 660703480cSRudolf Cornelissen if (si->ps.tvout) BT_stop_tvout(); 670b36eea4SRudolf Cornelissen 6820603b95SRudolf Cornelissen /* turn off screen(s) _after_ TVout is disabled (if applicable) */ 694022652cSRudolf Cornelissen head1_dpms(false, false, false, true); 704022652cSRudolf Cornelissen if (si->ps.secondary_head) head2_dpms(false, false, false, true); 713aa21459SRudolf Cornelissen if (si->ps.tvout) BT_dpms(false); 7208705d96Sshatty 7308705d96Sshatty /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ 74f2777ca1SRudolf Cornelissen startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 7508705d96Sshatty 7608705d96Sshatty /* calculate and set new mode bytes_per_row */ 7705ed3229SRudolf Cornelissen nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode); 7808705d96Sshatty 7908705d96Sshatty /*Perform the very long mode switch!*/ 8008705d96Sshatty if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ 8108705d96Sshatty { 8208705d96Sshatty uint8 colour_depth2 = colour_depth1; 8308705d96Sshatty 8408705d96Sshatty /* init display mode for secondary head */ 8508705d96Sshatty display_mode target2 = target; 8608705d96Sshatty 8708705d96Sshatty LOG(1,("SETMODE: setting DUALHEAD mode\n")); 8808705d96Sshatty 8908705d96Sshatty /* validate flags for secondary TVout */ 90b2459715SRudolf Cornelissen //fixme: remove or block on autodetect fail. (is now shutoff) 91b2459715SRudolf Cornelissen if ((0) && (target2.flags & TV_BITS)) 9208705d96Sshatty { 9308705d96Sshatty target.flags &= ~TV_BITS;//still needed for some routines... 9408705d96Sshatty target2.flags &= ~TV_BITS; 9508705d96Sshatty LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); 9608705d96Sshatty } 9708705d96Sshatty 9830f76422SRudolf Cornelissen /* detect which connectors have a CRT connected */ 9930f76422SRudolf Cornelissen //fixme: 'hot-plugging' for analog monitors removed: remove code as well; 10030f76422SRudolf Cornelissen //or make it work with digital panels connected as well. 10130f76422SRudolf Cornelissen // crt1 = nv_dac_crt_connected(); 10230f76422SRudolf Cornelissen // crt2 = nv_dac2_crt_connected(); 10330f76422SRudolf Cornelissen /* connect outputs 'straight-through' */ 10430f76422SRudolf Cornelissen // if (crt1) 10530f76422SRudolf Cornelissen // { 10630f76422SRudolf Cornelissen /* connector1 is used as primary output */ 10730f76422SRudolf Cornelissen // cross = false; 10830f76422SRudolf Cornelissen // } 10930f76422SRudolf Cornelissen // else 11030f76422SRudolf Cornelissen // { 11130f76422SRudolf Cornelissen // if (crt2) 11230f76422SRudolf Cornelissen /* connector2 is used as primary output */ 11330f76422SRudolf Cornelissen // cross = true; 11430f76422SRudolf Cornelissen // else 11530f76422SRudolf Cornelissen /* no CRT detected: assume connector1 is used as primary output */ 11630f76422SRudolf Cornelissen // cross = false; 11730f76422SRudolf Cornelissen // } 11830f76422SRudolf Cornelissen /* set output connectors assignment if possible */ 11930f76422SRudolf Cornelissen if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH) 12030f76422SRudolf Cornelissen /* invert output assignment in switch mode */ 12106f4c439SRudolf Cornelissen nv_general_head_select(true); 12230f76422SRudolf Cornelissen else 12306f4c439SRudolf Cornelissen nv_general_head_select(false); 12430f76422SRudolf Cornelissen 12508705d96Sshatty /* set the pixel clock PLL(s) */ 12608705d96Sshatty LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); 12730f76422SRudolf Cornelissen if (head1_set_pix_pll(target) == B_ERROR) 12808705d96Sshatty LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); 12908705d96Sshatty 13008705d96Sshatty LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); 13130f76422SRudolf Cornelissen if (head2_set_pix_pll(target2) == B_ERROR) 132a3b9d212SRudolf Cornelissen LOG(8,("SETMODE: error setting pixel clock (DAC2)\n")); 13308705d96Sshatty 13408705d96Sshatty /*set the colour depth for CRTC1 and the DAC */ 13508705d96Sshatty switch(target.space) 13608705d96Sshatty { 137bc5690abSRudolf Cornelissen case B_CMAP8: 138bc5690abSRudolf Cornelissen colour_depth1 = 8; 13930f76422SRudolf Cornelissen head1_mode(BPP8, 1.0); 1400669fe20SRudolf Cornelissen head1_depth(BPP8); 141bc5690abSRudolf Cornelissen break; 142bc5690abSRudolf Cornelissen case B_RGB15_LITTLE: 143bc5690abSRudolf Cornelissen colour_depth1 = 16; 14430f76422SRudolf Cornelissen head1_mode(BPP15, 1.0); 1450669fe20SRudolf Cornelissen head1_depth(BPP15); 146bc5690abSRudolf Cornelissen break; 14708705d96Sshatty case B_RGB16_LITTLE: 14808705d96Sshatty colour_depth1 = 16; 14930f76422SRudolf Cornelissen head1_mode(BPP16, 1.0); 1500669fe20SRudolf Cornelissen head1_depth(BPP16); 15108705d96Sshatty break; 15208705d96Sshatty case B_RGB32_LITTLE: 15308705d96Sshatty colour_depth1 = 32; 15430f76422SRudolf Cornelissen head1_mode(BPP32, 1.0); 1550669fe20SRudolf Cornelissen head1_depth(BPP32); 15608705d96Sshatty break; 15708705d96Sshatty } 158a3b9d212SRudolf Cornelissen /*set the colour depth for CRTC2 and DAC2 */ 15908705d96Sshatty switch(target2.space) 16008705d96Sshatty { 161bc5690abSRudolf Cornelissen case B_CMAP8: 162bc5690abSRudolf Cornelissen colour_depth2 = 8; 16330f76422SRudolf Cornelissen head2_mode(BPP8, 1.0); 1640669fe20SRudolf Cornelissen head2_depth(BPP8); 165bc5690abSRudolf Cornelissen break; 166bc5690abSRudolf Cornelissen case B_RGB15_LITTLE: 167bc5690abSRudolf Cornelissen colour_depth2 = 16; 16830f76422SRudolf Cornelissen head2_mode(BPP15, 1.0); 1690669fe20SRudolf Cornelissen head2_depth(BPP15); 170bc5690abSRudolf Cornelissen break; 17108705d96Sshatty case B_RGB16_LITTLE: 17208705d96Sshatty colour_depth2 = 16; 17330f76422SRudolf Cornelissen head2_mode(BPP16, 1.0); 1740669fe20SRudolf Cornelissen head2_depth(BPP16); 17508705d96Sshatty break; 17608705d96Sshatty case B_RGB32_LITTLE: 17708705d96Sshatty colour_depth2 = 32; 17830f76422SRudolf Cornelissen head2_mode(BPP32, 1.0); 1790669fe20SRudolf Cornelissen head2_depth(BPP32); 18008705d96Sshatty break; 18108705d96Sshatty } 18208705d96Sshatty 18308705d96Sshatty /* check if we are doing interlaced TVout mode */ 184b2459715SRudolf Cornelissen //fixme: we don't support interlaced mode? 18508705d96Sshatty si->interlaced_tv_mode = false; 186c0ebc619SRudolf Cornelissen 18708705d96Sshatty /*set the display(s) pitches*/ 1880669fe20SRudolf Cornelissen head1_set_display_pitch (); 18908705d96Sshatty //fixme: seperate for real dualhead modes: 19008705d96Sshatty //we need a secondary si->fbc! 1910669fe20SRudolf Cornelissen head2_set_display_pitch (); 19208705d96Sshatty 19308705d96Sshatty /*work out where the "right" screen starts*/ 19408705d96Sshatty startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3)); 19508705d96Sshatty 19608705d96Sshatty /* Tell card what memory to display */ 19708705d96Sshatty switch (target.flags & DUALHEAD_BITS) 19808705d96Sshatty { 19908705d96Sshatty case DUALHEAD_ON: 20008705d96Sshatty case DUALHEAD_SWITCH: 2010669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth1); 2020669fe20SRudolf Cornelissen head2_set_display_start(startadd_right,colour_depth2); 20308705d96Sshatty break; 20408705d96Sshatty case DUALHEAD_CLONE: 2050669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth1); 2060669fe20SRudolf Cornelissen head2_set_display_start(startadd,colour_depth2); 20708705d96Sshatty break; 20808705d96Sshatty } 20908705d96Sshatty 21008705d96Sshatty /* set the timing */ 2110669fe20SRudolf Cornelissen head1_set_timing(target); 212c0ebc619SRudolf Cornelissen head2_set_timing(target2); 21308705d96Sshatty 214c0ebc619SRudolf Cornelissen /* TVout support: program TVout encoder and modify CRTC timing */ 215b2459715SRudolf Cornelissen if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2); 21608705d96Sshatty } 21708705d96Sshatty else /* single head mode */ 21808705d96Sshatty { 21908705d96Sshatty int colour_mode = BPP32; 22008705d96Sshatty 22130f76422SRudolf Cornelissen /* connect output */ 22230f76422SRudolf Cornelissen if (si->ps.secondary_head) 22330f76422SRudolf Cornelissen { 22430f76422SRudolf Cornelissen /* detect which connectors have a CRT connected */ 22530f76422SRudolf Cornelissen //fixme: 'hot-plugging' for analog monitors removed: remove code as well; 22630f76422SRudolf Cornelissen //or make it work with digital panels connected as well. 22730f76422SRudolf Cornelissen // crt1 = nv_dac_crt_connected(); 22830f76422SRudolf Cornelissen // crt2 = nv_dac2_crt_connected(); 22930f76422SRudolf Cornelissen /* connect outputs 'straight-through' */ 23030f76422SRudolf Cornelissen // if (crt1) 23130f76422SRudolf Cornelissen // { 23230f76422SRudolf Cornelissen /* connector1 is used as primary output */ 23330f76422SRudolf Cornelissen // cross = false; 23430f76422SRudolf Cornelissen // } 23530f76422SRudolf Cornelissen // else 23630f76422SRudolf Cornelissen // { 23730f76422SRudolf Cornelissen // if (crt2) 23830f76422SRudolf Cornelissen /* connector2 is used as primary output */ 23930f76422SRudolf Cornelissen // cross = true; 24030f76422SRudolf Cornelissen // else 24130f76422SRudolf Cornelissen /* no CRT detected: assume connector1 is used as primary output */ 24230f76422SRudolf Cornelissen // cross = false; 24330f76422SRudolf Cornelissen // } 24430f76422SRudolf Cornelissen /* set output connectors assignment if possible */ 24506f4c439SRudolf Cornelissen nv_general_head_select(false); 24630f76422SRudolf Cornelissen } 24730f76422SRudolf Cornelissen 24808705d96Sshatty switch(target.space) 24908705d96Sshatty { 25008705d96Sshatty case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; 25108705d96Sshatty case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; 25208705d96Sshatty case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; 25308705d96Sshatty case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; 25408705d96Sshatty default: 25508705d96Sshatty LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); 25608705d96Sshatty return B_ERROR; 25708705d96Sshatty } 25808705d96Sshatty 25908705d96Sshatty /* set the pixel clock PLL */ 260c0ebc619SRudolf Cornelissen if (head1_set_pix_pll(target) == B_ERROR) 26108705d96Sshatty LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); 26208705d96Sshatty 26308705d96Sshatty /* set the colour depth for CRTC1 and the DAC */ 26408705d96Sshatty /* first set the colordepth */ 2650669fe20SRudolf Cornelissen head1_depth(colour_mode); 26608705d96Sshatty /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */ 26730f76422SRudolf Cornelissen head1_mode(colour_mode,1.0); 26808705d96Sshatty 26908705d96Sshatty /* set the display pitch */ 2700669fe20SRudolf Cornelissen head1_set_display_pitch(); 27108705d96Sshatty 27208705d96Sshatty /* tell the card what memory to display */ 2730669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth1); 27408705d96Sshatty 27508705d96Sshatty /* set the timing */ 276c0ebc619SRudolf Cornelissen head1_set_timing(target); 277b2459715SRudolf Cornelissen 278c0ebc619SRudolf Cornelissen /* TVout support: program TVout encoder and modify CRTC timing */ 279b2459715SRudolf Cornelissen if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target); 28008705d96Sshatty 28108705d96Sshatty //fixme: shut-off the videoPLL if it exists... 28208705d96Sshatty } 28308705d96Sshatty 28408705d96Sshatty /* update driver's mode store */ 28508705d96Sshatty si->dm = target; 28608705d96Sshatty 2873c4c0505SRudolf Cornelissen /* update FIFO data fetching according to mode */ 2883c4c0505SRudolf Cornelissen nv_crtc_update_fifo(); 289a393eaf8SRudolf Cornelissen if (si->ps.secondary_head) nv_crtc2_update_fifo(); 2903c4c0505SRudolf Cornelissen 29108705d96Sshatty /* set up acceleration for this mode */ 292dd43fd34SRudolf Cornelissen /* note: 2933c4c0505SRudolf Cornelissen * Maybe later we can forget about non-DMA mode (depends on 3D acceleration 2943c4c0505SRudolf Cornelissen * attempts). */ 295dd446dd3SRudolf Cornelissen if (!si->settings.dma_acc) 296b4c44701Sshatty nv_acc_init(); 297dd43fd34SRudolf Cornelissen else 298dd43fd34SRudolf Cornelissen nv_acc_init_dma(); 299*69ca2102SRudolf Cornelissen 300b4c44701Sshatty /* set up overlay unit for this mode */ 301aa1e552fSshatty nv_bes_init(); 30208705d96Sshatty 30389d37d46SRudolf Cornelissen /* note freemem range */ 30489d37d46SRudolf Cornelissen /* first free adress follows hardcursor and workspace */ 30521545d00SRudolf Cornelissen si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height; 30621545d00SRudolf Cornelissen if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048; 30789d37d46SRudolf Cornelissen /* last free adress is end-of-ram minus max space needed for overlay bitmaps */ 30889d37d46SRudolf Cornelissen //fixme possible: 30989d37d46SRudolf Cornelissen //if overlay buffers are allocated subtract buffersize from mem_high; 31089d37d46SRudolf Cornelissen //only allocate overlay buffers if 3D is not in use. (block overlay during 3D) 31121545d00SRudolf Cornelissen si->engine.threeD.mem_high = si->ps.memory_size - 1; 312f67620f9SRudolf Cornelissen /* Keep some extra distance as a workaround for certain bugs (see 313f67620f9SRudolf Cornelissen * DriverInterface.h for an explanation). */ 314fdd699c7SRudolf Cornelissen if (si->ps.card_arch < NV40A) 315f67620f9SRudolf Cornelissen si->engine.threeD.mem_high -= PRE_NV40_OFFSET; 316fdd699c7SRudolf Cornelissen else 317f67620f9SRudolf Cornelissen si->engine.threeD.mem_high -= NV40_PLUS_OFFSET; 318f67620f9SRudolf Cornelissen 31921545d00SRudolf Cornelissen si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */ 32089d37d46SRudolf Cornelissen 321bfecd0cdSRudolf Cornelissen /* restore screen(s) output state(s) */ 322bfecd0cdSRudolf Cornelissen SET_DPMS_MODE(si->dpms_flags); 32308705d96Sshatty 32408705d96Sshatty /* enable interrupts using the kernel driver */ 325155a2ad0SRudolf Cornelissen //fixme: 326155a2ad0SRudolf Cornelissen //add head2 once we use one driver instance 'per head' (instead of 'per card') 327155a2ad0SRudolf Cornelissen head1_interrupt_enable(true); 32808705d96Sshatty 329c9c0c72bSRudolf Cornelissen /* make sure a possible 3D add-on will re-initialize itself by signalling ready */ 33021545d00SRudolf Cornelissen si->engine.threeD.mode_changing = false; 331c9c0c72bSRudolf Cornelissen 33208705d96Sshatty /* optimize memory-access if needed */ 3330669fe20SRudolf Cornelissen // head1_mem_priority(colour_depth1); 33408705d96Sshatty 33508705d96Sshatty /* Tune RAM CAS-latency if needed. Must be done *here*! */ 33608705d96Sshatty nv_set_cas_latency(); 33708705d96Sshatty 338bfecd0cdSRudolf Cornelissen LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0)); 339bfecd0cdSRudolf Cornelissen 34008705d96Sshatty return B_OK; 34108705d96Sshatty } 34208705d96Sshatty 34308705d96Sshatty /* 34408705d96Sshatty Set which pixel of the virtual frame buffer will show up in the 34508705d96Sshatty top left corner of the display device. Used for page-flipping 34608705d96Sshatty games and virtual desktops. 34708705d96Sshatty */ 34808705d96Sshatty status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { 34908705d96Sshatty uint8 colour_depth; 35008705d96Sshatty uint32 startadd,startadd_right; 35108705d96Sshatty 35208705d96Sshatty LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); 35308705d96Sshatty 354255e5021SRudolf Cornelissen /* nVidia cards support pixelprecise panning on both heads in all modes: 355255e5021SRudolf Cornelissen * No stepping granularity needed! */ 356255e5021SRudolf Cornelissen 357255e5021SRudolf Cornelissen /* determine bits used for the colordepth */ 35808705d96Sshatty switch(si->dm.space) 35908705d96Sshatty { 36008705d96Sshatty case B_CMAP8: 36108705d96Sshatty colour_depth=8; 36208705d96Sshatty break; 363255e5021SRudolf Cornelissen case B_RGB15_LITTLE: 364255e5021SRudolf Cornelissen case B_RGB16_LITTLE: 36508705d96Sshatty colour_depth=16; 366255e5021SRudolf Cornelissen break; 367255e5021SRudolf Cornelissen case B_RGB24_LITTLE: 368255e5021SRudolf Cornelissen colour_depth=24; 36908705d96Sshatty break; 37008705d96Sshatty case B_RGB32_LITTLE: 37108705d96Sshatty colour_depth=32; 37208705d96Sshatty break; 37308705d96Sshatty default: 37408705d96Sshatty return B_ERROR; 37508705d96Sshatty } 37608705d96Sshatty 37708705d96Sshatty /* do not run past end of display */ 37808705d96Sshatty switch (si->dm.flags & DUALHEAD_BITS) 37908705d96Sshatty { 38008705d96Sshatty case DUALHEAD_ON: 38108705d96Sshatty case DUALHEAD_SWITCH: 38208705d96Sshatty if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) 38308705d96Sshatty return B_ERROR; 38408705d96Sshatty break; 38508705d96Sshatty default: 38608705d96Sshatty if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) 38708705d96Sshatty return B_ERROR; 38808705d96Sshatty break; 38908705d96Sshatty } 39008705d96Sshatty if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) 39108705d96Sshatty return B_ERROR; 39208705d96Sshatty 39308705d96Sshatty /* everybody remember where we parked... */ 39408705d96Sshatty si->dm.h_display_start = h_display_start; 39508705d96Sshatty si->dm.v_display_start = v_display_start; 39608705d96Sshatty 39708705d96Sshatty /* actually set the registers */ 39808705d96Sshatty //fixme: seperate both heads: we need a secondary si->fbc! 39908705d96Sshatty startadd = v_display_start * si->fbc.bytes_per_row; 40008705d96Sshatty startadd += h_display_start * (colour_depth >> 3); 401f2777ca1SRudolf Cornelissen startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 40208705d96Sshatty startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); 40308705d96Sshatty 404155a2ad0SRudolf Cornelissen /* disable interrupts using the kernel driver */ 405155a2ad0SRudolf Cornelissen head1_interrupt_enable(false); 406155a2ad0SRudolf Cornelissen if (si->ps.secondary_head) head2_interrupt_enable(false); 40708705d96Sshatty 40808705d96Sshatty switch (si->dm.flags & DUALHEAD_BITS) 40908705d96Sshatty { 41008705d96Sshatty case DUALHEAD_ON: 41108705d96Sshatty case DUALHEAD_SWITCH: 4120669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth); 4130669fe20SRudolf Cornelissen head2_set_display_start(startadd_right,colour_depth); 41408705d96Sshatty break; 41508705d96Sshatty case DUALHEAD_OFF: 4160669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth); 41708705d96Sshatty break; 41808705d96Sshatty case DUALHEAD_CLONE: 4190669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth); 4200669fe20SRudolf Cornelissen head2_set_display_start(startadd,colour_depth); 42108705d96Sshatty break; 42208705d96Sshatty } 42308705d96Sshatty 424155a2ad0SRudolf Cornelissen //fixme: 425155a2ad0SRudolf Cornelissen //add head2 once we use one driver instance 'per head' (instead of 'per card') 426155a2ad0SRudolf Cornelissen head1_interrupt_enable(true); 427155a2ad0SRudolf Cornelissen 42808705d96Sshatty return B_OK; 42908705d96Sshatty } 43008705d96Sshatty 431255e5021SRudolf Cornelissen /* Set the indexed color palette */ 43208705d96Sshatty void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { 43308705d96Sshatty int i; 43408705d96Sshatty uint8 *r,*g,*b; 43508705d96Sshatty 43608705d96Sshatty /* Protect gamma correction when not in CMAP8 */ 43708705d96Sshatty if (si->dm.space != B_CMAP8) return; 43808705d96Sshatty 43908705d96Sshatty r=si->color_data; 44008705d96Sshatty g=r+256; 44108705d96Sshatty b=g+256; 44208705d96Sshatty 44308705d96Sshatty i=first; 44408705d96Sshatty while (count--) 44508705d96Sshatty { 44608705d96Sshatty r[i]=*color_data++; 44708705d96Sshatty g[i]=*color_data++; 44808705d96Sshatty b[i]=*color_data++; 44908705d96Sshatty i++; 45008705d96Sshatty } 45130f76422SRudolf Cornelissen head1_palette(r,g,b); 45230f76422SRudolf Cornelissen if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b); 45308705d96Sshatty } 45408705d96Sshatty 45508705d96Sshatty /* Put the display into one of the Display Power Management modes. */ 456bfecd0cdSRudolf Cornelissen status_t SET_DPMS_MODE(uint32 dpms_flags) 457bfecd0cdSRudolf Cornelissen { 4584022652cSRudolf Cornelissen bool display, h1h, h1v, h2h, h2v, do_p1, do_p2; 45920603b95SRudolf Cornelissen 460155a2ad0SRudolf Cornelissen /* disable interrupts using the kernel driver */ 461155a2ad0SRudolf Cornelissen head1_interrupt_enable(false); 462155a2ad0SRudolf Cornelissen if (si->ps.secondary_head) head2_interrupt_enable(false); 46308705d96Sshatty 4644022652cSRudolf Cornelissen LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags)); 46508705d96Sshatty 466bfecd0cdSRudolf Cornelissen /* note current DPMS state for our reference */ 467bfecd0cdSRudolf Cornelissen si->dpms_flags = dpms_flags; 468bfecd0cdSRudolf Cornelissen 4694022652cSRudolf Cornelissen /* preset: DPMS for panels should be executed */ 4704022652cSRudolf Cornelissen do_p1 = do_p2 = true; 4714022652cSRudolf Cornelissen 47220603b95SRudolf Cornelissen /* determine signals to send to head(s) */ 47320603b95SRudolf Cornelissen display = h1h = h1v = h2h = h2v = true; 47408705d96Sshatty switch(dpms_flags) 47508705d96Sshatty { 47608705d96Sshatty case B_DPMS_ON: /* H: on, V: on, display on */ 47708705d96Sshatty break; 47808705d96Sshatty case B_DPMS_STAND_BY: 47920603b95SRudolf Cornelissen display = h1h = h2h = false; 48008705d96Sshatty break; 48108705d96Sshatty case B_DPMS_SUSPEND: 48220603b95SRudolf Cornelissen display = h1v = h2v = false; 48308705d96Sshatty break; 48408705d96Sshatty case B_DPMS_OFF: /* H: off, V: off, display off */ 48520603b95SRudolf Cornelissen display = h1h = h1v = h2h = h2v = false; 48608705d96Sshatty break; 48708705d96Sshatty default: 4884022652cSRudolf Cornelissen LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags)); 489155a2ad0SRudolf Cornelissen //fixme: 490155a2ad0SRudolf Cornelissen //add head2 once we use one driver instance 'per head' (instead of 'per card') 491155a2ad0SRudolf Cornelissen head1_interrupt_enable(true); 492155a2ad0SRudolf Cornelissen 49308705d96Sshatty return B_ERROR; 49408705d96Sshatty } 49520603b95SRudolf Cornelissen 49620603b95SRudolf Cornelissen /* CRTC used for TVout needs specific DPMS programming */ 49720603b95SRudolf Cornelissen if (si->dm.flags & TV_BITS) 49808705d96Sshatty { 4993c71b494SRudolf Cornelissen /* TV_PRIMARY tells us that the head to be used with TVout is the head that's 5003c71b494SRudolf Cornelissen * actually assigned as being the primary head at powerup: 5013c71b494SRudolf Cornelissen * so non dualhead-mode-dependant, and not 'fixed' CRTC1! */ 502a658603aSRudolf Cornelissen if (si->dm.flags & TV_PRIMARY) 503a658603aSRudolf Cornelissen { 504a658603aSRudolf Cornelissen LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n")); 50520603b95SRudolf Cornelissen 5063c71b494SRudolf Cornelissen if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH) 5073c71b494SRudolf Cornelissen { 50820603b95SRudolf Cornelissen if (!(si->settings.vga_on_tv)) 50908705d96Sshatty { 51020603b95SRudolf Cornelissen /* block VGA output on head displaying on TV */ 51120603b95SRudolf Cornelissen /* Note: 51220603b95SRudolf Cornelissen * this specific sync setting is required: Vsync is used to keep TVout 51320603b95SRudolf Cornelissen * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs). 51420603b95SRudolf Cornelissen * This leaves Hsync only for shutting off the VGA screen. */ 51520603b95SRudolf Cornelissen h1h = false; 51620603b95SRudolf Cornelissen h1v = true; 5174022652cSRudolf Cornelissen /* block panel DPMS updates */ 5184022652cSRudolf Cornelissen do_p1 = false; 51920603b95SRudolf Cornelissen } 52020603b95SRudolf Cornelissen else 52120603b95SRudolf Cornelissen { 52220603b95SRudolf Cornelissen /* when concurrent VGA is used alongside TVout on a head, DPMS is safest 52320603b95SRudolf Cornelissen * applied this way: Vsync is needed for stopping TVout successfully when 52420603b95SRudolf Cornelissen * a (new) modeswitch occurs. 52520603b95SRudolf Cornelissen * (see routine BT_stop_tvout() in nv_brooktreetv.c) */ 52620603b95SRudolf Cornelissen /* Note: 52720603b95SRudolf Cornelissen * applying 'normal' DPMS here and forcing Vsync on in the above mentioned 52820603b95SRudolf Cornelissen * routine seems to not always be enough: sometimes image generation will 52920603b95SRudolf Cornelissen * not resume in that case. */ 53020603b95SRudolf Cornelissen h1h = display; 53120603b95SRudolf Cornelissen h1v = true; 53208705d96Sshatty } 53308705d96Sshatty } 534a658603aSRudolf Cornelissen else 535a658603aSRudolf Cornelissen { 536a658603aSRudolf Cornelissen if (!(si->settings.vga_on_tv)) 537a658603aSRudolf Cornelissen { 538a658603aSRudolf Cornelissen h2h = false; 539a658603aSRudolf Cornelissen h2v = true; 5404022652cSRudolf Cornelissen do_p2 = false; 541a658603aSRudolf Cornelissen } 542a658603aSRudolf Cornelissen else 543a658603aSRudolf Cornelissen { 544a658603aSRudolf Cornelissen h2h = display; 545a658603aSRudolf Cornelissen h2v = true; 546a658603aSRudolf Cornelissen } 547a658603aSRudolf Cornelissen } 548a658603aSRudolf Cornelissen } 5493c71b494SRudolf Cornelissen else 5503c71b494SRudolf Cornelissen { 5513c71b494SRudolf Cornelissen LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n")); 5523c71b494SRudolf Cornelissen 5533c71b494SRudolf Cornelissen if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH) 5543c71b494SRudolf Cornelissen { 5553c71b494SRudolf Cornelissen if (!(si->settings.vga_on_tv)) 5563c71b494SRudolf Cornelissen { 5573c71b494SRudolf Cornelissen h2h = false; 5583c71b494SRudolf Cornelissen h2v = true; 5594022652cSRudolf Cornelissen do_p2 = false; 5603c71b494SRudolf Cornelissen } 5613c71b494SRudolf Cornelissen else 5623c71b494SRudolf Cornelissen { 5633c71b494SRudolf Cornelissen h2h = display; 5643c71b494SRudolf Cornelissen h2v = true; 5653c71b494SRudolf Cornelissen } 5663c71b494SRudolf Cornelissen } 5673c71b494SRudolf Cornelissen else 5683c71b494SRudolf Cornelissen { 5693c71b494SRudolf Cornelissen if (!(si->settings.vga_on_tv)) 5703c71b494SRudolf Cornelissen { 5713c71b494SRudolf Cornelissen h1h = false; 5723c71b494SRudolf Cornelissen h1v = true; 5734022652cSRudolf Cornelissen do_p1 = false; 5743c71b494SRudolf Cornelissen } 5753c71b494SRudolf Cornelissen else 5763c71b494SRudolf Cornelissen { 5773c71b494SRudolf Cornelissen h1h = display; 5783c71b494SRudolf Cornelissen h1v = true; 5793c71b494SRudolf Cornelissen } 5803c71b494SRudolf Cornelissen } 5813c71b494SRudolf Cornelissen } 5823c71b494SRudolf Cornelissen } 5833aa21459SRudolf Cornelissen 58420603b95SRudolf Cornelissen /* issue actual DPMS commands as far as applicable */ 5854022652cSRudolf Cornelissen head1_dpms(display, h1h, h1v, do_p1); 58620603b95SRudolf Cornelissen if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS)) 5874022652cSRudolf Cornelissen head2_dpms(display, h2h, h2v, do_p2); 58820603b95SRudolf Cornelissen if (si->dm.flags & TV_BITS) 58920603b95SRudolf Cornelissen BT_dpms(display); 59020603b95SRudolf Cornelissen 591155a2ad0SRudolf Cornelissen //fixme: 592155a2ad0SRudolf Cornelissen //add head2 once we use one driver instance 'per head' (instead of 'per card') 593155a2ad0SRudolf Cornelissen head1_interrupt_enable(true); 594155a2ad0SRudolf Cornelissen 59508705d96Sshatty return B_OK; 59608705d96Sshatty } 59708705d96Sshatty 59808705d96Sshatty /* Report device DPMS capabilities */ 59920603b95SRudolf Cornelissen uint32 DPMS_CAPABILITIES(void) 60020603b95SRudolf Cornelissen { 60108705d96Sshatty return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF); 60208705d96Sshatty } 60308705d96Sshatty 60408705d96Sshatty /* Return the current DPMS mode */ 605bfecd0cdSRudolf Cornelissen uint32 DPMS_MODE(void) 606bfecd0cdSRudolf Cornelissen { 607bfecd0cdSRudolf Cornelissen return si->dpms_flags; 60808705d96Sshatty } 609