1*08705d96Sshatty 2*08705d96Sshatty /* 3*08705d96Sshatty Copyright 1999, Be Incorporated. All Rights Reserved. 4*08705d96Sshatty This file may be used under the terms of the Be Sample Code License. 5*08705d96Sshatty 6*08705d96Sshatty Other authors: 7*08705d96Sshatty Mark Watson, 8*08705d96Sshatty Apsed, 9*08705d96Sshatty Rudolf Cornelissen 11/2002-7/2003 10*08705d96Sshatty */ 11*08705d96Sshatty 12*08705d96Sshatty #define MODULE_BIT 0x00200000 13*08705d96Sshatty 14*08705d96Sshatty #include "acc_std.h" 15*08705d96Sshatty 16*08705d96Sshatty /* 17*08705d96Sshatty Enable/Disable interrupts. Just a wrapper around the 18*08705d96Sshatty ioctl() to the kernel driver. 19*08705d96Sshatty */ 20*08705d96Sshatty static void interrupt_enable(bool flag) { 21*08705d96Sshatty status_t result; 22*08705d96Sshatty nv_set_bool_state sbs; 23*08705d96Sshatty 24*08705d96Sshatty /* set the magic number so the driver knows we're for real */ 25*08705d96Sshatty sbs.magic = NV_PRIVATE_DATA_MAGIC; 26*08705d96Sshatty sbs.do_it = flag; 27*08705d96Sshatty /* contact driver and get a pointer to the registers and shared data */ 28*08705d96Sshatty result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs)); 29*08705d96Sshatty } 30*08705d96Sshatty 31*08705d96Sshatty /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ 32*08705d96Sshatty status_t SET_DISPLAY_MODE(display_mode *mode_to_set) 33*08705d96Sshatty { 34*08705d96Sshatty /* BOUNDS WARNING: 35*08705d96Sshatty * It's impossible to deviate whatever small amount in a display_mode if the lower 36*08705d96Sshatty * and upper limits are the same! 37*08705d96Sshatty * Besides: 38*08705d96Sshatty * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE 39*08705d96Sshatty * returns B_BAD_VALUE! 40*08705d96Sshatty * Which means PROPOSEMODE should not return that on anything except on 41*08705d96Sshatty * deviations for: 42*08705d96Sshatty * display_mode.virtual_width; 43*08705d96Sshatty * display_mode.virtual_height; 44*08705d96Sshatty * display_mode.timing.h_display; 45*08705d96Sshatty * display_mode.timing.v_display; 46*08705d96Sshatty * So: 47*08705d96Sshatty * We don't use bounds here by making sure bounds and target are the same struct! 48*08705d96Sshatty * (See the call to PROPOSE_DISPLAY_MODE below) */ 49*08705d96Sshatty display_mode /*bounds,*/ target; 50*08705d96Sshatty 51*08705d96Sshatty uint8 colour_depth1 = 32; 52*08705d96Sshatty status_t result; 53*08705d96Sshatty uint32 startadd,startadd_right; 54*08705d96Sshatty // apsed TODO startadd is 19 bits if < g200 55*08705d96Sshatty 56*08705d96Sshatty bool display, h, v; 57*08705d96Sshatty si->switched_crtcs = false; 58*08705d96Sshatty 59*08705d96Sshatty /* Adjust mode to valid one and fail if invalid */ 60*08705d96Sshatty target /*= bounds*/ = *mode_to_set; 61*08705d96Sshatty /* show the mode bits */ 62*08705d96Sshatty LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); 63*08705d96Sshatty LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock)); 64*08705d96Sshatty LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n", 65*08705d96Sshatty target.virtual_width, target.virtual_height)); 66*08705d96Sshatty 67*08705d96Sshatty /* See BOUNDS WARNING above... */ 68*08705d96Sshatty if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; 69*08705d96Sshatty 70*08705d96Sshatty /* if not dualhead capable card clear dualhead flags */ 71*08705d96Sshatty if (!(target.flags & DUALHEAD_CAPABLE)) 72*08705d96Sshatty { 73*08705d96Sshatty target.flags &= ~DUALHEAD_BITS; 74*08705d96Sshatty } 75*08705d96Sshatty /* if not TVout capable card clear TVout flags */ 76*08705d96Sshatty if (!(target.flags & TV_CAPABLE)) 77*08705d96Sshatty { 78*08705d96Sshatty target.flags &= ~TV_BITS; 79*08705d96Sshatty } 80*08705d96Sshatty LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags)); 81*08705d96Sshatty 82*08705d96Sshatty /* disable interrupts using the kernel driver */ 83*08705d96Sshatty interrupt_enable(false); 84*08705d96Sshatty 85*08705d96Sshatty /* find current DPMS state, then turn off screen(s) */ 86*08705d96Sshatty nv_crtc_dpms_fetch(&display, &h, &v); 87*08705d96Sshatty nv_crtc_dpms(false, false, false); 88*08705d96Sshatty // if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0); 89*08705d96Sshatty 90*08705d96Sshatty /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ 91*08705d96Sshatty startadd = si->fbc.frame_buffer - si->framebuffer; 92*08705d96Sshatty 93*08705d96Sshatty /* calculate and set new mode bytes_per_row */ 94*08705d96Sshatty nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row); 95*08705d96Sshatty 96*08705d96Sshatty /*Perform the very long mode switch!*/ 97*08705d96Sshatty if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ 98*08705d96Sshatty { 99*08705d96Sshatty uint8 colour_depth2 = colour_depth1; 100*08705d96Sshatty 101*08705d96Sshatty /* init display mode for secondary head */ 102*08705d96Sshatty display_mode target2 = target; 103*08705d96Sshatty 104*08705d96Sshatty LOG(1,("SETMODE: setting DUALHEAD mode\n")); 105*08705d96Sshatty 106*08705d96Sshatty /* validate flags for secondary TVout */ 107*08705d96Sshatty if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS)) 108*08705d96Sshatty { 109*08705d96Sshatty target.flags &= ~TV_BITS;//still needed for some routines... 110*08705d96Sshatty target2.flags &= ~TV_BITS; 111*08705d96Sshatty LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); 112*08705d96Sshatty } 113*08705d96Sshatty 114*08705d96Sshatty /* set the pixel clock PLL(s) */ 115*08705d96Sshatty LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); 116*08705d96Sshatty if (nv_dac_set_pix_pll(target) == B_ERROR) 117*08705d96Sshatty LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); 118*08705d96Sshatty 119*08705d96Sshatty /* we do not need to set the pixelclock here for a head that's in TVout mode */ 120*08705d96Sshatty if (!(target2.flags & TV_BITS)) 121*08705d96Sshatty { 122*08705d96Sshatty LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); 123*08705d96Sshatty if (nv_maven_set_vid_pll(target2) == B_ERROR) 124*08705d96Sshatty LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n")); 125*08705d96Sshatty } 126*08705d96Sshatty 127*08705d96Sshatty /*set the colour depth for CRTC1 and the DAC */ 128*08705d96Sshatty switch(target.space) 129*08705d96Sshatty { 130*08705d96Sshatty case B_RGB16_LITTLE: 131*08705d96Sshatty colour_depth1 = 16; 132*08705d96Sshatty nv_dac_mode(BPP16, 1.0); 133*08705d96Sshatty nv_crtc_depth(BPP16); 134*08705d96Sshatty break; 135*08705d96Sshatty case B_RGB32_LITTLE: 136*08705d96Sshatty colour_depth1 = 32; 137*08705d96Sshatty nv_dac_mode(BPP32, 1.0); 138*08705d96Sshatty nv_crtc_depth(BPP32); 139*08705d96Sshatty break; 140*08705d96Sshatty } 141*08705d96Sshatty /*set the colour depth for CRTC2 and the MAVEN */ 142*08705d96Sshatty switch(target2.space) 143*08705d96Sshatty { 144*08705d96Sshatty case B_RGB16_LITTLE: 145*08705d96Sshatty colour_depth2 = 16; 146*08705d96Sshatty nv_maven_mode(BPP16, 1.0); 147*08705d96Sshatty g400_crtc2_depth(BPP16); 148*08705d96Sshatty break; 149*08705d96Sshatty case B_RGB32_LITTLE: 150*08705d96Sshatty colour_depth2 = 32; 151*08705d96Sshatty nv_maven_mode(BPP32DIR, 1.0); 152*08705d96Sshatty g400_crtc2_depth(BPP32DIR); 153*08705d96Sshatty break; 154*08705d96Sshatty } 155*08705d96Sshatty 156*08705d96Sshatty /* check if we are doing interlaced TVout mode */ 157*08705d96Sshatty si->interlaced_tv_mode = false; 158*08705d96Sshatty /* if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450)) 159*08705d96Sshatty si->interlaced_tv_mode = true; 160*08705d96Sshatty */ 161*08705d96Sshatty /*set the display(s) pitches*/ 162*08705d96Sshatty nv_crtc_set_display_pitch (); 163*08705d96Sshatty //fixme: seperate for real dualhead modes: 164*08705d96Sshatty //we need a secondary si->fbc! 165*08705d96Sshatty g400_crtc2_set_display_pitch (); 166*08705d96Sshatty 167*08705d96Sshatty /*work out where the "right" screen starts*/ 168*08705d96Sshatty startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3)); 169*08705d96Sshatty 170*08705d96Sshatty /* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */ 171*08705d96Sshatty si->crtc_delay = 44 + 0 * (colour_depth2 == 16); 172*08705d96Sshatty 173*08705d96Sshatty /* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */ 174*08705d96Sshatty /* (extra "blanking" line for MAVEN) */ 175*08705d96Sshatty target2.timing.v_display++; 176*08705d96Sshatty 177*08705d96Sshatty /* set the outputs */ 178*08705d96Sshatty switch (si->ps.card_type) 179*08705d96Sshatty { 180*08705d96Sshatty case NV11: 181*08705d96Sshatty switch (target.flags & DUALHEAD_BITS) 182*08705d96Sshatty { 183*08705d96Sshatty case DUALHEAD_ON: 184*08705d96Sshatty case DUALHEAD_CLONE: 185*08705d96Sshatty nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); 186*08705d96Sshatty si->switched_crtcs = false; 187*08705d96Sshatty break; 188*08705d96Sshatty case DUALHEAD_SWITCH: 189*08705d96Sshatty if (i2c_sec_tv_adapter() == B_OK) 190*08705d96Sshatty { 191*08705d96Sshatty /* Don't switch CRTC's because MAVEN YUV is impossible then, 192*08705d96Sshatty * and primary head output will be limited to 135Mhz pixelclock. */ 193*08705d96Sshatty LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); 194*08705d96Sshatty nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); 195*08705d96Sshatty si->switched_crtcs = true; 196*08705d96Sshatty } 197*08705d96Sshatty else 198*08705d96Sshatty { 199*08705d96Sshatty /* This limits the pixelclocks on both heads to 135Mhz, 200*08705d96Sshatty * but you can use overlay on the other output now. */ 201*08705d96Sshatty LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); 202*08705d96Sshatty nv_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC); 203*08705d96Sshatty si->switched_crtcs = false; 204*08705d96Sshatty /* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */ 205*08705d96Sshatty si->crtc_delay = 17 + 4 * (colour_depth1 == 16); 206*08705d96Sshatty /* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */ 207*08705d96Sshatty /* (extra "blanking" line for MAVEN) */ 208*08705d96Sshatty target.timing.v_display++; 209*08705d96Sshatty target2.timing.v_display--; 210*08705d96Sshatty } 211*08705d96Sshatty break; 212*08705d96Sshatty } 213*08705d96Sshatty break; 214*08705d96Sshatty //fixme: 215*08705d96Sshatty //setup crtc_delay and vertical timing adjust for G450(?)/G550, 216*08705d96Sshatty //and remove the '+1' in crtc2 vertical timing(?) 217*08705d96Sshatty case NV17: 218*08705d96Sshatty if (!si->ps.primary_dvi) 219*08705d96Sshatty /* output connector use is always 'straight-through' */ 220*08705d96Sshatty //fixme: re-evaluate when DVI is setup... 221*08705d96Sshatty { 222*08705d96Sshatty switch (target.flags & DUALHEAD_BITS) 223*08705d96Sshatty { 224*08705d96Sshatty case DUALHEAD_ON: 225*08705d96Sshatty case DUALHEAD_CLONE: 226*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 227*08705d96Sshatty si->switched_crtcs = false; 228*08705d96Sshatty break; 229*08705d96Sshatty case DUALHEAD_SWITCH: 230*08705d96Sshatty if (i2c_sec_tv_adapter() == B_OK) 231*08705d96Sshatty { 232*08705d96Sshatty /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, 233*08705d96Sshatty * and primary head output will be limited to 235Mhz pixelclock. */ 234*08705d96Sshatty LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); 235*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 236*08705d96Sshatty si->switched_crtcs = true; 237*08705d96Sshatty } 238*08705d96Sshatty else 239*08705d96Sshatty { 240*08705d96Sshatty /* This limits the pixelclocks on both heads to 235Mhz, 241*08705d96Sshatty * but you can use overlay on the other output now. */ 242*08705d96Sshatty LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); 243*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1); 244*08705d96Sshatty si->switched_crtcs = false; 245*08705d96Sshatty } 246*08705d96Sshatty break; 247*08705d96Sshatty } 248*08705d96Sshatty } 249*08705d96Sshatty else 250*08705d96Sshatty /* output connector use is cross-linked if no TV cable connected! */ 251*08705d96Sshatty //fixme: re-evaluate when DVI is setup... 252*08705d96Sshatty { 253*08705d96Sshatty switch (target.flags & DUALHEAD_BITS) 254*08705d96Sshatty { 255*08705d96Sshatty case DUALHEAD_ON: 256*08705d96Sshatty case DUALHEAD_CLONE: 257*08705d96Sshatty if (i2c_sec_tv_adapter() == B_OK) 258*08705d96Sshatty { 259*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 260*08705d96Sshatty si->switched_crtcs = false; 261*08705d96Sshatty } 262*08705d96Sshatty else 263*08705d96Sshatty { 264*08705d96Sshatty /* This limits the pixelclocks on both heads to 235Mhz, 265*08705d96Sshatty * but you can use overlay on the other output now. */ 266*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1); 267*08705d96Sshatty si->switched_crtcs = false; 268*08705d96Sshatty } 269*08705d96Sshatty break; 270*08705d96Sshatty case DUALHEAD_SWITCH: 271*08705d96Sshatty if (i2c_sec_tv_adapter() == B_OK) 272*08705d96Sshatty { 273*08705d96Sshatty /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, 274*08705d96Sshatty * and primary head output will be limited to 235Mhz pixelclock. */ 275*08705d96Sshatty LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); 276*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 277*08705d96Sshatty si->switched_crtcs = true; 278*08705d96Sshatty } 279*08705d96Sshatty else 280*08705d96Sshatty { 281*08705d96Sshatty LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); 282*08705d96Sshatty nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 283*08705d96Sshatty si->switched_crtcs = false; 284*08705d96Sshatty } 285*08705d96Sshatty break; 286*08705d96Sshatty } 287*08705d96Sshatty } 288*08705d96Sshatty break; 289*08705d96Sshatty default: 290*08705d96Sshatty break; 291*08705d96Sshatty } 292*08705d96Sshatty 293*08705d96Sshatty if (si->switched_crtcs) 294*08705d96Sshatty { 295*08705d96Sshatty uint32 temp = startadd; 296*08705d96Sshatty startadd = startadd_right; 297*08705d96Sshatty startadd_right = temp; 298*08705d96Sshatty } 299*08705d96Sshatty 300*08705d96Sshatty /*Tell card what memory to display*/ 301*08705d96Sshatty switch (target.flags & DUALHEAD_BITS) 302*08705d96Sshatty { 303*08705d96Sshatty case DUALHEAD_ON: 304*08705d96Sshatty case DUALHEAD_SWITCH: 305*08705d96Sshatty nv_crtc_set_display_start(startadd,colour_depth1); 306*08705d96Sshatty g400_crtc2_set_display_start(startadd_right,colour_depth2); 307*08705d96Sshatty break; 308*08705d96Sshatty case DUALHEAD_CLONE: 309*08705d96Sshatty nv_crtc_set_display_start(startadd,colour_depth1); 310*08705d96Sshatty g400_crtc2_set_display_start(startadd,colour_depth2); 311*08705d96Sshatty break; 312*08705d96Sshatty } 313*08705d96Sshatty 314*08705d96Sshatty /* set the timing */ 315*08705d96Sshatty nv_crtc_set_timing(target); 316*08705d96Sshatty /* we do not need to setup CRTC2 here for a head that's in TVout mode */ 317*08705d96Sshatty if (!(target2.flags & TV_BITS)) result = g400_crtc2_set_timing(target2); 318*08705d96Sshatty 319*08705d96Sshatty /* TVout support: setup CRTC2 and it's pixelclock */ 320*08705d96Sshatty if (si->ps.tvout && (target2.flags & TV_BITS)) 321*08705d96Sshatty { 322*08705d96Sshatty si->crtc_delay += 5; 323*08705d96Sshatty maventv_init(target2); 324*08705d96Sshatty } 325*08705d96Sshatty } 326*08705d96Sshatty else /* single head mode */ 327*08705d96Sshatty { 328*08705d96Sshatty status_t status; 329*08705d96Sshatty int colour_mode = BPP32; 330*08705d96Sshatty 331*08705d96Sshatty switch(target.space) 332*08705d96Sshatty { 333*08705d96Sshatty case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; 334*08705d96Sshatty case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; 335*08705d96Sshatty case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; 336*08705d96Sshatty case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; 337*08705d96Sshatty default: 338*08705d96Sshatty LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); 339*08705d96Sshatty return B_ERROR; 340*08705d96Sshatty } 341*08705d96Sshatty 342*08705d96Sshatty /* set the pixel clock PLL */ 343*08705d96Sshatty status = nv_dac_set_pix_pll(target); 344*08705d96Sshatty 345*08705d96Sshatty if (status==B_ERROR) 346*08705d96Sshatty LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); 347*08705d96Sshatty 348*08705d96Sshatty /* set the colour depth for CRTC1 and the DAC */ 349*08705d96Sshatty /* first set the colordepth */ 350*08705d96Sshatty nv_crtc_depth(colour_mode); 351*08705d96Sshatty /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */ 352*08705d96Sshatty nv_dac_mode(colour_mode,1.0); 353*08705d96Sshatty 354*08705d96Sshatty /* set the display pitch */ 355*08705d96Sshatty nv_crtc_set_display_pitch(); 356*08705d96Sshatty 357*08705d96Sshatty /* tell the card what memory to display */ 358*08705d96Sshatty nv_crtc_set_display_start(startadd,colour_depth1); 359*08705d96Sshatty 360*08705d96Sshatty /* enable primary analog output */ 361*08705d96Sshatty switch (si->ps.card_type) 362*08705d96Sshatty { 363*08705d96Sshatty case NV11: 364*08705d96Sshatty // nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); 365*08705d96Sshatty break; 366*08705d96Sshatty case NV17: 367*08705d96Sshatty // nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 368*08705d96Sshatty // gx50_general_output_select(); 369*08705d96Sshatty break; 370*08705d96Sshatty default: 371*08705d96Sshatty break; 372*08705d96Sshatty } 373*08705d96Sshatty 374*08705d96Sshatty /* set the timing */ 375*08705d96Sshatty nv_crtc_set_timing(target); 376*08705d96Sshatty 377*08705d96Sshatty //fixme: shut-off the videoPLL if it exists... 378*08705d96Sshatty } 379*08705d96Sshatty 380*08705d96Sshatty /* update driver's mode store */ 381*08705d96Sshatty si->dm = target; 382*08705d96Sshatty 383*08705d96Sshatty /* turn screen one on */ 384*08705d96Sshatty nv_crtc_dpms(display, h, v); 385*08705d96Sshatty /* turn screen two on if a dualhead mode is active */ 386*08705d96Sshatty // if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display,h,v); 387*08705d96Sshatty 388*08705d96Sshatty /* set up acceleration for this mode */ 389*08705d96Sshatty si->dm.virtual_height += 1;//for clipping! 390*08705d96Sshatty // nv_acc_init(); 391*08705d96Sshatty si->dm.virtual_height -= 1; 392*08705d96Sshatty 393*08705d96Sshatty /* clear line at bottom of screen (for maven) if dualhead mode */ 394*08705d96Sshatty // nv_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0); 395*08705d96Sshatty 396*08705d96Sshatty MSG(("SETMODE: booted since %f mS\n", system_time()/1000.0)); 397*08705d96Sshatty 398*08705d96Sshatty /* enable interrupts using the kernel driver */ 399*08705d96Sshatty interrupt_enable(true); 400*08705d96Sshatty 401*08705d96Sshatty /* optimize memory-access if needed */ 402*08705d96Sshatty // nv_crtc_mem_priority(colour_depth1); 403*08705d96Sshatty 404*08705d96Sshatty /* Tune RAM CAS-latency if needed. Must be done *here*! */ 405*08705d96Sshatty nv_set_cas_latency(); 406*08705d96Sshatty 407*08705d96Sshatty return B_OK; 408*08705d96Sshatty } 409*08705d96Sshatty 410*08705d96Sshatty /* 411*08705d96Sshatty Set which pixel of the virtual frame buffer will show up in the 412*08705d96Sshatty top left corner of the display device. Used for page-flipping 413*08705d96Sshatty games and virtual desktops. 414*08705d96Sshatty */ 415*08705d96Sshatty status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { 416*08705d96Sshatty uint8 colour_depth; 417*08705d96Sshatty uint32 startadd,startadd_right; 418*08705d96Sshatty 419*08705d96Sshatty LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); 420*08705d96Sshatty 421*08705d96Sshatty /* reset lower bits, don't return an error! */ 422*08705d96Sshatty //fixme: not needed in dualhead on Nvidia??? (pixelprecise panning on sec. head??) 423*08705d96Sshatty if (si->dm.flags & DUALHEAD_BITS) 424*08705d96Sshatty { 425*08705d96Sshatty switch(si->dm.space) 426*08705d96Sshatty { 427*08705d96Sshatty case B_RGB16_LITTLE: 428*08705d96Sshatty colour_depth=16; 429*08705d96Sshatty h_display_start &= ~0x1f; 430*08705d96Sshatty break; 431*08705d96Sshatty case B_RGB32_LITTLE: 432*08705d96Sshatty colour_depth=32; 433*08705d96Sshatty h_display_start &= ~0x0f; 434*08705d96Sshatty break; 435*08705d96Sshatty default: 436*08705d96Sshatty LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space)); 437*08705d96Sshatty return B_ERROR; 438*08705d96Sshatty } 439*08705d96Sshatty } 440*08705d96Sshatty else 441*08705d96Sshatty { 442*08705d96Sshatty /* Nvidia always does pixelprecise panning on primary head */ 443*08705d96Sshatty switch(si->dm.space) 444*08705d96Sshatty { 445*08705d96Sshatty case B_CMAP8: 446*08705d96Sshatty colour_depth=8; 447*08705d96Sshatty // h_display_start &= ~0x07; 448*08705d96Sshatty break; 449*08705d96Sshatty case B_RGB15_LITTLE: case B_RGB16_LITTLE: 450*08705d96Sshatty colour_depth=16; 451*08705d96Sshatty // h_display_start &= ~0x03; 452*08705d96Sshatty break; 453*08705d96Sshatty case B_RGB32_LITTLE: 454*08705d96Sshatty colour_depth=32; 455*08705d96Sshatty // h_display_start &= ~0x01; 456*08705d96Sshatty break; 457*08705d96Sshatty default: 458*08705d96Sshatty return B_ERROR; 459*08705d96Sshatty } 460*08705d96Sshatty } 461*08705d96Sshatty 462*08705d96Sshatty /* do not run past end of display */ 463*08705d96Sshatty switch (si->dm.flags & DUALHEAD_BITS) 464*08705d96Sshatty { 465*08705d96Sshatty case DUALHEAD_ON: 466*08705d96Sshatty case DUALHEAD_SWITCH: 467*08705d96Sshatty if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) 468*08705d96Sshatty return B_ERROR; 469*08705d96Sshatty break; 470*08705d96Sshatty default: 471*08705d96Sshatty if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) 472*08705d96Sshatty return B_ERROR; 473*08705d96Sshatty break; 474*08705d96Sshatty } 475*08705d96Sshatty if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) 476*08705d96Sshatty return B_ERROR; 477*08705d96Sshatty 478*08705d96Sshatty /* everybody remember where we parked... */ 479*08705d96Sshatty si->dm.h_display_start = h_display_start; 480*08705d96Sshatty si->dm.v_display_start = v_display_start; 481*08705d96Sshatty 482*08705d96Sshatty /* actually set the registers */ 483*08705d96Sshatty //fixme: seperate both heads: we need a secondary si->fbc! 484*08705d96Sshatty startadd = v_display_start * si->fbc.bytes_per_row; 485*08705d96Sshatty startadd += h_display_start * (colour_depth >> 3); 486*08705d96Sshatty startadd += si->fbc.frame_buffer - si->framebuffer; 487*08705d96Sshatty startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); 488*08705d96Sshatty 489*08705d96Sshatty /* account for switched CRTC's */ 490*08705d96Sshatty if (si->switched_crtcs) 491*08705d96Sshatty { 492*08705d96Sshatty uint32 temp = startadd; 493*08705d96Sshatty startadd = startadd_right; 494*08705d96Sshatty startadd_right = temp; 495*08705d96Sshatty } 496*08705d96Sshatty 497*08705d96Sshatty interrupt_enable(false); 498*08705d96Sshatty 499*08705d96Sshatty switch (si->dm.flags&DUALHEAD_BITS) 500*08705d96Sshatty { 501*08705d96Sshatty case DUALHEAD_ON: 502*08705d96Sshatty case DUALHEAD_SWITCH: 503*08705d96Sshatty nv_crtc_set_display_start(startadd,colour_depth); 504*08705d96Sshatty g400_crtc2_set_display_start(startadd_right,colour_depth); 505*08705d96Sshatty break; 506*08705d96Sshatty case DUALHEAD_OFF: 507*08705d96Sshatty nv_crtc_set_display_start(startadd,colour_depth); 508*08705d96Sshatty break; 509*08705d96Sshatty case DUALHEAD_CLONE: 510*08705d96Sshatty nv_crtc_set_display_start(startadd,colour_depth); 511*08705d96Sshatty g400_crtc2_set_display_start(startadd,colour_depth); 512*08705d96Sshatty break; 513*08705d96Sshatty } 514*08705d96Sshatty 515*08705d96Sshatty interrupt_enable(true); 516*08705d96Sshatty return B_OK; 517*08705d96Sshatty } 518*08705d96Sshatty 519*08705d96Sshatty /* 520*08705d96Sshatty Set the indexed color palette. 521*08705d96Sshatty */ 522*08705d96Sshatty void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { 523*08705d96Sshatty int i; 524*08705d96Sshatty uint8 *r,*g,*b; 525*08705d96Sshatty 526*08705d96Sshatty /* Protect gamma correction when not in CMAP8 */ 527*08705d96Sshatty if (si->dm.space != B_CMAP8) return; 528*08705d96Sshatty 529*08705d96Sshatty r=si->color_data; 530*08705d96Sshatty g=r+256; 531*08705d96Sshatty b=g+256; 532*08705d96Sshatty 533*08705d96Sshatty i=first; 534*08705d96Sshatty while (count--) 535*08705d96Sshatty { 536*08705d96Sshatty r[i]=*color_data++; 537*08705d96Sshatty g[i]=*color_data++; 538*08705d96Sshatty b[i]=*color_data++; 539*08705d96Sshatty i++; 540*08705d96Sshatty } 541*08705d96Sshatty nv_dac_palette(r,g,b); 542*08705d96Sshatty } 543*08705d96Sshatty 544*08705d96Sshatty 545*08705d96Sshatty /* masks for DPMS control bits */ 546*08705d96Sshatty enum { 547*08705d96Sshatty H_SYNC_OFF = 0x01, 548*08705d96Sshatty V_SYNC_OFF = 0x02, 549*08705d96Sshatty DISPLAY_OFF = 0x04, 550*08705d96Sshatty BITSMASK = (H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF) 551*08705d96Sshatty }; 552*08705d96Sshatty 553*08705d96Sshatty /* Put the display into one of the Display Power Management modes. */ 554*08705d96Sshatty status_t SET_DPMS_MODE(uint32 dpms_flags) { 555*08705d96Sshatty interrupt_enable(false); 556*08705d96Sshatty 557*08705d96Sshatty LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags)); 558*08705d96Sshatty 559*08705d96Sshatty if (si->dm.flags & DUALHEAD_BITS) /*dualhead*/ 560*08705d96Sshatty { 561*08705d96Sshatty switch(dpms_flags) 562*08705d96Sshatty { 563*08705d96Sshatty case B_DPMS_ON: /* H: on, V: on, display on */ 564*08705d96Sshatty nv_crtc_dpms(true, true, true); 565*08705d96Sshatty if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1); 566*08705d96Sshatty break; 567*08705d96Sshatty case B_DPMS_STAND_BY: 568*08705d96Sshatty nv_crtc_dpms(false, false, true); 569*08705d96Sshatty if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1); 570*08705d96Sshatty break; 571*08705d96Sshatty case B_DPMS_SUSPEND: 572*08705d96Sshatty nv_crtc_dpms(false, true, false); 573*08705d96Sshatty if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0); 574*08705d96Sshatty break; 575*08705d96Sshatty case B_DPMS_OFF: /* H: off, V: off, display off */ 576*08705d96Sshatty nv_crtc_dpms(false, false, false); 577*08705d96Sshatty if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0); 578*08705d96Sshatty break; 579*08705d96Sshatty default: 580*08705d96Sshatty LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); 581*08705d96Sshatty interrupt_enable(true); 582*08705d96Sshatty return B_ERROR; 583*08705d96Sshatty } 584*08705d96Sshatty } 585*08705d96Sshatty else /* singlehead */ 586*08705d96Sshatty { 587*08705d96Sshatty switch(dpms_flags) 588*08705d96Sshatty { 589*08705d96Sshatty case B_DPMS_ON: /* H: on, V: on, display on */ 590*08705d96Sshatty nv_crtc_dpms(true, true, true); 591*08705d96Sshatty break; 592*08705d96Sshatty case B_DPMS_STAND_BY: 593*08705d96Sshatty nv_crtc_dpms(false, false, true); 594*08705d96Sshatty break; 595*08705d96Sshatty case B_DPMS_SUSPEND: 596*08705d96Sshatty nv_crtc_dpms(false, true, false); 597*08705d96Sshatty break; 598*08705d96Sshatty case B_DPMS_OFF: /* H: off, V: off, display off */ 599*08705d96Sshatty nv_crtc_dpms(false, false, false); 600*08705d96Sshatty break; 601*08705d96Sshatty default: 602*08705d96Sshatty LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); 603*08705d96Sshatty interrupt_enable(true); 604*08705d96Sshatty return B_ERROR; 605*08705d96Sshatty } 606*08705d96Sshatty } 607*08705d96Sshatty interrupt_enable(true); 608*08705d96Sshatty return B_OK; 609*08705d96Sshatty } 610*08705d96Sshatty 611*08705d96Sshatty /* Report device DPMS capabilities */ 612*08705d96Sshatty uint32 DPMS_CAPABILITIES(void) { 613*08705d96Sshatty return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF); 614*08705d96Sshatty } 615*08705d96Sshatty 616*08705d96Sshatty 617*08705d96Sshatty /* Return the current DPMS mode */ 618*08705d96Sshatty uint32 DPMS_MODE(void) { 619*08705d96Sshatty bool display, h, v; 620*08705d96Sshatty 621*08705d96Sshatty interrupt_enable(false); 622*08705d96Sshatty nv_crtc_dpms_fetch(&display, &h, &v); 623*08705d96Sshatty interrupt_enable(true); 624*08705d96Sshatty 625*08705d96Sshatty if (display && h && v) 626*08705d96Sshatty return B_DPMS_ON; 627*08705d96Sshatty else if(v) 628*08705d96Sshatty return B_DPMS_STAND_BY; 629*08705d96Sshatty else if(h) 630*08705d96Sshatty return B_DPMS_SUSPEND; 631*08705d96Sshatty else 632*08705d96Sshatty return B_DPMS_OFF; 633*08705d96Sshatty } 634