// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
/*#include <mach/am_regs.h>*/

/*#include <mach/am_regs.h>*/

#include <linux/amlogic/media/frame_provider/tvin/tvin.h>
#include <linux/amlogic/media/vout/vclk_serve.h>
#include <linux/amlogic/media/vout/vdac_dev.h>
#include "../tvin_global.h"
#include "../tvin_format_table.h"
#include "tvafe.h"
#include "tvafe_regs.h"
#include "tvafe_cvd.h"
#include "tvafe_debug.h"
#include "tvafe_general.h"
/***************************Local defines**************************/
/* calibration validation function enable/disable */
/* #define TVAFE_ADC_CAL_VALIDATION */

/* edid config reg value */
#define TVAFE_EDID_CONFIG	0x03804050/* 0x03800050 */
#define HHI_ATV_DMD_SYS_CLK_CNTL	0xf3
#define VAFE_CLK_EN				23
#define VAFE_CLK_EN_WIDTH		1
#define VAFE_CLK_SELECT			24
#define VAFE_CLK_SELECT_WIDTH	2

/* TOP */
static const unsigned int cvbs_top_reg_default[][2] = {
	{TVFE_DVSS_MUXCTRL, 0x07000008,},
	{TVFE_DVSS_MUXVS_REF, 0x00000000,},
	{TVFE_DVSS_MUXCOAST_V, 0x00000000,},
	{TVFE_DVSS_SEP_HVWIDTH, 0x00000000,},
	{TVFE_DVSS_SEP_HPARA, 0x00000000,},
	{TVFE_DVSS_SEP_VINTEG, 0x00000000,},
	{TVFE_DVSS_SEP_H_THR, 0x00000000,},
	{TVFE_DVSS_SEP_CTRL, 0x00000000,},
	{TVFE_DVSS_GEN_WIDTH, 0x00000000,},
	{TVFE_DVSS_GEN_PRD, 0x00000000,},
	{TVFE_DVSS_GEN_COAST, 0x00000000,},
	{TVFE_DVSS_NOSIG_PARA, 0x00000000,},
	{TVFE_DVSS_NOSIG_PLS_TH, 0x00000000,},
	/* TVFE_DVSS_NOSIG_PLS_TH */
	{TVFE_DVSS_GATE_H, 0x00000000,},
	{TVFE_DVSS_GATE_V, 0x00000000,},
	{TVFE_DVSS_INDICATOR1, 0x00000000,},
	{TVFE_DVSS_INDICATOR2, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL1, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL2, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL3, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL4, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL5, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL6, 0x00000000,},
	{TVFE_DVSS_MVDET_CTRL7, 0x00000000,},
	{TVFE_SYNCTOP_SPOL_MUXCTRL, 0x00000009,},
	/* TVFE_SYNCTOP_SPOL_MUXCTRL */
	{TVFE_SYNCTOP_INDICATOR1_HCNT, 0x00000000,},
	/* TVFE_SYNCTOP_INDICATOR1_HCNT */
	{TVFE_SYNCTOP_INDICATOR2_VCNT, 0x00000000,},
	/* TVFE_SYNCTOP_INDICATOR2_VCNT */
	{TVFE_SYNCTOP_INDICATOR3, 0x00000000,},
	/* TVFE_SYNCTOP_INDICATOR3 */
	{TVFE_SYNCTOP_SFG_MUXCTRL1, 0x00000000,},
	/* TVFE_SYNCTOP_SFG_MUXCTRL1 */
	{TVFE_SYNCTOP_SFG_MUXCTRL2, 0x00330000,},
	/* TVFE_SYNCTOP_SFG_MUXCTRL2 */
	{TVFE_SYNCTOP_INDICATOR4, 0x00000000,},
	/* TVFE_SYNCTOP_INDICATOR4 */
	{TVFE_SYNCTOP_SAM_MUXCTRL, 0x00082001,},
	/* TVFE_SYNCTOP_SAM_MUXCTRL */
	{TVFE_MISC_WSS1_MUXCTRL1, 0x00000000,},
	/* TVFE_MISC_WSS1_MUXCTRL1 */
	{TVFE_MISC_WSS1_MUXCTRL2, 0x00000000,},
	/* TVFE_MISC_WSS1_MUXCTRL2 */
	{TVFE_MISC_WSS2_MUXCTRL1, 0x00000000,},
	/* TVFE_MISC_WSS2_MUXCTRL1 */
	{TVFE_MISC_WSS2_MUXCTRL2, 0x00000000,},
	/* TVFE_MISC_WSS2_MUXCTRL2 */
	{TVFE_MISC_WSS1_INDICATOR1, 0x00000000,},
	/* TVFE_MISC_WSS1_INDICATOR1 */
	{TVFE_MISC_WSS1_INDICATOR2, 0x00000000,},
	/* TVFE_MISC_WSS1_INDICATOR2 */
	{TVFE_MISC_WSS1_INDICATOR3, 0x00000000,},
	/* TVFE_MISC_WSS1_INDICATOR3 */
	{TVFE_MISC_WSS1_INDICATOR4, 0x00000000,},
	/* TVFE_MISC_WSS1_INDICATOR4 */
	{TVFE_MISC_WSS1_INDICATOR5, 0x00000000,},
	/* TVFE_MISC_WSS1_INDICATOR5 */
	{TVFE_MISC_WSS2_INDICATOR1, 0x00000000,},
	/* TVFE_MISC_WSS2_INDICATOR1 */
	{TVFE_MISC_WSS2_INDICATOR2, 0x00000000,},
	/* TVFE_MISC_WSS2_INDICATOR2 */
	{TVFE_MISC_WSS2_INDICATOR3, 0x00000000,},
	/* TVFE_MISC_WSS2_INDICATOR3 */
	{TVFE_MISC_WSS2_INDICATOR4, 0x00000000,},
	/* TVFE_MISC_WSS2_INDICATOR4 */
	{TVFE_MISC_WSS2_INDICATOR5, 0x00000000,},
	/* TVFE_MISC_WSS2_INDICATOR5 */
	{TVFE_AP_MUXCTRL1, 0x00000000,},
	{TVFE_AP_MUXCTRL2, 0x00000000,},
	{TVFE_AP_MUXCTRL3, 0x00000000,},
	{TVFE_AP_MUXCTRL4, 0x00000000,},
	{TVFE_AP_MUXCTRL5, 0x00000000,},
	{TVFE_AP_INDICATOR1, 0x00000000,},
	{TVFE_AP_INDICATOR2, 0x00000000,},
	{TVFE_AP_INDICATOR3, 0x00000000,},
	{TVFE_AP_INDICATOR4, 0x00000000,},
	{TVFE_AP_INDICATOR5, 0x00000000,},
	{TVFE_AP_INDICATOR6, 0x00000000,},
	{TVFE_AP_INDICATOR7, 0x00000000,},
	{TVFE_AP_INDICATOR8, 0x00000000,},
	{TVFE_AP_INDICATOR9, 0x00000000,},
	{TVFE_AP_INDICATOR10, 0x00000000,},
	{TVFE_AP_INDICATOR11, 0x00000000,},
	{TVFE_AP_INDICATOR12, 0x00000000,},
	{TVFE_AP_INDICATOR13, 0x00000000,},
	{TVFE_AP_INDICATOR14, 0x00000000,},
	{TVFE_AP_INDICATOR15, 0x00000000,},
	{TVFE_AP_INDICATOR16, 0x00000000,},
	{TVFE_AP_INDICATOR17, 0x00000000,},
	{TVFE_AP_INDICATOR18, 0x00000000,},
	{TVFE_AP_INDICATOR19, 0x00000000,},
	{TVFE_BD_MUXCTRL1, 0x00000000,},
	{TVFE_BD_MUXCTRL2, 0x00000000,},
	{TVFE_BD_MUXCTRL3, 0x00000000,},
	{TVFE_BD_MUXCTRL4, 0x00000000,},
	{TVFE_CLP_MUXCTRL1, 0x00000000,},
	{TVFE_CLP_MUXCTRL2, 0x00000000,},
	{TVFE_CLP_MUXCTRL3, 0x00000000,},
	{TVFE_CLP_MUXCTRL4, 0x00000000,},
	{TVFE_CLP_INDICATOR1, 0x00000000,},
	{TVFE_BPG_BACKP_H, 0x00000000,},
	{TVFE_BPG_BACKP_V, 0x00000000,},
	{TVFE_DEG_H, 0x00000000,},
	{TVFE_DEG_VODD, 0x00000000,},
	{TVFE_DEG_VEVEN, 0x00000000,},
	{TVFE_OGO_OFFSET1, 0x00000000,},
	{TVFE_OGO_GAIN1, 0x00000000,},
	{TVFE_OGO_GAIN2, 0x00000000,},
	{TVFE_OGO_OFFSET2, 0x00000000,},
	{TVFE_OGO_OFFSET3, 0x00000000,},
	{TVFE_VAFE_CTRL, 0x00000000,},
	{TVFE_VAFE_STATUS, 0x00000000,},
#ifdef CRYSTAL_25M
	{TVFE_TOP_CTRL, 0x30c4e6c
	/*0xc4f64 0x00004B60*/,},
	/* TVFE_TOP_CTRL */
#else/* 24M */
	{TVFE_TOP_CTRL, 0x30c4f64
	/*0xc4f64 0x00004B60*/,},
	/* TVFE_TOP_CTRL */
#endif
	/*enable in tvafe_dec_open or avdetect avplug in*/
	{TVFE_CLAMP_INTF, 0x00000666,},
	{TVFE_RST_CTRL, 0x00000000,},
	{TVFE_EXT_VIDEO_AFE_CTRL_MUX1, 0x00000000,},
	/* TVFE_EXT_VIDEO_AFE_CTRL_MUX1 */
	{TVFE_EDID_CONFIG, TVAFE_EDID_CONFIG,},
	/* TVFE_EDID_CONFIG */
	{TVFE_EDID_RAM_ADDR, 0x00000000,},
	{TVFE_EDID_RAM_WDATA, 0x00000000,},
	{TVFE_EDID_RAM_RDATA, 0x00000000,},
	{TVFE_APB_ERR_CTRL_MUX1, 0x8fff8fff,},
	/* TVFE_APB_ERR_CTRL_MUX1 */
	{TVFE_APB_ERR_CTRL_MUX2, 0x00008fff,},
	/* TVFE_APB_ERR_CTRL_MUX2 */
	{TVFE_APB_INDICATOR1, 0x00000000,},
	{TVFE_APB_INDICATOR2, 0x00000000,},
	{TVFE_ADC_READBACK_CTRL, 0x80140003,},
	/* TVFE_ADC_READBACK_CTRL */
	{TVFE_ADC_READBACK_INDICATOR, 0x00000000,},
	/* TVFE_ADC_READBACK_INDICATOR */
	{TVFE_INT_CLR, 0x00000000,},
	{TVFE_INT_MSKN, 0x00000000,},
	{TVFE_INT_INDICATOR1, 0x00000000,},
	{TVFE_INT_SET, 0x00000000,},
	/* {TVFE_CHIP_VERSION                      ,0x00000000,}, */
	/* TVFE_CHIP_VERSION */
	{TVFE_FREERUN_GEN_WIDTH, 0x00000000,},/* TVFE_FREERUN_GEN_WIDTH */
	{TVFE_FREERUN_GEN_PRD,  0x00000000,},/* TVFE_FREERUN_GEN_PRD */
	{TVFE_FREERUN_GEN_COAST, 0x00000000,},/* TVFE_FREERUN_GEN_COAST */
	{TVFE_FREERUN_GEN_CTRL, 0x00000000,},/* TVFE_FREERUN_GEN_CTRL */

	{TVFE_AAFILTER_CTRL1,   0x00100000,},
	/* TVFE_AAFILTER_CTRL1 bypass all */
	{TVFE_AAFILTER_CTRL2,   0x00000000,},
	/* TVFE_AAFILTER_CTRL2 */
	{TVFE_AAFILTER_CTRL3,   0x00000000,},
	/* TVFE_AAFILTER_CTRL3 */
	{TVFE_AAFILTER_CTRL4,   0x00000000,},
	/* TVFE_AAFILTER_CTRL4 */
	{TVFE_AAFILTER_CTRL5,   0x00000000,},
	/* TVFE_AAFILTER_CTRL5 */

	{TVFE_SOG_MON_CTRL1,   0x00000000,},/* TVFE_SOG_MON_CTRL1 */
	{TVFE_ADC_READBACK_CTRL1,   0x00000000,},/* TVFE_ADC_READBACK_CTRL1 */
	{TVFE_ADC_READBACK_CTRL2,   0x00000000,},/* TVFE_ADC_READBACK_CTRL2 */
#ifdef CRYSTAL_25M
	{TVFE_AFC_CTRL1,	 0x85730459,},/* TVFE_AFC_CTRL1 */
	{TVFE_AFC_CTRL2,	 0x342fa9ed,},/* TVFE_AFC_CTRL2 */
	{TVFE_AFC_CTRL3,	 0x2a02396,},/* TVFE_AFC_CTRL3 */
	{TVFE_AFC_CTRL4,	 0xfefbff14,},/* TVFE_AFC_CTRL4 */
	{TVFE_AFC_CTRL5,		0x0,},/* TVFE_AFC_CTRL5 */
#else/* for 24M */
	{TVFE_AFC_CTRL1,   0x893904d2,},
	/* TVFE_AFC_CTRL1 */
	{TVFE_AFC_CTRL2,   0xf4b9ac9,},
	/* TVFE_AFC_CTRL2 */
	{TVFE_AFC_CTRL3,   0x1fd8c36,},
	/* TVFE_AFC_CTRL3 */
	{TVFE_AFC_CTRL4,   0x2de6d04f,},
	/* TVFE_AFC_CTRL4 */
	{TVFE_AFC_CTRL5,          0x4,},
	/* TVFE_AFC_CTRL5 */
#endif
	{0xFFFFFFFF, 0x00000000,}
};

