You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2638 lines
82 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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);