1 /* 2 Copyright (c) 2002/03, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Programming of internal TV-out unit 8 */ 9 10 #include "radeon_interface.h" 11 #include "radeon_accelerant.h" 12 13 #include "tv_out_regs.h" 14 #include "pll_access.h" 15 #include "mmio.h" 16 #include "utils.h" 17 #include "set_mode.h" 18 19 #include <stdlib.h> 20 21 22 // mapping of offset in impactv_regs to register address 23 typedef struct register_mapping { 24 uint16 address; // register address 25 uint16 offset; // offset in impactv_regs 26 } register_mapping; 27 28 29 // internal TV-encoder: 30 31 // registers to write before programming PLL 32 static const register_mapping intern_reg_mapping_before_pll[] = { 33 { RADEON_TV_MASTER_CNTL, offsetof( impactv_regs, tv_master_cntl ) }, 34 { RADEON_TV_HRESTART, offsetof( impactv_regs, tv_hrestart ) }, 35 { RADEON_TV_VRESTART, offsetof( impactv_regs, tv_vrestart ) }, 36 { RADEON_TV_FRESTART, offsetof( impactv_regs, tv_frestart ) }, 37 { RADEON_TV_FTOTAL, offsetof( impactv_regs, tv_ftotal ) }, 38 { 0, 0 } 39 }; 40 41 // PLL registers to program 42 static const register_mapping intern_reg_mapping_pll[] = { 43 { RADEON_TV_PLL_CNTL, offsetof( impactv_regs, tv_tv_pll_cntl ) }, 44 { RADEON_TV_PLL_CNTL1, offsetof( impactv_regs, tv_pll_cntl1 ) }, 45 { RADEON_TV_PLL_FINE_CNTL, offsetof( impactv_regs, tv_pll_fine_cntl ) }, 46 { 0, 0 } 47 }; 48 49 // registers to write after programming of PLL 50 static const register_mapping intern_reg_mapping_after_pll[] = { 51 { RADEON_TV_HTOTAL, offsetof( impactv_regs, tv_htotal ) }, 52 { RADEON_TV_HDISP, offsetof( impactv_regs, tv_hdisp ) }, 53 { RADEON_TV_HSTART, offsetof( impactv_regs, tv_hstart ) }, 54 { RADEON_TV_VTOTAL, offsetof( impactv_regs, tv_vtotal ) }, 55 { RADEON_TV_VDISP, offsetof( impactv_regs, tv_vdisp ) }, 56 57 { RADEON_TV_TIMING_CNTL, offsetof( impactv_regs, tv_timing_cntl ) }, 58 59 { RADEON_TV_VSCALER_CNTL1, offsetof( impactv_regs, tv_vscaler_cntl1 ) }, 60 { RADEON_TV_VSCALER_CNTL2, offsetof( impactv_regs, tv_vscaler_cntl2 ) }, 61 62 { RADEON_TV_Y_SAW_TOOTH_CNTL, offsetof( impactv_regs, tv_y_saw_tooth_cntl ) }, 63 { RADEON_TV_Y_RISE_CNTL, offsetof( impactv_regs, tv_y_rise_cntl ) }, 64 { RADEON_TV_Y_FALL_CNTL, offsetof( impactv_regs, tv_y_fall_cntl ) }, 65 66 { RADEON_TV_MODULATOR_CNTL1, offsetof( impactv_regs, tv_modulator_cntl1 ) }, 67 { RADEON_TV_MODULATOR_CNTL2, offsetof( impactv_regs, tv_modulator_cntl2 ) }, 68 { RADEON_TV_RGB_CNTL, offsetof( impactv_regs, tv_rgb_cntl ) }, 69 { RADEON_TV_UV_ADR, offsetof( impactv_regs, tv_uv_adr ) }, 70 { RADEON_TV_PRE_DAC_MUX_CNTL, offsetof( impactv_regs, tv_pre_dac_mux_cntl ) }, 71 { RADEON_TV_CRC_CNTL, offsetof( impactv_regs, tv_crc_cntl ) }, 72 { 0, 0 } 73 }; 74 75 // registers to write when things settled down 76 static const register_mapping intern_reg_mapping_finish[] = { 77 { RADEON_TV_GAIN_LIMIT_SETTINGS, offsetof( impactv_regs, tv_gain_limit_settings ) }, 78 { RADEON_TV_LINEAR_GAIN_SETTINGS, offsetof( impactv_regs, tv_linear_gain_settings ) }, 79 { RADEON_TV_UPSAMP_AND_GAIN_CNTL, offsetof( impactv_regs, tv_upsamp_and_gain_cntl ) }, 80 81 { RADEON_TV_DAC_CNTL, offsetof( impactv_regs, tv_dac_cntl ) }, 82 { RADEON_TV_MASTER_CNTL, offsetof( impactv_regs, tv_master_cntl ) }, 83 { 0, 0 } 84 }; 85 86 87 88 89 // write list of MM I/O registers 90 static void writeMMIORegList( 91 accelerator_info *ai, impactv_regs *values, const register_mapping *mapping ) 92 { 93 vuint8 *regs = ai->regs; 94 95 for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) { 96 /*SHOW_FLOW( 2, "%x=%x", mapping->address, 97 *(uint32 *)((char *)(values) + mapping->offset) );*/ 98 99 OUTREG( regs, mapping->address, *(uint32 *)((char *)(values) + mapping->offset) ); 100 } 101 102 //snooze( 1000000 ); 103 } 104 105 106 // write list of PLL registers 107 static void writePLLRegList( 108 accelerator_info *ai, impactv_regs *values, const register_mapping *mapping ) 109 { 110 for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) { 111 /*SHOW_FLOW( 2, "%x=%x", mapping->address, 112 *(uint32 *)((char *)(values) + mapping->offset) );*/ 113 114 Radeon_OUTPLL( ai->regs, ai->si->asic, 115 mapping->address, *(uint32 *)((char *)(values) + mapping->offset) ); 116 } 117 118 //snooze( 1000000 ); 119 } 120 121 122 123 124 // read timing FIFO 125 #if 0 126 static uint32 Radeon_InternalTVOutReadFIFO( 127 accelerator_info *ai, uint16 addr ) 128 { 129 vuint8 *regs = ai->regs; 130 bigtime_t start_time; 131 uint32 res = ~0; 132 133 //SHOW_FLOW( 2, "addr=%d", addr ); 134 135 OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_RD); 136 137 start_time = system_time(); 138 139 do { 140 uint32 status; 141 142 status = INREG( regs, RADEON_TV_HOST_RD_WT_CNTL ); 143 144 if( (status & RADEON_TV_HOST_RD_WT_CNTL_RD_ACK) != 0 ) 145 break; 146 } while( system_time() - start_time < 2000000 ); 147 148 OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, 0); 149 res = INREG( regs, RADEON_TV_HOST_READ_DATA ); 150 151 //SHOW_FLOW( 2, "res=%x %x", res >> 14, res & 0x3fff ); 152 153 return res; 154 } 155 #endif 156 157 // write to timing FIFO 158 static void Radeon_InternalTVOutWriteFIFO( 159 accelerator_info *ai, uint16 addr, uint32 value ) 160 { 161 vuint8 *regs = ai->regs; 162 bigtime_t start_time; 163 164 //readFIFO( ai, addr, internal_encoder ); 165 166 //SHOW_FLOW( 2, "addr=%d, value=%x %x", addr, value >> 14, value & 0x3fff ); 167 168 OUTREG( regs, RADEON_TV_HOST_WRITE_DATA, value ); 169 OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_WT ); 170 171 start_time = system_time(); 172 173 do { 174 uint32 status; 175 176 status = INREG( regs, RADEON_TV_HOST_RD_WT_CNTL ); 177 178 if( (status & RADEON_TV_HOST_RD_WT_CNTL_WT_ACK) != 0 ) 179 break; 180 } while( system_time() - start_time < 2000000 ); 181 182 OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, 0 ); 183 } 184 185 186 // program TV-Out registers 187 void Radeon_InternalTVOutProgramRegisters( 188 accelerator_info *ai, impactv_regs *values ) 189 { 190 uint32 orig_tv_master_cntl = values->tv_master_cntl; 191 192 SHOW_FLOW0( 2, "" ); 193 194 // disable TV-out when registers are setup 195 // it gets enabled again when things have settled down 196 values->tv_master_cntl |= 197 RADEON_TV_MASTER_CNTL_TV_ASYNC_RST | 198 RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST | 199 RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST | 200 201 RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST | 202 RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST | 203 RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST; 204 205 writeMMIORegList( ai, values, intern_reg_mapping_before_pll ); 206 writePLLRegList( ai, values, intern_reg_mapping_pll ); 207 writeMMIORegList( ai, values, intern_reg_mapping_after_pll ); 208 209 // un-reset FIFO to access timing table 210 OUTREG( ai->regs, RADEON_TV_MASTER_CNTL, 211 orig_tv_master_cntl | 212 RADEON_TV_MASTER_CNTL_TV_ASYNC_RST | 213 RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST | 214 215 RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST | 216 RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST | 217 RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST ); 218 219 Radeon_ImpacTVwriteHorTimingTable( ai, Radeon_InternalTVOutWriteFIFO, values, true ); 220 Radeon_ImpacTVwriteVertTimingTable( ai, Radeon_InternalTVOutWriteFIFO, values ); 221 222 snooze( 50000 ); 223 224 values->tv_master_cntl = orig_tv_master_cntl; 225 writeMMIORegList( ai, values, intern_reg_mapping_finish ); 226 } 227 228 229 // read list of MM I/O registers 230 static void readMMIORegList( 231 accelerator_info *ai, impactv_regs *values, const register_mapping *mapping ) 232 { 233 vuint8 *regs = ai->regs; 234 235 for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) { 236 *(uint32 *)((char *)(values) + mapping->offset) = 237 INREG( regs, mapping->address ); 238 239 /*SHOW_FLOW( 2, "%x=%x", mapping->address, 240 *(uint32 *)((char *)(values) + mapping->offset) );*/ 241 } 242 243 //snooze( 1000000 ); 244 } 245 246 247 // read list of PLL registers 248 static void readPLLRegList( 249 accelerator_info *ai, impactv_regs *values, const register_mapping *mapping ) 250 { 251 for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) { 252 *(uint32 *)((char *)(values) + mapping->offset) = 253 Radeon_INPLL( ai->regs, ai->si->asic, mapping->address ); 254 255 /*SHOW_FLOW( 2, "%x=%x", mapping->address, 256 *(uint32 *)((char *)(values) + mapping->offset) );*/ 257 } 258 259 //snooze( 1000000 ); 260 } 261 262 263 // read TV-Out registers 264 void Radeon_InternalTVOutReadRegisters( 265 accelerator_info *ai, impactv_regs *values ) 266 { 267 readMMIORegList( ai, values, intern_reg_mapping_before_pll ); 268 readPLLRegList( ai, values, intern_reg_mapping_pll ); 269 readMMIORegList( ai, values, intern_reg_mapping_after_pll ); 270 readMMIORegList( ai, values, intern_reg_mapping_finish ); 271 272 //snooze( 1000000 ); 273 } 274