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