2 Copyright (c) 2002-2005, Thomas Kurschel
5 Part of Radeon accelerant
10 #include "radeon_accelerant.h"
12 #include "crtc_regs.h"
13 #include "GlobalData.h"
18 // hammer CRTC registers
19 void Radeon_ProgramCRTCRegisters( accelerator_info
*ai
, int crtc_idx
,
22 vuint8
*regs
= ai
->regs
;
27 OUTREGP( regs
, RADEON_CRTC_GEN_CNTL
, values
->crtc_gen_cntl
,
28 RADEON_CRTC_EXT_DISP_EN
);
30 OUTREG( regs
, RADEON_CRTC_H_TOTAL_DISP
, values
->crtc_h_total_disp
);
31 OUTREG( regs
, RADEON_CRTC_H_SYNC_STRT_WID
, values
->crtc_h_sync_strt_wid
);
32 OUTREG( regs
, RADEON_CRTC_V_TOTAL_DISP
, values
->crtc_v_total_disp
);
33 OUTREG( regs
, RADEON_CRTC_V_SYNC_STRT_WID
, values
->crtc_v_sync_strt_wid
);
34 OUTREG( regs
, RADEON_CRTC_OFFSET_CNTL
, values
->crtc_offset_cntl
);
35 OUTREG( regs
, RADEON_CRTC_PITCH
, values
->crtc_pitch
);
38 OUTREGP( regs
, RADEON_CRTC2_GEN_CNTL
, values
->crtc_gen_cntl
,
39 RADEON_CRTC2_VSYNC_DIS
|
40 RADEON_CRTC2_HSYNC_DIS
|
41 RADEON_CRTC2_DISP_DIS
|
42 RADEON_CRTC2_CRT2_ON
);
44 OUTREG( regs
, RADEON_CRTC2_H_TOTAL_DISP
, values
->crtc_h_total_disp
);
45 OUTREG( regs
, RADEON_CRTC2_H_SYNC_STRT_WID
, values
->crtc_h_sync_strt_wid
);
46 OUTREG( regs
, RADEON_CRTC2_V_TOTAL_DISP
, values
->crtc_v_total_disp
);
47 OUTREG( regs
, RADEON_CRTC2_V_SYNC_STRT_WID
, values
->crtc_v_sync_strt_wid
);
48 OUTREG( regs
, RADEON_CRTC2_OFFSET_CNTL
, values
->crtc_offset_cntl
);
49 OUTREG( regs
, RADEON_CRTC2_PITCH
, values
->crtc_pitch
);
54 // get required hsync delay depending on bit depth and output device
55 uint16
Radeon_GetHSyncFudge( crtc_info
*crtc
, int datatype
)
57 static int hsync_fudge_default
[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
58 static int hsync_fudge_fp
[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 };
60 // there is an sync delay which depends on colour-depth and output device
61 if( (crtc
->chosen_displays
& (dd_dvi
| dd_dvi_ext
| dd_lvds
)) != 0 )
62 return hsync_fudge_fp
[datatype
- 1];
64 return hsync_fudge_default
[datatype
- 1];
68 // calculate CRTC register content
69 void Radeon_CalcCRTCRegisters( accelerator_info
*ai
, crtc_info
*crtc
,
70 display_mode
*mode
, crtc_regs
*values
)
72 virtual_card
*vc
= ai
->vc
;
78 hsync_fudge
= Radeon_GetHSyncFudge( crtc
, vc
->datatype
);
80 if( crtc
->crtc_idx
== 0 ) {
81 // here, we should set interlace/double scan mode
82 // but we don't support them (anyone missing them?)
83 values
->crtc_gen_cntl
=
85 | (vc
->datatype
<< 8);
88 values
->crtc_gen_cntl
= RADEON_CRTC2_EN
90 | (0/*doublescan*/ ? RADEON_CRTC2_DBL_SCAN_EN
: 0)
91 | ((mode
->timing
.flags
& B_TIMING_INTERLACED
)
92 ? RADEON_CRTC2_INTERLACE_EN
: 0);
95 values
->crtc_h_total_disp
=
96 ((mode
->timing
.h_total
/ 8 - 1) & RADEON_CRTC_H_TOTAL
)
97 | (((mode
->timing
.h_display
/ 8 - 1) << RADEON_CRTC_H_DISP_SHIFT
) & RADEON_CRTC_H_DISP
);
99 hsync_wid
= (mode
->timing
.h_sync_end
- mode
->timing
.h_sync_start
) / 8;
101 hsync_start
= mode
->timing
.h_sync_start
- 8 + hsync_fudge
;
103 values
->crtc_h_sync_strt_wid
=
104 (hsync_start
& (RADEON_CRTC_H_SYNC_STRT_CHAR
| RADEON_CRTC_H_SYNC_STRT_PIX
))
105 | (hsync_wid
<< RADEON_CRTC_H_SYNC_WID_SHIFT
)
106 | ((mode
->flags
& B_POSITIVE_HSYNC
) == 0 ? RADEON_CRTC_H_SYNC_POL
: 0);
108 values
->crtc_v_total_disp
=
109 ((mode
->timing
.v_total
- 1) & RADEON_CRTC_V_TOTAL
)
110 | (((mode
->timing
.v_display
- 1) << RADEON_CRTC_V_DISP_SHIFT
) & RADEON_CRTC_V_DISP
);
112 vsync_wid
= mode
->timing
.v_sync_end
- mode
->timing
.v_sync_start
;
114 values
->crtc_v_sync_strt_wid
=
115 ((mode
->timing
.v_sync_start
- 1) & RADEON_CRTC_V_SYNC_STRT
)
116 | (vsync_wid
<< RADEON_CRTC_V_SYNC_WID_SHIFT
)
117 | ((mode
->flags
& B_POSITIVE_VSYNC
) == 0
118 ? RADEON_CRTC_V_SYNC_POL
: 0);
120 values
->crtc_offset_cntl
= 0;
122 values
->crtc_pitch
= Radeon_RoundVWidth( mode
->virtual_width
, vc
->bpp
) / 8;
124 SHOW_FLOW( 2, "crtc_pitch=%ld", values
->crtc_pitch
);
126 values
->crtc_pitch
|= values
->crtc_pitch
<< 16;
130 // update shown are of one port
131 static void moveOneDisplay( accelerator_info
*ai
, crtc_info
*crtc
)
133 virtual_card
*vc
= ai
->vc
;
136 offset
= (vc
->mode
.v_display_start
+ crtc
->rel_y
) * vc
->pitch
+
137 (vc
->mode
.h_display_start
+ crtc
->rel_x
) * vc
->bpp
+
140 SHOW_FLOW( 3, "Setting address %x on port %d",
141 offset
, crtc
->crtc_idx
);
143 OUTREG( ai
->regs
, crtc
->crtc_idx
== 0 ? RADEON_CRTC_OFFSET
: RADEON_CRTC2_OFFSET
, offset
);
146 // internal function: pan display
147 // engine lock should be hold
148 status_t
Radeon_MoveDisplay( accelerator_info
*ai
, uint16 h_display_start
, uint16 v_display_start
)
150 virtual_card
*vc
= ai
->vc
;
152 SHOW_FLOW( 4, "h_display_start=%ld, v_display_start=%ld",
153 h_display_start
, v_display_start
);
155 if( h_display_start
+ vc
->eff_width
> vc
->mode
.virtual_width
||
156 v_display_start
+ vc
->eff_height
> vc
->mode
.virtual_height
)
159 // this is needed both for get_mode_info and for scrolling of virtual screens
160 vc
->mode
.h_display_start
= h_display_start
& ~7;
161 vc
->mode
.v_display_start
= v_display_start
;
164 if( vc
->used_crtc
[0] )
165 moveOneDisplay( ai
, &ai
->si
->crtc
[0] );
166 if( vc
->used_crtc
[1] )
167 moveOneDisplay( ai
, &ai
->si
->crtc
[1] );
169 // overlay position must be adjusted
170 Radeon_UpdateOverlay( ai
);
175 // public function: pan display
176 status_t
MOVE_DISPLAY( uint16 h_display_start
, uint16 v_display_start
)
178 shared_info
*si
= ai
->si
;
181 ACQUIRE_BEN( si
->engine
.lock
);
183 // TBD: we should probably lock card first; in this case, we must
184 // split this function into locking and worker part, as this
185 // function is used internally as well
186 result
= Radeon_MoveDisplay( ai
, h_display_start
, v_display_start
);
188 RELEASE_BEN( si
->engine
.lock
);