📄 impactv.c
字号:
// as a result, you must not call Radeon_CalcPLLRegisters() afterwards// TBD: what's special in terms of PLL in TV-Out mode?void Radeon_CalcImpacTVRegisters( accelerator_info *ai, display_mode *mode, impactv_params *params, impactv_regs *values, int crtc_idx, bool internal_encoder, tv_standard_e tv_format, display_device_e display_device ){ const tv_timing *timing = ¶ms->timing; SHOW_FLOW0( 2, "" ); if( tv_format < ts_ntsc || tv_format > ts_max ) tv_format = ts_ntsc; values->tv_ftotal = timing->f_total; // RE: UV_THINNER should affect sharpness only, but the only effect is that // the colour fades out, so I leave it zero values->tv_vscaler_cntl1 = RADEON_TV_VSCALER_CNTL1_Y_W_EN; values->tv_vscaler_cntl1 = (values->tv_vscaler_cntl1 & 0xe3ff0000) | params->uv_inc; if( internal_encoder ) { // RE: was on - update: disabling it breaks restart values->tv_vscaler_cntl1 |= RADEON_TV_VSCALER_CNTL1_RESTART_FIELD; if( mode->timing.h_display == 1024 ) values->tv_vscaler_cntl1 |= 4 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; else values->tv_vscaler_cntl1 |= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; } else { values->tv_vscaler_cntl1 |= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; } values->tv_y_saw_tooth_cntl = params->y_saw_tooth_amp | (params->y_saw_tooth_slope << RADEON_TV_Y_SAW_TOOTH_CNTL_SLOPE_SHIFT); values->tv_y_fall_cntl = params->y_fall_accum_init | RADEON_TV_Y_FALL_CNTL_Y_FALL_PING_PONG | (params->y_coeff_enable ? RADEON_TV_Y_FALL_CNTL_Y_COEFF_EN : 0) | (params->y_coeff_value << RADEON_TV_Y_FALL_CNTL_Y_COEFF_VALUE_SHIFT); values->tv_y_rise_cntl = params->y_rise_accum_init | RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG; // RE: all dither flags/values were zero values->tv_vscaler_cntl2 = (values->tv_vscaler_cntl2 & 0x00fffff0) | (params->uv_accum_init << RADEON_TV_VSCALER_CNTL2_UV_ACCUM_INIT_SHIFT); if( internal_encoder ) { values->tv_vscaler_cntl2 |= RADEON_TV_VSCALER_CNTL2_DITHER_MODE | RADEON_TV_VSCALER_CNTL2_Y_OUTPUT_DITHER_EN | RADEON_TV_VSCALER_CNTL2_UV_OUTPUT_DITHER_EN | RADEON_TV_VSCALER_CNTL2_UV_TO_BUF_DITHER_EN; } values->tv_hrestart = params->h_restart; values->tv_vrestart = params->v_restart; values->tv_frestart = params->f_restart; values->tv_tv_pll_cntl = (params->tv_dividers.ref & RADEON_TV_PLL_CNTL_TV_M0_LO_MASK) | ((params->tv_dividers.feedback & RADEON_TV_PLL_CNTL_TV_N0_LO_MASK) << RADEON_TV_PLL_CNTL_TV_N0_LO_SHIFT) | ((params->tv_dividers.ref >> RADEON_TV_PLL_CNTL_TV_M0_LO_BITS) << RADEON_TV_PLL_CNTL_TV_M0_HI_SHIFT) | ((params->tv_dividers.feedback >> RADEON_TV_PLL_CNTL_TV_N0_LO_BITS) << RADEON_TV_PLL_CNTL_TV_N0_HI_SHIFT) | // RE: was on //RADEON_TV_PLL_CNTL_TV_SLIP_EN | (params->tv_dividers.post << RADEON_TV_PLL_CNTL_TV_P_SHIFT); //| // RE: was on //RADEON_TV_PLL_CNTL_TV_DTO_EN; values->tv_crt_pll_cntl = (params->crt_dividers.ref & RADEON_TV_CRT_PLL_CNTL_M0_LO_MASK) | ((params->crt_dividers.feedback & RADEON_TV_CRT_PLL_CNTL_N0_LO_MASK) << RADEON_TV_CRT_PLL_CNTL_N0_LO_SHIFT) | ((params->crt_dividers.ref >> RADEON_TV_CRT_PLL_CNTL_M0_LO_BITS) << RADEON_TV_CRT_PLL_CNTL_M0_HI_SHIFT) | ((params->crt_dividers.feedback >> RADEON_TV_CRT_PLL_CNTL_N0_LO_BITS) << RADEON_TV_CRT_PLL_CNTL_N0_HI_SHIFT) | (params->crt_dividers.extra_post == 2 ? RADEON_TV_CRT_PLL_CNTL_CLKBY2 : 0); // TK: from Gatos // in terms of byte clock devider, I have no clue how that works, // but leaving it 1 seems to be save values->tv_clock_sel_cntl = 0x33 | ((/*params->crt_dividers.post_code - 1*/0) << RADEON_TV_CLOCK_SEL_CNTL_BYTCLK_SHIFT) | (1 << RADEON_TV_CLOCK_SEL_CNTL_BYTCLKD_SHIFT); values->tv_clkout_cntl = 0x09; if( !internal_encoder ) values->tv_clkout_cntl |= 1 << 5; values->tv_htotal = mode->timing.h_total - 1; values->tv_hsize = mode->timing.h_display; values->tv_hdisp = mode->timing.h_display - 1; values->tv_hstart = // TK: was -12, but this cuts off the left border of the image internal_encoder ? values->tv_hdisp + 1 - params->mode888 + 12 : values->tv_hdisp + 1 - params->mode888 + 12; values->tv_vtotal = mode->timing.v_total - 1; values->tv_vdisp = mode->timing.v_display - 1; values->tv_sync_size = mode->timing.h_display + 8; values->tv_timing_cntl = (values->tv_timing_cntl & 0xfffff000) | params->h_inc; if( ai->si->asic >= rt_r300 ) { // this is a hack to fix improper UV scaling // (at least this is what the sample code says) values->tv_timing_cntl = (values->tv_timing_cntl & 0x00ffffff) | ((0x72 * 640 / mode->timing.h_display) << RADEON_TV_TIMING_CNTL_UV_OUTPUT_POST_SCALE_SHIFT); } if( internal_encoder ) { // tell TV-DAC to generate proper NTSC/PAL signal values->tv_dac_cntl = RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD | (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT); switch( tv_format ) { case ts_ntsc: values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_NTSC; break; case ts_pal_bdghi: case ts_pal_m: case ts_pal_nc: case ts_scart_pal: case ts_pal_60: values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_PAL; break; default: } // enable composite or S-Video DAC values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_RDACPD | RADEON_TV_DAC_CNTL_GDACPD | RADEON_TV_DAC_CNTL_BDACPD; if( (display_device & dd_ctv) != 0 ) { values->tv_dac_cntl &= ~RADEON_TV_DAC_CNTL_BDACPD; } if( (display_device & dd_stv) != 0 ) { values->tv_dac_cntl &= ~(RADEON_TV_DAC_CNTL_RDACPD | RADEON_TV_DAC_CNTL_GDACPD); } } else { values->tv_dac_cntl = (values->tv_dac_cntl & ~(RADEON_TV_DAC_CNTL_STD_NTSC | 0x88 | RADEON_TV_DAC_CNTL_BGSLEEP | RADEON_TV_DAC_CNTL_PEDESTAL)) | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD; } values->tv_modulator_cntl1 &= ~( RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK | RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK); switch( tv_format ) { case ts_ntsc: // RE: typo? //values->tv_dac_cntl |= values->tv_modulator_cntl1 |= RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | (0x46 << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | (0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT); values->tv_modulator_cntl2 = (-111 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) | ((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); break; case ts_pal_bdghi: values->tv_modulator_cntl1 |= RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | (0x3b << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | (0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT); values->tv_modulator_cntl2 = (-78 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) | ((62 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); break; case ts_scart_pal: // from register spec values->tv_modulator_cntl1 |= RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL; values->tv_modulator_cntl2 = (0 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) | ((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); break; default: // there are many formats missing, sigh... } // RE: values->tv_modulator_cntl1 |= RADEON_TV_MODULATOR_CNTL1_YFLT_EN | RADEON_TV_MODULATOR_CNTL1_UVFLT_EN | RADEON_TV_MODULATOR_CNTL1_SLEW_RATE_LIMIT | (2 << RADEON_TV_MODULATOR_CNTL1_CY_FILT_BLEND_SHIFT); if( internal_encoder ) { values->tv_data_delay_a = 0x0b0c0a06; values->tv_data_delay_b = 0x070a0a0c; } else { values->tv_data_delay_a = 0x07080604; values->tv_data_delay_b = 0x03070607; } values->tv_frame_lock_cntl = internal_encoder ? 0 : 0xf0f; if( internal_encoder ) { values->tv_pll_cntl1 = (4 << RADEON_TV_PLL_CNTL1_TVPCP_SHIFT) | (4 << RADEON_TV_PLL_CNTL1_TVPVG_SHIFT) | // RE: was 2 (1 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT) | RADEON_TV_PLL_CNTL1_TVCLK_SRC_SEL_TVPLLCLK | RADEON_TV_PLL_CNTL1_TVPLL_TEST; values->tv_rgb_cntl = ((crtc_idx == 1 ? 2 : 0) << RADEON_TV_RGB_CNTL_RGB_SRC_SEL_SHIFT) | RADEON_TV_RGB_CNTL_RGB_DITHER_EN | (0xb << RADEON_TV_RGB_CNTL_UVRAM_READ_MARGIN_SHIFT) | (7 << RADEON_TV_RGB_CNTL_FIFORAM_FIFOMACRO_READ_MARGIN_SHIFT); // RE: values->tv_rgb_cntl |= 0x4000000; values->tv_pre_dac_mux_cntl = RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN; // RE: /* | (0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/ } else { // this register seems to have completely different meaning on Theatre chip values->tv_pll_cntl1 = (1 << 3) | (1 << 4) | (4 << 8) | (1 << 11) | (5 << 13) | (4 << 16) | (1 << 19) | (5 << 21); // this one too values->tv_rgb_cntl = params->mode888; values->tv_pre_dac_mux_cntl = RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN; // RE: /*(0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/ } values->tv_pll_fine_cntl = 0; // TBD: this is certainly broken // (they do an ((orig & 0xe0) & 0x600) which is constant zero) values->tv_master_cntl = RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN | RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN; if( tv_format == ts_ntsc ) values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX; else values->tv_master_cntl &= ~RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX; // this is missing in the sample code if( internal_encoder ) values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_TV_ON; else values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX | // RE: guessed RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST | RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST | RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST; values->tv_gain_limit_settings = 0x017f05ff; values->tv_linear_gain_settings = 0x01000100; values->tv_upsamp_and_gain_cntl = 0x00000005; values->tv_crc_cntl = 0; SHOW_FLOW( 2, "tv_master_cntl=%x", values->tv_master_cntl ); memcpy( values->tv_upsample_filter_coeff, std_upsample_filter_coeff, RADEON_TV_UPSAMP_COEFF_NUM * sizeof( uint32 )); // setup output timing memcpy( values->tv_hor_timing, hor_timings[tv_format-1], RADEON_TV_TIMING_SIZE * sizeof( uint16 )); memcpy( values->tv_vert_timing, vert_timings[tv_format-1], RADEON_TV_TIMING_SIZE * sizeof( uint16 ) ); // arbitrary position of vertical timing table in FIFO values->tv_uv_adr = TV_UV_ADR_INI;}// get address of horizontal timing table in FIFO static uint16 getHorTimingTableAddr( impactv_regs *values, bool internal_encoder ){ switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_HCODE_TABLE_SEL_MASK) >> RADEON_TV_UV_ADR_HCODE_TABLE_SEL_SHIFT ) { case 0: return internal_encoder ? RADEON_TV_MAX_FIFO_ADDR_INTERN : RADEON_TV_MAX_FIFO_ADDR; case 1: return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK) >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2; case 2: return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK) >> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2; default: return 0; }}// get address of vertical timing table in FIFO static uint16 getVertTimingTableAddr( impactv_regs *values ){ switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_VCODE_TABLE_SEL_MASK) >> RADEON_TV_UV_ADR_VCODE_TABLE_SEL_SHIFT ) { case 0: return ((values->tv_uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) >> RADEON_TV_UV_ADR_MAX_UV_ADR_SHIFT) * 2 + 1; case 1: return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK) >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2 + 1; case 2: return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK) >> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2 + 1; default: return 0; }}// write horizontal timing tablevoid Radeon_ImpacTVwriteHorTimingTable( accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values, bool internal_encoder ){ uint16 addr = getHorTimingTableAddr( values, internal_encoder ); int i; for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2, --addr ) { uint32 value = ((uint32)values->tv_hor_timing[i] << 14) | values->tv_hor_timing[i + 1]; write( ai, addr, value ); if( values->tv_hor_timing[i] == 0 || values->tv_hor_timing[i + 1] == 0 ) break; }}// write vertical timing tablevoid Radeon_ImpacTVwriteVertTimingTable( accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values ){ uint16 addr = getVertTimingTableAddr( values ); int i; for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2 , ++addr ) { uint32 value = ((uint32)values->tv_vert_timing[i + 1] << 14) | values->tv_vert_timing[i]; write( ai, addr, value ); if( values->tv_vert_timing[i + 1] == 0 || values->tv_vert_timing[i] == 0 ) break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -