aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@bootlin.com>2018-12-06 09:24:38 -0500
committerBoris Brezillon <boris.brezillon@bootlin.com>2018-12-19 08:47:58 -0500
commit666e73587f90f42d90385c1bea1009a650bf73f4 (patch)
treecb6b1c0d554880ae33f1d782a36537bca0609a35 /drivers/gpu
parent6c4f52dca36f5e3e2354c30591d38e92f4657ed9 (diff)
drm/vc4: Take margin setup into account when updating planes
Applyin margins is just a matter of scaling all planes appropriately and adjusting the CRTC X/Y offset to account for the left/right/top/bottom borders. Create a vc4_plane_margins_adj() function doing that and call it from vc4_plane_setup_clipping_and_scaling() so that we are ready to attach margins properties to the HDMI connector. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Eric Anholt <eric@anholt.net> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20181206142439.10441-5-boris.brezillon@bootlin.com
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c43
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h3
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c50
3 files changed, 96 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 3ce136ba8791..97caf1671dd0 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -49,6 +49,13 @@ struct vc4_crtc_state {
49 struct drm_mm_node mm; 49 struct drm_mm_node mm;
50 bool feed_txp; 50 bool feed_txp;
51 bool txp_armed; 51 bool txp_armed;
52
53 struct {
54 unsigned int left;
55 unsigned int right;
56 unsigned int top;
57 unsigned int bottom;
58 } margins;
52}; 59};
53 60
54static inline struct vc4_crtc_state * 61static inline struct vc4_crtc_state *
@@ -624,6 +631,37 @@ static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc,
624 return MODE_OK; 631 return MODE_OK;
625} 632}
626 633
634void vc4_crtc_get_margins(struct drm_crtc_state *state,
635 unsigned int *left, unsigned int *right,
636 unsigned int *top, unsigned int *bottom)
637{
638 struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
639 struct drm_connector_state *conn_state;
640 struct drm_connector *conn;
641 int i;
642
643 *left = vc4_state->margins.left;
644 *right = vc4_state->margins.right;
645 *top = vc4_state->margins.top;
646 *bottom = vc4_state->margins.bottom;
647
648 /* We have to interate over all new connector states because
649 * vc4_crtc_get_margins() might be called before
650 * vc4_crtc_atomic_check() which means margins info in vc4_crtc_state
651 * might be outdated.
652 */
653 for_each_new_connector_in_state(state->state, conn, conn_state, i) {
654 if (conn_state->crtc != state->crtc)
655 continue;
656
657 *left = conn_state->tv.margins.left;
658 *right = conn_state->tv.margins.right;
659 *top = conn_state->tv.margins.top;
660 *bottom = conn_state->tv.margins.bottom;
661 break;
662 }
663}
664
627static int vc4_crtc_atomic_check(struct drm_crtc *crtc, 665static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
628 struct drm_crtc_state *state) 666 struct drm_crtc_state *state)
629{ 667{
@@ -671,6 +709,10 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
671 vc4_state->feed_txp = false; 709 vc4_state->feed_txp = false;
672 } 710 }
673 711
712 vc4_state->margins.left = conn_state->tv.margins.left;
713 vc4_state->margins.right = conn_state->tv.margins.right;
714 vc4_state->margins.top = conn_state->tv.margins.top;
715 vc4_state->margins.bottom = conn_state->tv.margins.bottom;
674 break; 716 break;
675 } 717 }
676 718
@@ -972,6 +1014,7 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
972 1014
973 old_vc4_state = to_vc4_crtc_state(crtc->state); 1015 old_vc4_state = to_vc4_crtc_state(crtc->state);
974 vc4_state->feed_txp = old_vc4_state->feed_txp; 1016 vc4_state->feed_txp = old_vc4_state->feed_txp;
1017 vc4_state->margins = old_vc4_state->margins;
975 1018
976 __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); 1019 __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
977 return &vc4_state->base; 1020 return &vc4_state->base;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 4f87b03f837d..c24b078f0593 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -707,6 +707,9 @@ bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
707 const struct drm_display_mode *mode); 707 const struct drm_display_mode *mode);
708void vc4_crtc_handle_vblank(struct vc4_crtc *crtc); 708void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
709void vc4_crtc_txp_armed(struct drm_crtc_state *state); 709void vc4_crtc_txp_armed(struct drm_crtc_state *state);
710void vc4_crtc_get_margins(struct drm_crtc_state *state,
711 unsigned int *right, unsigned int *left,
712 unsigned int *top, unsigned int *bottom);
710 713
711/* vc4_debugfs.c */ 714/* vc4_debugfs.c */
712int vc4_debugfs_init(struct drm_minor *minor); 715int vc4_debugfs_init(struct drm_minor *minor);
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 283abd7d1e9b..2901ed0c5223 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -258,6 +258,52 @@ static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
258 } 258 }
259} 259}
260 260
261static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
262{
263 struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
264 unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;
265 struct drm_crtc_state *crtc_state;
266
267 crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
268 pstate->crtc);
269
270 vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
271 if (!left && !right && !top && !bottom)
272 return 0;
273
274 if (left + right >= crtc_state->mode.hdisplay ||
275 top + bottom >= crtc_state->mode.vdisplay)
276 return -EINVAL;
277
278 adjhdisplay = crtc_state->mode.hdisplay - (left + right);
279 vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
280 adjhdisplay,
281 crtc_state->mode.hdisplay);
282 vc4_pstate->crtc_x += left;
283 if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left)
284 vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left;
285
286 adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
287 vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
288 adjvdisplay,
289 crtc_state->mode.vdisplay);
290 vc4_pstate->crtc_y += top;
291 if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top)
292 vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top;
293
294 vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
295 adjhdisplay,
296 crtc_state->mode.hdisplay);
297 vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
298 adjvdisplay,
299 crtc_state->mode.vdisplay);
300
301 if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
302 return -EINVAL;
303
304 return 0;
305}
306
261static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) 307static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
262{ 308{
263 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 309 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
@@ -306,6 +352,10 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
306 vc4_state->crtc_w = state->dst.x2 - state->dst.x1; 352 vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
307 vc4_state->crtc_h = state->dst.y2 - state->dst.y1; 353 vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
308 354
355 ret = vc4_plane_margins_adj(state);
356 if (ret)
357 return ret;
358
309 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0], 359 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
310 vc4_state->crtc_w); 360 vc4_state->crtc_w);
311 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0], 361 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],