From fa247f6d83657fb0380a56f74c044fae0994b4d7 Mon Sep 17 00:00:00 2001 From: Bang Nguyen Date: Wed, 31 Jul 2019 12:58:34 -0500 Subject: [PATCH] disp: msm: add panel's param feature to display FW Add the display's param feature such as HBM, ACL, or CABC feature to display framework Port from: f988eb8 Change-Id: I445ea7e58188d2354888e2202ed7119bf2e55fc9 Signed-off-by: Bang Nguyen Reviewed-on: https://gerrit.mot.com/1444400 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Submit-Approved: Jira Key Reviewed-on: https://gerrit.mot.com/1509802 Reviewed-by: Hua Tan --- msm/dsi/dsi_defs.h | 4 + msm/dsi/dsi_display.c | 22 +++++ msm/dsi/dsi_display.h | 2 + msm/dsi/dsi_panel.c | 175 ++++++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_panel.h | 30 ++++++- msm/msm_drv.h | 13 +++ msm/sde/sde_connector.c | 73 +++++++++++++++++ msm/sde/sde_connector.h | 7 ++ msm/sde/sde_kms.c | 3 + 9 files changed, 328 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 5179edfebd02..979a60254dbf 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -281,6 +281,8 @@ 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_ON: Turning HBM on + * @DSI_CMD_SET_HBM_OFF: Turning HBM off * @DSI_CMD_SET_MAX */ enum dsi_cmd_set_type { @@ -307,6 +309,8 @@ 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_ON, + DSI_CMD_SET_HBM_OFF, DSI_CMD_SET_MAX }; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 03f7ca1ab4a1..c13dab6a23ab 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -246,6 +246,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; diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index ea65e6b68a77..9537ab435f10 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -563,6 +563,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. diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 30f7fb4b66a0..52cbef5f41af 100755 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -101,6 +101,15 @@ static char dsi_dsc_rc_range_max_qp_1_1_scr1[][15] = { static char dsi_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}; +static struct panel_param_val_map hbm_map[HBM_STATE_NUM] = { + {HBM_OFF_STATE, DSI_CMD_SET_HBM_OFF, NULL}, + {HBM_ON_STATE, DSI_CMD_SET_HBM_ON, NULL}, +}; + +static struct panel_param dsi_panel_param[PARAM_ID_NUM] = { + {"HBM", hbm_map, HBM_STATE_NUM, HBM_OFF_STATE, HBM_OFF_STATE, false}, +}; + int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, char *buf, int pps_id) { @@ -830,6 +839,100 @@ static int dsi_panel_pwm_register(struct dsi_panel *panel) return 0; } +static int dsi_panel_send_param_cmd (struct dsi_panel *panel, + struct msm_param_info *param_info) +{ + int rc = 0; + struct panel_param_val_map *param_map; + struct panel_param_val_map *param_map_state; + struct panel_param *panel_param; + struct dsi_cmd_desc *cmds; + ssize_t len; + const struct mipi_dsi_host_ops *ops = panel->host->ops; + + panel_param = &panel->param_cmds[param_info->param_idx]; + if (!panel_param) { + DSI_ERR("%s: invalid panel_param.\n", __func__); + return -EINVAL; + } + + param_map = panel_param->val_map; + + DSI_DEBUG("%s: param_name=%s; val_max =%d, default_value=%d, value=%d\n", + __func__, panel_param->param_name, panel_param->val_max, + panel_param->default_value, panel_param->value); + + mutex_lock(&panel->panel_lock); + if (panel_param->value == param_info->value) + { + DSI_INFO("%s(mode=%d): requested value=%d is same. Do nothing\n", + __func__, param_info->param_idx, param_info->value); + rc = 0; + } else { + DSI_DEBUG("%s: requested: old=%d new=%d.\n", __func__, + panel_param->value, param_info->value); + param_map = panel->param_cmds[param_info->param_idx].val_map; + param_map_state = ¶m_map[param_info->value]; + + cmds = param_map_state->cmds->cmds; + if (param_map_state->cmds->state == DSI_CMD_SET_STATE_LP) + cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM | + MIPI_DSI_MSG_LASTCOMMAND; + len = ops->transfer(panel->host, &cmds->msg); + if (len < 0) { + rc = len; + DSI_ERR("%s:failed to send param cmd, rc=%d\n", + __func__, rc); + goto end; + } + + panel_param->value = param_info->value; + DSI_INFO("%s(%d) is setting new value %d\n", __func__, + param_info->param_idx, param_info->value); + rc = len; + } + +end: + mutex_unlock(&panel->panel_lock); + return rc; +}; + +static int dsi_panel_set_hbm(struct dsi_panel *panel, + struct msm_param_info *param_info) +{ + int rc = 0; + + pr_info("%s(%d)\n", __func__, param_info->value); + rc = dsi_panel_send_param_cmd(panel, param_info); + if (rc < 0) + DSI_ERR("%s: failed to send param cmds. ret=%d\n", __func__, rc); + + return rc; +}; + +int dsi_panel_set_param(struct dsi_panel *panel, + struct msm_param_info *param_info) +{ + int rc = 0; + + if (!panel || !param_info) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + DSI_DEBUG("%s+\n", __func__); + + if (param_info->param_idx == PARAM_HBM_ID) + rc = dsi_panel_set_hbm(panel, param_info); + else { + DSI_ERR("%s: Invalid set_param type=%d\n", + __func__, param_info->param_idx); + rc = -EINVAL; + } + + return rc; +} + static int dsi_panel_bl_register(struct dsi_panel *panel) { int rc = 0; @@ -1888,6 +1991,9 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-post-mode-switch-on-command", "qcom,mdss-dsi-qsync-on-commands", "qcom,mdss-dsi-qsync-off-commands", + "qcom,mdss-dsi-hbm-on-command", + "qcom,mdss-dsi-hbm-off-command", + }; const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { @@ -1914,6 +2020,8 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-post-mode-switch-on-command-state", "qcom,mdss-dsi-qsync-on-commands-state", "qcom,mdss-dsi-qsync-off-commands-state", + "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-hbm-off-command-state", }; static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt) @@ -3429,6 +3537,68 @@ end: utils->node = panel->panel_of_node; } +static int dsi_panel_parse_param_prop(struct dsi_panel *panel, + struct device_node *of_node) +{ + int i, j, rc =0; + struct panel_param *param; + struct panel_param_val_map *param_map; + struct dsi_panel_cmd_set *cmds; + enum dsi_cmd_set_type type; + const char *prop; + struct dsi_parser_utils *utils = &panel->utils; + + for (i = 0; i < PARAM_ID_NUM; i++) { + param = &dsi_panel_param[i]; + + for (j = 0; j < param->val_max; j++) { + param_map = ¶m->val_map[j]; + param_map->cmds = NULL; + cmds = kcalloc(param->val_max, + sizeof(struct dsi_panel_cmd_set), GFP_KERNEL); + if (cmds == NULL) { + rc = -ENOMEM; + goto err; + } + + param_map->cmds = cmds; + type = param_map->type; + prop = cmd_set_prop_map[type]; + if (!prop) + continue; + + rc = dsi_panel_parse_cmd_sets_sub(param_map->cmds, + type, utils); + if (rc) { + DSI_ERR("panel param cmd %s parsing failed\n", + param->param_name); + rc = -EINVAL; + goto parse_err; + } + } + + param->is_supported = true; + DSI_INFO("%s: feature enabled.\n", param->param_name); + } + + return rc; + +parse_err: + for (i = 0; i < ARRAY_SIZE(dsi_panel_param); i++) { + param = &dsi_panel_param[i]; + for (j = 0; j < param->val_max; j++) { + if (param->val_map[j].cmds) { + kfree(param->val_map[j].cmds); + param->val_map[j].cmds= NULL; + } + } + param->is_supported = false; + } +err: + return rc; + +} + static int dsi_panel_parse_mot_panel_config(struct dsi_panel *panel, struct device_node *of_node) { @@ -3555,6 +3725,11 @@ struct dsi_panel *dsi_panel_get(struct device *parent, if (rc) DSI_DEBUG("failed to parse mot_panel_config, rc = %d\n", rc); + panel->param_cmds = &dsi_panel_param[0]; + rc = dsi_panel_parse_param_prop(panel, of_node); + if (rc) + pr_debug("failed to parse panel param prop, rc =%d\n", rc); + rc = dsi_panel_parse_host_config(panel); if (rc) { DSI_ERR("failed to parse host configuration, rc=%d\n", diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index ccc90c5bd32b..dbdcb1ad94b2 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -28,7 +28,6 @@ #define DSI_MODE_MAX 32 -#define DSI_PANEL_MAX_PANEL_LEN 256 /* * Defining custom dsi msg flag, @@ -37,6 +36,9 @@ */ #define MIPI_DSI_MSG_ASYNC_OVERRIDE BIT(4) +#define DSI_PANEL_MAX_PANEL_LEN 256 +#define MAX_PARAM_NAME 10 + enum dsi_panel_rotation { DSI_PANEL_ROTATE_NONE = 0, DSI_PANEL_ROTATE_HV_FLIP, @@ -176,6 +178,27 @@ struct drm_panel_esd_config { u32 groups; }; +enum hbm_state { + HBM_OFF_STATE = 0, + HBM_ON_STATE, + HBM_STATE_NUM +}; + +struct panel_param_val_map { + int state; + enum dsi_cmd_set_type type; + struct dsi_panel_cmd_set *cmds; +}; + +struct panel_param { + const char *param_name; + struct panel_param_val_map *val_map; + const u16 val_max; + const u16 default_value; + u16 value; + bool is_supported; +}; + struct dsi_panel { const char *name; const char *type; @@ -236,6 +259,8 @@ struct dsi_panel { u32 disp_on_chk_val; bool no_panel_on_read_support; + + struct panel_param *param_cmds; }; static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel) @@ -356,4 +381,7 @@ void dsi_panel_ext_bridge_put(struct dsi_panel *panel); void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, struct dsi_display_mode *mode, u32 frame_threshold_us); +int dsi_panel_set_param(struct dsi_panel *panel, + struct msm_param_info *param_info); + #endif /* _DSI_PANEL_H_ */ diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 4ba732d86d7c..44210badce15 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -202,6 +202,8 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_QSYNC_MODE, CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE, + /* MOT feature panel*/ + CONNECTOR_PROP_HBM, /* total # of properties */ CONNECTOR_PROP_COUNT }; @@ -310,6 +312,17 @@ struct msm_roi_caps { struct msm_roi_alignment align; }; +enum msm_param_id { + PARAM_HBM_ID = 0, + PARAM_ID_NUM +}; + +struct msm_param_info { + enum msm_param_id param_idx; + enum msm_mdp_conn_property param_conn_idx; + int value; +}; + /** * struct msm_display_dsc_info - defines dsc configuration * @version: DSC version. diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index a470f0cc52ca..0f53f9da4ec9 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -692,6 +692,24 @@ static int _sde_connector_update_hdr_metadata(struct sde_connector *c_conn, return rc; } +static int _sde_connector_update_param(struct sde_connector *c_conn, + struct msm_param_info *param_info) +{ + struct dsi_display *dsi_display; + int rc = 0; + + if (!c_conn) { + SDE_ERROR("Invalid params sde_connector null\n"); + return -EINVAL; + } + + dsi_display = c_conn->display; + if (dsi_display && c_conn->ops.set_param) + rc = c_conn->ops.set_param(dsi_display, param_info); + + return rc; +} + static int _sde_connector_update_dirty_properties( struct drm_connector *connector) { @@ -1362,6 +1380,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, int idx, rc; uint64_t fence_user_fd; uint64_t __user prev_user_fd; + struct msm_param_info param_info; if (!connector || !state || !property) { SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n", @@ -1471,6 +1490,13 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, msm_property_set_dirty(&c_conn->property_info, &c_state->property_state, idx); break; + case CONNECTOR_PROP_HBM: + param_info.value = sde_connector_get_property( + connector->state, CONNECTOR_PROP_HBM); + param_info.param_idx = PARAM_HBM_ID; + param_info.param_conn_idx = CONNECTOR_PROP_HBM; + _sde_connector_update_param(c_conn, ¶m_info); + break; default: break; } @@ -2353,6 +2379,45 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn, return rc; } +static int sde_connector_install_panel_params(struct sde_connector *c_conn) +{ + struct panel_param *param_cmds; + uint32_t prop_idx; + int i; + struct dsi_display *dsi_display; + + + if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return 0; + + dsi_display = (struct dsi_display *) (c_conn->display); + param_cmds = dsi_display->panel->param_cmds; + for (i = 0; i < PARAM_ID_NUM; i++) { + SDE_DEBUG("%s:i = %d param_name = %s is_support=%d\n", + __func__, i, + param_cmds->param_name, param_cmds->is_supported); + + if (!strncmp(param_cmds->param_name, "HBM", 3)) + prop_idx = CONNECTOR_PROP_HBM; + else { + SDE_ERROR("Invalid param_name =%s\n", + param_cmds->param_name); + return -EINVAL; + } + + if (param_cmds->is_supported) + msm_property_install_volatile_range( + &c_conn->property_info, + param_cmds->param_name, + 0x0, 0, param_cmds->val_max, + param_cmds->default_value, prop_idx); + + param_cmds++; + } + + return 0; +} + int sde_connector_set_blob_data(struct drm_connector *conn, struct drm_connector_state *state, enum msm_mdp_conn_property prop_id) @@ -2683,6 +2748,14 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, } } + rc = sde_connector_install_panel_params(c_conn); + if (rc) { + SDE_ERROR_CONN(c_conn, + "failed to install property for panel params. rc =%d\n", + rc); + goto error_cleanup_fence; + } + rc = sde_connector_get_info(&c_conn->base, &display_info); if (!rc && (connector_type == DRM_MODE_CONNECTOR_DSI) && (display_info.capabilities & MSM_DISPLAY_CAP_VID_MODE)) diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index c2c21428e453..0c9cef26cc27 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -284,6 +284,13 @@ struct sde_connector_ops { */ bool (*force_esd_disable)(void *display); + /** + * set_param - set display's feature param setting + * @display: Pointer to private display handle + * Returns: Zero for success, negative for failure + */ + int (*set_param)(void *display, struct msm_param_info *param_info); + /** * config_hdr - configure HDR * @connector: Pointer to drm connector structure diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 4ba78711d45d..fd91532fd91d 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1438,6 +1438,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .motUtil_transfer = dsi_display_motUtil_transfer, .cmd_transfer = dsi_display_cmd_transfer, .force_esd_disable = dsi_display_force_esd_disable, + .set_param = dsi_display_set_param, .cont_splash_config = dsi_display_cont_splash_config, .get_panel_vfp = dsi_display_get_panel_vfp, .get_default_lms = dsi_display_get_default_lms, @@ -1456,6 +1457,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .check_status = NULL, .cmd_transfer = NULL, .force_esd_disable = NULL, + .set_param = NULL, .cont_splash_config = NULL, .get_panel_vfp = NULL, }; @@ -1474,6 +1476,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .config_hdr = dp_connector_config_hdr, .cmd_transfer = NULL, .force_esd_disable = NULL, + .set_param = NULL, .cont_splash_config = NULL, .get_panel_vfp = NULL, .update_pps = dp_connector_update_pps,