lcd: mute: wait vsync for display shadow [2/2]

PD#170101: lcd: mute: wait vsync for display shadow

Change-Id: If17838c40d46fd6f4b943d313456738fec50185a
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
This commit is contained in:
Evoke Zhang
2018-07-18 19:58:35 +08:00
committed by Yixun Lan
parent 6cf8325a38
commit 8bb9596359
11 changed files with 153 additions and 33 deletions

View File

@@ -32,8 +32,10 @@
"dsi_meas",
"mipi_enable_gate",
"mipi_bandgap_gate";
reg = <0x0 0xffd06000 0x0 0x400
0x0 0xff640000 0x0 0x100>;
reg = <0x0 0xffd06000 0x0 0x400 /* dsi_host */
0x0 0xff640000 0x0 0x100>; /* dsi_phy */
interrupts = <0 3 1>;
interrupt-names = "vsync";
pinctrl_version = <1>; /* for uboot */
/* power type:

View File

@@ -32,8 +32,10 @@
"dsi_meas",
"encl_top_gate",
"encl_int_gate";
reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
0x0 0xff644000 0x0 0x2000>; /* dsi_phy */
reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
0x0 0xff644000 0x0 0x200>; /* dsi_phy */
interrupts = <0 3 1>;
interrupt-names = "vsync";
pinctrl_version = <2>; /* for uboot */
/* power type:

View File

@@ -32,8 +32,10 @@
"dsi_meas",
"encl_top_gate",
"encl_int_gate";
reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
0x0 0xff644000 0x0 0x2000>; /* dsi_phy */
reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
0x0 0xff644000 0x0 0x200>; /* dsi_phy */
interrupts = <0 3 1>;
interrupt-names = "vsync";
pinctrl_version = <2>; /* for uboot */
/* power type:

View File

@@ -28,6 +28,8 @@
* "vencl_int_gate";
*/
reg = <0x0 0xc8834400 0x0 0x100>;
interrupts = <0 3 1>;
interrupt-names = "vsync";
pinctrl_version = <1>; /* for uboot */
/* power type:

View File

@@ -28,6 +28,8 @@
* "vencl_int_gate";
*/
reg = <0x0 0xc8834400 0x0 0x100>;
interrupts = <0 3 1>;
interrupt-names = "vsync";
pinctrl_version = <1>; /* for uboot */
pinctrl-names = "ttl_6bit_hvsync_de_on","ttl_6bit_hvsync_on",
"ttl_6bit_de_on","ttl_8bit_hvsync_de_on",

View File

@@ -29,7 +29,8 @@
/* 20180425: tvconfig suuport */
/* 20180620: fix coverity errors */
/* 20180626: txl suuport */
#define LCD_DRV_VERSION "20180626"
/* 20180718: mute: wait vsync for display shadow */
#define LCD_DRV_VERSION "20180718"
#define VPP_OUT_SATURATE (1 << 0)
@@ -97,6 +98,7 @@ extern void lcd_venc_change(struct lcd_config_s *pconf);
extern void lcd_if_enable_retry(struct lcd_config_s *pconf);
/* lcd debug */
extern void lcd_debug_test(unsigned int num);
extern void lcd_mute_setting(unsigned char flag);
extern int lcd_class_creat(void);
extern int lcd_class_remove(void);

View File

