diff --git a/techpack/display/config/konadisp.conf b/techpack/display/config/konadisp.conf index 928706fee29f..c98f8e02f196 100644 --- a/techpack/display/config/konadisp.conf +++ b/techpack/display/config/konadisp.conf @@ -12,3 +12,4 @@ export CONFIG_MSM_SDE_ROTATOR=y export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y export CONFIG_DRM_SDE_RSC=y export CONFIG_DISPLAY_BUILD=y +export CONFIG_DRM_DYNAMIC_REFRESH_RATE=y diff --git a/techpack/display/config/konadispconf.h b/techpack/display/config/konadispconf.h index 690d4ec79f41..b4dc7e829301 100644 --- a/techpack/display/config/konadispconf.h +++ b/techpack/display/config/konadispconf.h @@ -17,4 +17,5 @@ #define CONFIG_MSM_SDE_ROTATOR 1 #define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1 #define CONFIG_DRM_SDE_RSC 1 +#define CONFIG_DRM_DYNAMIC_REFRESH_RATE 1 diff --git a/techpack/display/config/saipdisp.conf b/techpack/display/config/saipdisp.conf index dbbf3c847dbb..59c283c3455a 100644 --- a/techpack/display/config/saipdisp.conf +++ b/techpack/display/config/saipdisp.conf @@ -11,3 +11,4 @@ export CONFIG_QCOM_MDSS_PLL=y export CONFIG_MSM_SDE_ROTATOR=y export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y export CONFIG_DRM_SDE_RSC=y +export CONFIG_DRM_DYNAMIC_REFRESH_RATE=y diff --git a/techpack/display/config/saipdispconf.h b/techpack/display/config/saipdispconf.h index 049024839701..09dc500defab 100644 --- a/techpack/display/config/saipdispconf.h +++ b/techpack/display/config/saipdispconf.h @@ -17,3 +17,4 @@ #define CONFIG_MSM_SDE_ROTATOR 1 #define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1 #define CONFIG_DRM_SDE_RSC 1 +#define CONFIG_DRM_DYNAMIC_REFRESH_RATE 1 diff --git a/techpack/display/include/uapi/display/drm/sde_drm.h b/techpack/display/include/uapi/display/drm/sde_drm.h index 67fc98b4152c..bd8e8c219a43 100644 --- a/techpack/display/include/uapi/display/drm/sde_drm.h +++ b/techpack/display/include/uapi/display/drm/sde_drm.h @@ -690,6 +690,27 @@ struct drm_msm_display_hint { #define DRM_IOCTL_MSM_DISPLAY_HINT DRM_IOW((DRM_COMMAND_BASE + \ DRM_MSM_DISPLAY_HINT), struct drm_msm_display_hint) +/* panel feature */ +typedef enum { + PARAM_HBM = 0, + PARAM_CABC, + PARAM_ACL, + PARAM_DC, + POWER_MODE_MAX_NUM, + PARAM_COLOR = POWER_MODE_MAX_NUM, + PARAM_MAX_NUM +} paramId_t; + +struct panel_param_info { + paramId_t param_idx; + __u32 value; +}; + +#define DRM_SET_PANEL_FEATURE (DRM_COMMAND_END -1) +#define DRM_IOCTL_SET_PANEL_FEATURE DRM_IOWR(DRM_SET_PANEL_FEATURE, struct panel_param_info) +#define DRM_GET_PANEL_FEATURE (DRM_COMMAND_END-2) +#define DRM_IOCTL_GET_PANEL_FEATURE DRM_IOWR(DRM_GET_PANEL_FEATURE, struct panel_param_info) + #if defined(__cplusplus) } #endif diff --git a/techpack/display/msm/Makefile b/techpack/display/msm/Makefile index 1e4e0f35fb78..936c8de54e87 100644 --- a/techpack/display/msm/Makefile +++ b/techpack/display/msm/Makefile @@ -44,6 +44,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_core_perf.o \ sde/sde_rm.o \ sde/sde_kms_utils.o \ + sde/sde_motUtil.o \ sde/sde_kms.o \ sde/sde_plane.o \ sde/sde_connector.o \ diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c b/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c index df9954da0454..50dc8a060463 100644 --- a/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c @@ -332,7 +332,7 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, u32 reg = 0; u32 hs_start = 0; u32 hs_end, active_h_start, active_h_end, h_total, width = 0; - u32 bytes_per_pkt, pkt_per_line, eol_byte_num; + u32 bytes_per_pkt, pkt_per_line, eol_byte_num, datatype; u32 vs_start = 0, vs_end = 0; u32 vpos_start = 0, vpos_end, active_v_start, active_v_end, v_total; @@ -342,7 +342,9 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, &pkt_per_line, &eol_byte_num); reg = bytes_per_pkt << 16; /* data type of compressed image */ - reg |= (0x0b << 8); + datatype = mode->dsc->datatype; + if(!datatype) datatype = 0x0b; + reg |= (datatype << 8); /* * pkt_per_line: * 0 == 1 pkt diff --git a/techpack/display/msm/dsi/dsi_defs.h b/techpack/display/msm/dsi/dsi_defs.h index 7303d30397bf..8f31e51cec75 100644 --- a/techpack/display/msm/dsi/dsi_defs.h +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -263,6 +263,27 @@ enum dsi_dyn_clk_feature_type { * @DSI_CMD_SET_POST_TIMING_SWITCH: Post timing switch * @DSI_CMD_SET_QSYNC_ON Enable qsync mode * @DSI_CMD_SET_QSYNC_OFF Disable qsync mode + * @DSI_CMD_SET_HBM_FOD_ON: Turning HBM_FOD on + * @DSI_CMD_SET_HBM_ON: Turning HBM on + * @DSI_CMD_SET_HBM_OFF: Turning HBM off + * @DSI_CMD_SET_ACL_ON: Turning ACL on + * @DSI_CMD_SET_ACL_OFF: Turning ACL off + * @DSI_CMD_SET_HBM_DIM_OFF: Turning HBM DIM off + * @DSI_CMD_SET_CABC_UI: CABC UI mode + * @DSI_CMD_SET_CABC_MV: CABC MV mode + * @DSI_CMD_SET_CABC_DIS: CABC DIS mode + * @DSI_CMD_SET_DFPS_CMD_120: DFPS switch to 120 + * @DSI_CMD_SET_DFPS_CMD_90: DFPS switch to 90 + * @DSI_CMD_SET_DFPS_CMD_60: DFPS switch to 60 + * @DSI_CMD_SET_DC_ON: DC mode on + * @DSI_CMD_SET_DC_OFF: DC mode off + * @DSI_CMD_SET_BRIGHTNESS_1E: Send demura codes when brightness changes to 0-1E + * @DSI_CMD_SET_BRIGHTNESS_1FD: Send demura codes when brightness changes to 1F-1FD + * @DSI_CMD_SET_BRIGHTNESS_2FF: Send demura codes when brightness changes to 1FE-2FF + * @DSI_CMD_SET_BRIGHTNESS_3FF: Send demura codes when brightness changes to 300-3FF + * @DSI_CMD_SET_BRIGHTNESS_4FF: Send demura codes when brightness changes to 400-4FF + * @DSI_CMD_SET_BRIGHTNESS_5FF: Send demura codes when brightness changes to 500-5FF + * @DSI_CMD_SET_BRIGHTNESS_FFF: Send demura codes when brightness changes to 600-FFF * @DSI_CMD_SET_MAX */ enum dsi_cmd_set_type { @@ -289,6 +310,27 @@ enum dsi_cmd_set_type { DSI_CMD_SET_POST_TIMING_SWITCH, DSI_CMD_SET_QSYNC_ON, DSI_CMD_SET_QSYNC_OFF, + DSI_CMD_SET_HBM_FOD_ON, + DSI_CMD_SET_HBM_ON, + DSI_CMD_SET_HBM_OFF, + DSI_CMD_SET_ACL_ON, + DSI_CMD_SET_ACL_OFF, + DSI_CMD_SET_HBM_DIM_OFF, + DSI_CMD_SET_CABC_UI, + DSI_CMD_SET_CABC_MV, + DSI_CMD_SET_CABC_DIS, + DSI_CMD_SET_DFPS_CMD_120, + DSI_CMD_SET_DFPS_CMD_90, + DSI_CMD_SET_DFPS_CMD_60, + DSI_CMD_SET_DC_ON, + DSI_CMD_SET_DC_OFF, + DSI_CMD_SET_BRIGHTNESS_1E, + DSI_CMD_SET_BRIGHTNESS_1FD, + DSI_CMD_SET_BRIGHTNESS_2FF, + DSI_CMD_SET_BRIGHTNESS_3FF, + DSI_CMD_SET_BRIGHTNESS_4FF, + DSI_CMD_SET_BRIGHTNESS_5FF, + DSI_CMD_SET_BRIGHTNESS_FFF, DSI_CMD_SET_MAX }; @@ -622,11 +664,13 @@ struct dsi_display_mode_priv_info { u32 dsi_transfer_time_us; u64 clk_rate_hz; u64 min_dsi_clk_hz; + u32 phy_drive_strength; struct msm_display_topology topology; struct msm_display_dsc_info dsc; struct msm_display_vdc_info vdc; bool dsc_enabled; + bool panel_dsc_update_pps_disable; bool vdc_enabled; struct msm_ratio pclk_scale; struct msm_roi_caps roi_caps; diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 109e6ede35c3..affe7b5d02d2 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -36,6 +36,7 @@ #define MAX_TE_SOURCE_ID 2 #define SEC_PANEL_NAME_MAX_LEN 256 +#define MAX_ESD_RECOVERY_RETRY 5 u8 dbgfs_tx_cmd_buf[SZ_4K]; static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; @@ -50,6 +51,10 @@ static const struct of_device_id dsi_display_dt_match[] = { {} }; +static int dsi_display_enable_status (struct dsi_display *display, bool enable); +static void dsi_display_is_probed(struct dsi_display *display, + int probe_status); + bool is_skip_op_required(struct dsi_display *display) { if (!display) @@ -161,6 +166,9 @@ static void dsi_display_set_ctrl_esd_check_flag(struct dsi_display *display, continue; ctrl->ctrl->esd_check_underway = enable; } + + if (enable) + display->disp_esd_chk_underway = enable; } static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en) @@ -219,10 +227,15 @@ int dsi_display_set_backlight(struct drm_connector *connector, mutex_lock(&panel->panel_lock); if (!dsi_panel_initialized(panel)) { + DSI_INFO("Ignor bl_level %u as panel is not init.\n",(u32)bl_lvl); rc = -EINVAL; goto error; } + if (!(panel->bl_config.bl_level && bl_lvl)) + DSI_INFO("bl_level changed from %u to %u\n", + (u32)(panel->bl_config.bl_level), (u32)bl_lvl); + panel->bl_config.bl_level = bl_lvl; /* scale backlight */ @@ -259,6 +272,28 @@ error: return rc; } +int dsi_display_set_param(void *display, struct msm_param_info *param_info) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + int rc = 0; + + if (dsi_display == NULL || dsi_display->panel == NULL) + return -EINVAL; + + panel = dsi_display->panel; + + DSI_DEBUG("%s+\n", __func__); + if (!dsi_panel_initialized(panel)) + return -EINVAL; + + rc = dsi_panel_set_param(panel, param_info); + if (rc) + DSI_ERR("[%s] failed to panel to set param. rc=%d\n", + dsi_display->name, rc); + return rc; +} + static int dsi_display_cmd_engine_enable(struct dsi_display *display) { int rc = 0; @@ -496,7 +531,8 @@ static void dsi_display_register_te_irq(struct dsi_display *display) error: /* disable the TE based ESD check */ DSI_WARN("Unable to register for TE IRQ\n"); - if (display->panel->esd_config.status_mode == ESD_MODE_PANEL_TE) + if (display->panel->esd_config.status_mode == ESD_MODE_PANEL_TE || + display->panel->esd_config.status_mode == ESD_MODE_TE_CHK_REG_RD) display->panel->esd_config.esd_enabled = false; } @@ -731,6 +767,40 @@ exit: return rc; } +int dsi_display_cmd_mipi_transfer(struct dsi_display *display, + struct mipi_dsi_msg *msg, + u32 flags) +{ + int rc = 0; + struct dsi_display_ctrl *m_ctrl; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + if (display->tx_cmd_buf == NULL) { + rc = dsi_host_alloc_cmd_tx_buffer(display); + if (rc) { + DSI_ERR("failed to allocate cmd tx buffer memory\n"); + goto done; + } + } + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EPERM; + } + + flags |= DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_CUSTOM_DMA_SCHED; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, &flags); + if (((flags & DSI_CTRL_CMD_READ) && rc <= 0) || + (!(flags & DSI_CTRL_CMD_READ) && rc)) + DSI_ERR("failed to transfer cmd. rc = %d\n", rc); + + dsi_display_cmd_engine_disable(display); +done: + return rc; +} + static int dsi_display_status_reg_read(struct dsi_display *display) { int rc = 0, i; @@ -880,6 +950,12 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, } else if (status_mode == ESD_MODE_PANEL_TE) { rc = dsi_display_status_check_te(dsi_display, te_rechecks); te_check_override = false; + } else if (status_mode == ESD_MODE_TE_CHK_REG_RD) { + rc = dsi_display_status_check_te(dsi_display, te_rechecks); + if (rc > 0) { + /* after checking for TE, then chk for reg_read status */ + rc = dsi_display_status_reg_read(dsi_display); + } } else { DSI_WARN("Unsupported check status mode: %d\n", status_mode); panel->esd_config.esd_enabled = false; @@ -912,6 +988,19 @@ release_panel_lock: return rc; } +bool dsi_display_force_esd_disable(void *display) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + + if (dsi_display == NULL) + return false; + + panel = dsi_display->panel; + + return (panel->esd_utag_enable? false: true); +} + static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, struct dsi_cmd_desc *cmd, u8 *payload, u32 payload_len) { @@ -942,6 +1031,166 @@ static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, return 0; } + +static int dsi_display_dispUtil_get_datatype (char dsi_cmd, u8 cmd_type, + size_t tx_len, u8 *tx_data_type) +{ + int rc = 0; + + *tx_data_type = 0; + + /* cmd_type = 0 : DSI DCS cmd; + * cmd_type = 1 : DSI Generic cmd */ + if (cmd_type > DISPUTIL_DSI_GENERIC) { + DSI_ERR("%s: Invalid DSI package type[%d] = 0x%x\n", + __func__, DISPUTIL_MIPI_CMD_TYPE, + cmd_type); + return -EINVAL; + } + + DSI_DEBUG("dsi_cmd =0x%x cmd_type=0x%x tx_len=0x%x\n", + dsi_cmd, cmd_type, (u32)tx_len); + + if (dsi_cmd == DISPUTIL_DSI_WRITE) { + /* This is a DSI write command */ + switch(tx_len) { + case 1: + if (cmd_type == DISPUTIL_DSI_GENERIC) + /* write, generic, no param */ + *tx_data_type = 0x3; + else if (cmd_type == DISPUTIL_DSI_DCS) + /* write, DCS, no param */ + *tx_data_type = 0x5; + break; + case 2: + if (cmd_type == DISPUTIL_DSI_GENERIC) + /* Write, generic, 1 param */ + *tx_data_type = 0x13; + else if (cmd_type == DISPUTIL_DSI_DCS) + /* write, DCS, 1 param */ + *tx_data_type = 0x15; + break; + default: + if (cmd_type == DISPUTIL_DSI_GENERIC) + /* Write, generic, long*/ + *tx_data_type = 0x29; + else if (cmd_type == DISPUTIL_DSI_DCS) + /* write, DCS, long*/ + *tx_data_type = 0x39; + break; + } + } else if (dsi_cmd == DISPUTIL_DSI_READ) { + if ((cmd_type == DISPUTIL_DSI_DCS) && (tx_len > 1)) { + /* Note: tx_len will include read command and payload */ + /* DCS read */ + DSI_ERR("DCS read supports no parameter. tx_len=%d\n", + (u32)tx_len); + rc = -EINVAL; + } else { + switch(tx_len) { + case 1: + if (cmd_type == DISPUTIL_DSI_GENERIC) + /* Read, generic, no param */ + *tx_data_type = 0x4; + else if (cmd_type == DISPUTIL_DSI_DCS) + /* Read, DCS, no param */ + *tx_data_type = 0x6; + break; + case 2: + if (cmd_type == DISPUTIL_DSI_GENERIC) + /* Read, Generic, 1 param */ + *tx_data_type = 0x14; + + break; + case 3: + if (cmd_type == DISPUTIL_DSI_GENERIC) + /* read, generic, 2 params */ + *tx_data_type = 0x24; + break; + default: + DSI_ERR("Invalid for tx_len= %d\n", (u32)tx_len); + break; + } + } + } else + rc = -EINVAL; + + if (rc) + DSI_ERR("Invalid input data: dsi_cmd=0x%x tx_data_type =0x%x for tx_len=0x%x\n", + dsi_cmd, *tx_data_type, (u32)tx_len); + + return rc; +} + +static int dsi_display_dispUtil_prepare(const char *cmd_buf, u32 cmd_buf_len, + struct dsi_cmd_desc *cmd, u8 *payload, u32 payload_len_max, + struct motUtil *motUtil_data) +{ + int rc, i; + u8 tx_data_type; + + memset(cmd, 0x00, sizeof(*cmd)); + + /* + * DISPUTIL_PAYLOAD_LEN_U and SDE_MOT_UTIL_PAYLOAD_LEN_L to + * indicate number of payload in bytes + */ + cmd->msg.tx_len = ((cmd_buf[DISPUTIL_PAYLOAD_LEN_U] << 8) | + (cmd_buf[DISPUTIL_PAYLOAD_LEN_L])); + rc = dsi_display_dispUtil_get_datatype(cmd_buf[DISPUTIL_CMD_TYPE], + cmd_buf[DISPUTIL_MIPI_CMD_TYPE], + cmd->msg.tx_len, &tx_data_type); + if (rc) + return rc; + + cmd->msg.type = tx_data_type; + cmd->msg.channel = 0; + cmd->last_command = 1; + cmd->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + + /* DISPUTIL_CMD_TYPE = 1 for DSI write cmd + * DISPUTIL_CMD_TYPE = 0 for DSI read cmd */ + if (cmd_buf[DISPUTIL_CMD_TYPE] == DISPUTIL_DSI_READ) { + //cmd->msg.flags |= MIPI_DSI_MSG_READ; /* This is a read DSI */ + cmd->msg.rx_buf = motUtil_data->rd_buf; + /* cmd_buf[3] = number bytes host wants to read */ + cmd->msg.rx_len = cmd_buf[DISPUTIL_NUM_BYTE_RD]; + + motUtil_data->read_cmd = true; + } else + motUtil_data->read_cmd = false; + + /* + * DISPUTIL_CMD_XFER_MODE = 0: DSI cmd transfers at HS mode + * DISPUTIL_CMD_XFER_MODE = 1: DSI cmd transfers at LP mode + */ + if (cmd_buf[DISPUTIL_CMD_XFER_MODE] == DISPUTIL_DSI_LP_MODE) + cmd->msg.flags |= MIPI_DSI_MSG_USE_LPM; + + cmd->msg.ctrl = 0; + cmd->post_wait_ms = 0; + + /* + * msg.tx_len is number of bytes of the payload. + * Checking msg.tx_len with the payload, DISPUTIL_PAYLOAD, + * to make sure they are matched + */ + if ((cmd->msg.tx_len > (cmd_buf_len - DISPUTIL_PAYLOAD)) || + (cmd->msg.tx_len > payload_len_max)) { + DSI_ERR("Incorrect payload length tx_len:%ld, payload_len_max=%d cmd_buf_len=%d\n", + cmd->msg.tx_len, payload_len_max, cmd_buf_len); + return -EINVAL; + } + + for (i = 0; i < cmd->msg.tx_len; i++) + payload[i] = cmd_buf[DISPUTIL_PAYLOAD + i]; + + cmd->msg.tx_buf = payload; + + return 0; +} + + static int dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, bool *state) { @@ -1111,6 +1360,144 @@ end: return rc; } +static int dsi_display_read_elvss_status(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_cmd_desc cmds; + u8 data[] = {06, 01, 00, 01, 00, 00, 01, 0xB7}; + u32 flags = 0; + u8 *payload; + int size, j; + u8 elvss_val; + pr_info("++\n"); + + if (!panel || !ctrl || !ctrl->ctrl) + return -EINVAL; + + DSI_DEBUG("++\n"); + cmds.msg.type = data[0]; + cmds.last_command = (data[1] == 1 ? true : false); + cmds.msg.channel = data[2]; + cmds.msg.flags |= (data[3] == 1 ? MIPI_DSI_MSG_REQ_ACK : 0); + cmds.msg.ctrl = 0; + cmds.post_wait_ms = cmds.msg.wait_ms = data[4]; + cmds.msg.tx_len = ((data[5] << 8) | (data[6])); + + size = cmds.msg.tx_len * sizeof(u8); + payload = kzalloc(size, GFP_KERNEL); + if (!payload) { + return -ENOMEM; + } + + for (j = 0; j < cmds.msg.tx_len; j++) + payload[j] = data[7+j]; + + cmds.msg.tx_buf = payload; + /* + * When DSI controller is not in initialized state, we do not want to + * read reg and hence we defer until next read + * happen. + */ + /* + if (dsi_ctrl_validate_host_state(ctrl->ctrl)) + return 0; + */ + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ | + DSI_CTRL_CMD_CUSTOM_DMA_SCHED); + + if (cmds.last_command) { + cmds.msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + cmds.msg.rx_buf = &elvss_val; + cmds.msg.rx_len = 1; + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds.msg, &flags); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + goto error; + } + + DSI_INFO("elvss val = 0x%x\n", elvss_val); +error: + if (elvss_val != 0) + return elvss_val; + return 0; +} + +static int dsi_display_elvss_read(struct dsi_display *display) +{ + struct dsi_display_ctrl *m_ctrl; + int rc; + + DSI_DEBUG("++\n"); + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return 0; + } + + rc = dsi_display_read_elvss_status(m_ctrl, display->panel); + if (rc <= 0) { + DSI_ERR("[%s] read elvss failed on master,rc=%d\n", + display->name, rc); + goto exit; + } + +exit: + dsi_display_cmd_engine_disable(display); + return rc; +} + +int dsi_display_read_elvss_volt(void *display) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + int rc = 0x1; + int elvss_vl = 0; + static bool read_flag = false; + + if (read_flag) + return rc; + + if (!dsi_display || !dsi_display->panel) + return -EINVAL; + + panel = dsi_display->panel; + + dsi_panel_acquire_panel_lock(panel); + + if (!panel->panel_initialized) { + DSI_WARN("Panel not initialized\n"); + goto release_panel_lock; + } + + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + dsi_panel_get_elvss_data(panel); + elvss_vl = dsi_display_elvss_read(dsi_display); + dsi_panel_get_elvss_data_1(panel); + if ( elvss_vl > 0) { + dsi_panel_set_elvss_dim_off(panel, elvss_vl); + dsi_panel_parse_elvss_config(panel, elvss_vl); + read_flag = true; + } else { + elvss_vl = 0x92; + dsi_panel_set_elvss_dim_off(panel, elvss_vl); + DSI_WARN("read elvss volt failed\n"); + } + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + +release_panel_lock: + dsi_panel_release_panel_lock(panel); + return rc; +} + static void _dsi_display_continuous_clk_ctrl(struct dsi_display *display, bool enable) { @@ -1139,47 +1526,92 @@ static void _dsi_display_continuous_clk_ctrl(struct dsi_display *display, } int dsi_display_cmd_receive(void *display, const char *cmd_buf, - u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len) + u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len) { - struct dsi_display *dsi_display = display; - struct dsi_cmd_desc cmd = {}; - u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE] = {0}; - bool state = false; - int rc = -1; + struct dsi_display *dsi_display = display; + struct dsi_cmd_desc cmd = {}; + u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE] = {0}; + bool state = false; + int rc = -1; - if (!dsi_display || !cmd_buf || !recv_buf) { - DSI_ERR("[DSI] invalid params\n"); - return -EINVAL; - } + if (!dsi_display || !cmd_buf || !recv_buf) { + DSI_ERR("[DSI] invalid params\n"); + return -EINVAL; + } SDE_EVT32(cmd_buf_len, recv_buf_len); - rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len, - &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE); - if (rc) { - DSI_ERR("[DSI] command prepare failed, rc = %d\n", rc); - return rc; - } + rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len, + &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE); + if (rc) { + DSI_ERR("[DSI] command prepare failed, rc = %d\n", rc); + return rc; + } - cmd.msg.rx_buf = recv_buf; - cmd.msg.rx_len = recv_buf_len; + cmd.msg.rx_buf = recv_buf; + cmd.msg.rx_len = recv_buf_len; - mutex_lock(&dsi_display->display_lock); - rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); - if (rc || !state) { - DSI_ERR("[DSI] Invalid host state = %d rc = %d\n", - state, rc); - rc = -EPERM; - goto end; - } + mutex_lock(&dsi_display->display_lock); + rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); + if (rc || !state) { + DSI_ERR("[DSI] Invalid host state = %d rc = %d\n", + state, rc); + rc = -EPERM; + goto end; + } - rc = dsi_display_cmd_rx(dsi_display, &cmd); - if (rc <= 0) - DSI_ERR("[DSI] Display command receive failed, rc=%d\n", rc); + rc = dsi_display_cmd_rx(dsi_display, &cmd); + if (rc <= 0) + DSI_ERR("[DSI] Display command receive failed, rc=%d\n", rc); end: - mutex_unlock(&dsi_display->display_lock); - return rc; + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_motUtil_transfer(void *display, const char *cmd_buf, + u32 cmd_buf_len, struct motUtil *motUtil_data) +{ + struct dsi_display *dsi_display = display; + struct dsi_cmd_desc cmd; + u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE]; + int rc = 0; + bool state = false; + + if (!dsi_display || !cmd_buf) { + DSI_ERR("[DSI] invalid params\n"); + return -EINVAL; + } + + DSI_INFO("[DSI] Display dispUtil transfer\n"); + + rc = dsi_display_dispUtil_prepare(cmd_buf, cmd_buf_len, + &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE, + motUtil_data); + if (rc) { + DSI_ERR("[DSI] command prepare failed. rc %d\n", rc); + return rc; + } + + mutex_lock(&dsi_display->display_lock); + rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); + if (rc || !state) { + DSI_ERR("[DSI] Invalid host state %d rc %d\n", + state, rc); + rc = -EPERM; + goto end; + } + + /* + * rc will be returned from ops->transfer, which will be 0 or 1 for + * DSI write command. rc will be returned for number of read bytes + * for DSI read commad + */ + rc = dsi_display->host.ops->transfer(&dsi_display->host, + &cmd.msg); +end: + mutex_unlock(&dsi_display->display_lock); + return rc; } int dsi_display_soft_reset(void *display) @@ -1296,7 +1728,8 @@ static bool dsi_display_is_te_based_esd(struct dsi_display *display) status_mode = display->panel->esd_config.status_mode; - if (status_mode == ESD_MODE_PANEL_TE && + if ((status_mode == ESD_MODE_PANEL_TE || + status_mode == ESD_MODE_TE_CHK_REG_RD) && gpio_is_valid(display->disp_te_gpio)) return true; return false; @@ -1720,6 +2153,8 @@ static ssize_t debugfs_read_esd_check_mode(struct file *file, case ESD_MODE_SW_SIM_SUCCESS: rc = snprintf(buf, len, "esd_sw_sim_success"); break; + case ESD_MODE_TE_CHK_REG_RD: + rc = snprintf(buf, len, "te_chk_reg_rd"); default: rc = snprintf(buf, len, "invalid"); break; @@ -3396,9 +3831,13 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, (display->enabled)) cmd_flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED; + if (msg->rx_buf) + cmd_flags |= DSI_CTRL_CMD_READ; rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg, &cmd_flags); - if (rc < 0) { + if (((cmd_flags & DSI_CTRL_CMD_READ) && rc <= 0) || + (!(cmd_flags & DSI_CTRL_CMD_READ) && rc < 0 )) { + DSI_ERR("[%s] cmd transfer failed, rc=%d\n", display->name, rc); goto error_disable_cmd_engine; @@ -4311,12 +4750,21 @@ static int dsi_display_res_init(struct dsi_display *display) } } + if (!strcmp(display->display_type, "primary")) + display->panel_idx = 0; + else if (!strcmp(display->display_type, "secondary")) + display->panel_idx = 1; + else { + DSI_WARN("Unalbe to find the display type"); + display->panel_idx = 0; + } display->panel = dsi_panel_get(&display->pdev->dev, display->panel_node, display->parser_node, display->display_type, display->cmdline_topology, - display->trusted_vm_env); + display->trusted_vm_env, + display->panel_idx); if (IS_ERR_OR_NULL(display->panel)) { rc = PTR_ERR(display->panel); DSI_ERR("failed to get panel, rc=%d\n", rc); @@ -4333,6 +4781,9 @@ static int dsi_display_res_init(struct dsi_display *display) display->panel->host_config.phy_type; } + dsi_panel_parse_panel_cfg(display->panel, + !strcmp(display->display_type, "primary")); + rc = dsi_display_parse_lane_map(display); if (rc) { DSI_ERR("Lane map not found, rc=%d\n", rc); @@ -5254,6 +5705,11 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, true); } } + + if (display->panel->dfps_caps.dfps_send_cmd_with_te_async) { + if ((display->panel->dfps_caps.current_fps != 60)&&(display->panel->dfps_caps.current_fps != 90)) + dsi_display_status_check_te(display,1); + } rc = dsi_display_dfps_update(display, mode); if (rc) { DSI_ERR("[%s]DSI dfps update failed, rc=%d\n", @@ -5281,6 +5737,10 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, DSI_ERR("Fail to add timing params\n"); } } + + if (display->panel->dfps_caps.dfps_send_cmd_support) + dsi_panel_dfps_send_cmd(display->panel); + if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) return rc; } @@ -5332,6 +5792,16 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, dsi_display_validate_dms_fps(display->panel->cur_mode, mode); } + if (priv_info->phy_drive_strength) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_phy_set_drive_strength_params(ctrl->phy, + priv_info->phy_drive_strength); + if (rc) + DSI_ERR("Fail to add drive strength params\n"); + } + } + if (priv_info->phy_timing_len) { display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; @@ -5829,6 +6299,7 @@ static int dsi_display_bind(struct device *dev, } DSI_INFO("Successfully bind display panel '%s'\n", display->name); + dsi_display_is_probed(display, 0); display->drm_dev = drm; display_for_each_ctrl(i, display) { @@ -5940,8 +6411,54 @@ static struct platform_driver dsi_display_driver = { .of_match_table = dsi_display_dt_match, .suppress_bind_attrs = true, }, + .shutdown = dsi_display_dev_shutdown, }; +void dsi_display_dev_shutdown(struct platform_device *pdev) +{ + int rc = 0; + struct dsi_display *display; + struct dsi_panel *panel; + + if (!pdev) { + DSI_ERR("Invalid device\n"); + return; + } + + display = platform_get_drvdata(pdev); + + if (display == NULL || display->panel == NULL) { + DSI_ERR("Invalid device\n"); + return; + } + + panel = display->panel; + + if (!panel->need_execute_shutdown) { + return; + } + + if (gpio_is_valid(panel->reset_config.disp_en_gpio)) + gpio_set_value(panel->reset_config.disp_en_gpio, 0); + + if (gpio_is_valid(panel->reset_config.reset_gpio)) + gpio_set_value(panel->reset_config.reset_gpio, 0); + + if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) + gpio_set_value(panel->reset_config.lcd_mode_sel_gpio, 0); + + if (gpio_is_valid(panel->panel_test_gpio)) { + rc = gpio_direction_input(panel->panel_test_gpio); + if (rc) + DSI_WARN("set dir for panel test gpio failed rc=%d\n", rc); + } + + rc = dsi_pwr_enable_regulator(&panel->power_info, false); + if (rc) + DSI_ERR("[%s] failed to enable vregs, rc=%d\n", panel->name, rc); + +} + static int dsi_display_init(struct dsi_display *display) { int rc = 0; @@ -6011,6 +6528,118 @@ static void dsi_display_firmware_display(const struct firmware *fw, DSI_DEBUG("success\n"); } +/* + Add /sys/class/drm path, other module can get panel info from this path. +*/ +struct dsi_display *display_panel = NULL; +static ssize_t panelId_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int written = 0; + + mutex_lock(&display_panel->drm_conn->dev->mode_config.mutex); + written = snprintf(buf, PAGE_SIZE, "0x%016llx\n", + display_panel->panel->panel_id); + mutex_unlock(&display_panel->drm_conn->dev->mode_config.mutex); + + return written; +} + +static ssize_t panelVer_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int written = 0; + + mutex_lock(&display_panel->drm_conn->dev->mode_config.mutex); + written = snprintf(buf, PAGE_SIZE, "0x%016llx\n", + display_panel->panel->panel_ver); + mutex_unlock(&display_panel->drm_conn->dev->mode_config.mutex); + + return written; +} + +static ssize_t panelName_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int written = 0; + + mutex_lock(&display_panel->drm_conn->dev->mode_config.mutex); + written = snprintf(buf, PAGE_SIZE, "%s\n", display_panel->panel->panel_name); + mutex_unlock(&display_panel->drm_conn->dev->mode_config.mutex); + + return written; +} + +static ssize_t panelRegDA_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int written = 0; + + mutex_lock(&display_panel->drm_conn->dev->mode_config.mutex); + written = snprintf(buf, PAGE_SIZE, "0x%02x\n", display_panel->panel->panel_regDA); + mutex_unlock(&display_panel->drm_conn->dev->mode_config.mutex); + + return written; +} + +static ssize_t panelSupplier_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int written = 0; + + mutex_lock(&display_panel->drm_conn->dev->mode_config.mutex); + written = scnprintf(buf, PAGE_SIZE, display_panel->panel->panel_supplier); + mutex_unlock(&display_panel->drm_conn->dev->mode_config.mutex); + + return written; +} + +static struct device_attribute panel_attributes[] = { + __ATTR_RO(panelId), + __ATTR_RO(panelVer), + __ATTR_RO(panelName), + __ATTR_RO(panelRegDA), + __ATTR_RO(panelSupplier), + __ATTR_NULL +}; + +#define DRM_RETRY_TIMES 3 +static int panel_class_create(struct platform_device *pdev) +{ + struct device_attribute *attrs = panel_attributes; + int i, j, error = 0; + + display_panel = platform_get_drvdata(pdev); + + for (j = 0; j < DRM_RETRY_TIMES; j++) { + if (display_panel->drm_conn->kdev) { + for (i = 0; attrs[i].attr.name != NULL; ++i) { + error = device_create_file(display_panel->drm_conn->kdev, &attrs[i]); + if (error) + break; + } + } else { + DSI_ERR("drm_conn->kdev is NULL, retry %d times\n", j); + } + } + + if (error) + goto device_destroy; + + return 0; + +device_destroy: + for (--i; i >= 0; --i) + device_remove_file(display_panel->drm_conn->kdev, &attrs[i]); + DSI_ERR("creating panel class failed\n"); + + return -ENODEV; +} + int dsi_display_dev_probe(struct platform_device *pdev) { struct dsi_display *display = NULL; @@ -6111,6 +6740,8 @@ int dsi_display_dev_probe(struct platform_device *pdev) goto end; } + panel_class_create(pdev); + return 0; end: if (display) @@ -6173,6 +6804,27 @@ int dsi_display_get_num_of_displays(void) return count; } +bool dsi_display_all_displays_dead(void) +{ + int index =0, num_displays =0, num_dead_displays =0; + + for (index = 0; index < MAX_DSI_ACTIVE_DISPLAY; index++) { + struct dsi_display *display = boot_displays[index].disp; + + if (display && display->panel_node) { + num_displays++; + + if (display->panel->is_panel_dead) + num_dead_displays++; + } + } + + pr_info("%d Display Dead(%d)\n", num_dead_displays, num_displays); + + return num_dead_displays == num_displays; +} +EXPORT_SYMBOL(dsi_display_all_displays_dead); + int dsi_display_get_active_displays(void **display_array, u32 max_display_count) { int index = 0, count = 0; @@ -6773,6 +7425,14 @@ int dsi_display_get_info(struct drm_connector *connector, true : false; info->poms_align_vsync = display->panel->poms_align_vsync; + info->panel_id = display->panel->panel_id; + info->panel_ver = display->panel->panel_ver; + info->panel_regDA = display->panel->panel_regDA; + strncpy(info->panel_name, display->panel->panel_name, + sizeof(display->panel->panel_name)); + strncpy(info->panel_supplier, display->panel->panel_supplier, + sizeof(display->panel->panel_supplier)); + switch (display->panel->panel_mode) { case DSI_OP_VIDEO_MODE: info->curr_panel_mode = MSM_DISPLAY_VIDEO_MODE; @@ -7890,6 +8550,7 @@ int dsi_display_prepare(struct dsi_display *display) { int rc = 0; struct dsi_display_mode *mode; + struct dsi_display_ctrl *ctrl = &display->ctrl[0]; if (!display) { DSI_ERR("Invalid params\n"); @@ -7901,6 +8562,9 @@ int dsi_display_prepare(struct dsi_display *display) return -EINVAL; } + DSI_INFO("panel_name=%s ctrl-index=%d\n", + display->panel->name, ctrl->ctrl->cell_index); + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); mutex_lock(&display->display_lock); @@ -8048,7 +8712,8 @@ error_ctrl_clk_off: (void)dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); error_panel_post_unprep: - (void)dsi_panel_post_unprepare(display->panel); + if (!display->is_cont_splash_enabled) + (void)dsi_panel_post_unprepare(display->panel); error: mutex_unlock(&display->display_lock); SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); @@ -8326,6 +8991,155 @@ static void dsi_display_panel_id_notification(struct dsi_display *display) } } +struct dsi_enable_status { + struct dsi_display *display; + int probed; + bool enable; + char pname[DSI_PANEL_MAX_PANEL_LEN]; +}; + +static struct dsi_enable_status enable_status[2] = { + { + .probed = -ENODEV, + }, + { + .probed = -ENODEV, + }, +}; + +static void dsi_display_is_probed (struct dsi_display *display, + int probe_status) + +{ + int enable_idx = 0; + + if (!display->display_type) + enable_idx = 0; + + if (!strcmp(display->display_type, "secondary")) + enable_idx = 1; + + enable_status[enable_idx].probed = probe_status; + strncpy(enable_status[enable_idx].pname, display->name, + sizeof(enable_status[enable_idx].pname)); + DSI_DEBUG("display->drm_conn[%d] set: probe =%d, name =%s\n", + enable_idx, probe_status, display->name); +} + + +int dsi_display_trigger_panel_dead_event(struct dsi_display *display) +{ + bool panel_dead; + struct drm_event event; + struct drm_connector *drm_conn = display->drm_conn; + + panel_dead = true; + event.type = DRM_EVENT_PANEL_DEAD; + event.length = sizeof(u32); + msm_mode_object_event_notify(&drm_conn->base, + drm_conn->dev, &event, (u8 *)&panel_dead); + + DSI_WARN("ESD is not recovered. Start ESD recovery again\n"); + return 0; +} + +static int dsi_display_chk_esd_recovery(struct dsi_display *display) +{ + int ret = 0; + u32 status_mode; + static int disp_esd_trigger = 0; + + status_mode = display->panel->esd_config.status_mode; + if (status_mode == ESD_MODE_TE_CHK_REG_RD) { + /* + * ESD detection is to check the TE signal and reag_status + * therefore when disp_esd_chk_underway is set, which means the + * ESD recovery is running, therefore after the panel is on + * then check if the ESD detection can be recovered or not. + * if it is not, then trigger the ESD again + */ + disp_esd_trigger++; + if (dsi_display_status_check_te(display, 1) <= 0) { + DSI_ERR("ESD: TE Check is still failed. disp_esd_trigger=%d\n", + disp_esd_trigger); + } else if (dsi_display_status_reg_read(display) <= 0) { + DSI_ERR("ESD: REG_READ is still failed. disp_esd_trigger=%d\n", + disp_esd_trigger); + } else { + display->disp_esd_chk_underway = false; + DSI_INFO("ESD_MODE_TE_CHK_REG_RD is good\n"); + disp_esd_trigger = 0; + display->disp_esd_chk_underway = false; + } + + if (disp_esd_trigger > 0 && disp_esd_trigger < MAX_ESD_RECOVERY_RETRY) { + DSI_WARN("ESD: disp_esd_trigger=%d, trigger ESD again\n"); + dsi_display_trigger_panel_dead_event(display); + } else if (disp_esd_trigger >= MAX_ESD_RECOVERY_RETRY) { + DSI_ERR("ESD: disp_esd_trigger=%d is Max, calling BUG\n", + disp_esd_trigger); + BUG(); + } + ret = -EIO; + } else + ret = 0; + + return ret; +} + +static int dsi_display_enable_status (struct dsi_display *display, bool enable) +{ + int ret = 0; + + if (!strncmp("DSI-1", display->drm_conn->name, 5)) { + DSI_DEBUG("display->drm_conn->name=%s enable = %d MAIN_DISPLAY\n", + display->drm_conn->name, enable); + enable_status[0].display = display; + enable_status[0].enable = enable; + } else if (!strncmp("DSI-2", display->drm_conn->name, 5)) { + DSI_DEBUG("display->drm_conn->name=%s enable = %d CLI_DISPLAY\n", + display->drm_conn->name, enable); + enable_status[1].display = display; + enable_status[1].enable = enable; + } else { + DSI_ERR("display->drm_conn: invalid name =%s\n", + display->drm_conn->name); + ret = -EINVAL; + } + + return ret; +} + +bool dsi_display_is_panel_enable (int panel_index, int *probe_status, + char **pname) +{ + struct dsi_display *display; + bool enable = false; + + if (panel_index > 1) { + pr_err("display->drm_conn: invalid panel index =%d\n", + panel_index); + if (probe_status) + *probe_status = -ENODEV; + return false; + } + + if (probe_status) + *probe_status = enable_status[panel_index].probed; + if (pname) + *pname = &enable_status[panel_index].pname[0]; + + display = enable_status[panel_index].display; + if (display) { + mutex_lock(&display->display_lock); + enable = enable_status[panel_index].enable; + mutex_unlock(&display->display_lock); + } + + return enable; +} +EXPORT_SYMBOL(dsi_display_is_panel_enable); + int dsi_display_enable(struct dsi_display *display) { int rc = 0; @@ -8357,6 +9171,7 @@ int dsi_display_enable(struct dsi_display *display) return -EINVAL; } + dsi_display_enable_status(display, 1); display->panel->panel_initialized = true; DSI_DEBUG("cont splash enabled, display enable not required\n"); dsi_display_panel_id_notification(display); @@ -8383,17 +9198,30 @@ int dsi_display_enable(struct dsi_display *display) display->name, rc); goto error; } + dsi_panel_reset_param(display->panel); + + if (display->panel->dfps_caps.dfps_send_cmd_support) { + display->panel->dfps_caps.current_fps = display->panel->dfps_caps.panel_on_fps; + if (mode->timing.refresh_rate != display->panel->dfps_caps.panel_on_fps) { + DSI_INFO("[%s] dst_refresh_rate %d panel_on_fps %d\n", __func__, mode->timing.refresh_rate, display->panel->dfps_caps.panel_on_fps); + dsi_panel_dfps_send_cmd(display->panel); + } + } + + dsi_display_enable_status(display, true); } dsi_display_panel_id_notification(display); /* Block sending pps command if modeset is due to fps difference */ if ((mode->priv_info->dsc_enabled || mode->priv_info->vdc_enabled) && !(mode->dsi_mode_flags & DSI_MODE_FLAG_DMS_FPS)) { - rc = dsi_panel_update_pps(display->panel); - if (rc) { - DSI_ERR("[%s] panel pps cmd update failed, rc=%d\n", - display->name, rc); - goto error; + if(!mode->priv_info->panel_dsc_update_pps_disable){ + rc = dsi_panel_update_pps(display->panel); + if (rc) { + DSI_ERR("[%s] panel pps cmd update failed, rc=%d\n", + display->name, rc); + goto error; + } } } @@ -8428,6 +9256,10 @@ int dsi_display_enable(struct dsi_display *display) goto error_disable_panel; } + if (display->disp_esd_chk_underway) + if (dsi_display_chk_esd_recovery(display)) + goto error; + goto error; error_disable_panel: @@ -8449,6 +9281,9 @@ int dsi_display_post_enable(struct dsi_display *display) mutex_lock(&display->display_lock); + if (display->panel->panel_hbm_dim_off) + dsi_display_read_elvss_volt(display); + if (display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) { if (display->config.panel_mode == DSI_OP_CMD_MODE) dsi_panel_mode_switch_to_cmd(display->panel); @@ -8571,6 +9406,7 @@ int dsi_display_disable(struct dsi_display *display) return -EINVAL; } + DSI_INFO("%s(%s)+\n", __func__, display->drm_conn->name); SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); mutex_lock(&display->display_lock); @@ -8583,6 +9419,8 @@ int dsi_display_disable(struct dsi_display *display) if (rc) DSI_ERR("[%s] display wake up failed, rc=%d\n", display->name, rc); + else + dsi_display_enable_status(display, false); if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { rc = dsi_display_vid_engine_disable(display); diff --git a/techpack/display/msm/dsi/dsi_display.h b/techpack/display/msm/dsi/dsi_display.h index 8724178e0541..3c8e7a5ec36e 100644 --- a/techpack/display/msm/dsi/dsi_display.h +++ b/techpack/display/msm/dsi/dsi_display.h @@ -20,6 +20,8 @@ #include "dsi_ctrl.h" #include "dsi_phy.h" #include "dsi_panel.h" +#include "sde_connector.h" +#include "sde_motUtil.h" #define MAX_DSI_CTRLS_PER_DISPLAY 2 #define DSI_CLIENT_NAME_SIZE 20 @@ -270,6 +272,7 @@ struct dsi_display { bool misr_enable; u32 misr_frame_count; u32 esd_trigger; + bool disp_esd_chk_underway; /* multiple dsi error handlers */ struct workqueue_struct *err_workq; struct work_struct fifo_underflow_work; @@ -299,12 +302,13 @@ struct dsi_display { int tx_cmd_buf_ndx; struct dsi_panel_cmd_set cmd_set; - bool enabled; + u32 panel_idx; }; int dsi_display_dev_probe(struct platform_device *pdev); int dsi_display_dev_remove(struct platform_device *pdev); +void dsi_display_dev_shutdown(struct platform_device *pdev); /** * dsi_display_get_num_of_displays() - returns number of display devices @@ -596,6 +600,8 @@ int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type, enum dsi_lclk_type l_type, enum dsi_clk_state curr_state); +int dsi_display_set_param(void *display, struct msm_param_info *param_info); + /** * dsi_post_clkon_cb() - Callback after clock is turned on * @priv: private data pointer. @@ -701,6 +707,29 @@ int dsi_display_cmd_transfer(struct drm_connector *connector, */ int dsi_display_cmd_receive(void *display, const char *cmd_buf, u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len); +/** + * dsi_display_motUtil_transfer() - Convert motUtil data and transfer command + * to the panel + * @display: Handle to display. + * @cmd_buf: Command buffer + * @cmd_buf_len: Command buffer length in bytes + * @motUtil_data: motUtil data information + */ +int dsi_display_motUtil_transfer(void *display, const char *cmd_buf, + u32 cmd_buf_len, struct motUtil *motUtil_data); + +/** + * dsi_display_trigger_panel_dead_event() - Trigger ESD recovery + * + * @display: Handle to display. + */ +int dsi_display_trigger_panel_dead_event(struct dsi_display *display); +/** + * dsi_display_force_esd_disable() - check if ESD UTAG is forced to disable ESD + * @display: Handle to display. + */ +bool dsi_display_force_esd_disable(void *display); + /** * dsi_display_soft_reset() - perform a soft reset on DSI controller @@ -764,6 +793,20 @@ enum dsi_pixel_format dsi_display_get_dst_format( struct drm_connector *connector, void *display); +/* + * dsi_display_cmd_mipi_transfer() - Sending the MIPI DSI command + * @display: Handle to display + * @msg: MIPI DSI command information + * @flags: Modifier flags + * Return: if this is a MIPI DSI read then it will return number read byte + * in success case. Otherwise will be "<=0" + * if this is a MIPI DSI write then it will return "0" for success + * + */ +int dsi_display_cmd_mipi_transfer(struct dsi_display *display, + struct mipi_dsi_msg *msg, + u32 flags); + /** * dsi_display_cont_splash_config() - initialize splash resources * @display: Handle to display diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index becb218efc44..a3a5b5a53f39 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -11,13 +11,20 @@ #include #include