static const unsigned int tvafe_pq_reg_trust_table[][2] = {
	/* reg    mask */
	{CVD2_CONTROL1,                     0xff}, /* 0x01 */
	{CVD2_OUTPUT_CONTROL,               0x0f}, /* 0x07 */
	{CVD2_LUMA_CONTRAST_ADJUSTMENT,     0xff}, /* 0x08 */
	{CVD2_LUMA_BRIGHTNESS_ADJUSTMENT,   0xff}, /* 0x09 */
	{CVD2_CHROMA_SATURATION_ADJUSTMENT, 0xff}, /* 0x0a */
	{CVD2_CHROMA_HUE_PHASE_ADJUSTMENT,  0xff}, /* 0x0b */
	{CVD2_REG_87,                       0xc0}, /* 0x87 */
	{CVD2_CHROMA_EDGE_ENHANCEMENT,      0xff}, /* 0xb5 */
	{CVD2_CHROMA_BW_MOTION,             0xff}, /* 0xe8 */
	{CVD2_REG_FA,                       0x80}, /* 0xfa */

	{ACD_REG_1B,                        0x0f000000},
	{ACD_REG_25,                        0xffffffff},
	{ACD_REG_53,                        0xffffffff},
	{ACD_REG_54,                        0xffffffff},
	{ACD_REG_55,                        0xc0fff3ff},
	{ACD_REG_56,                        0x00f00000},
	{ACD_REG_57,                        0x03ff81ff},
	{ACD_REG_58,                        0x8fffffff},
	{ACD_REG_59,                        0xffffffff},
	{ACD_REG_5B,                        0x3ff7ffff},
	{ACD_REG_64,                        0xffffffff},
	{ACD_REG_65,                        0xffffffff},
	{ACD_REG_66,                        0x80000ff0},
	{ACD_REG_6F,                        0xffffffff},
	{ACD_REG_74,                        0xffffffff},
	{ACD_REG_75,                        0x000000ff},
	{ACD_REG_86,                        0xc0000000},
	{ACD_REG_89,                        0x803ff3ff},
	{ACD_REG_8A,                        0x03ff1fff},
	{ACD_REG_8B,                        0x0fffffff},
	{ACD_REG_8C,                        0x0fffffff},
	{ACD_REG_94,                        0xffffffff},
	{ACD_REG_95,                        0xffffffff},
	{ACD_REG_96,                        0xffffffff},
	{ACD_REG_AE,                        0x00000001},
	{ACD_REG_AF,                        0x1f1f007f},

	{0xffffffff,                        0x00000000}, /* ending */
};

