lcd: mute: wait vsync for display shadow [2/2]
authorEvoke Zhang <evoke.zhang@amlogic.com>
Wed, 18 Jul 2018 11:58:35 +0000 (19:58 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Thu, 26 Jul 2018 14:21:02 +0000 (07:21 -0700)
PD#170101: lcd: mute: wait vsync for display shadow

Change-Id: If17838c40d46fd6f4b943d313456738fec50185a
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi
arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi
arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi
arch/arm64/boot/dts/amlogic/mesongxl_p212-panel.dtsi
arch/arm64/boot/dts/amlogic/mesongxm_q200-panel.dtsi
drivers/amlogic/media/vout/lcd/lcd_common.h
drivers/amlogic/media/vout/lcd/lcd_debug.c
drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c
drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c
drivers/amlogic/media/vout/lcd/lcd_vout.c
include/linux/amlogic/media/vout/lcd/lcd_vout.h

index 659314d..ac279f9 100644 (file)
                        "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:
index f52ce3b..ecaca4a 100644 (file)
                        "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:
index a92c4c4..277cdfd 100644 (file)
                        "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:
index 0d125f4..1eae48a 100644 (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:
index a2adb89..59fdf06 100644 (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",
index e3545c6..61a9a8f 100644 (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);
index 9c6927d..ffae269 100644 (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");
index 52d6789..fada75b 100644 (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);
 
index c36bd92..a9e71df 100644 (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);
 
index 96364e7..7d21061 100644 (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);
index 86cb36e..6b8cc4b 100644 (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;