msm: mdss: add multiple register support in ESD check
Current implementation cannot support multiple registers in ESD check, and it does not work for many cases. For example, some panels need check multiple registers to get its status, and some panels might return several possible values for one register read. To support this kind of behaviors, a new property in dtsi is added as "qcom,mdss-dsi-panel-status-valid-params" which specifies the valid value length we should check in the payload returned by panel, and the payload length panel should return is specified by the property "qcom,mdss-dsi- panel-status-read-length". "qcom,mdss-dsi-panel-status-value" is also extended to an array which specifies all the possible return values from panel. Change-Id: I098d04281b819581f53c7c509778e7b594aa499a Signed-off-by: Ray Zhang <rayz@codeaurora.org>
This commit is contained in:
parent
37563b3b8a
commit
1f05cf89cf
4 changed files with 170 additions and 43 deletions
|
@ -362,11 +362,18 @@ Optional properties:
|
|||
"reg_read_nt35596" = Reads panel status register to check the panel
|
||||
status for NT35596 panel.
|
||||
"te_signal_check" = Uses TE signal behaviour to check the panel status
|
||||
- qcom,mdss-dsi-panel-status-read-length: Integer value that specifies the expected read-back length of the
|
||||
panel register.
|
||||
- qcom,mdss-dsi-panel-status-value: An integer array that specifies the values of the panel status register
|
||||
which is used to check the panel status. The size of this array
|
||||
is specified by qcom,mdss-dsi-panel-status-read-length.
|
||||
- qcom,mdss-dsi-panel-status-read-length: Integer array that specify the expected read-back length of values
|
||||
for each of panel registers. Each length is corresponding to number of
|
||||
returned parameters of register introduced in specification.
|
||||
- qcom,mdss-dsi-panel-status-valid-params: Integer array that specify the valid returned values which need to check
|
||||
for each of register.
|
||||
Some panel need only check the first few values returned from panel.
|
||||
So: if this property is the same to qcom,mdss-dsi-panel-status-read-length,
|
||||
then just ignore this one.
|
||||
- qcom,mdss-dsi-panel-status-value: Multiple integer arrays, each specifies the values of the panel status register
|
||||
which is used to check the panel status. The size of each array is the sum of
|
||||
length specified in qcom,mdss-dsi-panel-status-read-length, and must be equal.
|
||||
This can cover that Some panel may return several alternative values.
|
||||
- qcom,mdss-dsi-panel-max-error-count: Integer value that specifies the maximum number of errors from register
|
||||
read that can be ignored before treating that the panel has gone bad.
|
||||
- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -451,8 +451,11 @@ struct mdss_dsi_ctrl_pdata {
|
|||
struct dsi_panel_cmds post_panel_on_cmds;
|
||||
struct dsi_panel_cmds off_cmds;
|
||||
struct dsi_panel_cmds status_cmds;
|
||||
u32 status_cmds_rlen;
|
||||
u32 *status_valid_params;
|
||||
u32 *status_cmds_rlen;
|
||||
u32 *status_value;
|
||||
unsigned char *return_buf;
|
||||
u32 groups; /* several alternative values to compare */
|
||||
u32 status_error_count;
|
||||
u32 max_status_error_count;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -1018,22 +1018,39 @@ void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata)
|
|||
|
||||
static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
int i, rc, *lenp;
|
||||
int start = 0;
|
||||
struct dcs_cmd_req cmdreq;
|
||||
|
||||
memset(&cmdreq, 0, sizeof(cmdreq));
|
||||
cmdreq.cmds = ctrl->status_cmds.cmds;
|
||||
cmdreq.cmds_cnt = ctrl->status_cmds.cmd_cnt;
|
||||
cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL | CMD_REQ_RX;
|
||||
cmdreq.rlen = ctrl->status_cmds_rlen;
|
||||
cmdreq.cb = NULL;
|
||||
cmdreq.rbuf = ctrl->status_buf.data;
|
||||
rc = 1;
|
||||
lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen;
|
||||
|
||||
if (ctrl->status_cmds.link_state == DSI_LP_MODE)
|
||||
cmdreq.flags |= CMD_REQ_LP_MODE;
|
||||
else if (ctrl->status_cmds.link_state == DSI_HS_MODE)
|
||||
cmdreq.flags |= CMD_REQ_HS_MODE;
|
||||
for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) {
|
||||
memset(&cmdreq, 0, sizeof(cmdreq));
|
||||
cmdreq.cmds = ctrl->status_cmds.cmds + i;
|
||||
cmdreq.cmds_cnt = 1;
|
||||
cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL | CMD_REQ_RX;
|
||||
cmdreq.rlen = ctrl->status_cmds_rlen[i];
|
||||
cmdreq.cb = NULL;
|
||||
cmdreq.rbuf = ctrl->status_buf.data;
|
||||
|
||||
return mdss_dsi_cmdlist_put(ctrl, &cmdreq);
|
||||
if (ctrl->status_cmds.link_state == DSI_LP_MODE)
|
||||
cmdreq.flags |= CMD_REQ_LP_MODE;
|
||||
else if (ctrl->status_cmds.link_state == DSI_HS_MODE)
|
||||
cmdreq.flags |= CMD_REQ_HS_MODE;
|
||||
|
||||
rc = mdss_dsi_cmdlist_put(ctrl, &cmdreq);
|
||||
if (rc <= 0) {
|
||||
pr_err("%s: get status: fail\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(ctrl->return_buf + start,
|
||||
ctrl->status_buf.data, lenp[i]);
|
||||
start += lenp[i];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -1328,10 +1328,35 @@ static int mdss_dsi_parse_reset_seq(struct device_node *np,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
int i, j;
|
||||
int len = 0, *lenp;
|
||||
int group = 0;
|
||||
|
||||
lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen;
|
||||
|
||||
for (i = 0; i < ctrl->status_cmds.cmd_cnt; i++)
|
||||
len += lenp[i];
|
||||
|
||||
for (j = 0; j < ctrl->groups; ++j) {
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (ctrl->return_buf[i] !=
|
||||
ctrl->status_value[group + i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
return true;
|
||||
group += len;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int mdss_dsi_gen_read_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
||||
{
|
||||
if (!mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf,
|
||||
ctrl_pdata->status_value, 0)) {
|
||||
if (!mdss_dsi_cmp_panel_reg_v2(ctrl_pdata)) {
|
||||
pr_err("%s: Read back value from panel is incorrect\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
|
@ -1466,10 +1491,61 @@ exit:
|
|||
return;
|
||||
}
|
||||
|
||||
/* the length of all the valid values to be checked should not be great
|
||||
* than the length of returned data from read command.
|
||||
*/
|
||||
static bool
|
||||
mdss_dsi_parse_esd_check_valid_params(struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) {
|
||||
if (ctrl->status_valid_params[i] > ctrl->status_cmds_rlen[i]) {
|
||||
pr_debug("%s: ignore valid params!\n", __func__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool mdss_dsi_parse_esd_status_len(struct device_node *np,
|
||||
char *prop_key, u32 **target, u32 cmd_cnt)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if (!of_find_property(np, prop_key, &tmp))
|
||||
return false;
|
||||
|
||||
tmp /= sizeof(u32);
|
||||
if (tmp != cmd_cnt) {
|
||||
pr_err("%s: request property number(%d) not match command count(%d)\n",
|
||||
__func__, tmp, cmd_cnt);
|
||||
return false;
|
||||
}
|
||||
|
||||
*target = kcalloc(tmp, sizeof(u32), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(*target)) {
|
||||
pr_err("%s: Error allocating memory for property\n",
|
||||
__func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(np, prop_key, *target, tmp)) {
|
||||
pr_err("%s: cannot get values from dts\n", __func__);
|
||||
kfree(*target);
|
||||
*target = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mdss_dsi_parse_esd_params(struct device_node *np,
|
||||
struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
u32 tmp;
|
||||
u32 i, status_len, *lenp;
|
||||
int rc;
|
||||
struct property *data;
|
||||
const char *string;
|
||||
|
@ -1485,37 +1561,55 @@ static void mdss_dsi_parse_esd_params(struct device_node *np,
|
|||
"qcom,mdss-dsi-panel-status-command",
|
||||
"qcom,mdss-dsi-panel-status-command-state");
|
||||
|
||||
rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-status-read-length",
|
||||
&tmp);
|
||||
ctrl->status_cmds_rlen = (!rc ? tmp : 1);
|
||||
|
||||
rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-max-error-count",
|
||||
&tmp);
|
||||
ctrl->max_status_error_count = (!rc ? tmp : 0);
|
||||
|
||||
ctrl->status_value = kzalloc(sizeof(u32) * ctrl->status_cmds_rlen,
|
||||
GFP_KERNEL);
|
||||
if (!ctrl->status_value) {
|
||||
pr_err("%s: Error allocating memory for status buffer\n",
|
||||
__func__);
|
||||
if (!mdss_dsi_parse_esd_status_len(np,
|
||||
"qcom,mdss-dsi-panel-status-read-length",
|
||||
&ctrl->status_cmds_rlen, ctrl->status_cmds.cmd_cnt)) {
|
||||
pinfo->esd_check_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mdss_dsi_parse_esd_status_len(np,
|
||||
"qcom,mdss-dsi-panel-status-valid-params",
|
||||
&ctrl->status_valid_params, ctrl->status_cmds.cmd_cnt)) {
|
||||
if (!mdss_dsi_parse_esd_check_valid_params(ctrl))
|
||||
goto error1;
|
||||
}
|
||||
|
||||
status_len = 0;
|
||||
lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen;
|
||||
for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i)
|
||||
status_len += lenp[i];
|
||||
|
||||
data = of_find_property(np, "qcom,mdss-dsi-panel-status-value", &tmp);
|
||||
tmp /= sizeof(u32);
|
||||
if (!data || (tmp != ctrl->status_cmds_rlen)) {
|
||||
pr_debug("%s: Panel status values not found\n", __func__);
|
||||
memset(ctrl->status_value, 0, ctrl->status_cmds_rlen);
|
||||
if (!IS_ERR_OR_NULL(data) && tmp != 0 && (tmp % status_len) == 0) {
|
||||
ctrl->groups = tmp / status_len;
|
||||
} else {
|
||||
rc = of_property_read_u32_array(np,
|
||||
"qcom,mdss-dsi-panel-status-value",
|
||||
ctrl->status_value, tmp);
|
||||
if (rc) {
|
||||
pr_debug("%s: Error reading panel status values\n",
|
||||
__func__);
|
||||
memset(ctrl->status_value, 0, ctrl->status_cmds_rlen);
|
||||
}
|
||||
pr_err("%s: Error parse panel-status-value\n", __func__);
|
||||
goto error1;
|
||||
}
|
||||
|
||||
ctrl->status_value = kzalloc(sizeof(u32) * status_len * ctrl->groups,
|
||||
GFP_KERNEL);
|
||||
if (!ctrl->status_value)
|
||||
goto error1;
|
||||
|
||||
ctrl->return_buf = kcalloc(status_len * ctrl->groups,
|
||||
sizeof(unsigned char), GFP_KERNEL);
|
||||
if (!ctrl->return_buf)
|
||||
goto error2;
|
||||
|
||||
rc = of_property_read_u32_array(np,
|
||||
"qcom,mdss-dsi-panel-status-value",
|
||||
ctrl->status_value, ctrl->groups * status_len);
|
||||
if (rc) {
|
||||
pr_debug("%s: Error reading panel status values\n",
|
||||
__func__);
|
||||
memset(ctrl->status_value, 0, ctrl->groups * status_len);
|
||||
}
|
||||
|
||||
ctrl->status_mode = ESD_MAX;
|
||||
|
@ -1545,10 +1639,16 @@ static void mdss_dsi_parse_esd_params(struct device_node *np,
|
|||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
kfree(ctrl->return_buf);
|
||||
error2:
|
||||
kfree(ctrl->status_value);
|
||||
error1:
|
||||
kfree(ctrl->status_valid_params);
|
||||
kfree(ctrl->status_cmds_rlen);
|
||||
pinfo->esd_check_enabled = false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue