xref: /haiku/src/add-ons/accelerants/radeon/theatre_out.c (revision 758b1d0e05fe1042cce6e00d194a147802d4f9be)
1 /*
2 	Copyright (c) 2002/03, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Programming of TV-out via Rage Theatre
8 */
9 
10 
11 #include "radeon_interface.h"
12 #include "radeon_accelerant.h"
13 
14 #include "theatre_regs.h"
15 #include "tv_out_regs.h"
16 #include "set_mode.h"
17 
18 #include <stdlib.h>
19 
20 
21 // mapping of offset in impactv_regs to register address
22 typedef struct register_mapping {
23 	uint16		address;			// register address
24 	uint16		offset;				// offset in impactv_regs
25 } register_mapping;
26 
27 
28 // Rage Theatre TV-Out:
29 
30 // registers to write at first
31 static const register_mapping theatre_reg_mapping_start[] = {
32 	{ THEATRE_VIP_MASTER_CNTL,		offsetof( impactv_regs, tv_master_cntl ) },
33 	{ THEATRE_VIP_TVO_DATA_DELAY_A,	offsetof( impactv_regs, tv_data_delay_a ) },
34 	{ THEATRE_VIP_TVO_DATA_DELAY_B,	offsetof( impactv_regs, tv_data_delay_b ) },
35 
36 	{ THEATRE_VIP_CLKOUT_CNTL,		offsetof( impactv_regs, tv_clkout_cntl ) },
37 	{ THEATRE_VIP_PLL_CNTL0,		offsetof( impactv_regs, tv_pll_cntl1 ) },
38 
39 	{ THEATRE_VIP_HRESTART,			offsetof( impactv_regs, tv_hrestart ) },
40 	{ THEATRE_VIP_VRESTART,			offsetof( impactv_regs, tv_vrestart ) },
41 	{ THEATRE_VIP_FRESTART,			offsetof( impactv_regs, tv_frestart ) },
42 	{ THEATRE_VIP_FTOTAL,			offsetof( impactv_regs, tv_ftotal ) },
43 
44 	{ THEATRE_VIP_CLOCK_SEL_CNTL, 	offsetof( impactv_regs, tv_clock_sel_cntl ) },
45 	{ THEATRE_VIP_TV_PLL_CNTL,		offsetof( impactv_regs, tv_tv_pll_cntl ) },
46 	{ THEATRE_VIP_CRT_PLL_CNTL,		offsetof( impactv_regs, tv_crt_pll_cntl ) },
47 
48 	{ THEATRE_VIP_HTOTAL,			offsetof( impactv_regs, tv_htotal ) },
49 	{ THEATRE_VIP_HSIZE,			offsetof( impactv_regs, tv_hsize ) },
50 	{ THEATRE_VIP_HDISP,			offsetof( impactv_regs, tv_hdisp ) },
51 	{ THEATRE_VIP_HSTART,			offsetof( impactv_regs, tv_hstart ) },
52 	{ THEATRE_VIP_VTOTAL,			offsetof( impactv_regs, tv_vtotal ) },
53 	{ THEATRE_VIP_VDISP,			offsetof( impactv_regs, tv_vdisp ) },
54 
55 	{ THEATRE_VIP_TIMING_CNTL,		offsetof( impactv_regs, tv_timing_cntl ) },
56 
57 	{ THEATRE_VIP_VSCALER_CNTL,		offsetof( impactv_regs, tv_vscaler_cntl1 ) },
58 	{ THEATRE_VIP_VSCALER_CNTL2,	offsetof( impactv_regs, tv_vscaler_cntl2 ) },
59 	{ THEATRE_VIP_SYNC_SIZE,		offsetof( impactv_regs, tv_sync_size ) },
60 	{ THEATRE_VIP_Y_SAW_TOOTH_CNTL, offsetof( impactv_regs, tv_y_saw_tooth_cntl ) },
61 	{ THEATRE_VIP_Y_RISE_CNTL,		offsetof( impactv_regs, tv_y_rise_cntl ) },
62 	{ THEATRE_VIP_Y_FALL_CNTL,		offsetof( impactv_regs, tv_y_fall_cntl ) },
63 
64 	{ THEATRE_VIP_MODULATOR_CNTL1,	offsetof( impactv_regs, tv_modulator_cntl1 ) },
65 	{ THEATRE_VIP_MODULATOR_CNTL2,	offsetof( impactv_regs, tv_modulator_cntl2 ) },
66 
67 	{ THEATRE_VIP_RGB_CNTL,			offsetof( impactv_regs, tv_rgb_cntl ) },
68 
69 	{ THEATRE_VIP_UV_ADR,			offsetof( impactv_regs, tv_uv_adr ) },
70 
71 	{ THEATRE_VIP_PRE_DAC_MUX_CNTL, offsetof( impactv_regs, tv_pre_dac_mux_cntl ) },
72 	{ THEATRE_VIP_FRAME_LOCK_CNTL,	offsetof( impactv_regs, tv_frame_lock_cntl ) },
73 	{ THEATRE_VIP_CRC_CNTL,			offsetof( impactv_regs, tv_crc_cntl ) },
74 	{ 0, 0 }
75 };
76 
77 // registers to write when things settled down
78 static const register_mapping theatre_reg_mapping_finish[] = {
79 	{ THEATRE_VIP_UPSAMP_COEFF0_0,	offsetof( impactv_regs, tv_upsample_filter_coeff[0*3+0] ) },
80 	{ THEATRE_VIP_UPSAMP_COEFF0_1,	offsetof( impactv_regs, tv_upsample_filter_coeff[0*3+1] ) },
81 	{ THEATRE_VIP_UPSAMP_COEFF0_2,	offsetof( impactv_regs, tv_upsample_filter_coeff[0*3+2] ) },
82 	{ THEATRE_VIP_UPSAMP_COEFF1_0,	offsetof( impactv_regs, tv_upsample_filter_coeff[1*3+0] ) },
83 	{ THEATRE_VIP_UPSAMP_COEFF1_1,	offsetof( impactv_regs, tv_upsample_filter_coeff[1*3+1] ) },
84 	{ THEATRE_VIP_UPSAMP_COEFF1_2,	offsetof( impactv_regs, tv_upsample_filter_coeff[1*3+2] ) },
85 	{ THEATRE_VIP_UPSAMP_COEFF2_0,	offsetof( impactv_regs, tv_upsample_filter_coeff[2*3+0] ) },
86 	{ THEATRE_VIP_UPSAMP_COEFF2_1,	offsetof( impactv_regs, tv_upsample_filter_coeff[2*3+1] ) },
87 	{ THEATRE_VIP_UPSAMP_COEFF2_2,	offsetof( impactv_regs, tv_upsample_filter_coeff[2*3+2] ) },
88 	{ THEATRE_VIP_UPSAMP_COEFF3_0,	offsetof( impactv_regs, tv_upsample_filter_coeff[3*3+0] ) },
89 	{ THEATRE_VIP_UPSAMP_COEFF3_1,	offsetof( impactv_regs, tv_upsample_filter_coeff[3*3+1] ) },
90 	{ THEATRE_VIP_UPSAMP_COEFF3_2,	offsetof( impactv_regs, tv_upsample_filter_coeff[3*3+2] ) },
91 	{ THEATRE_VIP_UPSAMP_COEFF4_0,	offsetof( impactv_regs, tv_upsample_filter_coeff[4*3+0] ) },
92 	{ THEATRE_VIP_UPSAMP_COEFF4_1,	offsetof( impactv_regs, tv_upsample_filter_coeff[4*3+1] ) },
93 	{ THEATRE_VIP_UPSAMP_COEFF4_2,	offsetof( impactv_regs, tv_upsample_filter_coeff[4*3+2] ) },
94 
95 	{ THEATRE_VIP_GAIN_LIMIT_SETTINGS,  offsetof( impactv_regs, tv_gain_limit_settings ) },
96 	{ THEATRE_VIP_LINEAR_GAIN_SETTINGS, offsetof( impactv_regs, tv_linear_gain_settings ) },
97 	{ THEATRE_VIP_UPSAMP_AND_GAIN_CNTL, offsetof( impactv_regs, tv_upsamp_and_gain_cntl ) },
98 
99 	{ THEATRE_VIP_TV_DAC_CNTL,		offsetof( impactv_regs, tv_dac_cntl ) },
100 	{ THEATRE_VIP_MASTER_CNTL,		offsetof( impactv_regs, tv_master_cntl ) },
101 	{ 0, 0 }
102 };
103 
104 
105 // write list of Rage Theatre registers
writeTheatreRegList(accelerator_info * ai,impactv_regs * values,const register_mapping * mapping)106 static void writeTheatreRegList(
107 	accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
108 {
109 	for( ; mapping->address != 0 || mapping->offset != 0; ++mapping ) {
110 		Radeon_VIPWrite( ai, ai->si->theatre_channel, mapping->address,
111 			*(uint32 *)((char *)(values) + mapping->offset) );
112 
113 /*		SHOW_FLOW( 2, "%x=%x", mapping->address,
114 			*(uint32 *)((char *)(values) + mapping->offset) );*/
115 	}
116 }
117 
118 
119 // read timing FIFO
Radeon_TheatreReadFIFO(accelerator_info * ai,uint16 addr)120 uint32 Radeon_TheatreReadFIFO(
121 	accelerator_info *ai, uint16 addr )
122 {
123 	bigtime_t start_time;
124 	uint32 res = ~0;
125 
126 	//SHOW_FLOW( 2, "addr=%d", addr );
127 
128 	Radeon_VIPWrite( ai, ai->si->theatre_channel,
129 		THEATRE_VIP_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_RD );
130 
131 	start_time = system_time();
132 
133 	do {
134 		uint32 status;
135 
136 		Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, &status );
137 
138 		if( (status & RADEON_TV_HOST_RD_WT_CNTL_RD_ACK) != 0 )
139 			break;
140 	} while( system_time() - start_time < 2000000 );
141 
142 	Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, 0);
143 	Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_READ_DATA, &res );
144 
145 	return res;
146 }
147 
148 
149 // write to timing FIFO
Radeon_TheatreWriteFIFO(accelerator_info * ai,uint16 addr,uint32 value)150 void Radeon_TheatreWriteFIFO(
151 	accelerator_info *ai, uint16 addr, uint32 value )
152 {
153 	bigtime_t start_time;
154 
155 	//readFIFO( ai, addr, internal_encoder );
156 
157 	//SHOW_FLOW( 2, "addr=%d, value=%x %x", addr, value >> 14, value & 0x3fff );
158 
159 	Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_WRITE_DATA, value);
160 	Radeon_VIPWrite( ai, ai->si->theatre_channel,
161 		THEATRE_VIP_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_WT);
162 
163 	start_time = system_time();
164 
165 	do {
166 		uint32 status;
167 
168 		Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, &status );
169 
170 		if( (status & RADEON_TV_HOST_RD_WT_CNTL_WT_ACK) != 0 )
171 			break;
172 	} while( system_time() - start_time < 2000000 );
173 
174 	Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_HOST_RD_WT_CNTL, 0 );
175 }
176 
177 
178 // program TV-Out registers
Radeon_TheatreProgramTVRegisters(accelerator_info * ai,impactv_regs * values)179 void Radeon_TheatreProgramTVRegisters(
180 	accelerator_info *ai, impactv_regs *values )
181 {
182 	uint32 orig_tv_master_cntl = values->tv_master_cntl;
183 
184 	SHOW_FLOW0( 2, "" );
185 
186 	// disable TV-out when registers are setup
187 	// it gets enabled again when things have settled down
188 	values->tv_master_cntl |=
189 		RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
190 		RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
191 		RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST |
192 
193 		RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
194 		RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
195 		RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST;
196 
197 	writeTheatreRegList( ai, values, theatre_reg_mapping_start );
198 
199 	// un-reset FIFO to access timing table
200 	Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL,
201 		orig_tv_master_cntl |
202 		RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
203 		RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
204 
205 		RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
206 		RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
207 		RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST );
208 
209 	Radeon_ImpacTVwriteHorTimingTable( ai, Radeon_TheatreWriteFIFO, values, false );
210 	Radeon_ImpacTVwriteVertTimingTable( ai, Radeon_TheatreWriteFIFO, values );
211 
212 	snooze( 50000 );
213 
214 	values->tv_master_cntl = orig_tv_master_cntl;
215 	writeTheatreRegList( ai, values, theatre_reg_mapping_finish );
216 }
217 
218 
219 // read list of Rage Theatre registers
readTheatreRegList(accelerator_info * ai,impactv_regs * values,const register_mapping * mapping)220 static void readTheatreRegList(
221 	accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
222 {
223 	for( ; mapping->address != 0 || mapping->offset != 0; ++mapping ) {
224 		Radeon_VIPRead( ai, ai->si->theatre_channel, mapping->address,
225 			(uint32 *)((char *)(values) + mapping->offset) );
226 
227 		/*SHOW_FLOW( 2, "%x=%x", mapping->address,
228 			*(uint32 *)((char *)(values) + mapping->offset) );*/
229 	}
230 
231 	//snooze( 1000000 );
232 }
233 
234 
235 // read TV-Out registers
Radeon_TheatreReadTVRegisters(accelerator_info * ai,impactv_regs * values)236 void Radeon_TheatreReadTVRegisters(
237 	accelerator_info *ai, impactv_regs *values )
238 {
239 	readTheatreRegList( ai, values, theatre_reg_mapping_start );
240 	readTheatreRegList( ai, values, theatre_reg_mapping_finish );
241 
242 	//snooze( 1000000 );
243 }
244 
245 
246 // detect TV-Out encoder
Radeon_DetectTVOut(accelerator_info * ai)247 void Radeon_DetectTVOut(
248 	accelerator_info *ai )
249 {
250 	shared_info *si = ai->si;
251 
252 	SHOW_FLOW0( 0, "" );
253 
254 	switch( si->tv_chip ) {
255 	case tc_external_rt1: {
256 		// for external encoder, we need the VIP channel
257 		int channel = Radeon_FindVIPDevice( ai, THEATRE_ID );
258 
259 		if( channel < 0 ) {
260 			SHOW_ERROR0( 2, "This card needs a Rage Theatre for TV-Out, but there is none." );
261 			si->tv_chip = tc_none;
262 		} else {
263 			SHOW_INFO( 2, "Rage Theatre found on VIP channel %d", channel );
264 			si->theatre_channel = channel;
265 		}
266 		break; }
267 	default:
268 		// for internal encoder, we don't have to look farther - it must be there
269 		;
270 	}
271 }
272