2 Copyright (c) 2002/03, Thomas Kurschel
5 Part of Radeon accelerant
7 Programming of TV-out via Rage Theatre
11 #include "radeon_interface.h"
12 #include "radeon_accelerant.h"
14 #include "theatre_regs.h"
15 #include "tv_out_regs.h"
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
28 // Rage Theatre TV-Out:
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
) },
36 { THEATRE_VIP_CLKOUT_CNTL
, offsetof( impactv_regs
, tv_clkout_cntl
) },
37 { THEATRE_VIP_PLL_CNTL0
, offsetof( impactv_regs
, tv_pll_cntl1
) },
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
) },
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
) },
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
) },
55 { THEATRE_VIP_TIMING_CNTL
, offsetof( impactv_regs
, tv_timing_cntl
) },
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
) },
64 { THEATRE_VIP_MODULATOR_CNTL1
, offsetof( impactv_regs
, tv_modulator_cntl1
) },
65 { THEATRE_VIP_MODULATOR_CNTL2
, offsetof( impactv_regs
, tv_modulator_cntl2
) },
67 { THEATRE_VIP_RGB_CNTL
, offsetof( impactv_regs
, tv_rgb_cntl
) },
69 { THEATRE_VIP_UV_ADR
, offsetof( impactv_regs
, tv_uv_adr
) },
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
) },
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] ) },
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
) },
99 { THEATRE_VIP_TV_DAC_CNTL
, offsetof( impactv_regs
, tv_dac_cntl
) },
100 { THEATRE_VIP_MASTER_CNTL
, offsetof( impactv_regs
, tv_master_cntl
) },
105 // write list of Rage Theatre registers
106 static void writeTheatreRegList(
107 accelerator_info
*ai
, impactv_regs
*values
, const register_mapping
*mapping
)
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
) );
113 /* SHOW_FLOW( 2, "%x=%x", mapping->address,
114 *(uint32 *)((char *)(values) + mapping->offset) );*/
120 uint32
Radeon_TheatreReadFIFO(
121 accelerator_info
*ai
, uint16 addr
)
123 bigtime_t start_time
;
126 //SHOW_FLOW( 2, "addr=%d", addr );
128 Radeon_VIPWrite( ai
, ai
->si
->theatre_channel
,
129 THEATRE_VIP_HOST_RD_WT_CNTL
, addr
| RADEON_TV_HOST_RD_WT_CNTL_RD
);
131 start_time
= system_time();
136 Radeon_VIPRead( ai
, ai
->si
->theatre_channel
, THEATRE_VIP_HOST_RD_WT_CNTL
, &status
);
138 if( (status
& RADEON_TV_HOST_RD_WT_CNTL_RD_ACK
) != 0 )
140 } while( system_time() - start_time
< 2000000 );
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
);
149 // write to timing FIFO
150 void Radeon_TheatreWriteFIFO(
151 accelerator_info
*ai
, uint16 addr
, uint32 value
)
153 bigtime_t start_time
;
155 //readFIFO( ai, addr, internal_encoder );
157 //SHOW_FLOW( 2, "addr=%d, value=%x %x", addr, value >> 14, value & 0x3fff );
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
);
163 start_time
= system_time();
168 Radeon_VIPRead( ai
, ai
->si
->theatre_channel
, THEATRE_VIP_HOST_RD_WT_CNTL
, &status
);
170 if( (status
& RADEON_TV_HOST_RD_WT_CNTL_WT_ACK
) != 0 )
172 } while( system_time() - start_time
< 2000000 );
174 Radeon_VIPWrite( ai
, ai
->si
->theatre_channel
, THEATRE_VIP_HOST_RD_WT_CNTL
, 0 );
178 // program TV-Out registers
179 void Radeon_TheatreProgramTVRegisters(
180 accelerator_info
*ai
, impactv_regs
*values
)
182 uint32 orig_tv_master_cntl
= values
->tv_master_cntl
;
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
|
193 RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST
|
194 RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST
|
195 RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST
;
197 writeTheatreRegList( ai
, values
, theatre_reg_mapping_start
);
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
|
205 RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST
|
206 RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST
|
207 RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST
);
209 Radeon_ImpacTVwriteHorTimingTable( ai
, Radeon_TheatreWriteFIFO
, values
, false );
210 Radeon_ImpacTVwriteVertTimingTable( ai
, Radeon_TheatreWriteFIFO
, values
);
214 values
->tv_master_cntl
= orig_tv_master_cntl
;
215 writeTheatreRegList( ai
, values
, theatre_reg_mapping_finish
);
219 // read list of Rage Theatre registers
220 static void readTheatreRegList(
221 accelerator_info
*ai
, impactv_regs
*values
, const register_mapping
*mapping
)
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
) );
227 /*SHOW_FLOW( 2, "%x=%x", mapping->address,
228 *(uint32 *)((char *)(values) + mapping->offset) );*/
235 // read TV-Out registers
236 void Radeon_TheatreReadTVRegisters(
237 accelerator_info
*ai
, impactv_regs
*values
)
239 readTheatreRegList( ai
, values
, theatre_reg_mapping_start
);
240 readTheatreRegList( ai
, values
, theatre_reg_mapping_finish
);
246 // detect TV-Out encoder
247 void Radeon_DetectTVOut(
248 accelerator_info
*ai
)
250 shared_info
*si
= ai
->si
;
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
);
260 SHOW_ERROR0( 2, "This card needs a Rage Theatre for TV-Out, but there is none." );
261 si
->tv_chip
= tc_none
;
263 SHOW_INFO( 2, "Rage Theatre found on VIP channel %d", channel
);
264 si
->theatre_channel
= channel
;
268 // for internal encoder, we don't have to look farther - it must be there