1 /* 2 Copyright (c) 2002-2004, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Display Power Management (DPMS) support 8 */ 9 10 #include "radeon_accelerant.h" 11 #include "mmio.h" 12 #include "crtc_regs.h" 13 #include "fp_regs.h" 14 #include "pll_regs.h" 15 #include "pll_access.h" 16 #include "tv_out_regs.h" 17 #include "theatre_regs.h" 18 #include "GlobalData.h" 19 #include "generic.h" 20 21 22 // public function: set DPMS mode 23 status_t SET_DPMS_MODE(uint32 dpms_flags) 24 { 25 virtual_card *vc = ai->vc; 26 status_t 27 result1 = B_OK, 28 result2 = B_OK; 29 30 if( vc->used_crtc[0] ) 31 result1 = Radeon_SetDPMS( ai, 0, dpms_flags ); 32 if( vc->used_crtc[0] ) 33 result1 = Radeon_SetDPMS( ai, 0, dpms_flags ); 34 35 if( result1 == B_OK && result2 == B_OK ) 36 return B_OK; 37 else 38 return B_ERROR; 39 } 40 41 // public function: report DPMS capabilities 42 uint32 DPMS_CAPABILITIES(void) 43 { 44 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 45 } 46 47 48 // public function: get current DPMS mode 49 uint32 DPMS_MODE(void) 50 { 51 // we just ask the primary virtual head what status it is in 52 return Radeon_GetDPMS( ai, ai->vc->used_crtc[0] ? 0 : 1 ); 53 } 54 55 56 // set DPMS state of LVDS port 57 static void Radeon_SetDPMS_LVDS( accelerator_info *ai, int mode ) 58 { 59 vuint8 *regs = ai->regs; 60 61 // for internal flat panel, switch backlight off too 62 switch( mode ) { 63 case B_DPMS_ON: 64 // on my laptop, the display has problems to wake-up, this 65 // should hopefully cure that 66 // (you get a dark picture first that becomes brighter step by step, 67 // after a couple of seconds you have full brightness again) 68 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON ); 69 //snooze( ai->si->fp_port.panel_pwr_delay * 1000 ); 70 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON | RADEON_LVDS_ON, 71 ~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) ); 72 break; 73 74 case B_DPMS_STAND_BY: 75 case B_DPMS_SUSPEND: 76 case B_DPMS_OFF: { 77 uint32 old_pixclks_cntl; 78 79 old_pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL); 80 81 // ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero 82 if( ai->si->is_mobility || ai->si->is_igp ) 83 Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb ); 84 85 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_DISPLAY_DIS, 86 ~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) ); 87 88 if( ai->si->is_mobility || ai->si->is_igp ) 89 Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, old_pixclks_cntl ); 90 91 break; } 92 } 93 } 94 95 96 // set DPMS state of DVI port 97 static void Radeon_SetDPMS_DVI( accelerator_info *ai, int mode ) 98 { 99 vuint8 *regs = ai->regs; 100 101 // it seems that DPMS doesn't work on DVI, so we disable FP completely 102 // (according to specs this is the official way to handle DVI though DPMS 103 // *should* be supported as well) 104 switch( mode ) { 105 case B_DPMS_ON: 106 OUTREGP( regs, RADEON_FP_GEN_CNTL, RADEON_FP_FPON | RADEON_FP_TMDS_EN, 107 ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); 108 break; 109 case B_DPMS_STAND_BY: 110 case B_DPMS_SUSPEND: 111 case B_DPMS_OFF: 112 OUTREGP( regs, RADEON_FP_GEN_CNTL, 0, ~RADEON_FP_FPON | RADEON_FP_TMDS_EN ); 113 break; 114 } 115 } 116 117 118 // set DPMS state of external DVI port 119 static void Radeon_SetDPMS_FP2( accelerator_info *ai, int mode ) 120 { 121 vuint8 *regs = ai->regs; 122 123 // it seems that DPMS doesn't work on DVI, so we disable FP completely 124 // (according to specs this is the official way to handle DVI though DPMS 125 // *should* be supported as well) 126 switch( mode ) { 127 case B_DPMS_ON: 128 OUTREGP( regs, RADEON_FP2_GEN_CNTL, 129 RADEON_FP_FPON | 130 (ai->si->asic >= rt_r200 ? RADEON_FP2_DV0_EN : 0), 131 ~(RADEON_FP2_BLANK_EN | RADEON_FP2_BLANK_EN) ); 132 break; 133 case B_DPMS_STAND_BY: 134 case B_DPMS_SUSPEND: 135 case B_DPMS_OFF: 136 OUTREGP( regs, RADEON_FP2_GEN_CNTL, 0, ~(RADEON_FP2_BLANK_EN | RADEON_FP2_BLANK_EN) ); 137 break; 138 } 139 } 140 141 142 // set DPMS mode for CRT DAC. 143 // warning: the CRTC-DAC only obbeys this setting if 144 // connected to CRTC1, else it collides with TV-DAC 145 static void Radeon_SetDPMS_CRT( accelerator_info *ai, int mode ) 146 { 147 vuint8 *regs = ai->regs; 148 149 switch( mode ) { 150 case B_DPMS_ON: 151 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS ); 152 break; 153 154 case B_DPMS_STAND_BY: 155 case B_DPMS_SUSPEND: 156 case B_DPMS_OFF: 157 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 158 RADEON_CRTC_DISPLAY_DIS, ~RADEON_CRTC_DISPLAY_DIS ); 159 break; 160 } 161 } 162 163 164 // set DPMS mode for TV-DAC in CRT mode 165 // warning: if the CRT-DAC is connected to CRTC2, it is 166 // affected by this setting too 167 static void Radeon_SetDPMS_TVCRT( accelerator_info *ai, int mode ) 168 { 169 vuint8 *regs = ai->regs; 170 171 switch( mode ) { 172 case B_DPMS_ON: 173 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_DISP_DIS ); 174 break; 175 176 case B_DPMS_STAND_BY: 177 case B_DPMS_SUSPEND: 178 case B_DPMS_OFF: 179 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 180 RADEON_CRTC2_DISP_DIS, ~RADEON_CRTC2_DISP_DIS ); 181 break; 182 } 183 } 184 185 186 // set DPMS mode for first CRTC 187 static void Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode ) 188 { 189 vuint8 *regs = ai->regs; 190 191 uint32 mask = RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_VSYNC_DIS; 192 193 switch( mode ) { 194 case B_DPMS_ON: 195 /* Screen: On; HSync: On, VSync: On */ 196 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~mask ); 197 break; 198 case B_DPMS_STAND_BY: 199 /* Screen: Off; HSync: Off, VSync: On */ 200 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 201 RADEON_CRTC_HSYNC_DIS, ~mask ); 202 break; 203 case B_DPMS_SUSPEND: 204 /* Screen: Off; HSync: On, VSync: Off */ 205 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 206 RADEON_CRTC_VSYNC_DIS, ~mask ); 207 break; 208 case B_DPMS_OFF: 209 /* Screen: Off; HSync: Off, VSync: Off */ 210 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, mask, ~mask ); 211 break; 212 } 213 214 // disable/enable memory requests and cursor 215 switch( mode ) { 216 case B_DPMS_ON: 217 /* Screen: On; HSync: On, VSync: On */ 218 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B ); 219 Radeon_ShowCursor( ai, 0 ); 220 break; 221 case B_DPMS_STAND_BY: 222 case B_DPMS_SUSPEND: 223 case B_DPMS_OFF: 224 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, 225 ~(RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_CUR_EN) ); 226 break; 227 } 228 } 229 230 231 // set DPMS mode of second CRTC 232 static void Radeon_SetDPMS_CRTC2( accelerator_info *ai, int mode ) 233 { 234 vuint8 *regs = ai->regs; 235 236 int mask = RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_VSYNC_DIS; 237 238 switch( mode ) { 239 case B_DPMS_ON: 240 /* Screen: On; HSync: On, VSync: On */ 241 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~mask ); 242 break; 243 case B_DPMS_STAND_BY: 244 /* Screen: Off; HSync: Off, VSync: On */ 245 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 246 RADEON_CRTC2_HSYNC_DIS, ~mask ); 247 break; 248 case B_DPMS_SUSPEND: 249 /* Screen: Off; HSync: On, VSync: Off */ 250 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 251 RADEON_CRTC2_VSYNC_DIS, ~mask ); 252 break; 253 case B_DPMS_OFF: 254 /* Screen: Off; HSync: Off, VSync: Off */ 255 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, mask, ~mask ); 256 break; 257 } 258 259 switch( mode ) { 260 case B_DPMS_ON: 261 /* Screen: On; HSync: On, VSync: On */ 262 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_DISP_REQ_EN_B ); 263 Radeon_ShowCursor( ai, 1 ); 264 break; 265 case B_DPMS_STAND_BY: 266 case B_DPMS_SUSPEND: 267 case B_DPMS_OFF: 268 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_REQ_EN_B, 269 ~(RADEON_CRTC2_DISP_REQ_EN_B | RADEON_CRTC2_CUR_EN) ); 270 break; 271 } 272 } 273 274 275 // set DPMS mode of TV-out 276 static void Radeon_SetDPMS_TVOUT( accelerator_info *ai, int mode ) 277 { 278 // we set to gain either to 0 for blank or 1 for normal operation 279 if( IS_INTERNAL_TV_OUT( ai->si->tv_chip )) { 280 OUTREG( ai->regs, RADEON_TV_LINEAR_GAIN_SETTINGS, 281 mode == B_DPMS_ON ? 0x01000100 : 0 ); 282 } else { 283 Radeon_VIPWrite( ai, ai->si->theatre_channel, RADEON_TV_LINEAR_GAIN_SETTINGS, 284 mode == B_DPMS_ON ? 0x01000100 : 0 ); 285 } 286 } 287 288 // set DPMS mode of one port 289 // engine lock is assumed to be hold 290 status_t Radeon_SetDPMS( accelerator_info *ai, int crtc_idx, int mode ) 291 { 292 crtc_info *crtc = &ai->si->crtc[crtc_idx]; 293 294 // test validity of mode once and for all 295 switch( mode ) { 296 case B_DPMS_ON: 297 case B_DPMS_STAND_BY: 298 case B_DPMS_SUSPEND: 299 case B_DPMS_OFF: 300 break; 301 default: 302 return B_BAD_VALUE; 303 } 304 305 if( crtc_idx == 0 ) 306 Radeon_SetDPMS_CRTC1( ai, mode ); 307 else 308 Radeon_SetDPMS_CRTC2( ai, mode ); 309 310 // possible ASIC bug: if CRT-DAC is connected to CRTC1, it obbeys 311 // RADEON_CRTC_DISPLAY_DIS; if it is connected to CRTC2, to 312 // RADEON_CRTC2_DISP_DIS - i.e. it follows the CRTC; 313 // but the TV-DAC always listens to RADEON_CRTC2_DISP_DIS, independant 314 // of the CRTC it gets its signal from; 315 // this is a guarantee that two virtual cards will collide! 316 if( crtc_idx == 0 || 1/* && (crtc->active_displays & dd_crt) != 0 */) 317 Radeon_SetDPMS_CRT( ai, mode ); 318 319 if( crtc_idx == 1 || (crtc->active_displays & (dd_tv_crt | dd_ctv | dd_stv)) != 0 ) 320 Radeon_SetDPMS_TVCRT( ai, mode ); 321 322 // TV-Out ignores DPMS completely, including the blank-screen trick 323 if( (crtc->active_displays & (dd_ctv | dd_stv)) != 0 ) 324 Radeon_SetDPMS_TVOUT( ai, mode ); 325 326 if( (crtc->active_displays & dd_lvds) != 0 ) 327 Radeon_SetDPMS_LVDS( ai, mode ); 328 329 if( (crtc->active_displays & dd_dvi) != 0 ) 330 Radeon_SetDPMS_DVI( ai, mode ); 331 332 if( (crtc->active_displays & dd_dvi_ext) != 0 ) 333 Radeon_SetDPMS_FP2( ai, mode ); 334 335 return B_OK; 336 } 337 338 339 // get DPMS mode of first port 340 static uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di ) 341 { 342 uint32 tmp; 343 344 tmp = INREG( di->regs, RADEON_CRTC_EXT_CNTL ); 345 346 if( (tmp & RADEON_CRTC_DISPLAY_DIS) == 0 ) 347 return B_DPMS_ON; 348 349 if( (tmp & RADEON_CRTC_VSYNC_DIS) == 0 ) 350 return B_DPMS_STAND_BY; 351 352 if( (tmp & RADEON_CRTC_HSYNC_DIS) == 0 ) 353 return B_DPMS_SUSPEND; 354 355 return B_DPMS_OFF; 356 } 357 358 359 // get DPMS mode of second port 360 static uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di ) 361 { 362 uint32 tmp; 363 364 tmp = INREG( di->regs, RADEON_CRTC2_GEN_CNTL ); 365 366 if( (tmp & RADEON_CRTC2_DISP_DIS) == 0 ) 367 return B_DPMS_ON; 368 369 if( (tmp & RADEON_CRTC2_VSYNC_DIS) == 0 ) 370 return B_DPMS_STAND_BY; 371 372 if( (tmp & RADEON_CRTC2_HSYNC_DIS) == 0 ) 373 return B_DPMS_SUSPEND; 374 375 return B_DPMS_OFF; 376 } 377 378 379 // get DPMS mode of one port 380 uint32 Radeon_GetDPMS( accelerator_info *ai, int crtc_idx ) 381 { 382 if( crtc_idx == 0 ) 383 return Radeon_GetDPMS_CRTC1( ai ); 384 else 385 return Radeon_GetDPMS_CRTC2( ai ); 386 } 387