static void tvafe_pq_apb_reg_trust_write(unsigned int addr,
		unsigned int mask, unsigned int val)
{
	unsigned int reg, i = 0, size;

	reg = (addr << 2);
	size = sizeof(tvafe_pq_reg_trust_table) / (sizeof(unsigned int) * 2);
	/* check reg trust */
	while (i < size) {
		if (tvafe_pq_reg_trust_table[i][0] == 0xFFFFFFFF) {
			tvafe_pr_info("%s: error: reg 0x%x is out of trust reg!\n",
				__func__, addr);
			return;
		}
		if (reg == tvafe_pq_reg_trust_table[i][0])
			break;
		i++;
	}
	if (i >= size)
		return;

	/* check mask trust */
	if ((mask & tvafe_pq_reg_trust_table[i][1]) != mask) {
		tvafe_pr_info("%s: warning: reg 0x%x mask 0x%x is out of trust mask 0x%x, change to 0x%x!\n",
				__func__, addr, mask,
				tvafe_pq_reg_trust_table[i][1],
				(mask & tvafe_pq_reg_trust_table[i][1]));
		mask &= tvafe_pq_reg_trust_table[i][1];
	}

	if (mask == 0xffffffff)
		W_APB_REG(reg, val);
	else
		W_APB_REG(reg, (R_APB_REG(reg) & (~(mask))) | (val & mask));

	if (tvafe_dbg_print & TVAFE_DBG_NORMAL)
		tvafe_pr_info("%s: apb: Reg0x%x(%u)=0x%x(%u) val=%x(%u) mask=%x(%u)\n",
			__func__, addr, addr,
			(val & mask), (val & mask),
			val, val, mask, mask);

	cvd_reg87_pal = R_APB_REG(CVD2_REG_87);
	acd_166 = R_APB_REG(ACD_REG_66);
}

