drm/exynos: fix to calculate CRTC shown via screen
authorJoonyoung Shim <jy0922.shim@samsung.com>
Thu, 27 Sep 2012 10:25:21 +0000 (19:25 +0900)
committerInki Dae <inki.dae@samsung.com>
Thu, 4 Oct 2012 01:10:53 +0000 (10:10 +0900)
This patch is to exactly calculate CRTC shown via screen for all cases.
Refer exynos_plane_get_size() function for this. Also source position of
fb is fixed when start position of CRTC is negative number.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_plane.c

index 8c3036dd512b2d52865e3b9afc0f048ebdfc1807..2a27b5678893e07ee4de028b1344a91b17f6e097 100644 (file)
@@ -32,6 +32,42 @@ static const uint32_t formats[] = {
        DRM_FORMAT_NV12MT,
 };
 
+/*
+ * This function is to get X or Y size shown via screen. This needs length and
+ * start position of CRTC.
+ *
+ *      <--- length --->
+ * CRTC ----------------
+ *      ^ start        ^ end
+ *
+ * There are six cases from a to b.
+ *
+ *             <----- SCREEN ----->
+ *             0                 last
+ *   ----------|------------------|----------
+ * CRTCs
+ * a -------
+ *        b -------
+ *        c --------------------------
+ *                 d --------
+ *                           e -------
+ *                                  f -------
+ */
+static int exynos_plane_get_size(int start, unsigned length, unsigned last)
+{
+       int end = start + length;
+       int size = 0;
+
+       if (start <= 0) {
+               if (end > 0)
+                       size = min_t(unsigned, end, last);
+       } else if (start <= last) {
+               size = min_t(unsigned, last - start, length);
+       }
+
+       return size;
+}
+
 int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                          struct drm_framebuffer *fb, int crtc_x, int crtc_y,
                          unsigned int crtc_w, unsigned int crtc_h,
@@ -64,8 +100,24 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                                (unsigned long)overlay->dma_addr[i]);
        }
 
-       actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w);
-       actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h);
+       actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
+       actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
+
+       if (crtc_x < 0) {
+               if (actual_w)
+                       src_x -= crtc_x;
+               else
+                       src_x += crtc_w;
+               crtc_x = 0;
+       }
+
+       if (crtc_y < 0) {
+               if (actual_h)
+                       src_y -= crtc_y;
+               else
+                       src_y += crtc_h;
+               crtc_y = 0;
+       }
 
        /* set drm framebuffer data. */
        overlay->fb_x = src_x;