lcd: optimize lcd notifier event for power sequence

PD#158197: lcd: optimize lcd notifier event for power sequence

Change-Id: I6b91bf1c2c6e31dfa3133f078d37d32fdce2a5bd
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
This commit is contained in:
Evoke Zhang
2018-01-22 11:37:13 +08:00
committed by Jianxin Pan
parent d636f6ddb9
commit 4b74c61a7e
11 changed files with 380 additions and 434 deletions

View File

@@ -24,11 +24,11 @@
/* 20170505: add a113 support to linux4.9 */
/* 20170905: fix coverity errors */
#define LCD_DRV_VERSION "20171201"
/* 20180122: support txlx, optimize lcd noitfier event */
#define LCD_DRV_VERSION "20180122"
#define VPP_OUT_SATURATE (1 << 0)
extern struct mutex lcd_power_mutex;
extern struct mutex lcd_vout_mutex;
extern unsigned char lcd_resume_flag;
extern int lcd_vout_serve_bypass;

View File

@@ -952,7 +952,7 @@ static void lcd_mute_setting(unsigned char flag)
}
}
static void lcd_test_check(void)
static void lcd_screen_restore(void)
{
unsigned int h_active, video_on_pixel;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
@@ -983,6 +983,11 @@ static void lcd_test_check(void)
}
}
static void lcd_screen_black(void)
{
lcd_mute_setting(1);
}
static void lcd_vinfo_update(void)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
@@ -1057,6 +1062,26 @@ static void lcd_debug_clk_change(unsigned int pclk)
&lcd_drv->lcd_info->mode);
}
static void lcd_power_interface_ctrl(int state)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
mutex_lock(&lcd_drv->power_mutex);
LCDPR("%s: %d\n", __func__, state);
if (state) {
if (lcd_drv->lcd_status & LCD_STATUS_ENCL_ON) {
aml_lcd_notifier_call_chain(
LCD_EVENT_IF_POWER_ON, NULL);
} else {
LCDERR("%s: can't power on when controller is off\n",
__func__);
}
} else {
aml_lcd_notifier_call_chain(LCD_EVENT_IF_POWER_OFF, NULL);
}
mutex_unlock(&lcd_drv->power_mutex);
}
static ssize_t lcd_debug_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
@@ -1254,16 +1279,7 @@ static ssize_t lcd_debug_store(struct class *class,
case 'p': /* power */
ret = sscanf(buf, "power %d", &temp);
if (ret == 1) {
mutex_lock(&lcd_power_mutex);
LCDPR("power: %d\n", temp);
if (temp) {
aml_lcd_notifier_call_chain(
LCD_EVENT_IF_POWER_ON, NULL);
} else {
aml_lcd_notifier_call_chain(
LCD_EVENT_IF_POWER_OFF, NULL);
}
mutex_unlock(&lcd_power_mutex);
lcd_power_interface_ctrl(temp);
} else {
LCDERR("invalid data\n");
return -EINVAL;
@@ -1450,6 +1466,7 @@ static ssize_t lcd_debug_enable_show(struct class *class,
static ssize_t lcd_debug_enable_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
int ret = 0;
unsigned int temp = 1;
@@ -1459,13 +1476,13 @@ static ssize_t lcd_debug_enable_store(struct class *class,
return -EINVAL;
}
if (temp) {
mutex_lock(&lcd_power_mutex);
mutex_lock(&lcd_drv->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
} else {
mutex_lock(&lcd_power_mutex);
mutex_lock(&lcd_drv->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_OFF, NULL);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
}
return count;
@@ -2673,36 +2690,14 @@ static struct class_attribute lcd_phy_debug_class_attrs[] = {
lcd_phy_debug_show, lcd_phy_debug_store),
};
static int lcd_black_screen_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if ((event & LCD_EVENT_BLACK_SCREEN) == 0)
return NOTIFY_DONE;
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_mute_setting(1);
return NOTIFY_OK;
}
static struct notifier_block lcd_black_screen_nb = {
.notifier_call = lcd_black_screen_notifier,
.priority = LCD_PRIORITY_BLACK_SCREEN,
};
int lcd_class_creat(void)
{
int i;
int ret;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
int type;
ret = aml_lcd_notifier_register(&lcd_black_screen_nb);
if (ret)
LCDERR("register lcd_black_screen_notifier failed\n");
lcd_drv->lcd_test_pattern_restore = lcd_test_check;
lcd_drv->lcd_screen_restore = lcd_screen_restore;
lcd_drv->lcd_screen_black = lcd_screen_black;
lcd_drv->lcd_debug_class = class_create(THIS_MODULE, "lcd");
if (IS_ERR(lcd_drv->lcd_debug_class)) {

View File

@@ -873,7 +873,26 @@ void lcd_tablet_driver_init_pre(void)
lcd_clk_set(pconf);
lcd_venc_set(pconf);
lcd_tcon_set(pconf);
lcd_drv->lcd_test_pattern_restore();
lcd_vcbus_write(VENC_INTCTRL, 0x200);
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
}
void lcd_tablet_driver_disable_post(void)
{
lcd_vcbus_write(ENCL_VIDEO_EN, 0); /* disable encl */
lcd_clk_disable();
lcd_clk_gate_switch(0);
#ifdef CONFIG_AMLOGIC_VPU
switch_vpu_mem_pd_vmod(VPU_VENCL, VPU_MEM_POWER_DOWN);
release_vpu_clk_vmod(VPU_VENCL);
#endif
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
}
int lcd_tablet_driver_init(void)
@@ -911,8 +930,6 @@ int lcd_tablet_driver_init(void)
break;
}
lcd_vcbus_write(VENC_INTCTRL, 0x200);
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
@@ -952,88 +969,7 @@ void lcd_tablet_driver_disable(void)
break;
}
lcd_vcbus_write(ENCL_VIDEO_EN, 0); /* disable encl */
lcd_clk_disable();
lcd_clk_gate_switch(0);
#ifdef CONFIG_AMLOGIC_VPU
switch_vpu_mem_pd_vmod(VPU_VENCL, VPU_MEM_POWER_DOWN);
release_vpu_clk_vmod(VPU_VENCL);
#endif
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
}
void lcd_tablet_driver_tiny_enable(void)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
struct lcd_config_s *pconf;
int ret;
pconf = lcd_drv->lcd_config;
ret = lcd_type_supported(pconf);
if (ret)
return;
/* init driver */
switch (pconf->lcd_basic.lcd_type) {
case LCD_TTL:
lcd_ttl_control_set(pconf);
lcd_ttl_pinmux_set(1);
break;
case LCD_LVDS:
lcd_lvds_control_set(pconf);
lcd_lvds_phy_set(pconf, 1);
break;
case LCD_VBYONE:
lcd_vbyone_pinmux_set(1);
lcd_vbyone_control_set(pconf);
lcd_vx1_wait_hpd();
lcd_vbyone_phy_set(pconf, 1);
lcd_tablet_vbyone_wait_stable();
case LCD_MIPI:
lcd_mipi_phy_set(pconf, 1);
lcd_mipi_control_set(pconf, 1);
break;
default:
break;
}
LCDPR("enable driver\n");
}
void lcd_tablet_driver_tiny_disable(void)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
struct lcd_config_s *pconf;
int ret;
LCDPR("disable driver\n");
pconf = lcd_drv->lcd_config;
ret = lcd_type_supported(pconf);
if (ret)
return;
switch (pconf->lcd_basic.lcd_type) {
case LCD_TTL:
lcd_ttl_pinmux_set(0);
break;
case LCD_LVDS:
lcd_lvds_phy_set(pconf, 0);
lcd_lvds_disable();
break;
case LCD_VBYONE:
lcd_vbyone_phy_set(pconf, 0);
lcd_vbyone_pinmux_set(0);
lcd_vbyone_disable();
case LCD_MIPI:
mipi_dsi_link_off(pconf);
lcd_mipi_phy_set(pconf, 0);
lcd_mipi_control_set(pconf, 0);
break;
default:
break;
}
}

