Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7e79bc4 authored by Shashank Babu Chinta Venkata's avatar Shashank Babu Chinta Venkata
Browse files

drm/msm/dsi-staging: add debugfs support to switch panel esd check mode



Panel ESD check mode is statically defined in device tree.
This change adds support to dynamically alter this mode from
debugfs node.

For example, the debugfs node for ESD check mode will be
available at /<debugfs-root>/<active display>/esd_check_mode

Commands for altering ESD check mode:

For register read based ESD check:
"echo reg_read> /d/dsi_nt35597_truly_dsc_cmd_display/esd_check_mode"
For panel TE based ESD check:
"echo te_signal_check> /d/dsi_nt35597_truly_dsc_cmd_display/esd_check_mode"

Change-Id: I6f8fbe180c1068d09acb9a5b8696c372ac19df9b
Signed-off-by: default avatarShashank Babu Chinta Venkata <sbchin@codeaurora.org>
parent 85a10b57
Loading
Loading
Loading
Loading
+175 −27
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@
#define NO_OVERRIDE -1
#define NO_OVERRIDE -1


#define MISR_BUFF_SIZE	256
#define MISR_BUFF_SIZE	256
#define ESD_MODE_STRING_MAX_LEN 256


#define MAX_NAME_SIZE	64
#define MAX_NAME_SIZE	64


@@ -1027,6 +1028,71 @@ static ssize_t debugfs_misr_setup(struct file *file,
	return rc;
	return rc;
}
}


static ssize_t debugfs_misr_read(struct file *file,
				 char __user *user_buf,
				 size_t user_len,
				 loff_t *ppos)
{
	struct dsi_display *display = file->private_data;
	char *buf;
	u32 len = 0;
	int rc = 0;
	struct dsi_ctrl *dsi_ctrl;
	int i;
	u32 misr;
	size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE);

	if (!display)
		return -ENODEV;

	if (*ppos)
		return 0;

	buf = kzalloc(max_len, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	mutex_lock(&display->display_lock);
	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
			DSI_CORE_CLK, DSI_CLK_ON);
	if (rc) {
		pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
		       display->name, rc);
		goto error;
	}

	for (i = 0; i < display->ctrl_count; i++) {
		dsi_ctrl = display->ctrl[i].ctrl;
		misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl);

		len += snprintf((buf + len), max_len - len,
			"DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr);

		if (len >= max_len)
			break;
	}

	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
			DSI_CORE_CLK, DSI_CLK_OFF);
	if (rc) {
		pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
		       display->name, rc);
		goto error;
	}

	if (copy_to_user(user_buf, buf, len)) {
		rc = -EFAULT;
		goto error;
	}

	*ppos += len;

error:
	mutex_unlock(&display->display_lock);
	kfree(buf);
	return len;
}

