msm: mdss: Add support for command mode autorefresh
This change adds support to autorefresh the command mode panels without having to manually issue a kickoff. We need to enable sys/class/graphics/fb0/msm_cmd_autorefresh_en to configure after how many idle ticks(read ptr/vsync) should we trigger a frame. e.g. If we want to send an update at 60fps we need to echo 1 > sys/class/graphics/fb0/msm_cmd_autorefresh_en to disable we need to echo 0 > sys/class/graphics/fb0/msm_cmd_autorefresh_en Change-Id: Ib0cda1142f8fadfa6cad5e61e0c7fb36fe43aca1 Signed-off-by: Siddhartha Agrawal <agrawals@codeaurora.org> [imaund@codeaurora.org: Updated INIT_COMPLETION call to reinit_completion] Signed-off-by: Ian Maund <imaund@codeaurora.org>
This commit is contained in:
parent
f40a73c904
commit
c4c4dac0e1
4 changed files with 268 additions and 3 deletions
|
@ -250,6 +250,9 @@ struct mdss_mdp_ctl {
|
||||||
u8 roi_changed;
|
u8 roi_changed;
|
||||||
u8 valid_roi;
|
u8 valid_roi;
|
||||||
|
|
||||||
|
int cmd_autorefresh_en;
|
||||||
|
int autorefresh_frame_cnt;
|
||||||
|
|
||||||
int (*start_fnc) (struct mdss_mdp_ctl *ctl);
|
int (*start_fnc) (struct mdss_mdp_ctl *ctl);
|
||||||
int (*stop_fnc) (struct mdss_mdp_ctl *ctl, int panel_power_state);
|
int (*stop_fnc) (struct mdss_mdp_ctl *ctl, int panel_power_state);
|
||||||
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
|
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
|
||||||
|
@ -1038,5 +1041,9 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl);
|
||||||
int mdss_mdp_wait_for_xin_halt(u32 xin_id, bool is_vbif_nrt);
|
int mdss_mdp_wait_for_xin_halt(u32 xin_id, bool is_vbif_nrt);
|
||||||
void mdss_mdp_set_ot_limit(struct mdss_mdp_set_ot_params *params,
|
void mdss_mdp_set_ot_limit(struct mdss_mdp_set_ot_params *params,
|
||||||
bool is_rot, bool is_wb, bool is_yuv);
|
bool is_rot, bool is_wb, bool is_yuv);
|
||||||
|
int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *ctl,
|
||||||
|
int frame_cnt);
|
||||||
|
int mdss_mdp_ctl_cmd_autorefresh_enable(struct mdss_mdp_ctl *ctl,
|
||||||
|
int frame_cnt);
|
||||||
|
|
||||||
#endif /* MDSS_MDP_H */
|
#endif /* MDSS_MDP_H */
|
||||||
|
|
|
@ -1786,6 +1786,20 @@ int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mdss_mdp_ctl_cmd_autorefresh_enable(struct mdss_mdp_ctl *ctl,
|
||||||
|
int frame_cnt)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
if (ctl->panel_data->panel_info.type == MIPI_CMD_PANEL) {
|
||||||
|
mdss_mdp_cmd_set_autorefresh_mode(ctl,
|
||||||
|
frame_cnt);
|
||||||
|
} else {
|
||||||
|
pr_err("Mode not supported for this panel\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff)
|
int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff)
|
||||||
{
|
{
|
||||||
switch (ctl->panel_data->panel_info.type) {
|
switch (ctl->panel_data->panel_info.type) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct mdss_mdp_cmd_ctx {
|
||||||
u32 pp_num;
|
u32 pp_num;
|
||||||
u8 ref_cnt;
|
u8 ref_cnt;
|
||||||
struct completion stop_comp;
|
struct completion stop_comp;
|
||||||
|
struct completion readptr_done;
|
||||||
wait_queue_head_t pp_waitq;
|
wait_queue_head_t pp_waitq;
|
||||||
struct list_head vsync_handlers;
|
struct list_head vsync_handlers;
|
||||||
int panel_power_state;
|
int panel_power_state;
|
||||||
|
@ -50,7 +51,10 @@ struct mdss_mdp_cmd_ctx {
|
||||||
spinlock_t koff_lock;
|
spinlock_t koff_lock;
|
||||||
struct work_struct clk_work;
|
struct work_struct clk_work;
|
||||||
struct work_struct pp_done_work;
|
struct work_struct pp_done_work;
|
||||||
|
struct mutex autorefresh_mtx;
|
||||||
atomic_t pp_done_cnt;
|
atomic_t pp_done_cnt;
|
||||||
|
int autorefresh_pending;
|
||||||
|
u8 autorefresh_init;
|
||||||
struct mdss_intf_recovery intf_recovery;
|
struct mdss_intf_recovery intf_recovery;
|
||||||
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
|
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
|
||||||
u32 pp_timeout_report_cnt;
|
u32 pp_timeout_report_cnt;
|
||||||
|
@ -259,6 +263,11 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
|
||||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||||
int set_clk_off = 0;
|
int set_clk_off = 0;
|
||||||
|
|
||||||
|
if (ctx->autorefresh_init) {
|
||||||
|
/* Do not turn off clocks if aurtorefresh is on. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&ctx->clk_mtx);
|
mutex_lock(&ctx->clk_mtx);
|
||||||
MDSS_XLOG(ctx->pp_num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
|
MDSS_XLOG(ctx->pp_num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
|
||||||
ctx->rdptr_enabled);
|
ctx->rdptr_enabled);
|
||||||
|
@ -267,6 +276,8 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
|
||||||
set_clk_off = 1;
|
set_clk_off = 1;
|
||||||
spin_unlock_irqrestore(&ctx->clk_lock, flags);
|
spin_unlock_irqrestore(&ctx->clk_lock, flags);
|
||||||
|
|
||||||
|
pr_debug("clk_enabled =%d set_clk_off=%d\n", ctx->clk_enabled,
|
||||||
|
set_clk_off);
|
||||||
if (ctx->clk_enabled && set_clk_off) {
|
if (ctx->clk_enabled && set_clk_off) {
|
||||||
ctx->clk_enabled = 0;
|
ctx->clk_enabled = 0;
|
||||||
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
|
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
|
||||||
|
@ -291,6 +302,11 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->autorefresh_init) {
|
||||||
|
pr_debug("Completing read pointer done\n");
|
||||||
|
complete_all(&ctx->readptr_done);
|
||||||
|
}
|
||||||
|
|
||||||
vsync_time = ktime_get();
|
vsync_time = ktime_get();
|
||||||
ctl->vsync_cnt++;
|
ctl->vsync_cnt++;
|
||||||
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
|
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
|
||||||
|
@ -303,7 +319,7 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx->vsync_enabled) {
|
if (!ctx->vsync_enabled) {
|
||||||
if (ctx->rdptr_enabled)
|
if (ctx->rdptr_enabled && !ctx->autorefresh_init)
|
||||||
ctx->rdptr_enabled--;
|
ctx->rdptr_enabled--;
|
||||||
|
|
||||||
/* keep clk on during kickoff */
|
/* keep clk on during kickoff */
|
||||||
|
@ -396,7 +412,7 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)
|
||||||
schedule_work(&ctx->pp_done_work);
|
schedule_work(&ctx->pp_done_work);
|
||||||
}
|
}
|
||||||
wake_up_all(&ctx->pp_waitq);
|
wake_up_all(&ctx->pp_waitq);
|
||||||
} else {
|
} else if (!ctl->cmd_autorefresh_en) {
|
||||||
pr_err("%s: should not have pingpong interrupt!\n", __func__);
|
pr_err("%s: should not have pingpong interrupt!\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,6 +761,97 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!ctl || !ctl->mixer_left) {
|
||||||
|
pr_err("invalid ctl structure\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
|
||||||
|
if (!ctx) {
|
||||||
|
pr_err("invalid ctx\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_cnt == ctl->autorefresh_frame_cnt) {
|
||||||
|
pr_err("No change to the refresh count\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pr_debug("%s enable = %d frame_cnt = %d clk_cnt=%d\n", __func__,
|
||||||
|
enable, frame_cnt, ctx->autorefresh_init);
|
||||||
|
|
||||||
|
mutex_lock(&ctx->autorefresh_mtx);
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
if (delayed) {
|
||||||
|
ctx->autorefresh_pending = frame_cnt;
|
||||||
|
} else {
|
||||||
|
if (!ctx->autorefresh_init) {
|
||||||
|
ctx->autorefresh_init = 1;
|
||||||
|
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));
|
||||||
|
/*
|
||||||
|
* This manual kickoff is needed to actually start the
|
||||||
|
* autorefresh feature. The h/w relies on one commit
|
||||||
|
* before it starts counting the read ptrs to trigger
|
||||||
|
* the frames.
|
||||||
|
*/
|
||||||
|
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
|
||||||
|
ctl->autorefresh_frame_cnt = frame_cnt;
|
||||||
|
ctl->cmd_autorefresh_en = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (ctx->autorefresh_init) {
|
||||||
|
/*
|
||||||
|
* Safe to turn off the feature. The clocks will be on
|
||||||
|
* at this time since the feature was enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mdss_mdp_pingpong_write(ctl->mixer_left->pingpong_base,
|
||||||
|
MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->autorefresh_init = 0;
|
||||||
|
ctl->autorefresh_frame_cnt = 0;
|
||||||
|
ctl->cmd_autorefresh_en = 0;
|
||||||
|
ctx->autorefresh_pending = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&ctx->autorefresh_mtx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function will be called from the sysfs node to enable and disable the
|
||||||
|
* feature.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is called from the commit thread. This function will check if
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
return __mdss_mdp_cmd_configure_autorefresh(ctl, frame_cnt, false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There are 3 partial update possibilities
|
* There are 3 partial update possibilities
|
||||||
* left only ==> enable left pingpong_done
|
* left only ==> enable left pingpong_done
|
||||||
|
@ -773,6 +880,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reinit_completion(&ctx->readptr_done);
|
||||||
/* sctl will be null for right only in the case of Partial update */
|
/* sctl will be null for right only in the case of Partial update */
|
||||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||||
|
|
||||||
|
@ -820,6 +928,16 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
||||||
|
|
||||||
mdss_mdp_cmd_set_sync_ctx(ctl, sctl);
|
mdss_mdp_cmd_set_sync_ctx(ctl, sctl);
|
||||||
|
|
||||||
|
if (ctx->autorefresh_init) {
|
||||||
|
/*
|
||||||
|
* If autorefresh is enabled then do not queue the frame till
|
||||||
|
* the next read ptr is done otherwise we might get a pp done
|
||||||
|
* immediately for the past autorefresh frame instead.
|
||||||
|
*/
|
||||||
|
pr_debug("Wait for read pointer done before enabling PP irq\n");
|
||||||
|
wait_for_completion(&ctx->readptr_done);
|
||||||
|
}
|
||||||
|
|
||||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
|
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
|
||||||
if (sctx)
|
if (sctx)
|
||||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, sctx->pp_num);
|
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, sctx->pp_num);
|
||||||
|
@ -828,7 +946,14 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
||||||
ctl->mdata->mdp_rev == MDSS_MDP_HW_REV_109)
|
ctl->mdata->mdp_rev == MDSS_MDP_HW_REV_109)
|
||||||
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_INTF_RESTORE, NULL);
|
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_INTF_RESTORE, NULL);
|
||||||
|
|
||||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1); /* Kickoff */
|
if (!ctx->autorefresh_pending && !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);
|
||||||
|
}
|
||||||
|
|
||||||
mdss_mdp_ctl_perf_set_transaction_status(ctl,
|
mdss_mdp_ctl_perf_set_transaction_status(ctl,
|
||||||
PERF_SW_COMMIT_STATE, PERF_STATUS_DONE);
|
PERF_SW_COMMIT_STATE, PERF_STATUS_DONE);
|
||||||
|
@ -1002,6 +1127,12 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
|
||||||
pr_debug("%s: transition from %d --> %d\n", __func__,
|
pr_debug("%s: transition from %d --> %d\n", __func__,
|
||||||
ctx->panel_power_state, panel_power_state);
|
ctx->panel_power_state, panel_power_state);
|
||||||
|
|
||||||
|
if (ctl->cmd_autorefresh_en) {
|
||||||
|
int pre_suspend = ctx->autorefresh_pending;
|
||||||
|
mdss_mdp_cmd_enable_cmd_autorefresh(ctl, 0);
|
||||||
|
ctx->autorefresh_pending = pre_suspend;
|
||||||
|
}
|
||||||
|
|
||||||
if (__mdss_mdp_cmd_is_panel_power_on_interactive(ctx)) {
|
if (__mdss_mdp_cmd_is_panel_power_on_interactive(ctx)) {
|
||||||
if (mdss_panel_is_power_on_lp(panel_power_state)) {
|
if (mdss_panel_is_power_on_lp(panel_power_state)) {
|
||||||
/*
|
/*
|
||||||
|
@ -1152,12 +1283,15 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
||||||
ctx->pp_timeout_report_cnt = 0;
|
ctx->pp_timeout_report_cnt = 0;
|
||||||
init_waitqueue_head(&ctx->pp_waitq);
|
init_waitqueue_head(&ctx->pp_waitq);
|
||||||
init_completion(&ctx->stop_comp);
|
init_completion(&ctx->stop_comp);
|
||||||
|
init_completion(&ctx->readptr_done);
|
||||||
spin_lock_init(&ctx->clk_lock);
|
spin_lock_init(&ctx->clk_lock);
|
||||||
spin_lock_init(&ctx->koff_lock);
|
spin_lock_init(&ctx->koff_lock);
|
||||||
mutex_init(&ctx->clk_mtx);
|
mutex_init(&ctx->clk_mtx);
|
||||||
|
mutex_init(&ctx->autorefresh_mtx);
|
||||||
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
|
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
|
||||||
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
|
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
|
||||||
atomic_set(&ctx->pp_done_cnt, 0);
|
atomic_set(&ctx->pp_done_cnt, 0);
|
||||||
|
ctx->autorefresh_init = 0;
|
||||||
INIT_LIST_HEAD(&ctx->vsync_handlers);
|
INIT_LIST_HEAD(&ctx->vsync_handlers);
|
||||||
|
|
||||||
ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
|
ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
|
||||||
|
|
|
@ -2366,7 +2366,116 @@ static ssize_t mdss_mdp_dyn_pu_store(struct device *dev,
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
static ssize_t mdss_cmd_autorefresh_enabled(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
ssize_t ret = 0;
|
||||||
|
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");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctl = mfd_to_ctl(mfd);
|
||||||
|
if (!ctl) {
|
||||||
|
pr_err("Invalid ctl structure\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (mfd->panel_info->type != MIPI_CMD_PANEL) {
|
||||||
|
pr_err("Panel doesnt support autorefresh\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
} else {
|
||||||
|
ret = snprintf(buf, PAGE_SIZE, "%d\n",
|
||||||
|
ctl->autorefresh_frame_cnt);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mdss_validate_autorefresh_param(int frame_cnt,
|
||||||
|
struct mdss_mdp_ctl *ctl)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_debug("Setting autorefresh_enable=%d frame_cnt=%d\n",
|
||||||
|
ctl->cmd_autorefresh_en,
|
||||||
|
frame_cnt);
|
||||||
|
|
||||||
|
no_change:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mdss_set_cmd_autorefresh(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
u32 data = 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctl = mfd_to_ctl(mfd);
|
||||||
|
if (!ctl) {
|
||||||
|
pr_err("Invalid ctl structure\n");
|
||||||
|
len = 0;
|
||||||
|
goto mode_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mfd->panel_info->type != MIPI_CMD_PANEL) {
|
||||||
|
pr_err("Panel doesnt support autorefresh\n");
|
||||||
|
len = 0;
|
||||||
|
goto mode_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
mfd->mdp_sync_pt_data.threshold = 2;
|
||||||
|
mfd->mdp_sync_pt_data.retire_threshold = 0;
|
||||||
|
} else {
|
||||||
|
mfd->mdp_sync_pt_data.threshold = 1;
|
||||||
|
mfd->mdp_sync_pt_data.retire_threshold = 1;
|
||||||
|
}
|
||||||
|
mdss_mdp_ctl_cmd_autorefresh_enable(ctl,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
pr_debug("Setting video autorefresh=%d cnt=%d\n",
|
||||||
|
ctl->cmd_autorefresh_en,
|
||||||
|
data);
|
||||||
|
|
||||||
|
mode_fail:
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR,
|
||||||
|
mdss_cmd_autorefresh_enabled,
|
||||||
|
mdss_set_cmd_autorefresh);
|
||||||
static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
|
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,
|
static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show,
|
||||||
mdss_mdp_ad_store);
|
mdss_mdp_ad_store);
|
||||||
|
@ -2377,6 +2486,7 @@ static struct attribute *mdp_overlay_sysfs_attrs[] = {
|
||||||
&dev_attr_vsync_event.attr,
|
&dev_attr_vsync_event.attr,
|
||||||
&dev_attr_ad.attr,
|
&dev_attr_ad.attr,
|
||||||
&dev_attr_dyn_pu.attr,
|
&dev_attr_dyn_pu.attr,
|
||||||
|
&dev_attr_msm_cmd_autorefresh_en.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue