mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
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:
committed by
gerrit autosubmit
parent
4ebc79c99c
commit
56b1900890
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user