@@ -967,6 +967,16 @@ static int lcd_hdr_info_print(char *buf, int offset)
return len;
}
static struct work_struct lcd_test_check_work;
static void lcd_test_pattern_check(struct work_struct *p_work)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
int flag;
flag = (lcd_drv->lcd_test_state > 0) ? 1 : 0;
aml_lcd_notifier_call_chain(LCD_EVENT_TEST_PATTERN, &flag);
}
#define LCD_ENC_TST_NUM_MAX 9
static char *lcd_enc_tst_str[] = {
"0-None", /* 0 */
@@ -993,15 +1003,17 @@ static unsigned int lcd_enc_tst[][7] = {
{0, 0x0, 0x0, 0x0, 1, 0, 3}, /* 8 */
};
static void lcd_debug_test(unsigned int num)
void lcd_debug_test(unsigned int num)
{
unsigned int h_active, video_on_pixel;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
int flag;
num = (num >= LCD_ENC_TST_NUM_MAX) ? 0 : num;
flag = (num > 0) ? 1 : 0;
aml_lcd_notifier_call_chain(LCD_EVENT_TEST_PATTERN, &flag);
if (lcd_drv->workqueue)
queue_work(lcd_drv->workqueue, &lcd_test_check_work);
else
schedule_work(&lcd_test_check_work);
h_active = lcd_drv->lcd_config->lcd_basic.h_active;
video_on_pixel = lcd_drv->lcd_config->lcd_timing.video_on_pixel;
@@ -1022,7 +1034,6 @@ static void lcd_debug_test(unsigned int num)
void lcd_mute_setting(unsigned char flag)
{
LCDPR("set lcd mute: %d\n", flag);
if (flag) {
lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3);
lcd_vcbus_write(ENCL_TST_MDSEL, 0);
@@ -1042,14 +1053,14 @@ static void lcd_screen_restore(void)
unsigned int h_active, video_on_pixel;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
unsigned int num;
int flag;
lcd_drv->lcd_mute = 0;
num = lcd_drv->lcd_test_flag;
num = (num >= LCD_ENC_TST_NUM_MAX) ? 0 : num;
flag = (num > 0) ? 1 : 0;
aml_lcd_notifier_call_chain(LCD_EVENT_TEST_PATTERN, &flag);
if (lcd_drv->workqueue)
queue_work(lcd_drv->workqueue, &lcd_test_check_work);
else
schedule_work(&lcd_test_check_work);
h_active = lcd_drv->lcd_config->lcd_basic.h_active;
video_on_pixel = lcd_drv->lcd_config->lcd_timing.video_on_pixel;
@@ -1267,8 +1278,8 @@ static ssize_t lcd_debug_store(struct class *class,
case 't': /* test */
ret = sscanf(buf, "test %d", &temp);
if (ret == 1) {
lcd_drv->lcd_test_flag = (unsigned char)temp;
lcd_debug_test(temp);
lcd_drv->lcd_test_flag =
(unsigned char)(temp | LCD_TEST_UPDATE);
} else {
LCDERR("invalid data\n");
return -EINVAL;
@@ -1826,14 +1837,14 @@ static ssize_t lcd_debug_test_show(struct class *class,
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
return sprintf(buf, "test pattern: %d\n", lcd_drv->lcd_test_flag);
return sprintf(buf, "test pattern: %d\n", lcd_drv->lcd_test_state);
}
static ssize_t lcd_debug_test_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
unsigned int temp = 0;
unsigned int temp = 0, i = 0;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
ret = kstrtouint(buf, 10, &temp);
@@ -1841,8 +1852,13 @@ static ssize_t lcd_debug_test_store(struct class *class,
pr_info("invalid data\n");
return -EINVAL;
}
lcd_drv->lcd_test_flag = (unsigned char)temp;
lcd_debug_test(temp);
temp = (temp >= LCD_ENC_TST_NUM_MAX) ? 0 : temp;
lcd_drv->lcd_test_flag = (unsigned char)(temp | LCD_TEST_UPDATE);
while (i++ < 5000) {
if (lcd_drv->lcd_test_state == temp)
break;
udelay(20);
}
return count;
}
@@ -1852,14 +1868,15 @@ static ssize_t lcd_debug_mute_show(struct class *class,
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
return sprintf(buf, "get lcd mute state: %d\n", lcd_drv->lcd_mute);
return sprintf(buf, "get lcd mute state: %d\n",
lcd_drv->lcd_mute_state);
}
static ssize_t lcd_debug_mute_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
unsigned int temp = 0;
unsigned int temp = 0, i = 0;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
ret = kstrtouint(buf, 10, &temp);
@@ -1867,8 +1884,13 @@ static ssize_t lcd_debug_mute_store(struct class *class,
pr_info("invalid data\n");
return -EINVAL;
}
lcd_drv->lcd_mute = (unsigned char)temp;
lcd_mute_setting(lcd_drv->lcd_mute);
temp = temp ? 1 : 0;
lcd_drv->lcd_mute_flag = (unsigned char)(temp | LCD_MUTE_UPDATE);
while (i++ < 5000) {
if (lcd_drv->lcd_mute_state == temp)
break;
udelay(20);
}
return count;
}
@@ -3045,6 +3067,8 @@ int lcd_class_creat(void)
lcd_drv->lcd_screen_restore = lcd_screen_restore;
lcd_drv->lcd_screen_black = lcd_screen_black;
INIT_WORK(&lcd_test_check_work, lcd_test_pattern_check);
lcd_drv->lcd_debug_class = class_create(THIS_MODULE, "lcd");
if (IS_ERR(lcd_drv->lcd_debug_class)) {
LCDERR("create lcd debug class fail\n");

View File

@@ -371,6 +371,14 @@ static void lcd_venc_set(struct lcd_config_s *pconf)
lcd_vcbus_write(ENCL_VIDEO_VSO_ELINE, pconf->lcd_timing.vs_ve_addr);
lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3);
/* default black pattern */
lcd_vcbus_write(ENCL_TST_MDSEL, 0);
lcd_vcbus_write(ENCL_TST_Y, 0);
lcd_vcbus_write(ENCL_TST_CB, 0);
lcd_vcbus_write(ENCL_TST_CR, 0);
lcd_vcbus_write(ENCL_TST_EN, 1);
lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, 0, 3, 1);
lcd_vcbus_write(ENCL_VIDEO_EN, 1);
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, NULL);
@@ -915,7 +923,7 @@ void lcd_tablet_driver_init_pre(void)
lcd_clk_set(pconf);
lcd_venc_set(pconf);
lcd_encl_tcon_set(pconf);
lcd_mute_setting(1);
lcd_drv->lcd_mute_state = 1;
lcd_vcbus_write(VENC_INTCTRL, 0x200);

View File

@@ -245,6 +245,14 @@ static void lcd_venc_set(struct lcd_config_s *pconf)
lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3);
/* default black pattern */
lcd_vcbus_write(ENCL_TST_MDSEL, 0);
lcd_vcbus_write(ENCL_TST_Y, 0);
lcd_vcbus_write(ENCL_TST_CB, 0);
lcd_vcbus_write(ENCL_TST_CR, 0);
lcd_vcbus_write(ENCL_TST_EN, 1);
lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, 0, 3, 1);
lcd_vcbus_write(ENCL_VIDEO_EN, 1);
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, NULL);
@@ -1259,7 +1267,7 @@ void lcd_tv_driver_init_pre(void)
lcd_clk_set(pconf);
lcd_venc_set(pconf);
lcd_encl_tcon_set(pconf);
lcd_mute_setting(1);
lcd_drv->lcd_mute_state = 1;
lcd_vcbus_write(VENC_INTCTRL, 0x200);