View File

@@ -293,11 +293,13 @@ static int lcd_get_vframe_rate_policy(void)
#ifdef CONFIG_PM
static int lcd_suspend(void)
{
mutex_lock(&lcd_power_mutex);
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
mutex_lock(&lcd_drv->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_OFF, NULL);
lcd_resume_flag = 0;
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
return 0;
}
@@ -313,20 +315,20 @@ static int lcd_resume(void)
queue_work(lcd_drv->workqueue,
&(lcd_drv->lcd_resume_work));
} else {
mutex_lock(&lcd_drv->power_mutex);
LCDPR("Warning: no lcd workqueue\n");
mutex_lock(&lcd_power_mutex);
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
}
} else {
mutex_lock(&lcd_drv->power_mutex);
LCDPR("directly lcd late resume\n");
mutex_lock(&lcd_power_mutex);
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
}
return 0;
@@ -1292,10 +1294,9 @@ int lcd_tablet_probe(struct device *dev)
lcd_drv->version = LCD_DRV_VERSION;
lcd_drv->vout_server_init = lcd_tablet_vout_server_init;
lcd_drv->driver_init_pre = lcd_tablet_driver_init_pre;
lcd_drv->driver_disable_post = lcd_tablet_driver_disable_post;
lcd_drv->driver_init = lcd_tablet_driver_init;
lcd_drv->driver_disable = lcd_tablet_driver_disable;
lcd_drv->driver_tiny_enable = lcd_tablet_driver_tiny_enable;
lcd_drv->driver_tiny_disable = lcd_tablet_driver_tiny_disable;
lcd_get_config(lcd_drv->lcd_config, dev);

View File

@@ -21,9 +21,8 @@
extern void lcd_tablet_config_update(struct lcd_config_s *pconf);
extern void lcd_tablet_config_post_update(struct lcd_config_s *pconf);
extern void lcd_tablet_driver_init_pre(void);
extern void lcd_tablet_driver_disable_post(void);
extern int lcd_tablet_driver_init(void);
extern void lcd_tablet_driver_disable(void);
extern void lcd_tablet_driver_tiny_enable(void);
extern void lcd_tablet_driver_tiny_disable(void);
#endif

View File