enum tvafe_adc_ch_e tvafe_port_to_channel(enum tvin_port_e port,
					  struct tvafe_pin_mux_s *pinmux)
{
	enum tvafe_adc_ch_e adc_ch = TVAFE_ADC_CH_NULL;

	if (!IS_TVAFE_SRC(port)) {
		tvafe_pr_info("%s set pin mux error!!!!!.\n", __func__);
		return TVAFE_ADC_CH_NULL;
	}

	adc_ch = (enum tvafe_adc_ch_e)pinmux->pin[port - TVIN_PORT_CVBS0];

	return adc_ch;
}

/*
 * tvafe pin mux setting for input source, cvd2 video position reg setting
 */
int tvafe_adc_pin_mux(enum tvafe_adc_ch_e adc_ch)
{
	if (adc_ch == TVAFE_ADC_CH_NULL) {
		tvafe_pr_info("%s set pin mux error!!!!!.\n", __func__);
		return -1;
	}

	if (adc_ch == TVAFE_ADC_CH_0) {
		W_APB_BIT(TVFE_VAFE_CTRL1, 1,
			  VAFE_IN_SEL_BIT, VAFE_IN_SEL_WID);
		if (tvafe_cpu_type() < TVAFE_CPU_TYPE_TL1)
			W_APB_BIT(TVFE_VAFE_CTRL2, 3, 4, 3);

	} else if (adc_ch == TVAFE_ADC_CH_1) {
		W_APB_BIT(TVFE_VAFE_CTRL1, 2,
			  VAFE_IN_SEL_BIT, VAFE_IN_SEL_WID);
		if (tvafe_cpu_type() < TVAFE_CPU_TYPE_TL1)
			W_APB_BIT(TVFE_VAFE_CTRL2, 5, 4, 3);

	} else if (adc_ch == TVAFE_ADC_CH_2) {
		W_APB_BIT(TVFE_VAFE_CTRL1, 3,
			  VAFE_IN_SEL_BIT, VAFE_IN_SEL_WID);
		W_APB_BIT(TVFE_VAFE_CTRL2, 6, 4, 3);
	} else if (adc_ch == TVAFE_ADC_CH_ATV) {
		/* atv demod data for cvd2 */
		W_APB_REG(TVFE_ATV_DMD_CLP_CTRL, 0x1300010);
		W_APB_BIT(TVFE_VAFE_CTRL2, 6, 4, 3);
	} else {
		tvafe_pr_info("%s set pin mux error!!!!!.\n", __func__);
		return -1;
	}

	tvafe_pr_info("%s set pin mux to adc_ch: %d ok.\n",
		      __func__, (unsigned int)adc_ch);
	return 0;
}

