[PATCH v3 2/3] drm/vc4: Take underscan setup into account when updating planes
Boris Brezillon
boris.brezillon at bootlin.com
Thu Nov 22 11:23:30 UTC 2018
Applying an underscan setup is just a matter of scaling all planes
appropriately and adjusting the CRTC X/Y offset to account for the
horizontal and vertical border.
Create an vc4_plane_underscan_adj() function doing that and call it from
vc4_plane_setup_clipping_and_scaling() so that we are ready to attach
underscan properties to the HDMI connector.
Signed-off-by: Boris Brezillon <boris.brezillon at bootlin.com>
---
Changes in v3:
- Rebase on top of the "cursor rescaling" changes
Changes in v2:
- Take changes on hborder/vborder meaning into account
---
drivers/gpu/drm/vc4/vc4_crtc.c | 47 +++++++++++++++++++++++++++++++
drivers/gpu/drm/vc4/vc4_drv.h | 3 ++
drivers/gpu/drm/vc4/vc4_plane.c | 50 +++++++++++++++++++++++++++++++++
3 files changed, 100 insertions(+)
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 3ce136ba8791..3ace68186f07 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -49,6 +49,11 @@ struct vc4_crtc_state {
struct drm_mm_node mm;
bool feed_txp;
bool txp_armed;
+
+ struct {
+ unsigned int vborder;
+ unsigned int hborder;
+ } underscan;
};
static inline struct vc4_crtc_state *
@@ -624,6 +629,39 @@ static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc,
return MODE_OK;
}
+void vc4_crtc_get_underscan_borders(struct drm_crtc_state *state,
+ unsigned int *vborder,
+ unsigned int *hborder)
+{
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+ struct drm_connector_state *conn_state;
+ struct drm_connector *conn;
+ int i;
+
+ *vborder = vc4_state->underscan.vborder;
+ *hborder = vc4_state->underscan.hborder;
+
+ /* We have to interate over all new connector states because
+ * vc4_crtc_get_underscan_borders() might be called before
+ * vc4_crtc_atomic_check() which means underscan info in vc4_crtc_state
+ * might be outdated.
+ */
+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
+ if (conn_state->crtc != state->crtc)
+ continue;
+
+ if (conn_state->underscan.mode == DRM_UNDERSCAN_ON) {
+ *vborder = conn_state->underscan.vborder;
+ *hborder = conn_state->underscan.hborder;
+ } else {
+ *vborder = 0;
+ *hborder = 0;
+ }
+
+ break;
+ }
+}
+
static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -657,6 +695,7 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
return ret;
for_each_new_connector_in_state(state->state, conn, conn_state, i) {
+ unsigned int vborder = 0, hborder = 0;
if (conn_state->crtc != crtc)
continue;
@@ -671,6 +710,13 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
vc4_state->feed_txp = false;
}
+ if (conn_state->underscan.mode == DRM_UNDERSCAN_ON) {
+ vborder = conn_state->underscan.vborder;
+ hborder = conn_state->underscan.hborder;
+ }
+
+ vc4_state->underscan.vborder = vborder;
+ vc4_state->underscan.hborder = hborder;
break;
}
@@ -972,6 +1018,7 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
old_vc4_state = to_vc4_crtc_state(crtc->state);
vc4_state->feed_txp = old_vc4_state->feed_txp;
+ vc4_state->underscan = old_vc4_state->underscan;
__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
return &vc4_state->base;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index d1000c4805c2..ce08c5dc199d 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,
const struct drm_display_mode *mode);
void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
void vc4_crtc_txp_armed(struct drm_crtc_state *state);
+void vc4_crtc_get_underscan_borders(struct drm_crtc_state *state,
+ unsigned int *vborder,
+ unsigned int *hborder);
/* vc4_debugfs.c */
int 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 8cda0d460a6d..78705d9ae25d 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)
}
}
+static int vc4_plane_underscan_adj(struct drm_plane_state *pstate)
+{
+ struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
+ unsigned int vborder, hborder, adjhdisplay, adjvdisplay;
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
+ pstate->crtc);
+
+ vc4_crtc_get_underscan_borders(crtc_state, &vborder, &hborder);
+ if (!vborder && !hborder)
+ return 0;
+
+ if (hborder * 2 >= crtc_state->mode.hdisplay ||
+ vborder * 2 >= crtc_state->mode.vdisplay)
+ return -EINVAL;
+
+ adjhdisplay = crtc_state->mode.hdisplay - (2 * hborder);
+ vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
+ adjhdisplay,
+ crtc_state->mode.hdisplay);
+ vc4_pstate->crtc_x += hborder;
+ if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - hborder)
+ vc4_pstate->crtc_x = crtc_state->mode.hdisplay - hborder;
+
+ adjvdisplay = crtc_state->mode.vdisplay - (2 * vborder);
+ vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
+ adjvdisplay,
+ crtc_state->mode.vdisplay);
+ vc4_pstate->crtc_y += vborder;
+ if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - vborder)
+ vc4_pstate->crtc_y = crtc_state->mode.vdisplay - vborder;
+
+ vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
+ adjhdisplay,
+ crtc_state->mode.hdisplay);
+ vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
+ adjvdisplay,
+ crtc_state->mode.vdisplay);
+
+ if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
+ return -EINVAL;
+
+ return 0;
+}
+
static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
{
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)
vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
+ ret = vc4_plane_underscan_adj(state);
+ if (ret)
+ return ret;
+
vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
vc4_state->crtc_w);
vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
--
2.17.1
More information about the dri-devel
mailing list