xref: /haiku/src/add-ons/accelerants/radeon/flat_panel.c (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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 
17 
18 void Radeon_ReadRMXRegisters(
19 	accelerator_info *ai, fp_regs *values )
20 {
21 	vuint8 *regs = ai->regs;
22 
23 	values->fp_horz_stretch = INREG( regs, RADEON_FP_HORZ_STRETCH );
24 	values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH );
25 }
26 
27 void Radeon_CalcRMXRegisters(
28 	fp_info *flatpanel, display_mode *mode, bool use_rmx, fp_regs *values )
29 {
30 	uint xres = mode->timing.h_display;
31 	uint yres = mode->timing.v_display;
32 	uint64 Hratio, Vratio;
33 
34 	if( !use_rmx ) {
35 		// disable RMX unit if requested
36 		values->fp_horz_stretch &=
37 			~(RADEON_HORZ_STRETCH_BLEND |
38 			  RADEON_HORZ_STRETCH_ENABLE);
39 
40 		values->fp_vert_stretch &=
41 			~(RADEON_VERT_STRETCH_ENABLE |
42 			  RADEON_VERT_STRETCH_BLEND);
43 
44 		return;
45 	}
46 
47 	// RMX unit can only upscale, not downscale
48 	if( xres > flatpanel->panel_xres )
49 		xres = flatpanel->panel_xres;
50 	if( yres > flatpanel->panel_yres )
51 		yres = flatpanel->panel_yres;
52 
53 	Hratio = FIX_SCALE * (uint32)xres / flatpanel->panel_xres;
54 	Vratio = FIX_SCALE * (uint32)yres / flatpanel->panel_yres;
55 
56 	// save it for overlay unit (overlays must be vertically scaled manually)
57 	flatpanel->h_ratio = Hratio;
58 	flatpanel->v_ratio = Vratio;
59 
60 	values->fp_horz_stretch = flatpanel->panel_xres << RADEON_HORZ_PANEL_SIZE_SHIFT;
61 
62 	if( Hratio == FIX_SCALE ) {
63 		values->fp_horz_stretch &=
64 			~(RADEON_HORZ_STRETCH_BLEND |
65 			  RADEON_HORZ_STRETCH_ENABLE);
66 	} else {
67 		uint32 stretch;
68 
69 		stretch = (uint32)((Hratio * RADEON_HORZ_STRETCH_RATIO_MAX +
70 			FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_HORZ_STRETCH_RATIO_MASK;
71 
72 		values->fp_horz_stretch = stretch
73 			| (values->fp_horz_stretch & (RADEON_HORZ_PANEL_SIZE |
74 				RADEON_HORZ_FP_LOOP_STRETCH |
75 				RADEON_HORZ_AUTO_RATIO_INC));
76 		values->fp_horz_stretch |=
77 			RADEON_HORZ_STRETCH_BLEND |
78 			RADEON_HORZ_STRETCH_ENABLE;
79 	}
80 	values->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO;
81 
82 	values->fp_vert_stretch = flatpanel->panel_yres << RADEON_VERT_PANEL_SIZE_SHIFT;
83 
84 	if( Vratio == FIX_SCALE ) {
85 		values->fp_vert_stretch &=
86 			~(RADEON_VERT_STRETCH_ENABLE |
87 			  RADEON_VERT_STRETCH_BLEND);
88 	} else {
89 		uint32 stretch;
90 
91 		stretch = (uint32)((Vratio * RADEON_VERT_STRETCH_RATIO_MAX +
92 			FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_VERT_STRETCH_RATIO_MASK;
93 
94 		values->fp_vert_stretch = stretch
95 			| (values->fp_vert_stretch & (RADEON_VERT_PANEL_SIZE |
96 				RADEON_VERT_STRETCH_RESERVED));
97 		values->fp_vert_stretch |=
98 			RADEON_VERT_STRETCH_ENABLE |
99 			RADEON_VERT_STRETCH_BLEND;
100 	}
101 	values->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN;
102 }
103 
104 // write RMX registers
105 void Radeon_ProgramRMXRegisters(
106 	accelerator_info *ai, fp_regs *values )
107 {
108 	vuint8 *regs = ai->regs;
109 
110 	OUTREG( regs, RADEON_FP_HORZ_STRETCH, values->fp_horz_stretch );
111 	OUTREG( regs, RADEON_FP_VERT_STRETCH, values->fp_vert_stretch );
112 }
113 
114 
115 void Radeon_ReadFPRegisters(
116 	accelerator_info *ai, fp_regs *values )
117 {
118 	vuint8 *regs = ai->regs;
119 
120     values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL );
121     values->fp2_gen_cntl = INREG( regs, RADEON_FP2_GEN_CNTL );
122     values->lvds_gen_cntl = INREG( regs, RADEON_LVDS_GEN_CNTL );
123 	values->fp_h_sync_strt_wid = INREG( regs, RADEON_FP_H_SYNC_STRT_WID );
124 	values->fp_v_sync_strt_wid = INREG( regs, RADEON_FP_V_SYNC_STRT_WID );
125 	values->fp2_h_sync_strt_wid = INREG( regs, RADEON_FP_H2_SYNC_STRT_WID );
126 	values->fp2_v_sync_strt_wid = INREG( regs, RADEON_FP_V2_SYNC_STRT_WID );
127 
128     SHOW_FLOW( 2, "before: fp_gen_cntl=%lx, horz=%lx, vert=%lx, lvds_gen_cntl=%lx",
129     	values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch,
130     	values->lvds_gen_cntl );
131 }
132 
133 // calculcate flat panel crtc registers;
134 // must be called after normal CRTC registers are determined
135 void Radeon_CalcFPRegisters(
136 	accelerator_info *ai, crtc_info *crtc,
137 	fp_info *fp_port, crtc_regs *crtc_values, fp_regs *values )
138 {
139 	// setup synchronization position
140 	// (most values are ignored according to fp_gen_cntl, but at least polarity
141 	//  and pixel precise horizontal sync position are always used)
142 	if( fp_port->is_fp2 ) {
143 		values->fp2_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid;
144 		values->fp2_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid;
145 	} else {
146 		values->fp_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid;
147 		values->fp_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid;
148 	}
149 
150 	if( fp_port->is_fp2 )
151 		values->fp2_gen_cntl = 0;
152 	else {
153 		// setup magic CRTC shadowing
154 		values->fp_gen_cntl &=
155 			~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
156 			  RADEON_FP_DFP_SYNC_SEL |
157 			  RADEON_FP_CRT_SYNC_SEL |
158 			  RADEON_FP_CRTC_LOCK_8DOT |
159 			  RADEON_FP_USE_SHADOW_EN |
160 			  RADEON_FP_CRTC_USE_SHADOW_VEND |
161 			  RADEON_FP_CRT_SYNC_ALT);
162 		values->fp_gen_cntl |=
163 			RADEON_FP_CRTC_DONT_SHADOW_VPAR |
164 			RADEON_FP_CRTC_DONT_SHADOW_HEND;
165 	}
166 
167 	// enable proper transmitter
168 	if( (crtc->chosen_displays & dd_lvds) != 0 ) {
169 		// using LVDS means there cannot be a DVI monitor
170 		values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
171 		values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
172 
173 	} else if( !fp_port->is_fp2 ) {
174 		// DVI on internal transmitter
175 		values->fp_gen_cntl |= RADEON_FP_FPON | RADEON_FP_TMDS_EN;
176 		// enabling 8 bit data may be dangerous; BIOS should have taken care of that
177 		values->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT;
178 
179 	} else {
180 		// DVI on external transmitter
181 		values->fp2_gen_cntl |= RADEON_FP2_FPON | RADEON_FP_PANEL_FORMAT;
182 		values->fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN;
183 
184 		if( ai->si->asic >= rt_r200 )
185 			values->fp2_gen_cntl |= RADEON_FP2_DV0_EN;
186 	}
187 
188     SHOW_FLOW( 2, "after: fp_gen_cntl=%lx, horz=%lx, vert=%lx, lvds_gen_cntl=%lx",
189     	values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch,
190     	values->lvds_gen_cntl );
191 }
192 
193 
194 // write flat panel registers
195 void Radeon_ProgramFPRegisters(
196 	accelerator_info *ai, crtc_info *crtc,
197 	fp_info *fp_port, fp_regs *values )
198 {
199 	shared_info *si = ai->si;
200 	vuint8 *regs = ai->regs;
201 
202 	SHOW_FLOW0( 2, "" );
203 
204 	OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, RADEON_FP_SEL_CRTC2 );
205 
206 	if( fp_port->is_fp2 ) {
207 		OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl,
208 			RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 );
209 		OUTREG( regs, RADEON_FP_H2_SYNC_STRT_WID, values->fp2_h_sync_strt_wid );
210 		OUTREG( regs, RADEON_FP_V2_SYNC_STRT_WID, values->fp2_v_sync_strt_wid );
211 	} else {
212 		OUTREG( regs, RADEON_FP_H_SYNC_STRT_WID, values->fp_h_sync_strt_wid );
213 		OUTREG( regs, RADEON_FP_V_SYNC_STRT_WID, values->fp_v_sync_strt_wid );
214 	}
215 
216 	// workaround for old AIW Radeon having display buffer underflow
217 	// in conjunction with DVI
218 	if( si->asic == rt_r100 ) {
219 		OUTREG( regs, RADEON_GRPH_BUFFER_CNTL,
220 			INREG( regs, RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000);
221 	}
222 
223 	if( (crtc->chosen_displays & dd_lvds) != 0 ) {
224 		OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl,
225 			RADEON_LVDS_ON | RADEON_LVDS_BLON );
226 	}
227 }
228