From dd8945224a2b0aa83d8fa9bb4a91b3fb9ad9374d Mon Sep 17 00:00:00 2001 From: Evoke Zhang Date: Thu, 10 Jan 2019 22:21:01 +0800 Subject: [PATCH] lcd: optimize unifykey read flow to avoid crash [1/1] 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 --- drivers/amlogic/media/vout/lcd/lcd_common.h | 3 +- drivers/amlogic/media/vout/lcd/lcd_tcon.c | 2 +- drivers/amlogic/media/vout/lcd/lcd_vout.c | 215 ++++++++++++--------- .../linux/amlogic/media/vout/lcd/lcd_unifykey.h | 3 +- 4 files changed, 126 insertions(+), 97 deletions(-) diff --git a/drivers/amlogic/media/vout/lcd/lcd_common.h b/drivers/amlogic/media/vout/lcd/lcd_common.h index 4195510..175b191 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_common.h +++ b/drivers/amlogic/media/vout/lcd/lcd_common.h @@ -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) diff --git a/drivers/amlogic/media/vout/lcd/lcd_tcon.c b/drivers/amlogic/media/vout/lcd/lcd_tcon.c index 702ab36..ad28c23 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tcon.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tcon.c @@ -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); diff --git a/drivers/amlogic/media/vout/lcd/lcd_vout.c b/drivers/amlogic/media/vout/lcd/lcd_vout.c index 967d96c..0d69569 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_vout.c +++ b/drivers/amlogic/media/vout/lcd/lcd_vout.c @@ -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); } diff --git a/include/linux/amlogic/media/vout/lcd/lcd_unifykey.h b/include/linux/amlogic/media/vout/lcd/lcd_unifykey.h index 2204c6c..c27f57f 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_unifykey.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_unifykey.h @@ -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); -- 2.7.4