void tvafe_set_regmap(struct am_regs_s *p)
{
	unsigned short i;

for (i = 0; i < p->length; i++) {
	switch (p->am_reg[i].type) {
	case REG_TYPE_PHY:
		if (tvafe_dbg_print & TVAFE_DBG_NORMAL)
			tvafe_pr_info("%s: bus type: phy..\n", __func__);
		break;
	case REG_TYPE_CBUS:
		if (p->am_reg[i].mask == 0xffffffff)
			aml_write_cbus(p->am_reg[i].addr, p->am_reg[i].val);
		else
			aml_write_cbus(p->am_reg[i].addr,
			(aml_read_cbus(p->am_reg[i].addr) &
			(~(p->am_reg[i].mask))) |
			(p->am_reg[i].val & p->am_reg[i].mask));
		if (tvafe_dbg_print & TVAFE_DBG_NORMAL)
			tvafe_pr_info("%s: cbus: Reg0x%x(%u)=0x%x(%u)val=%x(%u)mask=%x(%u)\n",
				__func__, p->am_reg[i].addr, p->am_reg[i].addr,
				(p->am_reg[i].val & p->am_reg[i].mask),
				(p->am_reg[i].val & p->am_reg[i].mask),
				p->am_reg[i].val, p->am_reg[i].val,
				p->am_reg[i].mask, p->am_reg[i].mask);
		break;
	case REG_TYPE_APB:
		tvafe_pq_apb_reg_trust_write(p->am_reg[i].addr,
			p->am_reg[i].mask, p->am_reg[i].val);
		break;
	default:
		if (tvafe_dbg_print & TVAFE_DBG_NORMAL)
			tvafe_pr_info("%s: bus type error!!!bustype = 0x%x................\n",
				__func__, p->am_reg[i].type);
		break;
		}
	}
}

/*
 * tvafe init cvbs setting with pal-i
 */
static void tvafe_set_cvbs_default(struct tvafe_cvd2_s *cvd2,
			struct tvafe_cvd2_mem_s *mem, enum tvin_port_e port)
{
	unsigned int i = 0;

	/**disable auto mode clock**/
	if (tvafe_cpu_type() < TVAFE_CPU_TYPE_TL1)
		W_HIU_REG(HHI_TVFE_AUTOMODE_CLK_CNTL, 0);

	/** enable tv_decoder mem clk **/
	if (tvafe_cpu_type() < TVAFE_CPU_TYPE_TM2_B)
		W_HIU_BIT(HHI_VPU_CLK_CNTL, 1, 28, 1);

