summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-11-08 11:18:38 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-08 11:18:38 -0800
commitcb5186819881878a9f64320a3a110e7490c57f2b (patch)
treec1cf73bd9a4c459e0841aa8f9e5e871f79994fbb /drivers
parentf4317920e6fad5d3c99fa3c7c4da4e85ef0d15f8 (diff)
parentd5da41a9807d90b8ee842a6bfafb35a7825f4ca7 (diff)
Merge "msm: mdss: add multiple partial update support"
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c121
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c71
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c165
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h89
10 files changed, 440 insertions, 40 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 7091dc2f38b9..3536cb2d294d 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -468,6 +468,7 @@ struct mdss_dsi_ctrl_pdata {
bool cmd_sync_wait_trigger;
struct mdss_rect roi;
+ struct mdss_dsi_dual_pu_roi dual_roi;
struct pwm_device *pwm_bl;
u32 pclk_rate;
u32 byte_clk_rate;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index bd0c2ad32c05..7c36bb627043 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -447,28 +447,82 @@ static int mdss_dsi_roi_merge(struct mdss_dsi_ctrl_pdata *ctrl,
static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */
static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00}; /* DTYPE_DCS_LWRITE */
+/*
+ * Some panels can support multiple ROIs as part of the below commands
+ */
+static char caset_dual[] = {0x2a, 0x00, 0x00, 0x03, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */
+static char paset_dual[] = {0x2b, 0x00, 0x00, 0x05, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */
+
/* pack into one frame before sent */
static struct dsi_cmd_desc set_col_page_addr_cmd[] = {
{{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset)}, caset}, /* packed */
{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset},
};
+/* pack into one frame before sent */
+static struct dsi_cmd_desc set_dual_col_page_addr_cmd[] = { /*packed*/
+ {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset_dual)}, caset_dual},
+ {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset_dual)}, paset_dual},
+};
+
+
+static void __mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct mdss_rect *roi, bool dual_roi)
+{
+ if (dual_roi) {
+ struct mdss_rect *first, *second;
+
+ first = &ctrl->panel_data.panel_info.dual_roi.first_roi;
+ second = &ctrl->panel_data.panel_info.dual_roi.second_roi;
+
+ caset_dual[1] = (((first->x) & 0xFF00) >> 8);
+ caset_dual[2] = (((first->x) & 0xFF));
+ caset_dual[3] = (((first->x - 1 + first->w) & 0xFF00) >> 8);
+ caset_dual[4] = (((first->x - 1 + first->w) & 0xFF));
+ /* skip the MPU setting byte*/
+ caset_dual[6] = (((second->x) & 0xFF00) >> 8);
+ caset_dual[7] = (((second->x) & 0xFF));
+ caset_dual[8] = (((second->x - 1 + second->w) & 0xFF00) >> 8);
+ caset_dual[9] = (((second->x - 1 + second->w) & 0xFF));
+ set_dual_col_page_addr_cmd[0].payload = caset_dual;
+
+ paset_dual[1] = (((first->y) & 0xFF00) >> 8);
+ paset_dual[2] = (((first->y) & 0xFF));
+ paset_dual[3] = (((first->y - 1 + first->h) & 0xFF00) >> 8);
+ paset_dual[4] = (((first->y - 1 + first->h) & 0xFF));
+ /* skip the MPU setting byte */
+ paset_dual[6] = (((second->y) & 0xFF00) >> 8);
+ paset_dual[7] = (((second->y) & 0xFF));
+ paset_dual[8] = (((second->y - 1 + second->h) & 0xFF00) >> 8);
+ paset_dual[9] = (((second->y - 1 + second->h) & 0xFF));
+ set_dual_col_page_addr_cmd[1].payload = paset_dual;
+ } else {
+ caset[1] = (((roi->x) & 0xFF00) >> 8);
+ caset[2] = (((roi->x) & 0xFF));
+ caset[3] = (((roi->x - 1 + roi->w) & 0xFF00) >> 8);
+ caset[4] = (((roi->x - 1 + roi->w) & 0xFF));
+ set_col_page_addr_cmd[0].payload = caset;
+
+ paset[1] = (((roi->y) & 0xFF00) >> 8);
+ paset[2] = (((roi->y) & 0xFF));
+ paset[3] = (((roi->y - 1 + roi->h) & 0xFF00) >> 8);
+ paset[4] = (((roi->y - 1 + roi->h) & 0xFF));
+ set_col_page_addr_cmd[1].payload = paset;
+ }
+ pr_debug("%s Sending 2A 2B cmnd with dual_roi=%d\n", __func__,
+ dual_roi);
+
+}
static void mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl,
struct mdss_rect *roi, int unicast)
{
struct dcs_cmd_req cmdreq;
+ struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info;
+ bool dual_roi = pinfo->dual_roi.enabled;
- caset[1] = (((roi->x) & 0xFF00) >> 8);
- caset[2] = (((roi->x) & 0xFF));
- caset[3] = (((roi->x - 1 + roi->w) & 0xFF00) >> 8);
- caset[4] = (((roi->x - 1 + roi->w) & 0xFF));
- set_col_page_addr_cmd[0].payload = caset;
-
- paset[1] = (((roi->y) & 0xFF00) >> 8);
- paset[2] = (((roi->y) & 0xFF));
- paset[3] = (((roi->y - 1 + roi->h) & 0xFF00) >> 8);
- paset[4] = (((roi->y - 1 + roi->h) & 0xFF));
- set_col_page_addr_cmd[1].payload = paset;
+ __mdss_dsi_send_col_page_addr(ctrl, roi, dual_roi);
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds_cnt = 2;
@@ -478,7 +532,9 @@ static void mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl,
cmdreq.rlen = 0;
cmdreq.cb = NULL;
- cmdreq.cmds = set_col_page_addr_cmd;
+ /* Send default or dual roi 2A/2B cmd */
+ cmdreq.cmds = dual_roi ? set_dual_col_page_addr_cmd :
+ set_col_page_addr_cmd;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
@@ -1837,20 +1893,28 @@ error:
pinfo->esd_check_enabled = false;
}
-static int mdss_dsi_parse_panel_features(struct device_node *np,
- struct mdss_dsi_ctrl_pdata *ctrl)
+static void mdss_dsi_parse_partial_update_caps(struct device_node *np,
+ struct mdss_dsi_ctrl_pdata *ctrl)
{
struct mdss_panel_info *pinfo;
-
- if (!np || !ctrl) {
- pr_err("%s: Invalid arguments\n", __func__);
- return -ENODEV;
- }
+ const char *data;
pinfo = &ctrl->panel_data.panel_info;
- pinfo->partial_update_supported = of_property_read_bool(np,
- "qcom,partial-update-enabled");
+ data = of_get_property(np, "qcom,partial-update-enabled", NULL);
+ if (data && !strcmp(data, "single_roi"))
+ pinfo->partial_update_supported =
+ PU_SINGLE_ROI;
+ else if (data && !strcmp(data, "dual_roi"))
+ pinfo->partial_update_supported =
+ PU_DUAL_ROI;
+ else if (data && !strcmp(data, "none"))
+ pinfo->partial_update_supported =
+ PU_NOT_SUPPORTED;
+ else
+ pinfo->partial_update_supported =
+ PU_NOT_SUPPORTED;
+
if (pinfo->mipi.mode == DSI_CMD_MODE) {
pinfo->partial_update_enabled = pinfo->partial_update_supported;
pr_info("%s: partial_update_enabled=%d\n", __func__,
@@ -1862,6 +1926,21 @@ static int mdss_dsi_parse_panel_features(struct device_node *np,
"qcom,partial-update-roi-merge");
}
}
+}
+
+static int mdss_dsi_parse_panel_features(struct device_node *np,
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mdss_panel_info *pinfo;
+
+ if (!np || !ctrl) {
+ pr_err("%s: Invalid arguments\n", __func__);
+ return -ENODEV;
+ }
+
+ pinfo = &ctrl->panel_data.panel_info;
+
+ mdss_dsi_parse_partial_update_caps(np, ctrl);
pinfo->dcs_cmd_by_left = of_property_read_bool(np,
"qcom,dcs-cmd-by-left");
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index bcd23d3c19f2..08e06c75522a 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -564,7 +564,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
"min_fps=%d\nmax_fps=%d\npanel_name=%s\n"
"primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n"
"is_cec_supported=%d\nis_pingpong_split=%d\n"
- "dfps_porch_mode=%d\n",
+ "dfps_porch_mode=%d\npu_roi_cnt=%d\ndual_dsi=%d",
pinfo->partial_update_enabled,
pinfo->roi_alignment.xstart_pix_align,
pinfo->roi_alignment.width_pix_align,
@@ -577,7 +577,8 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
pinfo->panel_name, pinfo->is_prim_panel,
pinfo->is_pluggable, pinfo->display_id,
pinfo->is_cec_supported, is_pingpong_split(mfd),
- dfps_porch_mode);
+ dfps_porch_mode, pinfo->partial_update_enabled,
+ is_panel_split(mfd));
return ret;
}
@@ -3282,6 +3283,7 @@ int mdss_fb_atomic_commit(struct fb_info *info,
mfd->msm_fb_backup.atomic_commit = true;
mfd->msm_fb_backup.disp_commit.l_roi = commit_v1->left_roi;
mfd->msm_fb_backup.disp_commit.r_roi = commit_v1->right_roi;
+ mfd->msm_fb_backup.disp_commit.flags = commit_v1->flags;
mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 9f3f018eb80a..dc07fa8bf82e 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -829,6 +829,9 @@ struct mdss_mdp_pipe {
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
+ /* flag to re-store roi in case of pu dual-roi validation error */
+ bool restore_roi;
+
/* compression ratio from the source format */
struct mult_factor comp_ratio;
@@ -1849,7 +1852,7 @@ void mdss_mdp_intersect_rect(struct mdss_rect *res_rect,
const struct mdss_rect *sci_rect);
void mdss_mdp_crop_rect(struct mdss_rect *src_rect,
struct mdss_rect *dst_rect,
- const struct mdss_rect *sci_rect);
+ const struct mdss_rect *sci_rect, bool normalize);
void rect_copy_mdss_to_mdp(struct mdp_rect *user, struct mdss_rect *kernel);
void rect_copy_mdp_to_mdss(struct mdp_rect *user, struct mdss_rect *kernel);
bool mdss_rect_overlap_check(struct mdss_rect *rect1, struct mdss_rect *rect2);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index d3130452328f..9ed44937efe6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -728,7 +728,7 @@ int mdss_mdp_get_pipe_overlap_bw(struct mdss_mdp_pipe *pipe,
/* crop rectangles */
if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req)
- mdss_mdp_crop_rect(&src, &dst, roi);
+ mdss_mdp_crop_rect(&src, &dst, roi, true);
/*
* when doing vertical decimation lines will be skipped, hence there is
@@ -1108,7 +1108,7 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
/* crop rectangles */
if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req)
- mdss_mdp_crop_rect(&src, &dst, roi);
+ mdss_mdp_crop_rect(&src, &dst, roi, true);
pr_debug("v_total=%d, xres=%d fps=%d\n", v_total, xres, fps);
pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) dst_y=%d bpp=%d yuv=%d\n",
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 353d07ad64ac..1ff5d5e68575 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -522,6 +522,56 @@ static void __update_avr_info(struct mdss_mdp_ctl *ctl,
}
/*
+ * __validate_dual_partial_update() - validation function for
+ * dual partial update ROIs
+ *
+ * - This function uses the commit structs "left_roi" and "right_roi"
+ * to pass the first and second ROI information for the multiple
+ * partial update feature.
+ * - Supports only SINGLE DSI with a max of 2 PU ROIs.
+ * - Not supported along with destination scalar.
+ * - Not supported when source-split is disabled.
+ * - Not supported with ping-pong split enabled.
+ */
+static int __validate_dual_partial_update(
+ struct mdss_mdp_ctl *ctl, struct mdp_layer_commit_v1 *commit)
+{
+ struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
+ struct mdss_data_type *mdata = ctl->mdata;
+ struct mdss_rect first_roi, second_roi;
+ int ret = 0;
+ struct mdp_destination_scaler_data *ds_data = commit->dest_scaler;
+
+ if (!mdata->has_src_split
+ || (is_panel_split(ctl->mfd))
+ || (is_pingpong_split(ctl->mfd))
+ || (ds_data && commit->dest_scaler_cnt &&
+ ds_data->flags & MDP_DESTSCALER_ENABLE)) {
+ pr_err("Invalid mode multi pu src_split:%d, split_mode:%d, ds_cnt:%d\n",
+ mdata->has_src_split, ctl->mfd->split_mode,
+ commit->dest_scaler_cnt);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ rect_copy_mdp_to_mdss(&commit->left_roi, &first_roi);
+ rect_copy_mdp_to_mdss(&commit->right_roi, &second_roi);
+
+ if (!is_valid_pu_dual_roi(pinfo, &first_roi, &second_roi))
+ ret = -EINVAL;
+
+ MDSS_XLOG(ctl->num, first_roi.x, first_roi.y, first_roi.w, first_roi.h,
+ second_roi.x, second_roi.y, second_roi.w, second_roi.h,
+ ret);
+ pr_debug("Multiple PU ROIs - roi0:{%d,%d,%d,%d}, roi1{%d,%d,%d,%d}, ret:%d\n",
+ first_roi.x, first_roi.y, first_roi.w, first_roi.h,
+ second_roi.x, second_roi.y, second_roi.w,
+ second_roi.h, ret);
+end:
+ return ret;
+}
+
+/*
* __layer_needs_src_split() - check needs source split configuration
* @layer: input layer
*
@@ -1000,6 +1050,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd,
pipe->is_handed_off = false;
pipe->async_update = (layer->flags & MDP_LAYER_ASYNC) ? true : false;
pipe->csc_coeff_set = layer->color_space;
+ pipe->restore_roi = false;
if (mixer->ctl) {
pipe->dst.x += mixer->ctl->border_x_off;
@@ -1007,7 +1058,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd,
pr_debug("border{%d,%d}\n", mixer->ctl->border_x_off,
mixer->ctl->border_y_off);
}
- pr_debug("src{%d,%d,%d,%d}, dst{%d,%d,%d,%d}\n",
+ pr_debug("pipe:%d src{%d,%d,%d,%d}, dst{%d,%d,%d,%d}\n", pipe->num,
pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
@@ -2625,6 +2676,7 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
{
struct mdss_overlay_private *mdp5_data;
struct mdp_destination_scaler_data *ds_data;
+ struct mdss_panel_info *pinfo;
int rc = 0;
if (!mfd || !commit) {
@@ -2658,6 +2710,23 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
}
}
+ pinfo = mfd->panel_info;
+ if (pinfo->partial_update_enabled == PU_DUAL_ROI) {
+ if (commit->flags & MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI) {
+ rc = __validate_dual_partial_update(mdp5_data->ctl,
+ commit);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("Multiple pu pre-validate fail\n");
+ return rc;
+ }
+ }
+ } else {
+ if (commit->flags & MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI) {
+ pr_err("Multiple partial update not supported!\n");
+ return -EINVAL;
+ }
+ }
+
ds_data = commit->dest_scaler;
if (ds_data && commit->dest_scaler_cnt &&
(ds_data->flags & MDP_DESTSCALER_ENABLE)) {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 9bdc66232dd5..8c64dcd0655c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1861,12 +1861,109 @@ int mdss_mode_switch_post(struct msm_fb_data_type *mfd, u32 mode)
return rc;
}
+static void __restore_pipe(struct mdss_mdp_pipe *pipe)
+{
+
+ if (!pipe->restore_roi)
+ return;
+
+ pr_debug("restoring pipe:%d dst from:{%d,%d,%d,%d} to:{%d,%d,%d,%d}\n",
+ pipe->num, pipe->dst.x, pipe->dst.y,
+ pipe->dst.w, pipe->dst.h, pipe->layer.dst_rect.x,
+ pipe->layer.dst_rect.y, pipe->layer.dst_rect.w,
+ pipe->layer.dst_rect.h);
+ pr_debug("restoring pipe:%d src from:{%d,%d,%d,%d} to:{%d,%d,%d,%d}\n",
+ pipe->num, pipe->src.x, pipe->src.y,
+ pipe->src.w, pipe->src.h, pipe->layer.src_rect.x,
+ pipe->layer.src_rect.y, pipe->layer.src_rect.w,
+ pipe->layer.src_rect.h);
+
+ pipe->src.x = pipe->layer.src_rect.x;
+ pipe->src.y = pipe->layer.src_rect.y;
+ pipe->src.w = pipe->layer.src_rect.w;
+ pipe->src.h = pipe->layer.src_rect.h;
+
+ pipe->dst.x = pipe->layer.dst_rect.x;
+ pipe->dst.y = pipe->layer.dst_rect.y;
+ pipe->dst.w = pipe->layer.dst_rect.w;
+ pipe->dst.h = pipe->layer.dst_rect.h;
+}
+
+ /**
+ * __crop_adjust_pipe_rect() - Adjust pipe roi for dual partial
+ * update feature.
+ * @pipe: pipe to check against.
+ * @dual_roi: roi's for the dual partial roi.
+ *
+ * For dual PU ROI case, the layer mixer is configured
+ * by merging the two width aligned ROIs (first_roi and
+ * second_roi) vertically. So, the y-offset of all the
+ * pipes belonging to the second_roi needs to adjusted
+ * accordingly. Also the cropping of the pipe's src/dst
+ * rect has to be done with respect to the ROI the pipe
+ * is intersecting with, before the adjustment.
+ */
+static int __crop_adjust_pipe_rect(struct mdss_mdp_pipe *pipe,
+ struct mdss_dsi_dual_pu_roi *dual_roi)
+{
+ u32 adjust_h;
+ u32 roi_y_pos;
+ int ret = 0;
+
+ pipe->restore_roi = false;
+ if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->first_roi)) {
+ mdss_mdp_crop_rect(&pipe->src, &pipe->dst,
+ &dual_roi->first_roi, false);
+ pipe->restore_roi = true;
+
+ } else if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->second_roi)) {
+ mdss_mdp_crop_rect(&pipe->src, &pipe->dst,
+ &dual_roi->second_roi, false);
+ adjust_h = dual_roi->second_roi.y;
+ roi_y_pos = dual_roi->first_roi.y + dual_roi->first_roi.h;
+
+ if (adjust_h > roi_y_pos) {
+ adjust_h = adjust_h - roi_y_pos;
+ pipe->dst.y -= adjust_h;
+ } else {
+ pr_err("wrong y-pos adjust_y:%d roi_y_pos:%d\n",
+ adjust_h, roi_y_pos);
+ ret = -EINVAL;
+ }
+ pipe->restore_roi = true;
+
+ } else {
+ ret = -EINVAL;
+ }
+
+ pr_debug("crop/adjusted p:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d} r:%d\n",
+ pipe->num, pipe->src.x, pipe->src.y,
+ pipe->src.w, pipe->src.h, pipe->dst.x,
+ pipe->dst.y, pipe->dst.w, pipe->dst.h,
+ pipe->restore_roi);
+
+ if (ret) {
+ pr_err("dual roi error p%d dst{%d,%d,%d,%d}",
+ pipe->num, pipe->dst.x, pipe->dst.y, pipe->dst.w,
+ pipe->dst.h);
+ pr_err(" roi1{%d,%d,%d,%d} roi2{%d,%d,%d,%d}\n",
+ dual_roi->first_roi.x, dual_roi->first_roi.y,
+ dual_roi->first_roi.w, dual_roi->first_roi.h,
+ dual_roi->second_roi.x, dual_roi->second_roi.y,
+ dual_roi->second_roi.w, dual_roi->second_roi.h);
+ }
+
+ return ret;
+}
+
static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
struct mdp_display_commit *commit)
{
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
+ struct mdss_dsi_dual_pu_roi *dual_roi = &pinfo->dual_roi;
struct mdss_rect l_roi = {0}, r_roi = {0};
struct mdp_rect tmp_roi = {0};
bool skip_partial_update = true;
@@ -1881,6 +1978,39 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
rect_copy_mdp_to_mdss(&commit->l_roi, &l_roi);
rect_copy_mdp_to_mdss(&commit->r_roi, &r_roi);
+ /*
+ * In case of dual partial update ROI, update the two ROIs to dual_roi
+ * struct and combine both the ROIs and assign it as a merged ROI in
+ * l_roi, as MDP would need only the merged ROI information for all
+ * LM settings.
+ */
+ if (pinfo->partial_update_enabled == PU_DUAL_ROI) {
+ if (commit->flags & MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI) {
+
+ if (!is_valid_pu_dual_roi(pinfo, &l_roi, &r_roi)) {
+ pr_err("Invalid dual roi - fall back to full screen update\n");
+ goto set_roi;
+ }
+
+ dual_roi->first_roi = (struct mdss_rect)
+ {l_roi.x, l_roi.y, l_roi.w, l_roi.h};
+ dual_roi->second_roi = (struct mdss_rect)
+ {r_roi.x, r_roi.y, r_roi.w, r_roi.h};
+ dual_roi->enabled = true;
+
+ l_roi.h += r_roi.h;
+ memset(&r_roi, 0, sizeof(struct mdss_rect));
+
+ pr_debug("Dual ROI - first_roi:{%d,%d,%d,%d}, second_roi:{%d,%d,%d,%d}\n",
+ dual_roi->first_roi.x, dual_roi->first_roi.y,
+ dual_roi->first_roi.w, dual_roi->first_roi.h,
+ dual_roi->second_roi.x, dual_roi->second_roi.y,
+ dual_roi->second_roi.w, dual_roi->second_roi.h);
+ } else {
+ dual_roi->enabled = false;
+ }
+ }
+
pr_debug("input: l_roi:-> %d %d %d %d r_roi:-> %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);
@@ -1926,12 +2056,24 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
}
list_for_each_entry(pipe, &mdp5_data->pipes_used, list) {
+ pr_debug("pipe:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d}\n",
+ pipe->num, pipe->src.x, pipe->src.y,
+ pipe->src.w, pipe->src.h, pipe->dst.x,
+ pipe->dst.y, pipe->dst.w, pipe->dst.h);
+
+ if (dual_roi->enabled) {
+ if (__crop_adjust_pipe_rect(pipe, dual_roi)) {
+ skip_partial_update = true;
+ break;
+ }
+ }
+
if (!__is_roi_valid(pipe, &l_roi, &r_roi)) {
skip_partial_update = true;
- pr_err("error. invalid pu config for pipe%d: %d,%d,%d,%d\n",
- pipe->num,
- pipe->dst.x, pipe->dst.y,
- pipe->dst.w, pipe->dst.h);
+ pr_err("error. invalid pu config for pipe%d: %d,%d,%d,%d, dual_pu_roi:%d\n",
+ pipe->num, pipe->dst.x, pipe->dst.y,
+ pipe->dst.w, pipe->dst.h,
+ dual_roi->enabled);
break;
}
}
@@ -1946,13 +2088,24 @@ set_roi:
ctl->mixer_right->width,
ctl->mixer_right->height};
}
+
+ if (pinfo->partial_update_enabled == PU_DUAL_ROI) {
+ if (dual_roi->enabled) {
+ /* we failed pu validation, restore pipes */
+ list_for_each_entry(pipe,
+ &mdp5_data->pipes_used, list)
+ __restore_pipe(pipe);
+ }
+ dual_roi->enabled = false;
+ }
}
- pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d\n",
+ pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d, dual_pu_roi:%d\n",
(l_roi.w && l_roi.h && r_roi.w && r_roi.h) ? "left+right" :
((l_roi.w && l_roi.h) ? "left-only" : "right-only"),
l_roi.x, l_roi.y, l_roi.w, l_roi.h,
- r_roi.x, r_roi.y, r_roi.w, r_roi.h);
+ r_roi.x, r_roi.y, r_roi.w, r_roi.h,
+ dual_roi->enabled);
mdss_mdp_set_roi(ctl, &l_roi, &r_roi);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index 1b04e783ac18..7591ebc3e2ee 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -1998,7 +1998,7 @@ static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe,
dst.x -= left_lm_w_from_mfd(pipe->mfd);
}
- mdss_mdp_crop_rect(&src, &dst, &roi);
+ mdss_mdp_crop_rect(&src, &dst, &roi, true);
if (mdata->has_src_split && is_right_mixer) {
/*
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index 8b0ebc3fdf05..bc1ecf1dbc29 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -241,7 +241,7 @@ void mdss_mdp_intersect_rect(struct mdss_rect *res_rect,
void mdss_mdp_crop_rect(struct mdss_rect *src_rect,
struct mdss_rect *dst_rect,
- const struct mdss_rect *sci_rect)
+ const struct mdss_rect *sci_rect, bool normalize)
{
struct mdss_rect res;
mdss_mdp_intersect_rect(&res, dst_rect, sci_rect);
@@ -253,9 +253,17 @@ void mdss_mdp_crop_rect(struct mdss_rect *src_rect,
src_rect->w = res.w;
src_rect->h = res.h;
}
- *dst_rect = (struct mdss_rect)
- {(res.x - sci_rect->x), (res.y - sci_rect->y),
- res.w, res.h};
+
+ /* adjust dest rect based on the sci_rect starting */
+ if (normalize) {
+ *dst_rect = (struct mdss_rect) {(res.x - sci_rect->x),
+ (res.y - sci_rect->y), res.w, res.h};
+
+ /* return the actual cropped intersecting rect */
+ } else {
+ *dst_rect = (struct mdss_rect) {res.x, res.y,
+ res.w, res.h};
+ }
}
}
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 18a93f9d3c3e..0483e3d42873 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -137,6 +137,25 @@ enum {
SIM_HW_TE_MODE,
};
+
+/*
+ * enum partial_update_mode - Different modes for partial update feature
+ *
+ * @PU_NOT_SUPPORTED: Feature is not supported on target.
+ * @PU_SINGLE_ROI: Default mode, only one ROI is triggered to the
+ * panel(one on each DSI in case of split dsi)
+ * @PU_DUAL_ROI: Support for sending two roi's that are clubbed
+ * together as one big single ROI. This is only
+ * supported on certain panels that have this
+ * capability in their DDIC.
+ *
+ */
+enum {
+ PU_NOT_SUPPORTED = 0,
+ PU_SINGLE_ROI,
+ PU_DUAL_ROI,
+};
+
struct mdss_rect {
u16 x;
u16 y;
@@ -664,6 +683,50 @@ struct mdss_panel_roi_alignment {
u32 min_height;
};
+
+/*
+ * Nomeclature used to represent partial ROI in case of
+ * dual roi when the panel supports it. Region marked (XXX) is
+ * the extended roi to align with the second roi since LM output
+ * has to be rectangle.
+ *
+ * For single ROI, only the first ROI will be used in the struct.
+ * DSI driver will merge it based on the partial_update_roi_merge
+ * property.
+ *
+ * -------------------------------
+ * | DSI0 | DSI1 |
+ * -------------------------------
+ * | | |
+ * | | |
+ * | =========|=======----+ |
+ * | | | |XXXX| |
+ * | | First| Roi |XXXX| |
+ * | | | |XXXX| |
+ * | =========|=======----+ |
+ * | | |
+ * | | |
+ * | | |
+ * | +----================= |
+ * | |XXXX| | | |
+ * | |XXXX| Second Roi | |
+ * | |XXXX| | | |
+ * | +----====|============ |
+ * | | |
+ * | | |
+ * | | |
+ * | | |
+ * | | |
+ * ------------------------------
+ *
+ */
+
+struct mdss_dsi_dual_pu_roi {
+ struct mdss_rect first_roi;
+ struct mdss_rect second_roi;
+ bool enabled;
+};
+
struct mdss_panel_info {
u32 xres;
u32 yres;
@@ -689,6 +752,7 @@ struct mdss_panel_info {
u32 vic; /* video identification code */
u32 deep_color;
struct mdss_rect roi;
+ struct mdss_dsi_dual_pu_roi dual_roi;
int pwm_pmic_gpio;
int pwm_lpg_chan;
int pwm_period;
@@ -723,8 +787,8 @@ struct mdss_panel_info {
u32 cont_splash_enabled;
bool esd_rdy;
- bool partial_update_supported; /* value from dts if pu is supported */
- bool partial_update_enabled; /* is pu currently allowed */
+ u32 partial_update_supported; /* value from dts if pu is supported */
+ u32 partial_update_enabled; /* is pu currently allowed */
u32 dcs_cmd_by_left;
u32 partial_update_roi_merge;
struct ion_handle *splash_ihdl;
@@ -1000,6 +1064,27 @@ static inline bool is_lm_configs_dsc_compatible(struct mdss_panel_info *pinfo,
return true;
}
+static inline bool is_valid_pu_dual_roi(struct mdss_panel_info *pinfo,
+ struct mdss_rect *first_roi, struct mdss_rect *second_roi)
+{
+ if ((first_roi->x != second_roi->x) || (first_roi->w != second_roi->w)
+ || (first_roi->y > second_roi->y)
+ || ((first_roi->y + first_roi->h) > second_roi->y)
+ || (is_dsc_compression(pinfo) &&
+ !is_lm_configs_dsc_compatible(pinfo,
+ first_roi->w, first_roi->h) &&
+ !is_lm_configs_dsc_compatible(pinfo,
+ second_roi->w, second_roi->h))) {
+ pr_err("Invalid multiple PU ROIs, roi0:{%d,%d,%d,%d}, roi1{%d,%d,%d,%d}\n",
+ first_roi->x, first_roi->y, first_roi->w,
+ first_roi->h, second_roi->x, second_roi->y,
+ second_roi->w, second_roi->h);
+ return false;
+ }
+
+ return true;
+}
+
int mdss_register_panel(struct platform_device *pdev,
struct mdss_panel_data *pdata);