@@ -837,10 +837,7 @@ static void lcd_vx1_timeout_reset(unsigned long data)
return;
LCDPR("%s\n", __func__);
if (vx1_timeout_reset_flag == 1)
lcd_drv->module_reset();
else
lcd_drv->module_tiny_reset();
lcd_drv->module_reset();
if (lcd_drv->lcd_config->lcd_control.vbyone_config->intr_en)
lcd_vx1_hold_reset();
vx1_timeout_reset_flag = 0;
@@ -855,7 +852,7 @@ static irqreturn_t lcd_vbyone_vsync_isr(int irq, void *dev_id)
struct vbyone_config_s *vx1_conf;
vx1_conf = lcd_drv->lcd_config->lcd_control.vbyone_config;
if (lcd_drv->lcd_status == 0)
if ((lcd_drv->lcd_status & LCD_STATUS_IF_ON) == 0)
return IRQ_HANDLED;
if (lcd_vcbus_read(VBO_STATUS_L) & 0x40) /* hpd detect */
return IRQ_HANDLED;
@@ -1240,7 +1237,26 @@ void lcd_tv_driver_init_pre(void)
lcd_clk_set(pconf);
lcd_venc_set(pconf);
lcd_tcon_set(pconf);
lcd_drv->lcd_test_pattern_restore();
lcd_vcbus_write(VENC_INTCTRL, 0x200);
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
}
void lcd_tv_driver_disable_post(void)
{
lcd_vcbus_write(ENCL_VIDEO_EN, 0); /* disable encl */
lcd_clk_disable();
lcd_clk_gate_switch(0);
#ifdef CONFIG_AMLOGIC_VPU
switch_vpu_mem_pd_vmod(VPU_VENCL, VPU_MEM_POWER_DOWN);
release_vpu_clk_vmod(VPU_VENCL);
#endif
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
}
int lcd_tv_driver_init(void)
@@ -1266,15 +1282,13 @@ int lcd_tv_driver_init(void)
lcd_vbyone_phy_set(pconf, 1);
lcd_vx1_intr_request = 1;
queue_delayed_work(lcd_drv->workqueue,
&lcd_drv->lcd_vx1_delayed_work,
msecs_to_jiffies(LCD_VX1_WAIT_STABLE_DELAY));
&lcd_drv->lcd_vx1_delayed_work,
msecs_to_jiffies(LCD_VX1_WAIT_STABLE_DELAY));
break;
default:
break;
}
lcd_vcbus_write(VENC_INTCTRL, 0x200);
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
return 0;
@@ -1310,15 +1324,6 @@ void lcd_tv_driver_disable(void)
break;
}
lcd_vcbus_write(ENCL_VIDEO_EN, 0); /* disable encl */
lcd_clk_disable();
lcd_clk_gate_switch(0);
#ifdef CONFIG_AMLOGIC_VPU
switch_vpu_mem_pd_vmod(VPU_VENCL, VPU_MEM_POWER_DOWN);
release_vpu_clk_vmod(VPU_VENCL);
#endif
if (lcd_debug_print_flag)
LCDPR("%s finished\n", __func__);
}
@@ -1341,18 +1346,11 @@ int lcd_tv_driver_change(void)
request_vpu_clk_vmod(pconf->lcd_timing.lcd_clk, VPU_VENCL);
#endif
if (lcd_drv->lcd_status == 0) {
/* only change parameters when panel is off */
switch (pconf->lcd_timing.clk_change) {
case LCD_CLK_PLL_CHANGE:
lcd_clk_generate_parameter(pconf);
break;
default:
break;
if (lcd_drv->lcd_status & LCD_STATUS_ENCL_ON) {
if (pconf->lcd_basic.lcd_type == LCD_VBYONE) {
if (lcd_drv->lcd_status & LCD_STATUS_IF_ON)
lcd_vbyone_interrupt_enable(0);
}
} else {
if (pconf->lcd_basic.lcd_type == LCD_VBYONE)
lcd_vbyone_interrupt_enable(0);
switch (pconf->lcd_timing.clk_change) {
case LCD_CLK_PLL_CHANGE:
@@ -1367,8 +1365,19 @@ int lcd_tv_driver_change(void)
}
lcd_venc_change(pconf);
if (pconf->lcd_basic.lcd_type == LCD_VBYONE)
lcd_vbyone_wait_stable();
if (pconf->lcd_basic.lcd_type == LCD_VBYONE) {
if (lcd_drv->lcd_status & LCD_STATUS_IF_ON)
lcd_vbyone_wait_stable();
}
} else {
/* only change parameters when panel is off */
switch (pconf->lcd_timing.clk_change) {
case LCD_CLK_PLL_CHANGE:
lcd_clk_generate_parameter(pconf);
break;
default:
break;
}
}
if (lcd_debug_print_flag)
@@ -1376,69 +1385,10 @@ int lcd_tv_driver_change(void)
return 0;
}
void lcd_tv_driver_tiny_enable(void)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
struct lcd_config_s *pconf;
int ret;
pconf = lcd_drv->lcd_config;
ret = lcd_type_supported(pconf);
if (ret)
return;
switch (pconf->lcd_basic.lcd_type) {
case LCD_LVDS:
lcd_lvds_control_set(pconf);
lcd_lvds_phy_set(pconf, 1);
break;
case LCD_VBYONE:
lcd_vbyone_pinmux_set(1);
lcd_vbyone_control_set(pconf);
lcd_vbyone_wait_hpd(pconf);
lcd_vbyone_phy_set(pconf, 1);
lcd_vbyone_power_on_wait_stable(pconf);
break;
default:
break;
}
LCDPR("enable driver\n");
}
void lcd_tv_driver_tiny_disable(void)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
struct lcd_config_s *pconf;
int ret;
LCDPR("disable driver\n");
pconf = lcd_drv->lcd_config;
ret = lcd_type_supported(pconf);
if (ret)
return;
switch (pconf->lcd_basic.lcd_type) {
case LCD_LVDS:
lcd_lvds_phy_set(pconf, 0);
lcd_lvds_disable();
break;
case LCD_VBYONE:
lcd_vbyone_interrupt_enable(0);
lcd_vbyone_phy_set(pconf, 0);
lcd_vbyone_pinmux_set(0);
lcd_vbyone_disable();
break;
default:
break;
}
}
#define VBYONE_IRQF IRQF_SHARED /* IRQF_DISABLED */ /* IRQF_SHARED */
int lcd_vbyone_interrupt_up(void)
{
int ret = 0;
unsigned int viu_vsync_irq = 0, venc_vx1_irq = 0;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
@@ -1450,42 +1400,39 @@ int lcd_vbyone_interrupt_up(void)
lcd_vx1_intr_request = 0;
lcd_encl_clk_err_cnt = 0;
tasklet_init(&lcd_vx1_reset_tasklet, lcd_vx1_timeout_reset,
123);
tasklet_init(&lcd_vx1_reset_tasklet, lcd_vx1_timeout_reset, 123);
INIT_DELAYED_WORK(&lcd_drv->lcd_vx1_delayed_work,
lcd_vx1_wait_stable_delayed);
if (!lcd_drv->res_vsync_irq) {
ret = -ENODEV;
goto err;
} else {
viu_vsync_irq = lcd_drv->res_vsync_irq->start;
LCDPR("viu_vsync_irq: %d\n", viu_vsync_irq);
LCDERR("res_vsync_irq is null\n");
return -1;
}
viu_vsync_irq = lcd_drv->res_vsync_irq->start;
LCDPR("viu_vsync_irq: %d\n", viu_vsync_irq);
if (request_irq(viu_vsync_irq, lcd_vbyone_vsync_isr,
IRQF_SHARED, "vbyone_vsync", (void *)"vbyone_vsync"))
LCDERR("can't request viu_vsync_irq\n");
else {
if (lcd_debug_print_flag)
LCDPR("request viu_vsync_irq successful\n");
}
if (request_irq(viu_vsync_irq, lcd_vbyone_vsync_isr,
IRQF_SHARED, "vbyone_vsync", (void *)"vbyone_vsync"))
LCDERR("can't request viu_vsync_irq\n");
else {
if (lcd_debug_print_flag)
LCDPR("request viu_vsync_irq successful\n");
}
if (!lcd_drv->res_vx1_irq) {
ret = -ENODEV;
goto err;
} else {
venc_vx1_irq = lcd_drv->res_vx1_irq->start;
LCDPR("venc_vx1_irq: %d\n", venc_vx1_irq);
LCDERR("res_vx1_irq is null\n");
return -1;
}
venc_vx1_irq = lcd_drv->res_vx1_irq->start;
LCDPR("venc_vx1_irq: %d\n", venc_vx1_irq);
if (request_irq(venc_vx1_irq, lcd_vbyone_interrupt_handler, 0,
"vbyone", (void *)"vbyone"))
LCDERR("can't request venc_vx1_irq\n");
else {
if (lcd_debug_print_flag)
LCDPR("request venc_vx1_irq successful\n");
}
if (request_irq(venc_vx1_irq, lcd_vbyone_interrupt_handler, 0,
"vbyone", (void *)"vbyone"))
LCDERR("can't request venc_vx1_irq\n");
else {
if (lcd_debug_print_flag)
LCDPR("request venc_vx1_irq successful\n");
}
lcd_vx1_intr_request = 1;
@@ -1500,10 +1447,6 @@ int lcd_vbyone_interrupt_up(void)
LCDPR("add vbyone hpll timer handler\n");
return 0;
err:
return -ENODEV;
}
void lcd_vbyone_interrupt_down(void)

