lcd: add retry flow to ensure power on state
authorEvoke Zhang <evoke.zhang@amlogic.com>
Mon, 14 May 2018 12:24:25 +0000 (20:24 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Wed, 16 May 2018 09:40:56 +0000 (02:40 -0700)
PD#166330: mipi panel status is incorrect sometimes when lcd enable

Change-Id: Iace4963e576752208815d672befa4e215f860097
Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
drivers/amlogic/drm/am_meson_lcd.c
drivers/amlogic/media/vout/lcd/lcd_common.c
drivers/amlogic/media/vout/lcd/lcd_common.h
drivers/amlogic/media/vout/lcd/lcd_debug.c
drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c
drivers/amlogic/media/vout/lcd/lcd_tablet/mipi_dsi_util.c
drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c
drivers/amlogic/media/vout/lcd/lcd_vout.c
include/linux/amlogic/media/vout/lcd/lcd_vout.h

index 6c82f29..61e00a9 100644 (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__);
index 7e72b3c..b162b82 100644 (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);
+       }
+}
+
index 03cdfff..4140c7b 100644 (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);
index 78fc4c9..709a17c 100644 (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[] = {
index 5ce13b9..4819a91 100644 (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);
        }
index 5312f59..c3836fb 100644 (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
index 901e247..696de28 100644 (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);
        }
index cf7eb89..182a62d 100644 (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);
        }
index bfee1e1..261d25d 100644 (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;
 };