	/** write top register **/
	i = 0;
	while (cvbs_top_reg_default[i][0] != 0xFFFFFFFF) {
		W_APB_REG(cvbs_top_reg_default[i][0],
			cvbs_top_reg_default[i][1]);
		i++;
	}
	if (tvafe_cpu_type() >= TVAFE_CPU_TYPE_TL1) {
		if (IS_TVAFE_ATV_SRC(port)) {
			adc_set_filter_ctrl(true, FILTER_ATV_DEMOD, NULL);
		} else if (IS_TVAFE_AVIN_SRC(port)) {
			adc_set_filter_ctrl(true, FILTER_TVAFE, NULL);
		}

#if (defined(CONFIG_AMLOGIC_ADC_DOUBLE_SAMPLING_FOR_CVBS) && defined(CRYSTAL_24M))
		if (!IS_TVAFE_ATV_SRC(port)) {
			W_APB_REG(TVFE_TOP_CTRL, 0x010c4d6c);
			W_APB_REG(TVFE_AAFILTER_CTRL1, 0x00012721);
			W_APB_REG(TVFE_AAFILTER_CTRL2, 0x1304fcfa);
			W_APB_REG(TVFE_AFC_CTRL1, 0x893904d2);
			W_APB_REG(TVFE_AFC_CTRL2, 0x0f4b9ac9);
			W_APB_REG(TVFE_AFC_CTRL3, 0x01fd8c36);
			W_APB_REG(TVFE_AFC_CTRL4, 0x2de6d04f);
			W_APB_REG(TVFE_AFC_CTRL5, 0x00000004);
		} else {
			W_APB_REG(TVFE_AAFILTER_CTRL1, 0x00182222);
			W_APB_REG(TVFE_AAFILTER_CTRL2, 0x252b39c6);
			W_APB_REG(TVFE_AFC_CTRL1, 0x05730459);
			W_APB_REG(TVFE_AFC_CTRL2, 0xf4b9ac9);
			W_APB_REG(TVFE_AFC_CTRL3, 0x1fd8c36);
			W_APB_REG(TVFE_AFC_CTRL4, 0x2de6d04f);
			W_APB_REG(TVFE_AFC_CTRL5, 0x00000004);
		}
#else
		W_APB_REG(TVFE_AAFILTER_CTRL1, 0x00182222);
		W_APB_REG(TVFE_AAFILTER_CTRL2, 0x252b39c6);
		W_APB_REG(TVFE_AFC_CTRL1, 0x05730459);
		W_APB_REG(TVFE_AFC_CTRL2, 0xf4b9ac9);
		W_APB_REG(TVFE_AFC_CTRL3, 0x1fd8c36);
		W_APB_REG(TVFE_AFC_CTRL4, 0x2de6d04f);
		W_APB_REG(TVFE_AFC_CTRL5, 0x00000004);
#endif
	}
	/* init some variables  */
	cvd2->vd_port = port;

	/* set cvd2 default format to pal-i */
	tvafe_cvd2_try_format(cvd2, mem, TVIN_SIG_FMT_CVBS_PAL_I);
}

void tvafe_enable_avout(enum tvin_port_e port, bool enable)
{
	if (tvafe_cpu_type() >= TVAFE_CPU_TYPE_TL1) {
		if (enable) {
			tvafe_clk_gate_ctrl(1);
			if (IS_TVAFE_ATV_SRC(port)) {
#ifdef CONFIG_AMLOGIC_VDAC
				vdac_enable(1, VDAC_MODULE_AVOUT_ATV);
#endif
			} else {
				W_APB_REG(TVFE_ATV_DMD_CLP_CTRL, 0);
#ifdef CONFIG_AMLOGIC_VDAC
				vdac_enable(1, VDAC_MODULE_AVOUT_AV);
#endif
			}
		} else {
#ifdef CONFIG_AMLOGIC_VDAC
			if (IS_TVAFE_ATV_SRC(port))
				vdac_enable(0, VDAC_MODULE_AVOUT_ATV);
			else
				vdac_enable(0, VDAC_MODULE_AVOUT_AV);
#endif
			tvafe_clk_gate_ctrl(0);
		}
	}
}

/*
 * tvafe init the whole module
 */
void tvafe_init_reg(struct tvafe_cvd2_s *cvd2, struct tvafe_cvd2_mem_s *mem,
		    enum tvin_port_e port)
{
	struct tvafe_user_param_s *user_param = tvafe_get_user_param();

	if (IS_TVAFE_SRC(port)) {
#ifdef CRYSTAL_25M
		if (tvafe_cpu_type() < TVAFE_CPU_TYPE_TL1)
			/* can't write !!! */
			W_HIU_REG(HHI_VAFE_CLKIN_CNTL, 0x703);
#endif

#if (defined(CONFIG_AMLOGIC_ADC_DOUBLE_SAMPLING_FOR_CVBS) && defined(CRYSTAL_24M))
		if (!IS_TVAFE_ATV_SRC(port)) {
			W_HIU_REG(HHI_ADC_PLL_CNTL3, 0xa92a2110);
			W_HIU_REG(HHI_ADC_PLL_CNTL4, 0x02973800);
			W_HIU_REG(HHI_ADC_PLL_CNTL, 0x08664220);
			W_HIU_REG(HHI_ADC_PLL_CNTL2, 0x34e0bf80);
			W_HIU_REG(HHI_ADC_PLL_CNTL3, 0x292a2110);
		} else {
#ifdef CONFIG_AMLOGIC_MEDIA_ADC
			if (IS_TVAFE_AVIN_SRC(port)) {
				if (adc_set_pll_cntl(1, ADC_EN_TVAFE, NULL))
					pr_err("%s:ADC_EN_TVAFE fail\n", __func__);
			}
#endif
		}
#else
#ifdef CONFIG_AMLOGIC_MEDIA_ADC
			if (IS_TVAFE_AVIN_SRC(port)) {
				if (adc_set_pll_cntl(1, ADC_EN_TVAFE, NULL))
					pr_err("%s:ADC_EN_TVAFE fail\n", __func__);
			}
#endif
#endif
		tvafe_set_cvbs_default(cvd2, mem, port);
		/*turn on/off av out*/
		tvafe_enable_avout(port, user_param->avout_en);
		/* CDAC_CTRL_RESV2<1>=0 */
	}

