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: Ujwal Patel <ujwalp@codeaurora.org>
Signed-off-by: Shivaraj Shetty <shivaraj@codeaurora.org>
This commit is contained in:
Ujwal Patel 2015-07-21 16:46:56 -07:00 committed by David Keitel
parent 85ec72fd28
commit 209aa00227
4 changed files with 108 additions and 43 deletions

View file

@ -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;
@ -2210,11 +2211,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;
@ -2240,46 +2242,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;
} }
@ -2853,11 +2894,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 {

View file

@ -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;
if (of_find_property(np, "qcom,config-select", NULL)) { ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata,
panel_data);
cfg_np = ctrl_pdata->panel_data.cfg_np;
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 (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
timing->lm_widths, 2)) { if (cfg_np) {
if (is_split_display && if (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
(timing->lm_widths[1] != 0)) { timing->lm_widths, 2)) {
pr_err("%s: lm-split not allowed with split display\n", if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)
__func__); && (timing->lm_widths[1] != 0)) {
rc = -EINVAL; pr_err("%s: lm-split not allowed with split display\n",
goto end; __func__);
} rc = -EINVAL;
goto end;
} }
} }
} else { pr_info("%s: cfg_node name %s lm_split:%dx%d\n", __func__,
pr_debug("%s: qcom,config-select is not present\n", __func__); cfg_np->name,
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))
@ -2225,7 +2238,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);

View file

@ -4144,12 +4144,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);

View file

@ -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;
}; };