msm: mdss: fix to update the correct panel info for dynamic fps

Current code does not reflect the correct panel information
when user space request the panel info and fps data after
the fps update.
This change fix the code, so further calls to get the
screen info have the correct panel data.

Change-Id: I3e0382748cbf8b480c2516223cfe14444d388e29
Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
This commit is contained in:
Ingrid Gallardo 2015-10-08 15:15:37 -07:00 committed by David Keitel
parent f337093cab
commit ce623e2090
8 changed files with 201 additions and 66 deletions

View file

@ -1612,7 +1612,11 @@ static void __mdss_dsi_update_video_mode_total(struct mdss_panel_data *pdata,
if (ctrl_pdata->shared_data->timing_db_mode)
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x1e4, 0x1);
ctrl_pdata->panel_data.panel_info.mipi.frame_rate = new_fps;
pr_debug("%s new_fps:%d vsync:%d hsync:%d frame_rate:%d\n",
__func__, new_fps, vsync_period, hsync_period,
ctrl_pdata->panel_data.panel_info.mipi.frame_rate);
ctrl_pdata->panel_data.panel_info.current_fps = new_fps;
MDSS_XLOG(current_dsi_v_total, new_dsi_v_total, new_fps,
ctrl_pdata->shared_data->timing_db_mode);
@ -1773,9 +1777,13 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
clk_disable_unprepare(ctrl_pdata->pll_byte_clk);
clk_disable_unprepare(ctrl_pdata->pll_pixel_clk);
if (!rc)
if (!rc) {
ctrl_pdata->panel_data.panel_info.mipi.frame_rate =
new_fps;
/* we are using current_fps to compare if dfps needed */
ctrl_pdata->panel_data.panel_info.current_fps =
new_fps;
}
} else {
ctrl_pdata->pclk_rate =
pdata->panel_info.mipi.dsi_pclk_rate;
@ -1843,7 +1851,7 @@ 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) {
ctrl_pdata->panel_data.panel_info.current_fps) {
if (pdata->panel_info.dfps_update
== DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP ||
pdata->panel_info.dfps_update

View file

@ -111,8 +111,6 @@ static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
int event, void *arg);
static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd,
int type);
static void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
struct fb_var_screeninfo *var);
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
@ -3260,7 +3258,7 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
pinfo->clk_rate = PICOS2KHZ(var->pixclock) * 1000;
}
static void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
struct fb_var_screeninfo *var)
{
var->xres = mdss_fb_get_panel_xres(pinfo);
@ -3279,6 +3277,11 @@ static void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
var->width = pinfo->physical_width;
if (pinfo->physical_height)
var->height = pinfo->physical_height;
pr_debug("ScreenInfo: res=%dx%d [%d, %d] [%d, %d]\n",
var->xres, var->yres, var->left_margin,
var->right_margin, var->upper_margin,
var->lower_margin);
}
/**

View file

@ -444,4 +444,6 @@ int mdss_fb_async_position_update(struct fb_info *info,
u32 mdss_fb_get_mode_switch(struct msm_fb_data_type *mfd);
void mdss_fb_report_panel_dead(struct msm_fb_data_type *mfd);
void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
struct fb_var_screeninfo *var);
#endif /* MDSS_FB_H */

View file

@ -1083,7 +1083,7 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int panel_power_mode);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg,
u32 flags);
int mdss_mdp_get_prefetch_lines(struct mdss_mdp_ctl *ctl);
int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo);
int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_pipe **left_plist, int left_cnt,
struct mdss_mdp_pipe **right_plist, int right_cnt);

View file

