From e4386a05af8fcc252d75259b5a6a566002cc0224 Mon Sep 17 00:00:00 2001 From: Evoke Zhang Date: Mon, 3 Sep 2018 13:16:34 +0800 Subject: [PATCH] lcd: add viu2 vsync interrupt & no viu vsync supoort PD#172761: lcd: add viu2 vsync interrupt & no viu vsync supoort Change-Id: Idefc6208af4cfe650907e97fd823353405fce35d Signed-off-by: Evoke Zhang --- .../boot/dts/amlogic/mesong12a_skt-panel.dtsi | 5 +- .../boot/dts/amlogic/mesong12b_skt-panel.dtsi | 5 +- drivers/amlogic/media/vout/lcd/lcd_debug.c | 4 + .../media/vout/lcd/lcd_tablet/lcd_tablet.c | 8 + .../amlogic/media/vout/lcd/lcd_tv/lcd_tv.c | 8 + drivers/amlogic/media/vout/lcd/lcd_vout.c | 177 ++++++++++++++++-- .../linux/amlogic/media/vout/lcd/lcd_vout.h | 11 ++ 7 files changed, 198 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi index dfb33469eceb..9ee5bcb3a810 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12a_skt-panel.dtsi @@ -36,8 +36,9 @@ "gp0_pll"; reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */ 0x0 0xff644000 0x0 0x200>; /* dsi_phy */ - interrupts = <0 3 1>; - interrupt-names = "vsync"; + interrupts = <0 3 1 + 0 56 1>; + interrupt-names = "vsync","vsync2"; 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 e29ab4e3146d..7182b406c567 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12b_skt-panel.dtsi @@ -36,8 +36,9 @@ "gp0_pll"; reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */ 0x0 0xff644000 0x0 0x200>; /* dsi_phy */ - interrupts = <0 3 1>; - interrupt-names = "vsync"; + interrupts = <0 3 1 + 0 56 1>; + interrupt-names = "vsync","vsync2"; pinctrl_version = <2>; /* for uboot */ /* power type: diff --git a/drivers/amlogic/media/vout/lcd/lcd_debug.c b/drivers/amlogic/media/vout/lcd/lcd_debug.c index 45a5ecbbab3f..e123ec770eea 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_debug.c +++ b/drivers/amlogic/media/vout/lcd/lcd_debug.c @@ -1904,6 +1904,10 @@ static ssize_t lcd_debug_mute_store(struct class *class, } temp = temp ? 1 : 0; lcd_drv->lcd_mute_flag = (unsigned char)(temp | LCD_MUTE_UPDATE); + if (temp) + LCDPR("set mute\n"); + else + LCDPR("clear mute\n"); while (i++ < 5000) { if (lcd_drv->lcd_mute_state == temp) break; diff --git a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c index 2cd629daefb1..221db171966b 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c @@ -118,13 +118,21 @@ static int lcd_vout_disable(enum vmode_e cur_vmod) static int lcd_vout_state; static int lcd_vout_set_state(int index) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + lcd_vout_state |= (1 << index); + lcd_drv->viu_sel = index; + return 0; } static int lcd_vout_clr_state(int index) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + lcd_vout_state &= ~(1 << index); + lcd_drv->viu_sel = LCD_VIU_SEL_NONE; + return 0; } diff --git a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c index 8e36aa7fb3c3..ef11430ae997 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c @@ -376,13 +376,21 @@ static int lcd_vout_disable(enum vmode_e cur_vmod) static int lcd_vout_state; static int lcd_vout_set_state(int index) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + lcd_vout_state |= (1 << index); + lcd_drv->viu_sel = index; + return 0; } static int lcd_vout_clr_state(int index) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + lcd_vout_state &= ~(1 << index); + lcd_drv->viu_sel = LCD_VIU_SEL_NONE; + return 0; } diff --git a/drivers/amlogic/media/vout/lcd/lcd_vout.c b/drivers/amlogic/media/vout/lcd/lcd_vout.c index a1adffb419da..30fc031a011e 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_vout.c +++ b/drivers/amlogic/media/vout/lcd/lcd_vout.c @@ -68,6 +68,12 @@ struct lcd_cdev_s { static struct lcd_cdev_s *lcd_cdev; +static int lcd_vsync_cnt; +static int lcd_vsync_cnt_previous; + +#define LCD_VSYNC_NONE_INTERVAL msecs_to_jiffies(500) +static struct timer_list lcd_vsync_none_timer; + /* ********************************************************* * lcd config define * ********************************************************* @@ -293,6 +299,22 @@ static void lcd_power_encl_on(void) lcd_driver->driver_init_pre(); lcd_driver->lcd_status |= LCD_STATUS_ENCL_ON; + /* vsync_none_timer conditional enabled to save cpu loading */ + if (lcd_driver->viu_sel == LCD_VIU_SEL_NONE) { + if (lcd_driver->vsync_none_timer_flag == 0) { + lcd_vsync_none_timer.expires = + jiffies + LCD_VSYNC_NONE_INTERVAL; + add_timer(&lcd_vsync_none_timer); + lcd_driver->vsync_none_timer_flag = 1; + LCDPR("add lcd_vsync_none_timer handler\n"); + } + } else { + if (lcd_driver->vsync_none_timer_flag) { + del_timer_sync(&lcd_vsync_none_timer); + lcd_driver->vsync_none_timer_flag = 0; + } + } + mutex_unlock(&lcd_vout_mutex); } @@ -303,6 +325,11 @@ static void lcd_power_encl_off(void) lcd_driver->lcd_status &= ~LCD_STATUS_ENCL_ON; lcd_driver->driver_disable_post(); + if (lcd_driver->vsync_none_timer_flag) { + del_timer_sync(&lcd_vsync_none_timer); + lcd_driver->vsync_none_timer_flag = 0; + } + mutex_unlock(&lcd_vout_mutex); } @@ -362,6 +389,7 @@ static void lcd_module_reset(void) lcd_driver->lcd_config->change_flag = 0; lcd_driver->lcd_mute_flag = (unsigned char)(0 | LCD_MUTE_UPDATE); + LCDPR("clear mute\n"); mutex_unlock(&lcd_vout_mutex); } @@ -375,16 +403,14 @@ 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) +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; #endif - if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0) - return IRQ_HANDLED; - #ifdef CONFIG_AMLOGIC_LCD_TABLET if (pconf->lcd_control.mipi_config->dread) { if (pconf->lcd_control.mipi_config->dread->flag) { @@ -420,9 +446,81 @@ static irqreturn_t lcd_vsync_isr(int irq, void *dev_id) lcd_driver->lcd_test_flag &= ~(LCD_TEST_UPDATE); } + if (lcd_vsync_print_cnt++ >= LCD_DEBUG_VSYNC_INTERVAL) { + lcd_vsync_print_cnt = 0; + if (lcd_debug_print_flag & LCD_DEBUG_LEVEL_VSYNC) { + LCDPR("%s: viu_sel: %d\n", + __func__, lcd_driver->viu_sel); + } + } +} + +static irqreturn_t lcd_vsync_isr(int irq, void *dev_id) +{ + if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0) + return IRQ_HANDLED; + + if (lcd_driver->viu_sel == 1) { + lcd_vsync_handler(); + if (lcd_vsync_cnt++ >= 65536) + lcd_vsync_cnt = 0; + } return IRQ_HANDLED; } +static irqreturn_t lcd_vsync2_isr(int irq, void *dev_id) +{ + if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0) + return IRQ_HANDLED; + + if (lcd_driver->viu_sel == 2) { + lcd_vsync_handler(); + if (lcd_vsync_cnt++ >= 65536) + lcd_vsync_cnt = 0; + } + return IRQ_HANDLED; +} + +#define LCD_WAIT_VSYNC_TIMEOUT 50000 +static void lcd_wait_vsync(void) +{ + int line_cnt, line_cnt_previous; + int i = 0; + + line_cnt = 0x1fff; + line_cnt_previous = lcd_vcbus_getb(ENCL_INFO_READ, 16, 13); + while (i++ < LCD_WAIT_VSYNC_TIMEOUT) { + line_cnt = lcd_vcbus_getb(ENCL_INFO_READ, 16, 13); + if (line_cnt < line_cnt_previous) + break; + line_cnt_previous = line_cnt; + udelay(2); + } + /*LCDPR("line_cnt=%d, line_cnt_previous=%d, i=%d\n", + * line_cnt, line_cnt_previous, i); + */ +} + +static void lcd_vsync_none_timer_handler(unsigned long arg) +{ + if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0) + goto lcd_vsync_none_timer_handler_end; + + if (lcd_vsync_cnt == lcd_vsync_cnt_previous) { + lcd_wait_vsync(); + lcd_vsync_handler(); + } + + lcd_vsync_cnt_previous = lcd_vsync_cnt; + +lcd_vsync_none_timer_handler_end: + if (lcd_driver->vsync_none_timer_flag) { + lcd_vsync_none_timer.expires = + jiffies + LCD_VSYNC_NONE_INTERVAL; + add_timer(&lcd_vsync_none_timer); + } +} + /* **************************************** * lcd notify * **************************************** @@ -934,6 +1032,10 @@ static int lcd_config_probe(struct platform_device *pdev) return -1; } + lcd_driver->res_vsync_irq = NULL; + lcd_driver->res_vsync2_irq = NULL; + lcd_driver->res_vx1_irq = NULL; + /* lcd driver assign */ ret = of_property_read_string(lcd_driver->dev->of_node, "mode", &str); if (ret) { @@ -982,6 +1084,24 @@ static int lcd_config_probe(struct platform_device *pdev) LCDPR("detect lcd_auto_test: %d\n", lcd_driver->lcd_auto_test); } + ret = of_property_read_string_index(lcd_driver->dev->of_node, + "interrupt-names", 0, &str); + if (ret == 0) { + lcd_driver->res_vsync_irq = platform_get_resource(pdev, + IORESOURCE_IRQ, 0); + } + ret = of_property_read_string_index(lcd_driver->dev->of_node, + "interrupt-names", 1, &str); + if (ret == 0) { + if (strcmp(str, "vbyone") == 0) { + lcd_driver->res_vx1_irq = + platform_get_resource(pdev, IORESOURCE_IRQ, 1); + } else if (strcmp(str, "vsync2") == 0) { + lcd_driver->res_vsync2_irq = + platform_get_resource(pdev, IORESOURCE_IRQ, 1); + } + } + lcd_driver->lcd_info = &lcd_vinfo; lcd_driver->lcd_config = &lcd_config_dft; lcd_driver->lcd_test_state = 0; @@ -989,12 +1109,10 @@ static int lcd_config_probe(struct platform_device *pdev) lcd_driver->lcd_mute_state = 0; lcd_driver->lcd_mute_flag = 0; lcd_driver->lcd_resume_type = 1; /* default workqueue */ + lcd_driver->viu_sel = LCD_VIU_SEL_NONE; + lcd_driver->vsync_none_timer_flag = 0; lcd_driver->power_ctrl = lcd_power_ctrl; lcd_driver->module_reset = lcd_module_reset; - lcd_driver->res_vsync_irq = platform_get_resource(pdev, - IORESOURCE_IRQ, 0); - lcd_driver->res_vx1_irq = platform_get_resource(pdev, - IORESOURCE_IRQ, 1); lcd_clk_config_probe(); lcd_config_default(); lcd_init_vout(); @@ -1023,16 +1141,33 @@ static int lcd_config_probe(struct platform_device *pdev) static int lcd_vsync_irq_init(void) { - if (!lcd_driver->res_vsync_irq) { - LCDERR("res_vsync_irq is null\n"); - return -1; + 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 { + LCDPR("request lcd_vsync_irq successful\n"); + } } - 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"); + 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 { + 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; } @@ -1041,6 +1176,16 @@ 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 diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index 9837b1e19d6e..79bc5d841a5e 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -29,6 +29,12 @@ * debug print define * ********************************** */ +#define LCD_DEBUG_LEVEL_NORMAL (1 << 0) +#define LCD_DEBUG_LEVEL_CLK (1 << 1) +#define LCD_DEBUG_LEVEL_VSYNC (1 << 3) + +#define LCD_DEBUG_VSYNC_INTERVAL 60 + /* #define LCD_DEBUG_INFO */ extern unsigned char lcd_debug_print_flag; #define LCDPR(fmt, args...) pr_info("lcd: "fmt"", ## args) @@ -410,6 +416,8 @@ struct lcd_duration_s { #define LCD_MUTE_UPDATE (1 << 4) #define LCD_TEST_UPDATE (1 << 4) + +#define LCD_VIU_SEL_NONE 0 struct aml_lcd_drv_s { char version[20]; struct lcd_data_s *data; @@ -424,6 +432,8 @@ struct aml_lcd_drv_s { unsigned char lcd_test_flag; unsigned char lcd_mute_state; unsigned char lcd_mute_flag; + unsigned char viu_sel; + unsigned char vsync_none_timer_flag; unsigned char clk_gate_state; struct clk *encl_top_gate; @@ -459,6 +469,7 @@ struct aml_lcd_drv_s { struct delayed_work lcd_probe_delayed_work; struct work_struct lcd_resume_work; struct resource *res_vsync_irq; + struct resource *res_vsync2_irq; struct resource *res_vx1_irq; struct mutex power_mutex;