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 <[email protected]> --- 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
