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

Commit cc224461 authored by Ujwal Patel's avatar Ujwal Patel
Browse files

msm: mdss: support panel topology configurations using module params



Starting patch I36dbf8d9e325675bb3affa1794b2fc93ee6151b4,
msm: mdss: enable different panel configuration modes, dsi panels can
have multiple topology configurations. Currently chosen configuration
is selected only through device tree using qcom,config-select property.
Add support to override this configuration using existing module param.
This module param can be changed by boot-loader display driver if present
or directly by user through kernel command line.

New module param usage:
panel=<lk_cfg>:<pan_intf>:<pan_intf_cfg>:<panel_topology_cfg>
where
<lk_cfg> = "1" lk/gcdb config or "0" non-lk/non-gcdb config;
<pan_intf> = dsi:<ctrl_id> or hdmi or edp;
<pan_intf_cfg> = panel interface specific string matching dt node name;
<panel_topology_cfg> = Optional. If used, format is "config%d";

Ex: panel=0:dsi:1:qcom,mdss_dsi_nt35597_dsc_wqxga_video:config2:0:none
    panel=0:dsi:0:qcom,mdss_dsi_nt35597_wqxga_cmd:config1:1:
          qcom,mdss_dsi_nt35597_wqxga_cmd:config1:cfg:split_dsi

Change-Id: I583ee801737282d3a0eb189e1bf8d66dd7a9b480
Signed-off-by: default avatarUjwal Patel <ujwalp@codeaurora.org>
Signed-off-by: default avatarShivaraj Shetty <shivaraj@codeaurora.org>
parent 42f2c43c
Loading
Loading
Loading
Loading
+67 −22
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@
#include "mdss_debug.h"
#include "mdss_debug.h"


#define XO_CLK_RATE	19200000
#define XO_CLK_RATE	19200000
#define CMDLINE_DSI_CTL_NUM_STRING_LEN 2


/* Master structure to hold all the information about the DSI/panel */
/* Master structure to hold all the information about the DSI/panel */
static struct mdss_dsi_data *mdss_dsi_res;
static struct mdss_dsi_data *mdss_dsi_res;
@@ -2183,11 +2184,12 @@ static struct device_node *mdss_dsi_pref_prim_panel(
static struct device_node *mdss_dsi_find_panel_of_node(
static struct device_node *mdss_dsi_find_panel_of_node(
		struct platform_device *pdev, char *panel_cfg)
		struct platform_device *pdev, char *panel_cfg)
{
{
	int len, i;
	int len, i = 0;
	int ctrl_id = pdev->id - 1;
	int ctrl_id = pdev->id - 1;
	char panel_name[MDSS_MAX_PANEL_LEN] = "";
	char panel_name[MDSS_MAX_PANEL_LEN] = "";
	char ctrl_id_stream[3] =  "0:";
	char ctrl_id_stream[3] =  "0:";
	char *stream = NULL, *pan = NULL, *override_cfg = NULL;
	char *str1 = NULL, *str2 = NULL, *override_cfg = NULL;
	char cfg_np_name[MDSS_MAX_PANEL_LEN] = "";
	struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
	struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
	struct mdss_panel_info *pinfo = &ctrl_pdata->panel_data.panel_info;
	struct mdss_panel_info *pinfo = &ctrl_pdata->panel_data.panel_info;
@@ -2213,46 +2215,85 @@ static struct device_node *mdss_dsi_find_panel_of_node(
		if (ctrl_id == 1)
		if (ctrl_id == 1)
			strlcpy(ctrl_id_stream, "1:", 3);
			strlcpy(ctrl_id_stream, "1:", 3);


		stream = strnstr(panel_cfg, ctrl_id_stream, len);
		/* get controller number */
		if (!stream) {
		str1 = strnstr(panel_cfg, ctrl_id_stream, len);
			pr_err("controller config is not present\n");
		if (!str1) {
			pr_err("%s: controller %s is not present in %s\n",
				__func__, ctrl_id_stream, panel_cfg);
			goto end;
			goto end;
		}
		}
		stream += 2;
		if ((str1 != panel_cfg) && (*(str1-1) != ':')) {
			str1 += CMDLINE_DSI_CTL_NUM_STRING_LEN;
			pr_debug("false match with config node name in \"%s\". search again in \"%s\"\n",
				panel_cfg, str1);
			str1 = strnstr(str1, ctrl_id_stream, len);
			if (!str1) {
				pr_err("%s: 2. controller %s is not present in %s\n",
					__func__, ctrl_id_stream, str1);
				goto end;
			}
		}
		str1 += CMDLINE_DSI_CTL_NUM_STRING_LEN;


		pan = strnchr(stream, strlen(stream), ':');
		/* get panel name */
		if (!pan) {
		str2 = strnchr(str1, strlen(str1), ':');
			strlcpy(panel_name, stream, MDSS_MAX_PANEL_LEN);
		if (!str2) {
			strlcpy(panel_name, str1, MDSS_MAX_PANEL_LEN);
		} else {
		} else {
			for (i = 0; (stream + i) < pan; i++)
			for (i = 0; (str1 + i) < str2; i++)
				panel_name[i] = *(stream + i);
				panel_name[i] = *(str1 + i);
			panel_name[i] = 0;
			panel_name[i] = 0;
		}
		}

		pr_info("%s: cmdline:%s panel_name:%s\n",
		pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
			__func__, panel_cfg, panel_name);
			 panel_cfg, panel_name);
		if (!strcmp(panel_name, NONE_PANEL))
			goto exit;


		mdss_node = of_parse_phandle(pdev->dev.of_node,
		mdss_node = of_parse_phandle(pdev->dev.of_node,
			"qcom,mdss-mdp", 0);
			"qcom,mdss-mdp", 0);

		if (!mdss_node) {
		if (!mdss_node) {
			pr_err("%s: %d: mdss_node null\n",
			pr_err("%s: %d: mdss_node null\n",
			       __func__, __LINE__);
			       __func__, __LINE__);
			return NULL;
			return NULL;
		}
		}
		dsi_pan_node = of_find_node_by_name(mdss_node,
		dsi_pan_node = of_find_node_by_name(mdss_node, panel_name);
						    panel_name);
		if (!dsi_pan_node) {
		if (!dsi_pan_node) {
			pr_err("%s: invalid pan node, selecting prim panel\n",
			pr_err("%s: invalid pan node \"%s\"\n",
			       __func__);
			       __func__, panel_name);
			goto end;
			goto end;
		} else {
			/* extract config node name if present */
			str1 += i;
			str2 = strnstr(str1, "config", strlen(str1));
			if (str2) {
				str1 = strnchr(str2, strlen(str2), ':');
				if (str1) {
					for (i = 0; ((str2 + i) < str1) &&
					     i < MDSS_MAX_PANEL_LEN; i++)
						cfg_np_name[i] = *(str2 + i);
					cfg_np_name[i] = 0;
				} else {
					strlcpy(cfg_np_name, str2,
						MDSS_MAX_PANEL_LEN);
				}
			}

			pr_debug("%s: cfg_np_name:%s\n", __func__, cfg_np_name);
			if (str2) {
				ctrl_pdata->panel_data.cfg_np =
					of_get_child_by_name(dsi_pan_node,
					cfg_np_name);
				if (!ctrl_pdata->panel_data.cfg_np)
					pr_warn("%s: can't find config node:%s. either no such node or bad name\n",
						__func__, cfg_np_name);
			}
		}
		}
		return dsi_pan_node;
		return dsi_pan_node;
	}
	}
end:
end:
	if (strcmp(panel_name, NONE_PANEL))
	if (strcmp(panel_name, NONE_PANEL))
		dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
		dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);

