aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/gpu/drm/tidss/tidss_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tidss/tidss_crtc.c')
-rw-r--r--drivers/gpu/drm/tidss/tidss_crtc.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index 032c31ee2820..d4ce9bab8c7e 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -17,6 +17,7 @@
#include "tidss_dispc.h"
#include "tidss_drv.h"
#include "tidss_irq.h"
+#include "tidss_plane.h"
/* Page flip and frame done IRQs */
@@ -111,6 +112,54 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
return dispc_vp_bus_check(dispc, hw_videoport, state);
}
+/*
+ * This needs all affected planes to be present in the atomic
+ * state. The untouched planes are added to the state in
+ * tidss_atomic_check().
+ */
+static void tidss_crtc_position_planes(struct tidss_device *tidss,
+ struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state,
+ bool newmodeset)
+{
+ struct drm_atomic_state *ostate = old_state->state;
+ struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+ struct drm_crtc_state *cstate = crtc->state;
+ int layer;
+
+ if (!newmodeset && !cstate->zpos_changed &&
+ !to_tidss_crtc_state(cstate)->plane_pos_changed)
+ return;
+
+ for (layer = 0; layer < tidss->feat->num_planes; layer++) {
+ struct drm_plane_state *pstate;
+ struct drm_plane *plane;
+ bool layer_active = false;
+ int i;
+
+ for_each_new_plane_in_state(ostate, plane, pstate, i) {
+ if (pstate->crtc != crtc || !pstate->visible)
+ continue;
+
+ if (pstate->normalized_zpos == layer) {
+ layer_active = true;
+ break;
+ }
+ }
+
+ if (layer_active) {
+ struct tidss_plane *tplane = to_tidss_plane(plane);
+
+ dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id,
+ tcrtc->hw_videoport,
+ pstate->crtc_x, pstate->crtc_y,
+ layer);
+ }
+ dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer,
+ layer_active);
+ }
+}
+
static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
@@ -146,6 +195,9 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
/* Write vp properties to HW if needed. */
dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
+ /* Update plane positions if needed. */
+ tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
+
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
spin_lock_irqsave(&ddev->event_lock, flags);
@@ -183,6 +235,7 @@ static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
return;
dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
+ tidss_crtc_position_planes(tidss, crtc, old_state, true);
/* Turn vertical blanking interrupt reporting on. */
drm_crtc_vblank_on(crtc);
@@ -318,6 +371,8 @@ static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+ state->plane_pos_changed = false;
+
state->bus_format = current_state->bus_format;
state->bus_flags = current_state->bus_flags;