/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2014-2019. All rights reserved. * Description : vfe part * Author : sdk * Create : 2014-12-27 */ #include "drv_vfe.h" #include "soc_log.h" #include "osal_ext.h" #include "drv_hddec_ext.h" #include "drv_vfe_offline.h" #include "drv_vfe_hal.h" #include "drv_vfe_platform.h" #include "linux/huanglong/securec.h" #include "drv_sys_ext.h" /************************** macro definition start***************************/ /* function moudle definition */ /* 同时支持TVD和HDDEC通路,同时需要修改TVD_SAMPLE_RATE_FROM_VFE为75000000 */ #define TVD_SAMPLE_RATE_FROM_VFE_TWO_ROUTE 75000000 /* macro definition for constant value */ #define VFE_CRYSTAL_FREQ 24000 /* k_hz */ #define VFE_U32_MAX 0xFFFFFFFF #define VFE_CHAN_MAX 4 #define VFE_CLAMP_LEVEL_MAX 0x10 #define VFE_SLICER_LEVEL_DEF 8 // 23 // 10 // 0x15 // 0x17 // 0x10 #define VFE_APLL_CLK_MIN 1300000 #define VFE_APLL_CLK_MAX 2600000 // 单位为k_hz, APLL最佳工作时钟范围时1300M到2600M #define VFE_APLL_CLK_BEST 1900000 /* 单位为k_hz, APLL最佳工作时钟为1600M */ #define VFE_APLL_POST_DIV_MAX 7 // postdiv1和postdiv2范围为1到7倍 #define VFE_DEF_REF_DIV 1 #define VFE_PHASE_DEF 28 #define VFE_PHASE_MAX 0x20 #define VFE_HTOTAL_DEF 1650 #define VFE_CLOCK_DEF 74250 /* 720p@60_hz */ #define VFE_GAIN_DEF 0 #define VFE_OFFSET_DEF 0x80 #define VFE_GAIN_MAX 0x20 #define VFE_OFFSET_MAX 0xFF #define VFE_SIF_GAIN_MAX 32 /* 单独sif输入的增益调整0到31db */ #define VFE_SIF_OFFSET_MAX 0x100 #define VFE_PRE_CAL_PIN 0x03 #define VFE_PRE_GAIN_CNT 0x30 #define VFE_CVBS_PIN_N 0 #define VFE_RF_PIN_N 0 #define VFE_VDAC_GAIN_MAX 0x7F /* 0xFF, modified from new equator data sheet */ #define VFE_VDAC_GAIN_ADDR 0x49d /* OTP VDAC1 GAIN ADDR */ #define VFE_VDAC_GAIN_I 0xc4 /* 通过电流调节的GAIN值 */ #define VFE_PLL_PHASE_LOCK_THR 0x10 #define INVALID_PRECAL_GAIN 0x7FFFFF00 #define BASE_PRECAL_GAIN 0x40000000 #define INVALID_PRECAL_OFFSET 0xFFFFFFC0 #define BASE_PRECAL_OFFSET 0 #define VFE_DAC_GAIN_DEF 0x33 // 0x3F // 0x20 /*************************** macro definition end****************************/ /************************** static declaration start*************************/ vfe_drv_ctx g_vfe_drv_ctx[VFE_WORKMODE_MAX]; static td_u32 g_get_pass_dpll_div[VFE_DPLL_DIV_BUTT] = { 16, // VFE_DPLL_DIV_16 32, // VFE_DPLL_DIV_32 64, // VFE_DPLL_DIV_64 128, // VFE_DPLL_DIV_128 }; /*************************** static declaration end**************************/ static td_void vfe_get_rgb_chn_mux1_val(const ext_drv_vfe_source_attr *source, td_u32 *r_mux1_val, td_u32 *g_mux1_val, td_u32 *b_mux1_val) { *r_mux1_val = INVLIAD_MUX_VAL; *g_mux1_val = INVLIAD_MUX_VAL; *b_mux1_val = INVLIAD_MUX_VAL; vfe_platform_get_rgb_mux1_val(source, r_mux1_val, g_mux1_val, b_mux1_val); if (*r_mux1_val == INVLIAD_MUX_VAL || *g_mux1_val == INVLIAD_MUX_VAL || *b_mux1_val == INVLIAD_MUX_VAL) { *r_mux1_val = 0; *g_mux1_val = 0; *b_mux1_val = 0; soc_log_err("invalid input RGB channel:\n"); soc_err_print_u32(source->r_chn_mux); soc_err_print_u32(source->g_chn_mux); soc_err_print_u32(source->b_chn_mux); return; } return; } static td_void vfe_get_cvbs_chn_mux1_val(ext_drv_input_mux cvbs_chn_mux, td_u32 *cvbs_mux1_val) { *cvbs_mux1_val = 0; if (cvbs_chn_mux == EXT_DRV_INPUT_MUX_CVBS0) { *cvbs_mux1_val = 0; } else if (cvbs_chn_mux == EXT_DRV_INPUT_MUX_CVBS1) { *cvbs_mux1_val = 1; } else if (cvbs_chn_mux == EXT_DRV_INPUT_MUX_CVBS2) { *cvbs_mux1_val = 2; // set value to 2 } else if (cvbs_chn_mux == EXT_DRV_INPUT_MUX_CVBS3) { *cvbs_mux1_val = 3; // set value to 3 } else { soc_log_err("invalid input CVBS channel: \n"); soc_err_print_u32(cvbs_chn_mux); return; } return; } td_void drv_vfe_check_r_chn_mux(const ext_drv_vfe_source_attr *source, td_bool *adc_chan_r_used, td_bool *adc_chan_g_used, td_bool *adc_chan_b_used) { if (source == TD_NULL || adc_chan_r_used == TD_NULL || adc_chan_g_used == TD_NULL || adc_chan_b_used == TD_NULL) { soc_log_err("input null pointer!\n"); return; } if (is_chan_r_in(source->r_chn_mux)) { *adc_chan_r_used = TD_TRUE; } if (is_chan_g_in(source->r_chn_mux)) { *adc_chan_g_used = TD_TRUE; } if (is_chan_b_in(source->r_chn_mux)) { *adc_chan_b_used = TD_TRUE; } } td_s32 drv_vfe_check_g_chn_mux(const ext_drv_vfe_source_attr *source, td_bool *adc_chan_r_used, td_bool *adc_chan_g_used, td_bool *adc_chan_b_used) { if (source == TD_NULL || adc_chan_r_used == TD_NULL || adc_chan_g_used == TD_NULL || adc_chan_b_used == TD_NULL) { soc_log_err("input null pointer!\n"); return TD_FAILURE; } if (is_chan_r_in(source->g_chn_mux)) { if (*adc_chan_r_used == TD_TRUE) { return TD_FAILURE; } else { *adc_chan_r_used = TD_TRUE; } } if (is_chan_g_in(source->g_chn_mux)) { if (*adc_chan_g_used == TD_TRUE) { return TD_FAILURE; } else { *adc_chan_g_used = TD_TRUE; } } if (is_chan_b_in(source->g_chn_mux)) { if (*adc_chan_b_used == TD_TRUE) { return TD_FAILURE; } else { *adc_chan_b_used = TD_TRUE; } } return TD_SUCCESS; } td_s32 drv_vfe_check_b_chn_mux(const ext_drv_vfe_source_attr *source, td_bool *adc_chan_r_used, td_bool *adc_chan_g_used, td_bool *adc_chan_b_used) { if (source == TD_NULL || adc_chan_r_used == TD_NULL || adc_chan_g_used == TD_NULL || adc_chan_b_used == TD_NULL) { soc_log_err("input null pointer!\n"); return TD_FAILURE; } if (is_chan_r_in(source->b_chn_mux)) { if (*adc_chan_r_used == TD_TRUE) { return TD_FAILURE; } else { *adc_chan_r_used = TD_TRUE; } } if (is_chan_g_in(source->b_chn_mux)) { if (*adc_chan_g_used == TD_TRUE) { return TD_FAILURE; } else { *adc_chan_g_used = TD_TRUE; } } if (is_chan_b_in(source->b_chn_mux)) { if (*adc_chan_b_used == TD_TRUE) { return TD_FAILURE; } else { *adc_chan_b_used = TD_TRUE; } } return TD_SUCCESS; } td_s32 drv_vfe_check_rgb_chn_mux(const ext_drv_vfe_source_attr *source) { td_s32 ret; td_bool adc_chan_r_used = TD_FALSE; td_bool adc_chan_g_used = TD_FALSE; td_bool adc_chan_b_used = TD_FALSE; drv_vfe_check_r_chn_mux(source, &adc_chan_r_used, &adc_chan_g_used, &adc_chan_b_used); ret = drv_vfe_check_g_chn_mux(source, &adc_chan_r_used, &adc_chan_g_used, &adc_chan_b_used); if (ret == TD_FAILURE) { return TD_FAILURE; } ret = drv_vfe_check_b_chn_mux(source, &adc_chan_r_used, &adc_chan_g_used, &adc_chan_b_used); if (ret == TD_FAILURE) { return TD_FAILURE; } if (adc_chan_r_used == TD_FALSE || adc_chan_g_used == TD_FALSE || adc_chan_b_used == TD_FALSE) { return TD_FAILURE; } return TD_SUCCESS; } td_void drv_vfe_print_rgb_chn_mux(const ext_drv_vfe_source_attr *source) { soc_log_err("invalid input RGB channel:\n"); if (source != TD_NULL) { soc_err_print_u32(source->r_chn_mux); soc_err_print_u32(source->g_chn_mux); soc_err_print_u32(source->b_chn_mux); } } static td_s32 vfe_check_input_attr(const ext_drv_vfe_source_attr *source) { td_s32 ret; switch (source->work_mode) { case EXT_DRV_VFE_WORK_MODE_HDDEC: { ret = drv_vfe_check_rgb_chn_mux(source); if (ret == TD_FAILURE) { drv_vfe_print_rgb_chn_mux(source); return TD_FAILURE; } break; } case EXT_DRV_VFE_WORK_MODE_TVD: { if (!is_cvbs_in(source->cvbs_chn_mux)) { soc_log_err("invalid input CVBS channel:\n"); soc_err_print_u32(source->cvbs_chn_mux); return TD_FAILURE; } break; } case EXT_DRV_VFE_WORK_MODE_TVD_SVIDEO: { if (!is_cvbs_in(source->sy_chn_mux) || (!is_cvbs_in(source->sc_chn_mux))) { soc_log_err("invalid input sy_chn_mux or sc_chn_mux channel:\n"); soc_err_print_u32(source->cvbs_chn_mux); return TD_FAILURE; } break; } default: { soc_log_err("invalid input work mode:\n"); soc_err_print_u32(source->work_mode); return TD_FAILURE; } } if (source->sog_chn_mux >= EXT_DRV_INPUT_MUX_SOG_MAX) { soc_log_err(" invalid input com channel:\n"); soc_err_print_u32(source->sog_chn_mux); return TD_FAILURE; } if (source->sync_chn_mux >= EXT_DRV_INPUT_MUX_SYNC_MAX) { soc_log_err(" invalid input slicer1 channel:\n"); soc_err_print_u32(source->sync_chn_mux); return TD_FAILURE; } return TD_SUCCESS; } static td_s32 vfe_check_pll_attr(const ext_drv_vfe_pll_attr *pll_attr) { if (pll_attr == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } if ((pll_attr->bypass_dpll != TD_TRUE) && (pll_attr->bypass_dpll != TD_FALSE)) { soc_log_err("invalid pll bypass dpll value:\n"); soc_err_print_u32(pll_attr->bypass_dpll); return TD_FAILURE; } if (pll_attr->sample_clk <= 0) { soc_log_err("invalid pll sample clk value:\n"); soc_err_print_u32(pll_attr->sample_clk); return TD_FAILURE; } if (pll_attr->h_total <= 0) { soc_log_err("invalid pll htotal value:\n"); soc_err_print_u32(pll_attr->h_total); return TD_FAILURE; } return TD_SUCCESS; } static td_s32 vfe_check_clamp_attr(const ext_drv_vfe_clamp_attr *clamp) { const ext_drv_vfe_vclamp_attr *vclamp_attr = NULL; const ext_drv_vfe_iclamp_attr *iclamp_attr = NULL; if (clamp->clamp_type >= EXT_DRV_VFE_CLAMP_MAX) { soc_log_err("invalid clamp type :\n"); soc_err_print_u32(clamp->clamp_type); return TD_FAILURE; } if (clamp->clamp_type != EXT_DRV_VFE_CLAMP_I) { vclamp_attr = &clamp->vclamp_attr; if (vclamp_attr->vclamp_type >= EXT_DRV_VFE_VCLAMP_ON_MAX) { soc_log_err("invalid v clamp type :\n"); soc_err_print_u32(vclamp_attr->vclamp_type); return TD_FAILURE; } if (vclamp_attr->blk_level >= EXT_DRV_VFE_VCLAMP_BLK_MAX) { soc_log_err("invalid v clamp blank value :\n"); soc_err_print_u32(vclamp_attr->blk_level); return TD_FAILURE; } if (vclamp_attr->mid_level >= EXT_DRV_VFE_VCLAMP_MID_MAX) { soc_log_err("invalid v clamp middle value :\n"); soc_err_print_u32(vclamp_attr->mid_level); return TD_FAILURE; } } if (clamp->clamp_type != EXT_DRV_VFE_CLAMP_V) { iclamp_attr = &clamp->iclamp_attr; if (iclamp_attr->imax_type >= EXT_DRV_VFE_IMAX_TYPE_MAX) { soc_log_err("invalid i clamp imax type :\n"); soc_err_print_u32(iclamp_attr->imax_type); return TD_FAILURE; } if (iclamp_attr->iclamp_level >= VFE_CLAMP_LEVEL_MAX) { soc_log_err("invalid i clamp level value :\n"); soc_err_print_u32(iclamp_attr->iclamp_level); return TD_FAILURE; } } return TD_SUCCESS; } static td_s32 vfe_check_lpf_attr(const ext_drv_vfe_lpf_filter_attr *lpf_attr) { if (lpf_attr->rgb_chn_lpf_mode >= EXT_DRV_VFE_LPF_MODE_MAX) { soc_log_err("invalid rg_bchn lpf mode :\n"); soc_err_print_u32(lpf_attr->rgb_chn_lpf_mode); return TD_FAILURE; } if ((lpf_attr->com_chn_filter.filter_en != TD_FALSE) && (lpf_attr->com_chn_filter.filter_en != TD_TRUE)) { soc_log_err("invalid comchn filter enable value :\n"); soc_err_print_u32(lpf_attr->com_chn_filter.filter_en); return TD_FAILURE; } if (lpf_attr->com_chn_filter.filter_ib >= EXT_DRV_VFE_FILTER_IB_MAX) { soc_log_err("invalid comchn filter ib value :\n"); soc_err_print_u32(lpf_attr->com_chn_filter.filter_ib); return TD_FAILURE; } if (lpf_attr->com_chn_filter.filter_r >= EXT_DRV_VFE_FILTER_R_MAX) { soc_log_err("invalid comchn filter r value :\n"); soc_err_print_u32(lpf_attr->com_chn_filter.filter_r); return TD_FAILURE; } return TD_SUCCESS; } static td_s32 vfe_calcu_pass_dpll_cfg(td_u32 sample_clk, vfe_dpll_div_sel *dpll_div, td_u32 *int_mult, td_u32 *frac_mult) { vfe_dpll_div_sel dpll_div_sel, best_dpll_div; td_u32 temp_div, temp_diff, min_diff, temp_apll_clk, best_apll_clk; td_u32 inter_mult; td_u32 fra_mult; td_u64 tmep; min_diff = VFE_U32_MAX; best_dpll_div = VFE_DPLL_DIV_16; best_apll_clk = VFE_APLL_CLK_BEST; soc_dbg_print_u32(sample_clk); /* APLL的VCO时钟从小到大遍历 */ for (dpll_div_sel = VFE_DPLL_DIV_16; dpll_div_sel < VFE_DPLL_DIV_BUTT; dpll_div_sel++) { temp_div = g_get_pass_dpll_div[dpll_div_sel]; temp_apll_clk = sample_clk * temp_div; soc_dbg_print_u32(temp_apll_clk); if ((temp_apll_clk < VFE_APLL_CLK_MIN) || (temp_apll_clk > VFE_APLL_CLK_MAX)) { continue; } temp_diff = abs(VFE_APLL_CLK_BEST - temp_apll_clk); soc_dbg_print_u32(dpll_div_sel); soc_dbg_print_u32(temp_diff); if (temp_diff < min_diff) { min_diff = temp_diff; best_dpll_div = dpll_div_sel; best_apll_clk = temp_apll_clk; soc_dbg_print_u32(temp_diff); soc_dbg_print_u32(min_diff); } } *dpll_div = best_dpll_div; inter_mult = best_apll_clk / VFE_CRYSTAL_FREQ; tmep = best_apll_clk % VFE_CRYSTAL_FREQ; tmep <<= 24; // mv left 24 bits do_div(tmep, VFE_CRYSTAL_FREQ); fra_mult = tmep & 0xFFFFFF; *int_mult = inter_mult & 0xFFF; *frac_mult = fra_mult & 0xFFFFFF; soc_dbg_print_u32(*dpll_div); soc_dbg_print_u32(*int_mult); soc_dbg_print_u32(*frac_mult); soc_dbg_print_u32(best_apll_clk); return TD_SUCCESS; } static td_void vfe_calcu_bypass_dpll_cfg1(td_u32 sample_clk, td_u32 *int_mult, td_u32 *post_div1, td_u32 *post_div2) { td_u32 post_div_index1, post_div_index2; td_u32 best_post_div1 = 0; td_u32 best_post_div2 = 0; td_u32 temp_diff, temp_apll_clk, temp_frac; td_u32 int_min_diff; td_u32 best_int_apll_clk = 0; int_min_diff = VFE_U32_MAX; for (post_div_index1 = 1; post_div_index1 <= VFE_APLL_POST_DIV_MAX; post_div_index1++) { for (post_div_index2 = 1; post_div_index2 <= VFE_APLL_POST_DIV_MAX; post_div_index2++) { temp_apll_clk = sample_clk * post_div_index1 * post_div_index2; if ((temp_apll_clk < VFE_APLL_CLK_MIN) || (temp_apll_clk > VFE_APLL_CLK_MAX)) { continue; } temp_frac = temp_apll_clk % VFE_CRYSTAL_FREQ; temp_diff = abs(VFE_APLL_CLK_BEST - temp_apll_clk); if (temp_frac == 0 && temp_diff < int_min_diff) { int_min_diff = temp_diff; best_int_apll_clk = temp_apll_clk; best_post_div1 = post_div_index1; best_post_div2 = post_div_index2; } } } *int_mult = best_int_apll_clk / VFE_CRYSTAL_FREQ; *post_div1 = best_post_div1; *post_div2 = best_post_div2; soc_dbg_print_u32(*int_mult); soc_dbg_print_u32(*post_div1); soc_dbg_print_u32(*post_div2); return; } td_void vfe_hal_set_fnpll(td_void) { vfe_hal_reg_write(0xDC0, 0x1); vfe_hal_reg_write(0xDD0, 0x40430022); vfe_hal_reg_write(0xDE0, 0x5F); vfe_hal_reg_write(0xDF0, 0x800180A6); vfe_hal_reg_write(0xE00, 0x0028A285); } static td_void vfe_calcu_bypass_dpll_cfg2(td_u32 sample_clk, td_u32 *int_mult, td_u32 *post_div1, td_u32 *post_div2) { td_u32 div_index1, div_index2; td_u32 best_post_div1 = 0; td_u32 best_post_div2 = 0; td_u32 temp_diff, temp_apll_clk, temp_frac; td_u32 min_diff = VFE_U32_MAX; td_u32 best_int_apll_clk = 0; for (div_index1 = 1; div_index1 <= VFE_APLL_POST_DIV_MAX; div_index1++) { for (div_index2 = 1; div_index2 <= VFE_APLL_POST_DIV_MAX; div_index2++) { temp_apll_clk = sample_clk * div_index1 * div_index2; if ((temp_apll_clk < 1500000) || (temp_apll_clk > 2800000)) { /* clock min value 1500000, max 2800000 */ continue; } temp_frac = temp_apll_clk % VFE_CRYSTAL_FREQ; temp_diff = 2800000 - temp_apll_clk; /* max clock value 2800000 */ if (temp_frac == 0 && temp_diff < min_diff) { min_diff = temp_diff; best_int_apll_clk = temp_apll_clk; best_post_div1 = div_index1; best_post_div2 = div_index2; } } } *int_mult = best_int_apll_clk / VFE_CRYSTAL_FREQ; *post_div1 = best_post_div1 - 1; *post_div2 = best_post_div2 - 1; soc_dbg_print_u32(*int_mult); soc_dbg_print_u32(*post_div1); soc_dbg_print_u32(*post_div2); vfe_hal_set_fnpll(); return; } static td_void vfe_calcu_bypass_dpll_cfg(td_u32 sample_clk, td_u32 *int_mult, td_u32 *post_div1, td_u32 *post_div2) { ext_chip_name_id name_id = CHIP_NAME_RESERVED13; ext_chip_revision chip_revision = CHIP_REVISION_MAX; td_s32 ret = ext_drv_sys_get_chip_name_id(&name_id); if (ret != TD_SUCCESS) { soc_log_err("ext_drv_sys_get_chip_name_id error \n"); return; } ret = ext_drv_sys_get_chip_revision(&chip_revision); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_drv_sys_get_chip_revision, ret); return; } if ((name_id == CHIP_NAME_RESERVED17 || name_id == CHIP_NAME_RESERVED19 || name_id == CHIP_NAME_HI3751V811) && chip_revision == CHIP_REVISION_C) { vfe_calcu_bypass_dpll_cfg2(sample_clk, int_mult, post_div1, post_div2); } else { vfe_calcu_bypass_dpll_cfg1(sample_clk, int_mult, post_div1, post_div2); } return; } td_s32 vfe_set_no_sig_pll_attr(ext_drv_vfe_pll_attr *pll_attr) { td_s32 ret; td_u32 int_mult = 0; const td_u32 frac_mult = 0; td_u32 post_div1 = 0; td_u32 post_div2 = 0; td_bool dpll_fp_reset, dpll_lpf_reset, apll_coeff_en; td_u32 temp_h_freq; const td_u32 max_h_total = 4095; /* h_total寄存器为12bit最大为4095 */ ret = vfe_check_pll_attr(pll_attr); if (ret != TD_SUCCESS) { soc_log_err(" some attr of pll attr is invalid\n"); return TD_FAILURE; } temp_h_freq = pll_attr->sample_clk / pll_attr->h_total; if (pll_attr->h_total > max_h_total) { pll_attr->sample_clk = pll_attr->sample_clk * max_h_total / pll_attr->h_total; pll_attr->h_total = max_h_total; } vfe_hal_set_apll_bypass(TD_FALSE); /* 复位MPG */ vfe_hal_set_mpg_reset(TD_TRUE); /* pll启动时序要求 */ vfe_hal_set_apll_coeff_en(TD_FALSE); /* DPLL环路处于断开状态,为SDP模式,闭合为CP模式 */ vfe_hal_set_dpll_ff_reset(TD_FALSE); /* ff_rst_n复位 */ vfe_hal_set_apll_power(TD_FALSE, TD_FALSE); /* apll power down */ vfe_hal_set_dpll_lpf_fbdiv_reset(TD_FALSE); /* lpf_fbdiv_rst_n 复位 */ vfe_hal_set_apll_post_out_en(pll_attr->bypass_dpll); /* 选择是否时钟输出是否bypass DPLL,直接通过APLL的POSTDIV输出 */ vfe_calcu_bypass_dpll_cfg(pll_attr->sample_clk, &int_mult, &post_div1, &post_div2); vfe_hal_set_apll_int_cfg(int_mult); vfe_hal_set_apll_frac_cfg(frac_mult); vfe_hal_set_apll_post_div(post_div1, post_div2); vfe_hal_set_dpll_htotal_cfg(VFE_DPLL_DIV_32, pll_attr->h_total); vfe_hal_set_dpll_pdiv_cfg(VFE_DPLL_DIV_64); dpll_fp_reset = TD_TRUE; dpll_lpf_reset = TD_TRUE; apll_coeff_en = TD_FALSE; vfe_hal_set_dpll_ff_reset(dpll_fp_reset); /* ff_rst_n撤销复位 */ vfe_hal_set_apll_power(TD_TRUE, TD_TRUE); /* apll power on */ osal_msleep(5); // sleep for 5 ms vfe_hal_set_apll_coeff_en(apll_coeff_en); /* DPLL环路处于闭合状态则表示为pass dpll */ vfe_hal_set_dpll_lpf_fbdiv_reset(dpll_lpf_reset); /* lpf_fbdiv_rst_n 撤销复位 */ osal_msleep(10); // sleep for 10 ms /* 撤销复位MPG */ vfe_hal_set_mpg_reset(TD_FALSE); osal_msleep(10); // sleep for 10 ms vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_DPLL); return TD_SUCCESS; } td_void drv_vfe_pll_reset(const ext_drv_vfe_pll_attr *pll_attr) { vfe_hal_set_apll_bypass(TD_FALSE); /* 复位MPG */ vfe_hal_set_mpg_reset(TD_TRUE); /* pll启动时序要求 */ vfe_hal_set_apll_coeff_en(TD_FALSE); /* DPLL环路处于断开状态,为SDP模式,闭合为CP模式 */ vfe_hal_set_dpll_ff_reset(TD_FALSE); /* ff_rst_n复位 */ vfe_hal_set_apll_power(TD_FALSE, TD_FALSE); /* apll power down */ vfe_hal_set_dpll_lpf_fbdiv_reset(TD_FALSE); /* lpf_fbdiv_rst_n 复位 */ /* 选择是否时钟输出是否bypass DPLL,直接通过APLL的POSTDIV输出 */ if (pll_attr != TD_NULL) { vfe_hal_set_apll_post_out_en(pll_attr->bypass_dpll); } } td_void drv_vfe_pll_de_reset(td_bool dpll_fp_reset, td_bool dpll_lpf_reset, td_bool apll_coeff_en) { vfe_hal_set_dpll_ff_reset(dpll_fp_reset); /* ff_rst_n撤销复位 */ vfe_hal_set_apll_power(TD_TRUE, TD_TRUE); /* apll power on */ osal_msleep(5); // sleep for 5 ms vfe_hal_set_apll_coeff_en(apll_coeff_en); /* DPLL环路处于闭合状态则表示为pass dpll */ vfe_hal_set_dpll_lpf_fbdiv_reset(dpll_lpf_reset); /* lpf_fbdiv_rst_n 撤销复位 */ vfe_platform_set_rgb_com_chn_adc_reset(); osal_msleep(10); // sleep for 10 ms /* 撤销复位MPG */ vfe_hal_set_mpg_reset(TD_FALSE); osal_msleep(10); // sleep for 10 ms vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_DPLL); } td_void drv_vfe_set_pll_cfg(td_bool *dpll_fp_reset, td_bool *dpll_lpf_reset, td_bool *apll_coeff_en, td_bool flag) { if (dpll_fp_reset == TD_NULL || dpll_lpf_reset == TD_NULL || apll_coeff_en == TD_NULL) { soc_log_err("input null point.\n"); return; } if (flag == TD_FALSE) { *dpll_fp_reset = TD_FALSE; *dpll_lpf_reset = TD_FALSE; *apll_coeff_en = TD_FALSE; } else if (flag == TD_TRUE) { *dpll_fp_reset = TD_TRUE; *dpll_lpf_reset = TD_TRUE; *apll_coeff_en = TD_TRUE; } } td_s32 vfe_set_pll_attr(ext_drv_vfe_pll_attr *pll_attr, td_u32 phase) { td_s32 ret; td_u32 int_mult = 0; td_u32 frac_mult = 0; td_u32 post_div1 = 0; td_u32 post_div2 = 0; td_bool dpll_fp_reset = TD_FALSE; td_bool dpll_lpf_reset = TD_FALSE; td_bool apll_coeff_en = TD_FALSE; vfe_dpll_div_sel dpll_div = VFE_DPLL_DIV_64; td_u32 temp_h_freq; const td_u32 max_h_total = 4095; /* h_total寄存器为12bit最大为4095 */ ret = vfe_check_pll_attr(pll_attr); if (ret != TD_SUCCESS) { soc_log_err(" some attr of pll attr is invalid\n"); return TD_FAILURE; } temp_h_freq = pll_attr->sample_clk / pll_attr->h_total; if (pll_attr->h_total > max_h_total) { pll_attr->sample_clk = pll_attr->sample_clk * max_h_total / pll_attr->h_total; pll_attr->h_total = max_h_total; } drv_vfe_pll_reset(pll_attr); if (pll_attr->bypass_dpll) { soc_log_dbg("PLL set bypass dpll [CVBS MODE]\n"); vfe_calcu_bypass_dpll_cfg(pll_attr->sample_clk, &int_mult, &post_div1, &post_div2); vfe_hal_set_apll_int_cfg(int_mult); vfe_hal_set_apll_frac_cfg(frac_mult); vfe_hal_set_apll_post_div(post_div1, post_div2); drv_vfe_set_pll_cfg(&dpll_fp_reset, &dpll_lpf_reset, &apll_coeff_en, TD_FALSE); } else { soc_log_dbg("PLL set dpll [HDDEC MODE]\n"); vfe_calcu_pass_dpll_cfg(pll_attr->sample_clk, &dpll_div, &int_mult, &frac_mult); vfe_hal_set_apll_int_cfg(int_mult); vfe_hal_set_apll_frac_cfg(frac_mult); if (dpll_div == VFE_DPLL_DIV_32) { dpll_div = VFE_DPLL_DIV_64; } else if (dpll_div == VFE_DPLL_DIV_64) { dpll_div = VFE_DPLL_DIV_32; } vfe_hal_set_dpll_htotal_cfg(dpll_div, pll_attr->h_total); vfe_hal_set_dpll_pdiv_cfg(dpll_div); vfe_hal_platform_set_rg_pll_cfg(); vfe_hal_platform_set_rg_offset_cfg(); /* pll配置会影响相位,需要重新配置一下 */ drv_vfe_set_pll_cfg(&dpll_fp_reset, &dpll_lpf_reset, &apll_coeff_en, TD_TRUE); } drv_vfe_pll_de_reset(dpll_fp_reset, dpll_lpf_reset, apll_coeff_en); return TD_SUCCESS; } static td_void vfe_sync_slicer_init(td_void) { vfe_syncslicer_attr slicer_attr = { 0 }; slicer_attr.sync_clamp = VFE_SYNC_CLAMP_ANALOG; slicer_attr.clamp_level = VFE_SYNC_CLAMP_LEVEL_1_25V; // VFE_SYNC_CLAMP_LEVEL_1_25V, VFE_SYNC_CLAMP_LEVEL_0_95V slicer_attr.slicer_lpf = VFE_SLICER_LPF_OFF; slicer_attr.slicer_ilkg = VFE_SLICER_ILKG_800N_A; // VFE_SLICER_ILKG_0N_A slicer_attr.deglitch = TD_TRUE; // TD_FALSE vfe_hal_set_sync1_slicer(&slicer_attr); vfe_hal_set_slicer1_level(VFE_SLICER_LEVEL_DEF); vfe_hal_set_sync2_slicer(&slicer_attr); vfe_hal_set_slicer2_level(VFE_SLICER_LEVEL_DEF); vfe_hal_set_slicer_power(TD_TRUE, TD_TRUE); vfe_hal_set_hs0_in_cfg(VFE_HS_ROUTE_SEL_SMMIT_TRIGGER, TD_TRUE); vfe_hal_set_hs1_in_cfg(VFE_HS_ROUTE_SEL_SMMIT_TRIGGER, TD_TRUE); vfe_hal_set_vs0_in_cfg(VFE_VS_ROUTE_HDDEC); vfe_hal_set_vs1_in_cfg(VFE_VS_ROUTE_HDDEC); #ifdef CONFIG_SOCT_FPGA_SUPPORT vfe_hal_set_dpll_fre_div_reset(VFE_FRE_DIV_RST_SEL_ASYNC_CTRL, TD_FALSE); #else vfe_hal_set_dpll_fre_div_reset(VFE_FRE_DIV_RST_SEL_VCOAST_CTRL, TD_FALSE); #endif /* equator 时钟正反向 */ vfe_hal_set_cvbs_rgb_pctrl(TD_TRUE, TD_TRUE); vfe_hal_set_polar_out(TD_FALSE, TD_TRUE, TD_FALSE, TD_FALSE); return; } static td_void vfe_power_init(td_void) { vfe_hal_set_v_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_pga_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_TRUE); vfe_hal_set_adc_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); // adc powerdown return; } static td_void vfe_pll_init(td_void) { vfe_hal_set_apll_ref_div(VFE_DEF_REF_DIV); /* APLL输出24_m_hz时钟默认不分频 */ vfe_hal_set_dpll_lock_phase_cfg(VFE_PLL_PHASE_LOCK_THR); /* DPLL 锁定阈值配置信号 */ vfe_hal_set_pll_reserv_init(); /* PLL预留寄存器初始化 */ vfe_hal_set_apll_bypass(TD_TRUE); /* APLL 旁路控制信号为bypass */ vfe_hal_set_apll_post_out_en(TD_TRUE); /* bypass DPLL */ vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_APLL); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_APLL_OUT, VFE_CHN_CLK_APLL_OUT, VFE_CHN_CLK_APLL_OUT); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); vfe_hal_set_dpll_lock_sel(); vfe_hal_set_dpll_pdiv_cfg(VFE_DPLL_DIV_64); vfe_hal_set_apll_four_phase_power(TD_FALSE); /* 不进行四相分频输出 */ vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_EXTER); vfe_hal_rgb_clock_sel(TD_FALSE); return; } static td_void vfe_pga_init(td_void) { /* 初始增益 */ vfe_hal_set_r_chn_gain(VFE_GAIN_DEF); vfe_hal_set_g_chn_gain(VFE_GAIN_DEF); vfe_hal_set_b_chn_gain(VFE_GAIN_DEF); vfe_hal_set_com_chn_gain(VFE_GAIN_DEF); vfe_hal_set_sif_chn_gain(VFE_GAIN_DEF); vfe_platform_set_rgb_chn_offset(); /* 初始偏移 */ vfe_hal_set_com_chn_offset(VFE_OFFSET_DEF); vfe_hal_set_sif_chn_offset(VFE_OFFSET_DEF); return; } static td_void vfe_adc_init(td_void) { /* ADC上电复位时序要求 */ vfe_hal_set_adc_ldo_en(TD_TRUE, VFE_LDO_OUT_VOL_SEL_1_2V); vfe_hal_set_band_gap_power(TD_FALSE); /* bandgap总电源关闭 */ vfe_hal_set_dac_ip_pd(TD_TRUE); vfe_hal_set_adc_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); /* 4个通道的电源关闭 */ osal_msleep(1); vfe_hal_set_adc_power(TD_TRUE, TD_TRUE, TD_TRUE, TD_TRUE); /* 4个通道的电源打开 */ vfe_hal_set_dac_ip_pd(TD_FALSE); vfe_hal_set_band_gap_power(TD_TRUE); /* bandgap总电源关闭 */ vfe_platform_set_sync_slicer_delay(); vfe_hal_set_rgb_com_chn_adc_reset(TD_FALSE); /* RGB通道复位,撤销复位 */ osal_msleep(1); vfe_hal_set_rgb_com_chn_adc_reset(TD_TRUE); osal_msleep(10); // sleep for 10 ms vfe_hal_set_adc_t(2); /* 模拟部推荐值 2 */ return; } td_void vfe_hal_set_apll_cfg(td_void) { // move from vfe_set_pll_attr /* 由于HDDEC能够较准确的获取到行频h_freq计算出clk,对频率的锁定不需要太多约束 */ vfe_hal_set_apll_cfg1(0x00); vfe_hal_set_apll_cfg2(0xc0); vfe_hal_set_apll_cfg3(0x0); vfe_hal_set_apll_cfg4(0x20); vfe_hal_set_apll_cfg5(0x05); vfe_hal_set_apll_cfg6(0xc4); vfe_hal_set_apll_cfg7(0x0, 0x4); } td_void ext_drv_vfe_hal_set_apll(td_void) { vfe_hal_apb_reset(TD_FALSE); vfe_hal_cvbs_srst_req(TD_FALSE); vfe_hal_rgb_srst_req(TD_FALSE); vfe_hal_set_rgb_com_chn_adc_reset(TD_FALSE); vfe_hal_set_dpll_ff_reset(TD_FALSE); vfe_power_init(); vfe_adc_init(); vfe_pll_init(); vfe_sync_slicer_init(); vfe_pga_init(); vfe_hal_set_clamp_init(); vfe_hal_platform_set_pll_tmux1_sel(); vfe_platform_set_vdac_out_chan_sel(); vfe_hal_set_hs_delay(); vfe_hal_set_apll_cfg(); vfe_hal_set_rgb_com_chn_adc_reset(TD_TRUE); vfe_hal_set_adc_res(VFE_ADC_RST_OFF); vfe_hal_set_dac_power(); vfe_hal_set_offset_dac_pd(); vfe_hal_platform_set_chn_fe_cal(); vfe_hal_set_dpll_ff_reset(TD_TRUE); #ifndef CONFIG_SOCT_FPGA_SUPPORT vfe_hal_set_power_down(); #endif } td_s32 drv_vfe_ctx_init(td_void) { td_u32 h_idx; td_u32 idx; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; errno_t err_ret; for (h_idx = 0; h_idx < VFE_WORKMODE_MAX; h_idx++) { idx = (h_idx & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", h_idx); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; err_ret = memset_s(vfe_ctx, sizeof(vfe_drv_ctx), 0, sizeof(vfe_drv_ctx)); if (err_ret != EOK) { soc_log_err("secure func call error\n"); return err_ret; } vfe_ctx->source_attr.src_type = EXT_DRV_HDDEC_SRC_MAX; vfe_ctx->source_attr.work_mode = EXT_DRV_VFE_WORK_MODE_MAX; } return TD_SUCCESS; } td_s32 ext_drv_vfe_init(td_void) { td_s32 ret = TD_SUCCESS; errno_t err_ret; soc_dbg_func_enter(); #ifdef CONFIG_SOCT_FPGA_SUPPORT ret = vfe_hal_fpga_init(); #else ret = vfe_hal_init(); #endif if (ret != TD_SUCCESS) { soc_log_info("call vfe init hailed\n"); return ret; } vfe_platform_init_config(); err_ret = drv_vfe_ctx_init(); if (err_ret != TD_SUCCESS) { return err_ret; } ext_drv_vfe_hal_set_apll(); soc_dbg_func_exit(); return ret; } td_s32 ext_drv_vfe_adc_cal(td_void) { vfe_hal_platform_set_chn_fe_cal(); return TD_SUCCESS; } td_s32 ext_drv_vfe_apll_cfg7(td_u32 apll_cfg1, td_u32 apll_cfg2) { vfe_hal_set_apll_cfg7(apll_cfg1, apll_cfg2); return TD_SUCCESS; } td_s32 ext_drv_vfe_de_init(td_void) { td_u32 h_idx; td_u32 idx; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; errno_t err_ret; soc_dbg_func_enter(); for (h_idx = 0; h_idx < VFE_WORKMODE_MAX; h_idx++) { idx = (h_idx & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", h_idx); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; err_ret = memset_s(vfe_ctx, sizeof(vfe_drv_ctx), 0, sizeof(vfe_drv_ctx)); if (err_ret != EOK) { soc_log_err("secure func call error\n"); return err_ret; } vfe_ctx->source_attr.work_mode = EXT_DRV_VFE_WORK_MODE_MAX; } vfe_power_init(); vfe_hal_set_rgb_com_chn_adc_reset(TD_FALSE); vfe_hal_apb_reset(TD_TRUE); vfe_hal_cvbs_srst_req(TD_TRUE); vfe_hal_rgb_srst_req(TD_TRUE); vfe_hal_set_low_power(); #ifdef CONFIG_SOCT_FPGA_SUPPORT vfe_hal_fpga_deinit(); #else vfe_hal_de_init(); #endif vfe_hal_comm_reg_deinit_cs(); soc_dbg_func_exit(); return TD_SUCCESS; } #ifndef CONFIG_SOCT_FPGA_SUPPORT td_void ext_drv_vfe_re_open_init(td_void) { vfe_power_init(); vfe_pll_init(); vfe_sync_slicer_init(); vfe_hal_set_dac_power(); vfe_hal_set_power_on(); return; } td_s8 ext_drv_vfe_set_power_down(td_void) { vfe_hal_set_power_down(); return TD_SUCCESS; } #endif td_void drv_vfe_set_chn_mux(vfe_drv_ctx_s_ptr vfe_ctx, vfe_chn_mux_sel** mux_param_ptr_array, const ext_drv_vfe_source_attr *source) { td_u32 r_mux1_val = 0; td_u32 g_mux1_val = 0; td_u32 b_mux1_val = 0; vfe_chn_mux_sel *r_chn_mux = TD_NULL; vfe_chn_mux_sel *g_chn_mux = TD_NULL; vfe_chn_mux_sel *b_chn_mux = TD_NULL; if (source == TD_NULL || mux_param_ptr_array == TD_NULL) { soc_log_info("input para invalid at line %d.\n", __LINE__); return; } r_chn_mux = mux_param_ptr_array[0]; g_chn_mux = mux_param_ptr_array[1]; b_chn_mux = mux_param_ptr_array[2]; // array index is 2 vfe_get_rgb_chn_mux1_val(source, &r_mux1_val, &g_mux1_val, &b_mux1_val); r_chn_mux->chn_mux1_p = r_mux1_val; g_chn_mux->chn_mux1_p = g_mux1_val; b_chn_mux->chn_mux1_p = b_mux1_val; r_chn_mux->chn_mux1_n = r_mux1_val; g_chn_mux->chn_mux1_n = g_mux1_val; b_chn_mux->chn_mux1_n = b_mux1_val; vfe_platform_config_chn_mux_n(r_chn_mux, g_chn_mux, b_chn_mux); r_chn_mux->chn_mux2_p = VFE_RCHN_MUX2_NOLPF; r_chn_mux->chn_mux2_n = VFE_RCHN_MUX2_NOLPF; g_chn_mux->chn_mux2_p = VFE_GCHN_MUX2_NOLPF; g_chn_mux->chn_mux2_n = VFE_GCHN_MUX2_NOLPF; b_chn_mux->chn_mux2_p = VFE_BCHN_MUX2_NOLPF; b_chn_mux->chn_mux2_n = VFE_BCHN_MUX2_NOLPF; vfe_platform_check_chn_lpf_mode(vfe_ctx, r_chn_mux, g_chn_mux, b_chn_mux); vfe_hal_set_r_chn_mux(r_chn_mux); vfe_hal_set_g_chn_mux(g_chn_mux); vfe_hal_set_b_chn_mux(b_chn_mux); vfe_hal_set_sog_chn_mux(source->sog_chn_mux); vfe_hal_set_sync_chn_mux(source->sync_chn_mux); vfe_hal_platform_set_mux_4_sdp_selb(); } td_void drv_vfe_update_hddec_cfg(vfe_drv_ctx_s_ptr vfe_ctx, vfe_chn_mux_sel** mux_param_ptr_array, const ext_drv_vfe_source_attr *source, const ext_drv_vfe_pll_mode *pll_mode) { soc_log_dbg("EXT_DRV_VFE_WORK_MODE_HDDEC\n"); if (source == TD_NULL || vfe_ctx == TD_NULL || pll_mode == TD_NULL) { soc_log_info("input para invalid at line %d.\n", __LINE__); return; } vfe_hal_set_adc_res(VFE_ADC_RST_RGB); /* step 1 : confirgure MUX1/MUX2/CLAMP */ vfe_hal_peri_equator_sel(TD_TRUE); vfe_hal_peri_vfe_agc_sel(TD_TRUE); drv_vfe_set_chn_mux(vfe_ctx, mux_param_ptr_array, source); vfe_hal_set_v_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_i_clamp_power(TD_TRUE, TD_TRUE, TD_TRUE, TD_FALSE); /* step 2 : confirgure PLL */ vfe_hal_set_pll_refresh_mode(VFE_REFRESH_BYVS_MODE_DIRECT); vfe_hal_set_phase_refresh_mode(VFE_REFRESH_BYVS_MODE_DIRECT); vfe_hal_set_clock_sel_refresh_mode(VFE_REFRESH_BYVS_MODE_DIRECT); vfe_hal_set_apll_power(TD_TRUE, TD_TRUE); /* POWER ON */ vfe_hal_set_dpll_ff_reset(TD_TRUE); vfe_hal_set_dpll_lpf_fbdiv_reset(TD_TRUE); /* 复位撤销 */ if (*pll_mode == EXT_DRV_VFE_PLL_MODE_HDDEC) { vfe_platform_set_apll_four_phase_power(); vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_EXTER); vfe_hal_set_adc_ofcal_en(TD_FALSE, TD_FALSE, TD_FALSE, TD_TRUE); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_DPLL_OUT); /* VFE_ADCCHN_CLK_SEL_DPLL, vfe_set_pll_attr will set again. */ vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_APLL); } else if (*pll_mode == EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD) { vfe_hal_set_adc_ofcal_en(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); /* VFE_ADCCHN_CLK_SEL_DPLL, vfe_set_pll_attr will set again. */ vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_DPLL); } /* step 3 : confirgure output */ vfe_hal_set_out_put_mode(VFE_OUT_MODE_RGB); /* step 4 : confirgure calibration */ vfe_platform_config_calibration(vfe_ctx->source_attr.work_mode); /* step 5 : store the CTX */ vfe_ctx->source_attr.r_chn_mux = source->r_chn_mux; vfe_ctx->source_attr.g_chn_mux = source->g_chn_mux; vfe_ctx->source_attr.b_chn_mux = source->b_chn_mux; vfe_ctx->source_attr.sog_chn_mux = source->sog_chn_mux; vfe_ctx->source_attr.sync_chn_mux = source->sync_chn_mux; } td_void drv_vfe_tvd_config_pll(const ext_drv_vfe_pll_mode *pll_mode) { td_u32 vfe_two_route; if (pll_mode == TD_NULL) { soc_log_err("input pll_mode is null pointer.\n"); return; } vfe_platform_config_tvd_pll(); vfe_two_route = CFG_VFE_TWO_ROUTE_SUPPORT; if (vfe_two_route) { vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_EXTER); } else { vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_INTER); } if (*pll_mode == EXT_DRV_VFE_PLL_MODE_TVD_CVBS) { vfe_hal_set_adc_ofcal_en(TD_TRUE, TD_TRUE, TD_TRUE, TD_FALSE); vfe_platform_set_rgb_chn_clk_sel(); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_APLL); } else if (*pll_mode == EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD) { vfe_hal_set_adc_ofcal_en(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_DPLL); } return; } td_void drv_vfe_update_tvd_cfg(vfe_drv_ctx_s_ptr vfe_ctx, vfe_chn_mux_sel** mux_param_ptr_array, const ext_drv_vfe_source_attr *source, const ext_drv_vfe_pll_mode *pll_mode) { td_u32 cvbs_mux1_val; vfe_chn_mux_sel *com_chn_mux = TD_NULL; if ((vfe_ctx == TD_NULL) || (mux_param_ptr_array == TD_NULL) || (source == TD_NULL) || (pll_mode == TD_NULL)) { soc_log_err("input null pointer.\n"); return; } com_chn_mux = mux_param_ptr_array[3]; // array index is 3 soc_log_dbg("EXT_DRV_VFE_WORK_MODE_TVD\n"); vfe_hal_set_adc_res(VFE_ADC_RST_CVBS); /* step 1 : confirgure MUX1/MUX2/CLAMP */ vfe_hal_peri_equator_sel(TD_FALSE); vfe_hal_peri_vfe_agc_sel(TD_TRUE); vfe_hal_sys_vfe_apb_rst_req(TD_FALSE); vfe_hal_sys_vfe_cvbs_mode(TD_FALSE); vfe_hal_fir_bypass(0); vfe_get_cvbs_chn_mux1_val(source->cvbs_chn_mux, &cvbs_mux1_val); com_chn_mux->chn_mux1_p = cvbs_mux1_val; vfe_platform_set_com_chn_mux_cfg(com_chn_mux); vfe_hal_set_com_chn_mux(com_chn_mux); // add this since for reserved9 vfe_hal_platform_set_dig_ana2_and_ana7(); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_TRUE); /* step 2 : confirgure PLL */ drv_vfe_tvd_config_pll(pll_mode); /* step 3 : confirgure output */ vfe_hal_set_out_put_mode(VFE_OUT_MODE_G_CVBS); vfe_platform_adc_dig_calib(vfe_ctx->source_attr.work_mode); /* step 4 : store the CTX */ vfe_ctx->source_attr.cvbs_chn_mux = source->cvbs_chn_mux; } td_void drv_vfe_update_tvd_rf_cfg(vfe_drv_ctx_s_ptr vfe_ctx, vfe_chn_mux_sel** mux_param_ptr_array, const ext_drv_vfe_source_attr *source, const ext_drv_vfe_pll_mode *pll_mode) { /* step 1 : confirgure MUX1/MUX2/CLAMP */ td_u32 mux1_val; td_u32 vfe_two_route; vfe_sif_mux_p_sel chn_mux_p; vfe_sif_mux_n_sel chn_mux_n; vfe_chn_mux_sel *r_chn_mux = TD_NULL; vfe_chn_mux_sel *com_chn_mux = TD_NULL; if ((vfe_ctx == TD_NULL) || (mux_param_ptr_array == TD_NULL) || (source == TD_NULL) || (pll_mode == TD_NULL)) { soc_log_err("input null pointer.\n"); return; } r_chn_mux = mux_param_ptr_array[0]; com_chn_mux = mux_param_ptr_array[3]; // array index is 3 soc_log_dbg("EXT_DRV_VFE_WORK_MODE_TVD_RF\n"); vfe_hal_peri_equator_sel(TD_FALSE); vfe_hal_peri_vfe_agc_sel(TD_TRUE); vfe_get_cvbs_chn_mux1_val(source->r_chn_mux, &mux1_val); chn_mux_p = (vfe_sif_mux_p_sel)mux1_val; chn_mux_n = VFE_SIF_MUX_N_SEL_CVBS_VCOM; vfe_get_cvbs_chn_mux1_val(source->r_chn_mux, &mux1_val); com_chn_mux->chn_mux1_p = mux1_val; com_chn_mux->chn_mux2_p = VFE_COMCHN_MUX2_TEST2; com_chn_mux->chn_mux2_n = VFE_COMCHN_MUX2_TEST2; com_chn_mux->chn_mux1_n = VFE_RF_PIN_N; r_chn_mux->chn_mux2_p = VFE_RCHN_MUX2_SIF; r_chn_mux->chn_mux2_n = VFE_RCHN_MUX2_SIF; vfe_hal_set_com_chn_mux(com_chn_mux); vfe_hal_set_sif_chn_mux(chn_mux_p, chn_mux_n, TD_TRUE); vfe_hal_platform_set_dig_ana2_and_ana7(); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_TRUE); /* step 2 : confirgure PLL */ vfe_two_route = CFG_VFE_TWO_ROUTE_SUPPORT; if (vfe_two_route) { vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_EXTER); } else { vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_INTER); } if (*pll_mode == EXT_DRV_VFE_PLL_MODE_TVD_CVBS) { vfe_hal_set_adc_ofcal_en(TD_FALSE, TD_TRUE, TD_TRUE, TD_FALSE); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_SIF_IN, VFE_CHN_CLK_TIEL, VFE_CHN_CLK_SIF_IN); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_SIF); } /* step 3 : confirgure output */ vfe_hal_set_out_put_mode(VFE_OUT_MODE_RGB); // VFE_OUT_MODE_G_CVBS /* step 4 : store the CTX */ vfe_ctx->source_attr.cvbs_chn_mux = source->cvbs_chn_mux; } td_void drv_vfe_tvd_svideo_config_pll(const ext_drv_vfe_pll_mode *pll_mode) { td_u32 vfe_two_route; if (pll_mode == TD_NULL) { soc_log_err("input null pointer.\n"); return; } vfe_hal_set_apll_four_phase_power(TD_TRUE); vfe_hal_set_pll_dsm_pd(TD_TRUE); vfe_two_route = CFG_VFE_TWO_ROUTE_SUPPORT; if (vfe_two_route) { vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_EXTER); } else { vfe_hal_set_sdp_clk_sel(VFE_SDP_CLK_SEL_INTER); } if (*pll_mode == EXT_DRV_VFE_PLL_MODE_TVD_CVBS) { vfe_hal_set_adc_ofcal_en(TD_TRUE, TD_TRUE, TD_TRUE, TD_FALSE); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_APLL_OUT, VFE_CHN_CLK_APLL_OUT, VFE_CHN_CLK_APLL_OUT); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_APLL); } else if (*pll_mode == EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD) { vfe_hal_set_adc_ofcal_en(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_rgb_chn_clk_sel(VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT, VFE_CHN_CLK_DPLL_OUT); vfe_hal_set_com_chn_clk_sel(VFE_CHN_CLK_APLL_OUT); vfe_hal_set_adc_clk_sel(VFE_ADCCHN_CLK_SEL_DPLL); } return; } td_void drv_vfe_update_tvd_svideo_cfg(vfe_drv_ctx_s_ptr vfe_ctx, vfe_chn_mux_sel** mux_param_ptr_array, const ext_drv_vfe_source_attr *source, const ext_drv_vfe_pll_mode *pll_mode) { td_u32 cvbs_mux1_val; vfe_chn_mux_sel *r_chn_mux = TD_NULL; vfe_chn_mux_sel *com_chn_mux = TD_NULL; if ((mux_param_ptr_array == TD_NULL) || (source == TD_NULL) || (pll_mode == TD_NULL)) { soc_log_err("input null pointer.\n"); return; } r_chn_mux = mux_param_ptr_array[0]; com_chn_mux = mux_param_ptr_array[3]; // array index is 3 soc_log_dbg("EXT_DRV_VFE_WORK_MODE_TVD\n"); vfe_hal_platform_set_svideo_adc_res(); /* step 1 : confirgure MUX1/MUX2/CLAMP */ vfe_hal_peri_equator_sel(TD_FALSE); vfe_hal_peri_vfe_agc_sel(TD_TRUE); vfe_hal_sys_vfe_apb_rst_req(TD_FALSE); vfe_hal_sys_vfe_cvbs_mode(TD_FALSE); vfe_hal_fir_bypass(0); vfe_get_cvbs_chn_mux1_val(source->cvbs_chn_mux, &cvbs_mux1_val); com_chn_mux->chn_mux1_p = cvbs_mux1_val; com_chn_mux->chn_mux1_n = VFE_CVBS_PIN_N; vfe_hal_platform_set_chn_mux2_value(com_chn_mux); vfe_hal_set_com_chn_mux(com_chn_mux); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_TRUE); /* step 2 : confirgure PLL */ drv_vfe_tvd_svideo_config_pll(pll_mode); /* step 3 : confirgure output */ vfe_hal_set_out_put_mode(VFE_OUT_MODE_G_CVBS); vfe_hal_set_sc_mux(SC_P_SEL_CVBS1, SC_N_SEL_CVBS_VCOM); vfe_hal_sc_mux_clamp_sel(TD_TRUE); r_chn_mux->chn_mux1_p = VFE_RCHN_MUX3_HANG; r_chn_mux->chn_mux1_n = VFE_RCHN_MUX3_HANG; r_chn_mux->chn_mux2_p = VFE_RCHN_RC_MUX3_SOURCEFFILTER; r_chn_mux->chn_mux2_n = VFE_RCHN_RC_MUX3_SOURCEFFILTER; vfe_hal_set_r_chn_mux(r_chn_mux); vfe_hal_set_com_chn_pga_cap(VFE_PGA_FEEDBACK_CAP_MAX); vfe_hal_set_r_chn_pga_power(TD_TRUE); vfe_hal_set_r_chn_pga_cap(VFE_PGA_FEEDBACK_CAP_MAX); vfe_hal_platform_set_r_chn_gain(); } td_s32 vfe_connect(vfe_drv_ctx_s_ptr vfe_ctx, vfe_chn_mux_sel** mux_param_ptr_array, const ext_drv_vfe_source_attr *source, const ext_drv_vfe_pll_mode *pll_mode) { if (source == TD_NULL || vfe_ctx == TD_NULL) { soc_log_err("input null point.\n"); return TD_FAILURE; } switch (vfe_ctx->source_attr.work_mode) { case EXT_DRV_VFE_WORK_MODE_HDDEC: { drv_vfe_update_hddec_cfg(vfe_ctx, mux_param_ptr_array, source, pll_mode); break; } case EXT_DRV_VFE_WORK_MODE_TVD: { drv_vfe_update_tvd_cfg(vfe_ctx, mux_param_ptr_array, source, pll_mode); break; } case EXT_DRV_VFE_WORK_MODE_TVD_RF: { drv_vfe_update_tvd_rf_cfg(vfe_ctx, mux_param_ptr_array, source, pll_mode); break; } case EXT_DRV_VFE_WORK_MODE_TVD_SVIDEO: { drv_vfe_update_tvd_svideo_cfg(vfe_ctx, mux_param_ptr_array, source, pll_mode); /* step 4 : confirgure calibration */ vfe_platform_adc_dig_calib(vfe_ctx->source_attr.work_mode); /* step 4 : store the CTX */ vfe_ctx->source_attr.cvbs_chn_mux = source->cvbs_chn_mux; break; } default: { soc_log_err("VFE vfe_ctx->source_attr.work_mode = %d error. \n", vfe_ctx->source_attr.work_mode); return TD_FAILURE; } } return TD_SUCCESS; } td_void ext_drv_vfe_invalid_work_mode(const ext_drv_vfe_source_attr *source, ext_drv_vfe_pll_mode *pll_mode, td_u32 h_idx, td_u32 *free_idx) { if (source == TD_NULL || pll_mode == TD_NULL || free_idx == TD_NULL) { soc_log_err("input invalid.\n"); return; } soc_dbg_print_u32(*free_idx); if (*free_idx == VFE_WORKMODE_MAX) { *free_idx = h_idx; } if (*pll_mode == EXT_DRV_VFE_PLL_MODE_BUTT) { switch (source->work_mode) { case EXT_DRV_VFE_WORK_MODE_HDDEC: { soc_log_dbg("set pll mode HDDEC\n"); *pll_mode = EXT_DRV_VFE_PLL_MODE_HDDEC; break; } case EXT_DRV_VFE_WORK_MODE_TVD: { soc_log_dbg("set pll mode TVD_CVBS\n"); *pll_mode = EXT_DRV_VFE_PLL_MODE_TVD_CVBS; break; } case EXT_DRV_VFE_WORK_MODE_TVD_RF: { soc_log_dbg("set pll mode TVD_RF\n"); *pll_mode = EXT_DRV_VFE_PLL_MODE_TVD_RF; break; } case EXT_DRV_VFE_WORK_MODE_TVD_SVIDEO: { soc_log_dbg("set pll mode TVD_SVIDEO\n"); *pll_mode = EXT_DRV_VFE_PLL_MODE_TVD_SVIDEO; break; } default: { soc_log_err("work_mode set error:\n"); soc_err_print_u32(source->work_mode); break; } } } } td_s32 ext_drv_vfe_valid_work_mode(vfe_drv_ctx_s_ptr vfe_ctx, const ext_drv_vfe_source_attr *source, ext_drv_vfe_pll_mode *pll_mode, td_u32 h_idx) { if (vfe_ctx == TD_NULL || source == TD_NULL || pll_mode == TD_NULL) { soc_log_info("input para invalid at line %d.\n", __LINE__); return TD_FAILURE; } soc_dbg_print_u32(h_idx); soc_dbg_print_u32(source->work_mode); if (source->work_mode == EXT_DRV_VFE_WORK_MODE_HDDEC) { if (vfe_ctx->source_attr.work_mode == EXT_DRV_VFE_WORK_MODE_TVD) { soc_log_dbg("VFE work mode set as EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD!\n"); *pll_mode = EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD; } else { soc_log_err("VFE work mode overrun!\n"); return TD_FAILURE; } } else if (source->work_mode == EXT_DRV_VFE_WORK_MODE_TVD) { if (vfe_ctx->source_attr.work_mode == EXT_DRV_VFE_WORK_MODE_HDDEC) { soc_log_dbg("VFE work mode set as EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD!\n"); *pll_mode = EXT_DRV_VFE_PLL_MODE_HDDEC_A_TVD; } else { soc_log_err("VFE work mode overrun!\n"); return TD_FAILURE; } } else if (source->work_mode == EXT_DRV_VFE_WORK_MODE_TVD_SVIDEO) { td_s32 ret; ret = vfe_platform_set_tvd_rf_work_mode(vfe_ctx, pll_mode); return ret; } else if (source->work_mode == EXT_DRV_VFE_WORK_MODE_TVD_RF) { soc_log_err("VFE work mode overrun!\n"); return TD_FAILURE; } else { soc_log_err("invalid source->work_mode = %d!\n", source->work_mode); } return TD_SUCCESS; } td_s32 ext_drv_vfe_check_work_mode(vfe_drv_ctx_s_ptr vfe_ctx, const ext_drv_vfe_source_attr *source, ext_drv_vfe_pll_mode *pll_mode, td_u32 *free_idx) { td_u32 h_idx; td_u32 idx; td_s32 ret; for (h_idx = 0; h_idx < VFE_WORKMODE_MAX; h_idx++) { idx = (h_idx & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", h_idx); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (vfe_ctx == TD_NULL) { soc_log_err("null point vfe_ctx.\n"); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { ext_drv_vfe_invalid_work_mode(source, pll_mode, h_idx, free_idx); } else { ret = ext_drv_vfe_valid_work_mode(vfe_ctx, source, pll_mode, h_idx); if (ret != TD_SUCCESS) { return TD_FAILURE; } } } return TD_SUCCESS; } td_s32 ext_drv_vfe_check_validation(td_u32 free_idx, ext_drv_vfe_pll_mode pll_mode) { if (free_idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE connected work mode over flow!\n"); soc_err_print_u32(free_idx); return TD_FAILURE; } if (pll_mode >= EXT_DRV_VFE_PLL_MODE_BUTT) { soc_log_err("pll_mode set error\n"); soc_err_print_u32(pll_mode); return TD_FAILURE; } return TD_SUCCESS; } td_s32 ext_drv_vfe_do_connect(const ext_drv_vfe_source_attr *source, vfe_drv_ctx_s_ptr vfe_ctx, td_u32 free_idx, ext_drv_vfe_pll_mode pll_mode, vfe_chn_mux_sel** mux_param_ptr_array) { td_s32 ret; td_u32 idx; td_u32 custom_hddec_set_vclamp; vfe_chn_mux_sel *b_chn_mux = TD_NULL; idx = (free_idx & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", free_idx); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (source == TD_NULL || vfe_ctx == TD_NULL) { soc_log_err("input source or vfe_ctx is invalid.\n"); return TD_FAILURE; } vfe_ctx->source_attr.src_type = source->src_type; vfe_ctx->source_attr.work_mode = source->work_mode; ret = vfe_connect(vfe_ctx, mux_param_ptr_array, source, &pll_mode); if (ret != TD_SUCCESS) { soc_log_err("VFE connect failure.\n"); } vfe_hal_set_rgb_com_chn_adc_reset(TD_FALSE); osal_msleep(1); vfe_hal_set_rgb_com_chn_adc_reset(TD_TRUE); custom_hddec_set_vclamp = CFG_CUSTOM_HDDEC_SET_VCLAMP_SUPPORT; if (custom_hddec_set_vclamp) { b_chn_mux = mux_param_ptr_array[2]; // 2: array 2 if (source->work_mode == EXT_DRV_VFE_WORK_MODE_TVD) { /* modify start av black dot */ /* mm 0xf8a22198 0xf */ ext_drv_vfe_cfg_hddec_crg_reg(TD_TRUE); /* mm 0xff2601d8 0x75 */ vfe_hal_set_vs0_in_cfg(VFE_VS_ROUTE_SCT_FB); vfe_hal_set_vs1_in_cfg(VFE_VS_ROUTE_SCT_FB); /* mm 0xff260000 0xf */ b_chn_mux->chn_mux1_p = 0; b_chn_mux->chn_mux1_n = 0; b_chn_mux->chn_mux2_p = VFE_BCHN_MUX2_TESTINP; b_chn_mux->chn_mux2_n = VFE_BCHN_MUX2_TESTINP; vfe_hal_set_b_chn_mux(b_chn_mux); /* mm 0xff260004 0x03 */ vfe_hal_set_bchan_mux(0); /* mm 0xff240080 0x00FF0001 */ ext_drv_hddec_set_vclamp(); /* modify end av black dot */ } } return TD_SUCCESS; } td_s32 ext_drv_vfe_connect(td_handle *vfe, const ext_drv_vfe_source_attr *source) { td_s32 ret; vfe_chn_mux_sel r_chn_mux = { 0 }; vfe_chn_mux_sel g_chn_mux = { 0 }; vfe_chn_mux_sel b_chn_mux = { 0 }; vfe_chn_mux_sel com_chn_mux = { 0 }; vfe_chn_mux_sel* mux_param_ptr_array[4] = { // size 4 (vfe_chn_mux_sel*)&r_chn_mux, (vfe_chn_mux_sel*)&g_chn_mux, (vfe_chn_mux_sel*)&b_chn_mux, (vfe_chn_mux_sel*)&com_chn_mux }; td_u32 free_idx; ext_drv_vfe_pll_mode pll_mode = EXT_DRV_VFE_PLL_MODE_BUTT; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; soc_dbg_func_enter(); if (vfe == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } if (source == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } #ifndef CONFIG_SOCT_FPGA_SUPPORT ext_drv_vfe_re_open_init(); #endif *vfe = TD_INVALID_HANDLE; if (vfe_check_input_attr(source) != TD_SUCCESS) { soc_log_err("some attr of vfe input attr is invalid\n"); return TD_FAILURE; } free_idx = VFE_WORKMODE_MAX; ret = ext_drv_vfe_check_work_mode(vfe_ctx, source, &pll_mode, &free_idx); if (ret != TD_SUCCESS) { return TD_FAILURE; } ret = ext_drv_vfe_check_validation(free_idx, pll_mode); if (ret != TD_SUCCESS) { return TD_FAILURE; } soc_log_dbg("find the vfe index and PLL work mode :\n"); soc_dbg_print_u32(free_idx); soc_dbg_print_u32(pll_mode); *vfe = ((SOC_ID_VFE << 16) | (SOC_ID_VFE << 8) | free_idx); // 16: mv left 16 bits, 8: mv left 8 bits soc_dbg_print_u32(*vfe); ret = ext_drv_vfe_do_connect(source, vfe_ctx, free_idx, pll_mode, mux_param_ptr_array); soc_dbg_func_exit(); return TD_SUCCESS; } td_void ext_drv_vfe_set_power(td_void) { soc_log_dbg("EXT_DRV_VFE_WORK_MODE_HDDEC\n"); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_r_chn_adc_power(TD_FALSE); vfe_hal_set_r_chn_pga_power(TD_FALSE); vfe_hal_set_g_chn_adc_power(TD_FALSE); vfe_hal_set_g_chn_pga_power(TD_FALSE); vfe_hal_set_b_chn_adc_power(TD_FALSE); vfe_hal_set_b_chn_pga_power(TD_FALSE); vfe_hal_set_pll_refresh_mode(VFE_REFRESH_BYVS_MODE_DIRECT); vfe_hal_set_phase_refresh_mode(VFE_REFRESH_BYVS_MODE_DIRECT); vfe_hal_set_clock_sel_refresh_mode(VFE_REFRESH_BYVS_MODE_DIRECT); } td_s32 ext_drv_vfe_set_power_by_mode(vfe_drv_ctx_s_ptr vfe_ctx) { switch (vfe_ctx->source_attr.work_mode) { case EXT_DRV_VFE_WORK_MODE_HDDEC: { ext_drv_vfe_set_power(); break; } case EXT_DRV_VFE_WORK_MODE_TVD: { soc_log_dbg("EXT_DRV_VFE_WORK_MODE_TVD\n"); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_com_chn_adc_power(TD_FALSE); vfe_hal_set_com_chn_pga_power(TD_FALSE); break; } case EXT_DRV_VFE_WORK_MODE_TVD_SVIDEO: { soc_log_dbg("EXT_DRV_VFE_WORK_MODE_TVD\n"); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_com_chn_adc_power(TD_FALSE); vfe_hal_set_com_chn_pga_power(TD_FALSE); break; } case EXT_DRV_VFE_WORK_MODE_TVD_RF: { soc_log_dbg("EXT_DRV_VFE_WORK_MODE_TVD_RF\n"); vfe_hal_set_i_clamp_power(TD_FALSE, TD_FALSE, TD_FALSE, TD_FALSE); vfe_hal_set_com_chn_adc_power(TD_FALSE); vfe_hal_set_com_chn_pga_power(TD_FALSE); break; } default: { soc_log_err("VFE vfe_ctx->source_attr.work_mode = %d error. \n", vfe_ctx->source_attr.work_mode); return TD_FAILURE; } } return TD_SUCCESS; } td_s32 ext_drv_vfe_disconnect(td_handle vfe) { td_u32 idx; td_u32 custom_hddec_set_vclamp; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_s32 ret; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err("work mode is not SIF\n"); soc_err_print_u32(vfe_ctx->source_attr.work_mode); return TD_FAILURE; } ret = ext_drv_vfe_set_power_by_mode(vfe_ctx); if (ret == TD_FAILURE) { return ret; } vfe_hal_platform_reset_part_cfg_by_mode(vfe_ctx->source_attr.work_mode); custom_hddec_set_vclamp = CFG_CUSTOM_HDDEC_SET_VCLAMP_SUPPORT; if (custom_hddec_set_vclamp) { soc_log_dbg("custom_hddec_set_vclamp\n"); if (vfe_ctx->source_attr.work_mode == EXT_DRV_VFE_WORK_MODE_TVD) { /* mm 0xf8a22198 0x70 */ ext_drv_vfe_cfg_hddec_crg_reg(TD_FALSE); /* mm 0xff2601d8 0x70 */ vfe_hal_set_vs0_in_cfg(VFE_VS_ROUTE_HDDEC); vfe_hal_set_vs1_in_cfg(VFE_VS_ROUTE_HDDEC); /* mm 0xff260004 0x33 */ vfe_hal_set_bchan_mux(0x3); } } ret = memset_s(vfe_ctx, sizeof(vfe_drv_ctx), 0, sizeof(vfe_drv_ctx)); if (ret != EOK) { soc_log_err("secure func call error\n"); return ret; } vfe_ctx->source_attr.work_mode = EXT_DRV_VFE_WORK_MODE_MAX; #ifndef CONFIG_SOCT_FPGA_SUPPORT vfe_hal_set_power_down(); vfe_hal_set_adc_res(VFE_ADC_RST_OFF); #endif return TD_SUCCESS; } /* 设置PLL的时钟 */ td_s32 ext_drv_vfe_set_pll_attr(td_handle vfe, ext_drv_vfe_pll_attr *pll_attr) { td_s32 ret; td_u32 idx; td_u32 vfe_two_route; errno_t err_ret; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; vfe_two_route = CFG_VFE_TWO_ROUTE_SUPPORT; if (vfe_two_route) { if (vfe_ctx->source_attr.work_mode != EXT_DRV_VFE_WORK_MODE_HDDEC) { soc_log_dbg("VFE_SUPPORT_TWO_ROUTE: work_mode != EXT_DRV_VFE_WORK_MODE_HDDEC\n"); return TD_SUCCESS; } } ret = vfe_set_pll_attr(pll_attr, vfe_ctx->phase); if (ret != TD_SUCCESS) { soc_log_err("VFE set pll attr failure.\n"); } err_ret = memcpy_s(&vfe_ctx->pll_attr, sizeof(vfe_ctx->pll_attr), pll_attr, sizeof(ext_drv_vfe_pll_attr)); if (err_ret != EOK) { soc_log_err("secure func call error\n"); return err_ret; } if (vfe_ctx->source_attr.work_mode == EXT_DRV_VFE_WORK_MODE_HDDEC) { #ifndef CONFIG_SOCT_FPGA_SUPPORT soc_log_dbg("EXT_VFE_EXTERNAL:set pll refresh mode VFE_REFRESH_BYVS_MODE_VBI\n"); vfe_hal_set_pll_refresh_mode(VFE_REFRESH_BYVS_MODE_VBI); #endif } return TD_SUCCESS; } /* 同步类型选择以及外同步和复合同步是否极性反向 */ td_s32 ext_drv_vfe_set_sync_type(td_handle vfe, ext_drv_vfe_sync_type sync_type, td_bool sep_sync_inv) { vfe_pll_sync_sel en_pll_sync_sel; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (sync_type >= EXT_DRV_VFE_SYNC_MAX) { soc_log_err("invalid sync type :\n"); soc_err_print_u32(sync_type); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set sync type when vfe not connected !\n"); return TD_FAILURE; } en_pll_sync_sel = VFE_PLL_SYNC_SEL_SLICER0; if (sync_type == EXT_DRV_VFE_SYNC_SEP) { if (vfe_ctx->source_attr.sync_chn_mux == EXT_DRV_INPUT_MUX_SYNC_HVS0) { soc_func_trace_low_freq_cnt_begin(1000); // 1000: input freq value soc_log_dbg("pll_sync_sel set as VFE_PLL_SYNC_SEL_HS0\n"); soc_func_trace_low_freq_cnt_end(); en_pll_sync_sel = VFE_PLL_SYNC_SEL_HS0; } else { soc_func_trace_low_freq_cnt_begin(1000); // 1000: input freq value soc_log_dbg("pll_sync_sel set as VFE_PLL_SYNC_SEL_HS1\n"); soc_func_trace_low_freq_cnt_end(); en_pll_sync_sel = VFE_PLL_SYNC_SEL_HS1; } } vfe_hal_set_sync_type(en_pll_sync_sel, vfe_ctx->source_attr.src_type); vfe_hal_set_polar_out(TD_TRUE, sep_sync_inv, TD_TRUE, TD_FALSE); vfe_ctx->dpll_sync_sel = sync_type; return TD_SUCCESS; } td_s32 ext_drv_vfe_set_gain(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, td_u32 gain) { vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (gain >= VFE_GAIN_MAX) { soc_log_err("invalid gain value :\n"); soc_err_print_u32(gain); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set gain when vfe not connected !\n"); soc_err_print_u32(vfe_ctx->source_attr.work_mode); return TD_FAILURE; } switch (data_chn) { case EXT_DRV_VFE_DATA_CHN_R: { vfe_hal_set_r_chn_gain(gain); break; } case EXT_DRV_VFE_DATA_CHN_G: { vfe_hal_set_g_chn_gain(gain); break; } case EXT_DRV_VFE_DATA_CHN_B: { vfe_hal_set_b_chn_gain(gain); break; } case EXT_DRV_VFE_DATA_CHN_COM: { vfe_hal_set_com_chn_gain(gain); break; } default: { soc_log_err("invalid data channel value :\n"); soc_err_print_u32(data_chn); return TD_FAILURE; } } return TD_SUCCESS; } td_s32 ext_drv_vfe_get_gain(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, td_u32 *gain) { vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (gain == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } switch (data_chn) { case EXT_DRV_VFE_DATA_CHN_R: { vfe_hal_get_r_chn_gain(gain); break; } case EXT_DRV_VFE_DATA_CHN_G: { vfe_hal_get_g_chn_gain(gain); break; } case EXT_DRV_VFE_DATA_CHN_B: { vfe_hal_get_b_chn_gain(gain); break; } case EXT_DRV_VFE_DATA_CHN_COM: { vfe_hal_get_com_chn_gain(gain); break; } default: { soc_log_err("invalid data channel value :\n"); soc_err_print_u32(data_chn); return TD_FAILURE; } } return TD_SUCCESS; } td_s32 ext_drv_vfe_set_offset(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, td_u32 offset) { vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (offset > VFE_OFFSET_MAX) { soc_log_err("invalid offset value :\n"); soc_err_print_u32(offset); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set offset when vfe not connected !\n"); return TD_FAILURE; } switch (data_chn) { case EXT_DRV_VFE_DATA_CHN_R: { vfe_hal_set_r_chn_offset(offset); break; } case EXT_DRV_VFE_DATA_CHN_G: { vfe_hal_set_g_chn_offset(offset); break; } case EXT_DRV_VFE_DATA_CHN_B: { vfe_hal_set_b_chn_offset(offset); break; } case EXT_DRV_VFE_DATA_CHN_COM: { vfe_hal_set_com_chn_offset(offset); break; } default: { soc_log_err("invalid data channel value :\n"); soc_err_print_u32(data_chn); return TD_FAILURE; } } return TD_SUCCESS; } td_s32 ext_drv_vfe_get_offset(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, td_u32 *offset) { vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (offset == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } switch (data_chn) { case EXT_DRV_VFE_DATA_CHN_R: { vfe_hal_get_r_chn_offset(offset); break; } case EXT_DRV_VFE_DATA_CHN_G: { vfe_hal_get_g_chn_offset(offset); break; } case EXT_DRV_VFE_DATA_CHN_B: { vfe_hal_get_b_chn_offset(offset); break; } case EXT_DRV_VFE_DATA_CHN_COM: { vfe_hal_get_com_chn_offset(offset); break; } default: { soc_log_err("invalid data channel value :\n"); soc_err_print_u32(data_chn); return TD_FAILURE; } } return TD_SUCCESS; } td_s32 ext_drv_vfe_get_sif_gain(td_handle vfe, td_u32 *sif_gain) { vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (sif_gain == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode != EXT_DRV_VFE_WORK_MODE_TVD_RF) { soc_log_err("work mode = %d is not SIF\n", vfe_ctx->source_attr.work_mode); return TD_FAILURE; } vfe_hal_get_sif_chn_gain(sif_gain); return TD_SUCCESS; } /* 设置htotal(采样时钟) */ td_s32 ext_drv_vfe_set_htotal(td_handle vfe, td_u32 htotal) { vfe_dpll_div_sel dpll_div; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; vfe_hal_set_apll_cfg7(0, 0); vfe_hal_get_dpll_pdiv_cfg(&dpll_div); vfe_hal_set_dpll_htotal_cfg(dpll_div, htotal); osal_msleep(20); // sleep for 20 ms vfe_ctx->pll_attr.h_total = htotal; return TD_SUCCESS; } td_s32 ext_drv_vfe_set_phase(td_handle vfe, td_u32 phase) { vfe_dpll_div_sel dpll_div; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (phase >= VFE_PHASE_MAX) { soc_log_err("invalid phase value :\n"); soc_err_print_u32(phase); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set phase when vfe not connected !\n"); return TD_FAILURE; } vfe_hal_get_dpll_pdiv_cfg(&dpll_div); vfe_hal_set_phase(dpll_div, phase); vfe_ctx->phase = phase; return TD_SUCCESS; } td_void ext_drv_vfe_set_r_chn_clamp(const ext_drv_vfe_clamp_attr *clamp) { if (clamp == TD_NULL) { soc_log_err("input clamp is null!\n"); return; } if (clamp->clamp_type == EXT_DRV_VFE_CLAMP_V) { vfe_hal_set_r_chn_v_clamp(&clamp->vclamp_attr); } else { vfe_hal_set_r_chn_i_clamp(&clamp->iclamp_attr); } } td_void ext_drv_vfe_set_g_chn_clamp(const ext_drv_vfe_clamp_attr *clamp) { if (clamp == TD_NULL) { soc_log_err("input clamp is null!\n"); return; } if (clamp->clamp_type == EXT_DRV_VFE_CLAMP_V) { vfe_hal_set_g_chn_v_clamp(&clamp->vclamp_attr); } else { vfe_hal_set_g_chn_i_clamp(&clamp->iclamp_attr); } } td_void ext_drv_vfe_set_b_chn_clamp(const ext_drv_vfe_clamp_attr *clamp) { if (clamp == TD_NULL) { soc_log_err("input clamp is null!\n"); return; } if (clamp->clamp_type == EXT_DRV_VFE_CLAMP_V) { vfe_hal_set_b_chn_v_clamp(&clamp->vclamp_attr); } else { vfe_hal_set_b_chn_i_clamp(&clamp->iclamp_attr); } } td_s32 ext_drv_vfe_set_cvbs_clamp(const ext_drv_vfe_clamp_attr *clamp) { if (clamp == TD_NULL) { soc_log_err("clamp is invalid!\n"); return TD_FAILURE; } if (clamp->clamp_type == EXT_DRV_VFE_CLAMP_V) { soc_log_err("please chose i clamp!\n"); return TD_FAILURE; } else { vfe_hal_set_com_chn_i_clamp(&clamp->iclamp_attr); } return TD_SUCCESS; } td_s32 ext_drv_vfe_set_clamp_by_chn(vfe_drv_ctx_s_ptr vfe_ctx, const ext_drv_vfe_clamp_attr *clamp, ext_drv_vfe_data_chn_type data_chn) { td_s32 ret; if (vfe_ctx == TD_NULL) { soc_log_err("invaliad para vfe_ctx\n"); return TD_FAILURE; } if (data_chn == EXT_DRV_VFE_DATA_CHN_R) { ext_drv_vfe_set_r_chn_clamp(clamp); ret = memcpy_s(&vfe_ctx->r_chn_clamp, sizeof(vfe_ctx->r_chn_clamp), clamp, sizeof(ext_drv_vfe_clamp_attr)); if (ret != EOK) { soc_log_err("secure func call error\n"); return ret; } } else if (data_chn == EXT_DRV_VFE_DATA_CHN_G) { ext_drv_vfe_set_g_chn_clamp(clamp); ret = memcpy_s(&vfe_ctx->g_chn_clamp, sizeof(vfe_ctx->g_chn_clamp), clamp, sizeof(ext_drv_vfe_clamp_attr)); if (ret != EOK) { soc_log_err("secure func call error\n"); return ret; } } else if (data_chn == EXT_DRV_VFE_DATA_CHN_B) { ext_drv_vfe_set_b_chn_clamp(clamp); ret = memcpy_s(&vfe_ctx->b_chn_clamp, sizeof(vfe_ctx->b_chn_clamp), clamp, sizeof(ext_drv_vfe_clamp_attr)); if (ret != EOK) { soc_log_err("secure func call error\n"); return ret; } } else if (data_chn == EXT_DRV_VFE_DATA_CHN_COM) { ret = ext_drv_vfe_set_cvbs_clamp(clamp); if (ret != TD_SUCCESS) { return TD_FAILURE; } ret = memcpy_s(&vfe_ctx->com_chn_clamp, sizeof(vfe_ctx->com_chn_clamp), clamp, sizeof(ext_drv_vfe_clamp_attr)); if (ret != EOK) { soc_log_err("secure func call error\n"); return ret; } } else { soc_log_err("invalid data channel value :\n"); soc_err_print_u32(data_chn); return TD_FAILURE; } return TD_SUCCESS; } /* iclamp和vclamp */ td_s32 ext_drv_vfe_set_clamp(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, const ext_drv_vfe_clamp_attr *clamp) { td_s32 ret; td_u32 idx; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; if (clamp == TD_NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; ret = vfe_check_clamp_attr(clamp); if (ret != TD_SUCCESS) { soc_log_err(" some attr of clamp attr is invalid\n"); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set clamp attr when vfe not connected !\n"); return TD_FAILURE; } ret = ext_drv_vfe_set_clamp_by_chn(vfe_ctx, clamp, data_chn); if (ret != TD_SUCCESS) { return ret; } return TD_SUCCESS; } /* 在标准信号时保持默认值,非标讯号可微调slicer level,一共16档范围为0-32,目前只能使用通道0 */ td_s32 ext_drv_vfe_set_slicer_level(td_handle vfe, ext_drv_vfe_sync_chn_type sync_chn, td_u32 level) { td_u32 temp_lev; td_u32 idx; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (level > VFE_SLICER_LEVEL_MAX) { soc_log_err("invalid slicer level value :\n"); soc_err_print_u32(level); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set slicer level when vfe not connected !\n"); return TD_FAILURE; } temp_lev = VFE_SLICER_LEVEL_MAX - level; switch (sync_chn) { case EXT_DRV_VFE_SYNC_CHN_1: { vfe_hal_set_slicer1_level(temp_lev); break; } case EXT_DRV_VFE_SYNC_CHN_2: { vfe_hal_set_slicer2_level(temp_lev); break; } default: { soc_log_err("invalid sync channel value :\n"); soc_err_print_u32(sync_chn); return TD_FAILURE; } } return TD_SUCCESS; } td_s32 ext_drv_vfe_get_slicer_level(td_handle vfe, ext_drv_vfe_sync_chn_type sync_chn, td_u32 *level) { td_u32 temp_lev = 0; td_u32 idx; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (level == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } switch (sync_chn) { case EXT_DRV_VFE_SYNC_CHN_1: { vfe_hal_get_slicer1_level(&temp_lev); break; } case EXT_DRV_VFE_SYNC_CHN_2: { vfe_hal_get_slicer2_level(&temp_lev); break; } default: { soc_log_err("invalid sync channel value :\n"); soc_err_print_u32(sync_chn); return TD_FAILURE; } } *level = VFE_SLICER_LEVEL_MAX - temp_lev; return TD_SUCCESS; } td_s32 ext_drv_vfe_set_lpf_by_chan(vfe_drv_ctx_s_ptr vfe_ctx, ext_drv_vfe_data_chn_type data_chn, const ext_drv_vfe_lpf_filter_attr *lpf_attr) { td_s32 ret; if (vfe_ctx == TD_NULL || lpf_attr == TD_NULL) { soc_log_err("input null pointer.\n"); return TD_FAILURE; } switch (data_chn) { case EXT_DRV_VFE_DATA_CHN_R: if (vfe_ctx->source_attr.work_mode == EXT_DRV_VFE_WORK_MODE_TVD_RF) { soc_log_err(" EXT_DRV_VFE_WORK_MODE_TVD_RF can't set LPF!\n"); } else { vfe_hal_set_r_chn_lpf(lpf_attr->rgb_chn_lpf_mode); // SIF通道不能调整滤波系数 vfe_ctx->r_chn_lpf_mode = lpf_attr->rgb_chn_lpf_mode; } break; case EXT_DRV_VFE_DATA_CHN_G: vfe_hal_set_g_chn_lpf(lpf_attr->rgb_chn_lpf_mode); vfe_ctx->g_chn_lpf_mode = lpf_attr->rgb_chn_lpf_mode; break; case EXT_DRV_VFE_DATA_CHN_B: vfe_hal_set_b_chn_lpf(lpf_attr->rgb_chn_lpf_mode); vfe_ctx->b_chn_lpf_mode = lpf_attr->rgb_chn_lpf_mode; break; case EXT_DRV_VFE_DATA_CHN_COM: vfe_hal_set_com_chn_filter(&lpf_attr->com_chn_filter); ret = memcpy_s(&vfe_ctx->com_chn_filter, sizeof(vfe_ctx->com_chn_filter), &lpf_attr->com_chn_filter, sizeof(ext_drv_vfe_filter_attr)); if (ret != EOK) { soc_log_err("secure func call error\n"); return ret; } break; default: soc_err_print_u32(data_chn); return TD_FAILURE; } return TD_SUCCESS; } /* 调整各个通道的滤波的工作模式 */ td_s32 ext_drv_vfe_set_lpf_attr(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, const ext_drv_vfe_lpf_filter_attr *lpf_attr) { td_s32 ret; td_u32 idx; vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (lpf_attr == NULL) { soc_log_err("NULL point \n"); return TD_FAILURE; } if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err(" can't set lpf attr when vfe not connected !\n"); return TD_FAILURE; } ret = vfe_check_lpf_attr(lpf_attr); if (ret != TD_SUCCESS) { soc_log_err("some attr of lpf attr is invalid \n"); return TD_FAILURE; } ret = ext_drv_vfe_set_lpf_by_chan(vfe_ctx, data_chn, lpf_attr); if (ret != TD_SUCCESS) { return ret; } return TD_SUCCESS; } td_s32 drv_vfe_check_ctx_workmode(td_handle vfe) { vfe_drv_ctx_s_ptr vfe_ctx = TD_NULL; td_u32 idx; idx = (vfe & 0xFF); if (idx >= VFE_WORKMODE_MAX) { soc_log_err("VFE handle(%#x) is invalid, vi_id error.\n", vfe); return TD_FAILURE; } vfe_ctx = &g_vfe_drv_ctx[idx]; if (vfe_ctx->source_attr.work_mode >= EXT_DRV_VFE_WORK_MODE_MAX) { soc_log_err("vfe not connected !\n"); return TD_FAILURE; } return TD_SUCCESS; } td_s32 ext_drv_vfe_power_ctrl(td_handle vfe, ext_drv_vfe_data_chn_type data_chn, td_bool enable) { ext_drv_vfe_pll_attr pll_attr; td_s32 ret; if (data_chn == EXT_DRV_VFE_DATA_CHN_DAC) { vfe_hal_set_vdac2_power(enable); soc_log_info("set AVOUT %s\n", enable ? "enable" : "disable"); return TD_SUCCESS; } ret = drv_vfe_check_ctx_workmode(vfe); if (ret != TD_SUCCESS) { soc_log_err(" can't set power ctrl when vfe not connected !\n"); return TD_FAILURE; } pll_attr.bypass_dpll = TD_TRUE; pll_attr.h_total = 856; // set h_total to 856 pll_attr.sample_clk = vfe_platform_get_sample_clk(TD_FALSE); switch (data_chn) { case EXT_DRV_VFE_DATA_CHN_R: vfe_hal_set_r_chn_pga_power(enable); vfe_hal_set_r_chn_adc_power(enable); break; case EXT_DRV_VFE_DATA_CHN_G: vfe_hal_set_g_chn_pga_power(enable); vfe_hal_set_g_chn_adc_power(enable); break; case EXT_DRV_VFE_DATA_CHN_B: vfe_hal_set_b_chn_pga_power(enable); vfe_hal_set_b_chn_adc_power(enable); break; case EXT_DRV_VFE_DATA_CHN_COM: vfe_hal_set_com_chn_pga_power(enable); vfe_hal_set_com_chn_adc_power(enable); break; case EXT_DRV_VFE_DATA_CHN_APLL: vfe_set_no_sig_pll_attr(&pll_attr); break; default: soc_err_print_u32(data_chn); return TD_FAILURE; } return TD_SUCCESS; } td_s32 ext_drv_vfe_set_video_out_gain(td_u32 r_gain, td_u32 i_gain) { soc_func_trace_low_freq_cnt_begin(1000); // 1000: input freq value soc_dbg_print_u32(r_gain); soc_dbg_print_u32(i_gain); soc_func_trace_low_freq_cnt_end(); vfe_hal_set_vdac_gain(r_gain, i_gain); return TD_SUCCESS; } td_s32 ext_drv_vfe_cfg_video_out(ext_drv_vfe_video_out_chn video_out_chn, td_bool enable, ext_drv_source ensource) { switch (video_out_chn) { case EXT_DRV_VFE_VIDEO_OUT_CHN_1: { vfe_hal_set_vdac1_chan_sel(VFE_VDAC1_CHAN_SEL_EXTVDAC1); vfe_hal_set_dac0_clk_en(enable, TD_TRUE); if (ensource == EXT_DRV_SOURCE_ATV) { vfe_hal_set_dac0_cvbs_out(TD_FALSE); } else if (ensource == EXT_DRV_SOURCE_CVBS) { vfe_hal_set_dac0_cvbs_out(TD_TRUE); } vfe_hal_set_vdac2_power(enable); vfe_hal_set_vdac1_power(TD_TRUE); break; } case EXT_DRV_VFE_VIDEO_OUT_CHN_2: { vfe_hal_set_dac1_clk_en(enable, TD_TRUE); vfe_hal_set_vdac2_power(enable); break; } default: { soc_err_print_u32(video_out_chn); return TD_FAILURE; } } return TD_SUCCESS; } td_u32 ext_drv_vfe_get_cvbs_sample_rate(td_void) { return vfe_platform_get_sample_clk(TD_TRUE); } td_void ext_vfe_drv_pm_lowpower_enter(td_void) { vfe_hal_pm_lowpower_enter(); } td_void ext_vfe_drv_pm_lowpower_exit(td_void) { vfe_hal_pm_lowpower_exit(); } EXPORT_SYMBOL(ext_drv_vfe_init); EXPORT_SYMBOL(ext_drv_vfe_de_init); EXPORT_SYMBOL(ext_drv_vfe_adc_cal); EXPORT_SYMBOL(ext_drv_vfe_apll_cfg7); EXPORT_SYMBOL(ext_drv_vfe_connect); EXPORT_SYMBOL(ext_drv_vfe_disconnect); EXPORT_SYMBOL(ext_drv_vfe_set_pll_attr); EXPORT_SYMBOL(ext_drv_vfe_set_sync_type); EXPORT_SYMBOL(ext_drv_vfe_set_gain); EXPORT_SYMBOL(ext_drv_vfe_get_gain); EXPORT_SYMBOL(ext_drv_vfe_set_offset); EXPORT_SYMBOL(ext_drv_vfe_get_offset); EXPORT_SYMBOL(ext_drv_vfe_get_sif_gain); EXPORT_SYMBOL(ext_drv_vfe_set_htotal); EXPORT_SYMBOL(ext_drv_vfe_set_phase); EXPORT_SYMBOL(ext_drv_vfe_set_clamp); EXPORT_SYMBOL(ext_drv_vfe_set_slicer_level); EXPORT_SYMBOL(ext_drv_vfe_get_slicer_level); EXPORT_SYMBOL(ext_drv_vfe_set_lpf_attr); EXPORT_SYMBOL(ext_drv_vfe_power_ctrl); EXPORT_SYMBOL(ext_drv_vfe_set_video_out_gain); EXPORT_SYMBOL(ext_drv_vfe_cfg_video_out);