lcd: optimize unifykey read flow to avoid crash [1/1]
authorEvoke Zhang <evoke.zhang@amlogic.com>
Thu, 10 Jan 2019 14:21:01 +0000 (22:21 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Wed, 27 Feb 2019 07:54:39 +0000 (23:54 -0800)
PD#SWPL-4682

Problem:
lcd wait unifykey init timeout and read unifykey will crash

Solution:
incrase wait unifykey init time, and add read protection

Verify:
x301

Change-Id: Ib86a2b3b0c6c1491606404358420fd213dcfdaa8
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
drivers/amlogic/media/vout/lcd/lcd_common.h
drivers/amlogic/media/vout/lcd/lcd_tcon.c
drivers/amlogic/media/vout/lcd/lcd_vout.c
include/linux/amlogic/media/vout/lcd/lcd_unifykey.h

index 4195510..175b191 100644 (file)
@@ -37,7 +37,8 @@
 /* 20181225: update phy config */
 /* 20190108: tl1 support tablet mode */
 /* 20190115: tl1 tcon all interface support */
-#define LCD_DRV_VERSION    "20190115"
+/* 20190225: optimize unifykey read flow to avoid crash */
+#define LCD_DRV_VERSION    "20190225"
 
 #define VPP_OUT_SATURATE            (1 << 0)
 
index 702ab36..ad28c23 100644 (file)
@@ -383,7 +383,7 @@ static void lcd_tcon_config_delayed(struct work_struct *work)
        while (key_init_flag == 0) {
                if (i++ >= LCD_UNIFYKEY_WAIT_TIMEOUT)
                        break;
-               msleep(20);
+               msleep(LCD_UNIFYKEY_RETRY_INTERVAL);
                key_init_flag = key_unify_get_init_flag();
        }
        LCDPR("tcon: key_init_flag=%d, i=%d\n", key_init_flag, i);
index 967d96c..0d69569 100644 (file)
@@ -463,14 +463,40 @@ static void lcd_resume_work(struct work_struct *p_work)
        mutex_unlock(&lcd_driver->power_mutex);
 }
 
