msm: mdss: enable partial update with ping-pong split
When ping-pong split is enabled, frame-buffer is not split and user-land program is not aware that at lower level there are two physical panels. Because of this, user-land will always send a single ROI covering the entire frame-buffer. In such cases, it is driver's responsibility to split the ROI into two when ROI is crossing mid-point and make topology changes when ROI is only on left or right panel. Add these changes to support partial update with ping-pong split. Change-Id: I3fa1beac2f7e9700d5b3a3d4fda63078f1e6e976 Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
This commit is contained in:
parent
0974ef0df1
commit
edafc2a85a
5 changed files with 173 additions and 35 deletions
|
@ -246,6 +246,7 @@ struct mdss_mdp_ctl {
|
||||||
int power_state;
|
int power_state;
|
||||||
|
|
||||||
u32 intf_num;
|
u32 intf_num;
|
||||||
|
u32 slave_intf_num; /* ping-pong split */
|
||||||
u32 intf_type;
|
u32 intf_type;
|
||||||
|
|
||||||
u32 opmode;
|
u32 opmode;
|
||||||
|
|
|
@ -2503,10 +2503,10 @@ static void mdss_mdp_ctl_split_display_enable(int enable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdss_mdp_ctl_dst_split_display_enable(int enable,
|
static void mdss_mdp_ctl_pp_split_display_enable(bool enable,
|
||||||
struct mdss_mdp_ctl *ctl)
|
struct mdss_mdp_ctl *ctl)
|
||||||
{
|
{
|
||||||
u32 config = 0, cntl = 0;
|
u32 cfg = 0, cntl = 0;
|
||||||
|
|
||||||
if (ctl->mdata->nppb == 0) {
|
if (ctl->mdata->nppb == 0) {
|
||||||
pr_err("No PPB to enable PP split\n");
|
pr_err("No PPB to enable PP split\n");
|
||||||
|
@ -2516,14 +2516,12 @@ static void mdss_mdp_ctl_dst_split_display_enable(int enable,
|
||||||
mdss_mdp_ctl_split_display_enable(enable, ctl, NULL);
|
mdss_mdp_ctl_split_display_enable(enable, ctl, NULL);
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
/* Set slave intf */
|
cfg = ctl->slave_intf_num << 20; /* Set slave intf */
|
||||||
config = ((ctl->intf_num + 1) - MDSS_MDP_INTF0) << 20;
|
cfg |= BIT(16); /* Set horizontal split */
|
||||||
config |= BIT(16); /* Set horizontal split*/
|
cntl = BIT(5); /* enable dst split */
|
||||||
cntl = BIT(5); /* enable dst split*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writel_relaxed(config, ctl->mdata->mdp_base +
|
writel_relaxed(cfg, ctl->mdata->mdp_base + ctl->mdata->ppb[0].cfg_off);
|
||||||
ctl->mdata->ppb[0].cfg_off);
|
|
||||||
writel_relaxed(cntl, ctl->mdata->mdp_base + ctl->mdata->ppb[0].ctl_off);
|
writel_relaxed(cntl, ctl->mdata->mdp_base + ctl->mdata->ppb[0].ctl_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2740,7 +2738,8 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
|
||||||
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, out);
|
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, out);
|
||||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
|
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
|
||||||
} else if (is_pingpong_split(ctl->mfd)) {
|
} else if (is_pingpong_split(ctl->mfd)) {
|
||||||
mdss_mdp_ctl_dst_split_display_enable(1, ctl);
|
ctl->slave_intf_num = (ctl->intf_num + 1);
|
||||||
|
mdss_mdp_ctl_pp_split_display_enable(true, ctl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3708,9 +3707,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
|
||||||
ATRACE_END("mixer_programming");
|
ATRACE_END("mixer_programming");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl->roi_bkup.w = ctl->roi.w;
|
|
||||||
ctl->roi_bkup.h = ctl->roi.h;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With partial frame update, enable split display bit only
|
* With partial frame update, enable split display bit only
|
||||||
* when validity of ROI's on both the DSI's are identical
|
* when validity of ROI's on both the DSI's are identical
|
||||||
|
@ -3733,17 +3729,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
|
||||||
|
|
||||||
mdss_mdp_xlog_mixer_reg(ctl);
|
mdss_mdp_xlog_mixer_reg(ctl);
|
||||||
|
|
||||||
if (ctl->panel_data &&
|
|
||||||
ctl->panel_data->panel_info.partial_update_enabled) {
|
|
||||||
/*
|
|
||||||
* update roi of panel_info which will be
|
|
||||||
* used by dsi to set col_page addr of panel
|
|
||||||
*/
|
|
||||||
ctl->panel_data->panel_info.roi = ctl->roi;
|
|
||||||
if (sctl && sctl->panel_data)
|
|
||||||
sctl->panel_data->panel_info.roi = sctl->roi;
|
|
||||||
}
|
|
||||||
|
|
||||||
ATRACE_BEGIN("frame_ready");
|
ATRACE_BEGIN("frame_ready");
|
||||||
mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_CFG_DONE);
|
mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_CFG_DONE);
|
||||||
if (commit_cb)
|
if (commit_cb)
|
||||||
|
@ -3756,6 +3741,69 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
|
||||||
if (ctl->ops.wait_pingpong && !mdata->serialize_wait4pp)
|
if (ctl->ops.wait_pingpong && !mdata->serialize_wait4pp)
|
||||||
mdss_mdp_display_wait4pingpong(ctl, false);
|
mdss_mdp_display_wait4pingpong(ctl, false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if serialize_wait4pp is false then roi_bkup used in wait4pingpong
|
||||||
|
* will be of previous frame as expected.
|
||||||
|
*/
|
||||||
|
ctl->roi_bkup.w = ctl->roi.w;
|
||||||
|
ctl->roi_bkup.h = ctl->roi.h;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update roi of panel_info which will be
|
||||||
|
* used by dsi to set col_page addr of panel.
|
||||||
|
*/
|
||||||
|
if (ctl->panel_data &&
|
||||||
|
ctl->panel_data->panel_info.partial_update_enabled) {
|
||||||
|
|
||||||
|
if (is_pingpong_split(ctl->mfd)) {
|
||||||
|
bool pp_split = false;
|
||||||
|
struct mdss_rect l_roi, r_roi, temp = {0};
|
||||||
|
u32 opmode = mdss_mdp_ctl_read(ctl,
|
||||||
|
MDSS_MDP_REG_CTL_TOP) & ~0xF0; /* clear OUT_SEL */
|
||||||
|
/*
|
||||||
|
* with pp split enabled, it is a requirement that both
|
||||||
|
* panels share equal load, so split-point is center.
|
||||||
|
*/
|
||||||
|
u32 left_panel_w = left_lm_w_from_mfd(ctl->mfd) / 2;
|
||||||
|
|
||||||
|
mdss_rect_split(&ctl->roi, &l_roi, &r_roi,
|
||||||
|
left_panel_w);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If update is only on left panel then we still send
|
||||||
|
* zeroed out right panel ROIs to DSI driver. Based on
|
||||||
|
* zeroed ROI, DSI driver identifies which panel is not
|
||||||
|
* transmitting.
|
||||||
|
*/
|
||||||
|
ctl->panel_data->panel_info.roi = l_roi;
|
||||||
|
ctl->panel_data->next->panel_info.roi = r_roi;
|
||||||
|
|
||||||
|
/* based on the roi, update ctl topology */
|
||||||
|
if (!mdss_rect_cmp(&temp, &l_roi) &&
|
||||||
|
!mdss_rect_cmp(&temp, &r_roi)) {
|
||||||
|
/* left + right */
|
||||||
|
opmode |= (ctl->intf_num << 4);
|
||||||
|
pp_split = true;
|
||||||
|
} else if (mdss_rect_cmp(&temp, &l_roi)) {
|
||||||
|
/* right only */
|
||||||
|
opmode |= (ctl->slave_intf_num << 4);
|
||||||
|
pp_split = false;
|
||||||
|
} else {
|
||||||
|
/* left only */
|
||||||
|
opmode |= (ctl->intf_num << 4);
|
||||||
|
pp_split = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, opmode);
|
||||||
|
|
||||||
|
mdss_mdp_ctl_pp_split_display_enable(pp_split, ctl);
|
||||||
|
} else {
|
||||||
|
ctl->panel_data->panel_info.roi = ctl->roi;
|
||||||
|
if (sctl && sctl->panel_data)
|
||||||
|
sctl->panel_data->panel_info.roi = sctl->roi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (commit_cb)
|
if (commit_cb)
|
||||||
commit_cb->commit_cb_fnc(MDP_COMMIT_STAGE_READY_FOR_KICKOFF,
|
commit_cb->commit_cb_fnc(MDP_COMMIT_STAGE_READY_FOR_KICKOFF,
|
||||||
commit_cb->data);
|
commit_cb->data);
|
||||||
|
|
|
@ -607,9 +607,6 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
|
||||||
|
|
||||||
pdata = ctl->panel_data;
|
pdata = ctl->panel_data;
|
||||||
|
|
||||||
ctl->roi_bkup.w = ctl->width;
|
|
||||||
ctl->roi_bkup.h = ctl->height;
|
|
||||||
|
|
||||||
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
|
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
|
||||||
ctx->rdptr_enabled, ctl->roi_bkup.w,
|
ctx->rdptr_enabled, ctl->roi_bkup.w,
|
||||||
ctl->roi_bkup.h);
|
ctl->roi_bkup.h);
|
||||||
|
@ -1261,8 +1258,9 @@ end:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
|
static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
|
||||||
struct mdss_mdp_cmd_ctx *ctx, int pp_num,
|
struct mdss_mdp_cmd_ctx *ctx, int pp_num,
|
||||||
int pingpong_split_slave) {
|
int pingpong_split_slave)
|
||||||
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ctx->ctl = ctl;
|
ctx->ctl = ctl;
|
||||||
|
|
|
@ -1520,9 +1520,24 @@ static int mdss_mdp_commit_cb(enum mdp_commit_stage_type commit_stage,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __validate_roi(struct mdss_mdp_pipe *pipe,
|
/**
|
||||||
|
* __is_roi_valid() - Check if ctl roi is valid for a given pipe.
|
||||||
|
* @pipe: pipe to check against.
|
||||||
|
* @ctl_roi: roi of the ctl path.
|
||||||
|
*
|
||||||
|
* Validate ctl roi against pipe's destination rectangle by checking following
|
||||||
|
* conditions. If any of these conditions are met then return failure,
|
||||||
|
* success otherwise.
|
||||||
|
*
|
||||||
|
* 1. Pipe has scaling and pipe's destination is intersecting with ctl roi.
|
||||||
|
* 2. Pipe's destination and ctl roi overlap, meaning pipe's output is
|
||||||
|
* intersecting or within ctl roi. In such cases, pipe should not be
|
||||||
|
* part of used list and should have been omitted by user-land program.
|
||||||
|
*/
|
||||||
|
static bool __is_roi_valid(struct mdss_mdp_pipe *pipe,
|
||||||
struct mdss_rect *ctl_roi)
|
struct mdss_rect *ctl_roi)
|
||||||
{
|
{
|
||||||
|
/* condition #1 above */
|
||||||
if (pipe->scale.enable_pxl_ext ||
|
if (pipe->scale.enable_pxl_ext ||
|
||||||
(pipe->src.w != pipe->dst.w) ||
|
(pipe->src.w != pipe->dst.w) ||
|
||||||
(pipe->src.h != pipe->dst.h)) {
|
(pipe->src.h != pipe->dst.h)) {
|
||||||
|
@ -1531,10 +1546,14 @@ static bool __validate_roi(struct mdss_mdp_pipe *pipe,
|
||||||
mdss_mdp_intersect_rect(&res, &pipe->dst, ctl_roi);
|
mdss_mdp_intersect_rect(&res, &pipe->dst, ctl_roi);
|
||||||
|
|
||||||
if (!mdss_rect_cmp(&res, &pipe->dst))
|
if (!mdss_rect_cmp(&res, &pipe->dst))
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/* condition #2 above */
|
||||||
|
if (mdss_rect_overlap_check(&pipe->dst, ctl_roi))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mdss_pend_mode_switch(struct msm_fb_data_type *mfd, bool pend_switch)
|
void mdss_pend_mode_switch(struct msm_fb_data_type *mfd, bool pend_switch)
|
||||||
|
@ -1689,9 +1708,9 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
|
||||||
if (data && ctl->panel_data->panel_info.partial_update_enabled) {
|
if (data && ctl->panel_data->panel_info.partial_update_enabled) {
|
||||||
struct mdss_rect ctl_roi;
|
struct mdss_rect ctl_roi;
|
||||||
struct mdp_rect *in_roi;
|
struct mdp_rect *in_roi;
|
||||||
|
|
||||||
skip_partial_update = false;
|
skip_partial_update = false;
|
||||||
list_for_each_entry(pipe, &mdp5_data->pipes_used, list) {
|
list_for_each_entry(pipe, &mdp5_data->pipes_used, list) {
|
||||||
|
|
||||||
in_roi = pipe->mixer_left->is_right_mixer ?
|
in_roi = pipe->mixer_left->is_right_mixer ?
|
||||||
&data->r_roi : &data->l_roi;
|
&data->r_roi : &data->l_roi;
|
||||||
|
|
||||||
|
@ -1700,10 +1719,14 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
|
||||||
ctl_roi.w = in_roi->w;
|
ctl_roi.w = in_roi->w;
|
||||||
ctl_roi.h = in_roi->h;
|
ctl_roi.h = in_roi->h;
|
||||||
|
|
||||||
if (__validate_roi(pipe, &ctl_roi)) {
|
if (!__is_roi_valid(pipe, &ctl_roi)) {
|
||||||
skip_partial_update = true;
|
skip_partial_update = true;
|
||||||
pr_err("error. invalid config with partial update for pipe%d\n",
|
pr_debug("error. invalid config with partial update for pipe%d\n",
|
||||||
pipe->num);
|
pipe->num);
|
||||||
|
pr_debug("ctl_roi: %d,%d,%d,%d pipe->dst: %d,%d,%d,%d\n",
|
||||||
|
ctl_roi.x, ctl_roi.y, ctl_roi.w,
|
||||||
|
ctl_roi.h, pipe->dst.x, pipe->dst.y,
|
||||||
|
pipe->dst.w, pipe->dst.h);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1712,6 +1735,8 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
|
||||||
if (!skip_partial_update) {
|
if (!skip_partial_update) {
|
||||||
mdss_mdp_set_roi(ctl, data);
|
mdss_mdp_set_roi(ctl, data);
|
||||||
} else {
|
} else {
|
||||||
|
memset(&temp_data, 0, sizeof(temp_data));
|
||||||
|
|
||||||
temp_data.l_roi = (struct mdp_rect){0, 0,
|
temp_data.l_roi = (struct mdp_rect){0, 0,
|
||||||
ctl->mixer_left->width, ctl->mixer_left->height};
|
ctl->mixer_left->width, ctl->mixer_left->height};
|
||||||
if (ctl->mixer_right) {
|
if (ctl->mixer_right) {
|
||||||
|
@ -3429,7 +3454,7 @@ static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
|
||||||
|
|
||||||
if (mfd->panel_info->partial_update_enabled && mdp5_data->dyn_pu_state
|
if (mfd->panel_info->partial_update_enabled && mdp5_data->dyn_pu_state
|
||||||
&& (cmd != MSMFB_HISTOGRAM_STOP)) {
|
&& (cmd != MSMFB_HISTOGRAM_STOP)) {
|
||||||
pr_err("Partial update feature is enabled.\n");
|
pr_debug("Partial update feature is enabled.\n");
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -540,6 +540,72 @@ static inline int mdss_rect_cmp(struct mdss_rect *rect1,
|
||||||
rect1->w == rect2->w && rect1->h == rect2->h);
|
rect1->w == rect2->w && rect1->h == rect2->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mdss_rect_overlap_check() - compare two rects and check if they overlap
|
||||||
|
* @rect1 - rect value to compare
|
||||||
|
* @rect2 - rect value to compare
|
||||||
|
*
|
||||||
|
* Returns true if rects overlap, false otherwise.
|
||||||
|
*/
|
||||||
|
static inline bool mdss_rect_overlap_check(struct mdss_rect *rect1,
|
||||||
|
struct mdss_rect *rect2)
|
||||||
|
{
|
||||||
|
u32 rect1_left = rect1->x, rect1_right = rect1->x + rect1->w;
|
||||||
|
u32 rect1_top = rect1->y, rect1_bottom = rect1->y + rect1->h;
|
||||||
|
u32 rect2_left = rect2->x, rect2_right = rect2->x + rect2->w;
|
||||||
|
u32 rect2_top = rect2->y, rect2_bottom = rect2->y + rect2->h;
|
||||||
|
|
||||||
|
if ((rect1_right <= rect2_left) ||
|
||||||
|
(rect1_left >= rect2_right) ||
|
||||||
|
(rect1_bottom <= rect2_top) ||
|
||||||
|
(rect1_top >= rect2_bottom))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mdss_rect_split() - split roi into two with regards to split-point.
|
||||||
|
* @in_roi - input roi, non-split
|
||||||
|
* @l_roi - left roi after split
|
||||||
|
* @r_roi - right roi after split
|
||||||
|
*
|
||||||
|
* Split input ROI into left and right ROIs with respect to split-point. This
|
||||||
|
* is useful during partial update with ping-pong split enabled, where user-land
|
||||||
|
* program is aware of only one frame-buffer but physically there are two
|
||||||
|
* distinct panels which requires their own ROIs.
|
||||||
|
*/
|
||||||
|
static inline void mdss_rect_split(struct mdss_rect *in_roi,
|
||||||
|
struct mdss_rect *l_roi, struct mdss_rect *r_roi, u32 splitpoint)
|
||||||
|
{
|
||||||
|
memset(l_roi, 0x0, sizeof(*l_roi));
|
||||||
|
memset(r_roi, 0x0, sizeof(*r_roi));
|
||||||
|
|
||||||
|
/* left update needed */
|
||||||
|
if (in_roi->x < splitpoint) {
|
||||||
|
*l_roi = *in_roi;
|
||||||
|
|
||||||
|
if (l_roi->x + l_roi->w >= splitpoint)
|
||||||
|
l_roi->w = splitpoint - in_roi->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* right update needed */
|
||||||
|
if ((in_roi->x + in_roi->w) > splitpoint) {
|
||||||
|
*r_roi = *in_roi;
|
||||||
|
|
||||||
|
if (in_roi->x < splitpoint) {
|
||||||
|
r_roi->x = 0;
|
||||||
|
r_roi->w = in_roi->x + in_roi->w - splitpoint;
|
||||||
|
} else {
|
||||||
|
r_roi->x = in_roi->x - splitpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("left: %d,%d,%d,%d right: %d,%d,%d,%d\n",
|
||||||
|
l_roi->x, l_roi->y, l_roi->w, l_roi->h,
|
||||||
|
r_roi->x, r_roi->y, r_roi->w, r_roi->h);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mdss_panel_get_vtotal() - return panel vertical height
|
* mdss_panel_get_vtotal() - return panel vertical height
|
||||||
* @pinfo: Pointer to panel info containing all panel information
|
* @pinfo: Pointer to panel info containing all panel information
|
||||||
|
|
Loading…
Add table
Reference in a new issue