From: Rob Clark <r...@ti.com>

For drivers that can support rotated scanout, the extra parameter
checking in drm-core, while nice, tends to get confused.  To solve
this drivers can set the crtc or plane invert_dimensions field so
that the dimension checking takes into account the rotation that
the driver is performing.
---
Note: RFC still mainly because I've only tested the CRTC rotation so
far.. still need to write some test code for plane rotation.

 drivers/gpu/drm/drm_crtc.c |   50 +++++++++++++++++++++++++++++--------------
 include/drm/drm_crtc.h     |    9 ++++++++
 2 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0dff444..261c9bd 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -375,6 +375,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc 
*crtc,

        crtc->dev = dev;
        crtc->funcs = funcs;
+       crtc->invert_dimensions = false;

        mutex_lock(&dev->mode_config.mutex);

@@ -609,6 +610,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane 
*plane,
        plane->base.properties = &plane->properties;
        plane->dev = dev;
        plane->funcs = funcs;
+       plane->invert_dimensions = false;
        plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
                                      GFP_KERNEL);
        if (!plane->format_types) {
@@ -1758,6 +1760,9 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
        fb_width = fb->width << 16;
        fb_height = fb->height << 16;

+       if (plane->invert_dimensions)
+               swap(fb_width, fb_height);
+
        /* Make sure source coordinates are inside the fb. */
        if (plane_req->src_w > fb_width ||
            plane_req->src_x > fb_width - plane_req->src_w ||
@@ -1856,6 +1861,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);

        if (crtc_req->mode_valid) {
+               int hdisplay, vdisplay;
                /* If we have a mode we need a framebuffer. */
                /* If we pass -1, set the mode with the currently bound fb */
                if (crtc_req->fb_id == -1) {
@@ -1891,14 +1897,20 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,

                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);

-               if (mode->hdisplay > fb->width ||
-                   mode->vdisplay > fb->height ||
-                   crtc_req->x > fb->width - mode->hdisplay ||
-                   crtc_req->y > fb->height - mode->vdisplay) {
-                       DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb 
size %ux%u.\n",
-                                     mode->hdisplay, mode->vdisplay,
-                                     crtc_req->x, crtc_req->y,
-                                     fb->width, fb->height);
+               hdisplay = mode->hdisplay;
+               vdisplay = mode->vdisplay;
+
+               if (crtc->invert_dimensions)
+                       swap(hdisplay, vdisplay);
+
+               if (hdisplay > fb->width ||
+                   vdisplay > fb->height ||
+                   crtc_req->x > fb->width - hdisplay ||
+                   crtc_req->y > fb->height - vdisplay) {
+                       DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport 
%ux%u+%d+%d%s.\n",
+                                     fb->width, fb->height,
+                                     hdisplay, vdisplay, crtc_req->x, 
crtc_req->y,
+                                     crtc->invert_dimensions ? " (inverted)" : 
"");
                        ret = -ENOSPC;
                        goto out;
                }
@@ -3452,6 +3464,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        struct drm_framebuffer *fb;
        struct drm_pending_vblank_event *e = NULL;
        unsigned long flags;
+       int hdisplay, vdisplay;
        int ret = -EINVAL;

        if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -3481,14 +3494,19 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                goto out;
        fb = obj_to_fb(obj);

-       if (crtc->mode.hdisplay > fb->width ||
-           crtc->mode.vdisplay > fb->height ||
-           crtc->x > fb->width - crtc->mode.hdisplay ||
-           crtc->y > fb->height - crtc->mode.vdisplay) {
-               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport 
%ux%u+%d+%d.\n",
-                             fb->width, fb->height,
-                             crtc->mode.hdisplay, crtc->mode.vdisplay,
-                             crtc->x, crtc->y);
+       hdisplay = crtc->mode.hdisplay;
+       vdisplay = crtc->mode.vdisplay;
+
+       if (crtc->invert_dimensions)
+               swap(hdisplay, vdisplay);
+
+       if (hdisplay > fb->width ||
+           vdisplay > fb->height ||
+           crtc->x > fb->width - hdisplay ||
+           crtc->y > fb->height - vdisplay) {
+               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport 
%ux%u+%d+%d%s.\n",
+                             fb->width, fb->height, hdisplay, vdisplay, 
crtc->x, crtc->y,
+                             crtc->invert_dimensions ? " (inverted)" : "");
                ret = -ENOSPC;
                goto out;
        }
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b5017c9..78dd5b5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -364,6 +364,9 @@ struct drm_crtc_funcs {
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
+ * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
+ *    invert the width/height of the crtc.  This is used if the driver
+ *    is performing 90 or 270 degree rotated scanout
  * @x: x position on screen
  * @y: y position on screen
  * @funcs: CRTC control functions
@@ -397,6 +400,8 @@ struct drm_crtc {
         */
        struct drm_display_mode hwmode;

+       bool invert_dimensions;
+
        int x, y;
        const struct drm_crtc_funcs *funcs;

@@ -636,6 +641,9 @@ struct drm_plane_funcs {
  * @gamma_size: size of gamma table
  * @gamma_store: gamma correction table
  * @enabled: enabled flag
+ * @invert_dimensions: for purposes of error checking plane vs fb sizes,
+ *    invert the width/height of the plane.  This is used if the driver
+ *    is performing 90 or 270 degree rotated scanout
  * @funcs: helper functions
  * @helper_private: storage for drver layer
  */
@@ -657,6 +665,7 @@ struct drm_plane {
        uint16_t *gamma_store;

        bool enabled;
+       bool invert_dimensions;

        const struct drm_plane_funcs *funcs;
        void *helper_private;
-- 
1.7.9.1

Reply via email to