lcd: add high resolution vsync measure debug function [1/1]

PD#SWPL-134937

Problem:
need high resolution vsync measure debug function for lcd

Solution:
add high resolution vsync measure debug function

Verify:
am301

Change-Id: I1b1391a6210e2132ce36ebb27df83398b583f1f2
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
This commit is contained in:
Evoke Zhang
2023-08-04 19:51:52 +08:00
committed by gerrit autosubmit
parent 4ebc79c99c
commit 56b1900890
7 changed files with 310 additions and 2 deletions
+2 -1
View File
@@ -44,7 +44,8 @@
/* 20230816: optimize clk accuracy*/
/* 20230821: update clk ss support*/
/* 20230823: add dma driver for tcon lut*/
#define LCD_DRV_VERSION "20230823"
/* 20230824: support high resolution vsync measure debug*/
#define LCD_DRV_VERSION "20230824"
extern struct mutex lcd_vout_mutex;
extern spinlock_t lcd_reg_spinlock;
+187 -1
View File
@@ -4228,6 +4228,191 @@ static ssize_t lcd_debug_vinfo_show(struct device *dev,
return len;
}
//make sure 30min diff is less than half frame
#define LCD_VS_MSR_ERR_MAX 280 //unit:0.000001
#define LCD_VS_MSR_DUMP 1
#define LCD_VS_MSR_AVG 2
#define LCD_VS_MSR_SNAPSHOT 3
static unsigned int lcd_vs_msr_sel;
static ssize_t lcd_debug_vs_msr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aml_lcd_drv_s *pdrv = dev_get_drvdata(dev);
ssize_t len = 0, n = PR_BUF_MAX;
unsigned long long sum = 0, target;
unsigned int avg, err, i;
if (!pdrv->vs_msr)
return sprintf(buf, "vs_msr buffer is NULL\n");
target = pdrv->config.timing.sync_duration_num;
target = lcd_do_div(target * 1000000, pdrv->config.timing.sync_duration_den);
switch (lcd_vs_msr_sel) {
case LCD_VS_MSR_DUMP:
for (i = 0; i < pdrv->vs_msr_cnt; i++) {
if (target >= pdrv->vs_msr[i])
err = target - pdrv->vs_msr[i];
else
err = pdrv->vs_msr[i] - target;
if (len >= PR_BUF_MAX)
return len;
n = PR_BUF_MAX - len;
len += snprintf(buf + len, n, "[%d]: %d, %d%s\n",
i, pdrv->vs_msr[i],
err, (err > pdrv->vs_msr_err_th) ? "(X)" : "");
}
break;
case LCD_VS_MSR_AVG:
for (i = 0; i < pdrv->vs_msr_cnt; i++)
sum += pdrv->vs_msr[i];
avg = lcd_do_div(sum, pdrv->vs_msr_cnt);
if (target >= avg)
err = target - avg;
else
err = avg - target;
len = sprintf(buf, "vs_msr avg: %d, err: %d%s\n",
avg, err, (err > pdrv->vs_msr_err_th) ? "(X)" : "");
break;
case LCD_VS_MSR_SNAPSHOT:
for (i = 0; i < pdrv->vs_msr_i; i++) {
if (target >= pdrv->vs_msr_rt[i])
err = target - pdrv->vs_msr_rt[i];
else
err = pdrv->vs_msr_rt[i] - target;
if (len >= PR_BUF_MAX)
return len;
n = PR_BUF_MAX - len;
len += snprintf(buf + len, n, "[%d]: %d, %d%s\n",
i, pdrv->vs_msr_rt[i],
err, (err > pdrv->vs_msr_err_th) ? "(X)" : "");
}
break;
default:
break;
}
if (len >= PR_BUF_MAX)
return len;
n = PR_BUF_MAX - len;
len += snprintf(buf + len, n,
"vs_msr max:%d, min:%d\n"
"vs_msr en:%d, err_th:%d, i:%d, cnt:%d, cnt_max:%d\n",
pdrv->vs_msr_max, pdrv->vs_msr_min,
pdrv->vs_msr_en, pdrv->vs_msr_err_th,
pdrv->vs_msr_i, pdrv->vs_msr_cnt, pdrv->vs_msr_cnt_max);
return len;
}
static ssize_t lcd_debug_vs_msr_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct aml_lcd_drv_s *pdrv = dev_get_drvdata(dev);
char *buf_orig;
char *parm[8] = {NULL};
unsigned int temp, msr_en;
int ret;
if (!buf)
return count;
buf_orig = kstrdup(buf, GFP_KERNEL);
if (!buf_orig) {
LCDERR("%s: buf malloc error\n", __func__);
return count;
}
lcd_debug_parse_param(buf_orig, (char **)&parm);
if (strcmp(parm[0], "init") == 0) {
if (!parm[1]) {
pr_err("invalid data\n");
goto lcd_debug_vs_msr_store_next;
}
ret = kstrtouint(parm[1], 10, &temp);
if (ret) {
pr_err("invalid data\n");
goto lcd_debug_vs_msr_store_next;
}
if (temp) {
pdrv->vs_msr_cnt_max = temp;
pdrv->vs_msr = kcalloc(pdrv->vs_msr_cnt_max,
sizeof(unsigned int), GFP_KERNEL);
if (!pdrv->vs_msr)
goto lcd_debug_vs_msr_store_next;
pdrv->vs_msr_rt = kcalloc(300, sizeof(unsigned int), GFP_KERNEL);
if (!pdrv->vs_msr_rt)
goto lcd_debug_vs_msr_store_next;
pr_info("vs_msr buffer init ok, size: %d\n", pdrv->vs_msr_cnt_max);
} else {
if (pdrv->vs_msr_en) {
pr_err("vs_msr is still enabled, can't release buffer\n");
goto lcd_debug_vs_msr_store_next;
}
pdrv->vs_msr_i = 0;
pdrv->vs_msr_cnt = 0;
pdrv->vs_msr_cnt_max = 0;
kfree(pdrv->vs_msr);
pdrv->vs_msr = NULL;
kfree(pdrv->vs_msr_rt);
pdrv->vs_msr_rt = NULL;
}
} else if (strcmp(parm[0], "en") == 0) {
if (parm[1]) {
ret = kstrtouint(parm[1], 10, &temp);
if (ret) {
pr_err("invalid data\n");
goto lcd_debug_vs_msr_store_next;
}
if (temp) {
if (!pdrv->vs_msr || !pdrv->vs_msr_rt) {
pr_err("vs_msr buffer is NULL, can't enable\n");
goto lcd_debug_vs_msr_store_next;
}
pdrv->vs_msr_cnt = 0;
pdrv->vs_msr_i = 0;
pdrv->vs_msr_max = 0;
pdrv->vs_msr_min = 0xffffffff;
msr_en = 1; //waiting for behind parameters
} else {
pdrv->vs_msr_en = 0;
}
}
if (parm[2]) {
ret = kstrtouint(parm[2], 10, &temp);
if (ret) {
pr_err("invalid data\n");
goto lcd_debug_vs_msr_store_next;
}
pdrv->vs_msr_err_th = temp;
} else {
if (pdrv->vs_msr_err_th == 0)
pdrv->vs_msr_err_th = LCD_VS_MSR_ERR_MAX;
}
if (msr_en)
pdrv->vs_msr_en = 1;
pr_info("vs_msr en:%d, err_th:%d\n"
"i:%d, cnt:%d, cnt_max:%d\n",
pdrv->vs_msr_en, pdrv->vs_msr_err_th,
pdrv->vs_msr_i, pdrv->vs_msr_cnt, pdrv->vs_msr_cnt_max);
} else if (strcmp(parm[0], "dump") == 0) {
lcd_vs_msr_sel = LCD_VS_MSR_DUMP;
} else if (strcmp(parm[0], "avg") == 0) {
lcd_vs_msr_sel = LCD_VS_MSR_AVG;
} else if (strcmp(parm[0], "snapshot") == 0) {
lcd_vs_msr_sel = LCD_VS_MSR_SNAPSHOT;
} else {
LCDERR("invalid command\n");
kfree(buf_orig);
return -EINVAL;
}
lcd_debug_vs_msr_store_next:
kfree(buf_orig);
return count;
}
static struct device_attribute lcd_debug_attrs[] = {
__ATTR(help, 0444, lcd_debug_common_help, NULL),
__ATTR(debug, 0644, lcd_debug_show, lcd_debug_store),
@@ -4251,7 +4436,8 @@ static struct device_attribute lcd_debug_attrs[] = {
__ATTR(dump, 0644, lcd_debug_dump_show, lcd_debug_dump_store),
__ATTR(print, 0644, lcd_debug_print_show, lcd_debug_print_store),
__ATTR(cus_ctrl, 0444, lcd_debug_cus_ctrl_show, NULL),
__ATTR(vinfo, 0444, lcd_debug_vinfo_show, NULL)
__ATTR(vinfo, 0444, lcd_debug_vinfo_show, NULL),
__ATTR(vs_msr, 0644, lcd_debug_vs_msr_show, lcd_debug_vs_msr_store)
};
static const char *lcd_rgb_debug_usage_str = {
+20
View File
@@ -641,6 +641,7 @@ static int lcd_vsync_print_cnt;
static inline void lcd_vsync_handler(struct aml_lcd_drv_s *pdrv)
{
unsigned long flags = 0;
unsigned int temp;
if (!pdrv)
return;
@@ -682,6 +683,25 @@ static inline void lcd_vsync_handler(struct aml_lcd_drv_s *pdrv)
pdrv->test_state = pdrv->test_flag;
lcd_debug_test(pdrv, pdrv->test_state);
}
if (pdrv->vs_msr && pdrv->vs_msr_rt && pdrv->vs_msr_en) {
temp = vout_frame_rate_msr_high_res(pdrv->viu_sel);
pdrv->vs_msr_rt[pdrv->vs_msr_i++] = temp;
pdrv->vs_msr_sum_temp += temp;
if (temp > pdrv->vs_msr_max)
pdrv->vs_msr_max = temp;
if (temp < pdrv->vs_msr_min)
pdrv->vs_msr_min = temp;
if (pdrv->vs_msr_i >= pdrv->config.timing.frame_rate) {
pdrv->vs_msr[pdrv->vs_msr_cnt++] =
lcd_do_div(pdrv->vs_msr_sum_temp, pdrv->vs_msr_i);
pdrv->vs_msr_sum_temp = 0;
if (pdrv->vs_msr_cnt >= pdrv->vs_msr_cnt_max)
pdrv->vs_msr_en = 0;
else
pdrv->vs_msr_i = 0;
}
}
spin_unlock_irqrestore(&pdrv->isr_lock, flags);
if (lcd_vsync_print_cnt++ >= LCD_DEBUG_VSYNC_INTERVAL) {
+76
View File
@@ -29,6 +29,7 @@
struct vout_mux_data_s {
struct clk *msr_clk;
unsigned int (*vs_measure)(int index);
unsigned int (*vs_measure_high_res)(int index);
void (*msr_ctrl_init)(struct platform_device *pdev, struct vout_mux_data_s *vdata);
void (*update_viu_mux)(int index, unsigned int mux_sel);
void (*clear_viu_mux)(int index, unsigned int mux_sel);
@@ -132,6 +133,34 @@ static unsigned int vout_vs_measure_dft(int index)
return fr;
}
static unsigned int vout_vs_measure_high_res_dft(int index)
{
unsigned int val[2], fr;
unsigned long long clk_msr;
if (index > 1)
return 0;
if (vout_vdo_meas_init == 0)
return 0;
clk_msr = VDIN_MEAS_CLK_FREQ;
val[0] = vout_vcbus_read(VPP_VDO_MEAS_VS_COUNT_HI);
val[1] = vout_vcbus_read(VPP_VDO_MEAS_VS_COUNT_LO);
clk_msr *= 1000000;
if (val[0] & 0xffff)
return 0;
fr = vout_do_div(clk_msr, val[1]);
if (vout_debug_print) {
VOUTPR("%s: 0x%04x=0x%08x, clk_msr=%lld, fr=%d\n",
__func__, VPP_VDO_MEAS_VS_COUNT_LO,
vout_vcbus_read(VPP_VDO_MEAS_VS_COUNT_LO),
clk_msr, fr);
}
return fr;
}
#ifndef CONFIG_AMLOGIC_ZAPPER_CUT
static unsigned int vout_vs_measure_s5(int index)
{
@@ -163,6 +192,37 @@ static unsigned int vout_vs_measure_s5(int index)
return fr;
}
static unsigned int vout_vs_measure_high_res_s5(int index)
{
struct vinfo_s *vinfo = NULL;
unsigned int venc_index, val, fr;
unsigned long long clk_msr = VDIN_MEAS_CLK_FREQ;
if (vout_vdo_meas_init == 0)
return 0;
if (index == 1)
vinfo = get_current_vinfo();
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
else if (index == 2)
vinfo = get_current_vinfo2();
#endif
#ifdef CONFIG_AMLOGIC_VOUT3_SERVE
else if (index == 3)
vinfo = get_current_vinfo3();
#endif
if (!vinfo)
return 0;
venc_index = (vinfo->viu_mux >> 4) & 0xf;
if (venc_index >= 1)
return 0;
clk_msr *= 1000000;
val = vout_vcbus_read(VPU_VENC_RO_MEAS0);
fr = vout_do_div(clk_msr, val);
return fr;
}
#endif
unsigned int vout_frame_rate_measure(int index)
@@ -176,6 +236,17 @@ unsigned int vout_frame_rate_measure(int index)
return fr;
}
unsigned int vout_frame_rate_msr_high_res(int index)
{
unsigned int fr;
if (!vout_mux_data || !vout_mux_data->vs_measure_high_res)
return 0;
fr = vout_mux_data->vs_measure_high_res(index);
return fr;
}
/* **********************************************************
* vout venc mux
* **********************************************************
@@ -366,6 +437,7 @@ void vout_viu_mux_clear(int index, unsigned int mux_sel)
static struct vout_mux_data_s vout_mux_match_data = {
.msr_clk = NULL,
.vs_measure = vout_vs_measure_dft,
.vs_measure_high_res = vout_vs_measure_high_res_dft,
.msr_ctrl_init = vout_meas_ctrl_init_dft,
.update_viu_mux = vout_viu_mux_update_default,
.clear_viu_mux = NULL,
@@ -375,6 +447,7 @@ static struct vout_mux_data_s vout_mux_match_data = {
static struct vout_mux_data_s vout_mux_match_data_t7 = {
.msr_clk = NULL,
.vs_measure = vout_vs_measure_dft,
.vs_measure_high_res = vout_vs_measure_high_res_dft,
.msr_ctrl_init = vout_meas_ctrl_init_dft,
.update_viu_mux = vout_viu_mux_update_t7,
.clear_viu_mux = vout_viu_mux_clear_t7,
@@ -383,6 +456,7 @@ static struct vout_mux_data_s vout_mux_match_data_t7 = {
static struct vout_mux_data_s vout_mux_match_data_t3 = {
.msr_clk = NULL,
.vs_measure = vout_vs_measure_dft,
.vs_measure_high_res = vout_vs_measure_high_res_dft,
.msr_ctrl_init = vout_meas_ctrl_init_dft,
.update_viu_mux = vout_viu_mux_update_t3,
.clear_viu_mux = vout_viu_mux_clear_t7,
@@ -391,6 +465,7 @@ static struct vout_mux_data_s vout_mux_match_data_t3 = {
static struct vout_mux_data_s vout_mux_match_data_t5w = {
.msr_clk = NULL,
.vs_measure = vout_vs_measure_dft,
.vs_measure_high_res = vout_vs_measure_high_res_dft,
.msr_ctrl_init = vout_meas_ctrl_init_dft,
.update_viu_mux = vout_viu_mux_update_t3,
.clear_viu_mux = vout_viu_mux_clear_t7,
@@ -399,6 +474,7 @@ static struct vout_mux_data_s vout_mux_match_data_t5w = {
static struct vout_mux_data_s vout_mux_match_data_s5 = {
.msr_clk = NULL,
.vs_measure = vout_vs_measure_s5,
.vs_measure_high_res = vout_vs_measure_high_res_s5,
.msr_ctrl_init = vout_meas_ctrl_init_s5,
.update_viu_mux = vout_viu_mux_update_t3,
.clear_viu_mux = vout_viu_mux_clear_t7,
@@ -510,6 +510,18 @@ static ssize_t vout_frame_rate_show(struct class *class,
return ret;
}
static ssize_t vout_frame_rate_high_res_show(struct class *class,
struct class_attribute *attr, char *buf)
{
unsigned int fr;
int ret = 0;
fr = vout_frame_rate_msr_high_res(1);
ret = sprintf(buf, "%d.%06d\n", (fr / 1000000), (fr % 1000000));
return ret;
}
static ssize_t vout_bist_show(struct class *class,
struct class_attribute *attr, char *buf)
{
@@ -773,6 +785,7 @@ static struct class_attribute vout_class_attrs[] = {
__ATTR(fr_hint, 0644, vout_fr_hint_show, vout_fr_hint_store),
__ATTR(fr_range, 0644, vout_fr_range_show, NULL),
__ATTR(frame_rate, 0644, vout_frame_rate_show, NULL),
__ATTR(fr_high_res, 0644, vout_frame_rate_high_res_show, NULL),
__ATTR(bist, 0644, vout_bist_show, vout_bist_store),
__ATTR(bl_brightness, 0644, vout_bl_brightness_show, vout_bl_brightness_store),
__ATTR(vinfo, 0444, vout_vinfo_show, NULL),
@@ -704,6 +704,17 @@ struct aml_lcd_drv_s {
#endif
void *debug_info;
unsigned int *vs_msr_rt;
unsigned int *vs_msr;
unsigned int vs_msr_max;
unsigned int vs_msr_min;
unsigned long long vs_msr_sum_temp;
unsigned int vs_msr_i;
unsigned int vs_msr_cnt;
unsigned int vs_msr_cnt_max;
unsigned int vs_msr_err_th;
unsigned char vs_msr_en;
unsigned int vout_state;
unsigned int fr_auto_policy;
unsigned int fr_mode;
@@ -393,4 +393,5 @@ enum vmode_e validate_vmode(char *name, unsigned int frac);
int set_current_vmode(enum vmode_e mode);
void disable_vout_mode_set_sysfs(void);
unsigned int vout_frame_rate_measure(int index);
unsigned int vout_frame_rate_msr_high_res(int index);
#endif /* _VOUT_NOTIFY_H_ */