exit:
	return dsi_pan_node;
	return dsi_pan_node;
}
}


@@ -2825,11 +2866,15 @@ static int mdss_dsi_parse_hw_cfg(struct platform_device *pdev, char *pan_cfg)
		cfg_prim = strnstr(pan_cfg, "cfg:", strlen(pan_cfg));
		cfg_prim = strnstr(pan_cfg, "cfg:", strlen(pan_cfg));
	if (cfg_prim) {
	if (cfg_prim) {
		cfg_prim += 4;
		cfg_prim += 4;

		cfg_sec = strnchr(cfg_prim, strlen(cfg_prim), ':');
		cfg_sec = strnchr(cfg_prim, strlen(cfg_prim), ':');
		if (!cfg_sec)
		if (!cfg_sec)
			cfg_sec = cfg_prim + strlen(cfg_prim);
			cfg_sec = cfg_prim + strlen(cfg_prim);
		for (i = 0; (cfg_prim + i) < cfg_sec; i++)

		for (i = 0; ((cfg_prim + i) < cfg_sec) &&
		     (*(cfg_prim+i) != '#'); i++)
			dsi_cfg[i] = *(cfg_prim + i);
			dsi_cfg[i] = *(cfg_prim + i);

		dsi_cfg[i] = '\0';
		dsi_cfg[i] = '\0';
		data = dsi_cfg;
		data = dsi_cfg;
	} else {
	} else {
+32 −19
Original line number Original line Diff line number Diff line
@@ -1374,6 +1374,11 @@ static int mdss_dsi_parse_dsc_params(struct device_node *np,
	int rc = 0;
	int rc = 0;
	struct dsc_desc *dsc = &timing->dsc;
	struct dsc_desc *dsc = &timing->dsc;


	if (!np) {
		pr_err("%s: device node pointer is NULL\n", __func__);
		return -EINVAL;
	}

	rc = of_property_read_u32(np, "qcom,mdss-dsc-encoders", &data);
	rc = of_property_read_u32(np, "qcom,mdss-dsc-encoders", &data);
	if (rc) {
	if (rc) {
		if (!of_find_property(np, "qcom,mdss-dsc-encoders", NULL)) {
		if (!of_find_property(np, "qcom,mdss-dsc-encoders", NULL)) {
@@ -1471,32 +1476,40 @@ end:
}
}


static int mdss_dsi_parse_compression_params(struct device_node *np,
static int mdss_dsi_parse_compression_params(struct device_node *np,
	struct dsi_panel_timing *pt, bool is_split_display)
	struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data)
{
{
	int rc = 0;
	int rc = 0;
	bool is_split_display = panel_data->panel_info.is_split_display;
	const char *data;
	const char *data;
	struct device_node *cfg_np = NULL;
	struct mdss_panel_timing *timing = &pt->timing;
	struct mdss_panel_timing *timing = &pt->timing;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct device_node *cfg_np;

	ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata,
							panel_data);
	cfg_np = ctrl_pdata->panel_data.cfg_np;


	if (of_find_property(np, "qcom,config-select", NULL)) {
	if (!cfg_np && of_find_property(np, "qcom,config-select", NULL)) {
		cfg_np = of_parse_phandle(np, "qcom,config-select", 0);
		cfg_np = of_parse_phandle(np, "qcom,config-select", 0);
		if (!cfg_np) {
		if (!cfg_np)
			pr_err("%s: error parsing qcom,config-select\n",
			pr_err("%s:err parsing qcom,config-select\n", __func__);
				__func__);
		ctrl_pdata->panel_data.cfg_np = cfg_np;
		} else {
	}

	if (cfg_np) {
		if (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
		if (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
		    timing->lm_widths, 2)) {
		    timing->lm_widths, 2)) {
				if (is_split_display &&
			if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)
				    (timing->lm_widths[1] != 0)) {
			    && (timing->lm_widths[1] != 0)) {
				pr_err("%s: lm-split not allowed with split display\n",
				pr_err("%s: lm-split not allowed with split display\n",
					__func__);
					__func__);
				rc = -EINVAL;
				rc = -EINVAL;
				goto end;
				goto end;
			}
			}
		}
		}
		}
		pr_info("%s: cfg_node name %s lm_split:%dx%d\n", __func__,
	} else {
			cfg_np->name,
		pr_debug("%s: qcom,config-select is not present\n", __func__);
			timing->lm_widths[0], timing->lm_widths[1]);
	}
	}


	if ((timing->lm_widths[0] == 0) && (timing->lm_widths[1] == 0))
	if ((timing->lm_widths[0] == 0) && (timing->lm_widths[1] == 0))
@@ -2224,7 +2237,7 @@ static int mdss_dsi_panel_config_res_properties(struct device_node *np,
		"qcom,mdss-dsi-timing-switch-command-state");
		"qcom,mdss-dsi-timing-switch-command-state");


	rc = mdss_dsi_parse_compression_params(np, pt,
	rc = mdss_dsi_parse_compression_params(np, pt,
			panel_data->panel_info.is_split_display);
			panel_data);
	if (rc) {
	if (rc) {
		pr_err("%s: parsing compression params failed. rc:%d\n",
		pr_err("%s: parsing compression params failed. rc:%d\n",
			__func__, rc);
			__func__, rc);
+7 −2
Original line number Original line Diff line number Diff line
@@ -4095,12 +4095,17 @@ static int __init mdss_mdp_driver_init(void)


module_param_string(panel, mdss_mdp_panel, MDSS_MAX_PANEL_LEN, 0);
module_param_string(panel, mdss_mdp_panel, MDSS_MAX_PANEL_LEN, 0);
MODULE_PARM_DESC(panel,
MODULE_PARM_DESC(panel,
		"panel=<lk_cfg>:<pan_intf>:<pan_intf_cfg> "
		"panel=<lk_cfg>:<pan_intf>:<pan_intf_cfg>:<panel_topology_cfg> "
		"where <lk_cfg> is "1"-lk/gcdb config or "0" non-lk/non-gcdb "
		"where <lk_cfg> is "1"-lk/gcdb config or "0" non-lk/non-gcdb "
		"config; <pan_intf> is dsi:<ctrl_id> or hdmi or edp "
		"config; <pan_intf> is dsi:<ctrl_id> or hdmi or edp "
		"<pan_intf_cfg> is panel interface specific string "
		"<pan_intf_cfg> is panel interface specific string "
		"Ex: This string is panel's device node name from DT "
		"Ex: This string is panel's device node name from DT "
		"for DSI interface "
		"for DSI interface "
		"hdmi/edp interface does not use this string");
		"hdmi/edp interface does not use this string "
		"<panel_topology_cfg> is an optional string. Currently it is "
		"only valid for DSI panels. In dual-DSI case, it needs to be"
		"used on both panels or none. When used, format is config%d "
		"where %d is one of the configuration found in device node of "
		"panel selected by <pan_intf_cfg>");


module_init(mdss_mdp_driver_init);
module_init(mdss_mdp_driver_init);
+2 −0
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@
#ifndef MDSS_PANEL_H
#ifndef MDSS_PANEL_H
#define MDSS_PANEL_H
#define MDSS_PANEL_H


#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/stringify.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/types.h>
@@ -689,6 +690,7 @@ struct mdss_panel_data {
	struct mdss_panel_timing *current_timing;
	struct mdss_panel_timing *current_timing;
	bool active;
	bool active;


	struct device_node *cfg_np; /* NULL if config node is not present */
	struct mdss_panel_data *next;
	struct mdss_panel_data *next;
};
};