blob: 3dc4889ed2c4c80d8d50eede1e3c4da6b9aacf36 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* drivers/amlogic/media/enhancement/amvecm/vlock.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
/* media module used media/registers/cpu_version.h since kernel 5.4 */
#include <linux/amlogic/media/registers/cpu_version.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/amvecm/amvecm.h>
#include <linux/amlogic/media/vout/vinfo.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/video_sink/vpp.h>
#include <linux/io.h>
#include <linux/clk.h>
#ifdef CONFIG_AMLOGIC_LCD
#include <linux/amlogic/media/vout/lcd/lcd_notify.h>
#endif
#include "arch/vpp_regs.h"
#include "vlock.h"
#include "amvecm_vlock_regmap.h"
#include "amcm.h"
#include "reg_helper.h"
#include <linux/amlogic/gki_module.h>
/* video lock */
/* 0:off;
* 1:auto enc; VLOCK_MODE_AUTO_ENC
* 2:auto pll;
* 4:manual pll; VLOCK_MODE_MANUAL_PLL
* 8:manual_enc mode(only support lvds/vx1)
*/
enum VLOCK_MD vlock_mode = VLOCK_MODE_MANUAL_ENC;
unsigned int vlock_en;
/*
*0:only support 50->50;60->60;24->24;30->30;
*1:support 24/30/50/60/100/120 mix,such as 50->60;
*/
static unsigned int vlock_adapt;
static unsigned int vlock_dis_cnt_limit = 2;
static unsigned int vlock_delta_limit = 2;
/*limit vlock pll m adj*/
static unsigned int vlock_pll_m_limit = 1;
/*for 24MHZ clock, 50hz input, delta value (10) of(0x3011-0x3012) == 0.001HZ */
static unsigned int vlock_delta_cnt_limit = 10;
/*hdmi support enable default,cvbs support not good,need debug with vlsi*/
static unsigned int vlock_support = VLOCK_SUP_MODE;
static unsigned int vlock_enc_stable_flag;
static unsigned int vlock_pll_stable_cnt;
static unsigned int vlock_pll_adj_limit;
static unsigned int vlock_pll_val_last;
static unsigned int vlock_intput_type;
/* [reg(0x3009) x linemax_num)]>>24 is the limit line of enc mode
* change from 4 to 3,for 4 may cause shake issue for 60.3hz input
*/
static signed int vlock_line_limit = 2;
static signed int vlock_enc_maxtune_line_num = 8;
module_param(vlock_enc_maxtune_line_num, uint, 0664);
MODULE_PARM_DESC(vlock_enc_maxtune_line_num, "\n vlock_enc_maxtune_line_num\n");
static signed int vlock_enc_maxtune_pixel_num = 10;
module_param(vlock_enc_maxtune_pixel_num, uint, 0664);
MODULE_PARM_DESC(vlock_enc_maxtune_pixel_num, "\n vlock_enc_maxtune_pixel_num\n");
static unsigned int vlock_enc_adj_limit;
/* 0x3009 default setting for 2 line(1080p-output) is 0x8000 */
static unsigned int vlock_capture_limit = 0x10000/*0x8000*/;
static unsigned int vlock_debug;
static unsigned int vlock_dynamic_adjust = 1;
static unsigned int hw_clk_ok;
static unsigned int vlock_sync_limit_flag;
static unsigned int vlock_state = VLOCK_STATE_NULL;/*1/2/3:vlock step*/
static enum vframe_source_type_e pre_source_type =
VFRAME_SOURCE_TYPE_OTHERS;
static enum vframe_source_mode_e pre_source_mode =
VFRAME_SOURCE_MODE_OTHERS;
static unsigned int pre_input_freq;
static unsigned int pre_output_freq;
static unsigned int vlock_dis_cnt;
static bool vlock_vmode_changed;
static unsigned int vlock_notify_event = VOUT_EVENT_MODE_CHANGE;
static unsigned int vlock_input_pre;
//static unsigned int pre_hiu_reg_m;
//static unsigned int pre_hiu_reg_frac;
//static signed int pre_enc_max_line;
//static signed int pre_enc_max_pixel;
//static signed int org_enc_line_num;
//static signed int org_enc_pixel_num;
//static unsigned int enc_max_line_addr;
//static unsigned int enc_max_pixel_addr;
//static unsigned int enc_video_mode_addr;
//static unsigned int enc_video_mode_adv_addr;
//static unsigned int enc_max_line_switch_addr;
static unsigned int vlock_dis_cnt_no_vf;
static unsigned int vlock_dis_cnt_no_vf_limit = 5;
static unsigned int vlock_log_cnt;/*cnt base: vlock_log_s*/
static unsigned int vlock_log_size = 60;/*size base: vlock_log_s*/
static unsigned int vlock_log_delta_frac = 100;
static unsigned int vlock_log_delta_ivcnt = 0xff;
static unsigned int vlock_log_delta_ovcnt = 0xff;
static unsigned int vlock_log_delta_vcnt = 0xff;
static unsigned int vlock_log_last_ivcnt;
static unsigned int vlock_log_last_ovcnt;
static unsigned int vlock_log_delta_m;
static unsigned int vlock_log_delta_en;
//static unsigned int hhi_pll_reg_m;
//static unsigned int hhi_pll_reg_frac;
u32 phase_en_after_frqlock;
u32 vlock_ss_en = 1;
static struct stvlock_sig_sts vlock0;
static struct stvlock_sig_sts vlock1;
static struct stvlock_sig_sts vlock2;
static struct stvlock_sig_sts *vlock_tab[VLOCK_ENC_MAX];
#define dprintk(level, fmt, arg...) \
do { \
if ((vlock_debug & VLOCK_DEBUG_INFO) >= level) \
pr_info("vlock: " fmt, ## arg); \
} while (0)
/*static unsigned int hhi_pll_reg_vlock_ctl;*/
module_param(vlock_log_size, uint, 0664);
MODULE_PARM_DESC(vlock_log_size, "\n vlock_log_size\n");
module_param(vlock_log_cnt, uint, 0664);
MODULE_PARM_DESC(vlock_log_cnt, "\n vlock_log_cnt\n");
module_param(vlock_log_delta_frac, uint, 0664);
MODULE_PARM_DESC(vlock_log_delta_frac, "\n vlock_log_delta_frac\n");
module_param(vlock_log_delta_m, uint, 0664);
MODULE_PARM_DESC(vlock_log_delta_m, "\n vlock_log_delta_m\n");
module_param(vlock_log_delta_en, uint, 0664);
MODULE_PARM_DESC(vlock_log_delta_en, "\n vlock_log_delta_en\n");
module_param(vlock_log_delta_ivcnt, uint, 0664);
MODULE_PARM_DESC(vlock_log_delta_ivcnt, "\n vlock_log_delta_ivcnt\n");
module_param(vlock_log_delta_ovcnt, uint, 0664);
MODULE_PARM_DESC(vlock_log_delta_ovcnt, "\n vlock_log_delta_ovcnt\n");
module_param(vlock_log_delta_vcnt, uint, 0664);
MODULE_PARM_DESC(vlock_log_delta_vcnt, "\n vlock_log_delta_vcnt\n");
//static unsigned int vlock_frac;
//module_param(vlock_frac, uint, 0664);
//MODULE_PARM_DESC(vlock_frac, "\n vlock_frac\n");
//static unsigned int vlock_frac_delta;
//module_param(vlock_frac_delta, uint, 0664);
//MODULE_PARM_DESC(vlock_frac_delta, "\n vlock_frac_delta\n");
static unsigned int vlock_latch_en_cnt = 20;
module_param(vlock_latch_en_cnt, uint, 0664);
MODULE_PARM_DESC(vlock_latch_en_cnt, "\n vlock_latch_en_cnt\n");
u32 vlock_tune_sync_on = 1;
module_param(vlock_tune_sync_on, uint, 0664);
MODULE_PARM_DESC(vlock_tune_sync_on, "\n vlock_tune_sync_on\n");
static unsigned int vlock_log_en;
struct vlock_log_s **vlock_log;
//static u16 frc_init_first_flag;
//static signed int err_accum;
//static unsigned int last_i_vsync;
u32 loop0_err_lmt = 0xb800;
u32 loop1_err_lmt = 0x4800;
u32 loop_err_rs = 3;
u32 loop_err_gain = 128;
u32 loop0_en = 2; /*0:off, 1:on 2:auto*/
u32 loop1_en = 1; /*0:off, 1:on 2:auto*/
u32 speed_up_en = 1;
struct reg_map vlock_reg_maps[REG_MAP_END] = {0};
struct vlk_reg_map_tab regmap_tab_tm2[] = {
{.base = 0xff000000, .size = 0x4000},/*vpu*/
{.base = 0xff63c000, .size = 0x0100},/*hiu*/
{.base = 0x00000000, .size = 0x0000},/*anactrl*/
};
struct vlk_reg_map_tab regmap_tab_t7[] = {
{.base = 0xff000000, .size = 0x4000,},/*vpu*/
{.base = 0x00000000, .size = 0x0000,},/*hiu*/
{.base = 0xfe008000, .size = 0x0100,},/*anactrl*/
};
int amvecm_hiu_reg_read(unsigned int reg, unsigned int *val)
{
/**val = readl(amvecm_hiu_reg_base+((reg - 0x1000)<<2));*/
*val = aml_read_hiubus(reg);
/*pr_info("vlock rd hiu reg:0x%x,0x%x\n", (reg - 0x1000), *val);*/
return 0;
}
int amvecm_hiu_reg_write(unsigned int reg, unsigned int val)
{
/*writel(val, (amvecm_hiu_reg_base+((reg - 0x1000)<<2)));*/
/*pr_info("vlock rd hiu reg:0x%x,0x%x\n", (reg - 0x1000), val);*/
aml_write_hiubus(reg, val);
return 0;
}
static int vlock_hiu_reg_wt_bits(unsigned int reg, unsigned int value,
unsigned int start, unsigned int len)
{
unsigned int rd_val;
amvecm_hiu_reg_read(reg, &rd_val);
amvecm_hiu_reg_write(reg, ((rd_val &
~(((1L << (len)) - 1) << (start))) |
(((value) & ((1L << (len)) - 1)) << (start))));
return 0;
}
u32 vlock_read_vpp_reg(u32 reg)
{
return READ_VPP_REG(reg);
}
void vlock_write_vpp_reg(u32 reg, const u32 value)
{
WRITE_VPP_REG(reg, value);
}
u32 vlock_read_vpp_reg_bits(u32 reg, const u32 start, const u32 len)
{
return READ_VPP_REG_BITS(reg, start, len);
}
void vlock_write_vpp_reg_bits(u32 reg, const u32 value, const u32 start, const u32 len)
{
WRITE_VPP_REG_BITS(reg, value, start, len);
}
int vlock_init_reg_map(struct device *dev, struct stvlock_sig_sts *pvlock)
{
int i = 0;
struct vlk_reg_map_tab *regmap;
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7)
regmap = (struct vlk_reg_map_tab *)&regmap_tab_t7;
else
regmap = (struct vlk_reg_map_tab *)&regmap_tab_tm2;
for (i = REG_MAP_VPU; i < REG_MAP_END; i++) {
vlock_reg_maps[i].phy_addr = regmap[i].base;
vlock_reg_maps[i].size = regmap[i].size;
if (vlock_reg_maps[i].phy_addr == 0) {
vlock_reg_maps[i].p = 0;
} else {
vlock_reg_maps[i].p = devm_ioremap(dev,
vlock_reg_maps[i].phy_addr,
vlock_reg_maps[i].size);
if (IS_ERR(vlock_reg_maps[i].p)) {
pr_info("%s id %x map error\n", __func__, i);
return -ENOMEM;
}
}
pr_info("ID:0x%x map phy: 0x%x 0x%p\n", i, vlock_reg_maps[i].phy_addr,
vlock_reg_maps[i].p);
}
return 0;
}
void vlock_write_reg(enum vlock_regmap_e bus, u32 addr, u32 val)
{
if (vlock_reg_maps[bus].p) {
writel(val, vlock_reg_maps[bus].p + addr);
} else {
if (bus == REG_MAP_HIU)
amvecm_hiu_reg_write(addr, val);
else if (bus == REG_MAP_VPU)
WRITE_VPP_REG(addr, val);
}
}
int vlock_read_reg(enum vlock_regmap_e bus, u32 addr)
{
u32 val;
if (vlock_reg_maps[bus].p) {
return readl(vlock_reg_maps[bus].p + addr);
}
if (bus == REG_MAP_HIU) {
amvecm_hiu_reg_read(addr, &val);
return val;
} else if (bus == REG_MAP_VPU) {
return READ_VPP_REG(addr);
}
return 0;
}
static int vlock_reg_wt_bits(enum vlock_regmap_e bus, unsigned int reg, unsigned int value,
unsigned int start, unsigned int len)
{
unsigned int rd_val;
rd_val = vlock_read_reg(bus, reg);
vlock_write_reg(bus, reg, ((rd_val &
~(((1L << (len)) - 1) << (start))) |
(((value) & ((1L << (len)) - 1)) << (start))));
return 0;
}
static unsigned int vlock_reg_rd_bits(enum vlock_regmap_e bus, unsigned int _reg,
unsigned int _start, unsigned int _len)
{
return (vlock_read_reg(bus, _reg) >> (_start)) & ((1L << (_len)) - 1);
}
u32 vlock_get_panel_pll_m(struct stvlock_sig_sts *pvlock)
{
u32 val;
if (!pvlock)
return 0;
if (pvlock->dtdata->vlk_pll_sel == vlock_pll_sel_hdmi) {
amvecm_hiu_reg_read(HHI_HDMI_PLL_CNTL, &val);
} else {
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7) {
if (pvlock->idx == VLOCK_ENC0)
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL0_CNTL0, 0, 8);
else if (pvlock->idx == VLOCK_ENC1)
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL1_CNTL0, 0, 8);
else if (pvlock->idx == VLOCK_ENC2)
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL2_CNTL0, 0, 8);
else
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL0_CNTL0, 0, 8);
} else {
amvecm_hiu_reg_read(pvlock->hhi_pll_reg_m, &val);
}
}
return val;
}
u32 vlock_get_panel_pll_frac(struct stvlock_sig_sts *pvlock)
{
u32 val;
if (!pvlock)
return 0;
if (pvlock->dtdata->vlk_pll_sel == vlock_pll_sel_hdmi) {
amvecm_hiu_reg_read(HHI_HDMI_PLL_CNTL2, &val);
} else {
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7) {
if (pvlock->idx == VLOCK_ENC0)
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL0_CNTL1, 0, 19);
else if (pvlock->idx == VLOCK_ENC1)
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL1_CNTL1, 0, 19);
else if (pvlock->idx == VLOCK_ENC2)
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL2_CNTL1, 0, 19);
else
val =
vlock_reg_rd_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL0_CNTL1, 0, 19);
} else {
amvecm_hiu_reg_read(pvlock->hhi_pll_reg_frac, &val);
}
}
return val;
}
void vlock_set_panel_pll_m(struct stvlock_sig_sts *pvlock, u32 val)
{
#ifdef CONFIG_AMLOGIC_LCD
u32 m = val;
#endif
if (!pvlock)
return;
if (pvlock->dtdata->vlk_pll_sel == vlock_pll_sel_hdmi) {
amvecm_hiu_reg_write(HHI_HDMI_PLL_CNTL, val);
} else {
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7) {
if (pvlock->idx == VLOCK_ENC0)
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL0_CNTL0, val, 0, 8);
else if (pvlock->idx == VLOCK_ENC1)
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL1_CNTL0, val, 0, 8);
else if (pvlock->idx == VLOCK_ENC2)
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL2_CNTL0, val, 0, 8);
else
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL0_CNTL0, val, 0, 8);
}
#ifdef CONFIG_AMLOGIC_LCD
else
lcd_vlock_m_update(pvlock->idx, m);
#endif
}
}
void vlock_set_panel_pll_frac(struct stvlock_sig_sts *pvlock, u32 val)
{
#ifdef CONFIG_AMLOGIC_LCD
u32 frac = val;
#endif
if (!pvlock)
return;
if (pvlock->dtdata->vlk_pll_sel == vlock_pll_sel_hdmi) {
amvecm_hiu_reg_write(HHI_HDMI_PLL_CNTL2, val);
} else {
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7) {
if (pvlock->idx == VLOCK_ENC0)
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL0_CNTL1, val, 0, 19);
else if (pvlock->idx == VLOCK_ENC1)
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL1_CNTL1, val, 0, 19);
else if (pvlock->idx == VLOCK_ENC2)
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL2_CNTL1, val, 0, 19);
else
vlock_reg_wt_bits(REG_MAP_ANACTRL,
ANACTRL_TCON_PLL0_CNTL1, val, 0, 19);
}
#ifdef CONFIG_AMLOGIC_LCD
else
lcd_vlock_frac_update(pvlock->idx, frac);
#endif
}
}
void vlock_set_panel_ss(u32 onoff)
{
#ifdef CONFIG_AMLOGIC_LCD
if (onoff)
lcd_ss_enable(1);
else
lcd_ss_enable(0);
#endif
}
int __attribute__((weak))frc_is_on(void)
{
return 0;
}
static void vlock_tune_sync_frc(u32 frc_vporch_cal)
{
u32 max_lncnt;
u32 max_pxcnt;
u32 frc_v_porch;
max_lncnt = READ_VPP_REG(0x1cbb);
max_pxcnt = READ_VPP_REG(0x1cb0);
frc_v_porch = ((max_lncnt - frc_vporch_cal) <= 1950) ?
frc_vporch_cal : (max_lncnt - 1950);
if ((vlock_debug & VLOCK_DEBUG_FLASH))
pr_info("vlock: %s max_lncnt =%d max_pxcnt =%d frc_v_porch =%d\n",
__func__,
max_lncnt, max_pxcnt, frc_v_porch);
WRITE_VPP_REG(ENCL_SYNC_TO_LINE_EN, (1 << 13) | (max_lncnt - frc_v_porch));
WRITE_VPP_REG(ENCL_SYNC_PIXEL_EN, (1 << 15) | (max_pxcnt - 1));
WRITE_VPP_REG(ENCL_SYNC_LINE_LENGTH, max_lncnt - frc_v_porch - 1);
}
bool vlock_vsync_skip_for_frc(void)
{
int ret = false;
struct stvlock_sig_sts *pvlock;
#ifdef VLOCK_DEBUG_ENC_IDX
pvlock = vlock_tab[VLOCK_DEBUG_ENC_IDX];
#else
pvlock = vlock_tab[VLOCK_ENC0];
#endif
if (!pvlock->dtdata->vlk_ctl_for_frc)
return true;
if (pvlock->dtdata->vlk_ctl_for_frc && pvlock->frame_cnt_in >= 10)
ret = true;
return ret;
}
int vlock_sync_frc_vporch(struct stvlock_frc_param frc_param)
{
int ret = -1;
struct stvlock_sig_sts *pvlock;
#ifdef VLOCK_DEBUG_ENC_IDX
pvlock = vlock_tab[VLOCK_DEBUG_ENC_IDX];
#else
pvlock = vlock_tab[VLOCK_ENC0];
#endif
if (!pvlock)
return ret;
if (pvlock->dtdata->vlk_ctl_for_frc) {
if (pvlock->fsm_sts == VLOCK_STATE_ENABLE_STEP1_DONE ||
pvlock->fsm_sts == VLOCK_STATE_ENABLE_STEP2_DONE) {
pvlock->enc_frc_v_porch = frc_param.frc_v_porch;
pvlock->enc_frc_max_line = frc_param.max_lncnt;
pvlock->enc_frc_max_pixel = frc_param.max_pxcnt;
pr_info("vlock: vlock not done, is locking ..., frc set max lncnt and ma px cnt!");
ret = 0;
} else {
pr_info("vlock: vlock is NULL or Disable, frc set max lncnt and ma px cnt!");
vlock_tune_sync_frc(frc_param.frc_v_porch);
ret = 0;
}
} else {
pr_info("vlock: vlk_ctl_for_frc = 0 no need vlock avoid flash patch!!!");
vlock_tune_sync_frc(frc_param.frc_v_porch);
ret = 0;
}
return ret;
}
EXPORT_SYMBOL(vlock_sync_frc_vporch);
static void vlock_tune_sync(struct stvlock_sig_sts *pvlock)
{
u32 offset_enc = pvlock->offset_encl;
if (pvlock->dtdata->vlk_chip == vlock_chip_t3 && pvlock->idx == VLOCK_ENC0) {
if (vlock_tune_sync_on) {
/* MEMC 4K ENCL setting, vlock will change the ENCL_VIDEO_MAX_LNCNT,
* so need dynamic change this register
*/
u32 frc_v_porch = pvlock->enc_frc_v_porch;
u32 max_lncnt = pvlock->enc_frc_max_line;
u32 max_pxcnt = pvlock->enc_frc_max_pixel;
if ((vlock_debug & VLOCK_DEBUG_FLASH))
pr_info("vlock: frc_v_porch =%d max_lncnt =%d max_pxcnt =%d\n",
frc_v_porch, max_lncnt, max_pxcnt);
if (!frc_is_on())
return;
/*shdow register*/
WRITE_VPP_REG(ENCL_SYNC_TO_LINE_EN, (1 << 13) | (max_lncnt - frc_v_porch));
WRITE_VPP_REG(ENCL_SYNC_PIXEL_EN, (1 << 15) | (max_pxcnt - 1));
WRITE_VPP_REG(ENCL_SYNC_LINE_LENGTH, max_lncnt - frc_v_porch - 1);
pvlock->enc_frc_max_line =
READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
pvlock->enc_frc_max_pixel =
READ_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc);
pvlock->enc_frc_v_porch =
READ_VPP_REG(pvlock->enc_frc_v_porch_addr + offset_enc);
if ((vlock_debug & VLOCK_DEBUG_FLASH))
pr_info("vlock: %s enc_frc_max_line =%d enc_frc_max_pixel =%d enc_frc_v_porch =%d\n",
__func__, pvlock->enc_frc_max_line,
pvlock->enc_frc_max_pixel, pvlock->enc_frc_v_porch);
}
}
}
static unsigned int vlock_check_input_hz(struct vframe_s *vf)
{
unsigned int ret_hz = 0;
unsigned int duration = vf->duration;
if (vf->source_type != VFRAME_SOURCE_TYPE_CVBS &&
vf->source_type != VFRAME_SOURCE_TYPE_HDMI)
ret_hz = 0;
else if (vf->source_type == VFRAME_SOURCE_TYPE_HDMI &&
(vlock_support & VLOCK_SUPPORT_HDMI)) {
if (duration != 0)
ret_hz = (96000 + duration / 2) / duration;
if (diff(ret_hz, 60) <= 1)
ret_hz = 60;
else if (diff(ret_hz, 50) <= 1)
ret_hz = 50;
else if (diff(ret_hz, 30) <= 1)
ret_hz = 30;
} else if (vf->source_type == VFRAME_SOURCE_TYPE_CVBS &&
(vlock_support & VLOCK_SUPPORT_CVBS)) {
if (vf->source_mode == VFRAME_SOURCE_MODE_NTSC)
ret_hz = 60;
else if (vf->source_mode == VFRAME_SOURCE_MODE_PAL ||
vf->source_mode == VFRAME_SOURCE_MODE_SECAM)
ret_hz = 50;
else
ret_hz = 0;
}
return ret_hz;
}
static unsigned int vlock_check_output_hz(unsigned int sync_duration_num,
unsigned int sync_duration_den)
{
unsigned int ret_hz = 0;
unsigned int tempHz;
tempHz = (sync_duration_num * 100) / sync_duration_den;
if (tempHz == 2400)
ret_hz = 24;
else if (tempHz == 3000)
ret_hz = 30;
else if (tempHz == 5000)
ret_hz = 50;
else if ((tempHz > 5990) && (tempHz <= 6000))
ret_hz = 60;
else if (tempHz == 10000)
ret_hz = 100;
else if (tempHz == 12000)
ret_hz = 120;
else
ret_hz = 0;
if (ret_hz == 0 && (vlock_debug & VLOCK_DEBUG_INFO))
pr_info("tempHz=%d, sync_duration_num:%d den:%d\n", tempHz,
sync_duration_num, sync_duration_den);
return ret_hz;
}
/*
* Tm2 have two pll, hdmi pll and panel pll
* hdmi tx output mode vlock pll need switch to hdmi pll
* panel output mode, vlock pll need switch to panel pll
* des: 0-switch to panel pll , 1-switch to hdmi pll
* param: vlock_mode
* param: vlock_pll_sel
*/
static void vlock_pll_select(struct stvlock_sig_sts *pvlock,
u32 vlock_mode, u32 workmd)
{
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s md:%d\n", __func__, workmd);
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7) {
if (workmd == vlock_pll_sel_disable) {
if (pvlock->idx == VLOCK_ENC0) {
/* enc0: need disable vlock clk lock */
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 0, 0, 1);
} else if (pvlock->idx == VLOCK_ENC1) {
/* enc1: need disable vlock clk lock */
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 0, 1, 1);
} else if (pvlock->idx == VLOCK_ENC2) {
/* enc2: need disable vlock clk lock */
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 0, 2, 1);
}
} else {
if (IS_AUTO_PLL_MODE(vlock_mode)) {
if (pvlock->idx == VLOCK_ENC0) {
/*enc0*/
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK,
1, 0, 1);
} else if (pvlock->idx == VLOCK_ENC1) {
/*enc1*/
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK,
1, 1, 1);
} else if (pvlock->idx == VLOCK_ENC2) {
/*enc2*/
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK,
1, 2, 1);
}
}
}
} else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TM2)) {
if (workmd == vlock_pll_sel_disable) {
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0, 0, 2);
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0, 4, 2);
} else {
if (IS_AUTO_PLL_MODE(vlock_mode)) {
if (workmd == vlock_pll_sel_hdmi) {
/*auto pll mode, hdmi M/F value from vlock*/
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0, 0, 2);
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 3, 4, 2);
} else {
/*auto pll mode, panel M/F value from vlock*/
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 3, 0, 2);
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0, 4, 2);
}
}
}
} else {
/* tv chip only have tcon pll */
if (workmd == vlock_pll_sel_disable) {
if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2) {
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0x4, 0, 3);
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0x0, 0, 3);
}
} else {
if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2) {
if (IS_AUTO_MODE(vlock_mode)) {
if (IS_AUTO_ENC_MODE(vlock_mode))
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL,
0, 0, 3);
else
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL,
0x7, 0, 3);
} else if (IS_MANUAL_MODE(vlock_mode)) {
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_VLOCK_CNTL, 0x6, 0, 3);
}
}
}
}
}
/*
* TM2 verB
* when vlk_hwver config is vlock_hw_tm2verB, then this function
* is valid.
*/
void vlock_set_phase_frq_lock_speed(struct stvlock_sig_sts *pvlock)
{
u32 data = 0;
u32 offset_vlck = pvlock->offset_vlck;
if (pvlock->dtdata->vlk_hwver < vlock_hw_tm2verb)
return;
if (speed_up_en && IS_AUTO_MODE(vlock_mode)) {
data = 0;
/*27-24 RW reg_loop1_err_rs*/
data |= (loop_err_rs << 24);
/*23-16 RW reg_loop1_err_gain*/
data |= (loop_err_gain << 16);
/*11-8 RW reg_loop0_err_rs*/
data |= (loop_err_rs << 8);
/*7-0 RW reg_loop0_err_gain*/
data |= (loop_err_gain << 0);
WRITE_VPP_REG(VPU_VLOCK_ERR_CTRL0 + offset_vlck, data);
data = 0;
/*23 RW reg_loop0_err_lmt_en frq*/
if (loop0_en > 1) {
/*auto enc mode enable limit lock is too slow*/
if (IS_AUTO_PLL_MODE(vlock_mode))
data |= (0x1 << 23);
} else {
data |= (loop0_en << 23);
}
/*22-0 RW reg_loop0_err_lmt*/
data |= (loop0_err_lmt << 0);
WRITE_VPP_REG(VPU_VLOCK_LOOP0_ERR_LMT + offset_vlck, data);
pr_info("%s LOOP0_ERR_LMT w:0x%x r:0x%x\n", __func__, data,
READ_VPP_REG(VPU_VLOCK_LOOP0_ERR_LMT + offset_vlck));
data = 0;
/*23 RW reg_loop1_err_lmt_en phase*/
if (loop1_en)
data |= (0x1 << 23);
/*22-0 RW reg_loop1_err_lmt*/
data |= (loop1_err_lmt << 0);
WRITE_VPP_REG(VPU_VLOCK_LOOP1_ERR_LMT + offset_vlck, data);
pr_info("%s LOOP1_ERR_LMT w:0x%x r:0x%x\n", __func__, data,
READ_VPP_REG(VPU_VLOCK_LOOP1_ERR_LMT + offset_vlck));
} else {
WRITE_VPP_REG(VPU_VLOCK_LOOP1_ERR_LMT + offset_vlck, 0);
WRITE_VPP_REG(VPU_VLOCK_LOOP0_ERR_LMT + offset_vlck, 0);
}
}
void vlock_reset(struct stvlock_sig_sts *pvlock, u32 onoff)
{
u32 offset_vlck = pvlock->offset_vlck;
if (onoff) {
/*cal accum1 value*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 2, 1);
/*cal accum0 value*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 5, 1);
} else {
/*cal accum1 value*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 2, 1);
/*cal accum0 value*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 5, 1);
}
/*pr_info("%s (%d)\n", __func__, onoff);*/
}
/*vlock is support eq_after gxbb,but which is useful only for tv chip
*after gxl,the enable/disable reg_bit is changed
*/
static void vlock_enable(struct stvlock_sig_sts *pvlock, bool enable)
{
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
unsigned int tmp_value;
#endif
if (is_meson_gxtvbb_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
if (vlock_mode & VLOCK_MODE_MANUAL_PLL) {
amvecm_hiu_reg_read(HHI_HDMI_PLL_CNTL6, &tmp_value);
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL6, 0, 20, 1);
/*vlsi suggest config:don't enable load signal,
*on gxtvbb this load signal will effect SSG,
*which may result in flashes black
*/
if (is_meson_gxtvbb_cpu() &&
(((tmp_value >> 21) & 0x3) != 2))
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL6, 2, 21, 2);
} else {
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL6, enable, 20, 1);
}
#endif
} else if (is_meson_txl_cpu() || is_meson_txlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
if (vlock_mode & VLOCK_MODE_MANUAL_PLL)
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL5, 0, 3, 1);
else
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL5, enable, 3, 1);
#endif
} else if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2) {
/*reset*/
if (!(vlock_mode & VLOCK_MODE_MANUAL_PLL)) {
/*reset*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 5, 1);*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 5, 1);*/
}
if (!enable) {
/*vlock_hiu_reg_wt_bits(*/
/* HHI_HDMI_PLL_VLOCK_CNTL + offset_vlck, 0, 0, 3);*/
/*WRITE_VPP_REG(VPU_VLOCK_CTRL + offset_vlck, 0);*/
}
}
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info(">>>[%s] (%d)\n", __func__, enable);
}
static void vlock_hw_reinit(struct stvlock_sig_sts *pvlock,
struct vlock_regs_s *vlock_regs, unsigned int len)
{
unsigned int i;
u32 offset_vlck = pvlock->offset_vlck;
if ((vlock_debug & VLOCK_DEBUG_FLUSH_REG_DIS) || !vlock_regs)
return;
for (i = 0; i < len; i++)
WRITE_VPP_REG(vlock_regs[i].addr + offset_vlck, vlock_regs[i].val);
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("[%s]\n", __func__);
}
void vlock_clk_config(struct device *dev)
{
struct clk *clk;
/*unsigned int clk_frq;*/
struct stvlock_sig_sts *pvlock = vlock_tab[VLOCK_ENC0];
if (!pvlock)
return;
vlock_init_reg_map(dev, pvlock);
/*pr_info("%s\n", __func__);*/
if (pvlock->dtdata->vlk_chip <= vlock_chip_tm2)
amvecm_hiu_reg_write(HHI_VID_LOCK_CLK_CNTL, 0x80);
/*need set clock tree */
clk = devm_clk_get(dev, "cts_vid_lock_clk");
if (!IS_ERR(clk)) {
clk_set_rate(clk, 24000000);
if (clk_prepare_enable(clk) < 0)
pr_info("vlock clk enable fail\n");
/*clk_frq = clk_get_rate(clk);*/
/*pr_info("cts_vid_lock_clk:%d\n", clk_frq);*/
hw_clk_ok = 1;
} else {
pr_err("vlock clk not cfg\n");
hw_clk_ok = 0;
}
}
static void vlock_setting(struct vframe_s *vf, struct stvlock_sig_sts *pvlock)
{
unsigned int freq_hz = 0;
unsigned int reg_value = 0, hiu_reg_value, hiu_reg_value_2;
unsigned int hiu_m_val = 0, hiu_frac_val = 0, temp_value;
unsigned int input_hz, output_hz;
u32 offset_vlck = pvlock->offset_vlck;
u32 offset_enc = pvlock->offset_encl;
input_hz = pvlock->input_hz;
output_hz = pvlock->output_hz;
if (vlock_debug & VLOCK_DEBUG_INFO) {
pr_info(">>>[%s]\n", __func__);
pr_info("inputHz:%d,outputHz:%d\n", input_hz, output_hz);
pr_info("type_original:0x%x\n", vf->type_original);
}
vlock_set_phase_frq_lock_speed(pvlock);
/*vlock_set_clk_src, after tm2 use clk tree*/
if (pvlock->dtdata->vlk_chip <= vlock_chip_tm2)
amvecm_hiu_reg_write(HHI_VID_LOCK_CLK_CNTL, 0x80);
if (IS_ENC_MODE(vlock_mode)) {
/*init default config for enc mode*/
vlock_hw_reinit(pvlock, vlock_enc_setting, VLOCK_DEFAULT_REG_SIZE);
/*vlock line limit*/
/*WRITE_VPP_REG(VPU_VLOCK_OUTPUT0_CAPT_LMT + offset_vlck,*/
/* vlock_capture_limit);*/
/* VLOCK_CNTL_EN disable */
vlock_enable(pvlock, 0);
/* disable to adjust pll */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 29, 1);
/* CFG_VID_LOCK_ADJ_EN enable */
if ((vlock_mode & (VLOCK_MODE_MANUAL_ENC |
VLOCK_MODE_MANUAL_SOFT_ENC))) {
/*auto vlock off*/
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc, 0, 13, 1);
WRITE_VPP_REG_BITS(pvlock->enc_video_mode_adv_addr + offset_enc, 1, 14, 1);
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc,
pvlock->pre_enc_max_pixel, 0, 13);
} else {
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc, 1, 13, 1);
WRITE_VPP_REG_BITS(pvlock->enc_video_mode_adv_addr + offset_enc, 0, 14, 1);
}
/* enable to adjust enc */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 30, 1);
if (get_cpu_type() < MESON_CPU_MAJOR_ID_TL1) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
/*clear accum1 value*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 2, 1);
/*clear accum0 value*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 5, 1);
#endif
}
/*@20180314 new add*/
/*
*set input & output freq
*bit0~7:input freq
*bit8~15:output freq
*/
if ((vf->type_original & VIDTYPE_TYPEMASK) &&
!(vlock_mode & VLOCK_MODE_MANUAL_SOFT_ENC)) {
/*tl1 fix i problem*/
if (get_cpu_type() < MESON_CPU_MAJOR_ID_TL1)
input_hz = input_hz >> 1;
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, 1, 28, 1);
} else {
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
if (input_hz > 0 && output_hz > 0 &&
(input_hz * 2 == output_hz))
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
0, 28, 1);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
1, 28, 1);
}
}
freq_hz = input_hz | (output_hz << 8);
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, freq_hz, 0, 16);
/*
*Ifrm_cnt_mod:0x3001(bit23~16);
*(output_freq/input_freq)*Ifrm_cnt_mod must be integer
*/
if (vlock_adapt == 0) {
if (output_hz > 0 && input_hz > 0) {
if (input_hz == 24 && output_hz == 60)
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
2, 16, 8);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
output_hz / input_hz, 16, 8);
} else {
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, 1, 16, 8);
}
} else {
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, input_hz, 16, 8);
}
temp_value = READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
if (!temp_value)
pr_info("vlock err: enc_max_line %d\n", temp_value);
WRITE_VPP_REG_BITS(VPU_VLOCK_OROW_OCOL_MAX + offset_vlck, temp_value + 1, 0, 14);
/* diff time/vtotal */
if (vlock_capture_limit < 0x8000 ||
vlock_capture_limit > 0x100000) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock capture_limit error:0x%x",
vlock_capture_limit);
vlock_capture_limit = 0x60000;
}
/*vlock line limit*/
WRITE_VPP_REG(VPU_VLOCK_OUTPUT0_CAPT_LMT + offset_vlck, vlock_capture_limit);
/*tune pixel*/
/*temp_value = READ_VPP_REG(pvlock->enc_max_pixel_addr + + offset_vlck);*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_OROW_OCOL_MAX + offset_vlck,*/
/* temp_value + 1, 16, 14);*/
WRITE_VPP_REG_BITS(VPU_VLOCK_ADJ_EN_SYNC_CTRL + offset_vlck,
vlock_latch_en_cnt, 8, 8);
WRITE_VPP_REG_BITS(pvlock->enc_video_mode_addr + offset_enc, 1, 15, 1);
}
if ((vlock_mode & (VLOCK_MODE_AUTO_PLL |
VLOCK_MODE_MANUAL_PLL))) {
/* av pal in,1080p60 hdmi out as default */
vlock_hw_reinit(pvlock, vlock_pll_setting, VLOCK_DEFAULT_REG_SIZE);
/*
*set input & output freq
*bit0~7:input freq
*bit8~15:output freq
*/
if (vf->type_original & VIDTYPE_TYPEMASK) {
if (get_cpu_type() < MESON_CPU_MAJOR_ID_TL1)
input_hz = input_hz >> 1;
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, 1, 28, 1);
} else {
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
if (input_hz > 0 && output_hz > 0 &&
(input_hz * 2 == output_hz))
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
0, 28, 1);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
1, 28, 1);
}
}
freq_hz = input_hz | (output_hz << 8);
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, freq_hz, 0, 16);
/*
*Ifrm_cnt_mod:0x3001(bit23~16);
*(output_freq/input_freq)*Ifrm_cnt_mod must be integer
*/
if (vlock_adapt == 0)
if (output_hz > 0 && input_hz > 0)
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
output_hz / input_hz, 16, 8);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
1, 16, 8);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck,
input_hz, 16, 8);
hiu_reg_value = vlock_get_panel_pll_m(pvlock);
hiu_reg_value_2 = vlock_get_panel_pll_frac(pvlock);
if (vlock_debug & VLOCK_DEBUG_INFO) {
pr_info("pll_reg_m:0x%x\n", hiu_reg_value);
pr_info("pll_reg_frac:0x%x\n", hiu_reg_value_2);
}
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
hiu_m_val = hiu_reg_value & 0xff;
/*discard low 5 bits*/
hiu_frac_val = (hiu_reg_value_2 >> 5) & 0xfff;
reg_value = (hiu_m_val << 12) + hiu_frac_val;
} else if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXTVBB)) {
hiu_m_val = hiu_reg_value & 0x1FF;
hiu_frac_val = hiu_reg_value_2 & 0x3FF;
if (hiu_reg_value_2 & 0x800) {
hiu_m_val -= 1;
if (hiu_reg_value_2 & 0x400)
hiu_m_val -= 1;
hiu_frac_val = 0x400 -
((~(hiu_frac_val - 1)) & 0x3ff);
} else if (hiu_reg_value_2 & 0x400) {
hiu_m_val += 1;
}
reg_value = (hiu_m_val << 12)
+ (hiu_frac_val << 2);
} else {
pr_info("err: m f value\n");
}
///if (vlock_debug & VLOCK_DEBUG_INFO) {
// pr_info("hiu_m_val=0x%x\n", hiu_m_val);
// pr_info("hiu_frac_val=0x%x\n", hiu_frac_val);
//}
WRITE_VPP_REG_BITS(VPU_VLOCK_MX4096 + offset_vlck, reg_value, 0, 21);
/*vlock_pll_adj_limit = (reg_value * 0x8000) >> 24;*/
vlock_pll_adj_limit = reg_value >> VLOCK_PLL_ADJ_LIMIT;
vlock_pll_val_last = ((reg_value & 0x3fff000) << 4) | (reg_value & 0x3fff);
/*enable vlock to adj pll*/
/* CFG_VID_LOCK_ADJ_EN disable */
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc, 0, 13, 1);
/* disable to adjust enc */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 30, 1);
/* VLOCK_CNTL_EN enable */
vlock_enable(pvlock, 1);
/* enable to adjust pll */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 29, 1);
}
/*initial phase lock setting*/
if (pvlock->phlock_en) {
if (!phase_en_after_frqlock) {
if (IS_PLL_MODE(vlock_mode))
vlock_hw_reinit(pvlock, vlock_pll_phase_setting,
VLOCK_PHASE_REG_SIZE);
else
vlock_hw_reinit(pvlock, vlock_encl_phase_setting,
VLOCK_PHASE_REG_SIZE);
/*enable pll mode and enc mode phase lock*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 3, 0, 2);*/
if (IS_PLL_MODE(vlock_mode))
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 0, 1);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 1, 1);
/*if (IS_PLL_MODE(vlock_mode))*/
/* WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 0, 1);*/
/*else*/
/* WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 1, 1);*/
}
}
/* vlock module output goes to which module */
switch (VLOCK_OUT_ENCL/*READ_VPP_REG_BITS(VPU_VIU_VENC_MUX_CTRL, 0, 2)*/) { /* ?? */
case VLOCK_OUT_ENCL:/* ENCL */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, VLOCK_OUT_ENCL, 26, 2);
break;
case VLOCK_OUT_ENCI:/* ENCI */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, VLOCK_OUT_ENCI, 26, 2);
break;
case VLOCK_OUT_ENCP: /* ENCP */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, VLOCK_OUT_ENCP, 26, 2);
break;
default:
break;
}
if (vf->source_type == VFRAME_SOURCE_TYPE_TUNER ||
vf->source_type == VFRAME_SOURCE_TYPE_CVBS)
/* Input Vsync source select from tv-decoder */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 2, 16, 3);
else if (vf->source_type == VFRAME_SOURCE_TYPE_HDMI)
/* Input Vsync source select from hdmi-rx */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 16, 3);
/*frq lock flag window*/
WRITE_VPP_REG_BITS(VPU_VLOCK_STBDET_WIN0_WIN1 + offset_vlck, 0x18, 0, 8);
/*phase lock flag window*/
WRITE_VPP_REG_BITS(VPU_VLOCK_STBDET_WIN0_WIN1 + offset_vlck, 0x18, 8, 8);
/*enable vlock*/
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 31, 1);
}
void vlock_vmode_check(struct stvlock_sig_sts *pvlock)
{
const struct vinfo_s *vinfo;
u32 offset_vlck;
u32 offset_enc;
if (!pvlock)
return;
offset_vlck = pvlock->offset_vlck;
offset_enc = pvlock->offset_encl;
vinfo = get_current_vinfo();
vlock_vmode_changed = 0;
if (vlock_notify_event == VOUT_EVENT_MODE_CHANGE ||
pvlock->pre_hiu_reg_m == 0) {
if (vlock_mode & (VLOCK_MODE_MANUAL_PLL |
VLOCK_MODE_AUTO_PLL)) {
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
pvlock->pre_hiu_reg_frac =
(pvlock->val_frac >> 5) & 0xfff;
pvlock->pre_hiu_reg_m = pvlock->val_m & 0xff;
} else {
pvlock->pre_hiu_reg_frac = pvlock->val_frac & 0xfff;
pvlock->pre_hiu_reg_m = pvlock->val_m & 0x1ff;
}
}
if (vlock_mode &
(VLOCK_MODE_MANUAL_ENC |
VLOCK_MODE_AUTO_ENC |
VLOCK_MODE_MANUAL_SOFT_ENC)) {
pvlock->pre_enc_max_line =
READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
pvlock->pre_enc_max_pixel =
READ_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc);
if (!pvlock->pre_enc_max_line || !pvlock->pre_enc_max_pixel)
pr_info("vlock chk err: maxLine %d,maxPixel %d\n",
pvlock->pre_enc_max_line, pvlock->pre_enc_max_pixel);
vlock_capture_limit =
((1024 * 1024 * 16) * vlock_line_limit) /
(vinfo->vtotal + 1);
}
vlock_notify_event = 0;
vlock_vmode_changed = 1;
}
}
static void vlock_disable_step1(struct stvlock_sig_sts *pvlock)
{
unsigned int m_reg_value, tmp_value;
/*unsigned int enc_max_line, enc_max_pixel;*/
u32 m_f_reg_value, pll_m, pll_f;
u32 offset_vlck = pvlock->offset_vlck;
u32 offset_enc = pvlock->offset_encl;
/* VLOCK_CNTL_EN disable */
vlock_enable(pvlock, 0);
vlock_vmode_check(pvlock);
m_f_reg_value = READ_VPP_REG(VPU_VLOCK_RO_M_INT_FRAC + offset_vlck);
if (IS_AUTO_PLL_MODE(vlock_mode)) {
pll_m = (m_f_reg_value >> 16) & 0xff;
pll_f = m_f_reg_value & 0xffff;
pr_info("vlock exit m:0x%x f:0x%x\n", pll_m, pll_f);
if ((vlock_debug & VLOCK_DEBUG_INFO) &&
(diff((pvlock->val_m & 0xff), pll_m) > 8))
vlock_reg_dump(pvlock);
}
if (IS_PLL_MODE(vlock_mode)) {
if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2) {
/*restore the orginal pll setting*/
/*tmp_value = vlock_get_panel_pll_m(pvlock);*/
/*m_reg_value = tmp_value & 0xff;*/
/*if (m_reg_value != (pvlock->val_m & 0xff))*/
vlock_set_panel_pll_m(pvlock, pvlock->val_m);
/*tmp_value = vlock_get_panel_pll_frac(pvlock);*/
/*m_reg_value = tmp_value & 0x1ffff;*/
/*if (m_reg_value != (pvlock->val_frac & 0xfff))*/
vlock_set_panel_pll_frac(pvlock, pvlock->val_frac);
/*amvecm_hiu_reg_write(hhi_pll_reg_frac,*/
/* vlock.val_frac);*/
pr_info("vlock restore original m:0x%x f:0x%x\n",
pvlock->val_m, pvlock->val_frac);
} else {
tmp_value = vlock_get_panel_pll_frac(pvlock);
m_reg_value = tmp_value & 0xfff;
if (m_reg_value != pvlock->pre_hiu_reg_frac) {
tmp_value = (tmp_value & 0xfffff000) |
(pvlock->pre_hiu_reg_frac & 0xfff);
vlock_set_panel_pll_frac(pvlock, tmp_value);
}
tmp_value = vlock_get_panel_pll_m(pvlock);
m_reg_value = tmp_value & 0x1ff;
if (m_reg_value != pvlock->pre_hiu_reg_m &&
pvlock->pre_hiu_reg_m != 0) {
tmp_value = (tmp_value & 0xfffffe00) |
(pvlock->pre_hiu_reg_m & 0x1ff);
vlock_set_panel_pll_m(pvlock, tmp_value);
}
}
}
if (IS_ENC_MODE(vlock_mode)) {
pvlock->err_accum = 0;
WRITE_VPP_REG_BITS(pvlock->enc_video_mode_adv_addr + offset_enc, 0, 14, 1);
WRITE_VPP_REG_BITS(pvlock->enc_video_mode_addr + offset_enc, 0, 15, 1);
/*restore h,v total*/
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc, 0x1fff, 0, 13);
WRITE_VPP_REG(pvlock->enc_max_line_addr + offset_enc,
pvlock->org_enc_line_num);
WRITE_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc,
pvlock->org_enc_pixel_num);
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("restore hv total:%d %d\n", pvlock->org_enc_line_num,
pvlock->org_enc_pixel_num);
pvlock->enc_frc_max_line = pvlock->org_enc_line_num;
pvlock->enc_frc_max_pixel = pvlock->org_enc_pixel_num;
vlock_tune_sync(pvlock);
}
vlock_dis_cnt = vlock_dis_cnt_limit;
pre_source_type = VFRAME_SOURCE_TYPE_OTHERS;
pre_source_mode = VFRAME_SOURCE_MODE_OTHERS;
pre_input_freq = 0;
pre_output_freq = 0;
vlock_state = VLOCK_STATE_DISABLE_STEP1_DONE;
if (vlock_mode & VLOCK_MODE_MANUAL_MIX_PLL_ENC) {
vlock_mode &= ~VLOCK_MODE_MANUAL_MIX_PLL_ENC;
vlock_mode |= VLOCK_MODE_MANUAL_PLL;
}
vlock_pll_stable_cnt = 0;
vlock_enc_stable_flag = 0;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info(">>>[%s]\n", __func__);
}
static bool vlock_disable_step2(struct stvlock_sig_sts *pvlock)
{
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
unsigned int temp_val;
#endif
bool ret = false;
u32 offset_vlck = pvlock->offset_vlck;
u32 offset_enc = pvlock->offset_encl;
/* need delay to disable follow regs(vlsi suggest!!!) */
if (vlock_dis_cnt > 0) {
vlock_dis_cnt--;
} else if (vlock_dis_cnt == 0) {
/* pll source set default */
vlock_pll_select(pvlock, vlock_mode, vlock_pll_sel_disable);
/* disable to adjust pll */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 29, 1);
/* CFG_VID_LOCK_ADJ_EN disable */
WRITE_VPP_REG_BITS(ENCL_MAX_LINE_SWITCH_POINT + offset_enc, 0, 13, 1);
/* disable to adjust pll */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 30, 1);
/* disable vid_lock_en */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 31, 1);
vlock_state = VLOCK_STATE_DISABLE_STEP2_DONE;
if (is_meson_gxtvbb_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
amvecm_hiu_reg_read(HHI_HDMI_PLL_CNTL6, &temp_val); /* ?? */
if (((temp_val >> 21) & 0x3) != 0)
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL6, 0, 21, 2); /* ?? */
#endif
}
vlock_reset(pvlock, 1);
vlock_reset(pvlock, 0);
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 0, 2);
/*restore ss setting*/
if (vlock_ss_en && !pvlock->ss_sts)
vlock_set_panel_ss(true);
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info(">>>[%s]\n", __func__);
ret = true;
}
return ret;
}
static void vlock_enable_step1(struct vframe_s *vf, struct vinfo_s *vinfo,
struct stvlock_sig_sts *pvlock)
{
if (vinfo->vtotal && pvlock->output_hz)
vlock_enc_adj_limit = (XTAL_VLOCK_CLOCK * vlock_line_limit) /
(vinfo->vtotal * pvlock->output_hz);
vlock_setting(vf, pvlock);
if (vlock_debug & VLOCK_DEBUG_INFO) {
pr_info("%s:vmode/source_type/source_mode/input_freq/output_freq:\n",
__func__);
pr_info("\t %d/%d/%d/%d => %d/%d/%d/%d\n",
pre_source_type, pre_source_mode,
pre_input_freq, pre_output_freq,
vf->source_type, vf->source_mode,
pvlock->input_hz, pvlock->output_hz);
}
pre_source_type = vf->source_type;
pre_source_mode = vf->source_mode;
pre_input_freq = pvlock->input_hz;
pre_output_freq = pvlock->output_hz;
vlock_sync_limit_flag = 0;
vlock_vmode_changed = 0;
vlock_dis_cnt = 0;
/*vlock_state = VLOCK_STATE_ENABLE_STEP1_DONE;*/
vlock_pll_stable_cnt = 0;
vlock_log_cnt = 0;
vlock_enc_stable_flag = 0;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info(">>>[%s]\n", __func__);
}
void vlock_log_start(void)
{
unsigned int i;
vlock_log = kmalloc_array(vlock_log_size, sizeof(struct vlock_log_s *),
GFP_KERNEL);
if (!vlock_log)
return;
for (i = 0; i < vlock_log_size; i++) {
vlock_log[i] = kmalloc(sizeof(*vlock_log[i]), GFP_KERNEL);
if (!vlock_log[i])
return;
}
vlock_log_en = 1;
pr_info("%s done\n", __func__);
}
void vlock_log_stop(void)
{
unsigned int i;
for (i = 0; i < vlock_log_size; i++)
kfree(vlock_log[i]);
kfree(vlock_log);
vlock_log_en = 0;
pr_info("%s done\n", __func__);
}
void vlock_log_print(void)
{
unsigned int i, j;
if (!vlock_log[0])
return;
for (i = 0; i < vlock_log_size; i++) {
pr_info("\n*******[%d]pll_m:0x%x,pll_frac:0x%x*******\n",
i, vlock_log[i]->pll_m, vlock_log[i]->pll_frac);
pr_info("*******enc_line_max:0x%x,line_num_adj:%d*******\n",
vlock_log[i]->enc_line_max, vlock_log[i]->line_num_adj);
pr_info("*******enc_pixel_max:0x%x,pixel_num_adj:%d*******\n",
vlock_log[i]->enc_pixel_max,
vlock_log[i]->pixel_num_adj);
pr_info("*******T0:%d(0x%x),vdif_err:%d(0x%x),err_sum:%d(0x%x),margin:%d(0x%x)*******\n",
vlock_log[i]->T0, vlock_log[i]->T0,
vlock_log[i]->vdif_err, vlock_log[i]->vdif_err,
vlock_log[i]->err_sum, vlock_log[i]->err_sum,
vlock_log[i]->margin, vlock_log[i]->margin);
for (j = 0; j < VLOCK_REG_NUM;) {
if ((j % 8 == 0) && ((j + 7) < VLOCK_REG_NUM)) {
pr_info("0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
vlock_log[i]->vlock_regs[j],
vlock_log[i]->vlock_regs[j + 1],
vlock_log[i]->vlock_regs[j + 2],
vlock_log[i]->vlock_regs[j + 3],
vlock_log[i]->vlock_regs[j + 4],
vlock_log[i]->vlock_regs[j + 5],
vlock_log[i]->vlock_regs[j + 6],
vlock_log[i]->vlock_regs[j + 7]);
j += 8;
} else {
pr_info("0x%08x\t",
vlock_log[i]->vlock_regs[j]);
j++;
}
}
}
pr_info("%s done\n", __func__);
}
void vlock_reg_get(struct stvlock_sig_sts *pvlock)
{
unsigned int i;
u32 offset_vlck = pvlock->offset_vlck;
for (i = 0; i < VLOCK_REG_NUM; i++)
vlock_log[vlock_log_cnt]->vlock_regs[i] =
READ_VPP_REG(VPU_VLOCK_CTRL + offset_vlck + i);
}
static void vlock_enable_step3_enc(struct stvlock_sig_sts *pvlock)
{
unsigned int line_num = 0, enc_max_line = 0, polity_line_num = 0;
unsigned int pixel_num = 0, enc_max_pixel = 0, polity_pixel_num = 0;
/*unsigned int val;*/
//static u32 cnt;
u32 offset_vlck = pvlock->offset_vlck;
u32 offset_enc = pvlock->offset_encl;
if (pvlock->enable_cnt++ > 15)
pvlock->enable_cnt = 0;
if (!pvlock->pre_enc_max_pixel || !pvlock->pre_enc_max_line) {
pr_info("vlock enc max val err P:%d L:%d\n",
pvlock->pre_enc_max_pixel, pvlock->pre_enc_max_line);
return;
}
/*vlock pixel num adjust*/
if (!(vlock_debug & VLOCK_DEBUG_ENC_PIXEL_ADJ_DIS) &&
pvlock->dtdata->vlk_chip < vlock_chip_tm2) {/*only adj line*/
polity_pixel_num =
READ_VPP_REG_BITS(VPU_VLOCK_RO_LINE_PIX_ADJ + offset_vlck, 13, 1);
pixel_num = READ_VPP_REG_BITS(VPU_VLOCK_RO_LINE_PIX_ADJ + offset_vlck, 0, 14);
if (polity_pixel_num) {
pixel_num = (~(pixel_num - 1)) & 0x3fff;
if (pixel_num > vlock_enc_maxtune_pixel_num)
pixel_num = vlock_enc_maxtune_pixel_num;
enc_max_pixel = pvlock->org_enc_pixel_num - pixel_num;
} else {
if (pixel_num > vlock_enc_maxtune_pixel_num)
pixel_num = vlock_enc_maxtune_pixel_num;
enc_max_pixel = pvlock->org_enc_pixel_num + pixel_num;
}
if (enc_max_pixel > 0x1fff) {
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc,
pvlock->org_enc_pixel_num, 0, 13);
/*val = pixel_num;*/
} else {
WRITE_VPP_REG_BITS(pvlock->enc_max_line_switch_addr + offset_enc,
enc_max_pixel, 0, 13);
/*val = enc_max_pixel;*/
}
if ((vlock_debug & VLOCK_DEBUG_INFO) && pvlock->enable_cnt == 0) {
pr_info("polity_pixel_num=%d, pixel_num=%d, org_pixel=%d\n",
polity_pixel_num, pixel_num, pvlock->org_enc_pixel_num);
pr_info("\t wr addr:0x%x, %d\n",
pvlock->enc_max_line_switch_addr + offset_enc, enc_max_pixel);
}
}
/*vlock line num adjust*/
if (!(vlock_debug & VLOCK_DEBUG_ENC_LINE_ADJ_DIS) && vlock_vsync_skip_for_frc()) {
polity_line_num = READ_VPP_REG_BITS(VPU_VLOCK_RO_LINE_PIX_ADJ + offset_vlck, 29, 1);
line_num = READ_VPP_REG_BITS(VPU_VLOCK_RO_LINE_PIX_ADJ + offset_vlck, 16, 14);
if ((vlock_debug & VLOCK_DEBUG_INFO)) {
READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
pr_info("vlock: enc_max_line_num = %d\n",
READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc));
}
if (polity_line_num) {
line_num = (~(line_num - 1)) & 0x3fff;
if (line_num > vlock_enc_maxtune_line_num)
line_num = vlock_enc_maxtune_line_num;
enc_max_line = pvlock->org_enc_line_num - line_num;
} else {
if (line_num > vlock_enc_maxtune_line_num)
line_num = vlock_enc_maxtune_line_num;
enc_max_line = pvlock->org_enc_line_num + line_num;
}
if (enc_max_pixel > 0x1fff)
enc_max_line += 1;
WRITE_VPP_REG(pvlock->enc_max_line_addr + offset_enc, enc_max_line);
if ((vlock_debug & VLOCK_DEBUG_FLASH)) {
pr_info("polity_line_num=%d line_num=%d, org_line=%d\n",
polity_line_num, line_num, pvlock->org_enc_line_num);
pr_info("\t wr addr:0x%x, %d\n",
pvlock->enc_max_line_addr + offset_enc, enc_max_line);
}
vlock_tune_sync(pvlock);
}
if (vlock_log_en && vlock_log_cnt < vlock_log_size) {
vlock_log[vlock_log_cnt]->enc_line_max = enc_max_line;
vlock_log[vlock_log_cnt]->line_num_adj = line_num;
vlock_log[vlock_log_cnt]->enc_pixel_max = enc_max_pixel;
vlock_log[vlock_log_cnt]->pixel_num_adj = pixel_num;
vlock_reg_get(pvlock);
vlock_log_cnt++;
}
/*if (vlock_debug & VLOCK_DEBUG_INFO)*/
/* pr_info(">>>[%s]\n", __func__);*/
}
static void vlock_enable_step3_soft_enc(struct stvlock_sig_sts *pvlock)
{
unsigned int ia, oa, tmp_value;
signed int margin;
signed int pixel_adj;
signed int err, vdif_err;
signed int T0, tfrac;
signed int line_adj;
u32 offset_vlck = pvlock->offset_vlck;
u32 offset_enc = pvlock->offset_encl;
signed int reg_errclip_rate =
READ_VPP_REG_BITS(VPU_VLOCK_LOOP0_CTRL0 + offset_vlck, 24, 8);
signed int reg_accum_lmt = READ_VPP_REG(VPU_VLOCK_LOOP0_ACCUM_LMT + offset_vlck);
signed int reg_capt_gain =
READ_VPP_REG_BITS(VPU_VLOCK_LOOP0_CTRL0 + offset_vlck, 0, 8);
signed int reg_capt_rs =
READ_VPP_REG_BITS(VPU_VLOCK_LOOP0_CTRL0 + offset_vlck, 8, 4);
signed int reg_capt_lmt = READ_VPP_REG(VPU_VLOCK_OUTPUT0_CAPT_LMT + offset_vlck);
if (pvlock->last_i_vsync == 0) {
pvlock->last_i_vsync = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
return;
}
ia = (READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck) + pvlock->last_i_vsync + 1) / 2;
/*for 25Hz->50Hz, 30Hz->60Hz*/
if (READ_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, 16, 8) == 2)
ia = ia / 2;
oa = READ_VPP_REG(VPU_VLOCK_RO_VS_O_DIST + offset_vlck);
if (ia == 0 || oa == 0) {
vlock_state = VLOCK_STATE_ENABLE_FORCE_RESET;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s:vlock enc work abnormal! force reset vlock\n",
__func__);
return;
}
/*check enc adj limit*/
tmp_value = abs(ia - oa);
if (tmp_value > vlock_enc_adj_limit) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s:vlock enc abs[%d](ia[%d]-oa[%d]) over limit,don't do adj\n",
__func__, tmp_value, ia, oa);
return;
}
if (ia < oa)
margin = ia >> 8;
else
margin = oa >> 8;
margin *= reg_errclip_rate;
margin = (margin >> 26) ? 0x3ffffff : margin;
margin = margin << 5;
margin = (margin >> 28) ? 0xfffffff : margin;
err = oa - ia;
if (!(err < margin && err > -margin))
err = 0;
vdif_err = pvlock->err_accum + err;
vdif_err = (vdif_err > (1 << 30)) ? (1 << 30) :
(vdif_err < -(1 << 30)) ? -(1 << 30) : vdif_err;
pvlock->err_accum = (vdif_err > reg_accum_lmt) ? reg_accum_lmt :
(vdif_err < -reg_accum_lmt) ? -reg_accum_lmt : vdif_err;
T0 = (pvlock->err_accum * reg_capt_gain) >> reg_capt_rs;
T0 = -T0;
T0 = (reg_capt_lmt < T0) ? reg_capt_lmt :
(T0 < -reg_capt_lmt) ? -reg_capt_lmt : T0;
T0 = (T0 * pvlock->pre_enc_max_line) >> 10;
line_adj = T0 >> 14;
tfrac = T0 - (line_adj << 14);
pixel_adj = (tfrac * pvlock->pre_enc_max_pixel + 8192) >> 14;
while ((pixel_adj < 0) && (pvlock->pre_enc_max_pixel > 0)) {
line_adj = line_adj - 1;
pixel_adj = pvlock->pre_enc_max_pixel + pixel_adj;
}
while (((pixel_adj + pvlock->pre_enc_max_pixel) > 0x1fff) &&
(pvlock->pre_enc_max_pixel > 0)) {
line_adj = line_adj + 1;
pixel_adj = pixel_adj - pvlock->pre_enc_max_pixel;
}
if (line_adj > vlock_line_limit)
line_adj = vlock_line_limit;
else if (line_adj < -vlock_line_limit)
line_adj = -vlock_line_limit;
pixel_adj &= 0xfffffffe;/*clean bit0*/
if (vlock_enc_stable_flag++ > VLOCK_ENC_STABLE_CNT)
vlock_enc_stable_flag = VLOCK_ENC_STABLE_CNT;
if (vlock_enc_stable_flag < VLOCK_ENC_STABLE_CNT &&
(!(vlock_debug & VLOCK_DEBUG_ENC_LINE_ADJ_DIS)))
WRITE_VPP_REG(pvlock->enc_max_line_addr + offset_enc,
pvlock->pre_enc_max_line + line_adj);
if (!(vlock_debug & VLOCK_DEBUG_ENC_PIXEL_ADJ_DIS))
WRITE_VPP_REG(pvlock->enc_max_line_switch_addr + offset_enc,
pvlock->pre_enc_max_pixel + pixel_adj);
pvlock->last_i_vsync = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
if (vlock_log_en && vlock_log_cnt < vlock_log_size) {
vlock_log[vlock_log_cnt]->enc_line_max = pvlock->pre_enc_max_line;
vlock_log[vlock_log_cnt]->line_num_adj = line_adj;
vlock_log[vlock_log_cnt]->enc_pixel_max = pvlock->pre_enc_max_pixel;
vlock_log[vlock_log_cnt]->pixel_num_adj = pixel_adj;
vlock_log[vlock_log_cnt]->T0 = T0;
vlock_log[vlock_log_cnt]->vdif_err = err;
vlock_log[vlock_log_cnt]->err_sum = pvlock->err_accum;
vlock_log[vlock_log_cnt]->margin = margin;
vlock_reg_get(pvlock);
vlock_log_cnt++;
}
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info(">>>[%s]\n", __func__);
}
/*check pll adj value (0x3020),otherwise may cause blink*/
static void vlock_pll_adj_limit_check(unsigned int *pll_val)
{
unsigned int m_reg_value, pll_cur, pll_last, pll_ret;
m_reg_value = *pll_val;
if (m_reg_value != 0) {
pll_cur = ((m_reg_value & 0x3fff0000) >> 4) |
(m_reg_value & 0x3fff);
pll_last = ((vlock_pll_val_last & 0x3fff0000) >> 4) |
(vlock_pll_val_last & 0x3fff);
if (abs(pll_cur - pll_last) > vlock_pll_adj_limit) {
if (pll_cur > pll_last)
pll_ret = pll_last + vlock_pll_adj_limit;
else
pll_ret = pll_last - vlock_pll_adj_limit;
*pll_val = ((pll_ret & 0x3fff000) << 4) |
(pll_ret & 0x3fff);
}
}
}
static void vlock_update_pll(struct stvlock_sig_sts *pvlock)
{
/* pll data update */
if (pvlock->dtdata->vlk_chip >= vlock_chip_t7) {
if (pvlock->idx == VLOCK_ENC0) {
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 2, 3, 2);
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 0, 3, 2);
} else if (pvlock->idx == VLOCK_ENC1) {
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 2, 5, 2);
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 0, 5, 2);
} else if (pvlock->idx == VLOCK_ENC1) {
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 2, 7, 2);
vlock_reg_wt_bits(REG_MAP_ANACTRL, ANACTRL_TCON_PLL_VLOCK, 0, 7, 2);
}
}
}
static void vlock_enable_step3_pll(struct stvlock_sig_sts *pvlock)
{
unsigned int m_reg_value, tmp_value, abs_val;
unsigned int ia, oa, abs_cnt;
unsigned int pre_m, new_m, tar_m, org_m;
u32 m_f_reg_value;
//static u32 m_update_cnt, f_update_cnt;
u32 mchang = 0;
/*static u32 aaa;*/
u32 offset_vlck = pvlock->offset_vlck;
u32 loop0, loop1;
loop0 = READ_VPP_REG(VPU_VLOCK_RO_LOOP0_ACCUM + offset_vlck);
loop1 = READ_VPP_REG(VPU_VLOCK_RO_LOOP1_ACCUM + offset_vlck);
/*vs_i*/
tmp_value = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
abs_val = abs(vlock_log_last_ivcnt - tmp_value);
if (abs_val > vlock_log_delta_ivcnt && vlock_log_delta_en & (1 << 0))
pr_info("%s: abs_ivcnt over 0x%x:0x%x(last:0x%x,cur:0x%x)\n",
__func__, vlock_log_delta_ivcnt,
abs_val, vlock_log_last_ivcnt, tmp_value);
vlock_log_last_ivcnt = tmp_value;
/*vs_o*/
tmp_value = READ_VPP_REG(VPU_VLOCK_RO_VS_O_DIST + offset_vlck);
abs_val = abs(vlock_log_last_ovcnt - tmp_value);
if (abs_val > vlock_log_delta_ovcnt && vlock_log_delta_en & (1 << 1))
pr_info("%s: abs_ovcnt over 0x%x:0x%x(last:0x%x,cur:0x%x)\n",
__func__, vlock_log_delta_ovcnt,
abs_val, vlock_log_last_ivcnt, tmp_value);
vlock_log_last_ovcnt = tmp_value;
/*delta_vs*/
abs_val = abs(vlock_log_last_ovcnt - vlock_log_last_ivcnt);
if (abs_val > vlock_log_delta_vcnt && vlock_log_delta_en & (1 << 2))
pr_info("%s: abs_vcnt over 0x%x:0x%x(ivcnt:0x%x,ovcnt:0x%x)\n",
__func__, vlock_log_delta_vcnt,
abs_val, vlock_log_last_ivcnt, vlock_log_last_ovcnt);
m_f_reg_value = READ_VPP_REG(VPU_VLOCK_RO_M_INT_FRAC + offset_vlck);
if (vlock_log_en && vlock_log_cnt < vlock_log_size) {
tmp_value = vlock_get_panel_pll_frac(pvlock);
vlock_log[vlock_log_cnt]->pll_frac = tmp_value;
tmp_value = vlock_get_panel_pll_m(pvlock);
vlock_log[vlock_log_cnt]->pll_m = tmp_value;
vlock_reg_get(pvlock);
vlock_log_cnt++;
}
if (m_f_reg_value == 0) {
vlock_state = VLOCK_STATE_ENABLE_FORCE_RESET;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s:vlock pll work abnormal! force reset vlock\n",
__func__);
return;
}
/*check adjust delta limit*/
if (pvlock->dtdata->vlk_hwver < vlock_hw_ver2)
vlock_pll_adj_limit_check(&m_f_reg_value);
/*vlsi suggest config:don't enable load signal,
*on gxtvbb this load signal will effect SSG,
*which may result in flashes black
*/
if (is_meson_gxtvbb_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
amvecm_hiu_reg_read(HHI_HDMI_PLL_CNTL6, &tmp_value);
if (((tmp_value >> 21) & 0x3) != 2)
vlock_hiu_reg_wt_bits(HHI_HDMI_PLL_CNTL6, 2, 21, 2);
#endif
}
/* add delta count check
*for interlace input need div 2
*0:progressive type
*1:interlace type
*/
if (vlock_intput_type &&
pvlock->dtdata->vlk_hwver < vlock_hw_ver2)
ia = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck) / 2;
else
ia = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
/*for 25Hz->50Hz, 30Hz->60Hz*/
if (READ_VPP_REG_BITS(VPU_VLOCK_MISC_CTRL + offset_vlck, 16, 8) == 2)
ia = ia / 2;
oa = READ_VPP_REG(VPU_VLOCK_RO_VS_O_DIST + offset_vlck);
abs_cnt = abs(ia - oa);
if (abs_cnt > (oa / 3)) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s:vlock input cnt abnormal!!\n", __func__);
return;
}
/*m*/
tmp_value = vlock_get_panel_pll_m(pvlock);
if (pvlock->dtdata->vlk_hwver < vlock_hw_ver2) {
abs_val = abs(((m_f_reg_value >> 16) & 0xff) -
(pvlock->pre_hiu_reg_m & 0xff));
if (abs_val > vlock_log_delta_m &&
(vlock_log_delta_en & (1 << 4)))
pr_info("vlock m delta:%d(0x%x,0x%x)\n",
abs_val, ((m_f_reg_value >> 16) & 0x1ff),
(tmp_value & 0x1ff));
if (abs_val <= vlock_pll_m_limit &&
(((m_f_reg_value >> 16) & 0x1ff) !=
(tmp_value & 0x1ff)) &&
abs_cnt > vlock_delta_cnt_limit) {
tmp_value = (tmp_value & 0xfffffe00) |
((m_f_reg_value >> 16) & 0x1ff);
vlock_set_panel_pll_m(pvlock, tmp_value);
//vlock_pll_val_last &= 0x0000ffff;
//vlock_pll_val_last |= (m_f_reg_value & 0xffff0000);
}
} else {
pre_m = (tmp_value & 0xff);
new_m = ((m_f_reg_value >> 16) & 0x1ff);
org_m = (pvlock->val_m & 0xff);
if (pvlock->m_update_cnt++ > VLOCK_UPDATE_M_CNT) {
pvlock->m_update_cnt = 0;
if (org_m != new_m || pre_m != org_m) {
if (new_m > org_m)
tar_m = org_m + 1;
else if (new_m < org_m)
tar_m = org_m - 1;
else
tar_m = org_m;
m_reg_value = (tmp_value & 0xffffff00) + tar_m;
if (tar_m != pre_m) {
vlock_set_panel_pll_m(pvlock, m_reg_value);
mchang = 1;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock m: pre=0x%x, rp=0x%x, wr=0x%x\n",
pre_m, new_m, m_reg_value);
}
}
}
}
vlock_pll_val_last &= 0x0000ffff;
vlock_pll_val_last |= (m_f_reg_value & 0xffff0000);
/*frac*/
tmp_value = vlock_get_panel_pll_frac(pvlock);
if (pvlock->dtdata->vlk_hwver < vlock_hw_ver2) {
abs_val = abs(((m_f_reg_value & 0xfff) >> 2) -
(tmp_value & 0xfff));
if (abs_val >= vlock_log_delta_frac &&
(vlock_log_delta_en & (1 << 3)))
pr_info("vlock frac delta:%d(0x%x,0x%x)\n",
abs_val, ((m_f_reg_value & 0xfff) >> 2),
(tmp_value & 0xfff));
if (abs_val >= vlock_delta_limit &&
abs_cnt > vlock_delta_cnt_limit) {
tmp_value = (tmp_value & 0xfffff000) |
((m_f_reg_value & 0xfff) >> 2);
/*amvecm_hiu_reg_write(hhi_pll_reg_frac, tmp_value);*/
vlock_set_panel_pll_frac(pvlock, tmp_value);
//vlock_pll_val_last &= 0xffff0000;
//vlock_pll_val_last |= (m_f_reg_value & 0xfff);
}
/*check stable by diff frac*/
if ((abs_val < (2 * vlock_delta_limit)) &&
abs_cnt < vlock_enc_adj_limit)
vlock_pll_stable_cnt++;
else
vlock_pll_stable_cnt = 0;
} else {
/*tmp_value = (tmp_value & 0xfffe0000) |*/
/* ((m_f_reg_value & 0xfff) << 5);*/
tmp_value = ((m_f_reg_value & 0x3fff) << 5);
/*if (((tmp_value & 0x1ffff) !=*/
/* (vlock_get_panel_pll_frac(pvlock) & 0x1ffff)) &&*/
/* !mchang) */{
if (pvlock->f_update_cnt++ > VLOCK_UPDATE_F_CNT) {
pvlock->f_update_cnt = 0;
if (vlock_debug & VLOCK_DEBUG_INFO) {
pr_info("vlock f: 0x%x rep:0x%x(i:0x%x o:0x%x)(loop:0x%x,0x%x)\n",
tmp_value, m_f_reg_value, ia, oa, loop0, loop1);
}
vlock_set_panel_pll_frac(pvlock, tmp_value);/*16:0*/
}
}
}
vlock_update_pll(pvlock);
vlock_pll_val_last &= 0xffff0000;
vlock_pll_val_last |= (m_f_reg_value & 0xfff);
/*check stable by diff m*/
if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2) {
if (((m_f_reg_value >> 16) & 0xff) != (tmp_value & 0xff))
vlock_pll_stable_cnt = 0;
} else {
if (((m_f_reg_value >> 16) & 0x1ff) != (tmp_value & 0x1ff))
vlock_pll_stable_cnt = 0;
}
}
void vlock_clear_frame_counter(struct stvlock_sig_sts *pvlock)
{
pvlock->frame_cnt_in = 0;
pvlock->frame_cnt_no = 0;
vlock_log_cnt = 0;
pvlock->phlock_sts = false;
pvlock->frqlock_sts = false;
pvlock->pll_mode_pause = false;
/*vlock.frqlock_stable_cnt = 0;*/
if (phase_en_after_frqlock)
pvlock->phlock_en = false;
pvlock->start_chk_ph = false;
pvlock->all_lock_cnt = 0;
}
void vlock_set_en(bool en)
{
vlock_en = en;
}
void vlock_enable_step3_auto_enc(struct stvlock_sig_sts *pvlock)
{
struct vinfo_s *vinfo;
u32 oa;
u32 stbdec_win0, stbdec_win1;
u32 th0, th1;
//static u32 cnt;
u32 offset_vlck = pvlock->offset_vlck;
if (pvlock->enable_auto_enc_cnt++ < 10)
return;
pvlock->enable_auto_enc_cnt = 0;
/*one line error*/
oa = READ_VPP_REG(VPU_VLOCK_RO_VS_O_DIST + offset_vlck);
vinfo = get_current_vinfo();
stbdec_win0 = READ_VPP_REG(VPU_VLOCK_STBDET_WIN0_WIN1 + offset_vlck) & 0xff;
stbdec_win1 = (READ_VPP_REG(VPU_VLOCK_STBDET_WIN0_WIN1 + offset_vlck) >> 8) & 0xff;
th0 = (oa * stbdec_win0 * 7) / vinfo->vtotal;
th1 = (oa * stbdec_win1 * 8) / vinfo->vtotal;
WRITE_VPP_REG(VPU_VLOCK_WIN0_TH + offset_vlck, th0);
WRITE_VPP_REG(VPU_VLOCK_WIN1_TH + offset_vlck, th1);
}
void vlock_dev_param_init(void)
{
vlock_tab[VLOCK_ENC0] = &vlock0;
vlock_tab[VLOCK_ENC1] = &vlock1;
vlock_tab[VLOCK_ENC2] = &vlock2;
}
void vlock_status_init(void)
{
struct stvlock_sig_sts *pvlock;
u32 i, max_enc_num;
u32 offset_vlck;
u32 offset_enc;
struct vinfo_s *vinfo;
/*config vlock mode*/
/*todo:txlx & g9tv support auto pll,*/
/*but support not good,need vlsi support optimize*/
vinfo = get_current_vinfo();
vlock_dev_param_init();
pvlock = vlock_tab[VLOCK_ENC0];
if (pvlock->dtdata->vlk_chip == vlock_chip_t7)
max_enc_num = VLOCK_ENC2;
else
max_enc_num = VLOCK_ENC0;
for (i = VLOCK_ENC0; i <= max_enc_num; i++) {
pvlock = vlock_tab[i];
pvlock->idx = i;
if (i == VLOCK_ENC0) {
pvlock->offset_encl = 0x00;
pvlock->offset_vlck = 0x00;
} else if (i == VLOCK_ENC1) {
pvlock->offset_encl = 0x600;
pvlock->offset_vlck = 0x40;
} else if (i == VLOCK_ENC2) {
pvlock->offset_encl = 0x800;
pvlock->offset_vlck = 0x80;
}
offset_vlck = pvlock->offset_vlck;
offset_enc = pvlock->offset_encl;
/*initial pll register address*/
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TM2)) {
pvlock->hhi_pll_reg_m = HHI_TCON_PLL_CNTL0;
pvlock->hhi_pll_reg_frac = HHI_TCON_PLL_CNTL1;
/*hhi_pll_reg_vlock_ctl = HHI_HDMI_PLL_VLOCK_CNTL;*/
} else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) {
pvlock->hhi_pll_reg_m = HHI_HDMI_PLL_CNTL;
pvlock->hhi_pll_reg_frac = HHI_HDMI_PLL_CNTL2;
} else {
pvlock->hhi_pll_reg_m = HHI_HDMI_PLL_CNTL;
pvlock->hhi_pll_reg_frac = HHI_HDMI_PLL_CNTL2;
}
/*initial enc register address*/
switch (VLOCK_OUT_ENCL/*READ_VPP_REG_BITS(VPU_VIU_VENC_MUX_CTRL, 0, 2)*/) {/* ?? */
case 0:
pvlock->enc_max_line_addr = ENCL_VIDEO_MAX_LNCNT;
pvlock->enc_max_pixel_addr = ENCL_VIDEO_MAX_PXCNT;
pvlock->enc_video_mode_addr = ENCL_VIDEO_MODE;
pvlock->enc_video_mode_adv_addr = ENCL_VIDEO_MODE_ADV;
pvlock->enc_max_line_switch_addr = ENCL_MAX_LINE_SWITCH_POINT;
pvlock->enc_frc_v_porch_addr = ENCL_FRC_CTRL;
break;
/*enc mode not adapt to ENCP and ENCT*/
default:
pvlock->enc_max_line_addr = ENCL_VIDEO_MAX_LNCNT;
pvlock->enc_max_pixel_addr = ENCL_VIDEO_MAX_PXCNT;
pvlock->enc_video_mode_addr = ENCL_VIDEO_MODE;
pvlock->enc_video_mode_adv_addr = ENCL_VIDEO_MODE_ADV;
pvlock->enc_max_line_switch_addr = ENCL_MAX_LINE_SWITCH_POINT;
pvlock->enc_frc_v_porch_addr = ENCL_FRC_CTRL;
break;
}
/*back up original pll value*/
pvlock->val_m = vlock_get_panel_pll_m(pvlock);
pvlock->val_frac = vlock_get_panel_pll_frac(pvlock);
/*enc mode initial val*/
pvlock->org_enc_line_num = READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
pvlock->org_enc_pixel_num = READ_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc);
pvlock->pre_enc_max_line = READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
pvlock->pre_enc_max_pixel = READ_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc);
if (pvlock->dtdata->vlk_chip == vlock_chip_t3 && pvlock->idx == VLOCK_ENC0) {
pvlock->enc_frc_v_porch =
READ_VPP_REG_BITS(pvlock->enc_frc_v_porch_addr + offset_enc, 0, 16);
pvlock->enc_frc_max_line = pvlock->org_enc_line_num;
pvlock->enc_frc_max_pixel = pvlock->org_enc_pixel_num;
}
pr_info("vlock: enc org Line addr:0x%x org_enc_line_num val: %d\n",
pvlock->enc_max_line_addr + offset_enc,
pvlock->org_enc_line_num);
pr_info("vlock: enc org Pixel addr:0x%x val: %d\n",
pvlock->enc_max_pixel_addr + offset_enc,
pvlock->org_enc_pixel_num);
pvlock->fsm_sts = VLOCK_STATE_NULL;
pvlock->fsm_prests = VLOCK_STATE_NULL;
pvlock->vf_sts = false;
pvlock->vmd_chg = false;
pvlock->md_support = false;
pvlock->fsm_pause = false;
pvlock->ss_sts = true;
pvlock->phlock_sts = false;
pvlock->frqlock_sts = false;
pvlock->pll_mode_pause = false;
pvlock->m_update_cnt = 0;
pvlock->f_update_cnt = 0;
pvlock->enable_cnt = 0;
pvlock->enable_auto_enc_cnt = 0;
pvlock->pre_line = 0;
pvlock->pre_pixel = 0;
pvlock->chk_lock_sts_rstflag = 0;
pvlock->chk_lock_sts_cnt = 0;
pvlock->chk_lock_sts_vs_in = 0;
pvlock->chk_lock_sts_vs_out = 0;
/* when unlock disable ss*/
if (pvlock->dtdata->vlk_hwver >= vlock_hw_tm2verb) {
vlock_ss_en = 0;
speed_up_en = 1;
} else {
vlock_ss_en = 1;
}
if (!phase_en_after_frqlock)
pvlock->phlock_en = pvlock->dtdata->vlk_phlock_en;
/* vlock.phlock_percent = phlock_percent; */
vlock_clear_frame_counter(pvlock);
vlock_hw_reinit(pvlock, vlock_enc_setting, VLOCK_DEFAULT_REG_SIZE);
vlock_dis_cnt = 0;
msleep(2);
vlock_disable_step2(pvlock);
pr_info("%s vlock_en:%d\n", __func__, vlock_en);
}
pr_info("%s vlock_en:%d adj_type:%d mode:%d\n", __func__, vlock_en,
vinfo->fr_adj_type, vinfo->mode);
}
void vlock_dt_match_init(struct vecm_match_data_s *pdata)
{
struct stvlock_sig_sts *pvlock;
u32 i;
vlock_dev_param_init();
for (i = VLOCK_ENC0; i <= VLOCK_ENC2; i++) {
pvlock = vlock_tab[i];
pvlock->dtdata = pdata;
}
/*vlock_en = vlock.dtdata.vlk_support;*/
// pr_info("vlock dt support: %d\n", vlock.dtdata->vlk_support);
// pr_info("vlock dt new_fsm: %d\n", vlock.dtdata->vlk_new_fsm);
// pr_info("vlock dt hwver: %d\n", vlock.dtdata->vlk_hwver);
// pr_info("vlock dt phlock_en: %d\n", vlock.dtdata->vlk_phlock_en);
}
void vlock_set_phase(struct stvlock_sig_sts *pvlock, u32 percent)
{
u32 ia;
u32 data = 0;
u32 offset_vlck;
if (!pvlock->phlock_en)
return;
offset_vlck = pvlock->offset_vlck;
if (percent > 100) {
pr_info("percent val err:%d\n", percent);
return;
}
ia = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
pvlock->phlock_percent = percent;
data = (ia * (100 + pvlock->phlock_percent)) / 200;
WRITE_VPP_REG(VPU_VLOCK_LOOP1_PHSDIF_TGT + offset_vlck, data);
vlock_reset(pvlock, 1);
vlock_reset(pvlock, 0);
}
void vlock_set_phase_en(struct stvlock_sig_sts *pvlock, u32 en)
{
u32 offset_vlck = pvlock->offset_vlck;
if (en) {
pvlock->phlock_en = true;
if (IS_PLL_MODE(vlock_mode))
vlock_hw_reinit(pvlock, vlock_pll_phase_setting, VLOCK_PHASE_REG_SIZE);
else
vlock_hw_reinit(pvlock, vlock_encl_phase_setting, VLOCK_PHASE_REG_SIZE);
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 3, 0, 2);*/
if (IS_PLL_MODE(vlock_mode))
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 0, 1);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 1, 1);
vlock_reset(pvlock, 1);
vlock_reset(pvlock, 0);
} else {
pvlock->phlock_en = false;
}
pr_info("vlock phlock_en=%d\n", en);
}
u32 vlock_get_phase_en(u32 enc_idx)
{
struct stvlock_sig_sts *pvlock;
if (enc_idx < VLOCK_ENC_MAX)
pvlock = vlock_tab[enc_idx];
else
return 0;
if (!pvlock)
return 0;
return pvlock->phlock_en;
}
void vlock_phaselock_check(struct stvlock_sig_sts *pvlock,
struct vframe_s *vf)
{
/*vs_i*/
u32 ia;
u32 val, pre;
u32 offset_vlck;
offset_vlck = pvlock->offset_vlck;
ia = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
if (pvlock->phlock_en) {
if ((pvlock->frame_cnt_in % 20) == 0) {
pre = READ_VPP_REG(VPU_VLOCK_LOOP1_PHSDIF_TGT + offset_vlck);
val = (ia * (100 + pvlock->phlock_percent)) / 200;
if (abs(val - pre) > 5) {
WRITE_VPP_REG(VPU_VLOCK_LOOP1_PHSDIF_TGT + offset_vlck, val);
vlock_reset(pvlock, 1);
vlock_reset(pvlock, 0);
}
/*vdin0 register*/
pvlock->vdinsts.lcnt_sts =
READ_VPP_REG(0x1204/*VDIN_LCNT_STATUS*/);
pvlock->vdinsts.com_sts0 =
READ_VPP_REG(0x1205/*VDIN_COM_STATUS0*/);
pvlock->vdinsts.com_sts1 =
READ_VPP_REG(0x1206/*VDIN_COM_STATUS1*/);
}
}
}
bool vlock_get_phlock_flag_ex(struct stvlock_sig_sts *pvlock)
{
u32 flag;
u32 sts;
u32 offset_vlck;
if (!pvlock)
return 0;
if (!pvlock->phlock_en)
return false;
offset_vlck = pvlock->offset_vlck;
if (pvlock->dtdata->vlk_hwver >= vlock_hw_tm2verb)
flag = READ_VPP_REG(VPU_VLOCK_RO_LCK_FRM + offset_vlck) >> 17;
else
flag = READ_VPP_REG(VPU_VLOCK_RO_LCK_FRM + offset_vlck) >> 16;
flag = flag & 0x01;
if (pvlock->dtdata->vlk_new_fsm)
sts = pvlock->fsm_sts;
else
sts = vlock_state;
if (flag && sts == VLOCK_STATE_ENABLE_STEP2_DONE)
return true;
else
return false;
}
bool vlock_get_vlock_flag_ex(struct stvlock_sig_sts *pvlock)
{
u32 flag;
u32 sts;
u32 offset_vlck;
if (!pvlock)
return 0;
offset_vlck = pvlock->offset_vlck;
if (pvlock->dtdata->vlk_hwver >= vlock_hw_tm2verb)
flag = READ_VPP_REG(VPU_VLOCK_RO_LCK_FRM + offset_vlck) >> 16;
else
flag = READ_VPP_REG(VPU_VLOCK_RO_LCK_FRM + offset_vlck) >> 17;
flag = flag & 0x01;
if (pvlock->dtdata->vlk_new_fsm)
sts = pvlock->fsm_sts;
else
sts = vlock_state;
if (flag && sts == VLOCK_STATE_ENABLE_STEP2_DONE)
return true;
else
return false;
}
bool vlock_get_phlock_flag(void)
{
struct stvlock_sig_sts *pvlock = vlock_tab[VLOCK_ENC0];
return vlock_get_phlock_flag_ex(pvlock);
}
bool vlock_get_vlock_flag(void)
{
struct stvlock_sig_sts *pvlock = vlock_tab[VLOCK_ENC0];
return vlock_get_vlock_flag_ex(pvlock);
}
void vlock_enc_timing_monitor(struct stvlock_sig_sts *pvlock)
{
//static unsigned int pre_line, pre_pixel;
unsigned int cur_line, cur_pixel;
unsigned int val;
u32 offset_vlck = pvlock->offset_vlck;
val = READ_VPP_REG(VPU_VLOCK_RO_LINE_PIX_ADJ + offset_vlck);
cur_pixel = (val & 0x0000ffff);
cur_line = (val >> 16) & 0x0000ffff;
if ((vlock_debug & VLOCK_DEBUG_INFO) &&
(cur_line != pvlock->pre_line || cur_pixel != pvlock->pre_pixel)) {
dprintk(1, "adj line=(0x%04x,0x%04x) pixel=(0x%04x,0x%04x)\n",
cur_line, pvlock->pre_line, cur_pixel, pvlock->pre_pixel);
pvlock->pre_line = cur_line;
pvlock->pre_pixel = cur_pixel;
}
}
void vlock_auto_pll_sts_check(struct stvlock_sig_sts *pvlock)
{
u32 m_f_reg_value;
u32 pll_m, pll_f;
u32 offset_vlck = pvlock->offset_vlck;
if (vlock_debug & VLOCK_DEBUG_INFO) {
m_f_reg_value = READ_VPP_REG(VPU_VLOCK_RO_M_INT_FRAC + offset_vlck);
pll_m = (m_f_reg_value >> 16) & 0xff;
pll_f = m_f_reg_value & 0xffff;
if ((pvlock->val_m & 0xff) != pll_m)
dprintk(1, "vlock m:(0x%x 0x%x) f:0x%x\n",
pvlock->val_m, pll_m, pll_f);
}
}
u32 vlock_fsm_check_support(struct stvlock_sig_sts *pvlock,
struct vframe_s *vf, struct vinfo_s *vinfo)
{
u32 ret = true;
u32 vs_support = false;
u32 video_clk = vinfo->sync_duration_num / vinfo->sync_duration_den;
/* ex:30Hz->30Hz 50Hz->50Hz ...*/
if (pvlock->input_hz > 0 &&
(pvlock->input_hz == pvlock->output_hz))
vs_support = true;
/* ex:30Hz->60Hz 25Hz->50Hz or in 24->60Hz */
if ((pvlock->input_hz > 0 &&
((pvlock->input_hz * 2) == pvlock->output_hz) &&
(vlock_support & VLOCK_SUPPORT_1TO2)) ||
(pvlock->input_hz == 24 && pvlock->output_hz == 60))
vs_support = true;
if ((!vs_support && vlock_adapt == 0) ||
pvlock->input_hz == 0 || pvlock->output_hz == 0 ||
(((vf->type_original & VIDTYPE_TYPEMASK)
!= VIDTYPE_PROGRESSIVE) &&
is_meson_txlx_package_962E())) {
if (vlock_debug & VLOCK_DEBUG_INFO) {
pr_info("[%s] for no support case!!! vf:0x%x\n",
__func__, vf->type_original);
pr_info("vs_sup:%d input_hz:%d, output_hz:%d\n",
vs_support, pvlock->input_hz,
pvlock->output_hz);
pr_info("type_original:0x%x\n", vf->type_original);
}
ret = false;
}
if (vlock_notify_event == VOUT_EVENT_MODE_CHANGE_PRE) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("[%s] for vmode change pre case!!!\n",
__func__);
ret = false;
}
if (vinfo->fr_adj_type == VOUT_FR_ADJ_NONE ||
vinfo->fr_adj_type == VOUT_FR_ADJ_HDMI) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("[%s] for adj_type VOUT_FR_ADJ_NONE or VOUT_FR_ADJ_HDMI!!!\n",
__func__);
ret = false;
}
if (freerun_en == GAME_MODE &&
(vinfo->fr_adj_type == VOUT_FR_ADJ_FREERUN &&
((pvlock->input_hz == 50 && diff(video_clk, 50) <= 1) ||
(pvlock->input_hz == 60 && diff(video_clk, 60) <= 1)))) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("[%s] FREERUN input 50 or 60hz, fix out frame rate,video_clk :%d!!!\n",
__func__, video_clk);
ret = true;
} else if (freerun_en == FREERUN_MODE &&
vinfo->fr_adj_type == VOUT_FR_ADJ_FREERUN){
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("[%s] video_clk :%d VOUT_FR_ADJ_FREERUN and freerun_en == FREERUN_MODE!!!\n",
__func__, video_clk);
ret = false;
}
return ret;
}
void vlock_vmd_input_check(struct stvlock_sig_sts *pvlock)
{
if (vlock_input_pre != pvlock->input_hz && pvlock->md_support &&
(pvlock->output_hz == pvlock->input_hz * 2)) {
pvlock->fsm_sts = VLOCK_STATE_NULL;
pvlock->vmd_chg = true;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock input frame rate chg fsm_prests:%d fsm_sts:%d\n",
pvlock->fsm_prests, pvlock->fsm_sts);
}
vlock_input_pre = pvlock->input_hz;
}
u32 vlock_fsm_input_check(struct stvlock_sig_sts *pvlock, struct vframe_s *vf)
{
u32 ret = 0;
u32 vframe_sts;
struct vinfo_s *vinfo = NULL;
if (!vf)
vframe_sts = false;
else
vframe_sts = true;
vlock_vmode_check(pvlock);
if (vf) {
vinfo = get_current_vinfo();
pvlock->input_hz = vlock_check_input_hz(vf);
pvlock->output_hz =
vlock_check_output_hz(vinfo->sync_duration_num,
vinfo->sync_duration_den);
pvlock->duration = vf->duration;
//if (vlock_debug & VLOCK_DEBUG_INFO)
// pr_info("input_hz:%d duration:%d\n", pvlock->input_hz, pvlock->duration);
}
/*check vf exist status*/
if (pvlock->vf_sts != vframe_sts) {
pvlock->vf_sts = vframe_sts;
/*if (vlock_debug & VLOCK_DEBUG_INFO)*/
/* pr_info("vlock vfsts chg %d\n", vframe_sts);*/
ret = 1;
} else if (vlock_notify_event) {
/*check video mode status*/
pvlock->vmd_chg = true;
ret = 1;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock vmode chg\n");
}
if (pvlock->vf_sts)
pvlock->md_support = vlock_fsm_check_support(pvlock, vf, vinfo);
return ret;
}
u32 vlock_fsm_to_en_func(struct stvlock_sig_sts *pvlock,
struct vframe_s *vf)
{
u32 ret = 0;
struct vinfo_s *vinfo;
u32 offset_enc;
if (!pvlock || !vf)
return ret;
offset_enc = pvlock->offset_encl;
vdin_vlock_input_sel(pvlock, vf->type, vf->source_type);
if (vf->source_type != pre_source_type ||
vf->source_mode != pre_source_mode ||
pvlock->input_hz != pre_input_freq ||
pvlock->output_hz != pre_output_freq ||
vlock_vmode_changed ||
pvlock->fsm_sts == VLOCK_STATE_ENABLE_FORCE_RESET) {
/*back up original pll value*/
pvlock->val_m = vlock_get_panel_pll_m(pvlock);
pvlock->val_frac = vlock_get_panel_pll_frac(pvlock);
pvlock->org_enc_line_num = READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc);
pvlock->org_enc_pixel_num = READ_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc);
pvlock->pre_enc_max_line = pvlock->org_enc_line_num;
pvlock->pre_enc_max_pixel = pvlock->org_enc_pixel_num;
if (vlock_debug & VLOCK_DEBUG_FLASH)
pr_info("%s pre_enc_max_line:%d org_enc_line_num:%d pre_enc_max_pixel:%d\n",
__func__,
pvlock->pre_enc_max_line,
pvlock->org_enc_line_num,
pvlock->pre_enc_max_pixel);
//if (vlock_debug & VLOCK_DEBUG_INFO) {
// pr_info("HIU pll m[0x%x]=0x%x\n",
// pvlock->hhi_pll_reg_m, pvlock->val_m);
// pr_info("HIU pll f[0x%x]=0x%x\n",
// pvlock->hhi_pll_reg_frac, pvlock->val_frac);
// pr_info("vlock: Line %d,Pixel %d\n",
// pvlock->org_enc_line_num, pvlock->org_enc_pixel_num);
//}
vinfo = get_current_vinfo();
vlock_enable_step1(vf, vinfo, pvlock);
if (vlock_ss_en && IS_PLL_MODE(vlock_mode)) {
vlock_set_panel_ss(false);
pvlock->ss_sts = false;
}
ret = 1;
}
/* set phase
* out > in, game mode can't read write the same buffer
*/
if (pvlock->video_inverse)
pvlock->phlock_percent = 15;
else if ((pvlock->input_hz > 0) &&
(pvlock->input_hz * 2 == pvlock->output_hz))
pvlock->phlock_percent = 25;
else
pvlock->phlock_percent = 40;
return ret;
}
u32 vlock_fsm_en_step1_func(struct stvlock_sig_sts *pvlock,
struct vframe_s *vf)
{
u32 ret = 0;
u32 input_vs_cnt;
u32 offset_vlck = pvlock->offset_vlck;
//u32 offset_enc = pvlock->offset_enc;
if (pvlock->frame_cnt_in <= 3 &&
((vlock_mode & (VLOCK_MODE_MANUAL_ENC |
VLOCK_MODE_MANUAL_PLL)))) {
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 5, 1);*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 2, 1);*/
vlock_reset(pvlock, 1);
/*clear first 3 frame internal cnt*/
WRITE_VPP_REG(VPU_VLOCK_OVWRITE_ACCUM0 + offset_vlck, 0);
WRITE_VPP_REG(VPU_VLOCK_OVWRITE_ACCUM1 + offset_vlck, 0);
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s -0\n", __func__);
} else if (pvlock->frame_cnt_in == 4 &&
((vlock_mode & (VLOCK_MODE_MANUAL_ENC |
VLOCK_MODE_MANUAL_PLL)))) {
/*cal accum0 value*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 5, 1);*/
/*cal accum1 value*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 2, 1);*/
//vlock_reset(pvlock, 0);
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s -1\n", __func__);
} else if (pvlock->frame_cnt_in == 5) {
/*input_vs_cnt =*/
/*READ_VPP_REG_BITS(VPU_VLOCK_RO_VS_I_DIST + offset_vlck,*/
/* 0, 28);*/
input_vs_cnt = XTAL_VLOCK_CLOCK / pvlock->input_hz;
/*tl1 not need */
if (!cpu_after_eq(MESON_CPU_MAJOR_ID_TL1) &&
vf->type_original & VIDTYPE_TYPEMASK)
input_vs_cnt = input_vs_cnt << 1;
WRITE_VPP_REG(VPU_VLOCK_LOOP1_IMISSYNC_MAX + offset_vlck, input_vs_cnt * 125 / 100);
WRITE_VPP_REG(VPU_VLOCK_LOOP1_IMISSYNC_MIN + offset_vlck, input_vs_cnt * 70 / 100);
/*cal accum1 value*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 2, 1);*/
/*cal accum0 value*/
/*WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 0, 5, 1);*/
vlock_reset(pvlock, 0);
/*
* tl1 auto pll,swich clk need after
*several frames
*/
vlock_pll_select(pvlock, vlock_mode, pvlock->dtdata->vlk_pll_sel);
ret = 1;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s -2\n", __func__);
}
return ret;
}
u32 vlock_fsm_check_lock_sts(struct stvlock_sig_sts *pvlock,
struct vframe_s *vf)
{
u32 frqlock_sts = vlock_get_vlock_flag_ex(pvlock);
u32 phlock_sts = vlock_get_phlock_flag_ex(pvlock);
u32 pherr;
//static u32 rstflag;
u32 ret = VLOCK_CHG_NONE;
//static u32 cnt;
//static u32 vs_in, vs_out;
u32 temp_vs_in, temp_vs_out;
u32 pherr_negative = 0;/*-*/
u32 offset_vlck = pvlock->offset_vlck;
//u32 offset_enc = pvlock->offset_enc;
u32 all_lock_cnt = VLOCK_ALL_LOCK_CNT;
if (pvlock->input_hz * 2 == pvlock->output_hz)
all_lock_cnt = VLOCK_ALL_LOCK_CNT / 2;
if (pvlock->chk_lock_sts_cnt++ > 10)
pvlock->chk_lock_sts_cnt = 0;
/*check frq lock*/
if (pvlock->frqlock_sts != frqlock_sts) {
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock frq lock sts(%d,%d) --------- cnt:%d\n",
pvlock->frqlock_sts,
frqlock_sts, pvlock->frame_cnt_in);
pvlock->frqlock_sts = frqlock_sts;
}
/*enable phase lock after frq lock*/
if (phase_en_after_frqlock && !pvlock->phlock_en &&
pvlock->frqlock_sts && pvlock->frame_cnt_in > 50) {
if (pvlock->dtdata->vlk_phlock_en) {
pvlock->phlock_en = pvlock->dtdata->vlk_phlock_en;
pr_info("enable phase lock\n");
if (IS_PLL_MODE(vlock_mode))
vlock_hw_reinit(pvlock, vlock_pll_phase_setting,
VLOCK_PHASE_REG_SIZE);
else
vlock_hw_reinit(pvlock, vlock_encl_phase_setting,
VLOCK_PHASE_REG_SIZE);
if (IS_PLL_MODE(vlock_mode))
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 0, 1);
else
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 1, 1, 1);
vlock_reset(pvlock, 1);
vlock_reset(pvlock, 0);
}
}
/*check phase err*/
pherr = READ_VPP_REG(VPU_VLOCK_RO_PH_ERR + offset_vlck) & 0xffffff;
if ((vlock_debug & VLOCK_DEBUG_INFO) && pvlock->chk_lock_sts_cnt == 1 &&
IS_AUTO_MODE(vlock_mode))
pr_info("pherr cnt:0x%x\n", pherr);
/*after frq lock, then enable phase lock*/
if (pherr & 0x800000) {
pherr = 0xffffff - pherr + 1;/*negative value*/
pherr_negative = 1;
}
/*check phase error*/
if (IS_PLL_MODE(vlock_mode) &&
pvlock->phlock_en) {
if (pvlock->chk_lock_sts_rstflag) {
pvlock->chk_lock_sts_rstflag = false;
vlock_reset(pvlock, 0);
} else if (pherr > 0x1ff) {
if ((pvlock->frame_cnt_in % 80) == 0) {
vlock_reset(pvlock, 1);
pvlock->chk_lock_sts_rstflag = true;
}
}
}
/*check input vs time*/
temp_vs_in = READ_VPP_REG(VPU_VLOCK_RO_VS_I_DIST + offset_vlck);
temp_vs_out = READ_VPP_REG(VPU_VLOCK_RO_VS_O_DIST + offset_vlck);
/*counter clock 24Mhz, diff time > 2/10 is error sync*/
if ((diff(pvlock->chk_lock_sts_vs_in, temp_vs_in) >
(((2000000000 / (pvlock->input_hz * 83)) * 2) / 10)) &&
pvlock->frame_cnt_in > 2000)
pr_info("err insync t: cur:0x%x pre:0x%x\n",
temp_vs_in, pvlock->chk_lock_sts_vs_in);
pvlock->chk_lock_sts_vs_in = temp_vs_in;
/*check outpu vs time*/
if ((diff(pvlock->chk_lock_sts_vs_out, temp_vs_out) >
(((2000000000 / (pvlock->output_hz * 83)) * 2) / 10)) &&
pvlock->frame_cnt_in > 2000)
pr_info("err outsync t: cur:0x%x pre:0x%x\n",
temp_vs_out, pvlock->chk_lock_sts_vs_out);
pvlock->chk_lock_sts_vs_out = temp_vs_out;
/*check phase lock*/
if (pvlock->phlock_en) {
if (pvlock->phlock_sts != phlock_sts) {
pvlock->phlock_cnt = 0;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock ph lock sts(%d,%d) -----cnt:%d\n",
pvlock->phlock_sts,
phlock_sts, pvlock->frame_cnt_in);
pvlock->phlock_sts = phlock_sts;
} else {
pvlock->phlock_cnt++;
if (pvlock->phlock_sts && !pvlock->ss_sts &&
pvlock->phlock_cnt > 50) {
if (vlock_ss_en && !pvlock->ss_sts) {
pvlock->ss_sts = true;
vlock_set_panel_ss(true);
}
}
}
}
/*check phase flag*/
if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2 && pvlock->phlock_en) {
if (pvlock->start_chk_ph) {
if (!vlock_get_phlock_flag_ex(pvlock)) {
if (pvlock->all_lock_cnt++ > 2) {
if (pherr_negative)
pherr = pherr | 0x800000;
if (vlock_debug & VLOCK_DEBUG_INFO_ERR)
pr_info("ph unlock:ph err=0x%x\n",
pherr);
return VLOCK_CHG_NEED_RESET;
}
}
} else {
if (frqlock_sts && phlock_sts) {
if (pvlock->all_lock_cnt++ > all_lock_cnt) {
pvlock->start_chk_ph = 1;
pvlock->all_lock_cnt = 0;
if (vlock_debug & VLOCK_DEBUG_INFO_ERR)
pr_info("vlock:----- all lock\n");
}
} else {
pvlock->all_lock_cnt = 0;
pvlock->start_chk_ph = 0;
/* long time not lock reset vlock*/
if ((pvlock->frame_cnt_in++ % 18000) == 0) {
if (vlock_debug & VLOCK_DEBUG_INFO_ERR)
pr_info("long time unlock,rst\n");
return VLOCK_CHG_NEED_RESET;
}
}
}
}
/*pretect and enable ss*/
if (IS_PLL_MODE(vlock_mode) &&
pvlock->phlock_en) {
/*error check*/
if (pvlock->frame_cnt_in >= 3000 && !pvlock->ss_sts) {
/*pvlock->pll_mode_pause = true;*/
if (vlock_ss_en && !pvlock->ss_sts) {
pvlock->ss_sts = true;
vlock_set_panel_ss(true);
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock phase err, need retry\n");
return VLOCK_CHG_NEED_RESET;
}
}
}
return ret;
}
u32 vlock_fsm_en_step2_func(struct stvlock_sig_sts *pvlock,
struct vframe_s *vf)
{
u32 ret = 0;
if (vlock_dynamic_adjust &&
(cpu_after_eq(MESON_CPU_MAJOR_ID_GXTVBB)) &&
(IS_MANUAL_MODE(vlock_mode))) {
if (IS_MANUAL_ENC_MODE(vlock_mode))
vlock_enable_step3_enc(pvlock);
else if (IS_MANUAL_PLL_MODE(vlock_mode) &&
(!pvlock->pll_mode_pause))
vlock_enable_step3_pll(pvlock);
else if (IS_MANUAL_SOFTENC_MODE(vlock_mode))
vlock_enable_step3_soft_enc(pvlock);
}
if (IS_ENC_MODE(vlock_mode)) {
vlock_enable_step3_auto_enc(pvlock);
vlock_enc_timing_monitor(pvlock);
}
if (IS_AUTO_PLL_MODE(vlock_mode))
vlock_auto_pll_sts_check(pvlock);
/*check phase*/
vlock_phaselock_check(pvlock, vf);
ret = vlock_fsm_check_lock_sts(pvlock, vf);
if (ret == VLOCK_CHG_NEED_RESET)
return 0;
else
return 1;
}
void vlock_fsm_monitor(struct vframe_s *vf, struct stvlock_sig_sts *pvlock)
{
u32 changed;
u32 timeout = 0;
if (pvlock->fsm_pause)
return;
changed = vlock_fsm_input_check(pvlock, vf);
vlock_vmd_input_check(pvlock);
switch (pvlock->fsm_sts) {
case VLOCK_STATE_NULL:
if (pvlock->vf_sts) {
/*have frame in*/
pvlock->frame_cnt_no = 0;
if (pvlock->frame_cnt_in++ >= VLOCK_START_CNT) {
/*vframe input valid*/
if (pvlock->md_support) {
if (vlock_fsm_to_en_func(pvlock, vf)) {
vlock_clear_frame_counter(pvlock);
pvlock->fsm_sts =
VLOCK_STATE_ENABLE_STEP1_DONE;
} else {
/*error waitting here*/
vlock_clear_frame_counter(pvlock);
}
}
}
} else if (pvlock->vmd_chg) {
vlock_clear_frame_counter(pvlock);
pvlock->vmd_chg = false;
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP2_DONE;
} else {
/*disabled and waitting here*/
if (pvlock->frame_cnt_no++ > vlock_dis_cnt_no_vf_limit)
vlock_clear_frame_counter(pvlock);
}
break;
case VLOCK_STATE_ENABLE_STEP1_DONE:
if (pvlock->vf_sts) {
pvlock->frame_cnt_in++;
pvlock->frame_cnt_no = 0;
if (vlock_fsm_en_step1_func(pvlock, vf))
pvlock->fsm_sts = VLOCK_STATE_ENABLE_STEP2_DONE;
} else if (pvlock->vmd_chg) {
vlock_clear_frame_counter(pvlock);
pvlock->vmd_chg = false;
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP1_DONE;
} else {
if (pvlock->frame_cnt_no++ > vlock_dis_cnt_no_vf_limit) {
/*go to disable state*/
vlock_clear_frame_counter(pvlock);
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP1_DONE;
}
}
break;
case VLOCK_STATE_ENABLE_STEP2_DONE:
if (pvlock->vf_sts) {
pvlock->frame_cnt_in++;
pvlock->frame_cnt_no = 0;
if (!pvlock->md_support) {
/*function not support*/
vlock_clear_frame_counter(pvlock);
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP1_DONE;
} else if (vecm_latch_flag & FLAG_VLOCK_DIS) {
/*disable vlock by vecm cmd*/
vlock_disable_step1(pvlock);
timeout = 0;
while (vlock_disable_step2(pvlock) == 0) {
if (timeout++ > 4)
break;
}
//vlock_en = 0;
//vecm_latch_flag &= ~FLAG_VLOCK_DIS;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("[%s] vlock dis\n", __func__);
vlock_clear_frame_counter(pvlock);
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP1_DONE;
} else {
/*normal mode*/
pvlock->frame_cnt_no = 0;
if (vlock_fsm_en_step2_func(pvlock, vf) <= 0) {
pvlock->fsm_sts =
VLOCK_STATE_DISABLE_STEP1_DONE;
vlock_clear_frame_counter(pvlock);
}
}
} else if (pvlock->vmd_chg) {
vlock_clear_frame_counter(pvlock);
pvlock->vmd_chg = false;
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP1_DONE;
} else {
/*no frame input*/
if (pvlock->frame_cnt_no++ > vlock_dis_cnt_no_vf_limit) {
/*go to disable state*/
vlock_clear_frame_counter(pvlock);
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP1_DONE;
}
}
break;
case VLOCK_STATE_DISABLE_STEP1_DONE:
vlock_disable_step1(pvlock);
if (vlock_disable_step2(pvlock))
pvlock->fsm_sts = VLOCK_STATE_NULL;
else
pvlock->fsm_sts = VLOCK_STATE_DISABLE_STEP2_DONE;
break;
case VLOCK_STATE_DISABLE_STEP2_DONE:
if (vlock_disable_step2(pvlock)) {
pvlock->fsm_sts = VLOCK_STATE_NULL;
if (vecm_latch_flag & FLAG_VLOCK_DIS) {
vlock_en = 0;
vecm_latch_flag &= ~FLAG_VLOCK_DIS;
}
}
break;
default:
dprintk(0, "err state %d\n", pvlock->fsm_sts);
break;
}
/*capture log*/
if (((vlock_mode & (VLOCK_MODE_AUTO_PLL |
VLOCK_MODE_AUTO_ENC))) &&
vlock_log_en && vlock_log_cnt < vlock_log_size &&
(vlock_debug & VLOCK_DEBUG_AUTO_MODE_LOG_EN)) {
vlock_reg_get(pvlock);
vlock_log_cnt++;
}
if (pvlock->fsm_sts != pvlock->fsm_prests) {
if (vlock_debug & VLOCK_DEBUG_INFO)
dprintk(1, ">>> %s fsm %d to %d\n", __func__,
pvlock->fsm_prests, pvlock->fsm_sts);
pvlock->fsm_prests = pvlock->fsm_sts;
}
}
/*
* If is small window, output vs phase is not mif read phase. when is full
* window, mif read phase is output vpp vs phase.
* game mode will cause phase over lay at small window.
*/
u32 vlock_chk_is_small_win(struct vpp_frame_par_s *cur_video_sts)
{
struct vinfo_s *vinfo = get_current_vinfo();
u32 scaler_vout;
u32 panel_vout;
if (!cur_video_sts || !vinfo)
return 1;
panel_vout = (vinfo->vtotal * 75) / 100;
scaler_vout = cur_video_sts->VPP_vsc_endp -
cur_video_sts->VPP_vsc_startp;
if (scaler_vout < panel_vout &&
cur_video_sts->VPP_vsc_endp > cur_video_sts->VPP_vsc_startp) {
dprintk(3, "vtotal:%d\n", vinfo->vtotal);
dprintk(3, "scaler_vout:%d\n", scaler_vout);
dprintk(3, "VPP_vsc_endp:%d\n", cur_video_sts->VPP_vsc_endp);
dprintk(3, "VPP_vsc_startp:%d\n", cur_video_sts->VPP_vsc_startp);
return 1;
}
return 0;
}
/*new packed separeted from amvecm_on_vs,avoid the influencec of repeate call,
*which may affect vlock process
*/
void vlock_process(struct vframe_s *vf,
struct vpp_frame_par_s *cur_video_sts)
{
struct stvlock_sig_sts *pvlock;
#ifdef VLOCK_DEBUG_ENC_IDX
pvlock = vlock_tab[VLOCK_DEBUG_ENC_IDX];
#else
pvlock = vlock_tab[VLOCK_ENC0];
#endif
if (!pvlock)
return;
if (probe_ok == 0 || !vlock_en || !cur_video_sts) {
if (vlock_debug & VLOCK_DEBUG_INFO) {
pr_info("%s probe_ok:%d vlock_en:%d\n",
__func__, probe_ok, vlock_en);
if (!cur_video_sts)
pr_info("cur video sts is null\n");
}
return;
}
if (vlock_debug & VLOCK_DEBUG_FSM_PAUSE) {
/*if (vlock_debug & VLOCK_DEBUG_INFO)*/
/* pr_info("%s FSM_DIS\n", __func__);*/
return;
}
if (!hw_clk_ok && (vlock_debug & VLOCK_DEBUG_INFO))
pr_info("hw clk not config\n");
if (!(vlock_debug & VLOCK_DEBUG_FORCE_ON)) {
if (vlock_chk_is_small_win(cur_video_sts)) {
if (pvlock->dtdata->vlk_ctl_for_frc)
pvlock->fsm_sts = VLOCK_STATE_NULL;
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("%s is small win\n", __func__);
return;
}
}
/* todo:vlock processs only for tv chip */
if (pvlock->dtdata->vlk_new_fsm)
vlock_fsm_monitor(vf, pvlock);
}
EXPORT_SYMBOL(vlock_process);
void vlock_param_set(unsigned int val, enum vlock_param_e sel)
{
switch (sel) {
case VLOCK_EN:
vlock_en = val;
break;
case VLOCK_ADAPT:
vlock_adapt = val;
break;
case VLOCK_MODE:
vlock_mode = val;
break;
case VLOCK_DIS_CNT_LIMIT:
vlock_dis_cnt_limit = val;
break;
case VLOCK_DELTA_LIMIT:
vlock_delta_limit = val;
break;
case VLOCK_PLL_M_LIMIT:
vlock_pll_m_limit = val;
break;
case VLOCK_DELTA_CNT_LIMIT:
vlock_delta_cnt_limit = val;
break;
case VLOCK_DEBUG:
vlock_debug = val;
break;
case VLOCK_DYNAMIC_ADJUST:
vlock_dynamic_adjust = val;
break;
case VLOCK_DIS_CNT_NO_VF_LIMIT:
vlock_dis_cnt_no_vf_limit = val;
break;
case VLOCK_LINE_LIMIT:
vlock_line_limit = val;
break;
case VLOCK_SUPPORT:
vlock_support = val;
break;
default:
pr_info("%s:unknown vlock param:%d\n", __func__, sel);
break;
}
}
void vlock_status(struct stvlock_sig_sts *pvlock)
{
struct vinfo_s *vinfo;
u32 offset_enc = pvlock->offset_encl;
u32 offset_vlck = pvlock->offset_vlck;
pr_info("\nvlock Idx:%d parameters status\n", pvlock->idx);
pr_info("vlock driver version: %s\n", VLOCK_VER);
pr_info("vlock_mode:%d\n", vlock_mode);
pr_info("vlock_en:%d\n", vlock_en);
pr_info("vlock_adapt:%d\n", vlock_adapt);
pr_info("vlock_dis_cnt_limit:%d\n", vlock_dis_cnt_limit);
pr_info("vlock_delta_limit:%d\n", vlock_delta_limit);
pr_info("vlock_pll_m_limit:%d\n", vlock_pll_m_limit);
pr_info("vlock_delta_cnt_limit:%d\n", vlock_delta_cnt_limit);
pr_info("vlock_debug:0x%x\n", vlock_debug);
pr_info("\tDEBUG_INFO (0x1) FSM_PAUSE (0x40) FORCE_ON (0x80)\n");
pr_info("\tINFO_ERR (0x8000)\n");
pr_info("vlock_dynamic_adjust:%d\n", vlock_dynamic_adjust);
pr_info("vlock_state:%d\n", vlock_state);
pr_info("vecm_latch_flag:0x%x\n", vecm_latch_flag);
pr_info("vlock_sync_limit_flag:%d\n", vlock_sync_limit_flag);
pr_info("offset_vlck=0x%x offset_enc:0x%x\n", offset_vlck, offset_enc);
pr_info("pre_hiu_reg_m:0x%x\n", pvlock->pre_hiu_reg_m);
pr_info("pre_hiu_reg_frac:0x%x\n", pvlock->pre_hiu_reg_frac);
pr_info("enc_max_line_addr:0x%x 0x%x\n",
pvlock->enc_max_line_addr + offset_enc, pvlock->pre_enc_max_line);
pr_info("enc_max_pixel_addr:0x%x 0x%x\n",
pvlock->enc_max_pixel_addr + offset_enc, pvlock->pre_enc_max_pixel);
pr_info("vlock_dis_cnt:%d\n", vlock_dis_cnt);
pr_info("vlock_dis_cnt_no_vf:%d\n", vlock_dis_cnt_no_vf);
pr_info("vlock_dis_cnt_no_vf_limit:%d\n", vlock_dis_cnt_no_vf_limit);
pr_info("enc_video_mode_addr:0x%x\n", pvlock->enc_video_mode_addr + offset_enc);
pr_info("enc_max_line_switch_addr:0x%x\n", pvlock->enc_max_line_switch_addr + offset_enc);
pr_info("vlock_capture_limit:0x%x\n", vlock_capture_limit);
pr_info("vlock_line_limit:%d\n", vlock_line_limit);
pr_info("vlock_pll_stable_cnt:%d\n", vlock_pll_stable_cnt);
pr_info("vlock_enc_adj_limit:%d\n", vlock_enc_adj_limit);
pr_info("vlock_support:%d\n", vlock_support);
pr_info("vlock_enc_stable_flag:%d\n", vlock_enc_stable_flag);
pr_info("vlock_intput_type:%d\n", vlock_intput_type);
pr_info("vlock_pll_adj_limit:0x%x\n", vlock_pll_adj_limit);
pr_info("vlock_pll_val_last:0x%x\n", vlock_pll_val_last);
pr_info("vlock_ss_en:%d\n", vlock_ss_en);
pr_info("speed_up_en:%d\n", speed_up_en);
pr_info("loop0_en:%d\n", loop0_en);
pr_info("loop1_en:%d\n", loop1_en);
pr_info("loop0_err_lmt:0x%x\n", loop0_err_lmt);
pr_info("loop1_err_lmt:0x%x\n", loop1_err_lmt);
pr_info("loop_err_rs:%d\n", loop_err_rs);
pr_info("loop_err_gain:%d\n", loop_err_gain);
pr_info("offset_vlck:0x%x\n", pvlock->offset_vlck);
pr_info("offset_enc:0x%x\n", pvlock->offset_encl);
pr_info("vlk_fsm_sts:%d(2 is working)\n", pvlock->fsm_sts);
pr_info("vlk_support:%d\n", pvlock->dtdata->vlk_support);
pr_info("vlk_new_fsm:%d\n", pvlock->dtdata->vlk_new_fsm);
pr_info("md_support:%d\n", pvlock->md_support);
pr_info("vlk_phlock_en:%d\n", pvlock->dtdata->vlk_phlock_en);
pr_info("vlk_hwver:%d\n", pvlock->dtdata->vlk_hwver);
pr_info("vlk_pll_sel:%d\n", pvlock->dtdata->vlk_pll_sel);
pr_info("phlock flag:%d\n", vlock_get_phlock_flag_ex(pvlock));
pr_info("frqlock flag:%d\n", vlock_get_vlock_flag_ex(pvlock));
pr_info("phlock_percent:%d\n", pvlock->phlock_percent);
vinfo = get_current_vinfo();
pr_info("vinfo sync_duration_num:%d\n", vinfo->sync_duration_num);
pr_info("vinfo sync_duration_den:%d\n", vinfo->sync_duration_den);
pr_info("vinfo video_clk:%d\n", vinfo->video_clk);
pr_info("vinfo htotal:%d\n", vinfo->htotal);
pr_info("vinfo vtotal:%d\n", vinfo->vtotal);
pr_info("fr_adj_type:%d\n", vinfo->fr_adj_type);
pr_info("vframe input_hz:%d\n", pvlock->input_hz);
pr_info("vframe duration:%d\n", pvlock->duration);
pr_info("vframe output_hz:%d\n", pvlock->output_hz);
pr_info("val_m:(0x%0x, 0x%x)\n", pvlock->val_m, vlock_get_panel_pll_m(pvlock));
pr_info("val_f:(0x%0x, 0x%x)\n", pvlock->val_frac, vlock_get_panel_pll_frac(pvlock));
pr_info("lcnt_sts :0x%0x\n", pvlock->vdinsts.lcnt_sts);
pr_info("com_sts0 :0x%0x\n", pvlock->vdinsts.com_sts0);
pr_info("com_sts1 :0x%0x\n", pvlock->vdinsts.com_sts1);
}
void vlock_reg_dump(struct stvlock_sig_sts *pvlock)
{
unsigned int addr;
unsigned int val;
unsigned int offset_vlck = pvlock->offset_vlck;
unsigned int offset_enc = pvlock->offset_encl;
pr_info("----dump vlock reg----\n");
for (addr = (VPU_VLOCK_CTRL); addr <= (VPU_VLOCK_RO_M_INT_FRAC); addr++)
pr_info("[0x%04x]=0x%08x\n", addr + offset_vlck,
READ_VPP_REG(addr + offset_vlck));
if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2) {
for (addr = VPU_VLOCK_RO_PH_DIS; addr <= VPU_VLOCK_LOCK_TH1; addr++)
pr_info("[0x%04x]=0x%08x\n",
addr + offset_vlck, READ_VPP_REG(addr + offset_vlck));
if (pvlock->dtdata->vlk_hwver >= vlock_hw_tm2verb) {
for (addr = (VPU_VLOCK_LOOP0_ERR_LMT);
addr <= (VPU_VLOCK_ERR_CTRL0); addr++)
pr_info("[0x%04x]=0x%08x\n", addr + offset_vlck,
READ_VPP_REG(addr + offset_vlck));
}
}
//pr_info("[0x1cb3]=0x%08x\n", READ_VPP_REG(0x1cb3));
//pr_info("[0x1cb4]=0x%08x\n", READ_VPP_REG(0x1cb4));
//pr_info("[0x1cc8]=0x%08x\n", READ_VPP_REG(0x1cc8));
pr_info("[0x%04x]=0x%08x line_addr\n", pvlock->enc_max_line_addr + offset_enc,
READ_VPP_REG(pvlock->enc_max_line_addr + offset_enc));
pr_info("[0x%04x]=0x%08x pixel_addr\n", pvlock->enc_max_pixel_addr + offset_enc,
READ_VPP_REG(pvlock->enc_max_pixel_addr + offset_enc));
pr_info("[0x%04x]=0x%08x mode_addr\n", pvlock->enc_video_mode_addr + offset_enc,
READ_VPP_REG(pvlock->enc_video_mode_addr + offset_enc));
pr_info("[0x%04x]=0x%08x mode_adv_addr\n", pvlock->enc_video_mode_adv_addr + offset_enc,
READ_VPP_REG(pvlock->enc_video_mode_adv_addr + offset_enc));
pr_info("[0x%04x]=0x%08x line_switch_addr\n", pvlock->enc_max_line_switch_addr + offset_enc,
READ_VPP_REG(pvlock->enc_max_line_switch_addr + offset_enc));
val = vlock_get_panel_pll_m(pvlock);
pr_info("pll m=0x%08x\n", val);
val = vlock_get_panel_pll_frac(pvlock);
pr_info("pll f=0x%08x\n", val);
}
/*work around method for vlock process hdmirx input interlace source.@20170803
**for interlace input,TOP and BOT have one line delta,
**Which may cause vlock output jitter.
**The work around method is that changing vlock input select.
**So input vsync cnt may be stable,
**However the input hz should be div 2 as vlock input setting
*/
void vdin_vlock_input_sel(struct stvlock_sig_sts *vlock, unsigned int type,
enum vframe_source_type_e source_type)
{
struct stvlock_sig_sts *pvlock = vlock_tab[VLOCK_ENC0];
u32 offset_vlck;
//u32 offset_enc = pvlock->offset_enc;
if (!pvlock)
return;
offset_vlck = pvlock->offset_vlck;
//if (pvlock->dtdata->vlk_hwver >= vlock_hw_ver2)
// return;
dprintk(2, "%s vf type:0x%x, src:0x%x", __func__, type, source_type);
vlock_intput_type = type & VIDTYPE_TYPEMASK;
//if (vlock_intput_type == VIDTYPE_PROGRESSIVE ||
// (vlock_mode & VLOCK_MODE_MANUAL_SOFT_ENC))
// return;
if (vlock_intput_type == VIDTYPE_INTERLACE_TOP) {
/*
*1:fromhdmi rx ,
*2:from tv-decoder,
*3:from dvin,
*4:from dvin,
*5:from 2nd bt656
*/
if (source_type == VFRAME_SOURCE_TYPE_TUNER ||
source_type == VFRAME_SOURCE_TYPE_CVBS)
/* Input Vsync source select from tv-decoder */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, VLOCK_SRC_TV_DEC, 16, 3);
else if (source_type == VFRAME_SOURCE_TYPE_HDMI)
/* Input Vsync source select from hdmi-rx */
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, VLOCK_SRC_HDMI, 16, 3);
} else {
WRITE_VPP_REG_BITS(VPU_VLOCK_CTRL + offset_vlck, 7, 16, 3);
}
}
/*EXPORT_SYMBOL(vdin_vlock_input_sel);*/
#ifdef CONFIG_AMLOGIC_LCD
#define VLOCK_LCD_RETRY_MAX 100
void vlock_lcd_param_work(struct work_struct *p_work)
{
unsigned int param[LCD_VLOCK_PARAM_NUM + 1] = {0};
int i = 0;
param[LCD_VLOCK_PARAM_NUM] = 0; /* for lcd_index(venc index) */
while (i++ < VLOCK_LCD_RETRY_MAX) {
aml_lcd_notifier_call_chain(LCD_EVENT_VLOCK_PARAM, &param);
if (param[0] & LCD_VLOCK_PARAM_BIT_UPDATE) {
if (param[0] & LCD_VLOCK_PARAM_BIT_VALID) {
vlock_en = param[1];
vlock_mode = param[2];
vlock_pll_m_limit = param[3];
vlock_line_limit = param[4];
if (vlock_mode &
VLOCK_MODE_MANUAL_MIX_PLL_ENC) {
vlock_mode &=
~VLOCK_MODE_MANUAL_MIX_PLL_ENC;
vlock_mode |= VLOCK_MODE_MANUAL_PLL;
}
}
break;
}
msleep(20);
}
pr_info("lcd vlock_en=%d, vlock_mode=0x%x i=%d\n", vlock_en, vlock_mode, i);
}
#endif
void vlock_param_config(struct device_node *node)
{
unsigned int val;
int ret;
ret = of_property_read_u32(node, "vlock_en", &val);
if (!ret)
vlock_en = val;
ret = of_property_read_u32(node, "vlock_mode", &val);
if (!ret)
vlock_mode = val;
ret = of_property_read_u32(node, "vlock_pll_m_limit", &val);
if (!ret)
vlock_pll_m_limit = val;
ret = of_property_read_u32(node, "vlock_line_limit", &val);
if (!ret)
vlock_line_limit = val;
#ifdef CONFIG_AMLOGIC_LCD
/* lock vlock config data from LCD module */
schedule_work(&aml_lcd_vlock_param_work);
#endif
if (vlock_mode & VLOCK_MODE_MANUAL_MIX_PLL_ENC) {
vlock_mode &= ~VLOCK_MODE_MANUAL_MIX_PLL_ENC;
vlock_mode |= VLOCK_MODE_MANUAL_PLL;
}
}
int vlock_notify_callback(struct notifier_block *block, unsigned long cmd,
void *para)
{
const struct vinfo_s *vinfo;
u32 cnt = 0;
struct stvlock_sig_sts *pvlock = vlock_tab[VLOCK_ENC0];
#ifdef VLOCK_DEBUG_ENC_IDX
pvlock = vlock_tab[VLOCK_DEBUG_ENC_IDX];
#endif
if (!pvlock)
return 0;
if (!vlock_en)
return 0;
vinfo = get_current_vinfo();
if (!vinfo || !vinfo->name) {
pr_info("current vinfo or name NULL\n");
return -1;
}
if (vlock_debug & VLOCK_DEBUG_INFO)
pr_info("vlock notify vmode=%s, vinfo w=%d,h=%d, cmd: 0x%lx\n",
vinfo->name, vinfo->width, vinfo->height, cmd);
switch (cmd) {
case VOUT_EVENT_MODE_CHANGE_PRE:
pvlock->fsm_pause = true;
pvlock->fsm_sts = VLOCK_STATE_NULL;
vlock_notify_event = cmd;
if (pvlock->dtdata->vlk_new_fsm &&
pvlock->fsm_sts >= VLOCK_STATE_ENABLE_STEP1_DONE &&
pvlock->fsm_sts <= VLOCK_STATE_DISABLE_STEP1_DONE) {
/*stop vlock*/
vlock_disable_step1(pvlock);
while (!vlock_disable_step2(pvlock)) {
if (cnt++ > 10)
break;
}
}
pr_info("vlock: event MODE_CHANGE_PRE %d\n", cnt);
break;
case VOUT_EVENT_MODE_CHANGE:
pvlock->fsm_pause = false;
pvlock->fsm_sts = VLOCK_STATE_NULL;
vlock_notify_event = cmd;
pr_info("vlock: event MODE_CHANGE\n");
break;
default:
break;
}
return 0;
}
int phlock_phase_config(char *str)
{
unsigned char *ptr = str;
struct stvlock_sig_sts *pvlock;
u32 i;
vlock_dev_param_init();
dprintk(0, "%s: from bootargs is %s.\n", __func__, str);
for (i = VLOCK_ENC0; i <= VLOCK_ENC2; i++) {
pvlock = vlock_tab[i];
if (strstr(ptr, "1")) {
pvlock->phlock_percent = 15;/*give a default value*/
pvlock->video_inverse = 1;
} else {
pvlock->phlock_percent = 40;/*give a default value*/
pvlock->video_inverse = 0;
}
}
return 0;
}
__setup("video_reverse=", phlock_phase_config);
void vlock_parse_param(char *buf_orig, char **parm)
{
char *ps, *token;
unsigned int n = 0;
char delim1[3] = " ";
char delim2[2] = "\n";
ps = buf_orig;
strcat(delim1, delim2);
while (1) {
token = strsep(&ps, delim1);
if (!token)
break;
if (*token == '\0')
continue;
parm[n++] = token;
}
}
ssize_t vlock_debug_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
ssize_t len = 0;
len += sprintf(buf + len,
"echo vlock_mode val(0/1/2) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_en val(0/1) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_adapt val(0/1) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_dis_cnt_limit val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_delta_limit val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_pll_m_limit val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_delta_cnt_limit val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_debug val(0x111) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_dynamic_adjust val(0/1) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_dis_cnt_no_vf_limit val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_line_limit val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo vlock_support val(D) > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo enable > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo disable > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo status > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo dump_reg > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo log_start > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo log_stop > /sys/class/amvecm/vlock\n");
len += sprintf(buf + len,
"echo log_print > /sys/class/amvecm/vlock\n");
return len;
}
ssize_t vlock_debug_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count)
{
char *buf_orig, *parm[8] = {NULL};
long val;
unsigned int temp_val;
enum vlock_param_e sel = VLOCK_PARAM_MAX;
struct stvlock_sig_sts *pvlock = vlock_tab[VLOCK_ENC0];
if (!buf)
return count;
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
if (!is_meson_gxtvbb_cpu() &&
!is_meson_gxbb_cpu() &&
(get_cpu_type() < MESON_CPU_MAJOR_ID_GXL)) {
pr_info("\n chip does not support vlock process!!!\n");
return count;
}
#endif
buf_orig = kstrdup(buf, GFP_KERNEL);
vlock_parse_param(buf_orig, (char **)&parm);
if (!strncmp(parm[0], "vlock_mode", 10)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_MODE;
} else if (!strncmp(parm[0], "vlock_en", 8)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_EN;
} else if (!strncmp(parm[0], "vlock_adapt", 11)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_ADAPT;
} else if (!strncmp(parm[0], "vlock_dis_cnt_limit", 19)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_DIS_CNT_LIMIT;
} else if (!strncmp(parm[0], "vlock_delta_limit", 17)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_DELTA_LIMIT;
} else if (!strncmp(parm[0], "vlock_pll_m_limit", 17)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_PLL_M_LIMIT;
} else if (!strncmp(parm[0], "vlock_delta_cnt_limit", 21)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_DELTA_CNT_LIMIT;
} else if (!strncmp(parm[0], "vlock_debug", 11)) {
if (kstrtol(parm[1], 16, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_DEBUG;
} else if (!strncmp(parm[0], "vlock_dynamic_adjust", 20)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_DYNAMIC_ADJUST;
} else if (!strncmp(parm[0], "vlock_line_limit", 17)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_LINE_LIMIT;
} else if (!strncmp(parm[0], "vlock_dis_cnt_no_vf_limit", 25)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_DIS_CNT_NO_VF_LIMIT;
} else if (!strncmp(parm[0], "vlock_line_limit", 16)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_LINE_LIMIT;
} else if (!strncmp(parm[0], "vlock_support", 13)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
temp_val = val;
sel = VLOCK_SUPPORT;
} else if (!strncmp(parm[0], "enable", 6)) {
vecm_latch_flag |= FLAG_VLOCK_EN;
vlock_set_en(true);
} else if (!strncmp(parm[0], "disable", 7)) {
vecm_latch_flag |= FLAG_VLOCK_DIS;
if (pvlock->fsm_sts <= VLOCK_STATE_ENABLE_STEP1_DONE)
vlock_set_en(false);
} else if (!strncmp(parm[0], "status", 6)) {
if (!parm[1]) {
temp_val = VLOCK_ENC0;
} else {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
if (val <= VLOCK_ENC2)
temp_val = val;
else
temp_val = VLOCK_ENC0;
}
pvlock = vlock_tab[temp_val];
vlock_status(pvlock);
} else if (!strncmp(parm[0], "dump_reg", 8)) {
if (!parm[1]) {
temp_val = VLOCK_ENC0;
} else {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
if (val <= VLOCK_ENC2)
temp_val = val;
else
temp_val = VLOCK_ENC0;
}
pvlock = vlock_tab[temp_val];
vlock_reg_dump(pvlock);
} else if (!strncmp(parm[0], "log_start", 9)) {
vlock_log_start();
} else if (!strncmp(parm[0], "log_stop", 8)) {
vlock_log_stop();
} else if (!strncmp(parm[0], "log_print", 9)) {
vlock_log_print();
} else if (!strncmp(parm[0], "phase", 5)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
vlock_set_phase(pvlock, val);
} else if (!strncmp(parm[0], "phlock_en", 9)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
pvlock = vlock_tab[VLOCK_ENC0];
vlock_set_phase_en(pvlock, val);
pvlock = vlock_tab[VLOCK_ENC1];
vlock_set_phase_en(pvlock, val);
pvlock = vlock_tab[VLOCK_ENC2];
vlock_set_phase_en(pvlock, val);
} else if (!strncmp(parm[0], "ss_en", 5)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
vlock_ss_en = val;
pr_info("vlock_ss_en:%d\n", vlock_ss_en);
} else if (!strncmp(parm[0], "loop0lmt", 8)) {
if (kstrtol(parm[1], 16, &val) < 0)
return -EINVAL;
loop0_err_lmt = val;
pr_info("loop0_err_lmt:%d\n", loop0_err_lmt);
} else if (!strncmp(parm[0], "loop1lmt", 8)) {
if (kstrtol(parm[1], 16, &val) < 0)
return -EINVAL;
loop1_err_lmt = val;
pr_info("loop1_err_lmt:%d\n", loop1_err_lmt);
} else if (!strncmp(parm[0], "loop_err_rs", 11)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
loop_err_rs = val;
pr_info("loop_err_rs:%d\n", loop_err_rs);
} else if (!strncmp(parm[0], "loop_err_gain", 13)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
loop_err_gain = val;
pr_info("loop_err_gain:%d\n", loop_err_gain);
} else if (!strncmp(parm[0], "speedup", 7)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
speed_up_en = val;
pr_info("speed_up_en:%d\n", speed_up_en);
} else if (!strncmp(parm[0], "loop0_en", 8)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
loop0_en = val;
pr_info("loop0_en:%d\n", loop0_en);
} else if (!strncmp(parm[0], "loop1_en", 8)) {
if (kstrtol(parm[1], 10, &val) < 0)
return -EINVAL;
loop1_en = val;
pr_info("loop1_en:%d\n", loop1_en);
} else {
pr_info("----cmd list -----\n");
pr_info("vlock_mode val\n");
pr_info("vlock_en val\n");
pr_info("vlock_debug val\n");
pr_info("vlock_adapt val\n");
pr_info("vlock_dis_cnt_limit val\n");
pr_info("vlock_delta_limit val\n");
pr_info("vlock_dynamic_adjust val\n");
pr_info("vlock_line_limit val\n");
pr_info("vlock_dis_cnt_no_vf_limit val\n");
pr_info("vlock_line_limit val\n");
pr_info("vlock_support val\n");
pr_info("enable\n");
pr_info("disable\n");
pr_info("status\n");
pr_info("dump_reg\n");
pr_info("log_start\n");
pr_info("log_stop\n");
pr_info("log_print\n");
pr_info("phase persent\n");
pr_info("phlock_en 0 or 1\n");
pr_info("ss_en 0 or 1\n");
pr_info("loop0lmt val\n");
pr_info("loop1lmt val\n");
pr_info("loop_err_rs val\n");
pr_info("loop_err_gain val\n");
pr_info("speedup 0 or 1\n");
pr_info("not_exit 0 or 1\n");
}
if (sel < VLOCK_PARAM_MAX)
vlock_param_set(temp_val, sel);
kfree(buf_orig);
return count;
}
/*video lock end*/