MLK-19274: drm: imx: dcss: add rotation functionality
authorLaurentiu Palcu <laurentiu.palcu@nxp.com>
Mon, 20 Aug 2018 08:27:29 +0000 (11:27 +0300)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
This patch will allow userspace to rotate planes by setting the
'rotation' property. Generally, 0 and 180 rotations are allowed for
pretty much all 8-bit xRGB and 2-plane YUV420 formats. 90/270 rotations
can be performed only for non-compressed tiled GPU xRGB formats. Tiled
YUV420 formats do not allow rotations at all because these formats need
DTRC for de-tiling and DTRC has no rotation support.

For more info, consult the DPR Features chapter in the reference manual.

Test example:

modetest -M imx-drm -w 27:rotation:4 -w 32:rotation:33 -w 27:alpha:30 -s
42@31:3840x2160-60@XR24 -P 32@31:3840x2160@NV21

The above will perform:
 * 180 degree rotation of primary plane (XR24);
 * vertical flip of first overlay plane (rotate-0 | reflect-y);
 * set primary plane alpha to 30;

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
drivers/gpu/drm/imx/dcss/dcss-plane.c
drivers/gpu/imx/dcss/dcss-dpr.c
include/video/imx-dcss.h

index 0c19da0..8c9070c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -177,6 +177,37 @@ static const struct drm_plane_funcs dcss_plane_funcs = {
        .format_mod_supported = dcss_plane_format_mod_supported,
 };
 
+static bool dcss_plane_can_rotate(u32 pixel_format, bool mod_present,
+                                 u64 modifier, unsigned int rotation)
+{
+       enum dcss_color_space cs = dcss_drm_fourcc_to_colorspace(pixel_format);
+       bool linear_format = !mod_present ||
+                            (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
+       u32 supported_rotation = DRM_MODE_ROTATE_0;
+
+       if (cs == DCSS_COLORSPACE_RGB && linear_format)
+               supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+                                    DRM_MODE_REFLECT_MASK;
+       else if (cs == DCSS_COLORSPACE_RGB &&
+                modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
+               supported_rotation = DRM_MODE_ROTATE_MASK |
+                                    DRM_MODE_REFLECT_MASK;
+       else if (cs == DCSS_COLORSPACE_RGB &&
+                modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC)
+               supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+                                    DRM_MODE_REFLECT_MASK;
+       else if (cs == DCSS_COLORSPACE_YUV && linear_format &&
+                (pixel_format == DRM_FORMAT_NV12 ||
+                pixel_format == DRM_FORMAT_NV21))
+               supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+                                    DRM_MODE_REFLECT_MASK;
+       else if (cs == DCSS_COLORSPACE_YUV && linear_format &&
+                pixel_format == DRM_FORMAT_P010)
+               supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y;
+
+       return !!(rotation & supported_rotation);
+}
+
 static int dcss_plane_atomic_check(struct drm_plane *plane,
                                   struct drm_plane_state *state)
 {
@@ -216,6 +247,14 @@ static int dcss_plane_atomic_check(struct drm_plane *plane,
        if (!drm_rect_intersect(&crtc_rect, &disp_rect))
                return -EINVAL;
 
+       if (!dcss_plane_can_rotate(fb->format->format,
+                                  !!(fb->flags & DRM_MODE_FB_MODIFIERS),
+                                  fb->modifier,
+                                  state->rotation)) {
+               DRM_ERROR("requested rotation is not allowed!\n");
+               return -EINVAL;
+       }
+
        /* cropping is only available on overlay planes when DTRC is used */
        if (state->crtc_x < 0 || state->crtc_y < 0 ||
            state->crtc_x + state->crtc_w > hdisplay ||
@@ -388,7 +427,8 @@ static bool dcss_plane_needs_setup(struct drm_plane_state *state,
               state->src_w  != old_state->src_w  ||
               state->src_h  != old_state->src_h  ||
               fb->format->format != old_fb->format->format ||
-              fb->modifier  != old_fb->modifier;
+              fb->modifier  != old_fb->modifier ||
+              state->rotation != old_state->rotation;
 }
 
 static void dcss_plane_adjust(struct drm_rect *dis_rect,
@@ -509,6 +549,8 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
 
        dcss_dpr_set_res(dcss_plane->dcss, dcss_plane->ch_num,
                         src_w, src_h, adj_w, adj_h);
+       dcss_dpr_set_rotation(dcss_plane->dcss, dcss_plane->ch_num,
+                             state->rotation);
        dcss_plane_atomic_set_base(dcss_plane);
 
        if (fb->modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED) {
@@ -635,6 +677,15 @@ struct dcss_plane *dcss_plane_init(struct drm_device *drm,
        if (ret)
                return ERR_PTR(ret);
 
+       drm_plane_create_rotation_property(&dcss_plane->base,
+                                          DRM_MODE_ROTATE_0,
+                                          DRM_MODE_ROTATE_0   |
+                                          DRM_MODE_ROTATE_90  |
+                                          DRM_MODE_ROTATE_180 |
+                                          DRM_MODE_ROTATE_270 |
+                                          DRM_MODE_REFLECT_X  |
+                                          DRM_MODE_REFLECT_Y);
+
        dcss_plane->ch_num = 2 - zpos;
        dcss_plane->alpha_val = 255;
 
index 7f84232..c0da802 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 NXP
+ * Copyright (C) 2017-2018 NXP
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -19,6 +19,7 @@
 #include <linux/sizes.h>
 #include <linux/io.h>
 #include <linux/seq_file.h>
+#include <drm/drmP.h>
 #include <drm/drm_fourcc.h>
 
 #include <video/imx-dcss.h>
@@ -734,3 +735,21 @@ void dcss_dpr_irq_enable(struct dcss_soc *dcss, bool en)
        dcss_writel(en ? 0xfe : 0xff, dpr->ch[1].base_reg + DCSS_DPR_IRQ_MASK);
        dcss_writel(en ? 0xfe : 0xff, dpr->ch[2].base_reg + DCSS_DPR_IRQ_MASK);
 }
+
+void dcss_dpr_set_rotation(struct dcss_soc *dcss, int ch_num, u32 rotation)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
+
+       ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
+       ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
+
+       if (rotation & DRM_MODE_ROTATE_90)
+               ch->frame_ctrl |= 1 << ROT_ENC_POS;
+       else if (rotation & DRM_MODE_ROTATE_180)
+               ch->frame_ctrl |= 2 << ROT_ENC_POS;
+       else if (rotation & DRM_MODE_ROTATE_270)
+               ch->frame_ctrl |= 3 << ROT_ENC_POS;
+}
+EXPORT_SYMBOL(dcss_dpr_set_rotation);
index 03330f3..51a3615 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -84,6 +84,8 @@ void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format,
 void dcss_dpr_tile_derive(struct dcss_soc *dcss,
                          int ch_num,
                          uint64_t modifier);
+void dcss_dpr_set_rotation(struct dcss_soc *dcss, int ch_num, u32 rotation);
+
 /* DTG */
 void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm);
 void dcss_dtg_plane_pos_set(struct dcss_soc *dcss, int ch_num,