diff --git a/drivers/media/vout/lcd/backlight/lcd_bl.c b/drivers/media/vout/lcd/backlight/lcd_bl.c index 9850a8b84..2454c2a26 100644 --- a/drivers/media/vout/lcd/backlight/lcd_bl.c +++ b/drivers/media/vout/lcd/backlight/lcd_bl.c @@ -960,6 +960,7 @@ void bl_lcd_on_ctrl(struct aml_lcd_drv_s *pdrv) { struct aml_bl_drv_s *bdrv; unsigned long long local_time[2]; + unsigned int delay_ms; if (!pdrv) return; @@ -972,7 +973,14 @@ void bl_lcd_on_ctrl(struct aml_lcd_drv_s *pdrv) if (bdrv->probe_done == 0) return; + if (pdrv->status & LCD_STATUS_BL_PRE_ON) { + bdrv->pre_on_time = local_time[0]; + BLPR("[%d]: %s: pre_on\n", bdrv->index, __func__); + return; + } + if (bdrv->state & BL_STATE_BL_ON) { + bdrv->pre_on_time = 0; BLPR("[%d]: %s already on\n", bdrv->index, __func__); return; } @@ -982,13 +990,24 @@ void bl_lcd_on_ctrl(struct aml_lcd_drv_s *pdrv) bdrv->on_request = 1; /* lcd power on sequence control */ bl_pwm_ctrl_status_set(bdrv, 1); + if (bdrv->pre_on_time) { + local_time[1] = sched_clock(); + delay_ms = lcd_do_div((local_time[1] - bdrv->pre_on_time), 1000000); + bdrv->pre_on_time = 0; + if (delay_ms < bdrv->bconf.power_on_delay) + delay_ms = bdrv->bconf.power_on_delay - delay_ms; + else + delay_ms = 0; + } else { + delay_ms = bdrv->bconf.power_on_delay; + } if (bdrv->bconf.method < BL_CTRL_MAX) { #ifdef BL_POWER_ON_DELAY_WORK - lcd_queue_delayed_on_work(&bdrv->delayed_on_work, - bdrv->bconf.power_on_delay); + lcd_queue_delayed_on_work(&bdrv->delayed_on_work, delay_ms); #else - lcd_delay_ms(bdrv->bconf.power_on_delay); + if (delay_ms) + lcd_delay_ms(delay_ms); bl_on_function(bdrv); #endif } else { @@ -1014,6 +1033,8 @@ void bl_lcd_off_ctrl(struct aml_lcd_drv_s *pdrv) if (bdrv->probe_done == 0) return; + bdrv->pre_on_time = 0; + bdrv->on_request = 0; if (!(bdrv->state & BL_STATE_BL_ON)) { BLPR("[%d]: %s already off\n", bdrv->index, __func__); return; @@ -1021,7 +1042,6 @@ void bl_lcd_off_ctrl(struct aml_lcd_drv_s *pdrv) if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) BLPR("[%d]: %s\n", bdrv->index, __func__); - bdrv->on_request = 0; bdrv->state &= ~BL_STATE_LCD_ON; mutex_lock(&bl_level_mutex); bdrv->state |= BL_STATE_BL_INIT_ON; diff --git a/drivers/media/vout/lcd/lcd_common.h b/drivers/media/vout/lcd/lcd_common.h index 6768a2d13..71e68a25d 100644 --- a/drivers/media/vout/lcd/lcd_common.h +++ b/drivers/media/vout/lcd/lcd_common.h @@ -17,7 +17,8 @@ /* 20250121: initial version*/ /* 20250123: update lcd bootargs transfer by lrm */ /* 20250221: optimize vbyone interrupt handler */ -#define LCD_DRV_VERSION "20250221" +/* 20250304: support lcd_if early on with resume_type control */ +#define LCD_DRV_VERSION "20250304" #define CFMT_RGB565 0x05 #define CFMT_RGB_6bit 0x06 @@ -287,6 +288,7 @@ void lcd_screen_restore(struct aml_lcd_drv_s *pdrv); void lcd_venc_adj_vtotal(struct aml_lcd_drv_s *pdrv, unsigned int vtotal); /* lcd driver */ +void lcd_power_if_early_on(struct aml_lcd_drv_s *pdrv); void lcd_power_screen_black(struct aml_lcd_drv_s *pdrv); void lcd_power_screen_restore(struct aml_lcd_drv_s *pdrv); void lcd_proc_time_clear(struct aml_lcd_drv_s *pdrv); diff --git a/drivers/media/vout/lcd/lcd_config.c b/drivers/media/vout/lcd/lcd_config.c index a44d77a78..b015bdddf 100644 --- a/drivers/media/vout/lcd/lcd_config.c +++ b/drivers/media/vout/lcd/lcd_config.c @@ -343,7 +343,7 @@ int lcd_base_config_load_from_dts(struct aml_lcd_drv_s *pdrv) ret = of_property_read_u32(np, "resume_type", &val); if (ret) - pdrv->resume_type = 1; /* default workqueue */ + pdrv->resume_type = 0x1; /* default workqueue */ else pdrv->resume_type = (unsigned char)val; diff --git a/drivers/media/vout/lcd/lcd_debug.c b/drivers/media/vout/lcd/lcd_debug.c index 230c11b19..3d91e4cee 100644 --- a/drivers/media/vout/lcd/lcd_debug.c +++ b/drivers/media/vout/lcd/lcd_debug.c @@ -454,7 +454,7 @@ static int lcd_info_basic_print(struct aml_lcd_drv_s *pdrv, char *buf, int offse "[%d]: driver version: %s\n" "config_check_glb: %d, config_check_para: 0x%x, config_check_en: %d\n" "panel_type: %s, chip: %d, mode: %s, status: 0x%x\n" - "viu_sel: %d, isr_cnt: %d, resume_type: %d\n" + "viu_sel: %d, isr_cnt: %d, resume_type: 0x%x\n" "fr_auto_flag: 0x%x, fr_mode: %d, fr_duration: %d, frame_rate: %d\n" "fr_auto_policy(global): %d, fr_auto_cus: 0x%x, custom_pinmux: %d\n" "mute_state: %d(real %d), test_flag: 0x%x\n" @@ -1747,8 +1747,10 @@ static ssize_t lcd_debug_resume_show(struct device *dev, struct device_attribute { struct aml_lcd_drv_s *pdrv = dev_get_drvdata(dev); - return sprintf(buf, "lcd resume type: %d(%s)\n", - pdrv->resume_type, pdrv->resume_type ? "workqueue" : "directly"); + return sprintf(buf, "lcd resume type: 0x%x(%s %s)\n", + pdrv->resume_type, + (pdrv->resume_type & (1 << 0)) ? "workqueue" : "directly", + (pdrv->resume_type & (1 << 1)) ? "resume_if_on" : "late_resume_if_on"); } static ssize_t lcd_debug_resume_store(struct device *dev, struct device_attribute *attr, @@ -1758,13 +1760,13 @@ static ssize_t lcd_debug_resume_store(struct device *dev, struct device_attribut struct aml_lcd_drv_s *pdrv = dev_get_drvdata(dev); unsigned int temp = 1; - ret = kstrtouint(buf, 10, &temp); + ret = kstrtouint(buf, 16, &temp); if (ret) { LCDERR("invalid data\n"); return -EINVAL; } pdrv->resume_type = (unsigned char)temp; - LCDPR("set lcd resume flag: %d\n", pdrv->resume_type); + LCDPR("set lcd resume_type: 0x%x\n", pdrv->resume_type); return count; } diff --git a/drivers/media/vout/lcd/lcd_tablet/lcd_tablet.c b/drivers/media/vout/lcd/lcd_tablet/lcd_tablet.c index 6c6ab1de4..18ad19f7f 100644 --- a/drivers/media/vout/lcd/lcd_tablet/lcd_tablet.c +++ b/drivers/media/vout/lcd/lcd_tablet/lcd_tablet.c @@ -999,10 +999,18 @@ static int lcd_resume(void *data) if ((pdrv->status & LCD_STATUS_VMODE_ACTIVE) == 0) return 0; - if (pdrv->status & LCD_STATUS_POWER) + if (pdrv->status & LCD_STATUS_POWER) { + if (pdrv->status & LCD_STATUS_BL_PRE_ON) { + pdrv->status &= ~LCD_STATUS_BL_PRE_ON; +#ifdef CONFIG_AMLOGIC_BACKLIGHT + bl_lcd_on_ctrl(pdrv); +#endif + lcd_power_screen_restore(pdrv); + } return 0; + } - if (pdrv->resume_type) { + if (pdrv->resume_type & (1 << 0)) { lcd_queue_work(&pdrv->late_resume_work); } else { mutex_lock(&lcd_power_mutex); diff --git a/drivers/media/vout/lcd/lcd_tv/lcd_tv.c b/drivers/media/vout/lcd/lcd_tv/lcd_tv.c index e3b5da6af..5faeb4df1 100644 --- a/drivers/media/vout/lcd/lcd_tv/lcd_tv.c +++ b/drivers/media/vout/lcd/lcd_tv/lcd_tv.c @@ -631,6 +631,8 @@ static int lcd_set_current_vmode(enum vmode_e mode, void *data) //workaround for drm resume aml_lcd_notifier_call_chain(LCD_EVENT_PREPARE, (void *)pdrv); pdrv->status |= LCD_STATUS_PREPARE; + + lcd_power_if_early_on(pdrv); } pdrv->status |= LCD_STATUS_VMODE_ACTIVE; LCDPR("[%d]: fixed timing, exit vmode change\n", pdrv->index); @@ -1059,10 +1061,18 @@ static int lcd_resume(void *data) if ((pdrv->status & LCD_STATUS_VMODE_ACTIVE) == 0) return 0; - if (pdrv->status & LCD_STATUS_POWER) + if (pdrv->status & LCD_STATUS_POWER) { + if (pdrv->status & LCD_STATUS_BL_PRE_ON) { + pdrv->status &= ~LCD_STATUS_BL_PRE_ON; +#ifdef CONFIG_AMLOGIC_BACKLIGHT + bl_lcd_on_ctrl(pdrv); +#endif + lcd_power_screen_restore(pdrv); + } return 0; + } - if (pdrv->resume_type) { + if (pdrv->resume_type & (1 << 0)) { lcd_queue_work(&pdrv->late_resume_work); } else { mutex_lock(&lcd_power_mutex); diff --git a/drivers/media/vout/lcd/lcd_vout.c b/drivers/media/vout/lcd/lcd_vout.c index 2ba1a37c4..97ca752fc 100644 --- a/drivers/media/vout/lcd/lcd_vout.c +++ b/drivers/media/vout/lcd/lcd_vout.c @@ -911,6 +911,23 @@ static void lcd_power_if_off(struct aml_lcd_drv_s *pdrv) lcd_power_ctrl(pdrv, 0); } +void lcd_power_if_early_on(struct aml_lcd_drv_s *pdrv) +{ + if ((pdrv->resume_type & (1 << 1)) == 0) + return; + LCDPR("[%d]: %s\n", pdrv->index, __func__); + + if ((pdrv->resume_type & (1 << 0))) { + pdrv->status |= LCD_STATUS_BL_PRE_ON; + lcd_queue_work(&pdrv->late_resume_work); + } else { + LCDPR("[%d]: directly if_early_on\n", pdrv->index); + pdrv->status |= (LCD_STATUS_POWER | LCD_STATUS_BL_PRE_ON); + aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, (void *)pdrv); + lcd_if_enable_retry(pdrv); + } +} + void lcd_power_screen_black(struct aml_lcd_drv_s *pdrv) { unsigned long flags = 0; @@ -949,6 +966,8 @@ void lcd_power_screen_restore(struct aml_lcd_drv_s *pdrv) if (!pdrv || pdrv->probe_done == 0) return; + if ((pdrv->status & LCD_STATUS_BL_PRE_ON)) + return; local_time[0] = sched_clock(); reinit_completion(&pdrv->vsync_done); @@ -2809,13 +2828,17 @@ static int lcd_resume(struct platform_device *pdev) if (!pdrv) return 0; - if ((pdrv->status & LCD_STATUS_VMODE_ACTIVE) == 0) + if ((pdrv->status & LCD_STATUS_VMODE_ACTIVE) == 0) { + if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL) + LCDPR("[%d]: %s: vmode inactive, exit\n", pdrv->index, __func__); return 0; + } mutex_lock(&lcd_power_mutex); LCDPR("[%d]: %s\n", pdrv->index, __func__); aml_lcd_notifier_call_chain(LCD_EVENT_PREPARE, (void *)pdrv); pdrv->status |= LCD_STATUS_PREPARE; + lcd_power_if_early_on(pdrv); LCDPR("[%d]: %s finished\n", pdrv->index, __func__); mutex_unlock(&lcd_power_mutex); diff --git a/include/linux/amlogic/media/vout/lcd/aml_bl.h b/include/linux/amlogic/media/vout/lcd/aml_bl.h index bd1739023..f92edf033 100644 --- a/include/linux/amlogic/media/vout/lcd/aml_bl.h +++ b/include/linux/amlogic/media/vout/lcd/aml_bl.h @@ -239,6 +239,8 @@ struct aml_bl_drv_s { struct pinctrl *pin; unsigned int pinmux_flag; + + unsigned long long pre_on_time; }; struct bl_pwm_init_config_s { diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index 3e075e3de..3de190831 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -788,6 +788,7 @@ struct lcd_resource_s { #define LCD_STATUS_VMODE_ACTIVE BIT(6) //control status #define LCD_STATUS_TCON_RDY BIT(8) +#define LCD_STATUS_BL_PRE_ON BIT(12) #define LCD_VIU_SEL_NONE 0 @@ -888,7 +889,9 @@ struct aml_lcd_drv_s { unsigned char key_valid; unsigned char clk_path; /* 0=hpll, 1=gp0_pll */ unsigned char config_load; - unsigned char resume_type; /* 0=directly, 1=workqueue */ + /*bit[1]: 0=lcd_if late_resume(default), 1=lcd_if resume */ + /*bit[0]: 0=directly, 1=workqueue(default) */ + unsigned char resume_type; unsigned char init_flag; /* 0=none, 1=power on request */ unsigned char auto_test; unsigned char test_state;