View File

@@ -521,11 +521,13 @@ static int lcd_get_vframe_rate_policy(void)
#ifdef CONFIG_PM
static int lcd_suspend(void)
{
mutex_lock(&lcd_power_mutex);
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
mutex_lock(&lcd_drv->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_OFF, NULL);
lcd_resume_flag = 0;
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
return 0;
}
@@ -541,20 +543,20 @@ static int lcd_resume(void)
queue_work(lcd_drv->workqueue,
&(lcd_drv->lcd_resume_work));
} else {
mutex_lock(&lcd_drv->power_mutex);
LCDPR("Warning: no lcd workqueue\n");
mutex_lock(&lcd_power_mutex);
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
}
} else {
mutex_lock(&lcd_drv->power_mutex);
LCDPR("directly lcd late resume\n");
mutex_lock(&lcd_power_mutex);
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_drv->power_mutex);
}
return 0;
@@ -1413,11 +1415,10 @@ int lcd_tv_probe(struct device *dev)
lcd_drv->version = LCD_DRV_VERSION;
lcd_drv->vout_server_init = lcd_tv_vout_server_init;
lcd_drv->driver_init_pre = lcd_tv_driver_init_pre;
lcd_drv->driver_disable_post = lcd_tv_driver_disable_post;
lcd_drv->driver_init = lcd_tv_driver_init;
lcd_drv->driver_disable = lcd_tv_driver_disable;
lcd_drv->driver_change = lcd_tv_driver_change;
lcd_drv->driver_tiny_enable = lcd_tv_driver_tiny_enable;
lcd_drv->driver_tiny_disable = lcd_tv_driver_tiny_disable;
lcd_get_config(lcd_drv->lcd_config, dev);

