mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-01 02:21:16 +00:00
mdss: display: Add support for variable refresh rate
Add support for variable refresh rate by changing the VFP immediately and programming it to MDP TG and DSI registers. Change-Id: I186e80cf38d42f4224afedadda96cc613ae68470 Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org>
This commit is contained in:
parent
d82905e562
commit
6f1e602d38
6 changed files with 160 additions and 31 deletions
|
@ -126,6 +126,9 @@ Optional properties:
|
|||
implemented during suspend/resume.
|
||||
"dfps_immediate_clk_mode" = FPS change request is
|
||||
implemented immediately using DSI clocks.
|
||||
"dfps_immediate_porch_mode" = FPS change request is
|
||||
implemented immediately by changing panel porch
|
||||
values.
|
||||
- qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight
|
||||
control for this panel.
|
||||
"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
|
||||
|
|
|
@ -659,33 +659,58 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
|
|||
|
||||
if (new_fps !=
|
||||
ctrl_pdata->panel_data.panel_info.mipi.frame_rate) {
|
||||
rc = mdss_dsi_clk_div_config
|
||||
(&ctrl_pdata->panel_data.panel_info, new_fps);
|
||||
if (rc) {
|
||||
pr_err("%s: unable to initialize the clk dividers\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
ctrl_pdata->pclk_rate =
|
||||
ctrl_pdata->panel_data.panel_info.mipi.dsi_pclk_rate;
|
||||
ctrl_pdata->byte_clk_rate =
|
||||
ctrl_pdata->panel_data.panel_info.clk_rate / 8;
|
||||
|
||||
if (pdata->panel_info.dfps_update
|
||||
== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
|
||||
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
|
||||
0x0004);
|
||||
ctrl_pdata->panel_data.panel_info.mipi.frame_rate =
|
||||
new_fps;
|
||||
dsi_ctrl &= ~0x2;
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
|
||||
dsi_ctrl);
|
||||
mdss_dsi_controller_cfg(true, pdata);
|
||||
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
|
||||
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
|
||||
dsi_ctrl |= 0x2;
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
|
||||
dsi_ctrl);
|
||||
== DFPS_IMMEDIATE_PORCH_UPDATE_MODE) {
|
||||
u32 hsync_period, vsync_period;
|
||||
u32 new_dsi_v_total, current_dsi_v_total;
|
||||
vsync_period =
|
||||
mdss_panel_get_vtotal(&pdata->panel_info);
|
||||
hsync_period =
|
||||
mdss_panel_get_htotal(&pdata->panel_info);
|
||||
current_dsi_v_total =
|
||||
MIPI_INP((ctrl_pdata->ctrl_base) + 0x2C);
|
||||
new_dsi_v_total =
|
||||
((vsync_period - 1) << 16) | (hsync_period - 1);
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
|
||||
(current_dsi_v_total | 0x8000000));
|
||||
if (new_dsi_v_total & 0x8000000) {
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
|
||||
new_dsi_v_total);
|
||||
} else {
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
|
||||
(new_dsi_v_total | 0x8000000));
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
|
||||
(new_dsi_v_total & 0x7ffffff));
|
||||
}
|
||||
pdata->panel_info.mipi.frame_rate = new_fps;
|
||||
} else {
|
||||
rc = mdss_dsi_clk_div_config
|
||||
(&ctrl_pdata->panel_data.panel_info, new_fps);
|
||||
if (rc) {
|
||||
pr_err("%s: unable to initialize the clk dividers\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
ctrl_pdata->pclk_rate =
|
||||
pdata->panel_info.mipi.dsi_pclk_rate;
|
||||
ctrl_pdata->byte_clk_rate =
|
||||
pdata->panel_info.clk_rate / 8;
|
||||
|
||||
if (pdata->panel_info.dfps_update
|
||||
== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
|
||||
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
|
||||
0x0004);
|
||||
pdata->panel_info.mipi.frame_rate = new_fps;
|
||||
dsi_ctrl &= ~0x2;
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
|
||||
dsi_ctrl);
|
||||
mdss_dsi_controller_cfg(true, pdata);
|
||||
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
|
||||
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
|
||||
dsi_ctrl |= 0x2;
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
|
||||
dsi_ctrl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_debug("%s: Panel is already at this FPS\n", __func__);
|
||||
|
@ -1220,6 +1245,12 @@ int dsi_panel_device_register(struct device_node *pan_node,
|
|||
DFPS_IMMEDIATE_CLK_UPDATE_MODE;
|
||||
pr_debug("%s: dfps mode: Immediate clk\n",
|
||||
__func__);
|
||||
} else if (!strcmp(data,
|
||||
"dfps_immediate_porch_mode")) {
|
||||
pinfo->dfps_update =
|
||||
DFPS_IMMEDIATE_PORCH_UPDATE_MODE;
|
||||
pr_debug("%s: dfps mode: Immediate porch\n",
|
||||
__func__);
|
||||
} else {
|
||||
pr_debug("%s: dfps to default mode\n",
|
||||
__func__);
|
||||
|
|
|
@ -186,7 +186,8 @@ struct mdss_mdp_ctl {
|
|||
struct mdss_mdp_vsync_handler *);
|
||||
int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
|
||||
struct mdss_mdp_vsync_handler *);
|
||||
int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, int new_fps);
|
||||
int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_mdp_ctl *sctl, int new_fps);
|
||||
|
||||
struct blocking_notifier_head notifier_head;
|
||||
|
||||
|
|
|
@ -2240,9 +2240,12 @@ static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
|
|||
int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mdss_mdp_ctl *sctl = NULL;
|
||||
|
||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
|
||||
if (ctl->config_fps_fnc)
|
||||
ret = ctl->config_fps_fnc(ctl, fps);
|
||||
ret = ctl->config_fps_fnc(ctl, sctl, fps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -466,7 +466,63 @@ static void mdss_mdp_video_underrun_intr_done(void *arg)
|
|||
ctl->underrun_cnt);
|
||||
}
|
||||
|
||||
static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
|
||||
static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_ctl *ctl, int new_fps)
|
||||
{
|
||||
int curr_fps;
|
||||
u32 add_v_lines = 0;
|
||||
u32 current_vsync_period_f0, new_vsync_period_f0;
|
||||
struct mdss_panel_data *pdata;
|
||||
struct mdss_mdp_video_ctx *ctx;
|
||||
u32 vsync_period, hsync_period;
|
||||
|
||||
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
|
||||
if (!ctx) {
|
||||
pr_err("invalid ctx\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = ctl->panel_data;
|
||||
if (pdata == NULL) {
|
||||
pr_err("%s: Invalid panel data\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
|
||||
hsync_period = mdss_panel_get_htotal(&pdata->panel_info);
|
||||
curr_fps = mdss_panel_get_framerate(&pdata->panel_info);
|
||||
|
||||
if (curr_fps > new_fps) {
|
||||
add_v_lines = mult_frac(vsync_period,
|
||||
(curr_fps - new_fps), new_fps);
|
||||
pdata->panel_info.lcdc.v_front_porch += add_v_lines;
|
||||
} else {
|
||||
add_v_lines = mult_frac(vsync_period,
|
||||
(new_fps - curr_fps), new_fps);
|
||||
pdata->panel_info.lcdc.v_front_porch -= add_v_lines;
|
||||
}
|
||||
|
||||
vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
|
||||
current_vsync_period_f0 = mdp_video_read(ctx,
|
||||
MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0);
|
||||
new_vsync_period_f0 = (vsync_period * hsync_period);
|
||||
|
||||
mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
|
||||
current_vsync_period_f0 | 0x800000);
|
||||
if (new_vsync_period_f0 & 0x800000) {
|
||||
mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
|
||||
new_vsync_period_f0);
|
||||
} else {
|
||||
mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
|
||||
new_vsync_period_f0 | 0x800000);
|
||||
mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
|
||||
new_vsync_period_f0 & 0x7fffff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_mdp_ctl *sctl, int new_fps)
|
||||
{
|
||||
struct mdss_mdp_video_ctx *ctx;
|
||||
struct mdss_panel_data *pdata;
|
||||
|
@ -529,6 +585,40 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
|
|||
ctl->force_screen_state = MDSS_SCREEN_DEFAULT;
|
||||
mdss_mdp_display_commit(ctl, NULL);
|
||||
mdss_mdp_display_wait4comp(ctl);
|
||||
} else if (pdata->panel_info.dfps_update
|
||||
== DFPS_IMMEDIATE_PORCH_UPDATE_MODE){
|
||||
if (!ctx->timegen_en) {
|
||||
pr_err("TG is OFF. DFPS mode invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
video_vsync_irq_enable(ctl, true);
|
||||
INIT_COMPLETION(ctx->vsync_comp);
|
||||
rc = wait_for_completion_timeout(&ctx->vsync_comp,
|
||||
usecs_to_jiffies(VSYNC_TIMEOUT_US));
|
||||
WARN(rc <= 0, "timeout (%d) vsync interrupt on ctl=%d\n",
|
||||
rc, ctl->num);
|
||||
rc = 0;
|
||||
video_vsync_irq_disable(ctl);
|
||||
|
||||
rc = mdss_mdp_video_vfp_fps_update(ctl, new_fps);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: Error during DFPS\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
if (sctl) {
|
||||
rc = mdss_mdp_video_vfp_fps_update(sctl,
|
||||
new_fps);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: DFPS error\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
rc = mdss_mdp_ctl_intf_event(ctl,
|
||||
MDSS_EVENT_PANEL_UPDATE_FPS,
|
||||
(void *)new_fps);
|
||||
WARN(rc, "intf %d panel fps update error (%d)\n",
|
||||
ctl->intf_num, rc);
|
||||
} else {
|
||||
pr_err("intf %d panel, unknown FPS mode\n",
|
||||
ctl->intf_num);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -234,6 +234,7 @@ struct edp_panel_info {
|
|||
enum dynamic_fps_update {
|
||||
DFPS_SUSPEND_RESUME_MODE,
|
||||
DFPS_IMMEDIATE_CLK_UPDATE_MODE,
|
||||
DFPS_IMMEDIATE_PORCH_UPDATE_MODE,
|
||||
};
|
||||
|
||||
enum lvds_mode {
|
||||
|
|
Loading…
Reference in a new issue