vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon / dpms.c
blob598acde4d1c70b02d821e7bfe69667ec8e7c8cb4
1 /*
2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
7 Display Power Management (DPMS) support
8 */
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"
22 // public function: set DPMS mode
23 status_t SET_DPMS_MODE(uint32 dpms_flags)
25 virtual_card *vc = ai->vc;
26 status_t
27 result1 = B_OK,
28 result2 = B_OK;
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 )
36 return B_OK;
37 else
38 return B_ERROR;
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
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;
73 case B_DPMS_STAND_BY:
74 case B_DPMS_SUSPEND:
75 case B_DPMS_OFF: {
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 );
89 break; }
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)
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;
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)
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);
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);
140 break;
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;
152 switch( mode ) {
153 case B_DPMS_ON:
154 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS );
155 break;
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;
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;
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;
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);
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;
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;
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);
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;
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;
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 );
283 } else {
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
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;
306 if( crtc_idx == 0 )
307 Radeon_SetDPMS_CRTC1( ai, mode );
308 else
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 );
336 return B_OK;
340 // get DPMS mode of first port
341 static uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di )
343 uint32 tmp;
345 tmp = INREG( di->regs, RADEON_CRTC_EXT_CNTL );
347 if( (tmp & RADEON_CRTC_DISPLAY_DIS) == 0 )
348 return B_DPMS_ON;
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;
356 return B_DPMS_OFF;
360 // get DPMS mode of second port
361 static uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di )
363 uint32 tmp;
365 tmp = INREG( di->regs, RADEON_CRTC2_GEN_CNTL );
367 if( (tmp & RADEON_CRTC2_DISP_DIS) == 0 )
368 return B_DPMS_ON;
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;
376 return B_DPMS_OFF;
380 // get DPMS mode of one port
381 uint32 Radeon_GetDPMS( accelerator_info *ai, int crtc_idx )
383 if( crtc_idx == 0 )
384 return Radeon_GetDPMS_CRTC1( ai );
385 else
386 return Radeon_GetDPMS_CRTC2( ai );