View File

@@ -21,11 +21,10 @@
extern void lcd_tv_config_update(struct lcd_config_s *pconf);
extern void lcd_tv_driver_init_pre(void);
extern void lcd_tv_driver_disable_post(void);
extern int lcd_tv_driver_init(void);
extern void lcd_tv_driver_disable(void);
extern int lcd_tv_driver_change(void);
extern void lcd_tv_driver_tiny_enable(void);
extern void lcd_tv_driver_tiny_disable(void);
extern void lcd_vbyone_wait_stable(void);
extern int lcd_vbyone_interrupt_up(void);

View File

@@ -55,7 +55,6 @@ unsigned char lcd_debug_print_flag;
unsigned char lcd_resume_flag;
static struct aml_lcd_drv_s *lcd_driver;
struct mutex lcd_power_mutex;
struct mutex lcd_vout_mutex;
int lcd_vout_serve_bypass;
@@ -206,76 +205,6 @@ struct aml_lcd_drv_s *aml_lcd_get_driver(void)
}
/* ********************************************************* */
static void lcd_power_tiny_ctrl(int status)
{
struct lcd_power_ctrl_s *lcd_power = lcd_driver->lcd_config->lcd_power;
struct lcd_power_step_s *power_step;
#ifdef CONFIG_AMLOGIC_LCD_EXTERN
struct aml_lcd_extern_driver_s *ext_drv;
#endif
int i, index;
LCDPR("%s: %d\n", __func__, status);
i = 0;
while (i < LCD_PWR_STEP_MAX) {
if (status)
power_step = &lcd_power->power_on_step[i];
else
power_step = &lcd_power->power_off_step[i];
if (power_step->type >= LCD_POWER_TYPE_MAX)
break;
if (lcd_debug_print_flag) {
LCDPR("power_tiny_ctrl: %d, step %d\n", status, i);
LCDPR("type=%d, index=%d, value=%d, delay=%d\n",
power_step->type, power_step->index,
power_step->value, power_step->delay);
}
switch (power_step->type) {
case LCD_POWER_TYPE_CPU:
index = power_step->index;
lcd_cpu_gpio_set(index, power_step->value);
break;
case LCD_POWER_TYPE_PMU:
LCDPR("to do\n");
break;
case LCD_POWER_TYPE_SIGNAL:
if (status)
lcd_driver->driver_tiny_enable();
else
lcd_driver->driver_tiny_disable();
break;
#ifdef CONFIG_AMLOGIC_LCD_EXTERN
case LCD_POWER_TYPE_EXTERN:
index = power_step->index;
ext_drv = aml_lcd_extern_get_driver(index);
if (ext_drv) {
if (status) {
if (ext_drv->power_on)
ext_drv->power_on();
else
LCDERR("no ext power on\n");
} else {
if (ext_drv->power_off)
ext_drv->power_off();
else
LCDERR("no ext power off\n");
}
}
break;
#endif
default:
break;
}
if (power_step->delay)
mdelay(power_step->delay);
i++;
}
if (lcd_debug_print_flag)
LCDPR("%s: %d finished\n", __func__, status);
}
static void lcd_power_ctrl(int status)
{
struct lcd_power_ctrl_s *lcd_power = lcd_driver->lcd_config->lcd_power;
@@ -347,54 +276,77 @@ static void lcd_power_ctrl(int status)
LCDPR("%s: %d finished\n", __func__, status);
}
static void lcd_module_enable(void)
static void lcd_power_encl_on(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->driver_init_pre();
lcd_driver->lcd_status |= LCD_STATUS_ENCL_ON;
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_power_encl_off(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_status &= ~LCD_STATUS_ENCL_ON;
lcd_driver->driver_disable_post();
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_power_if_on(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->power_ctrl(1);
lcd_driver->lcd_status = 1;
lcd_driver->lcd_status |= LCD_STATUS_IF_ON;
lcd_driver->lcd_config->change_flag = 0;
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_module_disable(void)
static void lcd_power_if_off(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_status = 0;
lcd_driver->lcd_status &= ~LCD_STATUS_IF_ON;
lcd_driver->power_ctrl(0);
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_power_screen_black(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_screen_black();
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_power_screen_restore(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_screen_restore();
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_module_reset(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_status = 0;
lcd_driver->lcd_status &= ~LCD_STATUS_ON;
lcd_driver->power_ctrl(0);
msleep(500);
lcd_driver->driver_init_pre();
lcd_driver->power_ctrl(1);
lcd_driver->lcd_status = 1;
lcd_driver->lcd_config->change_flag = 0;
mutex_unlock(&lcd_vout_mutex);
}
static void lcd_module_tiny_reset(void)
{
mutex_lock(&lcd_vout_mutex);
lcd_driver->lcd_status = 0;
lcd_power_tiny_ctrl(0);
mdelay(500);
lcd_power_tiny_ctrl(1);
lcd_driver->lcd_status = 1;
lcd_driver->lcd_status |= LCD_STATUS_ON;
lcd_driver->lcd_config->change_flag = 0;
mutex_unlock(&lcd_vout_mutex);
@@ -402,60 +354,129 @@ static void lcd_module_tiny_reset(void)
static void lcd_resume_work(struct work_struct *p_work)
{
mutex_lock(&lcd_power_mutex);
mutex_lock(&lcd_driver->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_driver->power_mutex);
}
/* ****************************************
* lcd notify
* ****************************************
*/
static int lcd_power_notifier(struct notifier_block *nb,
static int lcd_power_encl_on_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if (event & LCD_EVENT_LCD_ON) {
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_module_enable();
} else if (event & LCD_EVENT_LCD_OFF) {
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_module_disable();
} else {
if ((event & LCD_EVENT_ENCL_ON) == 0)
return NOTIFY_DONE;
}
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_power_encl_on();
return NOTIFY_OK;
}
static struct notifier_block lcd_power_nb = {
.notifier_call = lcd_power_notifier,
.priority = LCD_PRIORITY_POWER_LCD,
static struct notifier_block lcd_power_encl_on_nb = {
.notifier_call = lcd_power_encl_on_notifier,
.priority = LCD_PRIORITY_POWER_ENCL_ON,
};
static int lcd_interface_notifier(struct notifier_block *nb,
static int lcd_power_encl_off_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if (event & LCD_EVENT_IF_ON) {
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_driver->power_tiny_ctrl(1);
} else if (event & LCD_EVENT_IF_OFF) {
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_driver->power_tiny_ctrl(0);
} else {
if ((event & LCD_EVENT_ENCL_OFF) == 0)
return NOTIFY_DONE;
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_power_encl_off();
return NOTIFY_OK;
}
static struct notifier_block lcd_power_encl_off_nb = {
.notifier_call = lcd_power_encl_off_notifier,
.priority = LCD_PRIORITY_POWER_ENCL_OFF,
};
static int lcd_power_if_on_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if ((event & LCD_EVENT_IF_ON) == 0)
return NOTIFY_DONE;
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
if (lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) {
lcd_power_if_on();
} else {
LCDERR("%s: can't power on when controller is off\n",
__func__);
return NOTIFY_DONE;
}
return NOTIFY_OK;
}
static struct notifier_block lcd_interface_nb = {
.notifier_call = lcd_interface_notifier,
.priority = LCD_PRIORITY_POWER_LCD,
static struct notifier_block lcd_power_if_on_nb = {
.notifier_call = lcd_power_if_on_notifier,
.priority = LCD_PRIORITY_POWER_IF_ON,
};
static int lcd_power_if_off_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if ((event & LCD_EVENT_IF_OFF) == 0)
return NOTIFY_DONE;
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_power_if_off();
return NOTIFY_OK;
}
static struct notifier_block lcd_power_if_off_nb = {
.notifier_call = lcd_power_if_off_notifier,
.priority = LCD_PRIORITY_POWER_IF_OFF,
};
static int lcd_power_screen_black_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if ((event & LCD_EVENT_SCREEN_BLACK) == 0)
return NOTIFY_DONE;
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_power_screen_black();
return NOTIFY_OK;
}
static struct notifier_block lcd_power_screen_black_nb = {
.notifier_call = lcd_power_screen_black_notifier,
.priority = LCD_PRIORITY_SCREEN_BLACK,
};
static int lcd_power_screen_restore_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
if ((event & LCD_EVENT_SCREEN_RESTORE) == 0)
return NOTIFY_DONE;
if (lcd_debug_print_flag)
LCDPR("%s: 0x%lx\n", __func__, event);
lcd_power_screen_restore();
return NOTIFY_OK;
}
static struct notifier_block lcd_power_screen_restore_nb = {
.notifier_call = lcd_power_screen_restore_notifier,
.priority = LCD_PRIORITY_SCREEN_RESTORE,
};
static int lcd_bl_select_notifier(struct notifier_block *nb,
@@ -476,6 +497,48 @@ static int lcd_bl_select_notifier(struct notifier_block *nb,
static struct notifier_block lcd_bl_select_nb = {
.notifier_call = lcd_bl_select_notifier,
};
static int lcd_notifier_register(void)
{
int ret = 0;
ret = aml_lcd_notifier_register(&lcd_bl_select_nb);
if (ret)
LCDERR("register aml_bl_select_notifier failed\n");
ret = aml_lcd_notifier_register(&lcd_power_encl_on_nb);
if (ret)
LCDERR("register lcd_power_encl_on_nb failed\n");
ret = aml_lcd_notifier_register(&lcd_power_encl_off_nb);
if (ret)
LCDERR("register lcd_power_encl_off_nb failed\n");
ret = aml_lcd_notifier_register(&lcd_power_if_on_nb);
if (ret)
LCDERR("register lcd_power_if_on_nb failed\n");
ret = aml_lcd_notifier_register(&lcd_power_if_off_nb);
if (ret)
LCDERR("register lcd_power_if_off_nb failed\n");
ret = aml_lcd_notifier_register(&lcd_power_screen_black_nb);
if (ret)
LCDERR("register lcd_power_screen_black_nb failed\n");
ret = aml_lcd_notifier_register(&lcd_power_screen_restore_nb);
if (ret)
LCDERR("register lcd_power_screen_restore_nb failed\n");
return 0;
}
static void lcd_notifier_unregister(void)
{
aml_lcd_notifier_unregister(&lcd_power_screen_restore_nb);
aml_lcd_notifier_unregister(&lcd_power_screen_black_nb);
aml_lcd_notifier_unregister(&lcd_power_if_off_nb);
aml_lcd_notifier_unregister(&lcd_power_if_on_nb);
aml_lcd_notifier_unregister(&lcd_power_encl_off_nb);
aml_lcd_notifier_unregister(&lcd_power_encl_on_nb);
aml_lcd_notifier_unregister(&lcd_bl_select_nb);
}
/* **************************************** */
/* ************************************************************* */
@@ -656,8 +719,6 @@ static void lcd_init_vout(void)
static int lcd_mode_probe(struct device *dev)
{
int ret;
switch (lcd_driver->lcd_mode) {
#ifdef CONFIG_AMLOGIC_LCD_TV
case LCD_MODE_TV:
@@ -677,15 +738,7 @@ static int lcd_mode_probe(struct device *dev)
lcd_class_creat();
lcd_fops_create();
ret = aml_lcd_notifier_register(&lcd_interface_nb);
if (ret)
LCDERR("register aml_bl_select_notifier failed\n");
ret = aml_lcd_notifier_register(&lcd_bl_select_nb);
if (ret)
LCDERR("register aml_bl_select_notifier failed\n");
ret = aml_lcd_notifier_register(&lcd_power_nb);
if (ret)
LCDPR("register lcd_power_notifier failed\n");
lcd_notifier_register();
/* add notifier for video sync_duration info refresh */
vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE,
@@ -696,6 +749,8 @@ static int lcd_mode_probe(struct device *dev)
static int lcd_mode_remove(struct device *dev)
{
lcd_notifier_unregister();
switch (lcd_driver->lcd_mode) {
#ifdef CONFIG_AMLOGIC_LCD_TV
case LCD_MODE_TV:
@@ -748,7 +803,7 @@ static void lcd_config_default(void)
pconf->lcd_basic.v_active = lcd_vcbus_read(ENCL_VIDEO_VAVON_ELINE)
- lcd_vcbus_read(ENCL_VIDEO_VAVON_BLINE) + 1;
if (lcd_vcbus_read(ENCL_VIDEO_EN)) {
lcd_driver->lcd_status = 1;
lcd_driver->lcd_status = LCD_STATUS_ON;
lcd_resume_flag = 1;
} else {
lcd_driver->lcd_status = 0;
@@ -803,8 +858,6 @@ static int lcd_config_probe(struct platform_device *pdev)
lcd_driver->lcd_resume_type = 1; /* default workqueue */
lcd_driver->power_ctrl = lcd_power_ctrl;
lcd_driver->module_reset = lcd_module_reset;
lcd_driver->power_tiny_ctrl = lcd_power_tiny_ctrl;
lcd_driver->module_tiny_reset = lcd_module_tiny_reset;
lcd_driver->res_vsync_irq = platform_get_resource(pdev,
IORESOURCE_IRQ, 0);
lcd_driver->res_vx1_irq = platform_get_resource(pdev,
@@ -924,7 +977,7 @@ static int lcd_probe(struct platform_device *pdev)
lcd_driver->data->chip_name);
mutex_init(&lcd_vout_mutex);
mutex_init(&lcd_power_mutex);
mutex_init(&lcd_driver->power_mutex);
lcd_vout_serve_bypass = 0;
/* init workqueue */
@@ -953,10 +1006,6 @@ static int lcd_remove(struct platform_device *pdev)
destroy_workqueue(lcd_driver->workqueue);
if (lcd_driver) {
aml_lcd_notifier_unregister(&lcd_power_nb);
aml_lcd_notifier_unregister(&lcd_bl_select_nb);
aml_lcd_notifier_unregister(&lcd_interface_nb);
lcd_fops_remove();
lcd_class_remove();
lcd_clk_config_remove();
@@ -978,19 +1027,19 @@ static int lcd_resume(struct platform_device *pdev)
queue_work(lcd_driver->workqueue,
&(lcd_driver->lcd_resume_work));
} else {
mutex_lock(&lcd_driver->power_mutex);
LCDPR("Warning: no lcd workqueue\n");
mutex_lock(&lcd_power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_driver->power_mutex);
}
} else {
mutex_lock(&lcd_driver->power_mutex);
LCDPR("directly lcd resume\n");
mutex_lock(&lcd_power_mutex);
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_driver->power_mutex);
}
return 0;
@@ -998,13 +1047,13 @@ static int lcd_resume(struct platform_device *pdev)
static int lcd_suspend(struct platform_device *pdev, pm_message_t state)
{
mutex_lock(&lcd_power_mutex);
mutex_lock(&lcd_driver->power_mutex);
if (lcd_driver->lcd_status) {
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_OFF, NULL);
lcd_resume_flag = 0;
LCDPR("%s finished\n", __func__);
}
mutex_unlock(&lcd_power_mutex);
mutex_unlock(&lcd_driver->power_mutex);
return 0;
}

View File

@@ -20,27 +20,45 @@
#include <linux/notifier.h>
#define LCD_PRIORITY_INIT_CONFIG 4
#define LCD_PRIORITY_INIT_VOUT 3
#define LCD_PRIORITY_INIT_CONFIG 12
#define LCD_PRIORITY_INIT_VOUT 11
#define LCD_PRIORITY_BLACK_SCREEN 3
#define LCD_PRIORITY_POWER_BL_OFF 2
#define LCD_PRIORITY_POWER_LCD 1
#define LCD_PRIORITY_POWER_BL_ON 0
#define LCD_PRIORITY_SCREEN_BLACK 7
#define LCD_PRIORITY_POWER_BL_OFF 6
#define LCD_PRIORITY_POWER_IF_OFF 5
#define LCD_PRIORITY_POWER_ENCL_OFF 4
#define LCD_PRIORITY_POWER_ENCL_ON 3
#define LCD_PRIORITY_POWER_IF_ON 2
#define LCD_PRIORITY_POWER_BL_ON 1
#define LCD_PRIORITY_SCREEN_RESTORE 0
#define LCD_EVENT_BL_ON (1 << 0)
#define LCD_EVENT_LCD_ON (1 << 1)
#define LCD_EVENT_IF_ON (1 << 2)
#define LCD_EVENT_POWER_ON (LCD_EVENT_BL_ON | LCD_EVENT_LCD_ON)
#define LCD_EVENT_IF_POWER_ON (LCD_EVENT_BL_ON | LCD_EVENT_IF_ON)
#define LCD_EVENT_BLACK_SCREEN (1 << 3)
#define LCD_EVENT_BL_OFF (1 << 4)
#define LCD_EVENT_LCD_OFF (1 << 5)
#define LCD_EVENT_IF_OFF (1 << 6)
#define LCD_EVENT_POWER_OFF (LCD_EVENT_BL_OFF | LCD_EVENT_LCD_OFF |\
LCD_EVENT_BLACK_SCREEN)
#define LCD_EVENT_IF_POWER_OFF (LCD_EVENT_BL_OFF | LCD_EVENT_IF_OFF |\
LCD_EVENT_BLACK_SCREEN)
/* orignal event */
#define LCD_EVENT_SCREEN_BLACK (1 << 0)
#define LCD_EVENT_BL_OFF (1 << 1)
#define LCD_EVENT_IF_OFF (1 << 2)
#define LCD_EVENT_ENCL_OFF (1 << 3)
#define LCD_EVENT_ENCL_ON (1 << 4)
#define LCD_EVENT_IF_ON (1 << 5)
#define LCD_EVENT_BL_ON (1 << 6)
#define LCD_EVENT_SCREEN_RESTORE (1 << 7)
/* combined event */
#define LCD_EVENT_POWER_ON (LCD_EVENT_BL_ON | LCD_EVENT_IF_ON | \
LCD_EVENT_ENCL_ON | LCD_EVENT_SCREEN_RESTORE)
#define LCD_EVENT_IF_POWER_ON (LCD_EVENT_IF_ON | LCD_EVENT_BL_ON | \
LCD_EVENT_SCREEN_RESTORE)
#define LCD_EVENT_POWER_OFF (LCD_EVENT_SCREEN_BLACK | \
LCD_EVENT_BL_OFF | LCD_EVENT_IF_OFF | \
LCD_EVENT_ENCL_OFF)
#define LCD_EVENT_IF_POWER_OFF (LCD_EVENT_SCREEN_BLACK | \
LCD_EVENT_BL_OFF | LCD_EVENT_IF_OFF)
#define LCD_EVENT_PREPARE (LCD_EVENT_ENCL_ON)
#define LCD_EVENT_ENABLE (LCD_EVENT_IF_ON | LCD_EVENT_BL_ON | \
LCD_EVENT_SCREEN_RESTORE)
#define LCD_EVENT_DISABLE (LCD_EVENT_SCREEN_BLACK | \
LCD_EVENT_BL_OFF | LCD_EVENT_IF_OFF)
#define LCD_EVENT_UNPREPARE (LCD_EVENT_ENCL_OFF)
/* lcd backlight index select */
#define LCD_EVENT_BACKLIGHT_SEL (1 << 8)

View File

@@ -396,6 +396,10 @@ struct lcd_duration_s {
unsigned int duration_den;
};
#define LCD_STATUS_IF_ON (1 << 0)
#define LCD_STATUS_ENCL_ON (1 << 1)
#define LCD_STATUS_ON (LCD_STATUS_IF_ON | LCD_STATUS_ENCL_ON)
struct aml_lcd_drv_s {
char *version;
struct lcd_data_s *data;
@@ -426,15 +430,14 @@ struct aml_lcd_drv_s {
void (*vout_server_init)(void);
void (*driver_init_pre)(void);
void (*driver_disable_post)(void);
int (*driver_init)(void);
void (*driver_disable)(void);
int (*driver_change)(void);
void (*module_reset)(void);
void (*power_tiny_ctrl)(int status);
void (*driver_tiny_enable)(void);
void (*driver_tiny_disable)(void);
void (*module_tiny_reset)(void);
void (*lcd_test_pattern_restore)(void);
void (*lcd_screen_black)(void);
void (*lcd_screen_restore)(void);
void (*power_ctrl)(int status);
struct workqueue_struct *workqueue;
@@ -443,6 +446,8 @@ struct aml_lcd_drv_s {
struct work_struct lcd_resume_work;
struct resource *res_vsync_irq;
struct resource *res_vx1_irq;
struct mutex power_mutex;
};
extern struct aml_lcd_drv_s *aml_lcd_get_driver(void);