2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
7 Display Power Management (DPMS) support
10 #include "radeon_accelerant.h"
12 #include "crtc_regs.h"
15 #include "pll_access.h"
16 #include "tv_out_regs.h"
17 #include "theatre_regs.h"
18 #include "GlobalData.h"
22 // public function: set DPMS mode
23 status_t
SET_DPMS_MODE(uint32 dpms_flags
)
25 virtual_card
*vc
= ai
->vc
;
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
);
35 if( result1
== B_OK
&& result2
== B_OK
)
41 // public function: report DPMS capabilities
42 uint32
DPMS_CAPABILITIES(void)
44 return B_DPMS_ON
| B_DPMS_STAND_BY
| B_DPMS_SUSPEND
| B_DPMS_OFF
;
48 // public function: get current DPMS mode
49 uint32
DPMS_MODE(void)
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 );
56 // set DPMS state of LVDS port
57 static void Radeon_SetDPMS_LVDS( accelerator_info
*ai
, int mode
)
59 vuint8
*regs
= ai
->regs
;
61 // for internal flat panel, switch backlight off too
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
);
76 uint32 old_pixclks_cntl
;
78 old_pixclks_cntl
= Radeon_INPLL( ai
->regs
, ai
->si
->asic
, RADEON_PIXCLKS_CNTL
);
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
);
84 OUTREGP( regs
, RADEON_LVDS_GEN_CNTL
, 0, ~(RADEON_LVDS_BLON
| RADEON_LVDS_ON
) );
86 if( ai
->si
->is_mobility
|| ai
->si
->is_igp
)
87 Radeon_OUTPLL( ai
->regs
, ai
->si
->asic
, RADEON_PIXCLKS_CNTL
, old_pixclks_cntl
);
94 // set DPMS state of DVI port
95 static void Radeon_SetDPMS_DVI( accelerator_info
*ai
, int mode
)
97 vuint8
*regs
= ai
->regs
;
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)
104 OUTREGP( regs
, RADEON_FP_GEN_CNTL
, RADEON_FP_FPON
| RADEON_FP_TMDS_EN
,
105 ~(RADEON_FP_FPON
| RADEON_FP_TMDS_EN
));
107 case B_DPMS_STAND_BY
:
110 OUTREGP( regs
, RADEON_FP_GEN_CNTL
, 0, ~RADEON_FP_FPON
| RADEON_FP_TMDS_EN
);
116 // set DPMS state of external DVI port
117 static void Radeon_SetDPMS_FP2( accelerator_info
*ai
, int mode
)
119 vuint8
*regs
= ai
->regs
;
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)
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
);
132 case B_DPMS_STAND_BY
:
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
);
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
)
150 vuint8
*regs
= ai
->regs
;
154 OUTREGP( regs
, RADEON_CRTC_EXT_CNTL
, 0, ~RADEON_CRTC_DISPLAY_DIS
);
157 case B_DPMS_STAND_BY
:
160 OUTREGP( regs
, RADEON_CRTC_EXT_CNTL
,
161 RADEON_CRTC_DISPLAY_DIS
, ~RADEON_CRTC_DISPLAY_DIS
);
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
)
172 vuint8
*regs
= ai
->regs
;
176 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
, 0,
177 ~(RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_VSYNC_DIS
| RADEON_CRTC2_HSYNC_DIS
) );
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
) );
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
) );
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
) );
195 // set DPMS mode for first CRTC
196 static void Radeon_SetDPMS_CRTC1( accelerator_info
*ai
, int mode
)
198 vuint8
*regs
= ai
->regs
;
200 uint32 mask
= ~(RADEON_CRTC_DISPLAY_DIS
| RADEON_CRTC_VSYNC_DIS
| RADEON_CRTC_HSYNC_DIS
);
204 OUTREGP( regs
, RADEON_CRTC_EXT_CNTL
, 0, mask
);
206 case B_DPMS_STAND_BY
:
207 OUTREGP( regs
, RADEON_CRTC_EXT_CNTL
,
208 (RADEON_CRTC_DISPLAY_DIS
| RADEON_CRTC_HSYNC_DIS
), mask
);
211 OUTREGP( regs
, RADEON_CRTC_EXT_CNTL
,
212 (RADEON_CRTC_DISPLAY_DIS
| RADEON_CRTC_VSYNC_DIS
), mask
);
215 OUTREGP( regs
, RADEON_CRTC_EXT_CNTL
,
216 (RADEON_CRTC_DISPLAY_DIS
| RADEON_CRTC_VSYNC_DIS
| RADEON_CRTC_HSYNC_DIS
), mask
);
220 // disable/enable memory requests and cursor
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 );
227 case B_DPMS_STAND_BY
:
230 OUTREGP( regs
, RADEON_CRTC_GEN_CNTL
, RADEON_CRTC_DISP_REQ_EN_B
,
231 ~(RADEON_CRTC_DISP_REQ_EN_B
| RADEON_CRTC_CUR_EN
) );
237 // set DPMS mode of second CRTC
238 static void Radeon_SetDPMS_CRTC2( accelerator_info
*ai
, int mode
)
240 vuint8
*regs
= ai
->regs
;
242 int mask
= ~(RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_VSYNC_DIS
| RADEON_CRTC2_HSYNC_DIS
);
246 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
, 0, mask
);
248 case B_DPMS_STAND_BY
:
249 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
, (RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_HSYNC_DIS
), mask
);
252 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
, (RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_VSYNC_DIS
), mask
);
255 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
,
256 (RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_VSYNC_DIS
| RADEON_CRTC2_HSYNC_DIS
), mask
);
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 );
266 case B_DPMS_STAND_BY
:
269 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
, RADEON_CRTC2_DISP_REQ_EN_B
,
270 ~(RADEON_CRTC2_DISP_REQ_EN_B
| RADEON_CRTC2_CUR_EN
) );
276 // set DPMS mode of TV-out
277 static void Radeon_SetDPMS_TVOUT( accelerator_info
*ai
, int mode
)
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 );
284 Radeon_VIPWrite( ai
, ai
->si
->theatre_channel
, RADEON_TV_LINEAR_GAIN_SETTINGS
,
285 mode
== B_DPMS_ON
? 0x01000100 : 0 );
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
)
293 crtc_info
*crtc
= &ai
->si
->crtc
[crtc_idx
];
295 // test validity of mode once and for all
298 case B_DPMS_STAND_BY
:
307 Radeon_SetDPMS_CRTC1( ai
, mode
);
309 Radeon_SetDPMS_CRTC2( ai
, mode
);
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
);
320 if( crtc_idx
== 1 || (crtc
->active_displays
& (dd_tv_crt
| dd_ctv
| dd_stv
)) != 0 )
321 Radeon_SetDPMS_TVCRT( ai
, mode
);
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
);
327 if( (crtc
->active_displays
& dd_lvds
) != 0 )
328 Radeon_SetDPMS_LVDS( ai
, mode
);
330 if( (crtc
->active_displays
& dd_dvi
) != 0 )
331 Radeon_SetDPMS_DVI( ai
, mode
);
333 if( (crtc
->active_displays
& dd_dvi_ext
) != 0 )
334 Radeon_SetDPMS_FP2( ai
, mode
);
340 // get DPMS mode of first port
341 static uint32
Radeon_GetDPMS_CRTC1( accelerator_info
*di
)
345 tmp
= INREG( di
->regs
, RADEON_CRTC_EXT_CNTL
);
347 if( (tmp
& RADEON_CRTC_DISPLAY_DIS
) == 0 )
350 if( (tmp
& RADEON_CRTC_VSYNC_DIS
) == 0 )
351 return B_DPMS_STAND_BY
;
353 if( (tmp
& RADEON_CRTC_HSYNC_DIS
) == 0 )
354 return B_DPMS_SUSPEND
;
360 // get DPMS mode of second port
361 static uint32
Radeon_GetDPMS_CRTC2( accelerator_info
*di
)
365 tmp
= INREG( di
->regs
, RADEON_CRTC2_GEN_CNTL
);
367 if( (tmp
& RADEON_CRTC2_DISP_DIS
) == 0 )
370 if( (tmp
& RADEON_CRTC2_VSYNC_DIS
) == 0 )
371 return B_DPMS_STAND_BY
;
373 if( (tmp
& RADEON_CRTC2_HSYNC_DIS
) == 0 )
374 return B_DPMS_SUSPEND
;
380 // get DPMS mode of one port
381 uint32
Radeon_GetDPMS( accelerator_info
*ai
, int crtc_idx
)
384 return Radeon_GetDPMS_CRTC1( ai
);
386 return Radeon_GetDPMS_CRTC2( ai
);