[PATCH 3/3] drm/tiny: ssd16xx: reject rotation changes without a matching mode
From: LiangCheng Wang
Date: Thu Jul 30 2026 - 23:52:46 EST
Portrait orientations are implemented by packing the framebuffer
column-major into the same physical RAM layout, so they need the
transposed mode that ssd16xx_connector_get_modes() reports, and a
framebuffer to match.
Setting the rotation property to 90 or 270 on its own provides neither:
the client keeps the mode and framebuffer it had while the driver switches
to portrait packing, and the result is displayed as garbage. Nothing
reports an error, and data_size is identical either way so no size check
catches it.
Reject the combination in the CRTC atomic check, so userspace gets -EINVAL
and can re-probe and do a full modeset instead. Rotation set through the
DT "rotation" property is unaffected, since probe() swaps the mode
dimensions before the connector is registered.
Tested on a Mayqueen PIXPAPER 4.26m (SSD1677, 800x480): rotation 90 at
runtime now fails with -EINVAL instead of corrupting the display, 180 still
applies, and DT rotation = <90> still comes up as 480x800.
Signed-off-by: LiangCheng Wang <zaq14760@xxxxxxxxx>
---
drivers/gpu/drm/tiny/ssd16xx.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/gpu/drm/tiny/ssd16xx.c b/drivers/gpu/drm/tiny/ssd16xx.c
index d311720bbfbe0dd288dbd588be02c79b5eab3eab..1224a3d4ce2cbe70406dfa6e550fc85a2ea62682 100644
--- a/drivers/gpu/drm/tiny/ssd16xx.c
+++ b/drivers/gpu/drm/tiny/ssd16xx.c
@@ -1730,6 +1730,40 @@ static enum drm_mode_status ssd16xx_crtc_mode_valid(struct drm_crtc *crtc,
static int ssd16xx_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_commit *state)
{
+ struct ssd16xx_device *device = crtc_to_ssd16xx_device(crtc);
+ struct drm_crtc_state *new_crtc_state =
+ drm_atomic_get_new_crtc_state(state, crtc);
+ struct drm_connector_state *new_conn_state;
+ unsigned int orientation;
+ bool want_portrait, mode_is_portrait;
+
+ if (!new_crtc_state->enable)
+ return 0;
+
+ new_conn_state = drm_atomic_get_new_connector_state(state,
+ &device->connector);
+ if (!new_conn_state)
+ return 0;
+
+ /*
+ * Portrait packing needs the transposed mode that
+ * ssd16xx_connector_get_modes() reports; without it the client keeps a
+ * framebuffer that would be packed with the wrong geometry.
+ */
+ orientation = to_ssd16xx_connector_state(new_conn_state)->orientation;
+ want_portrait = (orientation == 90 || orientation == 270);
+ mode_is_portrait = new_crtc_state->mode.hdisplay <
+ new_crtc_state->mode.vdisplay;
+
+ if (want_portrait != mode_is_portrait) {
+ drm_dbg(&device->drm,
+ "atomic_check: %u° orientation needs a %s mode, but %ux%u is set\n",
+ orientation, want_portrait ? "portrait" : "landscape",
+ new_crtc_state->mode.hdisplay,
+ new_crtc_state->mode.vdisplay);
+ return -EINVAL;
+ }
+
return 0;
}
--
2.34.1