From 8bb959635937edc032e4282ddabae16bb0252297 Mon Sep 17 00:00:00 2001 From: Evoke Zhang Date: Wed, 18 Jul 2018 19:58:35 +0800 Subject: [PATCH] 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 --- .../boot/dts/amlogic/mesonaxg_s400-panel.dtsi | 6 +- .../boot/dts/amlogic/mesong12a_skt-panel.dtsi | 6 +- .../boot/dts/amlogic/mesong12b_skt-panel.dtsi | 6 +- .../boot/dts/amlogic/mesongxl_p212-panel.dtsi | 2 + .../boot/dts/amlogic/mesongxm_q200-panel.dtsi | 2 + drivers/amlogic/media/vout/lcd/lcd_common.h | 4 +- drivers/amlogic/media/vout/lcd/lcd_debug.c | 64 +++++++++++------ .../media/vout/lcd/lcd_tablet/lcd_drv.c | 10 ++- .../amlogic/media/vout/lcd/lcd_tv/lcd_drv.c | 10 ++- drivers/amlogic/media/vout/lcd/lcd_vout.c | 68 ++++++++++++++++++- .../linux/amlogic/media/vout/lcd/lcd_vout.h | 8 ++- 11 files changed, 153 insertions(+), 33 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi index 659314d8f3f6..ac279f92832f 100644 --- a/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi @@ -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: diff --git a/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi index f52ce3b38049..ecaca4af424f 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi @@ -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: diff --git a/arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi index a92c4c41394a..277cdfd40795 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi @@ -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: diff --git a/arch/arm64/boot/dts/amlogic/mesongxl_p212-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesongxl_p212-panel.dtsi index 0d125f4f0bbf..1eae48a67ad9 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxl_p212-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxl_p212-panel.dtsi @@ -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: diff --git a/arch/arm64/boot/dts/amlogic/mesongxm_q200-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesongxm_q200-panel.dtsi index a2adb8921711..59fdf06171b0 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxm_q200-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxm_q200-panel.dtsi @@ -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", diff --git a/drivers/amlogic/media/vout/lcd/lcd_common.h b/drivers/amlogic/media/vout/lcd/lcd_common.h index e3545c60354e..61a9a8fdc32f 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_common.h +++ b/drivers/amlogic/media/vout/lcd/lcd_common.h @@ -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); diff --git a/drivers/amlogic/media/vout/lcd/lcd_debug.c b/drivers/amlogic/media/vout/lcd/lcd_debug.c index 9c6927d6e1b0..ffae26961e38 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_debug.c +++ b/drivers/amlogic/media/vout/lcd/lcd_debug.c @@ -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"); diff --git a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c index 52d67892de42..fada75b0c44e 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c @@ -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); diff --git a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c index c36bd923ed82..a9e71dfea271 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c @@ -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); diff --git a/drivers/amlogic/media/vout/lcd/lcd_vout.c b/drivers/amlogic/media/vout/lcd/lcd_vout.c index 96364e74a071..7d21061a1643 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_vout.c +++ b/drivers/amlogic/media/vout/lcd/lcd_vout.c @@ -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); diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index 86cb36eb0c18..6b8cc4b34a44 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -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; -- 2.20.1