Loading Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +12 −5 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/video/msm/mdss/mdss_dsi.h +5 −2 Original line number Diff line number Diff line /* 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 Loading Loading @@ -461,8 +461,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; Loading drivers/video/msm/mdss/mdss_dsi_host.c +30 −13 Original line number Diff line number Diff line /* 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 Loading Loading @@ -1018,13 +1018,19 @@ 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; rc = 1; lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) { memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds = ctrl->status_cmds.cmds; cmdreq.cmds_cnt = ctrl->status_cmds.cmd_cnt; 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; cmdreq.rlen = ctrl->status_cmds_rlen[i]; cmdreq.cb = NULL; cmdreq.rbuf = ctrl->status_buf.data; Loading @@ -1033,7 +1039,18 @@ static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl) else if (ctrl->status_cmds.link_state == DSI_HS_MODE) cmdreq.flags |= CMD_REQ_HS_MODE; return mdss_dsi_cmdlist_put(ctrl, &cmdreq); 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; } Loading drivers/video/msm/mdss/mdss_dsi_panel.c +123 −23 Original line number Diff line number Diff line /* 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 Loading Loading @@ -1322,10 +1322,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; Loading Loading @@ -1460,10 +1485,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; Loading @@ -1479,37 +1555,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 { 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, tmp); 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->status_cmds_rlen); } memset(ctrl->status_value, 0, ctrl->groups * status_len); } ctrl->status_mode = ESD_MAX; Loading Loading @@ -1539,10 +1633,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 Loading
Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +12 −5 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/video/msm/mdss/mdss_dsi.h +5 −2 Original line number Diff line number Diff line /* 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 Loading Loading @@ -461,8 +461,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; Loading
drivers/video/msm/mdss/mdss_dsi_host.c +30 −13 Original line number Diff line number Diff line /* 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 Loading Loading @@ -1018,13 +1018,19 @@ 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; rc = 1; lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) { memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds = ctrl->status_cmds.cmds; cmdreq.cmds_cnt = ctrl->status_cmds.cmd_cnt; 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; cmdreq.rlen = ctrl->status_cmds_rlen[i]; cmdreq.cb = NULL; cmdreq.rbuf = ctrl->status_buf.data; Loading @@ -1033,7 +1039,18 @@ static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl) else if (ctrl->status_cmds.link_state == DSI_HS_MODE) cmdreq.flags |= CMD_REQ_HS_MODE; return mdss_dsi_cmdlist_put(ctrl, &cmdreq); 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; } Loading
drivers/video/msm/mdss/mdss_dsi_panel.c +123 −23 Original line number Diff line number Diff line /* 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 Loading Loading @@ -1322,10 +1322,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; Loading Loading @@ -1460,10 +1485,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; Loading @@ -1479,37 +1555,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 { 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, tmp); 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->status_cmds_rlen); } memset(ctrl->status_value, 0, ctrl->groups * status_len); } ctrl->status_mode = ESD_MAX; Loading Loading @@ -1539,10 +1633,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