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:
parent
85ec72fd28
commit
209aa00227
4 changed files with 108 additions and 43 deletions
|
@ -32,6 +32,7 @@
|
|||
#include "mdss_debug.h"
|
||||
|
||||
#define XO_CLK_RATE 19200000
|
||||
#define CMDLINE_DSI_CTL_NUM_STRING_LEN 2
|
||||
|
||||
/* Master structure to hold all the information about the DSI/panel */
|
||||
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(
|
||||
struct platform_device *pdev, char *panel_cfg)
|
||||
{
|
||||
int len, i;
|
||||
int len, i = 0;
|
||||
int ctrl_id = pdev->id - 1;
|
||||
char panel_name[MDSS_MAX_PANEL_LEN] = "";
|
||||
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 mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
|
||||
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)
|
||||
strlcpy(ctrl_id_stream, "1:", 3);
|
||||
|
||||
stream = strnstr(panel_cfg, ctrl_id_stream, len);
|
||||
if (!stream) {
|
||||
pr_err("controller config is not present\n");
|
||||
/* get controller number */
|
||||
str1 = strnstr(panel_cfg, ctrl_id_stream, len);
|
||||
if (!str1) {
|
||||
pr_err("%s: controller %s is not present in %s\n",
|
||||
__func__, ctrl_id_stream, panel_cfg);
|
||||
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), ':');
|
||||
if (!pan) {
|
||||
strlcpy(panel_name, stream, MDSS_MAX_PANEL_LEN);
|
||||
/* get panel name */
|
||||
str2 = strnchr(str1, strlen(str1), ':');
|
||||
if (!str2) {
|
||||
strlcpy(panel_name, str1, MDSS_MAX_PANEL_LEN);
|
||||
} else {
|
||||
for (i = 0; (stream + i) < pan; i++)
|
||||
panel_name[i] = *(stream + i);
|
||||
for (i = 0; (str1 + i) < str2; i++)
|
||||
panel_name[i] = *(str1 + i);
|
||||
panel_name[i] = 0;
|
||||
}
|
||||
|
||||
pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
|
||||
panel_cfg, panel_name);
|
||||
pr_info("%s: cmdline:%s panel_name:%s\n",
|
||||
__func__, panel_cfg, panel_name);
|
||||
if (!strcmp(panel_name, NONE_PANEL))
|
||||
goto exit;
|
||||
|
||||
mdss_node = of_parse_phandle(pdev->dev.of_node,
|
||||
"qcom,mdss-mdp", 0);
|
||||
|
||||
"qcom,mdss-mdp", 0);
|
||||
if (!mdss_node) {
|
||||
pr_err("%s: %d: mdss_node null\n",
|
||||
__func__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
dsi_pan_node = of_find_node_by_name(mdss_node,
|
||||
panel_name);
|
||||
dsi_pan_node = of_find_node_by_name(mdss_node, panel_name);
|
||||
if (!dsi_pan_node) {
|
||||
pr_err("%s: invalid pan node, selecting prim panel\n",
|
||||
__func__);
|
||||
pr_err("%s: invalid pan node \"%s\"\n",
|
||||
__func__, panel_name);
|
||||
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;
|
||||
}
|
||||
end:
|
||||
if (strcmp(panel_name, NONE_PANEL))
|
||||
dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
|
||||
|
||||
exit:
|
||||
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));
|
||||
if (cfg_prim) {
|
||||
cfg_prim += 4;
|
||||
|
||||
cfg_sec = strnchr(cfg_prim, strlen(cfg_prim), ':');
|
||||
if (!cfg_sec)
|
||||
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] = '\0';
|
||||
data = dsi_cfg;
|
||||
} else {
|
||||
|
|
|
@ -1374,6 +1374,11 @@ static int mdss_dsi_parse_dsc_params(struct device_node *np,
|
|||
int rc = 0;
|
||||
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);
|
||||
if (rc) {
|
||||
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,
|
||||
struct dsi_panel_timing *pt, bool is_split_display)
|
||||
struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data)
|
||||
{
|
||||
int rc = 0;
|
||||
bool is_split_display = panel_data->panel_info.is_split_display;
|
||||
const char *data;
|
||||
struct device_node *cfg_np = NULL;
|
||||
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);
|
||||
if (!cfg_np) {
|
||||
pr_err("%s: error parsing qcom,config-select\n",
|
||||
__func__);
|
||||
} else {
|
||||
if (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
|
||||
timing->lm_widths, 2)) {
|
||||
if (is_split_display &&
|
||||
(timing->lm_widths[1] != 0)) {
|
||||
pr_err("%s: lm-split not allowed with split display\n",
|
||||
__func__);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
if (!cfg_np)
|
||||
pr_err("%s:err parsing qcom,config-select\n", __func__);
|
||||
ctrl_pdata->panel_data.cfg_np = cfg_np;
|
||||
}
|
||||
|
||||
if (cfg_np) {
|
||||
if (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
|
||||
timing->lm_widths, 2)) {
|
||||
if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)
|
||||
&& (timing->lm_widths[1] != 0)) {
|
||||
pr_err("%s: lm-split not allowed with split display\n",
|
||||
__func__);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_debug("%s: qcom,config-select is not present\n", __func__);
|
||||
pr_info("%s: cfg_node name %s lm_split:%dx%d\n", __func__,
|
||||
cfg_np->name,
|
||||
timing->lm_widths[0], timing->lm_widths[1]);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
rc = mdss_dsi_parse_compression_params(np, pt,
|
||||
panel_data->panel_info.is_split_display);
|
||||
panel_data);
|
||||
if (rc) {
|
||||
pr_err("%s: parsing compression params failed. rc:%d\n",
|
||||
__func__, rc);
|
||||
|
|
|
@ -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_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 "
|
||||
"config; <pan_intf> is dsi:<ctrl_id> or hdmi or edp "
|
||||
"<pan_intf_cfg> is panel interface specific string "
|
||||
"Ex: This string is panel's device node name from DT "
|
||||
"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);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef MDSS_PANEL_H
|
||||
#define MDSS_PANEL_H
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -689,6 +690,7 @@ struct mdss_panel_data {
|
|||
struct mdss_panel_timing *current_timing;
|
||||
bool active;
|
||||
|
||||
struct device_node *cfg_np; /* NULL if config node is not present */
|
||||
struct mdss_panel_data *next;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue