blob: e47db1b9a202dcb7053b07c9c7dadf356fa1b724 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
#include <linux/of_irq.h>
#include <linux/string.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/ctype.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <asm/div64.h>
#include <linux/sched/clock.h>
#include <linux/amlogic/media/vpu/vpu.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
#include <linux/amlogic/media/frame_sync/timestamp.h>
#include <linux/amlogic/media/frame_sync/tsync.h>
#include <linux/amlogic/media/frc/frc_reg.h>
#include <linux/amlogic/media/frc/frc_common.h>
#include <linux/amlogic/tee.h>
#include <linux/clk.h>
#include "frc_drv.h"
#include "frc_proc.h"
#include "frc_hw.h"
int frc_enable_cnt = 1;
module_param(frc_enable_cnt, int, 0664);
MODULE_PARM_DESC(frc_enable_cnt, "frc enable counter");
int frc_disable_cnt = 1;
module_param(frc_disable_cnt, int, 0664);
MODULE_PARM_DESC(frc_disable_cnt, "frc disable counter");
int frc_re_cfg_cnt = 3;/*need bigger than frc_disable_cnt 3, 15*/
module_param(frc_re_cfg_cnt, int, 0664);
MODULE_PARM_DESC(frc_re_cfg_cnt, "frc reconfig counter");
u32 secure_tee_handle;
void frc_fw_initial(struct frc_dev_s *devp)
{
if (!devp)
return;
devp->in_sts.vs_cnt = 0;
devp->in_sts.vs_tsk_cnt = 0;
devp->in_sts.vs_timestamp = sched_clock();
devp->in_sts.vf_repeat_cnt = 0;
devp->in_sts.vf_null_cnt = 0;
devp->out_sts.vs_cnt = 0;
devp->out_sts.vs_tsk_cnt = 0;
devp->out_sts.vs_timestamp = sched_clock();
devp->in_sts.vf = NULL;
devp->frc_sts.vs_cnt = 0;
devp->vs_timestamp = sched_clock();
}
void frc_hw_initial(struct frc_dev_s *devp)
{
frc_fw_initial(devp);
frc_mtx_set(devp);
frc_top_init(devp);
return;
}
void frc_in_reg_monitor(struct frc_dev_s *devp)
{
u32 i;
u32 reg;
//char *buf = devp->dbg_buf;
for (i = 0; i < MONITOR_REG_MAX; i++) {
reg = devp->dbg_in_reg[i];
if (reg != 0 && reg < 0x3fff) {
if (devp->dbg_buf_len > 300) {
devp->dbg_reg_monitor_i = 0;
devp->dbg_buf_len = 0;
return;
}
devp->dbg_buf_len++;
pr_info("ivs:%d 0x%x=0x%08x\n", devp->out_sts.vs_cnt,
reg, READ_FRC_REG(reg));
}
}
}
void frc_vf_monitor(struct frc_dev_s *devp)
{
if (devp->dbg_buf_len > 300) {
devp->dbg_vf_monitor = 0;
return;
}
devp->dbg_buf_len++;
pr_info("ivs:%d 0x%lx\n", devp->frc_sts.vs_cnt, (ulong)devp->in_sts.vf);
}
void frc_out_reg_monitor(struct frc_dev_s *devp)
{
u32 i;
u32 reg;
for (i = 0; i < MONITOR_REG_MAX; i++) {
reg = devp->dbg_out_reg[i];
if (reg != 0 && reg < 0x3fff) {
if (devp->dbg_buf_len > 300) {
devp->dbg_reg_monitor_o = 0;
devp->dbg_buf_len = 0;
return;
}
devp->dbg_buf_len++;
pr_info("\t\t\t\tovs:%d 0x%x=0x%08x\n", devp->out_sts.vs_cnt,
reg, READ_FRC_REG(reg));
}
}
}
void frc_dump_monitor_data(struct frc_dev_s *devp)
{
//char *buf = devp->dbg_buf;
//pr_info("%d, %s\n", devp->dbg_buf_len, buf);
devp->dbg_buf_len = 0;
}
/*frc-fw input task execution time*/
void frc_in_task_print(u64 timer)
{
static u64 in_tsk_inx, in_tsk_min, in_tsk_max, in_tsk_sum;
in_tsk_inx++;
in_tsk_sum += timer;
if (in_tsk_min > timer)
in_tsk_min = timer;
if (in_tsk_max < timer)
in_tsk_max = timer;
if (in_tsk_inx == 60) {
pr_frc(0, "in_tsk_time min = %lld max = %lld avg = %lld\n",
in_tsk_min, in_tsk_max, div64_u64(in_tsk_sum, 60));
in_tsk_min = in_tsk_max;
in_tsk_inx = 0;
in_tsk_sum = 0;
in_tsk_max = 0;
}
}
/*frc-fw output task execution time*/
void frc_out_task_print(u64 timer)
{
static u64 out_tsk_inx, out_tsk_min, out_tsk_max, out_tsk_sum;
out_tsk_inx++;
out_tsk_sum += timer;
if (out_tsk_min > timer)
out_tsk_min = timer;
if (out_tsk_max < timer)
out_tsk_max = timer;
if (out_tsk_inx == 60) {
pr_frc(0, "out_tsk_time min = %lld max = %lld avg = %lld\n",
out_tsk_min, out_tsk_max, div64_u64(out_tsk_sum, 60));
out_tsk_min = out_tsk_max;
out_tsk_inx = 0;
out_tsk_sum = 0;
out_tsk_max = 0;
}
}
irqreturn_t frc_input_isr(int irq, void *dev_id)
{
struct frc_dev_s *devp = (struct frc_dev_s *)dev_id;
u64 timestamp = sched_clock();
devp->in_sts.vs_cnt++;
/*update vs time*/
devp->in_sts.vs_duration = timestamp - devp->in_sts.vs_timestamp;
devp->in_sts.vs_timestamp = timestamp;
if (!devp->probe_ok || !devp->power_on_flag)
return IRQ_HANDLED;
inp_undone_read(devp);
if (devp->dbg_reg_monitor_i)
frc_in_reg_monitor(devp);
tasklet_schedule(&devp->input_tasklet);
return IRQ_HANDLED;
}
void frc_input_tasklet_pro(unsigned long arg)
{
struct frc_dev_s *devp = (struct frc_dev_s *)arg;
struct frc_fw_data_s *pfw_data;
u64 timestamp;
pfw_data = (struct frc_fw_data_s *)devp->fw_data;
if (!pfw_data)
return;
if (!devp->probe_ok)
return;
if (!devp->power_on_flag) {
// devp->power_off_flag++;
return;
}
devp->in_sts.vs_tsk_cnt++;
if (!devp->frc_fw_pause) {
timestamp = sched_clock();
if (pfw_data->scene_detect_input)
pfw_data->scene_detect_input(pfw_data);
if (pfw_data->film_detect_ctrl)
pfw_data->film_detect_ctrl(pfw_data);
if (pfw_data->bbd_ctrl)
pfw_data->bbd_ctrl(pfw_data);
if (pfw_data->iplogo_ctrl)
pfw_data->iplogo_ctrl(pfw_data);
// if (!devp->power_on_flag)
// devp->power_off_flag++;
if (devp->ud_dbg.inud_time_en)
frc_in_task_print(sched_clock() - timestamp);
}
}
irqreturn_t frc_output_isr(int irq, void *dev_id)
{
struct frc_dev_s *devp = (struct frc_dev_s *)dev_id;
u64 timestamp = sched_clock();
devp->out_sts.vs_cnt++;
/*update vs time*/
devp->out_sts.vs_duration = timestamp - devp->out_sts.vs_timestamp;
devp->out_sts.vs_timestamp = timestamp;
if (!devp->probe_ok || !devp->power_on_flag)
return IRQ_HANDLED;
me_undone_read(devp);
mc_undone_read(devp);
vp_undone_read(devp);
get_vout_info(devp);
if (devp->dbg_reg_monitor_o)
frc_out_reg_monitor(devp);
tasklet_schedule(&devp->output_tasklet);
return IRQ_HANDLED;
}
void frc_output_tasklet_pro(unsigned long arg)
{
struct frc_dev_s *devp = (struct frc_dev_s *)arg;
struct frc_fw_data_s *pfw_data;
u64 timestamp;
pfw_data = (struct frc_fw_data_s *)devp->fw_data;
if (!pfw_data)
return;
if (!devp->probe_ok)
return;
if (!devp->power_on_flag) {
// devp->power_off_flag++;
return;
}
devp->out_sts.vs_tsk_cnt++;
if (!devp->frc_fw_pause) {
timestamp = sched_clock();
if (pfw_data->scene_detect_output)
pfw_data->scene_detect_output(pfw_data);
if (pfw_data->me_ctrl)
pfw_data->me_ctrl(pfw_data);
if (pfw_data->vp_ctrl)
pfw_data->vp_ctrl(pfw_data);
if (pfw_data->mc_ctrl)
pfw_data->mc_ctrl(pfw_data);
if (pfw_data->melogo_ctrl)
pfw_data->melogo_ctrl(pfw_data);
// if (!devp->power_on_flag)
// devp->power_off_flag++;
if (devp->ud_dbg.outud_time_en)
frc_out_task_print(sched_clock() - timestamp);
}
}
void frc_change_to_state(enum frc_state_e state)
{
struct frc_dev_s *devp = get_frc_devp();
if (devp->frc_sts.state_transing) {
pr_frc(0, "%s state_transing busy!\n", __func__);
if (state != devp->frc_sts.new_state) {
devp->frc_sts.state = devp->frc_sts.new_state;
devp->frc_sts.new_state = state;
devp->frc_sts.frame_cnt = 0;
devp->frc_sts.state_transing = false;
pr_frc(0, "busy broken:%s %d->%d\n", __func__, devp->frc_sts.state, state);
}
} else if (devp->frc_sts.state != state) {
devp->frc_sts.new_state = state;
devp->frc_sts.state_transing = true;
pr_frc(1, "%s %d->%d\n", __func__, devp->frc_sts.state, state);
}
}
const char * const frc_state_ary[] = {
"FRC_STATE_DISABLE",
"FRC_STATE_ENABLE",
"FRC_STATE_BYPASS",
};
int frc_update_in_sts(struct frc_dev_s *devp, struct st_frc_in_sts *frc_in_sts,
struct vframe_s *vf, struct vpp_frame_par_s *cur_video_sts)
{
if (!vf || !cur_video_sts)
return -1;
frc_in_sts->vf_type = vf->type;
frc_in_sts->duration = vf->duration;
frc_in_sts->signal_type = vf->signal_type;
frc_in_sts->source_type = vf->source_type;
frc_in_sts->vf = vf;
/* for debug */
if (devp->dbg_force_en && devp->dbg_input_hsize && devp->dbg_input_vsize) {
frc_in_sts->in_hsize = devp->dbg_input_hsize;
frc_in_sts->in_vsize = devp->dbg_input_vsize;
} else {
if (devp->frc_hw_pos == FRC_POS_AFTER_POSTBLEND) {
frc_in_sts->in_hsize = devp->out_sts.vout_width;
frc_in_sts->in_vsize = devp->out_sts.vout_height;
} else {
frc_in_sts->in_hsize = cur_video_sts->nnhf_input_w;
frc_in_sts->in_vsize = cur_video_sts->nnhf_input_h;
}
}
//pr_frc(dbg_sts, "in size(%d,%d) sr_out(%d,%d) dbg(%d,%d)\n",
// frc_in_sts->in_hsize, frc_in_sts->in_vsize,
// cur_video_sts->nnhf_input_w, cur_video_sts->nnhf_input_h,
// devp->dbg_input_hsize, devp->dbg_input_vsize);
return 0;
}
enum efrc_event frc_input_sts_check(struct frc_dev_s *devp,
struct st_frc_in_sts *cur_in_sts)
{
/* check change */
enum efrc_event sts_change = FRC_EVENT_NO_EVENT;
//enum frc_state_e cur_state = devp->frc_sts.state;
u32 cur_sig_in;
/*back up*/
devp->in_sts.vf_type = cur_in_sts->vf_type;
devp->in_sts.duration = cur_in_sts->duration;
devp->in_sts.signal_type = cur_in_sts->signal_type;
devp->in_sts.source_type = cur_in_sts->source_type;
/* check size change */
if (devp->in_sts.in_hsize != cur_in_sts->in_hsize) {
pr_frc(1, "hsize change (%d - %d)\n",
devp->in_sts.in_hsize, cur_in_sts->in_hsize);
/*need reconfig*/
devp->frc_sts.re_cfg_cnt = frc_re_cfg_cnt;
sts_change |= FRC_EVENT_VF_CHG_IN_SIZE;
}
devp->in_sts.in_hsize = cur_in_sts->in_hsize;
/* check size change */
if (devp->in_sts.in_vsize != cur_in_sts->in_vsize) {
pr_frc(1, "vsize change (%d - %d)\n",
devp->in_sts.in_vsize, cur_in_sts->in_vsize);
/*need reconfig*/
devp->frc_sts.re_cfg_cnt = frc_re_cfg_cnt;
sts_change |= FRC_EVENT_VF_CHG_IN_SIZE;
}
devp->in_sts.in_vsize = cur_in_sts->in_vsize;
if (devp->frc_sts.out_put_mode_changed || devp->frc_sts.re_config) {
pr_frc(1, "out_put_mode_changed 0x%x re_config:%d\n",
devp->frc_sts.out_put_mode_changed,
devp->frc_sts.re_config);
if (devp->frc_sts.out_put_mode_changed ==
FRC_EVENT_VF_CHG_IN_SIZE) {
devp->frc_sts.re_cfg_cnt = 5;
} else {
devp->frc_sts.re_cfg_cnt = frc_re_cfg_cnt;
}
sts_change |= FRC_EVENT_VOUT_CHG;
devp->frc_sts.out_put_mode_changed = 0;
devp->frc_sts.re_config = 0;
}
/* check is same vframe */
pr_frc(dbg_sts, "vf (0x%lx, 0x%lx)\n", (ulong)devp->in_sts.vf, (ulong)cur_in_sts->vf);
if (devp->in_sts.vf == cur_in_sts->vf && cur_in_sts->vf_sts)
devp->in_sts.vf_repeat_cnt++;
devp->in_sts.vf = cur_in_sts->vf;
if (devp->frc_sts.re_cfg_cnt) {
devp->frc_sts.re_cfg_cnt--;
cur_sig_in = false;
} else if (devp->in_sts.in_hsize < FRC_H_LIMIT_SIZE ||
devp->in_sts.in_vsize < FRC_V_LIMIT_SIZE) {
cur_sig_in = false;
} else {
cur_sig_in = cur_in_sts->vf_sts;
}
pr_frc(dbg_sts, "vf_sts: %d, cur_sig_in:0x%x have_cnt:%d no_cnt:%d re_cfg_cnt:%d\n",
devp->in_sts.vf_sts, cur_sig_in,
devp->in_sts.have_vf_cnt, devp->in_sts.no_vf_cnt, devp->frc_sts.re_cfg_cnt);
pr_frc(dbg_sts, "hvsize (%d,%d) cur(%d,%d)\n",
devp->in_sts.in_hsize, devp->in_sts.in_vsize,
cur_in_sts->in_hsize, cur_in_sts->in_vsize);
switch (devp->in_sts.vf_sts) {
case VFRAME_NO:
if (cur_sig_in == VFRAME_HAVE) {
if (devp->in_sts.have_vf_cnt++ >= frc_enable_cnt) {
devp->in_sts.vf_sts = cur_sig_in;
//if (FRC_EVENT_VF_IS_GAME)
sts_change |= FRC_EVENT_VF_CHG_TO_HAVE;
devp->in_sts.have_vf_cnt = 0;
pr_frc(1, "FRC_EVENT_VF_CHG_TO_HAVE\n");
}
} else {
devp->in_sts.have_vf_cnt = 0;
if (devp->frc_sts.state == FRC_STATE_DISABLE &&
devp->in_sts.vf_null_cnt == 108) {
frc_change_to_state(FRC_STATE_BYPASS);
pr_frc(1, "no_frm->chg bypass\n");
} else if (devp->frc_sts.state == FRC_STATE_BYPASS &&
devp->in_sts.vf_null_cnt == 120) {
// clk_set_rate(devp->clk_frc, 333333333);
devp->clk_state = FRC_CLOCK_2MIN;
schedule_work(&devp->frc_clk_work);
pr_frc(1, "no_frm->reduce clk\n");
}
}
break;
case VFRAME_HAVE:
if (cur_sig_in == VFRAME_NO) {
if (devp->in_sts.no_vf_cnt++ >= frc_disable_cnt) {
devp->in_sts.vf_sts = cur_sig_in;
devp->in_sts.no_vf_cnt = 0;
pr_frc(1, "FRC_EVENT_VF_CHG_TO_NO\n");
sts_change |= FRC_EVENT_VF_CHG_TO_NO;
}
} else {
devp->in_sts.no_vf_cnt = 0;
}
break;
}
/* even attach , mode change */
if (devp->frc_sts.auto_ctrl && sts_change) {
if (sts_change & FRC_EVENT_VF_CHG_TO_NO)
frc_change_to_state(FRC_STATE_DISABLE);
else if (sts_change & FRC_EVENT_VF_CHG_TO_HAVE)
frc_change_to_state(FRC_STATE_ENABLE);
}
if (devp->dbg_vf_monitor)
frc_vf_monitor(devp);
return sts_change;
}
/*video_input_w
* input vframe and display mode handle
*
*/
void frc_input_vframe_handle(struct frc_dev_s *devp, struct vframe_s *vf,
struct vpp_frame_par_s *cur_video_sts)
{
struct st_frc_in_sts cur_in_sts;
u32 no_input = false, vd_en_flag, vd_regval;
enum efrc_event frc_event;
if (!devp)
return;
if (!devp->probe_ok || !devp->power_on_flag)
return;
vd_en_flag = get_video_enabled();
vd_regval = vpu_reg_read(0x1dfb);
if (devp->ud_dbg.res1_dbg_en == 1)
pr_frc(1, "get_vd_en=%2d, 0x1dfb=0x%8x\n",
vd_en_flag, vd_regval);
if (!vf || !cur_video_sts || vd_en_flag == 0) {
devp->in_sts.vf_null_cnt++;
no_input = true;
} else if ((vd_regval & (BIT_0 | BIT_8)) == 0) {
devp->in_sts.vf_null_cnt++;
no_input = true;
}
if (vf) {
if (vf->flag & VFRAME_FLAG_GAME_MODE) {
devp->in_sts.game_mode = true;
no_input = true;
} else {
devp->in_sts.game_mode = false;
}
if (vf->flag & VFRAME_FLAG_VIDEO_SECURE) {
devp->in_sts.secure_mode = true;
/*for test secure mode disable memc*/
//no_input = true;
} else {
devp->in_sts.secure_mode = false;
}
if ((vf->type & VIDTYPE_PIC) == VIDTYPE_PIC) {
devp->in_sts.pic_type = true;
no_input = true;
} else {
devp->in_sts.pic_type = false;
}
if (vf->height < FRC_V_LIMIT_SIZE ||
vf->width < FRC_H_LIMIT_SIZE) {
no_input = true;
}
}
if (devp->frc_hw_pos == FRC_POS_AFTER_POSTBLEND)
cur_in_sts.vf_sts = true;
else
cur_in_sts.vf_sts = no_input ? false : true;
frc_update_in_sts(devp, &cur_in_sts, vf, cur_video_sts);
/* check input is change */
frc_event = frc_input_sts_check(devp, &cur_in_sts);
if (frc_event)
pr_frc(1, "event = 0x%08x\n", frc_event);
}
void frc_state_change_finish(struct frc_dev_s *devp)
{
devp->frc_sts.state = devp->frc_sts.new_state;
devp->frc_sts.state_transing = false;
}
void frc_test_mm_secure_set_off(struct frc_dev_s *devp)
{
#ifdef CONFIG_AMLOGIC_TEE
if (!tee_enabled()) {
pr_frc(0, "tee is not enable\n");
return;
}
if (secure_tee_handle) {
tee_unprotect_mem(secure_tee_handle);
pr_frc(0, "%s handl:%d\n", __func__, secure_tee_handle);
secure_tee_handle = 0;
}
#endif
}
void frc_test_mm_secure_set_on(struct frc_dev_s *devp, u32 start, u32 size)
{
#ifdef CONFIG_AMLOGIC_TEE
if (!tee_enabled()) {
pr_frc(0, "tee is not enable\n");
return;
}
if (!secure_tee_handle) {
tee_protect_mem_by_type(TEE_MEM_TYPE_FRC, start, size, &secure_tee_handle);
pr_frc(0, "%s handl:%d start:0x%x size:0x%x\n", __func__,
secure_tee_handle, start, size);
}
#endif
}
void frc_mm_secure_set(struct frc_dev_s *devp)
{
#ifdef CONFIG_AMLOGIC_TEE
u32 addr_start;
u32 addr_size;
enum frc_state_e new_state;
if (!tee_enabled()) {
pr_frc(0, "tee is not enable\n");
return;
}
/*data buffer set to secure mode*/
addr_start = devp->buf.cma_mem_paddr_start + devp->buf.lossy_mc_y_data_buf_paddr[0];
addr_size = devp->buf.lossy_mc_y_link_buf_paddr[0] - devp->buf.lossy_mc_y_data_buf_paddr[0];
/*data buffer, me/mc info and link buffer set to secure mode*/
//addr_start = devp->buf.cma_mem_paddr_start + devp->buf.lossy_mc_y_info_buf_paddr;
//addr_size = devp->buf.norm_hme_data_buf_paddr[0] - devp->buf.lossy_mc_y_info_buf_paddr;
new_state = devp->frc_sts.new_state;
/*secure mode check*/
if (!devp->in_sts.secure_mode) {
if (devp->buf.secured) {
devp->buf.secured = false;
/*call secure api to exit secure mode*/
tee_unprotect_mem(secure_tee_handle);
frc_force_secure(false);
pr_frc(1, "%s tee_unprotect_mem %d\n", __func__,
secure_tee_handle);
secure_tee_handle = 0;
}
} else {
/*need set mm to secure mode*/
if (new_state == FRC_STATE_ENABLE) {
if (!devp->buf.secured) {
devp->buf.secured = true;
/*call secure api enter secure mode*/
tee_protect_mem_by_type(TEE_MEM_TYPE_FRC, addr_start,
addr_size, &secure_tee_handle);
frc_force_secure(true);
pr_frc(1, "%s handl:%d addr_start:0x%x addr_size:0x%x\n",
__func__, secure_tee_handle,
addr_start, addr_size);
}
} else {
if (devp->buf.secured) {
devp->buf.secured = false;
/*call secure api to exit secure mode*/
tee_unprotect_mem(secure_tee_handle);
frc_force_secure(false);
pr_frc(1, "%s tee_unprotect_mem %d\n", __func__,
secure_tee_handle);
secure_tee_handle = 0;
}
}
}
#else
if (devp->in_sts.secure_mode)
pr_frc(1, "err: secure no tee define!!!\n");
#endif
}
void frc_state_handle_old(struct frc_dev_s *devp)
{
enum frc_state_e cur_state;
enum frc_state_e new_state;
struct frc_fw_data_s *pfw_data;
u32 state_changed = 0;
u32 frame_cnt = 0;
u32 log = 1;
cur_state = devp->frc_sts.state;
new_state = devp->frc_sts.new_state;
frame_cnt = devp->frc_sts.frame_cnt;
pfw_data = (struct frc_fw_data_s *)devp->fw_data;
if (cur_state != new_state) {
state_changed = 1;
pr_frc(log, "sm state_changed (%d->%d) cnt:%d\n", cur_state, new_state,
devp->frc_sts.frame_cnt);
}
switch (cur_state) {
case FRC_STATE_DISABLE:
if (state_changed) {
if (new_state == FRC_STATE_BYPASS) {
set_frc_bypass(ON);
frc_mm_secure_set(devp);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state], frc_state_ary[new_state]);
frc_state_change_finish(devp);
} else if (new_state == FRC_STATE_ENABLE) {
if (devp->frc_sts.frame_cnt == 0) {
frc_mm_secure_set(devp);
frc_hw_initial(devp);
//first : set bypass off
set_frc_bypass(OFF);
if (pfw_data->frc_input_cfg)
pfw_data->frc_input_cfg(devp->fw_data);
//second: set frc enable on
set_frc_enable(ON);
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state], frc_state_ary[new_state]);
devp->frc_sts.frame_cnt = 0;
frc_state_change_finish(devp);
} else {
devp->frc_sts.frame_cnt++;
}
} else {
pr_frc(0, "err new state %d\n", new_state);
}
}
break;
case FRC_STATE_ENABLE:
if (state_changed) {
if (new_state == FRC_STATE_DISABLE) {
if (devp->frc_sts.frame_cnt == 0) {
frc_mm_secure_set(devp);
set_frc_enable(OFF);
devp->frc_sts.frame_cnt++;
} else {
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
frc_state_change_finish(devp);
}
} else if (new_state == FRC_STATE_BYPASS) {
//first frame set enable off
if (devp->frc_sts.frame_cnt == 0) {
frc_mm_secure_set(devp);
set_frc_enable(OFF);
//set_frc_bypass(OFF);
devp->frc_sts.frame_cnt++;
} else {
//second frame set bypass on
set_frc_bypass(ON);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state], frc_state_ary[new_state]);
frc_state_change_finish(devp);
}
} else {
pr_frc(0, "err new state %d\n", new_state);
}
}
break;
case FRC_STATE_BYPASS:
if (state_changed) {
if (new_state == FRC_STATE_DISABLE) {
set_frc_bypass(OFF);
set_frc_enable(OFF);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state], frc_state_ary[new_state]);
frc_state_change_finish(devp);
} else if (new_state == FRC_STATE_ENABLE) {
if (devp->frc_sts.frame_cnt == 0) {
frc_mm_secure_set(devp);
//first frame set bypass off
set_frc_bypass(OFF);
//set_frc_enable(OFF);
devp->frc_sts.frame_cnt++;
} else if (devp->frc_sts.frame_cnt == 1) {
frc_hw_initial(devp);
//second frame set enable on
if (pfw_data->frc_input_cfg)
pfw_data->frc_input_cfg(devp->fw_data);
set_frc_enable(ON);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state], frc_state_ary[new_state]);
frc_state_change_finish(devp);
} else {
devp->frc_sts.frame_cnt++;
}
} else {
pr_frc(0, "err new state %d\n", new_state);
}
}
break;
default:
pr_frc(0, "err state %d\n", cur_state);
break;
}
}
void frc_state_handle(struct frc_dev_s *devp)
{
enum frc_state_e cur_state;
enum frc_state_e new_state;
struct frc_fw_data_s *pfw_data;
u32 state_changed = 0;
u32 frame_cnt = 0;
static u8 forceidx;
static u8 framedelay;
u8 frc_input_fid = 0;
u32 log = 1;
cur_state = devp->frc_sts.state;
new_state = devp->frc_sts.new_state;
frame_cnt = devp->frc_sts.frame_cnt;
pfw_data = (struct frc_fw_data_s *)devp->fw_data;
if (cur_state != new_state) {
state_changed = 1;
pr_frc(log, "sm stat_change(%d->%d) frame_cnt:%d\n", cur_state,
new_state, frame_cnt);
}
switch (cur_state) {
case FRC_STATE_DISABLE:
if (state_changed) {
if (new_state == FRC_STATE_BYPASS) {
set_frc_bypass(ON);
frc_mm_secure_set(devp);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
frc_state_change_finish(devp);
} else if (new_state == FRC_STATE_ENABLE) {
if (devp->frc_sts.frame_cnt == 0) {
if (devp->clk_state != FRC_CLOCK_NOR &&
devp->clk_state != FRC_CLOCK_2NOR) {
devp->clk_state = FRC_CLOCK_2NOR;
schedule_work(&devp->frc_clk_work);
} else if (devp->clk_state == FRC_CLOCK_NOR) {
frc_mm_secure_set(devp);
// clk_set_rate(devp->clk_frc, 667000000);
frc_hw_initial(devp);
//first : set bypass off
set_frc_bypass(OFF);
if (pfw_data->frc_input_cfg)
pfw_data->frc_input_cfg(devp->fw_data);
//second: set frc enable on
set_frc_enable(ON);
framedelay =
(READ_FRC_REG(FRC_REG_TOP_CTRL9) >> 24) & 0xF;
pr_frc(log, "frc_frm_dly %d\n",
framedelay);
devp->frc_sts.frame_cnt++;
}
} else if (devp->frc_sts.frame_cnt == framedelay) {
forceidx = frc_frame_forcebuf_enable(1);
frc_frame_forcebuf_count(forceidx);
pr_frc(log, "d-e_force cnt %d, idx %d\n",
devp->frc_sts.frame_cnt, forceidx);
devp->frc_sts.frame_cnt++;
} else if (devp->frc_sts.frame_cnt > framedelay &&
devp->frc_sts.frame_cnt <
framedelay * 2) {
frc_frame_forcebuf_count(forceidx);
frc_input_fid =
READ_FRC_REG(FRC_REG_PAT_POINTER) >> 4 & 0xF;
pr_frc(log, "d-e_force cnt %d, readidx %d\n",
devp->frc_sts.frame_cnt, frc_input_fid);
devp->frc_sts.frame_cnt++;
} else if (devp->frc_sts.frame_cnt ==
framedelay * 2) {
frc_frame_forcebuf_enable(0);
frc_state_change_finish(devp);
pr_frc(log, "d-e_sm state change %s -> %s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
devp->frc_sts.frame_cnt = 0;
} else if (devp->frc_sts.frame_cnt < framedelay) {
devp->frc_sts.frame_cnt++;
}
} else {
pr_frc(0, "err new state %d\n", new_state);
}
}
break;
case FRC_STATE_ENABLE:
if (state_changed) {
if (new_state == FRC_STATE_DISABLE) {
if (devp->frc_sts.frame_cnt == 0) {
frc_mm_secure_set(devp);
frc_frame_forcebuf_enable(0);
set_frc_enable(OFF);
devp->frc_sts.frame_cnt++;
} else {
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
frc_state_change_finish(devp);
}
} else if (new_state == FRC_STATE_BYPASS) {
//first frame set enable off
if (devp->frc_sts.frame_cnt == 0) {
frc_mm_secure_set(devp);
frc_frame_forcebuf_enable(0);
set_frc_enable(OFF);
//set_frc_bypass(OFF);
devp->frc_sts.frame_cnt++;
} else {
//second frame set bypass on
set_frc_bypass(ON);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s->%s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
frc_state_change_finish(devp);
}
} else {
pr_frc(0, "err new state %d\n", new_state);
}
}
break;
case FRC_STATE_BYPASS:
if (state_changed) {
if (new_state == FRC_STATE_DISABLE) {
set_frc_bypass(OFF);
set_frc_enable(OFF);
devp->frc_sts.frame_cnt = 0;
pr_frc(log, "sm state change %s -> %s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
frc_state_change_finish(devp);
} else if (new_state == FRC_STATE_ENABLE) {
if (devp->frc_sts.frame_cnt == 0) {
//clk_set_rate(devp->clk_frc, 667000000);
if (devp->clk_state != FRC_CLOCK_NOR &&
devp->clk_state != FRC_CLOCK_2NOR) {
devp->clk_state = FRC_CLOCK_2NOR;
schedule_work(&devp->frc_clk_work);
} else if (devp->clk_state == FRC_CLOCK_NOR) {
//first frame set bypass off
frc_mm_secure_set(devp);
frc_hw_initial(devp);
set_frc_bypass(OFF);
devp->frc_sts.frame_cnt++;
}
} else if (devp->frc_sts.frame_cnt == 1) {
//second frame set enable on
if (pfw_data->frc_input_cfg)
pfw_data->frc_input_cfg(devp->fw_data);
set_frc_enable(ON);
framedelay =
(READ_FRC_REG(FRC_REG_TOP_CTRL9) >> 24) & 0xF;
pr_frc(log, "frc_frm_dly %d\n",
framedelay);
devp->frc_sts.frame_cnt++;
} else if (devp->frc_sts.frame_cnt == framedelay + 1) {
forceidx = frc_frame_forcebuf_enable(1);
frc_frame_forcebuf_count(forceidx);
pr_frc(log, "b-e_force cnt %d, idx %d\n",
devp->frc_sts.frame_cnt, forceidx);
devp->frc_sts.frame_cnt++;
} else if (devp->frc_sts.frame_cnt > framedelay + 1 &&
devp->frc_sts.frame_cnt <
framedelay * 2 + 1) {
frc_frame_forcebuf_count(forceidx);
frc_input_fid =
READ_FRC_REG(FRC_REG_PAT_POINTER) >> 4 & 0xF;
pr_frc(log, "b-e_force cnt %d, readidx %d\n",
devp->frc_sts.frame_cnt, frc_input_fid);
devp->frc_sts.frame_cnt++;
} else if (devp->frc_sts.frame_cnt ==
framedelay * 2 + 1) {
frc_frame_forcebuf_enable(0);
frc_state_change_finish(devp);
pr_frc(log, "b-e_sm state change %s -> %s\n",
frc_state_ary[cur_state],
frc_state_ary[new_state]);
devp->frc_sts.frame_cnt = 0;
} else if (devp->frc_sts.frame_cnt < framedelay + 1) {
devp->frc_sts.frame_cnt++;
}
} else {
pr_frc(0, "err new state %d\n", new_state);
}
}
break;
default:
pr_frc(0, "err state %d\n", cur_state);
break;
}
}
int frc_memc_set_level(u8 level)
{
struct frc_dev_s *devp = get_frc_devp();
struct frc_fw_data_s *pfw_data;
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
if (!devp->fw_data)
return 0;
pfw_data = (struct frc_fw_data_s *)devp->fw_data;
pr_frc(1, "set_memc_level:%d\n", level);
pfw_data->frc_top_type.frc_memc_level = level;
if (pfw_data->frc_memc_level)
pfw_data->frc_memc_level(pfw_data);
return 1;
}
int frc_memc_set_demo(u8 setdemo)
{
struct frc_dev_s *devp = get_frc_devp();
struct frc_fw_data_s *pfw_data;
u32 tmpstart = 0, tmpend = 0;
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
if (!devp->fw_data)
return 0;
pfw_data = (struct frc_fw_data_s *)devp->fw_data;
pr_frc(1, "set_demo_mode:%d\n", setdemo);
pr_frc(1, "in_hsize:%4d\n", pfw_data->frc_top_type.hsize);
pr_frc(1, "in_vsize:%4d\n", pfw_data->frc_top_type.vsize);
pr_frc(1, "out_hsize:%4d\n", pfw_data->frc_top_type.out_hsize);
pr_frc(1, "out_vsize:%4d\n", pfw_data->frc_top_type.out_vsize);
if (setdemo == 0) {
WRITE_FRC_BITS(FRC_MC_DEMO_WINDOW, 0, 3, 1);
WRITE_FRC_BITS(FRC_REG_MC_DEBUG1, 0, 17, 1);
} else if (setdemo < 3) {
tmpstart = pfw_data->frc_top_type.hsize / 2 << 16;
pr_frc(1, "demo_win_start:%4d\n", tmpstart);
WRITE_FRC_REG(FRC_REG_DEMOWINDOW1_XYXY_ST, tmpstart);
tmpend = ((pfw_data->frc_top_type.hsize - 1) << 16) +
(pfw_data->frc_top_type.vsize - 1);
pr_frc(1, "demo_win_end:%4d\n", tmpend);
WRITE_FRC_REG(FRC_REG_DEMOWINDOW1_XYXY_ED, tmpend);
WRITE_FRC_BITS(FRC_REG_MC_DEBUG1, (setdemo - 1), 17, 1);
WRITE_FRC_BITS(FRC_MC_DEMO_WINDOW, 1, 3, 1);
} else if (setdemo < 5) {
WRITE_FRC_REG(FRC_REG_DEMOWINDOW1_XYXY_ST, 0);
tmpend = ((pfw_data->frc_top_type.hsize / 2 - 1) << 16) +
(pfw_data->frc_top_type.vsize - 1);
pr_frc(1, "demo_win_end:%4d\n", tmpend);
WRITE_FRC_REG(FRC_REG_DEMOWINDOW1_XYXY_ED, tmpend);
WRITE_FRC_BITS(FRC_REG_MC_DEBUG1, (setdemo - 3), 17, 1);
WRITE_FRC_BITS(FRC_MC_DEMO_WINDOW, 1, 3, 1);
}
return 1;
}
int frc_init_out_line(void)
{
u32 vfb = 0;
vfb = aml_read_vcbus_s(ENCL_VIDEO_VAVON_BLINE);
if (vfb)
vfb = (vfb / 4) * 3; // 3/4 point of front vblank, default
return vfb;
}
void frc_vpp_vs_ir_chk_film(struct frc_dev_s *frc_devp)
{
if (!frc_devp->probe_ok || !frc_devp->power_on_flag)
return;
if (frc_devp->ud_dbg.res0_dbg_en == 1) {
if (!frc_devp->frc_fw_pause)
frc_devp->frc_fw_pause = 1;
pr_frc(6, "vscnt=%7d, glb=%10d, cntglb=%7d\n",
frc_devp->frc_sts.vs_cnt,
READ_FRC_REG(FRC_FD_DIF_GL),
READ_FRC_REG(FRC_FD_DIF_COUNT_GL));
} // restore prev setting ,need first set fw_pause=0 by
// echo frc_pause 0 > /sys/class/frc/debug
}