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