	tvafe_pr_info("%s ok.\n", __func__);
}

/*
 * tvafe set APB bus register accessing error exception
 */
void tvafe_set_apb_bus_err_ctrl(void)
{
	W_APB_REG(TVFE_APB_ERR_CTRL_MUX1, 0x8fff8fff);
	W_APB_REG(TVFE_APB_ERR_CTRL_MUX2, 0x00008fff);
}

/*
 * tvafe reset the whole module
 */
static void tvafe_reset_module(void)
{
	pr_info("%s: reset module\n", __func__);
	W_APB_BIT(TVFE_RST_CTRL, 1, ALL_CLK_RST_BIT, ALL_CLK_RST_WID);
	W_APB_BIT(TVFE_RST_CTRL, 0, ALL_CLK_RST_BIT, ALL_CLK_RST_WID);
	/*reset vdin asynchronous fifo*/
	/*for greenscreen on repeatedly power on/off*/
	W_APB_BIT(TVFE_RST_CTRL, 1, SAMPLE_OUT_RST_BIT, SAMPLE_OUT_RST_WID);
	W_APB_BIT(TVFE_RST_CTRL, 0, SAMPLE_OUT_RST_BIT, SAMPLE_OUT_RST_WID);
}

void tvafe_reg_setb(void __iomem *reg, unsigned int value,
		unsigned int _start, unsigned int _len)
{
	writel(((readl(reg) & (~(((1L << _len) - 1) << _start))) |
	       ((value & ((1L << _len) - 1)) << _start)), reg);
}

/*
 * tvafe power control of the module
 */
