diff --git a/drivers/amlogic/drm/am_meson_lcd.c b/drivers/amlogic/drm/am_meson_lcd.c index 6c82f2914857..61e00a91679b 100644 --- a/drivers/amlogic/drm/am_meson_lcd.c +++ b/drivers/amlogic/drm/am_meson_lcd.c @@ -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__); diff --git a/drivers/amlogic/media/vout/lcd/lcd_common.c b/drivers/amlogic/media/vout/lcd/lcd_common.c index 7e72b3c28106..b162b82961ef 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_common.c +++ b/drivers/amlogic/media/vout/lcd/lcd_common.c @@ -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); + } +} + diff --git a/drivers/amlogic/media/vout/lcd/lcd_common.h b/drivers/amlogic/media/vout/lcd/lcd_common.h index 03cdfffaa392..4140c7bf82c9 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_common.h +++ b/drivers/amlogic/media/vout/lcd/lcd_common.h @@ -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); diff --git a/drivers/amlogic/media/vout/lcd/lcd_debug.c b/drivers/amlogic/media/vout/lcd/lcd_debug.c index 78fc4c92f315..709a17c917a8 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_debug.c +++ b/drivers/amlogic/media/vout/lcd/lcd_debug.c @@ -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[] = { 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 5ce13b9a056b..4819a9172c6d 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c @@ -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); } diff --git a/drivers/amlogic/media/vout/lcd/lcd_tablet/mipi_dsi_util.c b/drivers/amlogic/media/vout/lcd/lcd_tablet/mipi_dsi_util.c index 5312f592f144..c3836fb5a241 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tablet/mipi_dsi_util.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tablet/mipi_dsi_util.c @@ -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 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 901e2473981e..696de2819427 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c @@ -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); } diff --git a/drivers/amlogic/media/vout/lcd/lcd_vout.c b/drivers/amlogic/media/vout/lcd/lcd_vout.c index cf7eb8922a68..182a62d89515 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_vout.c +++ b/drivers/amlogic/media/vout/lcd/lcd_vout.c @@ -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); } diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index bfee1e18a50c..261d25d8e186 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -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; };