lcd: add retry flow to ensure power on state

PD#166330: mipi panel status is incorrect sometimes when lcd enable

Change-Id: Iace4963e576752208815d672befa4e215f860097
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
This commit is contained in:
Evoke Zhang
2018-05-14 20:24:25 +08:00
committed by Yixun Lan
parent 556215ab62
commit f790c9bed5
9 changed files with 114 additions and 40 deletions

View File

@@ -255,6 +255,7 @@ static void am_lcd_encoder_enable(struct drm_encoder *encoder)
{
enum vmode_e vmode = get_current_vmode();
struct am_drm_lcd_s *lcd = encoder_to_lcd(encoder);
int retry_cnt = 0;
if (!lcd)
return;
@@ -271,6 +272,14 @@ static void am_lcd_encoder_enable(struct drm_encoder *encoder)
mutex_lock(&lcd->lcd_drv->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_PREPARE, NULL);
aml_lcd_notifier_call_chain(LCD_EVENT_ENABLE, NULL);
while (lcd->lcd_drv->lcd_config->retry_enable) {
if (retry_cnt++ > LCD_ENABLE_RETRY_MAX)
break;
pr_info("am_drm_lcd: retry enable...%d\n", retry_cnt);
aml_lcd_notifier_call_chain(LCD_EVENT_DISABLE, NULL);
msleep(1000);
aml_lcd_notifier_call_chain(LCD_EVENT_ENABLE, NULL);
}
mutex_unlock(&lcd->lcd_drv->power_mutex);
vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &vmode);
pr_info("am_drm_lcd: %s %d\n", __func__, __LINE__);

View File

@@ -997,3 +997,17 @@ void lcd_venc_change(struct lcd_config_s *pconf)
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, NULL);
}
void lcd_if_enable_retry(struct lcd_config_s *pconf)
{
int retry_cnt = 0;
while (pconf->retry_enable) {
if (retry_cnt++ > LCD_ENABLE_RETRY_MAX)
break;
LCDPR("retry enable...%d\n", retry_cnt);
aml_lcd_notifier_call_chain(LCD_EVENT_IF_POWER_OFF, NULL);
msleep(1000);
aml_lcd_notifier_call_chain(LCD_EVENT_IF_POWER_ON, NULL);
}
}

View File

@@ -92,6 +92,8 @@ extern void lcd_hdr_vinfo_update(void);
extern void lcd_timing_init_config(struct lcd_config_s *pconf);
extern int lcd_vmode_change(struct lcd_config_s *pconf);
extern void lcd_venc_change(struct lcd_config_s *pconf);
extern void lcd_if_enable_retry(struct lcd_config_s *pconf);
/* lcd debug */
extern int lcd_class_creat(void);
extern int lcd_class_remove(void);

View File

@@ -1156,6 +1156,7 @@ static void lcd_power_interface_ctrl(int state)
if (lcd_drv->lcd_status & LCD_STATUS_ENCL_ON) {
aml_lcd_notifier_call_chain(
LCD_EVENT_IF_POWER_ON, NULL);
lcd_if_enable_retry(lcd_drv->lcd_config);
} else {
LCDERR("%s: can't power on when controller is off\n",
__func__);
@@ -1562,6 +1563,7 @@ static ssize_t lcd_debug_enable_store(struct class *class,
if (temp) {
mutex_lock(&lcd_drv->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_drv->lcd_config);
mutex_unlock(&lcd_drv->power_mutex);
} else {
mutex_lock(&lcd_drv->power_mutex);
@@ -2882,10 +2884,14 @@ static ssize_t lcd_mipi_state_debug_show(struct class *class,
struct class_attribute *attr, char *buf)
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
unsigned int state_save;
return sprintf(buf, "state: %d, check_en: %d\n",
state_save = lcd_vcbus_getb(L_VCOM_VS_ADDR, 12, 1);
return sprintf(buf, "state: %d, check_en: %d, state_save: %d\n",
lcd_drv->lcd_config->lcd_control.mipi_config->check_state,
lcd_drv->lcd_config->lcd_control.mipi_config->check_en);
lcd_drv->lcd_config->lcd_control.mipi_config->check_en,
state_save);
}
static struct class_attribute lcd_interface_debug_class_attrs[] = {

View File

@@ -85,13 +85,16 @@ static int lcd_set_current_vmode(enum vmode_e mode)
mutex_lock(&lcd_drv->power_mutex);
if (!(mode & VMODE_INIT_BIT_MASK)) {
if (VMODE_LCD == (mode & VMODE_MODE_BIT_MASK))
if (VMODE_LCD == (mode & VMODE_MODE_BIT_MASK)) {
if (mode & VMODE_INIT_BIT_MASK) {
lcd_clk_gate_switch(1);
} else {
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
else
ret = -EINVAL;
} else
lcd_clk_gate_switch(1);
lcd_if_enable_retry(lcd_drv->lcd_config);
}
} else {
ret = -EINVAL;
}
lcd_drv->lcd_status |= LCD_STATUS_VMODE_ACTIVE;
mutex_unlock(&lcd_drv->power_mutex);
@@ -344,6 +347,7 @@ static int lcd_resume(void)
LCDPR("Warning: no lcd workqueue\n");
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_drv->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_drv->power_mutex);
}
@@ -352,6 +356,7 @@ static int lcd_resume(void)
LCDPR("directly lcd late resume\n");
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_drv->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_drv->power_mutex);
}