static ssize_t debugfs_esd_trigger_check(struct file *file,
static ssize_t debugfs_esd_trigger_check(struct file *file,
				  const char __user *user_buf,
				  const char __user *user_buf,
				  size_t user_len,
				  size_t user_len,
@@ -1083,19 +1149,16 @@ static ssize_t debugfs_esd_trigger_check(struct file *file,
	return rc;
	return rc;
}
}


static ssize_t debugfs_misr_read(struct file *file,
static ssize_t debugfs_alter_esd_check_mode(struct file *file,
				 char __user *user_buf,
				  const char __user *user_buf,
				  size_t user_len,
				  size_t user_len,
				  loff_t *ppos)
				  loff_t *ppos)
{
{
	struct dsi_display *display = file->private_data;
	struct dsi_display *display = file->private_data;
	struct drm_panel_esd_config *esd_config;
	char *buf;
	char *buf;
	u32 len = 0;
	int rc = 0;
	int rc = 0;
	struct dsi_ctrl *dsi_ctrl;
	size_t len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN);
	int i;
	u32 misr;
	size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE);


	if (!display)
	if (!display)
		return -ENODEV;
		return -ENODEV;
@@ -1103,35 +1166,103 @@ static ssize_t debugfs_misr_read(struct file *file,
	if (*ppos)
	if (*ppos)
		return 0;
		return 0;


	buf = kzalloc(max_len, GFP_KERNEL);
	buf = kzalloc(len, GFP_KERNEL);
	if (!buf)
	if (!buf)
		return -ENOMEM;
		return -ENOMEM;


	mutex_lock(&display->display_lock);
	if (copy_from_user(buf, user_buf, user_len)) {
	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
		rc = -EINVAL;
			DSI_CORE_CLK, DSI_CLK_ON);
	if (rc) {
		pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
		       display->name, rc);
		goto error;
		goto error;
	}
	}


	for (i = 0; i < display->ctrl_count; i++) {
	buf[len] = '\0'; /* terminate the string */
		dsi_ctrl = display->ctrl[i].ctrl;
	if (!display->panel) {
		misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl);
		rc = -EINVAL;
		goto error;
	}


		len += snprintf((buf + len), max_len - len,
	esd_config = &display->panel->esd_config;
			"DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr);
	if (!esd_config) {
		pr_err("Invalid panel esd config\n");
		rc = -EINVAL;
		goto error;
	}


		if (len >= max_len)
	if (!esd_config->esd_enabled)
			break;
		goto error;

	if (!strcmp(buf, "te_signal_check\n")) {
		esd_config->status_mode = ESD_MODE_PANEL_TE;
		dsi_display_change_te_irq_status(display, true);
	}
	}


	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
	if (!strcmp(buf, "reg_read\n")) {
			DSI_CORE_CLK, DSI_CLK_OFF);
		rc = dsi_panel_parse_esd_reg_read_configs(display->panel,
						display->panel_of);
		if (rc) {
		if (rc) {
		pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
			pr_err("failed to alter esd check mode,rc=%d\n",
		       display->name, rc);
						rc);
			rc = user_len;
			goto error;
		}
		esd_config->status_mode = ESD_MODE_REG_READ;
		if (dsi_display_is_te_based_esd(display))
			dsi_display_change_te_irq_status(display, false);
	}

	rc = len;
error:
	kfree(buf);
	return rc;
}

static ssize_t debugfs_read_esd_check_mode(struct file *file,
				 char __user *user_buf,
				 size_t user_len,
				 loff_t *ppos)
{
	struct dsi_display *display = file->private_data;
	struct drm_panel_esd_config *esd_config;
	char *buf;
	int rc = 0;
	size_t len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN);

	if (!display)
		return -ENODEV;

	if (*ppos)
		return 0;

	if (!display->panel) {
		pr_err("invalid panel data\n");
		return -EINVAL;
	}

	buf = kzalloc(len, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	esd_config = &display->panel->esd_config;
	if (!esd_config) {
		pr_err("Invalid panel esd config\n");
		rc = -EINVAL;
		goto error;
	}

	if (!esd_config->esd_enabled) {
		rc = snprintf(buf, len, "ESD feature not enabled");
		goto output_mode;
	}

	if (esd_config->status_mode == ESD_MODE_REG_READ)
		rc = snprintf(buf, len, "reg_read");

	if (esd_config->status_mode == ESD_MODE_PANEL_TE)
		rc = snprintf(buf, len, "te_signal_check");

output_mode:
	if (!rc) {
		rc = -EINVAL;
		goto error;
		goto error;
	}
	}


@@ -1143,7 +1274,6 @@ static ssize_t debugfs_misr_read(struct file *file,
	*ppos += len;
	*ppos += len;


error:
error:
	mutex_unlock(&display->display_lock);
	kfree(buf);
	kfree(buf);
	return len;
	return len;
}
}
@@ -1164,6 +1294,12 @@ static const struct file_operations esd_trigger_fops = {
	.write = debugfs_esd_trigger_check,
	.write = debugfs_esd_trigger_check,
};
};


