msm: mdss: Fix tearing and hang issues for autorefresh

While turning off autorefresh feature, there are some frames
that do not get transmitted causing timeouts. This change gracefully
exits autorefresh feature while new frames are pushed.

Crs-Fixed: 773221
Change-Id: I66ecf13133723ff5fad465755d50c6eb1ec0e52a
Signed-off-by: Siddhartha Agrawal <agrawals@codeaurora.org>
Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
This commit is contained in:
Siddhartha Agrawal 2014-12-19 12:15:13 -08:00 committed by David Keitel
parent 0080419738
commit cb4fe3d989
4 changed files with 68 additions and 59 deletions

View file

@ -277,7 +277,7 @@ struct mdss_mdp_ctl {
u8 roi_changed;
u8 valid_roi;
int cmd_autorefresh_en;
bool cmd_autorefresh_en;
int autorefresh_frame_cnt;
struct blocking_notifier_head notifier_head;

View file

@ -1991,8 +1991,7 @@ int mdss_mdp_ctl_cmd_autorefresh_enable(struct mdss_mdp_ctl *ctl,
{
int ret = 0;
if (ctl->panel_data->panel_info.type == MIPI_CMD_PANEL) {
mdss_mdp_cmd_set_autorefresh_mode(ctl,
frame_cnt);
ret = mdss_mdp_cmd_set_autorefresh_mode(ctl, frame_cnt);
} else {
pr_err("Mode not supported for this panel\n");
ret = -EINVAL;

View file

@ -53,8 +53,11 @@ struct mdss_mdp_cmd_ctx {
struct work_struct pp_done_work;
struct mutex autorefresh_mtx;
atomic_t pp_done_cnt;
int autorefresh_pending;
u8 autorefresh_init;
int autorefresh_pending_frame_cnt;
bool autorefresh_off_pending;
bool autorefresh_init;
struct mdss_intf_recovery intf_recovery;
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
u32 pp_timeout_report_cnt;
@ -307,6 +310,9 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
complete_all(&ctx->readptr_done);
}
if (ctx->autorefresh_off_pending)
ctx->autorefresh_off_pending = false;
vsync_time = ktime_get();
ctl->vsync_cnt++;
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
@ -765,7 +771,7 @@ static int __mdss_mdp_cmd_configure_autorefresh(struct mdss_mdp_ctl *ctl, int
frame_cnt, bool delayed)
{
struct mdss_mdp_cmd_ctx *ctx;
int enable = frame_cnt ? 1 : 0;
bool enable = frame_cnt ? true : false;
if (!ctl || !ctl->mixer_left) {
pr_err("invalid ctl structure\n");
@ -778,26 +784,25 @@ static int __mdss_mdp_cmd_configure_autorefresh(struct mdss_mdp_ctl *ctl, int
}
if (frame_cnt == ctl->autorefresh_frame_cnt) {
pr_err("No change to the refresh count\n");
pr_debug("No change to the refresh count\n");
return 0;
}
pr_debug("%s enable = %d frame_cnt = %d clk_cnt=%d\n", __func__,
pr_debug("%s enable = %d frame_cnt = %d init=%d\n", __func__,
enable, frame_cnt, ctx->autorefresh_init);
mutex_lock(&ctx->autorefresh_mtx);
if (enable) {
if (delayed) {
ctx->autorefresh_pending = frame_cnt;
ctx->autorefresh_pending_frame_cnt = frame_cnt;
} else {
if (!ctx->autorefresh_init) {
ctx->autorefresh_init = 1;
ctx->autorefresh_init = true;
mdss_mdp_cmd_clk_on(ctx);
}
mdss_mdp_pingpong_write(ctl->mixer_left->pingpong_base,
MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG,
(enable << 31) |
(frame_cnt));
BIT(31) | frame_cnt);
/*
* This manual kickoff is needed to actually start the
* autorefresh feature. The h/w relies on one commit
@ -806,9 +811,8 @@ static int __mdss_mdp_cmd_configure_autorefresh(struct mdss_mdp_ctl *ctl, int
*/
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
ctl->autorefresh_frame_cnt = frame_cnt;
ctl->cmd_autorefresh_en = 1;
ctl->cmd_autorefresh_en = true;
}
} else {
if (ctx->autorefresh_init) {
/*
@ -820,10 +824,12 @@ static int __mdss_mdp_cmd_configure_autorefresh(struct mdss_mdp_ctl *ctl, int
MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0);
}
ctx->autorefresh_init = 0;
ctx->autorefresh_init = false;
ctx->autorefresh_pending_frame_cnt = 0;
ctx->autorefresh_off_pending = true;
ctl->autorefresh_frame_cnt = 0;
ctl->cmd_autorefresh_en = 0;
ctx->autorefresh_pending = 0;
ctl->cmd_autorefresh_en = false;
}
mutex_unlock(&ctx->autorefresh_mtx);
@ -837,7 +843,6 @@ static int __mdss_mdp_cmd_configure_autorefresh(struct mdss_mdp_ctl *ctl, int
*/
int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *ctl, int frame_cnt)
{
return __mdss_mdp_cmd_configure_autorefresh(ctl, frame_cnt, true);
}
@ -846,8 +851,8 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *ctl, int frame_cnt)
* there was are any pending requests from the sys fs node for the feature and
* if so then it will enable in the h/w.
*/
int mdss_mdp_cmd_enable_cmd_autorefresh(struct mdss_mdp_ctl *ctl,
int frame_cnt)
static int mdss_mdp_cmd_enable_cmd_autorefresh(struct mdss_mdp_ctl *ctl,
int frame_cnt)
{
return __mdss_mdp_cmd_configure_autorefresh(ctl, frame_cnt, false);
}
@ -928,7 +933,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
mdss_mdp_cmd_set_sync_ctx(ctl, sctl);
if (ctx->autorefresh_init) {
if (ctx->autorefresh_init || ctx->autorefresh_off_pending) {
/*
* If autorefresh is enabled then do not queue the frame till
* the next read ptr is done otherwise we might get a pp done
@ -936,19 +941,20 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
*/
pr_debug("Wait for read pointer done before enabling PP irq\n");
wait_for_completion(&ctx->readptr_done);
mdss_mdp_cmd_clk_on(ctx);
}
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
if (sctx)
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, sctx->pp_num);
if (!ctx->autorefresh_pending && !ctl->cmd_autorefresh_en) {
if (!ctx->autorefresh_pending_frame_cnt && !ctl->cmd_autorefresh_en) {
/* Kickoff */
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
} else {
pr_debug("Enabling autorefresh in hardware.\n");
mdss_mdp_cmd_enable_cmd_autorefresh(ctl,
ctx->autorefresh_pending);
ctx->autorefresh_pending_frame_cnt);
}
mdss_mdp_ctl_perf_set_transaction_status(ctl,
@ -1124,9 +1130,9 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
ctx->panel_power_state, panel_power_state);
if (ctl->cmd_autorefresh_en) {
int pre_suspend = ctx->autorefresh_pending;
int pre_suspend = ctx->autorefresh_pending_frame_cnt;
mdss_mdp_cmd_enable_cmd_autorefresh(ctl, 0);
ctx->autorefresh_pending = pre_suspend;
ctx->autorefresh_pending_frame_cnt = pre_suspend;
}
mutex_lock(&ctl->offlock);
@ -1292,7 +1298,8 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
atomic_set(&ctx->pp_done_cnt, 0);
ctx->autorefresh_init = 0;
ctx->autorefresh_off_pending = false;
ctx->autorefresh_init = false;
INIT_LIST_HEAD(&ctx->vsync_handlers);
ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;

View file

@ -2516,8 +2516,8 @@ static ssize_t mdss_mdp_dyn_pu_store(struct device *dev,
return count;
}
static ssize_t mdss_cmd_autorefresh_enabled(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t mdss_mdp_cmd_autorefresh_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret = 0;
struct fb_info *fbi = dev_get_drvdata(dev);
@ -2546,86 +2546,89 @@ static ssize_t mdss_cmd_autorefresh_enabled(struct device *dev,
return ret;
}
static inline int mdss_validate_autorefresh_param(int frame_cnt,
struct mdss_mdp_ctl *ctl)
static inline int mdss_validate_autorefresh_param(struct mdss_mdp_ctl *ctl,
int frame_cnt)
{
int rc = 0;
if (frame_cnt == ctl->autorefresh_frame_cnt) {
/* No parameters were changed */
rc = -EINVAL;
pr_debug("No change to autorefresh parameters\n");
goto no_change;
goto exit;
}
/* Check for correctness. Frame cnt length is 16bits */
if (frame_cnt < 0 || frame_cnt >= BIT(16)) {
rc = -EINVAL;
pr_err("Invalid frame_cnt=%d passed to autorefresh\n",
frame_cnt);
goto no_change;
pr_err("frame cnt %d is out of range (16 bits).\n", frame_cnt);
goto exit;
}
pr_debug("Setting autorefresh_enable=%d frame_cnt=%d\n",
ctl->cmd_autorefresh_en,
frame_cnt);
ctl->cmd_autorefresh_en, frame_cnt);
no_change:
exit:
return rc;
}
static ssize_t mdss_set_cmd_autorefresh(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
static ssize_t mdss_mdp_cmd_autorefresh_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
u32 data = 0;
int frame_cnt, rc;
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
struct mdss_mdp_ctl *ctl;
if (!mfd) {
pr_err("Invalid mfd structure\n");
len = 0;
goto mode_fail;
rc = -EINVAL;
return rc;
}
ctl = mfd_to_ctl(mfd);
if (!ctl) {
pr_err("Invalid ctl structure\n");
len = 0;
goto mode_fail;
rc = -EINVAL;
return rc;
}
if (mfd->panel_info->type != MIPI_CMD_PANEL) {
pr_err("Panel doesnt support autorefresh\n");
len = 0;
goto mode_fail;
rc = -EINVAL;
return rc;
}
if (1 != sscanf(buf, "%d", &data)) {
pr_err("Not able to read video autorefresh value\n");
} else if (!mdss_validate_autorefresh_param(data, ctl)) {
if (ctl->autorefresh_frame_cnt) {
rc = kstrtoint(buf, 10, &frame_cnt);
if (rc) {
pr_err("kstrtoint failed. rc=%d\n", rc);
return rc;
} else {
rc = mdss_validate_autorefresh_param(ctl, frame_cnt);
if (rc)
return rc;
if (frame_cnt) {
/* enable autorefresh */
mfd->mdp_sync_pt_data.threshold = 2;
mfd->mdp_sync_pt_data.retire_threshold = 0;
} else {
/* disable autorefresh */
mfd->mdp_sync_pt_data.threshold = 1;
mfd->mdp_sync_pt_data.retire_threshold = 1;
}
mdss_mdp_ctl_cmd_autorefresh_enable(ctl,
data);
rc = mdss_mdp_ctl_cmd_autorefresh_enable(ctl, frame_cnt);
if (rc)
return rc;
}
pr_debug("Setting video autorefresh=%d cnt=%d\n",
ctl->cmd_autorefresh_en,
data);
ctl->cmd_autorefresh_en, frame_cnt);
mode_fail:
return len;
}
static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR,
mdss_cmd_autorefresh_enabled,
mdss_set_cmd_autorefresh);
mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store);
static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show,
mdss_mdp_ad_store);