View File

@@ -46,7 +46,7 @@
#define MIPI_DSI_COLOR_18BIT COLOR_18BIT_CFG_2
#define MIPI_DSI_COLOR_24BIT COLOR_24BIT
#define MIPI_DSI_TEAR_SWITCH MIPI_DCS_DISABLE_TEAR
#define CMD_TIMEOUT_CNT 3000
#define CMD_TIMEOUT_CNT 5000
/* ************************************************************* */
static char *operation_mode_table[] = {
@@ -566,7 +566,7 @@ static void set_dsi_phy_config(struct lcd_config_s *pconf)
/* Trigger a sync active for esc_clk */
dsi_phy_set_mask(MIPI_DSI_PHY_CTRL, (1 << 1));
/* Startup transfer */
/* Startup transfer, default lpclk */
dsi_host_write(MIPI_DSI_DWC_LPCLK_CTRL_OS,
(0x1 << BIT_AUTOCLKLANE_CTRL) |
(0x1 << BIT_TXREQUESTCLKHS));
@@ -678,7 +678,7 @@ static void set_mipi_dsi_host(unsigned int vcid, unsigned int chroma_subsample,
(1 << BIT_LP_VBP_EN) | /* enalbe lp */
(1 << BIT_LP_VSA_EN) | /* enalbe lp */
(0 << BIT_FRAME_BTA_ACK_EN) |
/* enable BTA after one frame, TODO, need check */
/* enable BTA after one frame, TODO, need check */
/* (1 << BIT_LP_CMD_EN) | */
/* enable the command transmission only in lp mode */
(vid_mode_type << BIT_VID_MODE_TYPE));
@@ -877,7 +877,7 @@ static int wait_bta_ack(void)
* Function: wait_cmd_fifo_empty
* Poll to check if the generic command fifo is empty
*/
static void wait_cmd_fifo_empty(void)
static int wait_cmd_fifo_empty(void)
{
unsigned int cmd_status;
int i = CMD_TIMEOUT_CNT;
@@ -885,9 +885,17 @@ static void wait_cmd_fifo_empty(void)
do {
udelay(10);
i--;
cmd_status = dsi_host_getb(MIPI_DSI_DWC_CMD_PKT_STATUS_OS,
BIT_GEN_CMD_EMPTY, 1);
} while ((cmd_status != 0x1) && (i > 0));
if (cmd_status == 0) {
cmd_status = dsi_host_read(MIPI_DSI_DWC_CMD_PKT_STATUS_OS);
} while ((((cmd_status >> BIT_GEN_CMD_EMPTY) & 0x1) != 0x1) && (i > 0));
print_mipi_cmd_status(i, cmd_status);
print_mipi_cmd_status(i, cmd_status);
return -1;
}
return 0;
}
#if 0
@@ -1072,9 +1080,10 @@ static int dsi_dcs_read_packet(struct dsi_cmd_request_s *req,
DT_GEN_SHORT_WR_1,
DT_GEN_SHORT_WR_2,
*/
static void dsi_generic_write_short_packet(struct dsi_cmd_request_s *req)
static int dsi_generic_write_short_packet(struct dsi_cmd_request_s *req)
{
unsigned int d_para[2];
int ret = 0;
switch (req->data_type) {
case DT_GEN_SHORT_WR_1:
@@ -1101,9 +1110,11 @@ static void dsi_generic_write_short_packet(struct dsi_cmd_request_s *req)
(((unsigned int)req->vc_id) << BIT_GEN_VC) |
(((unsigned int)req->data_type) << BIT_GEN_DT)));
if (req->req_ack == MIPI_DSI_DCS_REQ_ACK)
wait_bta_ack();
ret = wait_bta_ack();
else if (req->req_ack == MIPI_DSI_DCS_NO_ACK)
wait_cmd_fifo_empty();
ret = wait_cmd_fifo_empty();
return ret;
}
/* *************************************************************
@@ -1111,9 +1122,10 @@ static void dsi_generic_write_short_packet(struct dsi_cmd_request_s *req)
* DCS Write Short Packet with Generic Interface
* Supported Data Type: DT_DCS_SHORT_WR_0, DT_DCS_SHORT_WR_1,
*/
static void dsi_dcs_write_short_packet(struct dsi_cmd_request_s *req)
static int dsi_dcs_write_short_packet(struct dsi_cmd_request_s *req)
{
unsigned int d_command, d_para;
int ret = 0;
d_command = ((unsigned int)req->payload[2]) & 0xff;
d_para = (req->pld_count < 2) ?
@@ -1125,9 +1137,11 @@ static void dsi_dcs_write_short_packet(struct dsi_cmd_request_s *req)
(((unsigned int)req->vc_id) << BIT_GEN_VC) |
(((unsigned int)req->data_type) << BIT_GEN_DT)));
if (req->req_ack == MIPI_DSI_DCS_REQ_ACK)
wait_bta_ack();
ret = wait_bta_ack();
else if (req->req_ack == MIPI_DSI_DCS_NO_ACK)
wait_cmd_fifo_empty();
ret = wait_cmd_fifo_empty();
return ret;
}
/* *************************************************************
@@ -1135,11 +1149,12 @@ static void dsi_dcs_write_short_packet(struct dsi_cmd_request_s *req)
* Write Long Packet with Generic Interface
* Supported Data Type: DT_GEN_LONG_WR, DT_DCS_LONG_WR
*/
static void dsi_write_long_packet(struct dsi_cmd_request_s *req)
static int dsi_write_long_packet(struct dsi_cmd_request_s *req)
{
unsigned int d_command, payload_data, header_data;
unsigned int cmd_status;
unsigned int i, j, data_index, n, temp;
int ret = 0;
/* payload[2] start (payload[0]: data_type, payload[1]: data_cnt) */
data_index = DSI_CMD_SIZE_INDEX + 1;
@@ -1199,9 +1214,11 @@ static void dsi_write_long_packet(struct dsi_cmd_request_s *req)
(((unsigned int)req->data_type) << BIT_GEN_DT));
generic_if_wr(MIPI_DSI_DWC_GEN_HDR_OS, header_data);
if (req->req_ack == MIPI_DSI_DCS_REQ_ACK)
wait_bta_ack();
ret = wait_bta_ack();
else if (req->req_ack == MIPI_DSI_DCS_NO_ACK)
wait_cmd_fifo_empty();
ret = wait_cmd_fifo_empty();
return ret;
}
#ifdef DSI_CMD_READ_VALID
@@ -1269,7 +1286,7 @@ int dsi_read_single(unsigned char *payload, unsigned char *rd_data,
}
#endif
static void mipi_dsi_check_state(unsigned char reg, int cnt)
static int mipi_dsi_check_state(unsigned char reg, int cnt)
{
int ret = 0, i, len;
unsigned char *rd_data;
@@ -1278,13 +1295,13 @@ static void mipi_dsi_check_state(unsigned char reg, int cnt)
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
if (lcd_drv->lcd_config->lcd_control.mipi_config->check_en == 0)
return;
return 0;
LCDPR("%s\n", __func__);
rd_data = kmalloc_array(cnt, sizeof(unsigned char), GFP_KERNEL);
if (rd_data == NULL) {
LCDERR("%s: rd_data error\n", __func__);
return;
return 0;
}
payload[2] = reg;
@@ -1293,12 +1310,12 @@ static void mipi_dsi_check_state(unsigned char reg, int cnt)
lcd_drv->lcd_config->lcd_control.mipi_config->check_state = 0;
lcd_vcbus_setb(L_VCOM_VS_ADDR, 0, 12, 1);
kfree(rd_data);
return;
return -1;
}
if (ret > cnt) {
LCDERR("%s: read back cnt is wrong\n", __func__);
kfree(rd_data);
return;
return -1;
}
lcd_drv->lcd_config->lcd_control.mipi_config->check_state = 1;
@@ -1313,6 +1330,7 @@ static void mipi_dsi_check_state(unsigned char reg, int cnt)
pr_info("%s\n", str);
kfree(rd_data);
return 0;
}
/* *************************************************************
@@ -1337,6 +1355,7 @@ int dsi_write_cmd(unsigned char *payload)
struct dsi_cmd_request_s dsi_cmd_req;
unsigned char vc_id = MIPI_DSI_VIRTUAL_CHAN_ID;
unsigned int req_ack = MIPI_DSI_DCS_ACK_TYPE;
int ret = 0;
/* mipi command(payload) */
/* format: data_type, cmd_size, data.... */
@@ -1347,6 +1366,10 @@ int dsi_write_cmd(unsigned char *payload)
* data0=gpio_index, data1=gpio_value, data2=delay.
*/
while (i < DSI_CMD_SIZE_MAX) {
if (ret) {
LCDERR("%s: error, exit\n", __func__);
break;
}
if (payload[i] == 0xff) {
j = 2;
if (payload[i+1] == 0xff)
@@ -1374,7 +1397,7 @@ int dsi_write_cmd(unsigned char *payload)
break;
}
if (payload[i+DSI_GPIO_INDEX+2] > 0) {
mipi_dsi_check_state(
ret = mipi_dsi_check_state(
payload[i+DSI_GPIO_INDEX],
payload[i+DSI_GPIO_INDEX+1]);
}
@@ -1394,15 +1417,16 @@ int dsi_write_cmd(unsigned char *payload)
case DT_GEN_SHORT_WR_0:
case DT_GEN_SHORT_WR_1:
case DT_GEN_SHORT_WR_2:
dsi_generic_write_short_packet(&dsi_cmd_req);
ret = dsi_generic_write_short_packet(
&dsi_cmd_req);
break;
case DT_DCS_SHORT_WR_0:
case DT_DCS_SHORT_WR_1:
dsi_dcs_write_short_packet(&dsi_cmd_req);
ret = dsi_dcs_write_short_packet(&dsi_cmd_req);
break;
case DT_DCS_LONG_WR:
case DT_GEN_LONG_WR:
dsi_write_long_packet(&dsi_cmd_req);
ret = dsi_write_long_packet(&dsi_cmd_req);
break;
case DT_TURN_ON:
dsi_host_setb(MIPI_DSI_TOP_CNTL, 1, 2, 1);
@@ -1840,6 +1864,13 @@ static void mipi_dsi_link_on(struct lcd_config_s *pconf)
}
#endif
if (dconf->check_en) {
if (dconf->check_state == 0)
pconf->retry_enable = 1;
else
pconf->retry_enable = 0;
}
if (op_mode_disp != op_mode_init) {
set_mipi_dsi_host(MIPI_DSI_VIRTUAL_CHAN_ID,
0, /* Chroma sub sample, only for

View File

@@ -308,18 +308,17 @@ static int lcd_set_current_vmode(enum vmode_e mode)
/* do not change mode value here, for bit mask is useful */
lcd_vmode_vinfo_update(mode & VMODE_MODE_BIT_MASK);
if (!(mode & VMODE_INIT_BIT_MASK)) {
switch (mode & VMODE_MODE_BIT_MASK) {
case VMODE_LCD:
if (VMODE_LCD == (mode & VMODE_MODE_BIT_MASK)) {
if (mode & VMODE_INIT_BIT_MASK) {
lcd_clk_gate_switch(1);
} else {
mutex_lock(&lcd_vout_mutex);
ret = lcd_drv->driver_change();
mutex_unlock(&lcd_vout_mutex);
break;
default:
ret = -EINVAL;
}
} else
lcd_clk_gate_switch(1);
} else {
ret = -EINVAL;
}
lcd_drv->lcd_status |= LCD_STATUS_VMODE_ACTIVE;
@@ -602,6 +601,7 @@ static int lcd_resume(void)
LCDPR("Warning: no lcd workqueue\n");
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_drv->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_drv->power_mutex);
}
@@ -610,6 +610,7 @@ static int lcd_resume(void)
LCDPR("directly lcd late resume\n");
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_drv->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_drv->power_mutex);
}

