Loading Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +7 −2 Original line number Diff line number Diff line Loading @@ -333,8 +333,13 @@ Optional properties: as below: --> Reset GPIO value --> Sleep value (in ms) - qcom,partial-update-enabled: Boolean used to enable partial - qcom,partial-update-enabled: String used to enable partial panel update for command mode panels. "none": partial update is disabled "single_roi": default enable mode, only single roi is sent to panel "dual_roi": two rois are merged into one big roi. Panel ddic should be able to process two roi's along with the DCS command to send two rois. disabled if property is not specified. - qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating additional idle time in dsi clock cycles that is needed to compensate for smaller line width. Loading Loading @@ -630,7 +635,7 @@ Example: qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; qcom,mdss-tear-check-frame-rate = <6000>; qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; qcom,partial-update-enabled; qcom,partial-update-enabled = "single_roi"; qcom,dcs-cmd-by-left; qcom,mdss-dsi-lp11-init; qcom,mdss-dsi-init-delay-us = <100>; Loading drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +36 −13 Original line number Diff line number Diff line Loading @@ -1556,19 +1556,9 @@ int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl, return rc; } /** * dsi_ctrl_setup() - Setup DSI host hardware while coming out of idle screen. * @dsi_ctrl: DSI controller handle. * * Initializes DSI controller hardware with host configuration provided by * dsi_ctrl_update_host_config(). Initialization can be performed only during * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been * performed. * * Return: error code. */ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) { struct dsi_mode_info video_timing; int rc = 0; if (!dsi_ctrl) { Loading @@ -1578,6 +1568,12 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) mutex_lock(&dsi_ctrl->ctrl_lock); /* replace video mode width with actual roi width */ memcpy(&video_timing, &dsi_ctrl->host_config.video_timing, sizeof(video_timing)); video_timing.h_active = dsi_ctrl->roi.w; video_timing.v_active = dsi_ctrl->roi.h; dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw, &dsi_ctrl->host_config.lane_map); Loading @@ -1590,8 +1586,8 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) &dsi_ctrl->host_config.u.cmd_engine); dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, dsi_ctrl->host_config.video_timing.h_active * 3, &video_timing, video_timing.h_active * 3, 0x0); dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true); } else { Loading @@ -1611,6 +1607,26 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) return rc; } int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, bool *changed) { int rc = 0; if (!dsi_ctrl || !roi || !changed) { pr_err("Invalid params\n"); return -EINVAL; } mutex_lock(&dsi_ctrl->ctrl_lock); if (!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) { *changed = true; memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi)); } else *changed = false; mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } /** * dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal * to DSI PHY hardware. Loading Loading @@ -1789,6 +1805,13 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, pr_debug("[DSI_%d]Host config updated\n", ctrl->cell_index); memcpy(&ctrl->host_config, config, sizeof(ctrl->host_config)); ctrl->mode_bounds.x = ctrl->host_config.video_timing.h_active * ctrl->horiz_index; ctrl->mode_bounds.y = 0; ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active; ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active; memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds)); ctrl->roi.x = 0; error: mutex_unlock(&ctrl->ctrl_lock); return rc; Loading drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +23 −1 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ struct dsi_ctrl_interrupts { * struct dsi_ctrl - DSI controller object * @pdev: Pointer to platform device. * @cell_index: Instance cell id. * @horiz_index: Index in physical horizontal CTRL layout, 0 = leftmost * @name: Name of the controller instance. * @refcount: ref counter. * @ctrl_lock: Mutex for hardware and object access. Loading @@ -182,6 +183,10 @@ struct dsi_ctrl_interrupts { * @pwr_info: Power information. * @axi_bus_info: AXI bus information. * @host_config: Current host configuration. * @mode_bounds: Boundaries of the default mode ROI. * Origin is at top left of all CTRLs. * @roi: Partial update region of interest. * Origin is top left of this CTRL. * @tx_cmd_buf: Tx command buffer. * @cmd_buffer_size: Size of command buffer. * @debugfs_root: Root for debugfs entries. Loading @@ -189,6 +194,7 @@ struct dsi_ctrl_interrupts { struct dsi_ctrl { struct platform_device *pdev; u32 cell_index; u32 horiz_index; const char *name; u32 refcount; struct mutex ctrl_lock; Loading @@ -209,6 +215,9 @@ struct dsi_ctrl { struct dsi_ctrl_bus_scale_info axi_bus_info; struct dsi_host_config host_config; struct dsi_rect mode_bounds; struct dsi_rect roi; /* Command tx and rx */ struct drm_gem_object *tx_cmd_buf; u32 cmd_buffer_size; Loading Loading @@ -387,10 +396,24 @@ int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable); * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been * performed. * * Also used to program the video mode timing values. * * Return: error code. */ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); /** * dsi_ctrl_set_roi() - Set DSI controller's region of interest * @dsi_ctrl: DSI controller handle. * @roi: Region of interest rectangle, must be less than mode bounds * @changed: Output parameter, set to true of the controller's ROI was * dirtied by setting the new ROI, and DCS cmd update needed * * Return: error code. */ int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, bool *changed); /** * dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller * @dsi_ctrl: DSI controller handle. Loading @@ -401,7 +424,6 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); * * Return: error code. */ int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on); /** Loading drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +36 −0 Original line number Diff line number Diff line Loading @@ -411,4 +411,40 @@ struct dsi_display_mode { struct msm_mode_info *mode_info; }; /** * struct dsi_rect - dsi rectangle representation * Note: sde_rect is also using u16, this must be maintained for memcpy */ struct dsi_rect { u16 x; u16 y; u16 w; u16 h; }; /** * dsi_rect_intersect - intersect two rectangles * @r1: first rectangle * @r2: scissor rectangle * @result: result rectangle, all 0's on no intersection found */ void dsi_rect_intersect(const struct dsi_rect *r1, const struct dsi_rect *r2, struct dsi_rect *result); /** * dsi_rect_is_equal - compares two rects * @r1: rect value to compare * @r2: rect value to compare * * Returns true if the rects are same */ static inline bool dsi_rect_is_equal(struct dsi_rect *r1, struct dsi_rect *r2) { return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && r1->h == r2->h; } #endif /* _DSI_DEFS_H_ */ drivers/gpu/drm/msm/dsi-staging/dsi_display.c +130 −1 Original line number Diff line number Diff line Loading @@ -38,6 +38,30 @@ static const struct of_device_id dsi_display_dt_match[] = { static struct dsi_display *main_display; void dsi_rect_intersect(const struct dsi_rect *r1, const struct dsi_rect *r2, struct dsi_rect *result) { int l, t, r, b; if (!r1 || !r2 || !result) return; l = max(r1->x, r2->x); t = max(r1->y, r2->y); r = min((r1->x + r1->w), (r2->x + r2->w)); b = min((r1->y + r1->h), (r2->y + r2->h)); if (r <= l || b <= t) { memset(result, 0, sizeof(*result)); } else { result->x = l; result->y = t; result->w = r - l; result->h = b - t; } } int dsi_display_set_backlight(void *display, u32 bl_lvl) { struct dsi_display *dsi_display = display; Loading Loading @@ -2285,6 +2309,7 @@ static int dsi_display_bind(struct device *dev, display->name, i, rc); goto error_ctrl_deinit; } display_ctrl->ctrl->horiz_index = i; rc = dsi_phy_drv_init(display_ctrl->phy); if (rc) { Loading Loading @@ -2750,6 +2775,10 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp) display->panel->mode.panel_mode); break; } memcpy(&info->roi_caps, &display->panel->roi_caps, sizeof(info->roi_caps)); error: mutex_unlock(&display->display_lock); return rc; Loading Loading @@ -3036,10 +3065,110 @@ int dsi_display_prepare(struct dsi_display *display) return rc; } static int dsi_display_calc_ctrl_roi(const struct dsi_display *display, const struct dsi_display_ctrl *ctrl, const struct msm_roi_list *req_rois, struct dsi_rect *out_roi) { const struct dsi_rect *bounds = &ctrl->ctrl->mode_bounds; struct dsi_rect req_roi = { 0 }; int rc = 0; if (req_rois->num_rects > display->panel->roi_caps.num_roi) { pr_err("request for %d rois greater than max %d\n", req_rois->num_rects, display->panel->roi_caps.num_roi); rc = -EINVAL; goto exit; } /** * if no rois, user wants to reset back to full resolution * note: h_active is already divided by ctrl_count */ if (!req_rois->num_rects) { *out_roi = *bounds; goto exit; } /* intersect with the bounds */ req_roi.x = req_rois->roi[0].x1; req_roi.y = req_rois->roi[0].y1; req_roi.w = req_rois->roi[0].x2 - req_rois->roi[0].x1; req_roi.h = req_rois->roi[0].y2 - req_rois->roi[0].y1; dsi_rect_intersect(&req_roi, bounds, out_roi); exit: /* adjust the ctrl origin to be top left within the ctrl */ out_roi->x = out_roi->x - bounds->x; pr_debug("ctrl%d:%d: req (%d,%d,%d,%d) bnd (%d,%d,%d,%d) out (%d,%d,%d,%d)\n", ctrl->dsi_ctrl_idx, ctrl->ctrl->cell_index, req_roi.x, req_roi.y, req_roi.w, req_roi.h, bounds->x, bounds->y, bounds->w, bounds->h, out_roi->x, out_roi->y, out_roi->w, out_roi->h); return rc; } static int dsi_display_set_roi(struct dsi_display *display, struct msm_roi_list *rois) { int rc = 0; int i; if (!display || !rois || !display->panel) return -EINVAL; if (!display->panel->roi_caps.enabled) return 0; for (i = 0; i < display->ctrl_count; i++) { struct dsi_display_ctrl *ctrl = &display->ctrl[i]; struct dsi_rect ctrl_roi; bool changed = false; rc = dsi_display_calc_ctrl_roi(display, ctrl, rois, &ctrl_roi); if (rc) { pr_err("dsi_display_calc_ctrl_roi failed rc %d\n", rc); return rc; } rc = dsi_ctrl_set_roi(ctrl->ctrl, &ctrl_roi, &changed); if (rc) { pr_err("dsi_ctrl_set_roi failed rc %d\n", rc); return rc; } if (!changed) continue; /* send the new roi to the panel via dcs commands */ rc = dsi_panel_send_roi_dcs(display->panel, i, &ctrl_roi); if (rc) { pr_err("dsi_panel_set_roi failed rc %d\n", rc); return rc; } /* re-program the ctrl with the timing based on the new roi */ rc = dsi_ctrl_setup(ctrl->ctrl); if (rc) { pr_err("dsi_ctrl_setup failed rc %d\n", rc); return rc; } } return rc; } int dsi_display_pre_kickoff(struct dsi_display *display, struct msm_display_kickoff_params *params) { return 0; int rc = 0; rc = dsi_display_set_roi(display, params->rois); return rc; } int dsi_display_enable(struct dsi_display *display) Loading Loading
Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +7 −2 Original line number Diff line number Diff line Loading @@ -333,8 +333,13 @@ Optional properties: as below: --> Reset GPIO value --> Sleep value (in ms) - qcom,partial-update-enabled: Boolean used to enable partial - qcom,partial-update-enabled: String used to enable partial panel update for command mode panels. "none": partial update is disabled "single_roi": default enable mode, only single roi is sent to panel "dual_roi": two rois are merged into one big roi. Panel ddic should be able to process two roi's along with the DCS command to send two rois. disabled if property is not specified. - qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating additional idle time in dsi clock cycles that is needed to compensate for smaller line width. Loading Loading @@ -630,7 +635,7 @@ Example: qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; qcom,mdss-tear-check-frame-rate = <6000>; qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; qcom,partial-update-enabled; qcom,partial-update-enabled = "single_roi"; qcom,dcs-cmd-by-left; qcom,mdss-dsi-lp11-init; qcom,mdss-dsi-init-delay-us = <100>; Loading
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +36 −13 Original line number Diff line number Diff line Loading @@ -1556,19 +1556,9 @@ int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl, return rc; } /** * dsi_ctrl_setup() - Setup DSI host hardware while coming out of idle screen. * @dsi_ctrl: DSI controller handle. * * Initializes DSI controller hardware with host configuration provided by * dsi_ctrl_update_host_config(). Initialization can be performed only during * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been * performed. * * Return: error code. */ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) { struct dsi_mode_info video_timing; int rc = 0; if (!dsi_ctrl) { Loading @@ -1578,6 +1568,12 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) mutex_lock(&dsi_ctrl->ctrl_lock); /* replace video mode width with actual roi width */ memcpy(&video_timing, &dsi_ctrl->host_config.video_timing, sizeof(video_timing)); video_timing.h_active = dsi_ctrl->roi.w; video_timing.v_active = dsi_ctrl->roi.h; dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw, &dsi_ctrl->host_config.lane_map); Loading @@ -1590,8 +1586,8 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) &dsi_ctrl->host_config.u.cmd_engine); dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, dsi_ctrl->host_config.video_timing.h_active * 3, &video_timing, video_timing.h_active * 3, 0x0); dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true); } else { Loading @@ -1611,6 +1607,26 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) return rc; } int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, bool *changed) { int rc = 0; if (!dsi_ctrl || !roi || !changed) { pr_err("Invalid params\n"); return -EINVAL; } mutex_lock(&dsi_ctrl->ctrl_lock); if (!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) { *changed = true; memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi)); } else *changed = false; mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } /** * dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal * to DSI PHY hardware. Loading Loading @@ -1789,6 +1805,13 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, pr_debug("[DSI_%d]Host config updated\n", ctrl->cell_index); memcpy(&ctrl->host_config, config, sizeof(ctrl->host_config)); ctrl->mode_bounds.x = ctrl->host_config.video_timing.h_active * ctrl->horiz_index; ctrl->mode_bounds.y = 0; ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active; ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active; memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds)); ctrl->roi.x = 0; error: mutex_unlock(&ctrl->ctrl_lock); return rc; Loading
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +23 −1 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ struct dsi_ctrl_interrupts { * struct dsi_ctrl - DSI controller object * @pdev: Pointer to platform device. * @cell_index: Instance cell id. * @horiz_index: Index in physical horizontal CTRL layout, 0 = leftmost * @name: Name of the controller instance. * @refcount: ref counter. * @ctrl_lock: Mutex for hardware and object access. Loading @@ -182,6 +183,10 @@ struct dsi_ctrl_interrupts { * @pwr_info: Power information. * @axi_bus_info: AXI bus information. * @host_config: Current host configuration. * @mode_bounds: Boundaries of the default mode ROI. * Origin is at top left of all CTRLs. * @roi: Partial update region of interest. * Origin is top left of this CTRL. * @tx_cmd_buf: Tx command buffer. * @cmd_buffer_size: Size of command buffer. * @debugfs_root: Root for debugfs entries. Loading @@ -189,6 +194,7 @@ struct dsi_ctrl_interrupts { struct dsi_ctrl { struct platform_device *pdev; u32 cell_index; u32 horiz_index; const char *name; u32 refcount; struct mutex ctrl_lock; Loading @@ -209,6 +215,9 @@ struct dsi_ctrl { struct dsi_ctrl_bus_scale_info axi_bus_info; struct dsi_host_config host_config; struct dsi_rect mode_bounds; struct dsi_rect roi; /* Command tx and rx */ struct drm_gem_object *tx_cmd_buf; u32 cmd_buffer_size; Loading Loading @@ -387,10 +396,24 @@ int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable); * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been * performed. * * Also used to program the video mode timing values. * * Return: error code. */ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); /** * dsi_ctrl_set_roi() - Set DSI controller's region of interest * @dsi_ctrl: DSI controller handle. * @roi: Region of interest rectangle, must be less than mode bounds * @changed: Output parameter, set to true of the controller's ROI was * dirtied by setting the new ROI, and DCS cmd update needed * * Return: error code. */ int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, bool *changed); /** * dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller * @dsi_ctrl: DSI controller handle. Loading @@ -401,7 +424,6 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); * * Return: error code. */ int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on); /** Loading
drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +36 −0 Original line number Diff line number Diff line Loading @@ -411,4 +411,40 @@ struct dsi_display_mode { struct msm_mode_info *mode_info; }; /** * struct dsi_rect - dsi rectangle representation * Note: sde_rect is also using u16, this must be maintained for memcpy */ struct dsi_rect { u16 x; u16 y; u16 w; u16 h; }; /** * dsi_rect_intersect - intersect two rectangles * @r1: first rectangle * @r2: scissor rectangle * @result: result rectangle, all 0's on no intersection found */ void dsi_rect_intersect(const struct dsi_rect *r1, const struct dsi_rect *r2, struct dsi_rect *result); /** * dsi_rect_is_equal - compares two rects * @r1: rect value to compare * @r2: rect value to compare * * Returns true if the rects are same */ static inline bool dsi_rect_is_equal(struct dsi_rect *r1, struct dsi_rect *r2) { return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && r1->h == r2->h; } #endif /* _DSI_DEFS_H_ */
drivers/gpu/drm/msm/dsi-staging/dsi_display.c +130 −1 Original line number Diff line number Diff line Loading @@ -38,6 +38,30 @@ static const struct of_device_id dsi_display_dt_match[] = { static struct dsi_display *main_display; void dsi_rect_intersect(const struct dsi_rect *r1, const struct dsi_rect *r2, struct dsi_rect *result) { int l, t, r, b; if (!r1 || !r2 || !result) return; l = max(r1->x, r2->x); t = max(r1->y, r2->y); r = min((r1->x + r1->w), (r2->x + r2->w)); b = min((r1->y + r1->h), (r2->y + r2->h)); if (r <= l || b <= t) { memset(result, 0, sizeof(*result)); } else { result->x = l; result->y = t; result->w = r - l; result->h = b - t; } } int dsi_display_set_backlight(void *display, u32 bl_lvl) { struct dsi_display *dsi_display = display; Loading Loading @@ -2285,6 +2309,7 @@ static int dsi_display_bind(struct device *dev, display->name, i, rc); goto error_ctrl_deinit; } display_ctrl->ctrl->horiz_index = i; rc = dsi_phy_drv_init(display_ctrl->phy); if (rc) { Loading Loading @@ -2750,6 +2775,10 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp) display->panel->mode.panel_mode); break; } memcpy(&info->roi_caps, &display->panel->roi_caps, sizeof(info->roi_caps)); error: mutex_unlock(&display->display_lock); return rc; Loading Loading @@ -3036,10 +3065,110 @@ int dsi_display_prepare(struct dsi_display *display) return rc; } static int dsi_display_calc_ctrl_roi(const struct dsi_display *display, const struct dsi_display_ctrl *ctrl, const struct msm_roi_list *req_rois, struct dsi_rect *out_roi) { const struct dsi_rect *bounds = &ctrl->ctrl->mode_bounds; struct dsi_rect req_roi = { 0 }; int rc = 0; if (req_rois->num_rects > display->panel->roi_caps.num_roi) { pr_err("request for %d rois greater than max %d\n", req_rois->num_rects, display->panel->roi_caps.num_roi); rc = -EINVAL; goto exit; } /** * if no rois, user wants to reset back to full resolution * note: h_active is already divided by ctrl_count */ if (!req_rois->num_rects) { *out_roi = *bounds; goto exit; } /* intersect with the bounds */ req_roi.x = req_rois->roi[0].x1; req_roi.y = req_rois->roi[0].y1; req_roi.w = req_rois->roi[0].x2 - req_rois->roi[0].x1; req_roi.h = req_rois->roi[0].y2 - req_rois->roi[0].y1; dsi_rect_intersect(&req_roi, bounds, out_roi); exit: /* adjust the ctrl origin to be top left within the ctrl */ out_roi->x = out_roi->x - bounds->x; pr_debug("ctrl%d:%d: req (%d,%d,%d,%d) bnd (%d,%d,%d,%d) out (%d,%d,%d,%d)\n", ctrl->dsi_ctrl_idx, ctrl->ctrl->cell_index, req_roi.x, req_roi.y, req_roi.w, req_roi.h, bounds->x, bounds->y, bounds->w, bounds->h, out_roi->x, out_roi->y, out_roi->w, out_roi->h); return rc; } static int dsi_display_set_roi(struct dsi_display *display, struct msm_roi_list *rois) { int rc = 0; int i; if (!display || !rois || !display->panel) return -EINVAL; if (!display->panel->roi_caps.enabled) return 0; for (i = 0; i < display->ctrl_count; i++) { struct dsi_display_ctrl *ctrl = &display->ctrl[i]; struct dsi_rect ctrl_roi; bool changed = false; rc = dsi_display_calc_ctrl_roi(display, ctrl, rois, &ctrl_roi); if (rc) { pr_err("dsi_display_calc_ctrl_roi failed rc %d\n", rc); return rc; } rc = dsi_ctrl_set_roi(ctrl->ctrl, &ctrl_roi, &changed); if (rc) { pr_err("dsi_ctrl_set_roi failed rc %d\n", rc); return rc; } if (!changed) continue; /* send the new roi to the panel via dcs commands */ rc = dsi_panel_send_roi_dcs(display->panel, i, &ctrl_roi); if (rc) { pr_err("dsi_panel_set_roi failed rc %d\n", rc); return rc; } /* re-program the ctrl with the timing based on the new roi */ rc = dsi_ctrl_setup(ctrl->ctrl); if (rc) { pr_err("dsi_ctrl_setup failed rc %d\n", rc); return rc; } } return rc; } int dsi_display_pre_kickoff(struct dsi_display *display, struct msm_display_kickoff_params *params) { return 0; int rc = 0; rc = dsi_display_set_roi(display, params->rois); return rc; } int dsi_display_enable(struct dsi_display *display) Loading