static const struct file_operations esd_check_mode_fops = {
	.open = simple_open,
	.write = debugfs_alter_esd_check_mode,
	.read = debugfs_read_esd_check_mode,
};

static int dsi_display_debugfs_init(struct dsi_display *display)
static int dsi_display_debugfs_init(struct dsi_display *display)
{
{
	int rc = 0;
	int rc = 0;
@@ -1203,6 +1339,18 @@ static int dsi_display_debugfs_init(struct dsi_display *display)
		goto error_remove_dir;
		goto error_remove_dir;
	}
	}


	dump_file = debugfs_create_file("esd_check_mode",
					0644,
					dir,
					display,
					&esd_check_mode_fops);
	if (IS_ERR_OR_NULL(dump_file)) {
		rc = PTR_ERR(dump_file);
		pr_err("[%s] debugfs for esd check mode failed, rc=%d\n",
		       display->name, rc);
		goto error_remove_dir;
	}

	misr_data = debugfs_create_file("misr_data",
	misr_data = debugfs_create_file("misr_data",
					0600,
					0600,
					dir,
					dir,
+76 −50
Original line number Original line Diff line number Diff line
@@ -2580,54 +2580,23 @@ static void dsi_panel_esd_config_deinit(struct drm_panel_esd_config *esd_config)
	kfree(esd_config->status_cmd.cmds);
	kfree(esd_config->status_cmd.cmds);
}
}


static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel,
				struct device_node *of_node)
				struct device_node *of_node)
{
{
	struct drm_panel_esd_config *esd_config;
	int rc = 0;
	int rc = 0;
	u32 tmp;
	u32 tmp;
	u32 i, status_len, *lenp;
	u32 i, status_len, *lenp;
	struct property *data;
	struct property *data;
	const char *string;
	struct drm_panel_esd_config *esd_config;
	u8 *esd_mode = NULL;

	esd_config = &panel->esd_config;
	esd_config->status_mode = ESD_MODE_MAX;
	esd_config->esd_enabled = of_property_read_bool(of_node,
		"qcom,esd-check-enabled");


	if (!esd_config->esd_enabled)
	if (!panel || !of_node) {
		return 0;
		pr_err("Invalid Params\n");

		return -EINVAL;
	rc = of_property_read_string(of_node,
			"qcom,mdss-dsi-panel-status-check-mode", &string);
	if (!rc) {
		if (!strcmp(string, "bta_check")) {
			esd_config->status_mode = ESD_MODE_SW_BTA;
		} else if (!strcmp(string, "reg_read")) {
			esd_config->status_mode = ESD_MODE_REG_READ;
		} else if (!strcmp(string, "te_signal_check")) {
			if (panel->panel_mode == DSI_OP_CMD_MODE) {
				esd_config->status_mode = ESD_MODE_PANEL_TE;
			} else {
				pr_err("TE-ESD not valid for video mode\n");
				rc = -EINVAL;
				goto error;
			}
		} else {
			pr_err("No valid panel-status-check-mode string\n");
			rc = -EINVAL;
			goto error;
		}
	} else {
		pr_debug("status check method not defined!\n");
		rc = -EINVAL;
		goto error;
	}
	}


	if ((esd_config->status_mode == ESD_MODE_SW_BTA) ||
	esd_config = &panel->esd_config;
		(esd_config->status_mode == ESD_MODE_PANEL_TE))
	if (!esd_config)
		return 0;
		return -EINVAL;


	dsi_panel_parse_cmd_sets_sub(&esd_config->status_cmd,
	dsi_panel_parse_cmd_sets_sub(&esd_config->status_cmd,
				DSI_CMD_SET_PANEL_STATUS, of_node);
				DSI_CMD_SET_PANEL_STATUS, of_node);
@@ -2702,8 +2671,10 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
	}
	}


	esd_config->status_buf = kzalloc(SZ_4K, GFP_KERNEL);
	esd_config->status_buf = kzalloc(SZ_4K, GFP_KERNEL);
	if (!esd_config->status_buf)
	if (!esd_config->status_buf) {
		rc = -ENOMEM;
		goto error4;
		goto error4;
	}


	rc = of_property_read_u32_array(of_node,
	rc = of_property_read_u32_array(of_node,
		"qcom,mdss-dsi-panel-status-value",
		"qcom,mdss-dsi-panel-status-value",
@@ -2714,15 +2685,6 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
				esd_config->groups * status_len);
				esd_config->groups * status_len);
	}
	}


	if (panel->esd_config.status_mode == ESD_MODE_REG_READ)
		esd_mode = "register_read";
	else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA)
		esd_mode = "bta_trigger";
	else if (panel->esd_config.status_mode ==  ESD_MODE_PANEL_TE)
		esd_mode = "te_check";

	pr_info("ESD enabled with mode: %s\n", esd_mode);

	return 0;
	return 0;


