disp: msm: dsi: add support for dsi dynamic clock switch
This change adds support for dynamic switching of dsi clocks to avoid RF interference issues. Also with dynamic dsi clock switch feature coming into picture, now populate the supported refresh rate as list instead of providing a range. Modify the logic to enumerate all the modes in dsi driver, taking dynamic bit clocks, resolutions and refresh rates into account. Change-Id: I5b6e62bc935cf2234bdd96fcb3c7537b4e735fff Signed-off-by: Sandeep Panda <spanda@codeaurora.org> Signed-off-by: Ritesh Kumar <riteshk@codeaurora.org> Signed-off-by: Yujun Zhang <yujunzhang@codeaurora.org>
This commit is contained in:
@@ -1155,6 +1155,48 @@ static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
bool supported = false;
|
||||
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
const char *name = panel->name;
|
||||
|
||||
supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
|
||||
|
||||
if (!supported) {
|
||||
dyn_clk_caps->dyn_clk_support = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
dyn_clk_caps->bit_clk_list_len = utils->count_u32_elems(utils->data,
|
||||
"qcom,dsi-dyn-clk-list");
|
||||
|
||||
if (dyn_clk_caps->bit_clk_list_len < 1) {
|
||||
pr_err("[%s] failed to get supported bit clk list\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!dyn_clk_caps->bit_clk_list)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list",
|
||||
dyn_clk_caps->bit_clk_list,
|
||||
dyn_clk_caps->bit_clk_list_len);
|
||||
|
||||
if (rc) {
|
||||
pr_err("[%s] failed to parse supported bit clk list\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dyn_clk_caps->dyn_clk_support = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -1163,7 +1205,7 @@ static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
const char *name = panel->name;
|
||||
const char *type;
|
||||
u32 val = 0;
|
||||
u32 i;
|
||||
|
||||
supported = utils->read_bool(utils->data,
|
||||
"qcom,mdss-dsi-pan-enable-dynamic-fps");
|
||||
@@ -1171,66 +1213,64 @@ static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
|
||||
if (!supported) {
|
||||
pr_debug("[%s] DFPS is not supported\n", name);
|
||||
dfps_caps->dfps_support = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
type = utils->get_property(utils->data,
|
||||
"qcom,mdss-dsi-pan-fps-update", NULL);
|
||||
if (!type) {
|
||||
pr_err("[%s] dfps type not defined\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
} else if (!strcmp(type, "dfps_suspend_resume_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_SUSPEND_RESUME;
|
||||
} else if (!strcmp(type, "dfps_immediate_clk_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP;
|
||||
} else {
|
||||
pr_err("[%s] dfps type is not recognized\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
type = utils->get_property(utils->data,
|
||||
"qcom,mdss-dsi-pan-fps-update",
|
||||
NULL);
|
||||
if (!type) {
|
||||
pr_err("[%s] dfps type not defined\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
} else if (!strcmp(type, "dfps_suspend_resume_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_SUSPEND_RESUME;
|
||||
} else if (!strcmp(type, "dfps_immediate_clk_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP;
|
||||
} else {
|
||||
pr_err("[%s] dfps type is not recognized\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfps_caps->dfps_list_len = utils->count_u32_elems(utils->data,
|
||||
"qcom,dsi-supported-dfps-list");
|
||||
if (dfps_caps->dfps_list_len < 1) {
|
||||
pr_err("[%s] dfps refresh list not present\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils->read_u32(utils->data,
|
||||
"qcom,mdss-dsi-min-refresh-rate",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_err("[%s] Min refresh rate is not defined\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfps_caps->min_refresh_rate = val;
|
||||
dfps_caps->dfps_list = kcalloc(dfps_caps->dfps_list_len, sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!dfps_caps->dfps_list) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils->read_u32(utils->data,
|
||||
"qcom,mdss-dsi-max-refresh-rate",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_debug("[%s] Using default refresh rate\n", name);
|
||||
rc = utils->read_u32(utils->data,
|
||||
"qcom,mdss-dsi-panel-framerate",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_err("[%s] max refresh rate is not defined\n",
|
||||
name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
dfps_caps->max_refresh_rate = val;
|
||||
rc = utils->read_u32_array(utils->data,
|
||||
"qcom,dsi-supported-dfps-list",
|
||||
dfps_caps->dfps_list,
|
||||
dfps_caps->dfps_list_len);
|
||||
if (rc) {
|
||||
pr_err("[%s] dfps refresh rate list parse failed\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfps_caps->dfps_support = true;
|
||||
|
||||
if (dfps_caps->min_refresh_rate > dfps_caps->max_refresh_rate) {
|
||||
pr_err("[%s] min rate > max rate\n", name);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
/* calculate max and min fps */
|
||||
dfps_caps->max_refresh_rate = dfps_caps->dfps_list[0];
|
||||
dfps_caps->min_refresh_rate = dfps_caps->dfps_list[0];
|
||||
|
||||
pr_debug("[%s] DFPS is supported %d-%d, mode %d\n", name,
|
||||
dfps_caps->min_refresh_rate,
|
||||
dfps_caps->max_refresh_rate,
|
||||
dfps_caps->type);
|
||||
dfps_caps->dfps_support = true;
|
||||
for (i = 1; i < dfps_caps->dfps_list_len; i++) {
|
||||
if (dfps_caps->dfps_list[i] < dfps_caps->min_refresh_rate)
|
||||
dfps_caps->min_refresh_rate = dfps_caps->dfps_list[i];
|
||||
else if (dfps_caps->dfps_list[i] > dfps_caps->max_refresh_rate)
|
||||
dfps_caps->max_refresh_rate = dfps_caps->dfps_list[i];
|
||||
}
|
||||
|
||||
error:
|
||||
@@ -3053,6 +3093,13 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
pr_err("failed to parse qsync features, rc=%d\n", rc);
|
||||
}
|
||||
|
||||
if (panel->panel_mode == DSI_OP_VIDEO_MODE) {
|
||||
rc = dsi_panel_parse_dyn_clk_caps(panel);
|
||||
if (rc)
|
||||
pr_err("failed to parse dynamic clk config, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
rc = dsi_panel_parse_phy_props(panel);
|
||||
if (rc) {
|
||||
pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
|
||||
|
Verwijs in nieuw issue
Block a user