From ecbdb6bc60aca2518e332a4bfcf8e5d29af2bcd6 Mon Sep 17 00:00:00 2001 From: Jian Cao Date: Wed, 26 Feb 2025 13:19:29 +0000 Subject: [PATCH] vpp: lowlatency: add rdmd lowlatency line check [1/1] PD#SWPL-204261 Problem: display anomaly caused by frame over-field Solution: add rdmd lowlatency line check Verify: t5m Change-Id: I14accc686b1c74160a4945d6fb5b1e1c331036f1 Signed-off-by: Jian Cao --- drivers/media/common/rdma/rdma.c | 5 + drivers/media/common/rdma/rdma.h | 1 + drivers/media/enhancement/amvecm/vlock.c | 2 +- drivers/media/frc/frc_drv.c | 3 +- drivers/media/frc/frc_drv.h | 4 +- drivers/media/video_sink/video.c | 49 ++++++ drivers/media/video_sink/video_low_latency.c | 174 +++++++++++++++---- drivers/media/video_sink/video_low_latency.h | 5 + 8 files changed, 205 insertions(+), 38 deletions(-) diff --git a/drivers/media/common/rdma/rdma.c b/drivers/media/common/rdma/rdma.c index 108d5908c..0bd7f870c 100644 --- a/drivers/media/common/rdma/rdma.c +++ b/drivers/media/common/rdma/rdma.c @@ -300,6 +300,11 @@ int _vsync_rdma_config(int rdma_type) return 0; } +#ifndef CONFIG_AMLOGIC_ZAPPER_CUT + if (rdma_type == EX_VSYNC_RDMA && + is_video_process_in_thread() && vpp_low_latency_check()) + return -2; +#endif if (rdma_type == EX_VSYNC_RDMA) { spin_lock_irqsave(&lock, flags); force_rdma_config[rdma_type] = 1; diff --git a/drivers/media/common/rdma/rdma.h b/drivers/media/common/rdma/rdma.h index 0ea983a1d..fd0a1e39d 100644 --- a/drivers/media/common/rdma/rdma.h +++ b/drivers/media/common/rdma/rdma.h @@ -82,6 +82,7 @@ int is_in_vsync_isr_viu2(u8 cur_cpuid); int is_in_vsync_isr_viu3(u8 cur_cpuid); int is_video_process_in_thread(void); bool get_lowlatency_mode(void); +int vpp_low_latency_check(void); #ifdef CONFIG_AMLOGIC_LCD #ifdef CONFIG_AMLOGIC_BL_LDIM int is_in_ldim_vsync_isr(u8 cur_cpuid); diff --git a/drivers/media/enhancement/amvecm/vlock.c b/drivers/media/enhancement/amvecm/vlock.c index 27fd143da..66bac1767 100644 --- a/drivers/media/enhancement/amvecm/vlock.c +++ b/drivers/media/enhancement/amvecm/vlock.c @@ -2849,7 +2849,7 @@ u32 vlock_fsm_to_en_func(struct stvlock_sig_sts *pvlock, (pvlock->output_hz != 100) && (pvlock->output_hz != 120)) pvlock->phlock_percent = 25; else if (vlock_input_hz == 60 || vlock_input_hz == 120) - pvlock->phlock_percent = 30; + pvlock->phlock_percent = 50; else pvlock->phlock_percent = 40; diff --git a/drivers/media/frc/frc_drv.c b/drivers/media/frc/frc_drv.c index 5a414b019..91c15c0c7 100644 --- a/drivers/media/frc/frc_drv.c +++ b/drivers/media/frc/frc_drv.c @@ -1124,7 +1124,8 @@ static void frc_drv_initial(struct frc_dev_s *devp) fw_data->holdline_parm.reg_post_dly_vofst = 0;/*fixed*/ fw_data->holdline_parm.reg_mc_dly_vofst0 = 1;/*fixed*/ - fw_data->frc_top_type.motion_ctrl = RD_MOTION_BY_VPU_ISR; + fw_data->frc_top_type.motion_ctrl = is_video_process_in_thread() ? + RD_MOTION_BY_INP_ISR : RD_MOTION_BY_VPU_ISR; //vpp low latency need frc inp isr for (i = 0; i < RD_REG_MAX; i++) fw_data->reg_val[i].addr = 0x0; if (fw_data->frc_top_type.chip != 0) diff --git a/drivers/media/frc/frc_drv.h b/drivers/media/frc/frc_drv.h index 26b575c65..bb525e7af 100644 --- a/drivers/media/frc/frc_drv.h +++ b/drivers/media/frc/frc_drv.h @@ -143,8 +143,9 @@ // frc_20241016 frc disable when vsize change // frc_20241023 fix absolute value operation on unsigned int // frc_20241022 frc add std flow +// frc_2024-1104 frc coverity -#define FRC_FW_VER "2024-1104 frc coverity" +#define FRC_FW_VER "2024-1108 frc add vpp low latency support" #define FRC_KERDRV_VER 3500 #define FRC_DEVNO 1 @@ -867,4 +868,5 @@ int frc_buf_set(struct frc_dev_s *frc_devp); void set_vsync_2to1_mode(u8 enable); void set_pre_vsync_mode(u8 enable); struct frc_fw_data_s *get_fw_data(void); +int is_video_process_in_thread(void); #endif diff --git a/drivers/media/video_sink/video.c b/drivers/media/video_sink/video.c index 07a484748..bc4dc76a9 100644 --- a/drivers/media/video_sink/video.c +++ b/drivers/media/video_sink/video.c @@ -689,6 +689,8 @@ atomic_t video_prevsync_inirq_flag = ATOMIC_INIT(0); atomic_t video_pause_flag = ATOMIC_INIT(0); atomic_t video_proc_lock = ATOMIC_INIT(0); atomic_t video_recv_cnt = ATOMIC_INIT(0); +atomic_t video_llm_wake = ATOMIC_INIT(1); +atomic_t video_llm_done = ATOMIC_INIT(1); int trickmode_duration; int trickmode_duration_count; u32 trickmode_vpts; @@ -5462,6 +5464,7 @@ static irqreturn_t vsync_isr(int irq, void *dev_id) lowlatency_overrun_recovery_cnt++; vsync_cnt[VPP0]++; } + atomic_set(&video_llm_wake, 1); return IRQ_HANDLED; } @@ -13739,6 +13742,48 @@ static ssize_t lowlatency_en_store(const struct class *cla, return count; } +static ssize_t lowlatency_debug_show(const struct class *cla, + const struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + u32 p0 = 0, p1 = 0, p2 = 0, p3 = 0, p4 = 0, p5 = 0; + + get_low_latency_params(&p0, &p1, &p2, &p3, &p4, &p5); + + len += sprintf(buf + len, + "frame_line_threshold: %d\n", p0); + len += sprintf(buf + len, + "rdma_line_threshold: %d\n", p1); + len += sprintf(buf + len, + "rdma_check_min_line: %d\n", p2); + len += sprintf(buf + len, + "rdma_check_max_line: %d\n", p3); + len += sprintf(buf + len, + "rdma_add_delay_ms: %d\n", p4); + len += sprintf(buf + len, + "only_vpp_wake: %d\n", p5); + + return len; +} + +static ssize_t lowlatency_debug_store(const struct class *cla, + const struct class_attribute *attr, + const char *buf, size_t count) +{ + int p[6]; + + if (likely(parse_para(buf, 6, p) == 6)) { + /* default values: 10 7 0 0 0 0 */ + set_low_latency_params(p[0], p[1], p[2], p[3], p[4], p[5]); + } else { + pr_err("invalid parameter\n"); + return -EINVAL; + } + + return count; +} + static struct class_attribute amvideo_class_attrs[] = { __ATTR(axis, 0664, @@ -14376,6 +14421,10 @@ static struct class_attribute amvideo_class_attrs[] = { 0664, lowlatency_en_show, lowlatency_en_store), + __ATTR(lowlatency_debug, + 0664, + lowlatency_debug_show, + lowlatency_debug_store), }; static struct class_attribute amvideo_poll_class_attrs[] = { diff --git a/drivers/media/video_sink/video_low_latency.c b/drivers/media/video_sink/video_low_latency.c index 5098cb4c0..5d9b9de0a 100644 --- a/drivers/media/video_sink/video_low_latency.c +++ b/drivers/media/video_sink/video_low_latency.c @@ -82,13 +82,17 @@ static u32 lowlatency_proc_done; static u32 lowlatency_overflow_cnt; static u32 lowlatency_overrun_cnt; u32 lowlatency_overrun_recovery_cnt; -static u32 lowlatency_max_proc_lines; +static int lowlatency_max_proc_lines; static u32 lowlatency_max_enter_lines; static u32 lowlatency_max_exit_lines; static u32 lowlatency_min_enter_lines = 0xffffffff; static u32 lowlatency_min_exit_lines = 0xffffffff; +static u32 lowlatency_rdma_proc_drop; +static u32 lowlatency_rdma_err_drop; +static u32 lowlatency_rdma_err2_drop; + static u32 vsync_proc_done; -static u32 line_threshold = 10; +u32 frame_line_threshold = 10; /* n/100 */ #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA static bool first_irq = true; #endif @@ -108,6 +112,13 @@ static const struct vinfo_s *vinfo; static unsigned int low_latency_ver; static u32 lowlatency_enable; +u32 rdma_check_min_line, rdma_check_max_line; +u32 rdma_line_threshold = 7; /* n/1000 */ +u32 rdma_add_delay_ms; +u32 only_vpp_wake; + +static DEFINE_SPINLOCK(video_llm_lock); + void get_low_latency_info(u32 *enable, u32 *version) { if (!enable || !version) { @@ -129,6 +140,28 @@ int get_low_latency_version(void) return lowlatency_enable ? low_latency_ver : 0; } +void get_low_latency_params(u32 *p0, u32 *p1, u32 *p2, u32 *p3, u32 *p4, u32 *p5) +{ + if (p0 && p1 && p2 && p3 && p4 && p5) { + *p0 = frame_line_threshold; + *p1 = rdma_line_threshold; + *p2 = rdma_check_min_line; + *p3 = rdma_check_max_line; + *p4 = rdma_add_delay_ms; + *p5 = only_vpp_wake; + } +} + +void set_low_latency_params(u32 p0, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5) +{ + frame_line_threshold = p0; + rdma_line_threshold = p1; + rdma_check_min_line = p2; + rdma_check_max_line = p3; + rdma_add_delay_ms = p4; + only_vpp_wake = p5; +} + u32 vsync_proc_drop; ulong lowlatency_vsync_count; bool overrun_flag; @@ -1794,8 +1827,8 @@ int proc_lowlatency_frame(u8 instance_id) vinfo_height = cur_vinfo->height; start_line = get_active_start_line(); - min_line = (vinfo_height * line_threshold) / 100 + start_line; - max_line = (vinfo_height * (100 - line_threshold)) / 100 + start_line; + min_line = (vinfo_height * frame_line_threshold) / 100 + start_line; + max_line = (vinfo_height * (100 - frame_line_threshold)) / 100 + start_line; enc_line1 = get_cur_enc_line(); if (enc_line1 >= max_line || overrun_flag) { lowlatency_proc_drop++; @@ -1915,7 +1948,17 @@ ssize_t lowlatency_states_show(const struct class *cla, atomic_read(&video_recv_cnt)); len += sprintf(buf + len, "line threshold %d\n", - line_threshold); + frame_line_threshold); + len += sprintf(buf + len, + "rdma proc drop %llu\n", + (unsigned long long)lowlatency_rdma_proc_drop); + len += sprintf(buf + len, + "rdma err drop %llu\n", + (unsigned long long)lowlatency_rdma_err_drop); + len += sprintf(buf + len, + "rdma err2 drop %llu\n", + (unsigned long long)lowlatency_rdma_err2_drop); + return len; } @@ -1945,6 +1988,9 @@ ssize_t lowlatency_states_store(const struct class *cla, lowlatency_skip_frame_cnt = 0; vsync_proc_drop = 0; vsync_proc_done = 0; + lowlatency_rdma_proc_drop = 0; + lowlatency_rdma_err_drop = 0; + lowlatency_rdma_err2_drop = 0; pr_info("Clear the lowlatency states information!\n"); return count; } @@ -1954,25 +2000,96 @@ static int line_n_in; static struct task_struct *video_thread; static wait_queue_head_t frame_process_wq; static bool video_thread_init_done; +static int wake_flag; + +void vpp_lowlatency_wakeup(void) +{ + u32 enc_line; + + if (only_vpp_wake && !wake_flag) + return; + + if (get_low_latency_version() != 2 || !video_thread_init_done) + return; + spin_lock(&video_llm_lock); + if (!atomic_read(&video_llm_wake) || !atomic_read(&video_llm_done)) { + spin_unlock(&video_llm_lock); + return; + } + atomic_set(&video_llm_wake, 0); + atomic_set(&video_llm_done, 0); + spin_unlock(&video_llm_lock); + + line_n_in = 1; + wake_up_interruptible(&frame_process_wq); + enc_line = get_cur_enc_line(); + if (debug_flag & DEBUG_FLAG_LATENCY) + pr_info("%s, wakeup enc_line:%d wake_flag:%d\n", __func__, + enc_line, wake_flag); +} static irqreturn_t line_n_isr(int irq, void *dev_id) { - if (get_low_latency_version() == 2) { - if (debug_flag & DEBUG_FLAG_LATENCY) - pr_info("line_n isr\n"); - line_n_in = 1; - if (video_thread_init_done) - wake_up_interruptible(&frame_process_wq); - } + wake_flag = 1; + vpp_lowlatency_wakeup(); + wake_flag = 0; + return IRQ_HANDLED; } +int vpp_low_latency_check(void) +{ + u32 enc_line, min_line, max_line, start_line, vinfo_height; + const struct vinfo_s *cur_vinfo; + static ulong last_vsync_count; + + if (get_low_latency_version() != 2) + return 0; + + cur_vinfo = get_current_vinfo(); + if (!cur_vinfo) { + lowlatency_rdma_proc_drop++; + return -1; + } + + if (cur_vinfo->field_height != cur_vinfo->height) + vinfo_height = cur_vinfo->field_height; + else + vinfo_height = cur_vinfo->height; + + // check line count and configure only within the threshold range. + start_line = get_active_start_line(); + min_line = 0; + max_line = (vinfo_height * (1000 - rdma_line_threshold)) / 1000 + 1 + start_line; + if (rdma_check_min_line) + min_line = rdma_check_min_line; + if (rdma_check_max_line) + max_line = rdma_check_max_line; + + enc_line = get_cur_enc_line(); + if (enc_line < min_line || enc_line > max_line) { + if (debug_flag & DEBUG_FLAG_LATENCY) + pr_info("%s enc_line:%d min_line:%d max_line:%d\n", + __func__, enc_line, min_line, max_line); + lowlatency_rdma_err_drop++; + return -1; + } + + // avoid repeated configuration within the same vsync. + if (last_vsync_count == lowlatency_vsync_count) { + lowlatency_rdma_err2_drop++; + return -2; + } + last_vsync_count = lowlatency_vsync_count; + + return 0; +} + static int process_frame(void) { - u32 enc_line1, enc_line2, last_line; - u32 min_line, max_line, start_line, vinfo_height; + int enc_line1, enc_line2; + int max_line, start_line, vinfo_height; const struct vinfo_s *cur_vinfo; - bool err_flag = false; static ulong last_vsync_count; if (legacy_vpp) @@ -1989,12 +2106,15 @@ static int process_frame(void) else vinfo_height = cur_vinfo->height; + if (rdma_add_delay_ms) + mdelay(rdma_add_delay_ms); start_line = get_active_start_line(); - min_line = (vinfo_height * line_threshold) / 100 + start_line; - max_line = (vinfo_height * (100 - line_threshold)) / 100 + start_line; + + max_line = (vinfo_height * (100 - frame_line_threshold)) / 100 + start_line; enc_line1 = get_cur_enc_line(); if (debug_flag & DEBUG_FLAG_LATENCY) - pr_info("process frame start, line:%d\n", enc_line1); + pr_info("process frame start, line:%d start_line:%d max_line:%d\n", + enc_line1, start_line, max_line); if (enc_line1 >= max_line || overrun_flag) { lowlatency_proc_drop++; @@ -2013,23 +2133,6 @@ static int process_frame(void) return -4; } - last_line = enc_line1; - while (enc_line1 < min_line) { - usleep_range(500, 600); - enc_line1 = get_cur_enc_line(); - if (last_line == enc_line1) { - /* active line no change */ - err_flag = true; - break; - } - last_line = enc_line1; - } - if (err_flag) { - lowlatency_err_drop++; - atomic_dec(&video_proc_lock); - return -5; - } - atomic_set(&video_inirq_flag, 1); enc_line1 = get_cur_enc_line(); @@ -2081,6 +2184,7 @@ static int threadfunc(void *data) start_time = ktime_get(); ret = process_frame(); + atomic_set(&video_llm_done, 1); diff_time = ktime_sub(ktime_get(), start_time); time_cost_ms = ktime_to_ms(diff_time); time_cost_us = ktime_to_us(diff_time); diff --git a/drivers/media/video_sink/video_low_latency.h b/drivers/media/video_sink/video_low_latency.h index 2cf414e94..1e27e59ff 100644 --- a/drivers/media/video_sink/video_low_latency.h +++ b/drivers/media/video_sink/video_low_latency.h @@ -44,6 +44,9 @@ extern bool over_field; extern bool dvel_status; #endif +extern atomic_t video_llm_wake; +extern atomic_t video_llm_done; + ssize_t lowlatency_states_store(const struct class *cla, const struct class_attribute *attr, const char *buf, size_t count); @@ -62,6 +65,8 @@ void vf_pq_process(struct vframe_s *vf, void get_low_latency_info(u32 *enable, u32 *version); void set_low_latency_info(u32 enable, u32 version); int get_low_latency_version(void); +void get_low_latency_params(u32 *p0, u32 *p1, u32 *p2, u32 *p3, u32 *p4, u32 *p5); +void set_low_latency_params(u32 p0, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5); void video_lowlatency_init(struct platform_device *pdev); void video_lowlatency_exit(void); void video_lowlatency_line_n_num(void);