2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
10 #include "radeon_accelerant.h"
13 #include "memcntrl_regs.h"
17 #include "pll_access.h"
20 void Radeon_ReadRMXRegisters(
21 accelerator_info
*ai
, fp_regs
*values
)
23 vuint8
*regs
= ai
->regs
;
25 values
->fp_horz_stretch
= INREG( regs
, RADEON_FP_HORZ_STRETCH
);
26 values
->fp_vert_stretch
= INREG( regs
, RADEON_FP_VERT_STRETCH
);
29 void Radeon_CalcRMXRegisters(
30 fp_info
*flatpanel
, display_mode
*mode
, bool use_rmx
, fp_regs
*values
)
32 uint xres
= mode
->timing
.h_display
;
33 uint yres
= mode
->timing
.v_display
;
34 uint64 Hratio
, Vratio
;
37 // disable RMX unit if requested
38 values
->fp_horz_stretch
&=
39 ~(RADEON_HORZ_STRETCH_BLEND
|
40 RADEON_HORZ_STRETCH_ENABLE
);
42 values
->fp_vert_stretch
&=
43 ~(RADEON_VERT_STRETCH_ENABLE
|
44 RADEON_VERT_STRETCH_BLEND
);
49 // RMX unit can only upscale, not downscale
50 if( xres
> flatpanel
->panel_xres
)
51 xres
= flatpanel
->panel_xres
;
52 if( yres
> flatpanel
->panel_yres
)
53 yres
= flatpanel
->panel_yres
;
55 Hratio
= FIX_SCALE
* (uint32
)xres
/ flatpanel
->panel_xres
;
56 Vratio
= FIX_SCALE
* (uint32
)yres
/ flatpanel
->panel_yres
;
58 // save it for overlay unit (overlays must be vertically scaled manually)
59 flatpanel
->h_ratio
= Hratio
;
60 flatpanel
->v_ratio
= Vratio
;
62 values
->fp_horz_stretch
= flatpanel
->panel_xres
<< RADEON_HORZ_PANEL_SIZE_SHIFT
;
64 if( Hratio
== FIX_SCALE
) {
65 values
->fp_horz_stretch
&=
66 ~(RADEON_HORZ_STRETCH_BLEND
|
67 RADEON_HORZ_STRETCH_ENABLE
);
71 stretch
= (uint32
)((Hratio
* RADEON_HORZ_STRETCH_RATIO_MAX
+
72 FIX_SCALE
/ 2) >> FIX_SHIFT
) & RADEON_HORZ_STRETCH_RATIO_MASK
;
74 values
->fp_horz_stretch
= stretch
75 | (values
->fp_horz_stretch
& (RADEON_HORZ_PANEL_SIZE
|
76 RADEON_HORZ_FP_LOOP_STRETCH
|
77 RADEON_HORZ_AUTO_RATIO_INC
));
78 values
->fp_horz_stretch
|=
79 RADEON_HORZ_STRETCH_BLEND
|
80 RADEON_HORZ_STRETCH_ENABLE
;
82 values
->fp_horz_stretch
&= ~RADEON_HORZ_AUTO_RATIO
;
84 values
->fp_vert_stretch
= flatpanel
->panel_yres
<< RADEON_VERT_PANEL_SIZE_SHIFT
;
86 if( Vratio
== FIX_SCALE
) {
87 values
->fp_vert_stretch
&=
88 ~(RADEON_VERT_STRETCH_ENABLE
|
89 RADEON_VERT_STRETCH_BLEND
);
93 stretch
= (uint32
)((Vratio
* RADEON_VERT_STRETCH_RATIO_MAX
+
94 FIX_SCALE
/ 2) >> FIX_SHIFT
) & RADEON_VERT_STRETCH_RATIO_MASK
;
96 values
->fp_vert_stretch
= stretch
97 | (values
->fp_vert_stretch
& (RADEON_VERT_PANEL_SIZE
|
98 RADEON_VERT_STRETCH_RESERVED
));
99 values
->fp_vert_stretch
|=
100 RADEON_VERT_STRETCH_ENABLE
|
101 RADEON_VERT_STRETCH_BLEND
;
103 values
->fp_vert_stretch
&= ~RADEON_VERT_AUTO_RATIO_EN
;
106 // write RMX registers
107 void Radeon_ProgramRMXRegisters(
108 accelerator_info
*ai
, fp_regs
*values
)
110 vuint8
*regs
= ai
->regs
;
112 OUTREG( regs
, RADEON_FP_HORZ_STRETCH
, values
->fp_horz_stretch
);
113 OUTREG( regs
, RADEON_FP_VERT_STRETCH
, values
->fp_vert_stretch
);
117 void Radeon_ReadFPRegisters(
118 accelerator_info
*ai
, fp_regs
*values
)
120 vuint8
*regs
= ai
->regs
;
122 values
->fp_gen_cntl
= INREG( regs
, RADEON_FP_GEN_CNTL
);
123 values
->fp2_gen_cntl
= INREG( regs
, RADEON_FP2_GEN_CNTL
);
124 values
->lvds_gen_cntl
= INREG( regs
, RADEON_LVDS_GEN_CNTL
);
125 values
->tmds_pll_cntl
= INREG( regs
, RADEON_TMDS_PLL_CNTL
);
126 values
->tmds_trans_cntl
= INREG( regs
, RADEON_TMDS_TRANSMITTER_CNTL
);
127 values
->fp_h_sync_strt_wid
= INREG( regs
, RADEON_FP_H_SYNC_STRT_WID
);
128 values
->fp_v_sync_strt_wid
= INREG( regs
, RADEON_FP_V_SYNC_STRT_WID
);
129 values
->fp2_h_sync_strt_wid
= INREG( regs
, RADEON_FP_H2_SYNC_STRT_WID
);
130 values
->fp2_v_sync_strt_wid
= INREG( regs
, RADEON_FP_V2_SYNC_STRT_WID
);
131 values
->bios_4_scratch
= INREG( regs
, RADEON_BIOS_4_SCRATCH
);
132 values
->bios_5_scratch
= INREG( regs
, RADEON_BIOS_5_SCRATCH
);
133 values
->bios_6_scratch
= INREG( regs
, RADEON_BIOS_6_SCRATCH
);
135 if (ai
->si
->asic
== rt_rv280
) {
136 // bit 22 of TMDS_PLL_CNTL is read-back inverted
137 values
->tmds_pll_cntl
^= (1 << 22);
140 SHOW_FLOW( 2, "before: fp_gen_cntl=%08lx, horz=%08lx, vert=%08lx, lvds_gen_cntl=%08lx",
141 values
->fp_gen_cntl
, values
->fp_horz_stretch
, values
->fp_vert_stretch
,
142 values
->lvds_gen_cntl
);
145 // calculcate flat panel crtc registers;
146 // must be called after normal CRTC registers are determined
147 void Radeon_CalcFPRegisters(
148 accelerator_info
*ai
, crtc_info
*crtc
,
149 fp_info
*fp_port
, crtc_regs
*crtc_values
, fp_regs
*values
)
152 uint32 tmp
= values
->tmds_pll_cntl
& 0xfffff;
154 // setup synchronization position
155 // (most values are ignored according to fp_gen_cntl, but at least polarity
156 // and pixel precise horizontal sync position are always used)
157 if( fp_port
->is_fp2
) {
158 SHOW_FLOW0( 2, "is_fp2" );
159 values
->fp2_h_sync_strt_wid
= crtc_values
->crtc_h_sync_strt_wid
;
160 values
->fp2_v_sync_strt_wid
= crtc_values
->crtc_v_sync_strt_wid
;
162 SHOW_FLOW0( 2, "fp1" );
163 values
->fp_h_sync_strt_wid
= crtc_values
->crtc_h_sync_strt_wid
;
164 values
->fp_v_sync_strt_wid
= crtc_values
->crtc_v_sync_strt_wid
;
167 if( fp_port
->is_fp2
) {
168 // should retain POST values (esp bit 28)
169 values
->fp2_gen_cntl
&= (0xFFFF0000);
172 // setup magic CRTC shadowing
173 values
->fp_gen_cntl
&=
174 ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN
|
175 RADEON_FP_DFP_SYNC_SEL
|
176 RADEON_FP_CRT_SYNC_SEL
|
177 RADEON_FP_CRTC_LOCK_8DOT
|
178 RADEON_FP_USE_SHADOW_EN
|
179 RADEON_FP_CRTC_USE_SHADOW_VEND
|
180 RADEON_FP_CRT_SYNC_ALT
);
181 values
->fp_gen_cntl
|=
182 RADEON_FP_CRTC_DONT_SHADOW_VPAR
|
183 RADEON_FP_CRTC_DONT_SHADOW_HEND
;
186 for (i
= 0; i
< 4; i
++) {
187 if (ai
->si
->tmds_pll
[i
].freq
== 0)
189 if ((uint32
)(fp_port
->dot_clock
) < ai
->si
->tmds_pll
[i
].freq
) {
190 tmp
= ai
->si
->tmds_pll
[i
].value
;
195 if (IS_R300_VARIANT
|| (ai
->si
->asic
== rt_rv280
)) {
196 if (tmp
& 0xfff00000) {
197 values
->tmds_pll_cntl
= tmp
;
199 values
->tmds_pll_cntl
= ai
->si
->tmds_pll_cntl
& 0xfff00000;
200 values
->tmds_pll_cntl
|= tmp
;
203 values
->tmds_pll_cntl
= tmp
;
206 values
->tmds_trans_cntl
= ai
->si
->tmds_transmitter_cntl
207 & ~(RADEON_TMDS_TRANSMITTER_PLLRST
);
209 if (IS_R300_VARIANT
|| (ai
->si
->asic
== rt_r200
) || (ai
->si
->num_crtc
== 1))
210 values
->tmds_trans_cntl
&= ~(RADEON_TMDS_TRANSMITTER_PLLEN
);
211 else // weird, RV chips got this bit reversed?
212 values
->tmds_trans_cntl
|= (RADEON_TMDS_TRANSMITTER_PLLEN
);
215 // enable proper transmitter
216 if( (crtc
->chosen_displays
& dd_lvds
) != 0 ) {
217 // using LVDS means there cannot be a DVI monitor
218 SHOW_FLOW0( 2, "lvds" );
219 values
->lvds_gen_cntl
|= (RADEON_LVDS_ON
| RADEON_LVDS_BLON
);
220 values
->fp_gen_cntl
&= ~(RADEON_FP_FPON
| RADEON_FP_TMDS_EN
);
222 } else if( !fp_port
->is_fp2
) {
223 // DVI on internal transmitter
224 SHOW_FLOW0( 2, "DVI INT" );
225 values
->fp_gen_cntl
|= RADEON_FP_FPON
| RADEON_FP_TMDS_EN
;
226 // enabling 8 bit data may be dangerous; BIOS should have taken care of that
227 values
->fp_gen_cntl
|= RADEON_FP_PANEL_FORMAT
;
230 // DVI on external transmitter
231 SHOW_FLOW0( 2, "DVI EXT" );
232 values
->fp2_gen_cntl
|= RADEON_FP2_FPON
| RADEON_FP_PANEL_FORMAT
;
233 values
->fp2_gen_cntl
&= ~RADEON_FP2_BLANK_EN
;
235 //hack in missing bits test...
236 //values->fp2_gen_cntl |= (1 << 22) | (1 << 28);
238 if( ai
->si
->asic
>= rt_r200
)
239 values
->fp2_gen_cntl
|= RADEON_FP2_DV0_EN
;
242 SHOW_FLOW( 2, "after: fp_gen_cntl=%08lx, fp2_gen_cntl=%08lx, horz=%08lx, vert=%08lx, lvds_gen_cntl=%08lx",
243 values
->fp_gen_cntl
, values
->fp2_gen_cntl
, values
->fp_horz_stretch
, values
->fp_vert_stretch
,
244 values
->lvds_gen_cntl
);
248 // write flat panel registers
249 void Radeon_ProgramFPRegisters(
250 accelerator_info
*ai
, crtc_info
*crtc
,
251 fp_info
*fp_port
, fp_regs
*values
)
253 shared_info
*si
= ai
->si
;
254 vuint8
*regs
= ai
->regs
;
258 OUTREGP( regs
, RADEON_FP_GEN_CNTL
, values
->fp_gen_cntl
, RADEON_FP_SEL_CRTC2
);
260 if( fp_port
->is_fp2
) {
261 SHOW_FLOW0( 2, "is_fp2" );
262 OUTREGP( regs
, RADEON_FP2_GEN_CNTL
, values
->fp2_gen_cntl
,
263 ~(RADEON_FP2_SOURCE_SEL_MASK
| RADEON_FP2_SRC_SEL_MASK
));
264 OUTREGP( regs
, RADEON_FP2_GEN_CNTL
, values
->fp2_gen_cntl
,
265 RADEON_FP2_SOURCE_SEL_CRTC2
| RADEON_FP2_SRC_SEL_CRTC2
);
266 OUTREG( regs
, RADEON_FP_H2_SYNC_STRT_WID
, values
->fp2_h_sync_strt_wid
);
267 OUTREG( regs
, RADEON_FP_V2_SYNC_STRT_WID
, values
->fp2_v_sync_strt_wid
);
269 SHOW_FLOW0( 2, "is_fp1" );
270 OUTREG( regs
, RADEON_FP_H_SYNC_STRT_WID
, values
->fp_h_sync_strt_wid
);
271 OUTREG( regs
, RADEON_FP_V_SYNC_STRT_WID
, values
->fp_v_sync_strt_wid
);
274 // workaround for old AIW Radeon having display buffer underflow
275 // in conjunction with DVI
276 if( si
->asic
== rt_r100
) {
277 OUTREG( regs
, RADEON_GRPH_BUFFER_CNTL
,
278 INREG( regs
, RADEON_GRPH_BUFFER_CNTL
) & ~0x7f0000);
281 if ( ai
->si
->is_mobility
) {
282 OUTREG( regs
, RADEON_BIOS_4_SCRATCH
, values
->bios_4_scratch
);
283 OUTREG( regs
, RADEON_BIOS_5_SCRATCH
, values
->bios_5_scratch
);
284 OUTREG( regs
, RADEON_BIOS_6_SCRATCH
, values
->bios_6_scratch
);
287 if( (crtc
->chosen_displays
& dd_lvds
) != 0 ) {
289 //OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl,
290 // RADEON_LVDS_ON | RADEON_LVDS_BLON );
292 uint32 old_pixclks_cntl
;
295 old_pixclks_cntl
= Radeon_INPLL( ai
->regs
, ai
->si
->asic
, RADEON_PIXCLKS_CNTL
);
297 // ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero
298 if( ai
->si
->is_mobility
|| ai
->si
->is_igp
)
300 if (!(values
->lvds_gen_cntl
& RADEON_LVDS_ON
)) {
301 Radeon_OUTPLLP( ai
->regs
, ai
->si
->asic
, RADEON_PIXCLKS_CNTL
, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb
);
305 // get current state of LCD
306 tmp
= INREG( regs
, RADEON_LVDS_GEN_CNTL
);
308 // if LCD is on, and previous state was on, just write the state directly.
309 if (( tmp
& ( RADEON_LVDS_ON
| RADEON_LVDS_BLON
)) ==
310 ( values
->lvds_gen_cntl
& ( RADEON_LVDS_ON
| RADEON_LVDS_BLON
))) {
311 OUTREG( regs
, RADEON_LVDS_GEN_CNTL
, values
->lvds_gen_cntl
);
313 if ( values
->lvds_gen_cntl
& ( RADEON_LVDS_ON
| RADEON_LVDS_BLON
)) {
314 snooze( ai
->si
->panel_pwr_delay
* 1000 );
315 OUTREG( regs
, RADEON_LVDS_GEN_CNTL
, values
->lvds_gen_cntl
);
318 //turn on backlight, wait for stable before turning on data ???
319 OUTREG( regs
, RADEON_LVDS_GEN_CNTL
, values
->lvds_gen_cntl
| RADEON_LVDS_BLON
);
320 snooze( ai
->si
->panel_pwr_delay
* 1000 );
321 OUTREG( regs
, RADEON_LVDS_GEN_CNTL
, values
->lvds_gen_cntl
);
325 if( ai
->si
->is_mobility
|| ai
->si
->is_igp
) {
326 if (!(values
->lvds_gen_cntl
& RADEON_LVDS_ON
)) {
327 Radeon_OUTPLL( ai
->regs
, ai
->si
->asic
, RADEON_PIXCLKS_CNTL
, old_pixclks_cntl
);