@ -1063,10 +1063,9 @@ exit:
*(perf->bw_vote_mode));
}
static bool is_mdp_prefetch_needed(struct mdss_mdp_ctl *ctl)
static bool is_mdp_prefetch_needed(struct mdss_panel_info *pinfo)
{
struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
struct mdss_data_type *mdata = ctl->mdata;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
bool enable_prefetch = false;
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_105) {
@ -1090,7 +1089,7 @@ static bool is_mdp_prefetch_needed(struct mdss_mdp_ctl *ctl)
/**
* mdss_mdp_get_prefetch_lines: - Number of fetch lines in vertical front porch
* @ctl: Pointer to controller where prefetch lines will be calculated
* @pinfo: Pointer to the panel information.
*
* Returns the number of fetch lines in vertical front porch at which mdp
* can start fetching the next frame.
@ -1099,14 +1098,13 @@ static bool is_mdp_prefetch_needed(struct mdss_mdp_ctl *ctl)
* the mdp fetch lines as the last (25 - vbp - vpw) lines of vertical
* front porch.
*/
int mdss_mdp_get_prefetch_lines(struct mdss_mdp_ctl *ctl)
int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo)
{
int prefetch_avail = 0;
int v_total, vfp_start;
u32 prefetch_needed;
struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
if (!is_mdp_prefetch_needed(ctl))
if (!is_mdp_prefetch_needed(pinfo))
return 0;
v_total = mdss_panel_get_vtotal(pinfo);
@ -4151,17 +4149,36 @@ int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl)
if (!pinfo->dynamic_fps || !ctl->ops.config_fps_fnc)
return 0;
if (!pinfo->default_fps) {
/* we haven't got any call to update the fps */
return 0;
}
mdp5_data = mfd_to_mdp5_data(ctl->mfd);
if (!mdp5_data)
return -ENODEV;
/*
* Panel info is already updated with the new fps info,
* so we need to lock the data to make sure the panel info
* is not updated while we reconfigure the HW.
*/
mutex_lock(&mdp5_data->dfps_lock);
new_fps = pinfo->new_fps;
mutex_unlock(&mdp5_data->dfps_lock);
if (new_fps == pinfo->mipi.frame_rate) {
if ((pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) ||
(pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP)) {
new_fps = mdss_panel_get_framerate(pinfo);
} else {
new_fps = pinfo->new_fps;
}
pr_debug("fps new:%d old:%d\n", new_fps,
pinfo->current_fps);
if (new_fps == pinfo->current_fps) {
pr_debug("FPS is already %d\n", new_fps);
return 0;
ret = 0;
goto exit;
}
ret = ctl->ops.config_fps_fnc(ctl, new_fps);
@ -4171,6 +4188,8 @@ int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl)
pr_err("Failed to configure %d fps rc=%d\n",
new_fps, ret);
exit:
mutex_unlock(&mdp5_data->dfps_lock);
return ret;
}

View file