View File

@@ -328,7 +328,8 @@ static void lcd_power_screen_black(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_screen_black();
lcd_driver->lcd_mute_flag = (unsigned char)(1 | LCD_MUTE_UPDATE);
LCDPR("set mute\n");
mutex_unlock(&lcd_vout_mutex);
}
@@ -337,7 +338,8 @@ static void lcd_power_screen_restore(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_screen_restore();
lcd_driver->lcd_mute_flag = (unsigned char)(0 | LCD_MUTE_UPDATE);
LCDPR("clear mute\n");
mutex_unlock(&lcd_vout_mutex);
}
@@ -368,6 +370,41 @@ static void lcd_resume_work(struct work_struct *p_work)
mutex_unlock(&lcd_driver->power_mutex);
}
static irqreturn_t lcd_vsync_isr(int irq, void *dev_id)
{
int flag;
if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0)
return IRQ_HANDLED;
if (lcd_driver->lcd_mute_flag & LCD_MUTE_UPDATE) {
flag = lcd_driver->lcd_mute_flag & 0x1;
if (flag) {
if (lcd_driver->lcd_mute_state == 0) {
lcd_driver->lcd_mute_state = 1;
lcd_driver->lcd_screen_black();
}
} else {
if (lcd_driver->lcd_mute_state) {
lcd_driver->lcd_mute_state = 0;
lcd_driver->lcd_screen_restore();
}
}
lcd_driver->lcd_mute_flag &= ~(LCD_MUTE_UPDATE);
}
if (lcd_driver->lcd_test_flag & LCD_TEST_UPDATE) {
flag = lcd_driver->lcd_test_flag & 0xf;
if (flag != lcd_driver->lcd_test_state) {
lcd_driver->lcd_test_state = (unsigned char)flag;
lcd_debug_test(flag);
}
lcd_driver->lcd_test_flag &= ~(LCD_TEST_UPDATE);
}
return IRQ_HANDLED;
}
/* ****************************************
* lcd notify
* ****************************************
@@ -888,7 +925,10 @@ static int lcd_config_probe(struct platform_device *pdev)
lcd_driver->lcd_info = &lcd_vinfo;
lcd_driver->lcd_config = &lcd_config_dft;
lcd_driver->lcd_test_state = 0;
lcd_driver->lcd_test_flag = 0;
lcd_driver->lcd_mute_state = 0;
lcd_driver->lcd_mute_flag = 0;
lcd_driver->lcd_resume_type = 1; /* default workqueue */
lcd_driver->power_ctrl = lcd_power_ctrl;
lcd_driver->module_reset = lcd_module_reset;
@@ -922,6 +962,28 @@ static int lcd_config_probe(struct platform_device *pdev)
return 0;
}
static int lcd_vsync_irq_init(void)
{
if (!lcd_driver->res_vsync_irq) {
LCDERR("res_vsync_irq is null\n");
return -1;
}
if (request_irq(lcd_driver->res_vsync_irq->start, lcd_vsync_isr,
IRQF_SHARED, "lcd_vsync", (void *)"lcd_vsync"))
LCDERR("can't request lcd_vsync_irq\n");
else
LCDPR("request lcd_vsync_irq successful\n");
return 0;
}
static void lcd_vsync_irq_remove(void)
{
if (lcd_driver->res_vsync_irq)
free_irq(lcd_driver->res_vsync_irq->start, (void *)"lcd_vsync");
}
#ifdef CONFIG_OF
static struct lcd_data_s lcd_data_gxtvbb = {
@@ -1053,6 +1115,7 @@ static int lcd_probe(struct platform_device *pdev)
lcd_ioremap(pdev);
ret = lcd_config_probe(pdev);
lcd_vsync_irq_init();
LCDPR("%s %s\n", __func__, (ret ? "failed" : "ok"));
return 0;
@@ -1066,6 +1129,7 @@ static int lcd_remove(struct platform_device *pdev)
destroy_workqueue(lcd_driver->workqueue);
if (lcd_driver) {
lcd_vsync_irq_remove();
lcd_fops_remove();
lcd_class_remove();
lcd_config_remove(lcd_driver->dev);

View File

@@ -393,6 +393,8 @@ struct lcd_duration_s {
#define LCD_STATUS_VMODE_ACTIVE (1 << 2)
#define LCD_STATUS_ON (LCD_STATUS_IF_ON | LCD_STATUS_ENCL_ON)
#define LCD_MUTE_UPDATE (1 << 4)
#define LCD_TEST_UPDATE (1 << 4)
struct aml_lcd_drv_s {
char version[20];
struct lcd_data_s *data;
@@ -401,9 +403,11 @@ struct aml_lcd_drv_s {
unsigned char lcd_key_valid;
unsigned char lcd_clk_path; /* 0=hpll, 1=gp0_pll */
unsigned char lcd_config_load;
unsigned char lcd_test_flag;
unsigned char lcd_resume_type; /* 0=directly, 1=workqueue */
unsigned char lcd_mute;
unsigned char lcd_test_state;
unsigned char lcd_test_flag;
unsigned char lcd_mute_state;
unsigned char lcd_mute_flag;
unsigned char clk_gate_state;
struct clk *encl_top_gate;