error4:
error4:
@@ -2734,6 +2696,70 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
	kfree(esd_config->status_cmds_rlen);
	kfree(esd_config->status_cmds_rlen);
error1:
error1:
	kfree(esd_config->status_cmd.cmds);
	kfree(esd_config->status_cmd.cmds);
error:
	return rc;
}

static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
				     struct device_node *of_node)
{
	int rc = 0;
	const char *string;
	struct drm_panel_esd_config *esd_config;
	u8 *esd_mode = NULL;

	esd_config = &panel->esd_config;
	esd_config->status_mode = ESD_MODE_MAX;
	esd_config->esd_enabled = of_property_read_bool(of_node,
		"qcom,esd-check-enabled");

	if (!esd_config->esd_enabled)
		return 0;

	rc = of_property_read_string(of_node,
			"qcom,mdss-dsi-panel-status-check-mode", &string);
	if (!rc) {
		if (!strcmp(string, "bta_check")) {
			esd_config->status_mode = ESD_MODE_SW_BTA;
		} else if (!strcmp(string, "reg_read")) {
			esd_config->status_mode = ESD_MODE_REG_READ;
		} else if (!strcmp(string, "te_signal_check")) {
			if (panel->panel_mode == DSI_OP_CMD_MODE) {
				esd_config->status_mode = ESD_MODE_PANEL_TE;
			} else {
				pr_err("TE-ESD not valid for video mode\n");
				rc = -EINVAL;
				goto error;
			}
		} else {
			pr_err("No valid panel-status-check-mode string\n");
			rc = -EINVAL;
			goto error;
		}
	} else {
		pr_debug("status check method not defined!\n");
		rc = -EINVAL;
		goto error;
	}

	if (panel->esd_config.status_mode == ESD_MODE_REG_READ) {
		rc = dsi_panel_parse_esd_reg_read_configs(panel, of_node);
		if (rc) {
			pr_err("failed to parse esd reg read mode params, rc=%d\n",
						rc);
			goto error;
		}
		esd_mode = "register_read";
	} else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA) {
		esd_mode = "bta_trigger";
	} else if (panel->esd_config.status_mode ==  ESD_MODE_PANEL_TE) {
		esd_mode = "te_check";
	}

	pr_info("ESD enabled with mode: %s\n", esd_mode);

	return 0;

error:
error:
	panel->esd_config.esd_enabled = false;
	panel->esd_config.esd_enabled = false;
	return rc;
	return rc;
+3 −0
Original line number Original line Diff line number Diff line
@@ -283,6 +283,9 @@ struct dsi_panel *dsi_panel_ext_bridge_get(struct device *parent,
				struct device_node *of_node,
				struct device_node *of_node,
				int topology_override);
				int topology_override);


int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel,
				struct device_node *of_node);

void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
void dsi_panel_ext_bridge_put(struct dsi_panel *panel);


#endif /* _DSI_PANEL_H_ */
#endif /* _DSI_PANEL_H_ */