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 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 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 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 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 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 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 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