2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
7 Sets display modes, colour palette and handles DPMS
11 #include "GlobalData.h"
13 #include <sys/ioctl.h>
14 #include "radeon_regs.h"
16 #include "crtc_regs.h"
17 #include <GraphicsDefs.h>
19 #include "crtc_regs.h"
20 #include "overlay_regs.h"
21 #include "rbbm_regs.h"
24 #include "gpiopad_regs.h"
27 #include "tv_out_regs.h"
28 #include "config_regs.h"
30 #include "pll_access.h"
31 #include "theatre_regs.h"
39 status_t
Radeon_SetMode(
40 accelerator_info
*ai
, crtc_info
*crtc
, display_mode
*mode
, impactv_params
*tv_params
);
42 // round virtual width up to next valid size
43 uint32
Radeon_RoundVWidth(
44 int virtual_width
, int bpp
)
46 // we have to make both the CRTC and the accelerator happy:
47 // - the CRTC wants virtual width in pixels to be a multiple of 8
48 // - the accelerator expects width in bytes to be a multiple of 64
50 // to put that together, width (in bytes) must be a multiple of the least
51 // common nominator of bytes-per-pixel*8 (CRTC) and 64 (accelerator);
53 // if bytes-per-pixel is a power of two and less than 8, the LCM is 64;
54 // almost all colour depth satisfy that apart from 24 bit; in this case,
55 // the LCM is 64*3=192
57 // after dividing by bytes-per-pixel we get pixels: in first case,
58 // width must be multiple of 64/bytes-per-pixel; in second case,
59 // width must be multiple of 64*3/3=64
62 return (virtual_width
+ 64/bpp
- 1) & ~(64/bpp
- 1);
64 return (virtual_width
+ 63) & ~63;
68 // list of registers that must be reset before display mode switch
69 // to avoid interferences
74 { RADEON_OVR_CLR
, 0 },
75 { RADEON_OVR_WID_LEFT_RIGHT
, 0 },
76 { RADEON_OVR_WID_TOP_BOTTOM
, 0 },
77 { RADEON_OV0_SCALE_CNTL
, 0 }, // disable overlay
78 { RADEON_SUBPIC_CNTL
, 0 },
79 { RADEON_I2C_CNTL_1
, 0 },
83 static void Radeon_InitCommonRegs(
84 accelerator_info
*ai
)
86 vuint8
*regs
= ai
->regs
;
89 for( i
= 0; i
< sizeof( common_regs
) / sizeof( common_regs
[0] ); ++i
)
90 OUTREG( regs
, common_regs
[i
].reg
, common_regs
[i
].val
);
92 // enable extended display modes
93 OUTREGP( regs
, RADEON_CRTC_GEN_CNTL
,
94 RADEON_CRTC_EXT_DISP_EN
, ~RADEON_CRTC_EXT_DISP_EN
);
96 // disable flat panel auto-centering
97 // (if we have a CRT on CRTC1, this must be disabled;
98 // if we have a flat panel on CRTC1, we setup CRTC manually, not
99 // using the auto-centre, automatic-sync-override magic)
100 OUTREG( regs
, RADEON_CRTC_MORE_CNTL
, 0 );
104 // set display mode of one head;
105 // port restrictions, like fixed-sync TFTs connected to it, are taken care of
106 status_t
Radeon_SetMode(
107 accelerator_info
*ai
, crtc_info
*crtc
, display_mode
*mode
, impactv_params
*tv_params
)
109 virtual_card
*vc
= ai
->vc
;
110 shared_info
*si
= ai
->si
;
111 vuint8
*regs
= ai
->regs
;
114 display_device_e disp_devices
;
117 crtc_regs crtc_values
;
120 impactv_regs impactv_values
;
123 bool internal_tv_encoder
;
124 pll_dividers dividers
;
128 // don't destroy passed values, use our copy instead
131 disp_devices
= crtc
->chosen_displays
;
132 fp_info
= &si
->flatpanels
[crtc
->flatpanel_port
];
134 // if using an flat panel or LCD, maximum resolution
135 // is determined by the physical resolution;
136 // also, all timing is fixed
137 if( (disp_devices
& (dd_lvds
| dd_dvi
| dd_dvi_ext
)) != 0 ) {
138 SHOW_FLOW0( 0, "requested resolution higher than native panel" );
139 if( mode
->timing
.h_display
> fp_info
->panel_xres
)
140 mode
->timing
.h_display
= fp_info
->panel_xres
;
141 if( mode
->timing
.v_display
> fp_info
->panel_yres
)
142 mode
->timing
.v_display
= fp_info
->panel_yres
;
144 if( (disp_devices
& dd_dvi_ext
) != 0 ) {
145 SHOW_FLOW0( 0, "requested resolution less than second native panel" );
146 if( mode
->timing
.h_display
< fp_info
->panel_xres
)
147 mode
->timing
.h_display
= fp_info
->panel_xres
;
148 if( mode
->timing
.v_display
< fp_info
->panel_yres
)
149 mode
->timing
.v_display
= fp_info
->panel_yres
;
151 //TODO at this point we know we are going to do centered timing
152 //need to set flags to a. blank the unused memory, b.center screen
153 //for now it's in the top corner, and surrounded by garbage.
154 // although if the DVI panels are the same size and we are cloning
155 // we can switch the FP2 source to RMX, and drive both screens from
158 mode
->timing
.h_total
= mode
->timing
.h_display
+ fp_info
->h_blank
;
159 mode
->timing
.h_sync_start
= mode
->timing
.h_display
+ fp_info
->h_over_plus
;
160 mode
->timing
.h_sync_end
= mode
->timing
.h_sync_start
+ fp_info
->h_sync_width
;
161 mode
->timing
.v_total
= mode
->timing
.v_display
+ fp_info
->v_blank
;
162 mode
->timing
.v_sync_start
= mode
->timing
.v_display
+ fp_info
->v_over_plus
;
163 mode
->timing
.v_sync_end
= mode
->timing
.v_sync_start
+ fp_info
->v_sync_width
;
165 mode
->timing
.pixel_clock
= fp_info
->dot_clock
;
168 // TV-out supports at most 1024x768
169 if( (disp_devices
& (dd_ctv
| dd_stv
)) != 0 ) {
170 if( mode
->timing
.h_display
> 1024 )
171 mode
->timing
.h_display
= 1024;
173 if( mode
->timing
.v_display
> 768 )
174 mode
->timing
.v_display
= 768;
177 // if using TV-Out, the timing of the source signal must be tweaked to
179 internal_tv_encoder
= IS_INTERNAL_TV_OUT( si
->tv_chip
);
181 // we need higher accuracy then Be thought of
182 mode
->timing
.pixel_clock
*= 1000;
184 // TV stuff must be done first as it tweaks the display mode
185 if( (disp_devices
& (dd_ctv
| dd_stv
)) != 0 ) {
186 display_mode tweaked_mode
;
188 Radeon_CalcImpacTVParams(
189 &si
->pll
, tv_params
, vc
->tv_standard
, internal_tv_encoder
,
190 mode
, &tweaked_mode
);
192 *mode
= tweaked_mode
;
195 Radeon_GetFormat( mode
->space
, &format
, &bpp
);
198 vc
->datatype
= format
;
200 // time to read original register content
201 // lock hardware so noone bothers us
202 Radeon_WaitForIdle( ai
, true );
204 if( (disp_devices
& (dd_dvi
| dd_lvds
| dd_dvi_ext
)) != 0 ) {
205 if( crtc
->crtc_idx
== 0 )
206 Radeon_ReadRMXRegisters( ai
, &fp_values
);
208 Radeon_ReadFPRegisters( ai
, &fp_values
);
211 if( (disp_devices
& (dd_ctv
| dd_stv
)) != 0 ) {
212 // some register's content isn't created from scratch but
213 // only modified, so we need the original content first
214 if( internal_tv_encoder
)
215 Radeon_InternalTVOutReadRegisters( ai
, &impactv_values
);
217 Radeon_TheatreReadTVRegisters( ai
, &impactv_values
);
221 // calculate all hardware register values
222 Radeon_CalcCRTCRegisters( ai
, crtc
, mode
, &crtc_values
);
224 surface_cntl
= RADEON_SURF_TRANSLATION_DIS
;
226 if( (disp_devices
& (dd_ctv
| dd_stv
)) != 0 ) {
227 Radeon_CalcImpacTVRegisters( ai
, mode
, tv_params
, &impactv_values
,
228 crtc
->crtc_idx
, internal_tv_encoder
, vc
->tv_standard
, disp_devices
);
231 if( (disp_devices
& (dd_stv
| dd_ctv
)) == 0 )
232 Radeon_CalcCRTPLLDividers( &si
->pll
, mode
, ÷rs
);
234 dividers
= tv_params
->crt_dividers
;
236 if( (disp_devices
& dd_lvds
) != 0 && si
->flatpanels
[0].fixed_dividers
) {
237 SHOW_FLOW0( 0, "Using fixed dividers for laptop panel" );
238 dividers
.feedback
= si
->flatpanels
[0].feedback_div
;
239 dividers
.post_code
= si
->flatpanels
[0].post_div
;
240 dividers
.ref
= si
->flatpanels
[0].ref_div
;
243 Radeon_CalcPLLRegisters( mode
, ÷rs
, &pll_values
);
245 // for first CRTC1, we need to setup RMX properly
246 if( crtc
->crtc_idx
== 0 )
247 Radeon_CalcRMXRegisters( fp_info
, mode
,
248 (disp_devices
& (dd_lvds
| dd_dvi
| dd_dvi_ext
)) != 0,
251 if( (disp_devices
& (dd_lvds
| dd_dvi
| dd_dvi_ext
)) != 0 )
252 Radeon_CalcFPRegisters( ai
, crtc
, fp_info
, &crtc_values
, &fp_values
);
254 // we don't use pixel clock anymore, so it can be reset to Be's kHz
255 mode
->timing
.pixel_clock
/= 1000;
257 // write values to registers
259 Radeon_InitCommonRegs( ai
);
261 Radeon_ProgramCRTCRegisters( ai
, crtc
->crtc_idx
, &crtc_values
);
263 OUTREG( regs
, RADEON_SURFACE_CNTL
, surface_cntl
);
265 if( crtc
->crtc_idx
== 0 )
266 Radeon_ProgramRMXRegisters( ai
, &fp_values
);
268 if( (disp_devices
& (dd_lvds
| dd_dvi
| dd_dvi_ext
)) != 0 )
269 Radeon_ProgramFPRegisters( ai
, crtc
, fp_info
, &fp_values
);
271 //if( mode->timing.pixel_clock )
272 Radeon_ProgramPLL( ai
, crtc
->crtc_idx
, &pll_values
);
274 if( (disp_devices
& (dd_ctv
| dd_stv
)) != 0 ) {
275 if( internal_tv_encoder
)
276 Radeon_InternalTVOutProgramRegisters( ai
, &impactv_values
);
278 Radeon_TheatreProgramTVRegisters( ai
, &impactv_values
);
281 // spit out some debug stuff in a radeontool stylee
283 SHOW_FLOW( 0, "RADEON_DAC_CNTL %08X ", INREG( regs
, RADEON_DAC_CNTL
));
284 SHOW_FLOW( 0, "RADEON_DAC_CNTL2 %08X ", INREG( regs
, RADEON_DAC_CNTL2
));
285 SHOW_FLOW( 0, "RADEON_TV_DAC_CNTL %08X ", INREG( regs
, RADEON_TV_DAC_CNTL
));
286 SHOW_FLOW( 0, "RADEON_DISP_OUTPUT_CNTL %08X ", INREG( regs
, RADEON_DISP_OUTPUT_CNTL
));
287 SHOW_FLOW( 0, "RADEON_AUX_SC_CNTL %08X ", INREG( regs
, RADEON_AUX_SC_CNTL
));
288 SHOW_FLOW( 0, "RADEON_CRTC_EXT_CNTL %08X ", INREG( regs
, RADEON_CRTC_EXT_CNTL
));
289 SHOW_FLOW( 0, "RADEON_CRTC_GEN_CNTL %08X ", INREG( regs
, RADEON_CRTC_GEN_CNTL
));
290 SHOW_FLOW( 0, "RADEON_CRTC2_GEN_CNTL %08X ", INREG( regs
, RADEON_CRTC2_GEN_CNTL
));
291 SHOW_FLOW( 0, "RADEON_DISP_MISC_CNTL %08X ", INREG( regs
, RADEON_DISP_MISC_CNTL
));
292 SHOW_FLOW( 0, "RADEON_FP_GEN_CNTL %08X ", INREG( regs
, RADEON_FP_GEN_CNTL
));
293 SHOW_FLOW( 0, "RADEON_FP2_GEN_CNTL %08X ", INREG( regs
, RADEON_FP2_GEN_CNTL
));
294 SHOW_FLOW( 0, "RADEON_LVDS_GEN_CNTL %08X ", INREG( regs
, RADEON_LVDS_GEN_CNTL
));
295 SHOW_FLOW( 0, "RADEON_TMDS_PLL_CNTL %08X ", INREG( regs
, RADEON_TMDS_PLL_CNTL
));
296 SHOW_FLOW( 0, "RADEON_TMDS_TRANSMITTER_CNTL %08X ", INREG( regs
, RADEON_TMDS_TRANSMITTER_CNTL
));
297 SHOW_FLOW( 0, "RADEON_FP_H_SYNC_STRT_WID %08X ", INREG( regs
, RADEON_FP_H_SYNC_STRT_WID
));
298 SHOW_FLOW( 0, "RADEON_FP_V_SYNC_STRT_WID %08X ", INREG( regs
, RADEON_FP_V_SYNC_STRT_WID
));
299 SHOW_FLOW( 0, "RADEON_FP_H2_SYNC_STRT_WID %08X ", INREG( regs
, RADEON_FP_H2_SYNC_STRT_WID
));
300 SHOW_FLOW( 0, "RADEON_FP_V2_SYNC_STRT_WID %08X ", INREG( regs
, RADEON_FP_V2_SYNC_STRT_WID
));
303 crtc
->active_displays
= disp_devices
;
305 // programming is over, so hardware can be used again
306 RELEASE_BEN( si
->cp
.lock
);
308 // overlay must be setup again after modeswitch (whoever was using it)
309 // TBD: this won't work if another virtual card was using it,
310 // but currently, virtual cards don't work anyway...
311 si
->active_overlay
.crtc_idx
= -1;
317 // enable or disable VBlank interrupts
318 void Radeon_EnableIRQ(
319 accelerator_info
*ai
, bool enable
)
321 shared_info
*si
= ai
->si
;
322 uint32 int_cntl
, int_mask
;
324 int_cntl
= INREG( ai
->regs
, RADEON_GEN_INT_CNTL
);
326 RADEON_CRTC_VBLANK_MASK
327 | (si
->num_crtc
> 1 ? RADEON_CRTC2_VBLANK_MASK
: 0);
330 int_cntl
|= int_mask
;
332 int_cntl
&= ~int_mask
;
334 OUTREG( ai
->regs
, RADEON_GEN_INT_CNTL
, int_cntl
);
337 // on enable, we have to acknowledge all IRQs as the graphics card
338 // waits for that before it issues further IRQs
339 OUTREG( ai
->regs
, RADEON_GEN_INT_STATUS
, int_cntl
);
342 si
->enable_virtual_irq
= enable
;
346 // public function: set display mode
347 status_t
SET_DISPLAY_MODE(
348 display_mode
*mode_in
)
350 virtual_card
*vc
= ai
->vc
;
351 shared_info
*si
= ai
->si
;
352 display_mode bounds
, mode
;
354 mode
= bounds
= *mode_in
;
356 ACQUIRE_BEN( si
->engine
.lock
);
358 SHOW_FLOW( 2, "width=%d, height=%d", mode
.timing
.h_display
, mode
.timing
.v_display
);
360 // check mode and tweak parameters so we can program hardware
361 // without any further checks
362 if( PROPOSE_DISPLAY_MODE( &mode
, &bounds
, &bounds
) == B_ERROR
) {
363 SHOW_ERROR0( 2, "invalid mode" );
365 RELEASE_BEN( si
->engine
.lock
);
369 // already done by propose_display_mode, but it was undone on return;
370 // do this before equality check to recognize changes of multi-monitor mode
371 Radeon_DetectMultiMode( vc
, &mode
);
373 // mode switches can take quite long and are visible,
374 // so avoid them if possible
375 if( memcmp( &mode
, &vc
->mode
, sizeof( display_mode
)) == 0 &&
376 !vc
->enforce_mode_change
) {
377 RELEASE_BEN( si
->engine
.lock
);
381 // this flag was set when some internal parameter has changed that
382 // affects effective display mode
383 vc
->enforce_mode_change
= false;
385 // make sure, we don't get disturbed
386 //Radeon_Finish( ai );
387 Radeon_EnableIRQ( ai
, false );
389 // free cursor and framebuffer memory
393 fm
.magic
= RADEON_PRIVATE_DATA_MAGIC
;
394 fm
.memory_type
= mt_local
;
397 if( vc
->cursor
.mem_handle
) {
398 fm
.handle
= vc
->cursor
.mem_handle
;
399 ioctl( ai
->fd
, RADEON_FREE_MEM
, &fm
);
402 if( vc
->fb_mem_handle
) {
403 fm
.handle
= vc
->fb_mem_handle
;
404 ioctl( ai
->fd
, RADEON_FREE_MEM
, &fm
);
408 memcpy( &vc
->mode
, &mode
, sizeof( display_mode
));
410 // verify hardware restrictions *after* saving mode
411 // e.g. if you want a span mode but have one monitor disconnected,
412 // configuration shouldn't be touched, so you can continue working
413 // with two monitors later on just like nothing has happened
414 Radeon_VerifyMultiMode( vc
, si
, &mode
);
417 vc
->independant_heads
= vc
->assigned_crtc
[0] && si
->crtc
[0].chosen_displays
!= dd_none
;
419 if( si
->num_crtc
> 1 )
420 vc
->independant_heads
+= vc
->assigned_crtc
[1] && si
->crtc
[1].chosen_displays
!= dd_none
;
422 vc
->different_heads
= Radeon_DifferentPorts( &mode
);
423 SHOW_FLOW( 2, "independant heads: %d, different heads: %d",
424 vc
->independant_heads
, vc
->different_heads
);
425 vc
->scroll
= mode
.flags
& B_SCROLL
;
426 SHOW_FLOW( 2, "scrolling %s", vc
->scroll
? "enabled" : "disabled" );
428 // allocate frame buffer and cursor image memory
433 // alloc cursor memory
434 am
.magic
= RADEON_PRIVATE_DATA_MAGIC
;
436 am
.memory_type
= mt_local
;
439 if( ioctl( ai
->fd
, RADEON_ALLOC_MEM
, &am
) == B_OK
) {
440 vc
->cursor
.mem_handle
= am
.handle
;
441 vc
->cursor
.fb_offset
= am
.offset
;
443 // too bad that we are out of mem -> set reasonable values as
444 // it's too late to give up (ouch!)
445 SHOW_ERROR0( 2, "no memory for cursor image!" );
446 vc
->cursor
.mem_handle
= 0;
447 vc
->cursor
.fb_offset
= 0;
450 vc
->cursor
.data
= si
->local_mem
+ vc
->cursor
.fb_offset
;
452 // alloc frame buffer
453 Radeon_GetFormat( mode
.space
, &format
, &bpp
);
454 vc
->pitch
= Radeon_RoundVWidth( mode
.virtual_width
, bpp
) * bpp
;
455 am
.size
= vc
->pitch
* mode
.virtual_height
;
457 if( ioctl( ai
->fd
, RADEON_ALLOC_MEM
, &am
) == B_OK
) {
458 vc
->fb_mem_handle
= am
.handle
;
459 vc
->fb_offset
= am
.offset
;
461 // ouch again - set reasonable values
462 SHOW_ERROR0( 2, "no memory for frame buffer!" );
463 vc
->fb_mem_handle
= 0;
464 vc
->fb_offset
= 1024;
467 vc
->fbc
.frame_buffer
= si
->local_mem
+ vc
->fb_offset
;
468 vc
->fbc
.frame_buffer_dma
= (void *)((uint8
*)si
->framebuffer_pci
+ vc
->fb_offset
);
469 vc
->fbc
.bytes_per_row
= vc
->pitch
;
471 SHOW_FLOW( 0, "frame buffer CPU-address=%x, phys-address=%x",
472 vc
->fbc
.frame_buffer
, vc
->fbc
.frame_buffer_dma
);
475 // multi-screen stuff
476 Radeon_InitMultiModeVars( ai
, &mode
);
481 routing_regs routing_values
;
482 impactv_params tv_params
;
483 status_t err1
, err2
;
486 // we first switch off all output, so the monitor(s) won't get invalid signals
487 if( vc
->assigned_crtc
[0] ) {
488 // overwrite list of active displays to switch off displays
489 // someone else turned on
490 si
->crtc
[0].active_displays
= vc
->controlled_displays
;
491 Radeon_SetDPMS( ai
, 0, B_DPMS_SUSPEND
);
493 if( vc
->assigned_crtc
[1] ) {
494 si
->crtc
[1].active_displays
= vc
->controlled_displays
;
495 Radeon_SetDPMS( ai
, 1, B_DPMS_SUSPEND
);
498 // mark crtc that will be used from now on
499 vc
->used_crtc
[0] = vc
->assigned_crtc
[0] && si
->crtc
[0].chosen_displays
!= dd_none
;
500 vc
->used_crtc
[1] = vc
->assigned_crtc
[1] && si
->crtc
[1].chosen_displays
!= dd_none
;
502 // then change the mode
503 if( vc
->used_crtc
[0] )
504 err1
= Radeon_SetMode( ai
, &si
->crtc
[0], &mode
, &tv_params
);
505 if( vc
->used_crtc
[1] )
506 err2
= Radeon_SetMode( ai
, &si
->crtc
[1], &mode
, &tv_params
);
509 SHOW_FLOW( 2, "SetModes 1=%s, 2=%s",
510 (err1
== B_OK
) ? "OK" : "FAIL", (err2
== B_OK
) ? "OK" : "FAIL");
512 // setup signal routing
513 Radeon_ReadMonitorRoutingRegs( ai
, &routing_values
);
514 Radeon_CalcMonitorRouting( ai
, &tv_params
, &routing_values
);
515 Radeon_ProgramMonitorRouting( ai
, &routing_values
);
517 // finally, switch display(s) on
518 if( vc
->used_crtc
[0] )
519 Radeon_SetDPMS( ai
, 0, (err1
== B_OK
) ? B_DPMS_ON
: B_DPMS_SUSPEND
);
520 if( vc
->used_crtc
[1] )
521 Radeon_SetDPMS( ai
, 1, (err2
== B_OK
) ? B_DPMS_ON
: B_DPMS_SUSPEND
);
523 OUTREGP( ai
->regs
, RADEON_CRTC_EXT_CNTL
, 0, ~RADEON_CRTC_DISPLAY_DIS
);
526 SHOW_FLOW( 3, "pitch=%ld", vc
->pitch
);
528 // we'll modify bits of this reg, so save it for async access
529 si
->dac_cntl2
= INREG( ai
->regs
, RADEON_DAC_CNTL2
);
531 // setup 2D registers
533 // setup position of framebuffer for 2D commands
534 Radeon_FillStateBuffer( ai
, vc
->datatype
);
536 // remember that 2D accelerator is not prepared for any virtual card
539 // first move to well-defined position (to setup CRTC offset)
540 Radeon_MoveDisplay( ai
, 0, 0 );
541 // then to (probably faulty) user-defined pos
542 Radeon_MoveDisplay( ai
, mode
.h_display_start
, mode
.v_display_start
);
544 // set standard palette in direct-colour modes
545 if( vc
->used_crtc
[0] )
546 Radeon_InitPalette( ai
, 0 );
547 if( vc
->used_crtc
[1] )
548 Radeon_InitPalette( ai
, 1 );
550 // initialize cursor data
551 if( vc
->used_crtc
[0] )
552 Radeon_SetCursorColors( ai
, 0 );
553 if( vc
->used_crtc
[1] )
554 Radeon_SetCursorColors( ai
, 1 );
556 // sync should be settled now, so we can reenable IRQs
557 Radeon_EnableIRQ( ai
, true );
559 RELEASE_BEN( si
->engine
.lock
);
561 // !! all this must be done after lock has been
562 // released to avoid dead-lock !!
563 // TBD: any invalid intermediate states?
565 // move_cursor sets all cursor-related variables and registers
566 vc
->cursor
.is_visible
= false;