blob: 786f4ab55e9ec1eea69fe7a2dce08c7090e9b467 [file]
// 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/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/vout/vinfo.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/frc/frc_reg.h>
#include <linux/amlogic/media/frc/frc_common.h>
#include <linux/amlogic/media/registers/cpu_version.h>
#include "frc_drv.h"
#include "frc_proc.h"
#include "frc_interface.h"
/*
* every vsync handle
* vf : current input vf
* cur_video_sts: current video state
* called in vpp vs ir :vsync_fisr_in
* defined(CONFIG_AMLOGIC_MEDIA_FRC)
*/
int frc_input_handle(struct vframe_s *vf, struct vpp_frame_par_s *cur_video_sts)
{
struct frc_dev_s *devp = get_frc_devp();
u64 timestamp = sched_clock();
if (!devp)
return -1;
if (!devp->probe_ok || !devp->power_on_flag)
return -1;
/*update vs time*/
devp->frc_sts.vs_cnt++;
timestamp = div64_u64(timestamp, 1000);
devp->vs_duration = timestamp - devp->vs_timestamp;
devp->vs_timestamp = timestamp;
// frc_vpp_vs_ir_chk_film(devp);
/*vframe change detect and video state detects*/
// frc_boot_timestamp_check(devp);
frc_isr_print_zero(devp);
frc_input_vframe_handle(devp, vf, cur_video_sts);
// frc_isr_print_zero(devp);
/*frc work mode handle*/
// frc_state_handle_old(devp);
if (get_chip_type() == ID_T3X)
frc_state_handle_new(devp);
else
frc_state_handle(devp);
return 0;
}
EXPORT_SYMBOL(frc_input_handle);
/*
* for other module control frc
* FRC_STATE_ENABLE: FRC is working
* FRC_STATE_DISABLE: video data input to frc hw module, but frc not works
* FRC_STATE_BYPASS: video data not input to frc module
*
*/
int frc_set_mode(enum frc_state_e state)
{
if (state == FRC_STATE_DISABLE)
frc_change_to_state(FRC_STATE_DISABLE);
else if (state == FRC_STATE_BYPASS)
frc_change_to_state(FRC_STATE_BYPASS);
else if (state == FRC_STATE_ENABLE)
frc_change_to_state(FRC_STATE_ENABLE);
return 0;
}
/*
* get current frc video latency
* return: ms
*/
int frc_get_video_latency_for_gd(void)
{
struct frc_dev_s *devp = get_frc_devp();
struct frc_fw_data_s *fw_data;
struct frc_top_type_s *frc_top;
// u32 out_frm_dly_num;
struct vinfo_s *vinfo = get_current_vinfo();
u32 vout_hz = 0;
int delay_time = -1; /*ms*/
// delay_time = out_frm_dly_num;
if (!devp || !vinfo)
return -1;
fw_data = (struct frc_fw_data_s *)devp->fw_data;
frc_top = &fw_data->frc_top_type;
if (vinfo && vinfo->sync_duration_den != 0)
vout_hz = vinfo->sync_duration_num / vinfo->sync_duration_den;
if (devp->frc_sts.auto_ctrl == 1) {
if (devp->in_sts.frc_vf_rate == 0)
return -1;
else if (frc_top->film_mode == 0)
delay_time = 35 * 100 / devp->in_sts.frc_vf_rate;
else if (frc_top->film_mode != 0) // 30hz or 25hz
delay_time = 35 * 100 / devp->in_sts.frc_vf_rate;
else
delay_time = -2;
} else {
delay_time = -1;
}
return delay_time;
}
EXPORT_SYMBOL(frc_get_video_latency_for_gd);
/*
* get current frc video latency 1
* return: out vsync num
*/
int frc_get_video_latency_for_gd1(void)
{
struct frc_dev_s *devp = get_frc_devp();
struct frc_fw_data_s *fw_data;
struct frc_top_type_s *frc_top;
// u32 out_frm_dly_num;
struct vinfo_s *vinfo = get_current_vinfo();
u32 vout_hz = 0;
int delay_time = -1; /*ms*/
int delay_vsync_num = 0;
if (!devp || !vinfo)
return -1;
fw_data = (struct frc_fw_data_s *)devp->fw_data;
frc_top = &fw_data->frc_top_type;
if (vinfo && vinfo->sync_duration_den != 0)
vout_hz = vinfo->sync_duration_num / vinfo->sync_duration_den;
if (devp->frc_sts.auto_ctrl == 1) {
if (devp->in_sts.frc_vf_rate == 0)
return -1;
else if (frc_top->film_mode == 0)
delay_time = 35 * 100 / devp->in_sts.frc_vf_rate;
else if (frc_top->film_mode != 0) // 30hz or 25hz
delay_time = 35 * 100 / devp->in_sts.frc_vf_rate;
else
delay_time = -2;
} else {
return -1;
}
if (delay_time > 0)
delay_vsync_num = delay_time * vout_hz / 1000;
else
delay_vsync_num = -2;
return delay_vsync_num;
}
EXPORT_SYMBOL(frc_get_video_latency_for_gd1);
int frc_get_video_latency(void)
{
struct frc_dev_s *devp = get_frc_devp();
// u32 out_frm_dly_num;
struct vinfo_s *vinfo = get_current_vinfo();
u32 vout_hz = 0;
u32 delay_time = 0; /*ms*/
u32 delay = 0; /*ms*/
if (vinfo && vinfo->sync_duration_den != 0)
vout_hz = vinfo->sync_duration_num / vinfo->sync_duration_den;
// out_frm_dly_num = READ_FRC_BITS(FRC_REG_TOP_CTRL9, 24, 4);
if (vout_hz != 0)
delay = 35 * 100 / vout_hz;
// delay_time = out_frm_dly_num;
if (!devp || !vinfo)
return 0;
if (devp->frc_sts.auto_ctrl == 1) {
// if (devp->in_sts.vf_sts == VFRAME_NO)
// delay_time = delay;
// else if (devp->frc_sts.state == FRC_STATE_BYPASS ||
// devp->frc_sts.state == FRC_STATE_DISABLE)
// delay_time = 0;
// else if (devp->frc_sts.state == FRC_STATE_ENABLE)
// delay_time = delay;
delay_time = delay;
} else {
delay_time = 0;
}
return delay_time;
}
EXPORT_SYMBOL(frc_get_video_latency);
int frc_is_on(void)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok || !devp->power_on_flag)
return 0;
if (devp->clk_state == FRC_CLOCK_OFF)
return 0;
if ((READ_FRC_REG(FRC_TOP_CTRL) & 0x01) == FRC_STATE_ENABLE &&
devp->in_sts.vs_cnt >= devp->other2_flag)
return 1;
else
return 0;
}
EXPORT_SYMBOL(frc_is_on);
int frc_is_supported(void)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
return 1;
}
EXPORT_SYMBOL(frc_is_supported);
int frc_set_seg_display(u8 enable, u8 seg1, u8 seg2, u8 seg3)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
if (devp->clk_state == FRC_CLOCK_OFF)
return 0;
if (enable) {
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_POSI_AND_NUM41_NUM42, 0xE1 << 24, 0xFF000000);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 1 << 31, BIT_31);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 1 << 23, BIT_23);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 1 << 15, BIT_15);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 2 << 28, 0x70000000);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 1 << 20, 0x700000);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 2 << 12, 0x7000);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46,
seg1 << 24, 0xF000000);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, seg2 << 16, 0xF0000);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, seg3 << 8, 0xF00);
} else {
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 0, BIT_31);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 0, BIT_23);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_NUM43_NUM44_NUM45_NUM46, 0, BIT_15);
UPDATE_FRC_REG_BITS(FRC_MC_SEVEN_FLAG_POSI_AND_NUM41_NUM42, 0x03 << 24, 0xFF000000);
}
return 1;
}
EXPORT_SYMBOL(frc_set_seg_display);
int frc_drv_get_1st_frm(void)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 1;
if (!devp->probe_ok)
return 1;
if (devp->frc_sts.state != FRC_STATE_ENABLE)
return 1;
else if ((READ_FRC_REG(FRC_TOP_CTRL) & 0x01) == 0)
return 1;
else
return ((READ_FRC_REG(FRC_REG_PAT_POINTER) >> 12) & 0x1);
}
EXPORT_SYMBOL(frc_drv_get_1st_frm);
int frc_get_n2m_setting(void)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
if (devp->in_out_ratio == FRC_RATIO_1_1)
return 1;
else if (devp->in_out_ratio == FRC_RATIO_1_2)
return 2;
else if (devp->in_out_ratio == FRC_RATIO_2_5)
return 3;
else if (devp->in_out_ratio == FRC_RATIO_5_6)
return 4;
else if (devp->in_out_ratio == FRC_RATIO_5_12)
return 5;
else
return 0;
}
EXPORT_SYMBOL(frc_get_n2m_setting);
int frc_ready_to_switch(void)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
if (devp->st_change == 1)
return 1;
else if (devp->st_change == 2)
return 2;
else if (devp->st_change == 3)
return 3;
else
return 0;
}
EXPORT_SYMBOL(frc_ready_to_switch);
int frc_bypass_signal(void)
{
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
if (devp->need_bypass == 1)
return 1;
else if (devp->need_bypass == 2)
return 2;
else
return 0;
}
EXPORT_SYMBOL(frc_bypass_signal);
int frc_get_memc_size(u16 *hsize, u16 *vsize)
{
u32 temp_size;
int ret = 0;
int in_idx, out_idx, force_flag;
struct frc_dev_s *devp = get_frc_devp();
if (!devp)
return 0;
if (!devp->probe_ok)
return 0;
// if (devp->clk_state == FRC_CLOCK_OFF)
// ret = 0;
if ((READ_FRC_REG(FRC_TOP_CTRL) & 0x01) == 0x01) {
in_idx = (READ_FRC_REG(FRC_REG_PAT_POINTER) >> 4) & 0xF,
out_idx = (READ_FRC_REG(FRC_REG_OUT_FID) >> 12) & 0xF;
force_flag = (READ_FRC_REG(FRC_REG_TOP_CTRL7) >> 24) & 0x1F;
if (out_idx > 12 && ((in_idx == 3 - (16 - out_idx)) ||
(in_idx == 2 - (16 - out_idx)))) {
temp_size = READ_FRC_REG(FRC_FRAME_SIZE);
*vsize = (temp_size >> 16) & 0xFFF;
*hsize = temp_size & 0xFFF;
ret = 1;
} else if (((in_idx > out_idx) && (ABS(in_idx - out_idx) == 3 ||
ABS(in_idx - out_idx) == 2)) ||
force_flag != 0) {
temp_size = READ_FRC_REG(FRC_FRAME_SIZE);
*vsize = (temp_size >> 16) & 0xFFF;
*hsize = temp_size & 0xFFF;
ret = 1;
} else {
ret = 0;
}
}
return ret;
}
EXPORT_SYMBOL(frc_get_memc_size);