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->panel_pwr_delay * 1000 ); 70 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON ); 71 break; 72 73 case B_DPMS_STAND_BY: 74 case B_DPMS_SUSPEND: 75 case B_DPMS_OFF: { 76 uint32 old_pixclks_cntl; 77 78 old_pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL); 79 80 // ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero 81 if( ai->si->is_mobility || ai->si->is_igp ) 82 Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb ); 83 84 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, 0, ~(RADEON_LVDS_BLON | RADEON_LVDS_ON) ); 85 86 if( ai->si->is_mobility || ai->si->is_igp ) 87 Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, old_pixclks_cntl ); 88 89 break; } 90 } 91 } 92 93 94 // set DPMS state of DVI port 95 static void Radeon_SetDPMS_DVI( accelerator_info *ai, int mode ) 96 { 97 vuint8 *regs = ai->regs; 98 99 // it seems that DPMS doesn't work on DVI, so we disable FP completely 100 // (according to specs this is the official way to handle DVI though DPMS 101 // *should* be supported as well) 102 switch( mode ) { 103 case B_DPMS_ON: 104 OUTREGP( regs, RADEON_FP_GEN_CNTL, RADEON_FP_FPON | RADEON_FP_TMDS_EN, 105 ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); 106 break; 107 case B_DPMS_STAND_BY: 108 case B_DPMS_SUSPEND: 109 case B_DPMS_OFF: 110 OUTREGP( regs, RADEON_FP_GEN_CNTL, 0, ~RADEON_FP_FPON | RADEON_FP_TMDS_EN ); 111 break; 112 } 113 } 114 115 116 // set DPMS state of external DVI port 117 static void Radeon_SetDPMS_FP2( accelerator_info *ai, int mode ) 118 { 119 vuint8 *regs = ai->regs; 120 121 // it seems that DPMS doesn't work on DVI, so we disable FP completely 122 // (according to specs this is the official way to handle DVI though DPMS 123 // *should* be supported as well) 124 switch( mode ) { 125 case B_DPMS_ON: 126 OUTREGP( regs, RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_BLANK_EN); 127 OUTREGP( regs, RADEON_FP2_GEN_CNTL, RADEON_FP2_FPON, ~RADEON_FP2_FPON); 128 if (ai->si->asic >= rt_r200) { 129 OUTREGP( regs, RADEON_FP2_GEN_CNTL, RADEON_FP2_DV0_EN, ~RADEON_FP2_DV0_EN); 130 } 131 break; 132 case B_DPMS_STAND_BY: 133 case B_DPMS_SUSPEND: 134 case B_DPMS_OFF: 135 OUTREGP( regs, RADEON_FP2_GEN_CNTL, RADEON_FP2_BLANK_EN, ~RADEON_FP2_BLANK_EN ); 136 OUTREGP( regs, RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_FPON); 137 if (ai->si->asic >= rt_r200) { 138 OUTREGP( regs, RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DV0_EN); 139 } 140 break; 141 } 142 } 143 144 145 // set DPMS mode for CRT DAC. 146 // warning: the CRTC-DAC only obbeys this setting if 147 // connected to CRTC1, else it collides with TV-DAC 148 static void Radeon_SetDPMS_CRT( accelerator_info *ai, int mode ) 149 { 150 vuint8 *regs = ai->regs; 151 152 switch( mode ) { 153 case B_DPMS_ON: 154 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS ); 155 break; 156 157 case B_DPMS_STAND_BY: 158 case B_DPMS_SUSPEND: 159 case B_DPMS_OFF: 160 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 161 RADEON_CRTC_DISPLAY_DIS, ~RADEON_CRTC_DISPLAY_DIS ); 162 break; 163 } 164 } 165 166 167 // set DPMS mode for TV-DAC in CRT mode 168 // warning: if the CRT-DAC is connected to CRTC2, it is 169 // affected by this setting too 170 static void Radeon_SetDPMS_TVCRT( accelerator_info *ai, int mode ) 171 { 172 vuint8 *regs = ai->regs; 173 174 switch( mode ) { 175 case B_DPMS_ON: 176 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, 177 ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); 178 break; 179 case B_DPMS_STAND_BY: 180 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), 181 ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); 182 break; 183 case B_DPMS_SUSPEND: 184 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), 185 ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); 186 break; 187 case B_DPMS_OFF: 188 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS), 189 ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); 190 break; 191 } 192 } 193 194 195 // set DPMS mode for first CRTC 196 static void Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode ) 197 { 198 vuint8 *regs = ai->regs; 199 200 uint32 mask = ~(RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); 201 202 switch( mode ) { 203 case B_DPMS_ON: 204 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, mask ); 205 break; 206 case B_DPMS_STAND_BY: 207 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 208 (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS), mask ); 209 break; 210 case B_DPMS_SUSPEND: 211 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 212 (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS), mask ); 213 break; 214 case B_DPMS_OFF: 215 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 216 (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS), mask ); 217 break; 218 } 219 220 // disable/enable memory requests and cursor 221 switch( mode ) { 222 case B_DPMS_ON: 223 /* Screen: On; HSync: On, VSync: On */ 224 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B ); 225 Radeon_ShowCursor( ai, 0 ); 226 break; 227 case B_DPMS_STAND_BY: 228 case B_DPMS_SUSPEND: 229 case B_DPMS_OFF: 230 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, 231 ~(RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_CUR_EN) ); 232 break; 233 } 234 } 235 236 237 // set DPMS mode of second CRTC 238 static void Radeon_SetDPMS_CRTC2( accelerator_info *ai, int mode ) 239 { 240 vuint8 *regs = ai->regs; 241 242 int mask = ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS); 243 244 switch( mode ) { 245 case B_DPMS_ON: 246 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, mask ); 247 break; 248 case B_DPMS_STAND_BY: 249 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), mask ); 250 break; 251 case B_DPMS_SUSPEND: 252 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), mask); 253 break; 254 case B_DPMS_OFF: 255 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 256 (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS), mask); 257 break; 258 } 259 260 switch( mode ) { 261 case B_DPMS_ON: 262 /* Screen: On; HSync: On, VSync: On */ 263 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_DISP_REQ_EN_B ); 264 Radeon_ShowCursor( ai, 1 ); 265 break; 266 case B_DPMS_STAND_BY: 267 case B_DPMS_SUSPEND: 268 case B_DPMS_OFF: 269 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_REQ_EN_B, 270 ~(RADEON_CRTC2_DISP_REQ_EN_B | RADEON_CRTC2_CUR_EN) ); 271 break; 272 } 273 } 274 275 276 // set DPMS mode of TV-out 277 static void Radeon_SetDPMS_TVOUT( accelerator_info *ai, int mode ) 278 { 279 // we set to gain either to 0 for blank or 1 for normal operation 280 if( IS_INTERNAL_TV_OUT( ai->si->tv_chip )) { 281 OUTREG( ai->regs, RADEON_TV_LINEAR_GAIN_SETTINGS, 282 mode == B_DPMS_ON ? 0x01000100 : 0 ); 283 } else { 284 Radeon_VIPWrite( ai, ai->si->theatre_channel, RADEON_TV_LINEAR_GAIN_SETTINGS, 285 mode == B_DPMS_ON ? 0x01000100 : 0 ); 286 } 287 } 288 289 // set DPMS mode of one port 290 // engine lock is assumed to be hold 291 status_t Radeon_SetDPMS( accelerator_info *ai, int crtc_idx, int mode ) 292 { 293 crtc_info *crtc = &ai->si->crtc[crtc_idx]; 294 295 // test validity of mode once and for all 296 switch( mode ) { 297 case B_DPMS_ON: 298 case B_DPMS_STAND_BY: 299 case B_DPMS_SUSPEND: 300 case B_DPMS_OFF: 301 break; 302 default: 303 return B_BAD_VALUE; 304 } 305 306 if( crtc_idx == 0 ) 307 Radeon_SetDPMS_CRTC1( ai, mode ); 308 else 309 Radeon_SetDPMS_CRTC2( ai, mode ); 310 311 // possible ASIC bug: if CRT-DAC is connected to CRTC1, it obbeys 312 // RADEON_CRTC_DISPLAY_DIS; if it is connected to CRTC2, to 313 // RADEON_CRTC2_DISP_DIS - i.e. it follows the CRTC; 314 // but the TV-DAC always listens to RADEON_CRTC2_DISP_DIS, independant 315 // of the CRTC it gets its signal from; 316 // this is a guarantee that two virtual cards will collide! 317 if( crtc_idx == 0 || 1/* && (crtc->active_displays & dd_crt) != 0 */) 318 Radeon_SetDPMS_CRT( ai, mode ); 319 320 if( crtc_idx == 1 || (crtc->active_displays & (dd_tv_crt | dd_ctv | dd_stv)) != 0 ) 321 Radeon_SetDPMS_TVCRT( ai, mode ); 322 323 // TV-Out ignores DPMS completely, including the blank-screen trick 324 if( (crtc->active_displays & (dd_ctv | dd_stv)) != 0 ) 325 Radeon_SetDPMS_TVOUT( ai, mode ); 326 327 if( (crtc->active_displays & dd_lvds) != 0 ) 328 Radeon_SetDPMS_LVDS( ai, mode ); 329 330 if( (crtc->active_displays & dd_dvi) != 0 ) 331 Radeon_SetDPMS_DVI( ai, mode ); 332 333 if( (crtc->active_displays & dd_dvi_ext) != 0 ) 334 Radeon_SetDPMS_FP2( ai, mode ); 335 336 return B_OK; 337 } 338 339 340 // get DPMS mode of first port 341 static uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di ) 342 { 343 uint32 tmp; 344 345 tmp = INREG( di->regs, RADEON_CRTC_EXT_CNTL ); 346 347 if( (tmp & RADEON_CRTC_DISPLAY_DIS) == 0 ) 348 return B_DPMS_ON; 349 350 if( (tmp & RADEON_CRTC_VSYNC_DIS) == 0 ) 351 return B_DPMS_STAND_BY; 352 353 if( (tmp & RADEON_CRTC_HSYNC_DIS) == 0 ) 354 return B_DPMS_SUSPEND; 355 356 return B_DPMS_OFF; 357 } 358 359 360 // get DPMS mode of second port 361 static uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di ) 362 { 363 uint32 tmp; 364 365 tmp = INREG( di->regs, RADEON_CRTC2_GEN_CNTL ); 366 367 if( (tmp & RADEON_CRTC2_DISP_DIS) == 0 ) 368 return B_DPMS_ON; 369 370 if( (tmp & RADEON_CRTC2_VSYNC_DIS) == 0 ) 371 return B_DPMS_STAND_BY; 372 373 if( (tmp & RADEON_CRTC2_HSYNC_DIS) == 0 ) 374 return B_DPMS_SUSPEND; 375 376 return B_DPMS_OFF; 377 } 378 379 380 // get DPMS mode of one port 381 uint32 Radeon_GetDPMS( accelerator_info *ai, int crtc_idx ) 382 { 383 if( crtc_idx == 0 ) 384 return Radeon_GetDPMS_CRTC1( ai ); 385 else 386 return Radeon_GetDPMS_CRTC2( ai ); 387 } 388