+static struct delayed_work lcd_test_delayed_work;
+static void lcd_auto_test_delayed(struct work_struct *work)
+{
+       LCDPR("%s\n", __func__);
+       mutex_lock(&lcd_driver->power_mutex);
+       aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
+       mutex_unlock(&lcd_driver->power_mutex);
+}
+
+static void lcd_auto_test(unsigned char flag)
+{
+       lcd_driver->lcd_test_state = flag;
+       if (lcd_driver->workqueue) {
+               queue_delayed_work(lcd_driver->workqueue,
+                       &lcd_test_delayed_work,
+                       msecs_to_jiffies(20000));
+       } else {
+               schedule_delayed_work(&lcd_test_delayed_work,
+                       msecs_to_jiffies(20000));
+       }
+}
+
 static int lcd_vsync_print_cnt;
 static inline void lcd_vsync_handler(void)
 {
        int flag;
 #ifdef CONFIG_AMLOGIC_LCD_TABLET
-       struct lcd_config_s *pconf = lcd_driver->lcd_config;
+       struct lcd_config_s *pconf;
 #endif
 
+       if (lcd_driver == NULL)
+               return;
+
+       pconf = lcd_driver->lcd_config;
 #ifdef CONFIG_AMLOGIC_LCD_TABLET
        if (pconf->lcd_control.mipi_config->dread) {
                if (pconf->lcd_control.mipi_config->dread->flag) {
@@ -517,6 +543,9 @@ static inline void lcd_vsync_handler(void)
 
 static irqreturn_t lcd_vsync_isr(int irq, void *dev_id)
 {
+       if (lcd_driver == NULL)
+               return IRQ_HANDLED;
+
        if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0)
                return IRQ_HANDLED;
 
@@ -530,6 +559,9 @@ static irqreturn_t lcd_vsync_isr(int irq, void *dev_id)
 
 static irqreturn_t lcd_vsync2_isr(int irq, void *dev_id)
 {
+       if (lcd_driver == NULL)
+               return IRQ_HANDLED;
+
        if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0)
                return IRQ_HANDLED;
 
@@ -563,6 +595,9 @@ static void lcd_wait_vsync(void)
 
 static void lcd_vsync_none_timer_handler(unsigned long arg)
 {
+       if (lcd_driver == NULL)
+               return;
+
        if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0)
                goto lcd_vsync_none_timer_handler_end;
 
@@ -986,6 +1021,57 @@ static void lcd_fops_remove(void)
 }
 /* ************************************************************* */
 
+static int lcd_vsync_irq_init(void)
+{
+       if (lcd_driver->res_vsync_irq) {
+               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 {
+                       if (lcd_debug_print_flag)
+                               LCDPR("request lcd_vsync_irq successful\n");
+               }
+       }
+
+       if (lcd_driver->res_vsync2_irq) {
+               if (request_irq(lcd_driver->res_vsync2_irq->start,
+                       lcd_vsync2_isr, IRQF_SHARED,
+                       "lcd_vsync2", (void *)"lcd_vsync2")) {
+                       LCDERR("can't request lcd_vsync2_irq\n");
+               } else {
+                       if (lcd_debug_print_flag)
+                               LCDPR("request lcd_vsync2_irq successful\n");
+               }
+       }
+
+       /* add timer to monitor hpll frequency */
+       init_timer(&lcd_vsync_none_timer);
+       /* lcd_vsync_none_timer.data = NULL; */
+       lcd_vsync_none_timer.function = lcd_vsync_none_timer_handler;
+       lcd_vsync_none_timer.expires = jiffies + LCD_VSYNC_NONE_INTERVAL;
+       /*add_timer(&lcd_vsync_none_timer);*/
+       /*LCDPR("add lcd_vsync_none_timer handler\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");
+
+       if (lcd_driver->res_vsync2_irq) {
+               free_irq(lcd_driver->res_vsync2_irq->start,
+                       (void *)"lcd_vsync");
+       }
+
+       if (lcd_driver->vsync_none_timer_flag) {
+               del_timer_sync(&lcd_vsync_none_timer);
+               lcd_driver->vsync_none_timer_flag = 0;
+       }
+}
+
 static void lcd_init_vout(void)
 {
        switch (lcd_driver->lcd_mode) {
@@ -1030,11 +1116,15 @@ static int lcd_mode_probe(struct device *dev)
        lcd_fops_create();
 
        lcd_notifier_register();
+       lcd_vsync_irq_init();
 
        /* add notifier for video sync_duration info refresh */
        vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE,
                &lcd_driver->lcd_info->mode);
 
+       if (lcd_driver->lcd_auto_test)
+               lcd_auto_test(lcd_driver->lcd_auto_test);
+
        return 0;
 }
 
@@ -1071,16 +1161,22 @@ static void lcd_config_probe_delayed(struct work_struct *work)
        int i = 0;
        int ret;
 
-       if (lcd_driver->lcd_key_valid) {
+       key_init_flag = key_unify_get_init_flag();
+       while (key_init_flag == 0) {
+               if (i++ >= LCD_UNIFYKEY_WAIT_TIMEOUT)
+                       break;
+               msleep(LCD_UNIFYKEY_RETRY_INTERVAL);
                key_init_flag = key_unify_get_init_flag();
-               while (key_init_flag == 0) {
-                       if (i++ >= LCD_UNIFYKEY_WAIT_TIMEOUT)
-                               break;
-                       msleep(20);
-                       key_init_flag = key_unify_get_init_flag();
-               }
-               LCDPR("key_init_flag=%d, i=%d\n", key_init_flag, i);
        }
+       LCDPR("key_init_flag=%d, i=%d\n", key_init_flag, i);
+
+       if (key_init_flag == 0) {
+               kfree(lcd_driver);
+               lcd_driver = NULL;
+               LCDERR("key is not ready, probe exit\n");
+               return;
+       }
+
        ret = lcd_mode_probe(lcd_driver->dev);
        if (ret) {
                kfree(lcd_driver);
@@ -1234,57 +1330,6 @@ static int lcd_config_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int lcd_vsync_irq_init(void)
-{
-       if (lcd_driver->res_vsync_irq) {
-               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 {
-                       if (lcd_debug_print_flag)
-                               LCDPR("request lcd_vsync_irq successful\n");
-               }
-       }
-
-       if (lcd_driver->res_vsync2_irq) {
-               if (request_irq(lcd_driver->res_vsync2_irq->start,
-                       lcd_vsync2_isr, IRQF_SHARED,
-                       "lcd_vsync2", (void *)"lcd_vsync2")) {
-                       LCDERR("can't request lcd_vsync2_irq\n");
-               } else {
-                       if (lcd_debug_print_flag)
-                               LCDPR("request lcd_vsync2_irq successful\n");
-               }
-       }
-
-       /* add timer to monitor hpll frequency */
-       init_timer(&lcd_vsync_none_timer);
-       /* lcd_vsync_none_timer.data = NULL; */
-       lcd_vsync_none_timer.function = lcd_vsync_none_timer_handler;
-       lcd_vsync_none_timer.expires = jiffies + LCD_VSYNC_NONE_INTERVAL;
-       /*add_timer(&lcd_vsync_none_timer);*/
-       /*LCDPR("add lcd_vsync_none_timer handler\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");
-
-       if (lcd_driver->res_vsync2_irq) {
-               free_irq(lcd_driver->res_vsync2_irq->start,
-                       (void *)"lcd_vsync");
-       }
-
-       if (lcd_driver->vsync_none_timer_flag) {
-               del_timer_sync(&lcd_vsync_none_timer);
-               lcd_driver->vsync_none_timer_flag = 0;
-       }
-}
-
 #ifdef CONFIG_OF
 
 static struct lcd_data_s lcd_data_gxl = {
@@ -1372,28 +1417,6 @@ static const struct of_device_id lcd_dt_match_table[] = {
 };
 #endif
 
-static struct delayed_work lcd_test_delayed_work;
-static void lcd_auto_test_delayed(struct work_struct *work)
-{
-       LCDPR("%s\n", __func__);
-       mutex_lock(&lcd_driver->power_mutex);
-       aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
-       mutex_unlock(&lcd_driver->power_mutex);
-}
-
-static void lcd_auto_test(unsigned char flag)
-{
-       lcd_driver->lcd_test_state = flag;
-       if (lcd_driver->workqueue) {
-               queue_delayed_work(lcd_driver->workqueue,
-                       &lcd_test_delayed_work,
-                       msecs_to_jiffies(20000));
-       } else {
-               schedule_delayed_work(&lcd_test_delayed_work,
-                       msecs_to_jiffies(20000));
-       }
-}
-
 static int lcd_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
@@ -1439,32 +1462,29 @@ 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"));
 
-       if (lcd_driver->lcd_auto_test)
-               lcd_auto_test(lcd_driver->lcd_auto_test);
-
        return 0;
 }
 
 static int lcd_remove(struct platform_device *pdev)
 {
+       if (lcd_driver == NULL)
+               return 0;
+
        cancel_delayed_work(&lcd_driver->lcd_probe_delayed_work);
        cancel_work_sync(&(lcd_driver->lcd_resume_work));
        if (lcd_driver->workqueue)
                destroy_workqueue(lcd_driver->workqueue);
 
-       if (lcd_driver) {
-               lcd_vsync_irq_remove();
-               lcd_fops_remove();
-               lcd_debug_remove();
-               lcd_config_remove(lcd_driver->dev);
+       lcd_vsync_irq_remove();
+       lcd_fops_remove();
+       lcd_debug_remove();
+       lcd_config_remove(lcd_driver->dev);
 
-               kfree(lcd_driver);
-               lcd_driver = NULL;
-       }
+       kfree(lcd_driver);
+       lcd_driver = NULL;
 
        LCDPR("%s\n", __func__);
        return 0;
@@ -1480,6 +1500,8 @@ static int lcd_resume(struct platform_device *pdev)
                (get_resume_method() == UDEFINED_WAKEUP))
                return 0;
 
+       if (lcd_driver == NULL)
+               return 0;
        if ((lcd_driver->lcd_status & LCD_STATUS_VMODE_ACTIVE) == 0)
                return 0;
 
@@ -1506,6 +1528,9 @@ static int lcd_resume(struct platform_device *pdev)
 
 static int lcd_suspend(struct platform_device *pdev, pm_message_t state)
 {
+       if (lcd_driver == NULL)
+               return 0;
+
        mutex_lock(&lcd_driver->power_mutex);
        if (lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) {
                aml_lcd_notifier_call_chain(LCD_EVENT_POWER_OFF, NULL);
@@ -1521,6 +1546,8 @@ static void lcd_shutdown(struct platform_device *pdev)
        if (lcd_debug_print_flag)
                LCDPR("%s\n", __func__);
 
+       if (lcd_driver == NULL)
+               return;
        if (lcd_driver->lcd_status & LCD_STATUS_ENCL_ON)
                aml_lcd_notifier_call_chain(LCD_EVENT_POWER_OFF, NULL);
 }
index 2204c6c..c27f57f 100644 (file)
@@ -18,7 +18,8 @@
 #ifndef _INC_AML_LCD_UNIFYKEY_H__
 #define _INC_AML_LCD_UNIFYKEY_H__
 
-#define LCD_UNIFYKEY_WAIT_TIMEOUT    300
+#define LCD_UNIFYKEY_WAIT_TIMEOUT      500
+#define LCD_UNIFYKEY_RETRY_INTERVAL    20   /* ms */
 
 /* declare external unifykey function */
 extern void *get_ukdev(void);