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, 9a658603aSRudolf Cornelissen Rudolf Cornelissen 11/2002-11/2005 1008705d96Sshatty */ 1108705d96Sshatty 1208705d96Sshatty #define MODULE_BIT 0x00200000 1308705d96Sshatty 1408705d96Sshatty #include "acc_std.h" 1508705d96Sshatty 1608705d96Sshatty /* 1708705d96Sshatty Enable/Disable interrupts. Just a wrapper around the 1808705d96Sshatty ioctl() to the kernel driver. 1908705d96Sshatty */ 20ce3fc95eSRudolf Cornelissen static void interrupt_enable(bool flag) 21ce3fc95eSRudolf Cornelissen { 22ce3fc95eSRudolf Cornelissen status_t result = B_OK; 2308705d96Sshatty nv_set_bool_state sbs; 2408705d96Sshatty 25ce3fc95eSRudolf Cornelissen if (si->ps.int_assigned) 26ce3fc95eSRudolf Cornelissen { 2708705d96Sshatty /* set the magic number so the driver knows we're for real */ 2808705d96Sshatty sbs.magic = NV_PRIVATE_DATA_MAGIC; 2908705d96Sshatty sbs.do_it = flag; 3008705d96Sshatty /* contact driver and get a pointer to the registers and shared data */ 3108705d96Sshatty result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs)); 3208705d96Sshatty } 33ce3fc95eSRudolf Cornelissen } 3408705d96Sshatty 3508705d96Sshatty /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ 3608705d96Sshatty status_t SET_DISPLAY_MODE(display_mode *mode_to_set) 3708705d96Sshatty { 3808705d96Sshatty /* BOUNDS WARNING: 3908705d96Sshatty * It's impossible to deviate whatever small amount in a display_mode if the lower 4008705d96Sshatty * and upper limits are the same! 4108705d96Sshatty * Besides: 4208705d96Sshatty * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE 4308705d96Sshatty * returns B_BAD_VALUE! 4408705d96Sshatty * Which means PROPOSEMODE should not return that on anything except on 4508705d96Sshatty * deviations for: 4608705d96Sshatty * display_mode.virtual_width; 4708705d96Sshatty * display_mode.virtual_height; 4808705d96Sshatty * display_mode.timing.h_display; 4908705d96Sshatty * display_mode.timing.v_display; 5008705d96Sshatty * So: 5108705d96Sshatty * We don't use bounds here by making sure bounds and target are the same struct! 5208705d96Sshatty * (See the call to PROPOSE_DISPLAY_MODE below) */ 5308705d96Sshatty display_mode /*bounds,*/ target; 5408705d96Sshatty 5508705d96Sshatty uint8 colour_depth1 = 32; 5608705d96Sshatty uint32 startadd,startadd_right; 5730f76422SRudolf Cornelissen // bool crt1, crt2, cross; 5808705d96Sshatty 5908705d96Sshatty /* Adjust mode to valid one and fail if invalid */ 6008705d96Sshatty target /*= bounds*/ = *mode_to_set; 6108705d96Sshatty /* show the mode bits */ 6208705d96Sshatty LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); 6308705d96Sshatty LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock)); 6408705d96Sshatty LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n", 6508705d96Sshatty target.virtual_width, target.virtual_height)); 6608705d96Sshatty 6708705d96Sshatty /* See BOUNDS WARNING above... */ 6808705d96Sshatty if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; 6908705d96Sshatty 70c9c0c72bSRudolf Cornelissen /* make sure a possible 3D add-on will block rendering and re-initialize itself. 71c9c0c72bSRudolf Cornelissen * note: update in _this_ order only */ 72c9c0c72bSRudolf Cornelissen /* SET_DISPLAY_MODE will reset this flag when it's done. */ 7321545d00SRudolf Cornelissen si->engine.threeD.mode_changing = true; 7421545d00SRudolf Cornelissen /* every 3D add-on will reset this bit-flag when it's done. */ 7521545d00SRudolf Cornelissen si->engine.threeD.newmode = 0xffffffff; 7621545d00SRudolf Cornelissen /* every 3D clone needs to reclaim a slot. 7721545d00SRudolf Cornelissen * note: this also cleans up reserved channels for killed 3D clones.. */ 7821545d00SRudolf Cornelissen si->engine.threeD.clones = 0x00000000; 79afb207acSRudolf Cornelissen 8008705d96Sshatty /* disable interrupts using the kernel driver */ 8108705d96Sshatty interrupt_enable(false); 8208705d96Sshatty 830703480cSRudolf Cornelissen /* disable TVout if supported */ 840703480cSRudolf Cornelissen if (si->ps.tvout) BT_stop_tvout(); 850b36eea4SRudolf Cornelissen 8620603b95SRudolf Cornelissen /* turn off screen(s) _after_ TVout is disabled (if applicable) */ 870669fe20SRudolf Cornelissen head1_dpms(false, false, false); 880669fe20SRudolf Cornelissen if (si->ps.secondary_head) head2_dpms(false, false, false); 893aa21459SRudolf Cornelissen if (si->ps.tvout) BT_dpms(false); 9008705d96Sshatty 9108705d96Sshatty /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ 92f2777ca1SRudolf Cornelissen startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 9308705d96Sshatty 9408705d96Sshatty /* calculate and set new mode bytes_per_row */ 9505ed3229SRudolf Cornelissen nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode); 9608705d96Sshatty 9708705d96Sshatty /*Perform the very long mode switch!*/ 9808705d96Sshatty if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ 9908705d96Sshatty { 10008705d96Sshatty uint8 colour_depth2 = colour_depth1; 10108705d96Sshatty 10208705d96Sshatty /* init display mode for secondary head */ 10308705d96Sshatty display_mode target2 = target; 10408705d96Sshatty 10508705d96Sshatty LOG(1,("SETMODE: setting DUALHEAD mode\n")); 10608705d96Sshatty 10708705d96Sshatty /* validate flags for secondary TVout */ 108b2459715SRudolf Cornelissen //fixme: remove or block on autodetect fail. (is now shutoff) 109b2459715SRudolf Cornelissen if ((0) && (target2.flags & TV_BITS)) 11008705d96Sshatty { 11108705d96Sshatty target.flags &= ~TV_BITS;//still needed for some routines... 11208705d96Sshatty target2.flags &= ~TV_BITS; 11308705d96Sshatty LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); 11408705d96Sshatty } 11508705d96Sshatty 11630f76422SRudolf Cornelissen /* detect which connectors have a CRT connected */ 11730f76422SRudolf Cornelissen //fixme: 'hot-plugging' for analog monitors removed: remove code as well; 11830f76422SRudolf Cornelissen //or make it work with digital panels connected as well. 11930f76422SRudolf Cornelissen // crt1 = nv_dac_crt_connected(); 12030f76422SRudolf Cornelissen // crt2 = nv_dac2_crt_connected(); 12130f76422SRudolf Cornelissen /* connect outputs 'straight-through' */ 12230f76422SRudolf Cornelissen // if (crt1) 12330f76422SRudolf Cornelissen // { 12430f76422SRudolf Cornelissen /* connector1 is used as primary output */ 12530f76422SRudolf Cornelissen // cross = false; 12630f76422SRudolf Cornelissen // } 12730f76422SRudolf Cornelissen // else 12830f76422SRudolf Cornelissen // { 12930f76422SRudolf Cornelissen // if (crt2) 13030f76422SRudolf Cornelissen /* connector2 is used as primary output */ 13130f76422SRudolf Cornelissen // cross = true; 13230f76422SRudolf Cornelissen // else 13330f76422SRudolf Cornelissen /* no CRT detected: assume connector1 is used as primary output */ 13430f76422SRudolf Cornelissen // cross = false; 13530f76422SRudolf Cornelissen // } 13630f76422SRudolf Cornelissen /* set output connectors assignment if possible */ 13730f76422SRudolf Cornelissen if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH) 13830f76422SRudolf Cornelissen /* invert output assignment in switch mode */ 13906f4c439SRudolf Cornelissen nv_general_head_select(true); 14030f76422SRudolf Cornelissen else 14106f4c439SRudolf Cornelissen nv_general_head_select(false); 14230f76422SRudolf Cornelissen 14308705d96Sshatty /* set the pixel clock PLL(s) */ 14408705d96Sshatty LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); 14530f76422SRudolf Cornelissen if (head1_set_pix_pll(target) == B_ERROR) 14608705d96Sshatty LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); 14708705d96Sshatty 14808705d96Sshatty LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); 14930f76422SRudolf Cornelissen if (head2_set_pix_pll(target2) == B_ERROR) 150a3b9d212SRudolf Cornelissen LOG(8,("SETMODE: error setting pixel clock (DAC2)\n")); 15108705d96Sshatty 15208705d96Sshatty /*set the colour depth for CRTC1 and the DAC */ 15308705d96Sshatty switch(target.space) 15408705d96Sshatty { 155bc5690abSRudolf Cornelissen case B_CMAP8: 156bc5690abSRudolf Cornelissen colour_depth1 = 8; 15730f76422SRudolf Cornelissen head1_mode(BPP8, 1.0); 1580669fe20SRudolf Cornelissen head1_depth(BPP8); 159bc5690abSRudolf Cornelissen break; 160bc5690abSRudolf Cornelissen case B_RGB15_LITTLE: 161bc5690abSRudolf Cornelissen colour_depth1 = 16; 16230f76422SRudolf Cornelissen head1_mode(BPP15, 1.0); 1630669fe20SRudolf Cornelissen head1_depth(BPP15); 164bc5690abSRudolf Cornelissen break; 16508705d96Sshatty case B_RGB16_LITTLE: 16608705d96Sshatty colour_depth1 = 16; 16730f76422SRudolf Cornelissen head1_mode(BPP16, 1.0); 1680669fe20SRudolf Cornelissen head1_depth(BPP16); 16908705d96Sshatty break; 17008705d96Sshatty case B_RGB32_LITTLE: 17108705d96Sshatty colour_depth1 = 32; 17230f76422SRudolf Cornelissen head1_mode(BPP32, 1.0); 1730669fe20SRudolf Cornelissen head1_depth(BPP32); 17408705d96Sshatty break; 17508705d96Sshatty } 176a3b9d212SRudolf Cornelissen /*set the colour depth for CRTC2 and DAC2 */ 17708705d96Sshatty switch(target2.space) 17808705d96Sshatty { 179bc5690abSRudolf Cornelissen case B_CMAP8: 180bc5690abSRudolf Cornelissen colour_depth2 = 8; 18130f76422SRudolf Cornelissen head2_mode(BPP8, 1.0); 1820669fe20SRudolf Cornelissen head2_depth(BPP8); 183bc5690abSRudolf Cornelissen break; 184bc5690abSRudolf Cornelissen case B_RGB15_LITTLE: 185bc5690abSRudolf Cornelissen colour_depth2 = 16; 18630f76422SRudolf Cornelissen head2_mode(BPP15, 1.0); 1870669fe20SRudolf Cornelissen head2_depth(BPP15); 188bc5690abSRudolf Cornelissen break; 18908705d96Sshatty case B_RGB16_LITTLE: 19008705d96Sshatty colour_depth2 = 16; 19130f76422SRudolf Cornelissen head2_mode(BPP16, 1.0); 1920669fe20SRudolf Cornelissen head2_depth(BPP16); 19308705d96Sshatty break; 19408705d96Sshatty case B_RGB32_LITTLE: 19508705d96Sshatty colour_depth2 = 32; 19630f76422SRudolf Cornelissen head2_mode(BPP32, 1.0); 1970669fe20SRudolf Cornelissen head2_depth(BPP32); 19808705d96Sshatty break; 19908705d96Sshatty } 20008705d96Sshatty 20108705d96Sshatty /* check if we are doing interlaced TVout mode */ 202b2459715SRudolf Cornelissen //fixme: we don't support interlaced mode? 20308705d96Sshatty si->interlaced_tv_mode = false; 204*c0ebc619SRudolf Cornelissen 20508705d96Sshatty /*set the display(s) pitches*/ 2060669fe20SRudolf Cornelissen head1_set_display_pitch (); 20708705d96Sshatty //fixme: seperate for real dualhead modes: 20808705d96Sshatty //we need a secondary si->fbc! 2090669fe20SRudolf Cornelissen head2_set_display_pitch (); 21008705d96Sshatty 21108705d96Sshatty /*work out where the "right" screen starts*/ 21208705d96Sshatty startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3)); 21308705d96Sshatty 21408705d96Sshatty /* Tell card what memory to display */ 21508705d96Sshatty switch (target.flags & DUALHEAD_BITS) 21608705d96Sshatty { 21708705d96Sshatty case DUALHEAD_ON: 21808705d96Sshatty case DUALHEAD_SWITCH: 2190669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth1); 2200669fe20SRudolf Cornelissen head2_set_display_start(startadd_right,colour_depth2); 22108705d96Sshatty break; 22208705d96Sshatty case DUALHEAD_CLONE: 2230669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth1); 2240669fe20SRudolf Cornelissen head2_set_display_start(startadd,colour_depth2); 22508705d96Sshatty break; 22608705d96Sshatty } 22708705d96Sshatty 22808705d96Sshatty /* set the timing */ 2290669fe20SRudolf Cornelissen head1_set_timing(target); 230*c0ebc619SRudolf Cornelissen head2_set_timing(target2); 23108705d96Sshatty 232*c0ebc619SRudolf Cornelissen /* TVout support: program TVout encoder and modify CRTC timing */ 233b2459715SRudolf Cornelissen if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2); 23408705d96Sshatty } 23508705d96Sshatty else /* single head mode */ 23608705d96Sshatty { 23708705d96Sshatty int colour_mode = BPP32; 23808705d96Sshatty 23930f76422SRudolf Cornelissen /* connect output */ 24030f76422SRudolf Cornelissen if (si->ps.secondary_head) 24130f76422SRudolf Cornelissen { 24230f76422SRudolf Cornelissen /* detect which connectors have a CRT connected */ 24330f76422SRudolf Cornelissen //fixme: 'hot-plugging' for analog monitors removed: remove code as well; 24430f76422SRudolf Cornelissen //or make it work with digital panels connected as well. 24530f76422SRudolf Cornelissen // crt1 = nv_dac_crt_connected(); 24630f76422SRudolf Cornelissen // crt2 = nv_dac2_crt_connected(); 24730f76422SRudolf Cornelissen /* connect outputs 'straight-through' */ 24830f76422SRudolf Cornelissen // if (crt1) 24930f76422SRudolf Cornelissen // { 25030f76422SRudolf Cornelissen /* connector1 is used as primary output */ 25130f76422SRudolf Cornelissen // cross = false; 25230f76422SRudolf Cornelissen // } 25330f76422SRudolf Cornelissen // else 25430f76422SRudolf Cornelissen // { 25530f76422SRudolf Cornelissen // if (crt2) 25630f76422SRudolf Cornelissen /* connector2 is used as primary output */ 25730f76422SRudolf Cornelissen // cross = true; 25830f76422SRudolf Cornelissen // else 25930f76422SRudolf Cornelissen /* no CRT detected: assume connector1 is used as primary output */ 26030f76422SRudolf Cornelissen // cross = false; 26130f76422SRudolf Cornelissen // } 26230f76422SRudolf Cornelissen /* set output connectors assignment if possible */ 26306f4c439SRudolf Cornelissen nv_general_head_select(false); 26430f76422SRudolf Cornelissen } 26530f76422SRudolf Cornelissen 26608705d96Sshatty switch(target.space) 26708705d96Sshatty { 26808705d96Sshatty case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; 26908705d96Sshatty case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; 27008705d96Sshatty case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; 27108705d96Sshatty case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; 27208705d96Sshatty default: 27308705d96Sshatty LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); 27408705d96Sshatty return B_ERROR; 27508705d96Sshatty } 27608705d96Sshatty 27708705d96Sshatty /* set the pixel clock PLL */ 278*c0ebc619SRudolf Cornelissen if (head1_set_pix_pll(target) == B_ERROR) 27908705d96Sshatty LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); 28008705d96Sshatty 28108705d96Sshatty /* set the colour depth for CRTC1 and the DAC */ 28208705d96Sshatty /* first set the colordepth */ 2830669fe20SRudolf Cornelissen head1_depth(colour_mode); 28408705d96Sshatty /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */ 28530f76422SRudolf Cornelissen head1_mode(colour_mode,1.0); 28608705d96Sshatty 28708705d96Sshatty /* set the display pitch */ 2880669fe20SRudolf Cornelissen head1_set_display_pitch(); 28908705d96Sshatty 29008705d96Sshatty /* tell the card what memory to display */ 2910669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth1); 29208705d96Sshatty 29308705d96Sshatty /* set the timing */ 294*c0ebc619SRudolf Cornelissen head1_set_timing(target); 295b2459715SRudolf Cornelissen 296*c0ebc619SRudolf Cornelissen /* TVout support: program TVout encoder and modify CRTC timing */ 297b2459715SRudolf Cornelissen if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target); 29808705d96Sshatty 29908705d96Sshatty //fixme: shut-off the videoPLL if it exists... 30008705d96Sshatty } 30108705d96Sshatty 30208705d96Sshatty /* update driver's mode store */ 30308705d96Sshatty si->dm = target; 30408705d96Sshatty 3053c4c0505SRudolf Cornelissen /* update FIFO data fetching according to mode */ 3063c4c0505SRudolf Cornelissen nv_crtc_update_fifo(); 3073c4c0505SRudolf Cornelissen 30808705d96Sshatty /* set up acceleration for this mode */ 309dd43fd34SRudolf Cornelissen /* note: 3103c4c0505SRudolf Cornelissen * Maybe later we can forget about non-DMA mode (depends on 3D acceleration 3113c4c0505SRudolf Cornelissen * attempts). */ 312dd446dd3SRudolf Cornelissen if (!si->settings.dma_acc) 313b4c44701Sshatty nv_acc_init(); 314dd43fd34SRudolf Cornelissen else 315dd43fd34SRudolf Cornelissen nv_acc_init_dma(); 316b4c44701Sshatty /* set up overlay unit for this mode */ 317aa1e552fSshatty nv_bes_init(); 31808705d96Sshatty 31989d37d46SRudolf Cornelissen /* note freemem range */ 32089d37d46SRudolf Cornelissen /* first free adress follows hardcursor and workspace */ 32121545d00SRudolf Cornelissen si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height; 32221545d00SRudolf Cornelissen if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048; 32389d37d46SRudolf Cornelissen /* last free adress is end-of-ram minus max space needed for overlay bitmaps */ 32489d37d46SRudolf Cornelissen //fixme possible: 32589d37d46SRudolf Cornelissen //if overlay buffers are allocated subtract buffersize from mem_high; 32689d37d46SRudolf Cornelissen //only allocate overlay buffers if 3D is not in use. (block overlay during 3D) 32721545d00SRudolf Cornelissen si->engine.threeD.mem_high = si->ps.memory_size - 1; 328fee251bcSRudolf Cornelissen /* don't touch the DMA acceleration engine command buffer if it exists */ 329fee251bcSRudolf Cornelissen /* note: 330fdd699c7SRudolf Cornelissen * the buffer is 32kB in size. Keep some extra distance for safety (faulty apps). */ 331fdd699c7SRudolf Cornelissen if (si->settings.dma_acc) 332fdd699c7SRudolf Cornelissen { 333fdd699c7SRudolf Cornelissen if (si->ps.card_arch < NV40A) 334fdd699c7SRudolf Cornelissen { 335fdd699c7SRudolf Cornelissen /* keeping 32kB distance from the DMA buffer */ 33621545d00SRudolf Cornelissen si->engine.threeD.mem_high -= (64 * 1024); 337fdd699c7SRudolf Cornelissen } 338fdd699c7SRudolf Cornelissen else 339fdd699c7SRudolf Cornelissen { 340fdd699c7SRudolf Cornelissen /* 416kB distance is just OK: keeping another 64kB distance for safety; 341fdd699c7SRudolf Cornelissen * confirmed for NV43. */ 342fdd699c7SRudolf Cornelissen /* note: 343fdd699c7SRudolf Cornelissen * if you get too close to the DMA command buffer on NV40 and NV43 at 344fdd699c7SRudolf Cornelissen * least (both confirmed), the source DMA instance will mess-up for 345fdd699c7SRudolf Cornelissen * at least engine cmd NV_IMAGE_BLIT and NV12_IMAGE_BLIT. */ 34621545d00SRudolf Cornelissen si->engine.threeD.mem_high -= (512 * 1024); 347fdd699c7SRudolf Cornelissen } 348fdd699c7SRudolf Cornelissen } 34921545d00SRudolf Cornelissen si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */ 35089d37d46SRudolf Cornelissen 351bfecd0cdSRudolf Cornelissen /* restore screen(s) output state(s) */ 352bfecd0cdSRudolf Cornelissen SET_DPMS_MODE(si->dpms_flags); 35308705d96Sshatty 35408705d96Sshatty /* enable interrupts using the kernel driver */ 35508705d96Sshatty interrupt_enable(true); 35608705d96Sshatty 357c9c0c72bSRudolf Cornelissen /* make sure a possible 3D add-on will re-initialize itself by signalling ready */ 35821545d00SRudolf Cornelissen si->engine.threeD.mode_changing = false; 359c9c0c72bSRudolf Cornelissen 36008705d96Sshatty /* optimize memory-access if needed */ 3610669fe20SRudolf Cornelissen // head1_mem_priority(colour_depth1); 36208705d96Sshatty 36308705d96Sshatty /* Tune RAM CAS-latency if needed. Must be done *here*! */ 36408705d96Sshatty nv_set_cas_latency(); 36508705d96Sshatty 366bfecd0cdSRudolf Cornelissen LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0)); 367bfecd0cdSRudolf Cornelissen 36808705d96Sshatty return B_OK; 36908705d96Sshatty } 37008705d96Sshatty 37108705d96Sshatty /* 37208705d96Sshatty Set which pixel of the virtual frame buffer will show up in the 37308705d96Sshatty top left corner of the display device. Used for page-flipping 37408705d96Sshatty games and virtual desktops. 37508705d96Sshatty */ 37608705d96Sshatty status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { 37708705d96Sshatty uint8 colour_depth; 37808705d96Sshatty uint32 startadd,startadd_right; 37908705d96Sshatty 38008705d96Sshatty LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); 38108705d96Sshatty 382255e5021SRudolf Cornelissen /* nVidia cards support pixelprecise panning on both heads in all modes: 383255e5021SRudolf Cornelissen * No stepping granularity needed! */ 384255e5021SRudolf Cornelissen 385255e5021SRudolf Cornelissen /* determine bits used for the colordepth */ 38608705d96Sshatty switch(si->dm.space) 38708705d96Sshatty { 38808705d96Sshatty case B_CMAP8: 38908705d96Sshatty colour_depth=8; 39008705d96Sshatty break; 391255e5021SRudolf Cornelissen case B_RGB15_LITTLE: 392255e5021SRudolf Cornelissen case B_RGB16_LITTLE: 39308705d96Sshatty colour_depth=16; 394255e5021SRudolf Cornelissen break; 395255e5021SRudolf Cornelissen case B_RGB24_LITTLE: 396255e5021SRudolf Cornelissen colour_depth=24; 39708705d96Sshatty break; 39808705d96Sshatty case B_RGB32_LITTLE: 39908705d96Sshatty colour_depth=32; 40008705d96Sshatty break; 40108705d96Sshatty default: 40208705d96Sshatty return B_ERROR; 40308705d96Sshatty } 40408705d96Sshatty 40508705d96Sshatty /* do not run past end of display */ 40608705d96Sshatty switch (si->dm.flags & DUALHEAD_BITS) 40708705d96Sshatty { 40808705d96Sshatty case DUALHEAD_ON: 40908705d96Sshatty case DUALHEAD_SWITCH: 41008705d96Sshatty if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) 41108705d96Sshatty return B_ERROR; 41208705d96Sshatty break; 41308705d96Sshatty default: 41408705d96Sshatty if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) 41508705d96Sshatty return B_ERROR; 41608705d96Sshatty break; 41708705d96Sshatty } 41808705d96Sshatty if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) 41908705d96Sshatty return B_ERROR; 42008705d96Sshatty 42108705d96Sshatty /* everybody remember where we parked... */ 42208705d96Sshatty si->dm.h_display_start = h_display_start; 42308705d96Sshatty si->dm.v_display_start = v_display_start; 42408705d96Sshatty 42508705d96Sshatty /* actually set the registers */ 42608705d96Sshatty //fixme: seperate both heads: we need a secondary si->fbc! 42708705d96Sshatty startadd = v_display_start * si->fbc.bytes_per_row; 42808705d96Sshatty startadd += h_display_start * (colour_depth >> 3); 429f2777ca1SRudolf Cornelissen startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 43008705d96Sshatty startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); 43108705d96Sshatty 43208705d96Sshatty interrupt_enable(false); 43308705d96Sshatty 43408705d96Sshatty switch (si->dm.flags & DUALHEAD_BITS) 43508705d96Sshatty { 43608705d96Sshatty case DUALHEAD_ON: 43708705d96Sshatty case DUALHEAD_SWITCH: 4380669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth); 4390669fe20SRudolf Cornelissen head2_set_display_start(startadd_right,colour_depth); 44008705d96Sshatty break; 44108705d96Sshatty case DUALHEAD_OFF: 4420669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth); 44308705d96Sshatty break; 44408705d96Sshatty case DUALHEAD_CLONE: 4450669fe20SRudolf Cornelissen head1_set_display_start(startadd,colour_depth); 4460669fe20SRudolf Cornelissen head2_set_display_start(startadd,colour_depth); 44708705d96Sshatty break; 44808705d96Sshatty } 44908705d96Sshatty 45008705d96Sshatty interrupt_enable(true); 45108705d96Sshatty return B_OK; 45208705d96Sshatty } 45308705d96Sshatty 454255e5021SRudolf Cornelissen /* Set the indexed color palette */ 45508705d96Sshatty void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { 45608705d96Sshatty int i; 45708705d96Sshatty uint8 *r,*g,*b; 45808705d96Sshatty 45908705d96Sshatty /* Protect gamma correction when not in CMAP8 */ 46008705d96Sshatty if (si->dm.space != B_CMAP8) return; 46108705d96Sshatty 46208705d96Sshatty r=si->color_data; 46308705d96Sshatty g=r+256; 46408705d96Sshatty b=g+256; 46508705d96Sshatty 46608705d96Sshatty i=first; 46708705d96Sshatty while (count--) 46808705d96Sshatty { 46908705d96Sshatty r[i]=*color_data++; 47008705d96Sshatty g[i]=*color_data++; 47108705d96Sshatty b[i]=*color_data++; 47208705d96Sshatty i++; 47308705d96Sshatty } 47430f76422SRudolf Cornelissen head1_palette(r,g,b); 47530f76422SRudolf Cornelissen if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b); 47608705d96Sshatty } 47708705d96Sshatty 47808705d96Sshatty /* Put the display into one of the Display Power Management modes. */ 479bfecd0cdSRudolf Cornelissen status_t SET_DPMS_MODE(uint32 dpms_flags) 480bfecd0cdSRudolf Cornelissen { 48120603b95SRudolf Cornelissen bool display, h1h, h1v, h2h, h2v; 48220603b95SRudolf Cornelissen 48308705d96Sshatty interrupt_enable(false); 48408705d96Sshatty 48508705d96Sshatty LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags)); 48608705d96Sshatty 487bfecd0cdSRudolf Cornelissen /* note current DPMS state for our reference */ 488bfecd0cdSRudolf Cornelissen si->dpms_flags = dpms_flags; 489bfecd0cdSRudolf Cornelissen 49020603b95SRudolf Cornelissen /* determine signals to send to head(s) */ 49120603b95SRudolf Cornelissen display = h1h = h1v = h2h = h2v = true; 49208705d96Sshatty switch(dpms_flags) 49308705d96Sshatty { 49408705d96Sshatty case B_DPMS_ON: /* H: on, V: on, display on */ 49508705d96Sshatty break; 49608705d96Sshatty case B_DPMS_STAND_BY: 49720603b95SRudolf Cornelissen display = h1h = h2h = false; 49808705d96Sshatty break; 49908705d96Sshatty case B_DPMS_SUSPEND: 50020603b95SRudolf Cornelissen display = h1v = h2v = false; 50108705d96Sshatty break; 50208705d96Sshatty case B_DPMS_OFF: /* H: off, V: off, display off */ 50320603b95SRudolf Cornelissen display = h1h = h1v = h2h = h2v = false; 50408705d96Sshatty break; 50508705d96Sshatty default: 50608705d96Sshatty LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); 50708705d96Sshatty interrupt_enable(true); 50808705d96Sshatty return B_ERROR; 50908705d96Sshatty } 51020603b95SRudolf Cornelissen 51120603b95SRudolf Cornelissen /* CRTC used for TVout needs specific DPMS programming */ 51220603b95SRudolf Cornelissen if (si->dm.flags & TV_BITS) 51308705d96Sshatty { 514a658603aSRudolf Cornelissen if (si->dm.flags & TV_PRIMARY) 515a658603aSRudolf Cornelissen { 516a658603aSRudolf Cornelissen LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n")); 51720603b95SRudolf Cornelissen 51820603b95SRudolf Cornelissen if (!(si->settings.vga_on_tv)) 51908705d96Sshatty { 52020603b95SRudolf Cornelissen /* block VGA output on head displaying on TV */ 52120603b95SRudolf Cornelissen /* Note: 52220603b95SRudolf Cornelissen * this specific sync setting is required: Vsync is used to keep TVout 52320603b95SRudolf Cornelissen * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs). 52420603b95SRudolf Cornelissen * This leaves Hsync only for shutting off the VGA screen. */ 52520603b95SRudolf Cornelissen h1h = false; 52620603b95SRudolf Cornelissen h1v = true; 52720603b95SRudolf Cornelissen } 52820603b95SRudolf Cornelissen else 52920603b95SRudolf Cornelissen { 53020603b95SRudolf Cornelissen /* when concurrent VGA is used alongside TVout on a head, DPMS is safest 53120603b95SRudolf Cornelissen * applied this way: Vsync is needed for stopping TVout successfully when 53220603b95SRudolf Cornelissen * a (new) modeswitch occurs. 53320603b95SRudolf Cornelissen * (see routine BT_stop_tvout() in nv_brooktreetv.c) */ 53420603b95SRudolf Cornelissen /* Note: 53520603b95SRudolf Cornelissen * applying 'normal' DPMS here and forcing Vsync on in the above mentioned 53620603b95SRudolf Cornelissen * routine seems to not always be enough: sometimes image generation will 53720603b95SRudolf Cornelissen * not resume in that case. */ 53820603b95SRudolf Cornelissen h1h = display; 53920603b95SRudolf Cornelissen h1v = true; 54008705d96Sshatty } 54108705d96Sshatty } 542a658603aSRudolf Cornelissen else 543a658603aSRudolf Cornelissen { 544a658603aSRudolf Cornelissen LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n")); 545a658603aSRudolf Cornelissen 546a658603aSRudolf Cornelissen if (!(si->settings.vga_on_tv)) 547a658603aSRudolf Cornelissen { 548a658603aSRudolf Cornelissen /* block VGA output on head displaying on TV */ 549a658603aSRudolf Cornelissen /* Note: 550a658603aSRudolf Cornelissen * this specific sync setting is required: Vsync is used to keep TVout 551a658603aSRudolf Cornelissen * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs). 552a658603aSRudolf Cornelissen * This leaves Hsync only for shutting off the VGA screen. */ 553a658603aSRudolf Cornelissen h2h = false; 554a658603aSRudolf Cornelissen h2v = true; 555a658603aSRudolf Cornelissen } 556a658603aSRudolf Cornelissen else 557a658603aSRudolf Cornelissen { 558a658603aSRudolf Cornelissen /* when concurrent VGA is used alongside TVout on a head, DPMS is safest 559a658603aSRudolf Cornelissen * applied this way: Vsync is needed for stopping TVout successfully when 560a658603aSRudolf Cornelissen * a (new) modeswitch occurs. 561a658603aSRudolf Cornelissen * (see routine BT_stop_tvout() in nv_brooktreetv.c) */ 562a658603aSRudolf Cornelissen /* Note: 563a658603aSRudolf Cornelissen * applying 'normal' DPMS here and forcing Vsync on in the above mentioned 564a658603aSRudolf Cornelissen * routine seems to not always be enough: sometimes image generation will 565a658603aSRudolf Cornelissen * not resume in that case. */ 566a658603aSRudolf Cornelissen h2h = display; 567a658603aSRudolf Cornelissen h2v = true; 568a658603aSRudolf Cornelissen } 569a658603aSRudolf Cornelissen } 570a658603aSRudolf Cornelissen } 5713aa21459SRudolf Cornelissen 57220603b95SRudolf Cornelissen /* issue actual DPMS commands as far as applicable */ 57320603b95SRudolf Cornelissen head1_dpms(display, h1h, h1v); 57420603b95SRudolf Cornelissen if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS)) 57520603b95SRudolf Cornelissen head2_dpms(display, h2h, h2v); 57620603b95SRudolf Cornelissen if (si->dm.flags & TV_BITS) 57720603b95SRudolf Cornelissen BT_dpms(display); 57820603b95SRudolf Cornelissen 57908705d96Sshatty interrupt_enable(true); 58008705d96Sshatty return B_OK; 58108705d96Sshatty } 58208705d96Sshatty 58308705d96Sshatty /* Report device DPMS capabilities */ 58420603b95SRudolf Cornelissen uint32 DPMS_CAPABILITIES(void) 58520603b95SRudolf Cornelissen { 58608705d96Sshatty return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF); 58708705d96Sshatty } 58808705d96Sshatty 58908705d96Sshatty /* Return the current DPMS mode */ 590bfecd0cdSRudolf Cornelissen uint32 DPMS_MODE(void) 591bfecd0cdSRudolf Cornelissen { 592bfecd0cdSRudolf Cornelissen return si->dpms_flags; 59308705d96Sshatty } 594