void tvafe_enable_module(bool enable)
{
	/* enable */

	/* main clk up */
	if (tvafe_cpu_type() >= TVAFE_CPU_TYPE_T5) {
		tvafe_reg_setb(ana_addr, 1, VAFE_CLK_SELECT,
			       VAFE_CLK_SELECT_WIDTH);
		tvafe_reg_setb(ana_addr, 1, VAFE_CLK_EN,
			       VAFE_CLK_EN_WIDTH);
	} else if ((tvafe_cpu_type() >= TVAFE_CPU_TYPE_TL1) &&
		  (tvafe_cpu_type() <= TVAFE_CPU_TYPE_TM2_B)) {
		W_HIU_BIT(HHI_ATV_DMD_SYS_CLK_CNTL, 1,
			  VAFE_CLK_SELECT, VAFE_CLK_SELECT_WIDTH);
		W_HIU_BIT(HHI_ATV_DMD_SYS_CLK_CNTL, 1,
			  VAFE_CLK_EN, VAFE_CLK_EN_WIDTH);
	} else {
		W_HIU_REG(HHI_VAFE_CLKXTALIN_CNTL, 0x100);
		W_HIU_REG(HHI_VAFE_CLKOSCIN_CNTL, 0x100);
		W_HIU_REG(HHI_VAFE_CLKIN_CNTL, 0x100);
		W_HIU_REG(HHI_VAFE_CLKPI_CNTL, 0x100);
		W_HIU_REG(HHI_TVFE_AUTOMODE_CLK_CNTL, 0x100);
	}

	/* T5W add 3d comb clk */
	if (tvafe_cpu_type() >= TVAFE_CPU_TYPE_T5W) {
		vclk_clk_reg_setb(HHI_TVFE_CLK_CNTL, 1, TVFE_CLK_GATE,
				  TVFE_CLK_GATE_WIDTH);
		vclk_clk_reg_setb(HHI_TVFE_CLK_CNTL, 1, TVFE_CLK_SEL,
				  TVFE_CLK_SEL_WIDTH);
	}

	/* tvfe power up */
	W_APB_BIT(TVFE_TOP_CTRL, 1, COMP_CLK_ENABLE_BIT, COMP_CLK_ENABLE_WID);
	W_APB_BIT(TVFE_TOP_CTRL, 1, EDID_CLK_EN_BIT, EDID_CLK_EN_WID);
	W_APB_BIT(TVFE_TOP_CTRL, 1, DCLK_ENABLE_BIT, DCLK_ENABLE_WID);
	W_APB_BIT(TVFE_TOP_CTRL, 1, VAFE_MCLK_EN_BIT, VAFE_MCLK_EN_WID);
	W_APB_BIT(TVFE_TOP_CTRL, 3, TVFE_ADC_CLK_DIV_BIT, TVFE_ADC_CLK_DIV_WID);

	/*reset module*/
	tvafe_reset_module();

	/* disable */
	if (!enable) {
		/* tvfe power down */
		W_APB_BIT(TVFE_TOP_CTRL, 0, COMP_CLK_ENABLE_BIT,
				COMP_CLK_ENABLE_WID);
		W_APB_BIT(TVFE_TOP_CTRL, 0, EDID_CLK_EN_BIT, EDID_CLK_EN_WID);
		W_APB_BIT(TVFE_TOP_CTRL, 0, DCLK_ENABLE_BIT, DCLK_ENABLE_WID);
		W_APB_BIT(TVFE_TOP_CTRL, 0, VAFE_MCLK_EN_BIT, VAFE_MCLK_EN_WID);
		W_APB_BIT(TVFE_TOP_CTRL, 0, TVFE_ADC_CLK_DIV_BIT,
			TVFE_ADC_CLK_DIV_WID);

		/* T5W add 3d comb clk */
		if (tvafe_cpu_type() >= TVAFE_CPU_TYPE_T5W) {
			vclk_clk_reg_setb(HHI_TVFE_CLK_CNTL, 0, TVFE_CLK_GATE,
					  TVFE_CLK_GATE_WIDTH);
			vclk_clk_reg_setb(HHI_TVFE_CLK_CNTL, 0, TVFE_CLK_SEL,
					  TVFE_CLK_SEL_WIDTH);
		}

		/* main clk down */
		if (tvafe_cpu_type() >= TVAFE_CPU_TYPE_T5) {
			tvafe_reg_setb(ana_addr, 0, VAFE_CLK_SELECT,
				       VAFE_CLK_SELECT_WIDTH);
			tvafe_reg_setb(ana_addr, 0, VAFE_CLK_EN,
				       VAFE_CLK_EN_WIDTH);
		} else if ((tvafe_cpu_type() >= TVAFE_CPU_TYPE_TL1) &&
			  (tvafe_cpu_type() <= TVAFE_CPU_TYPE_TM2_B)) {
			W_HIU_BIT(HHI_ATV_DMD_SYS_CLK_CNTL, 0,
				  VAFE_CLK_SELECT, VAFE_CLK_SELECT_WIDTH);
			W_HIU_BIT(HHI_ATV_DMD_SYS_CLK_CNTL, 0,
				  VAFE_CLK_EN, VAFE_CLK_EN_WIDTH);
		} else {
			W_HIU_REG(HHI_VAFE_CLKXTALIN_CNTL, 0);
			W_HIU_REG(HHI_VAFE_CLKOSCIN_CNTL, 0);
			W_HIU_REG(HHI_VAFE_CLKIN_CNTL, 0);
			W_HIU_REG(HHI_VAFE_CLKPI_CNTL, 0);
			W_HIU_REG(HHI_TVFE_AUTOMODE_CLK_CNTL, 0);
		}
	}
}

/*
 * tvafe power control of the module
 */
static void tvafe_top_enable_module(bool enable)
{
	/* disable */
	if (!enable) {
		W_APB_BIT(TVFE_VAFE_CTRL1, 0,
			  VAFE_PGA_EN_BIT, VAFE_PGA_EN_WID);
	}
	W_APB_BIT(TVFE_TOP_CTRL, 0, DCLK_ENABLE_BIT, DCLK_ENABLE_WID);
	tvafe_pr_info("reset module\n");
	W_APB_BIT(TVFE_RST_CTRL, 1, DCLK_RST_BIT, DCLK_RST_WID);
	W_APB_BIT(TVFE_RST_CTRL, 0, DCLK_RST_BIT, DCLK_RST_WID);
}

static void tvafe_top_init_reg(enum tvin_port_e port)
{
	W_APB_BIT(TVFE_TOP_CTRL, 1, DCLK_ENABLE_BIT, DCLK_ENABLE_WID);
	if (IS_TVAFE_AVIN_SRC(port)) {
		if (port == TVIN_PORT_CVBS1)
			W_APB_REG(TVFE_VAFE_CTRL1, 0x0000110e);
		else
			W_APB_REG(TVFE_VAFE_CTRL1, 0x0000210e);
	}
	tvafe_pr_info("%s ok.\n", __func__);
}

void white_pattern_pga_reset(enum tvin_port_e port)
{
	tvafe_top_enable_module(false);
	tvafe_top_init_reg(port);
	W_APB_BIT(TVFE_CLAMP_INTF, 1, CLAMP_EN_BIT, CLAMP_EN_WID);
}

