drm/tegra: plane: Support horizontal reflection
authorDmitry Osipenko <digetx@gmail.com>
Wed, 17 Jun 2020 23:40:39 +0000 (02:40 +0300)
committerThierry Reding <treding@nvidia.com>
Fri, 17 Jul 2020 14:06:17 +0000 (16:06 +0200)
Support horizontal reflection mode which will allow to support 180°
rotation mode when combined with the vertical reflection.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/plane.c
drivers/gpu/drm/tegra/plane.h

index 27b1b82..03c75db 100644 (file)
@@ -368,6 +368,12 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
        h_size = window->src.w * bpp;
        v_size = window->src.h;
 
+       if (window->reflect_x)
+               h_offset += (window->src.w - 1) * bpp;
+
+       if (window->reflect_y)
+               v_offset += window->src.h - 1;
+
        value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
        tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE);
 
@@ -404,9 +410,6 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
                tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE);
        }
 
-       if (window->reflect_y)
-               v_offset += window->src.h - 1;
-
        tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET);
        tegra_plane_writel(plane, v_offset, DC_WINBUF_ADDR_V_OFFSET);
 
@@ -470,6 +473,9 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
                value |= COLOR_EXPAND;
        }
 
+       if (window->reflect_x)
+               value |= H_DIRECTION;
+
        if (window->reflect_y)
                value |= V_DIRECTION;
 
@@ -601,7 +607,10 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
                                    struct drm_plane_state *state)
 {
        struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
-       unsigned int rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y;
+       unsigned int supported_rotation = DRM_MODE_ROTATE_0 |
+                                         DRM_MODE_REFLECT_X |
+                                         DRM_MODE_REFLECT_Y;
+       unsigned int rotation = state->rotation;
        struct tegra_bo_tiling *tiling = &plane_state->tiling;
        struct tegra_plane *tegra = to_tegra_plane(plane);
        struct tegra_dc *dc = to_tegra_dc(state->crtc);
@@ -639,7 +648,21 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
                return -EINVAL;
        }
 
-       rotation = drm_rotation_simplify(state->rotation, rotation);
+       /*
+        * Older userspace used custom BO flag in order to specify the Y
+        * reflection, while modern userspace uses the generic DRM rotation
+        * property in order to achieve the same result.  The legacy BO flag
+        * duplicates the DRM rotation property when both are set.
+        */
+       if (tegra_fb_is_bottom_up(state->fb))
+               rotation |= DRM_MODE_REFLECT_Y;
+
+       rotation = drm_rotation_simplify(rotation, supported_rotation);
+
+       if (rotation & DRM_MODE_REFLECT_X)
+               plane_state->reflect_x = true;
+       else
+               plane_state->reflect_x = false;
 
        if (rotation & DRM_MODE_REFLECT_Y)
                plane_state->reflect_y = true;
@@ -706,7 +729,8 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
        window.dst.w = drm_rect_width(&plane->state->dst);
        window.dst.h = drm_rect_height(&plane->state->dst);
        window.bits_per_pixel = fb->format->cpp[0] * 8;
-       window.reflect_y = tegra_fb_is_bottom_up(fb) || state->reflect_y;
+       window.reflect_x = state->reflect_x;
+       window.reflect_y = state->reflect_y;
 
        /* copy from state */
        window.zpos = plane->state->normalized_zpos;
@@ -792,6 +816,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
        err = drm_plane_create_rotation_property(&plane->base,
                                                 DRM_MODE_ROTATE_0,
                                                 DRM_MODE_ROTATE_0 |
+                                                DRM_MODE_REFLECT_X |
                                                 DRM_MODE_REFLECT_Y);
        if (err < 0)
                dev_err(dc->dev, "failed to create rotation property: %d\n",
@@ -1080,6 +1105,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
        err = drm_plane_create_rotation_property(&plane->base,
                                                 DRM_MODE_ROTATE_0,
                                                 DRM_MODE_ROTATE_0 |
+                                                DRM_MODE_REFLECT_X |
                                                 DRM_MODE_REFLECT_Y);
        if (err < 0)
                dev_err(dc->dev, "failed to create rotation property: %d\n",
index 98e1b62..051d03d 100644 (file)
@@ -136,6 +136,7 @@ struct tegra_dc_window {
        unsigned int stride[2];
        unsigned long base[3];
        unsigned int zpos;
+       bool reflect_x;
        bool reflect_y;
 
        struct tegra_bo_tiling tiling;
index e05ef60..4cd0461 100644 (file)
@@ -61,6 +61,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
        copy->tiling = state->tiling;
        copy->format = state->format;
        copy->swap = state->swap;
+       copy->reflect_x = state->reflect_x;
        copy->reflect_y = state->reflect_y;
        copy->opaque = state->opaque;
 
index 8047fc9..c691dd7 100644 (file)
@@ -46,6 +46,7 @@ struct tegra_plane_state {
        u32 format;
        u32 swap;
 
+       bool reflect_x;
        bool reflect_y;
 
        /* used for legacy blending support only */