xref: /haiku/src/add-ons/accelerants/radeon/flat_panel.c (revision 1e36cfc2721ef13a187c6f7354dc9cbc485e89d3)
1 /*
2 	Copyright (c) 2002-2004, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Flat panel support
8 */
9 
10 #include "radeon_accelerant.h"
11 #include "mmio.h"
12 #include "fp_regs.h"
13 #include "memcntrl_regs.h"
14 #include "utils.h"
15 #include "set_mode.h"
16 #include "pll_regs.h"
17 #include "pll_access.h"
18 
19 
20 void Radeon_ReadRMXRegisters(
21 	accelerator_info *ai, fp_regs *values )
22 {
23 	vuint8 *regs = ai->regs;
24 
25 	values->fp_horz_stretch = INREG( regs, RADEON_FP_HORZ_STRETCH );
26 	values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH );
27 }
28 
29 void Radeon_CalcRMXRegisters(
30 	fp_info *flatpanel, display_mode *mode, bool use_rmx, fp_regs *values )
31 {
32 	uint xres = mode->timing.h_display;
33 	uint yres = mode->timing.v_display;
34 	uint64 Hratio, Vratio;
35 
36 	if( !use_rmx ) {
37 		// disable RMX unit if requested
38 		values->fp_horz_stretch &=
39 			~(RADEON_HORZ_STRETCH_BLEND |
40 			  RADEON_HORZ_STRETCH_ENABLE);
41 
42 		values->fp_vert_stretch &=
43 			~(RADEON_VERT_STRETCH_ENABLE |
44 			  RADEON_VERT_STRETCH_BLEND);
45 
46 		return;
47 	}
48 
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;
54 
55 	Hratio = FIX_SCALE * (uint32)xres / flatpanel->panel_xres;
56 	Vratio = FIX_SCALE * (uint32)yres / flatpanel->panel_yres;
57 
58 	// save it for overlay unit (overlays must be vertically scaled manually)
59 	flatpanel->h_ratio = Hratio;
60 	flatpanel->v_ratio = Vratio;
61 
62 	values->fp_horz_stretch = flatpanel->panel_xres << RADEON_HORZ_PANEL_SIZE_SHIFT;
63 
64 	if( Hratio == FIX_SCALE ) {
65 		values->fp_horz_stretch &=
66 			~(RADEON_HORZ_STRETCH_BLEND |
67 			  RADEON_HORZ_STRETCH_ENABLE);
68 	} else {
69 		uint32 stretch;
70 
71 		stretch = (uint32)((Hratio * RADEON_HORZ_STRETCH_RATIO_MAX +
72 			FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_HORZ_STRETCH_RATIO_MASK;
73 
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;
81 	}
82 	values->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO;
83 
84 	values->fp_vert_stretch = flatpanel->panel_yres << RADEON_VERT_PANEL_SIZE_SHIFT;
85 
86 	if( Vratio == FIX_SCALE ) {
87 		values->fp_vert_stretch &=
88 			~(RADEON_VERT_STRETCH_ENABLE |
89 			  RADEON_VERT_STRETCH_BLEND);
90 	} else {
91 		uint32 stretch;
92 
93 		stretch = (uint32)((Vratio * RADEON_VERT_STRETCH_RATIO_MAX +
94 			FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_VERT_STRETCH_RATIO_MASK;
95 
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;
102 	}
103 	values->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN;
104 }
105 
106 // write RMX registers
107 void Radeon_ProgramRMXRegisters(
108 	accelerator_info *ai, fp_regs *values )
109 {
110 	vuint8 *regs = ai->regs;
111 
112 	OUTREG( regs, RADEON_FP_HORZ_STRETCH, values->fp_horz_stretch );
113 	OUTREG( regs, RADEON_FP_VERT_STRETCH, values->fp_vert_stretch );
114 }
115 
116 
117 void Radeon_ReadFPRegisters(
118 	accelerator_info *ai, fp_regs *values )
119 {
120 	vuint8 *regs = ai->regs;
121 
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->fp_h_sync_strt_wid = INREG( regs, RADEON_FP_H_SYNC_STRT_WID );
126 	values->fp_v_sync_strt_wid = INREG( regs, RADEON_FP_V_SYNC_STRT_WID );
127 	values->fp2_h_sync_strt_wid = INREG( regs, RADEON_FP_H2_SYNC_STRT_WID );
128 	values->fp2_v_sync_strt_wid = INREG( regs, RADEON_FP_V2_SYNC_STRT_WID );
129 	values->bios_4_scratch =  INREG( regs, RADEON_BIOS_4_SCRATCH );
130 	values->bios_5_scratch =  INREG( regs, RADEON_BIOS_5_SCRATCH );
131 	values->bios_6_scratch =  INREG( regs, RADEON_BIOS_6_SCRATCH );
132 
133     SHOW_FLOW( 2, "before: fp_gen_cntl=%08lx, horz=%08lx, vert=%08lx, lvds_gen_cntl=%08lx",
134     	values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch,
135     	values->lvds_gen_cntl );
136 }
137 
138 // calculcate flat panel crtc registers;
139 // must be called after normal CRTC registers are determined
140 void Radeon_CalcFPRegisters(
141 	accelerator_info *ai, crtc_info *crtc,
142 	fp_info *fp_port, crtc_regs *crtc_values, fp_regs *values )
143 {
144 	// setup synchronization position
145 	// (most values are ignored according to fp_gen_cntl, but at least polarity
146 	//  and pixel precise horizontal sync position are always used)
147 	if( fp_port->is_fp2 ) {
148 		values->fp2_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid;
149 		values->fp2_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid;
150 	} else {
151 		values->fp_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid;
152 		values->fp_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid;
153 	}
154 
155 	if( fp_port->is_fp2 )
156 		values->fp2_gen_cntl = 0;
157 	else {
158 		// setup magic CRTC shadowing
159 		values->fp_gen_cntl &=
160 			~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
161 			  RADEON_FP_DFP_SYNC_SEL |
162 			  RADEON_FP_CRT_SYNC_SEL |
163 			  RADEON_FP_CRTC_LOCK_8DOT |
164 			  RADEON_FP_USE_SHADOW_EN |
165 			  RADEON_FP_CRTC_USE_SHADOW_VEND |
166 			  RADEON_FP_CRT_SYNC_ALT);
167 		values->fp_gen_cntl |=
168 			RADEON_FP_CRTC_DONT_SHADOW_VPAR |
169 			RADEON_FP_CRTC_DONT_SHADOW_HEND;
170 	}
171 
172 	// enable proper transmitter
173 	if( (crtc->chosen_displays & dd_lvds) != 0 ) {
174 		// using LVDS means there cannot be a DVI monitor
175 		values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
176 		values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
177 
178 	} else if( !fp_port->is_fp2 ) {
179 		// DVI on internal transmitter
180 		values->fp_gen_cntl |= RADEON_FP_FPON | RADEON_FP_TMDS_EN;
181 		// enabling 8 bit data may be dangerous; BIOS should have taken care of that
182 		values->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT;
183 
184 	} else {
185 		// DVI on external transmitter
186 		values->fp2_gen_cntl |= RADEON_FP2_FPON | RADEON_FP_PANEL_FORMAT;
187 		values->fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN;
188 
189 		if( ai->si->asic >= rt_r200 )
190 			values->fp2_gen_cntl |= RADEON_FP2_DV0_EN;
191 	}
192 
193     SHOW_FLOW( 2, "after: fp_gen_cntl=%08lx, horz=%08lx, vert=%08lx, lvds_gen_cntl=%08lx",
194     	values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch,
195     	values->lvds_gen_cntl );
196 }
197 
198 
199 // write flat panel registers
200 void Radeon_ProgramFPRegisters(
201 	accelerator_info *ai, crtc_info *crtc,
202 	fp_info *fp_port, fp_regs *values )
203 {
204 	shared_info *si = ai->si;
205 	vuint8 *regs = ai->regs;
206 
207 	SHOW_FLOW0( 2, "" );
208 
209 	OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, RADEON_FP_SEL_CRTC2 );
210 
211 	if( fp_port->is_fp2 ) {
212 		OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl,
213 			RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 );
214 		OUTREG( regs, RADEON_FP_H2_SYNC_STRT_WID, values->fp2_h_sync_strt_wid );
215 		OUTREG( regs, RADEON_FP_V2_SYNC_STRT_WID, values->fp2_v_sync_strt_wid );
216 	} else {
217 		OUTREG( regs, RADEON_FP_H_SYNC_STRT_WID, values->fp_h_sync_strt_wid );
218 		OUTREG( regs, RADEON_FP_V_SYNC_STRT_WID, values->fp_v_sync_strt_wid );
219 	}
220 
221 	// workaround for old AIW Radeon having display buffer underflow
222 	// in conjunction with DVI
223 	if( si->asic == rt_r100 ) {
224 		OUTREG( regs, RADEON_GRPH_BUFFER_CNTL,
225 			INREG( regs, RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000);
226 	}
227 
228 	if ( ai->si->is_mobility ) {
229 		OUTREG( regs, RADEON_BIOS_4_SCRATCH, values->bios_4_scratch);
230 		OUTREG( regs, RADEON_BIOS_5_SCRATCH, values->bios_5_scratch);
231 		OUTREG( regs, RADEON_BIOS_6_SCRATCH, values->bios_6_scratch);
232     }
233 
234 	if( (crtc->chosen_displays & dd_lvds) != 0 ) {
235 
236 		//OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl,
237 		//	RADEON_LVDS_ON | RADEON_LVDS_BLON );
238 
239 		uint32 old_pixclks_cntl;
240 		uint32 tmp;
241 
242 		old_pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL);
243 
244 		// ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero
245 		if( ai->si->is_mobility || ai->si->is_igp )
246 		{
247 			if (!(values->lvds_gen_cntl & RADEON_LVDS_ON)) {
248 				Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb );
249 			}
250 		}
251 
252 		// get current state of LCD
253 		tmp = INREG( regs, RADEON_LVDS_GEN_CNTL);
254 
255 		// if LCD is on, and previous state was on, just write the state directly.
256 		if (( tmp & ( RADEON_LVDS_ON | RADEON_LVDS_BLON )) ==
257 			( values->lvds_gen_cntl & ( RADEON_LVDS_ON | RADEON_LVDS_BLON ))) {
258 			OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl );
259 		} else {
260 			if ( values->lvds_gen_cntl & ( RADEON_LVDS_ON | RADEON_LVDS_BLON )) {
261 				snooze( ai->si->panel_pwr_delay * 1000 );
262 				OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl );
263 			} else {
264 
265 				//turn on backlight, wait for stable before turning on data ???
266 				OUTREG( regs, RADEON_LVDS_GEN_CNTL,	values->lvds_gen_cntl | RADEON_LVDS_BLON );
267 				snooze( ai->si->panel_pwr_delay * 1000 );
268 				OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl );
269 			}
270 		}
271 
272 		if( ai->si->is_mobility || ai->si->is_igp ) {
273 			if (!(values->lvds_gen_cntl & RADEON_LVDS_ON)) {
274 				Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, old_pixclks_cntl );
275 			}
276 		}
277 	}
278 }
279