From 151e7ee8232ce765ed25ce760ed9a65c3ab71fe3 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 6 Jul 2017 11:45:48 -0700
Subject: [PATCH 130/454] drm/vc4: Add support for setting DPMS in firmwarekms.

This ensures that the screen goes blank during DPMS (screensaver),
including the cursor.  Planes don't necessarily get disabled during
CRTC disable, so we need to be careful to not leave them on or turn
them back on early.

Signed-off-by: Eric Anholt <eric@anholt.net>
---
 drivers/gpu/drm/vc4/vc4_firmware_kms.c | 40 ++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 3 deletions(-)

--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -36,6 +36,8 @@ struct vc4_crtc {
 	struct drm_crtc base;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
+	struct drm_plane *primary;
+	struct drm_plane *cursor;
 	void __iomem *regs;
 
 	struct drm_pending_vblank_event *event;
@@ -124,8 +126,6 @@ static void vc4_primary_plane_atomic_upd
 	u32 bpp = 32;
 	int ret;
 
-	vc4_plane_set_primary_blank(plane, false);
-
 	fbinfo->xres = state->crtc_w;
 	fbinfo->yres = state->crtc_h;
 	fbinfo->xres_virtual = state->crtc_w;
@@ -169,6 +169,12 @@ static void vc4_primary_plane_atomic_upd
 				       vc4_plane->fbinfo_bus_addr);
 	WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
 	WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
+
+	/* If the CRTC is on (or going to be on) and we're enabled,
+	 * then unblank.  Otherwise, stay blank until CRTC enable.
+	*/
+	if (state->crtc->state->active)
+		vc4_plane_set_primary_blank(plane, false);
 }
 
 static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
@@ -186,7 +192,12 @@ static void vc4_cursor_plane_atomic_upda
 	struct drm_framebuffer *fb = state->fb;
 	struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
 	int ret;
-	u32 packet_state[] = { true, state->crtc_x, state->crtc_y, 0 };
+	u32 packet_state[] = {
+		state->crtc->state->active,
+		state->crtc_x,
+		state->crtc_y,
+		0
+	};
 	u32 packet_info[] = { state->crtc_w, state->crtc_h,
 			      0, /* unused */
 			      bo->paddr + fb->offsets[0],
@@ -329,10 +340,30 @@ static void vc4_crtc_mode_set_nofb(struc
 
 static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 {
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+	/* Always turn the planes off on CRTC disable. In DRM, planes
+	 * are enabled/disabled through the update/disable hooks
+	 * above, and the CRTC enable/disable independently controls
+	 * whether anything scans out at all, but the firmware doesn't
+	 * give us a CRTC-level control for that.
+	 */
+	vc4_cursor_plane_atomic_disable(vc4_crtc->cursor,
+					vc4_crtc->cursor->state);
+	vc4_plane_set_primary_blank(vc4_crtc->primary, true);
 }
 
 static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 {
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+	/* Unblank the planes (if they're supposed to be displayed). */
+	if (vc4_crtc->primary->state->fb)
+		vc4_plane_set_primary_blank(vc4_crtc->primary, false);
+	if (vc4_crtc->cursor->state->fb) {
+		vc4_cursor_plane_atomic_update(vc4_crtc->cursor,
+					       vc4_crtc->cursor->state);
+	}
 }
 
 static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -626,6 +657,9 @@ static int vc4_fkms_bind(struct device *
 	primary_plane->crtc = crtc;
 	cursor_plane->crtc = crtc;
 
+	vc4_crtc->primary = primary_plane;
+	vc4_crtc->cursor = cursor_plane;
+
 	vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
 	if (!vc4_encoder)
 		return -ENOMEM;