@ -68,10 +68,6 @@ struct mdss_mdp_video_ctx {
struct completion vsync_comp;
int wait_pending;
u32 default_fps;
u32 saved_vtotal;
u32 saved_vfporch;
atomic_t vsync_ref;
spinlock_t vsync_lock;
spinlock_t dfps_lock;
@ -716,12 +712,25 @@ static void mdss_mdp_video_underrun_intr_done(void *arg)
schedule_work(&ctl->recover_work);
}
static int mdss_mdp_video_timegen_update(struct mdss_mdp_video_ctx *ctx,
struct mdss_panel_info *pinfo)
/**
* mdss_mdp_video_hfp_fps_update() - configure mdp with new fps.
* @ctx: pointer to the master context.
* @pdata: panel information data.
*
* This function configures the hardware to modify the fps.
* within mdp for the hfp method.
* Function assumes that timings for the new fps configuration
* are already updated in the panel data passed as parameter.
*
* Return: 0 - succeed, otherwise - fail
*/
static int mdss_mdp_video_hfp_fps_update(struct mdss_mdp_video_ctx *ctx,
struct mdss_panel_data *pdata)
{
u32 hsync_period, vsync_period;
u32 hsync_start_x, hsync_end_x, display_v_start, display_v_end;
u32 display_hctl, hsync_ctl;
struct mdss_panel_info *pinfo = &pdata->panel_info;
hsync_period = mdss_panel_get_htotal(pinfo, true);
vsync_period = mdss_panel_get_vtotal(pinfo);
@ -752,48 +761,32 @@ static int mdss_mdp_video_timegen_update(struct mdss_mdp_video_ctx *ctx,
return 0;
}
static int mdss_mdp_video_hfp_fps_update(struct mdss_mdp_video_ctx *ctx,
struct mdss_panel_data *pdata, int new_fps)
{
int curr_fps;
int add_h_pixels = 0;
int hsync_period;
int diff;
hsync_period = mdss_panel_get_htotal(&pdata->panel_info, true);
curr_fps = mdss_panel_get_framerate(&pdata->panel_info);
diff = curr_fps - new_fps;
add_h_pixels = mult_frac(hsync_period, diff, new_fps);
pdata->panel_info.lcdc.h_front_porch += add_h_pixels;
mdss_mdp_video_timegen_update(ctx, &pdata->panel_info);
return 0;
}
/**
* mdss_mdp_video_vfp_fps_update() - configure mdp with new fps.
* @ctx: pointer to the master context.
* @pdata: panel information data.
*
* This function configures the hardware to modify the fps.
* within mdp for the vfp method.
* Function assumes that timings for the new fps configuration
* are already updated in the panel data passed as parameter.
*
* Return: 0 - succeed, otherwise - fail
*/
static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_video_ctx *ctx,
struct mdss_panel_data *pdata, int new_fps)
struct mdss_panel_data *pdata)
{
int add_v_lines = 0;
u32 current_vsync_period_f0, new_vsync_period_f0;
int vsync_period, hsync_period;
int diff;
/*
* Change in the blanking times are already in the
* panel info, so just get the vtotal and htotal expected
* for this panel to configure those in hw.
*/
vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
hsync_period = mdss_panel_get_htotal(&pdata->panel_info, true);
if (!ctx->default_fps) {
ctx->default_fps = mdss_panel_get_framerate(&pdata->panel_info);
ctx->saved_vtotal = vsync_period;
ctx->saved_vfporch = pdata->panel_info.lcdc.v_front_porch;
}
diff = ctx->default_fps - new_fps;
add_v_lines = mult_frac(ctx->saved_vtotal, diff, new_fps);
pdata->panel_info.lcdc.v_front_porch = ctx->saved_vfporch +
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);
@ -809,6 +802,11 @@ static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_video_ctx *ctx,
mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
new_vsync_period_f0 & 0x7fffff);
}
pr_debug("if:%d vtotal:%d htotal:%d f0:0x%x nw_f0:0x%x\n",
ctx->intf_num, vsync_period, hsync_period,
current_vsync_period_f0, new_vsync_period_f0);
MDSS_XLOG(ctx->intf_num, current_vsync_period_f0,
hsync_period, vsync_period, new_vsync_period_f0);
@ -822,9 +820,9 @@ static int mdss_mdp_video_fps_update(struct mdss_mdp_video_ctx *ctx,
if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP)
rc = mdss_mdp_video_hfp_fps_update(ctx, pdata, new_fps);
rc = mdss_mdp_video_hfp_fps_update(ctx, pdata);
else
rc = mdss_mdp_video_vfp_fps_update(ctx, pdata, new_fps);
rc = mdss_mdp_video_vfp_fps_update(ctx, pdata);
return rc;
}
@ -923,7 +921,6 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
struct mdss_mdp_video_ctx *ctx, *sctx = NULL;
struct mdss_panel_data *pdata;
int rc = 0;
u32 hsync_period, vsync_period;
struct mdss_data_type *mdata = ctl->mdata;
struct mdss_mdp_ctl *sctl = NULL;
@ -956,9 +953,6 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
goto end;
}
vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
hsync_period = mdss_panel_get_htotal(&pdata->panel_info, true);
pr_debug("ctl:%d dfps_update:%d fps:%d\n",
ctl->num, pdata->panel_info.dfps_update, new_fps);
MDSS_XLOG(ctl->num, pdata->panel_info.dfps_update,
@ -1275,7 +1269,7 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
mdata = ctl->mdata;
pinfo->prg_fet = mdss_mdp_get_prefetch_lines(ctl);
pinfo->prg_fet = mdss_mdp_get_prefetch_lines(pinfo);
if (!pinfo->prg_fet) {
pr_debug("programmable fetch is not needed/supported\n");
return;

View file

@ -2657,6 +2657,91 @@ static ssize_t dynamic_fps_sysfs_rda_dfps(struct device *dev,
return ret;
} /* dynamic_fps_sysfs_rda_dfps */
static int calc_extra_blanking(struct mdss_panel_data *pdata, u32 new_fps)
{
int add_porches, diff;
/* calculate extra: lines for vfp-method, pixels for hfp-method */
diff = pdata->panel_info.default_fps - new_fps;
add_porches = mult_frac(pdata->panel_info.saved_total,
diff, new_fps);
return add_porches;
}
static void cache_initial_timings(struct mdss_panel_data *pdata)
{
if (!pdata->panel_info.default_fps) {
/*
* This value will change dynamically once the
* actual dfps update happen in hw.
*/
pdata->panel_info.current_fps =
mdss_panel_get_framerate(&pdata->panel_info);
/*
* Keep the initial fps and porch values for this panel before
* any dfps update happen, this is to prevent losing precision
* in further calculations.
*/
pdata->panel_info.default_fps =
mdss_panel_get_framerate(&pdata->panel_info);
if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) {
pdata->panel_info.saved_total =
mdss_panel_get_vtotal(&pdata->panel_info);
pdata->panel_info.saved_fporch =
pdata->panel_info.lcdc.v_front_porch;
} else if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) {
pdata->panel_info.saved_total =
mdss_panel_get_htotal(&pdata->panel_info, true);
pdata->panel_info.saved_fporch =
pdata->panel_info.lcdc.h_front_porch;
}
}
}
static void mdss_mdp_dfps_update_params(struct mdss_panel_data *pdata,
u32 new_fps)
{
/* Keep initial values before any dfps update */
cache_initial_timings(pdata);
if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) {
int add_v_lines;
/* calculate extra vfp lines */
add_v_lines = calc_extra_blanking(pdata, new_fps);
/* update panel info with new values */
pdata->panel_info.lcdc.v_front_porch =
pdata->panel_info.saved_fporch + add_v_lines;
pdata->panel_info.mipi.frame_rate = new_fps;
pdata->panel_info.prg_fet =
mdss_mdp_get_prefetch_lines(&pdata->panel_info);
} else if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) {
int add_h_pixels;
/* calculate extra hfp pixels */
add_h_pixels = calc_extra_blanking(pdata, new_fps);
/* update panel info */
pdata->panel_info.lcdc.h_front_porch =
pdata->panel_info.saved_fporch + add_h_pixels;
pdata->panel_info.mipi.frame_rate = new_fps;
} else {
/* in clock method we are not updating panel data here */
pdata->panel_info.new_fps = new_fps;
}
}
static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@ -2665,6 +2750,7 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct fb_var_screeninfo *var = &mfd->fbi->var;
rc = kstrtoint(buf, 10, &dfps);
if (rc) {
@ -2707,7 +2793,19 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
dfps = pdata->panel_info.max_fps;
}
pdata->panel_info.new_fps = dfps;
pr_debug("new_fps:%d\n", dfps);
mdss_mdp_dfps_update_params(pdata, dfps);
if (pdata->next)
mdss_mdp_dfps_update_params(pdata->next, dfps);
/*
* Update the panel info in the upstream
* data, so any further call to get the screen
* info has the updated timings.
*/
mdss_panelinfo_to_fb_var(&pdata->panel_info, var);
MDSS_XLOG(dfps);
mutex_unlock(&mdp5_data->dfps_lock);
return count;
@ -3824,6 +3922,7 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
case metadata_op_frame_rate:
metadata->data.panel_frame_rate =
mdss_panel_get_framerate(mfd->panel_info);
pr_debug("current fps:%d\n", metadata->data.panel_frame_rate);
break;
case metadata_op_get_caps:
ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);

View file

@ -551,7 +551,17 @@ struct mdss_panel_info {
bool panel_ack_disabled;
bool esd_check_enabled;
char dfps_update;
/* new requested fps before it is updated in hw */
int new_fps;
/* stores initial fps after boot */
u32 default_fps;
/* stores initial vtotal (vfp-method) or htotal (hfp-method) */
u32 saved_total;
/* stores initial vfp (vfp-method) or hfp (hfp-method) */
u32 saved_fporch;
/* current fps, once is programmed in hw */
int current_fps;
int panel_max_fps;
int panel_max_vtotal;
u32 mode_gpio_state;