View File

@@ -193,6 +193,7 @@ static struct lcd_config_s lcd_config_dft = {
.lcd_power = &lcd_power_config,
.pinmux_flag = 0,
.change_flag = 0,
.retry_enable = 0,
};
static struct vinfo_s lcd_vinfo = {
@@ -361,6 +362,7 @@ static void lcd_resume_work(struct work_struct *p_work)
{
mutex_lock(&lcd_driver->power_mutex);
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_driver->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_driver->power_mutex);
}
@@ -1071,6 +1073,7 @@ static int lcd_resume(struct platform_device *pdev)
mutex_lock(&lcd_driver->power_mutex);
LCDPR("Warning: no lcd workqueue\n");
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_driver->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_driver->power_mutex);
}
@@ -1079,6 +1082,7 @@ static int lcd_resume(struct platform_device *pdev)
LCDPR("directly lcd resume\n");
lcd_resume_flag = 1;
aml_lcd_notifier_call_chain(LCD_EVENT_POWER_ON, NULL);
lcd_if_enable_retry(lcd_driver->lcd_config);
LCDPR("%s finished\n", __func__);
mutex_unlock(&lcd_driver->power_mutex);
}

View File

@@ -362,6 +362,7 @@ struct lcd_clk_gate_ctrl_s {
struct reset_control *vencl;
};
#define LCD_ENABLE_RETRY_MAX 2
struct lcd_config_s {
char *lcd_propname;
unsigned int backlight_index;
@@ -373,6 +374,7 @@ struct lcd_config_s {
struct pinctrl *pin;
unsigned char pinmux_flag;
unsigned char change_flag;
unsigned char retry_enable;
struct lcd_clk_gate_ctrl_s rstc;
};