MMFMWK-7806: drm: imx: dcss: check up/down scale ratios
authorLaurentiu Palcu <laurentiu.palcu@nxp.com>
Wed, 6 Dec 2017 09:03:50 +0000 (11:03 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
When scaling up/down, DCSS has limits that cannot be exceeded. This
patch adds checks before the plane is updated and rejects those planes
that exceed the up/down scale limits.

Currently, the limit is 3:1 for downscaling and 1:3 for upscaling for
both video and graphics channels.

When support for WR_SCL/RD_SRC will be added, these limits will increase
to the following values:
 * video: 7:1 downscale, 1:7 upscale
 * graphics: 5:1 downscale, 1:5 upscale

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

index b0e8e26..d2cbc2f 100644 (file)
@@ -119,6 +119,7 @@ static const struct drm_plane_funcs dcss_plane_funcs = {
 static int dcss_plane_atomic_check(struct drm_plane *plane,
                                   struct drm_plane_state *state)
 {
+       struct dcss_plane *dcss_plane = to_dcss_plane(plane);
        struct drm_framebuffer *fb = state->fb;
        struct drm_gem_cma_object *cma_obj;
        struct drm_crtc_state *crtc_state;
@@ -145,6 +146,13 @@ static int dcss_plane_atomic_check(struct drm_plane *plane,
            state->crtc_y + state->crtc_h > vdisplay)
                return -EINVAL;
 
+       if (!dcss_scaler_can_scale(dcss_plane->dcss, dcss_plane->ch_num,
+                                  state->src_w >> 16, state->src_h >> 16,
+                                  state->crtc_w, state->crtc_h)) {
+               DRM_DEBUG_KMS("Invalid upscale/downscale ratio.");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
index a16809a..acac9a2 100644 (file)
@@ -339,6 +339,48 @@ static void dcss_scaler_fractions_set(struct dcss_soc *dcss, int ch_num,
                          DCSS_SCALER_H_CHR_INC);
 }
 
+/*
+ * The values below are without RD_SRC/WR_SCL support. When support will be
+ * added, these need to be changed accordingly.
+ */
+#define DCSS_SCALER_VIDEO_RATIO                        3 /* 7 with RD_SRC/WR_SCL */
+#define DCSS_SCALER_GRAPHICS_RATIO             3 /* 5 with RD_SRC/WR_SCL */
+
+/* convert to fixed point (###.# #### #### ####), easier to work with */
+#define DCSS_SCALER_VIDEO_DOWN_RATIO_FP (DCSS_SCALER_VIDEO_RATIO << 13)
+#define DCSS_SCALER_VIDEO_UP_RATIO_FP \
+               ((1 << 13) / DCSS_SCALER_VIDEO_RATIO)
+
+#define DCSS_SCALER_GRAPHICS_DOWN_RATIO_FP (DCSS_SCALER_GRAPHICS_RATIO << 13)
+#define DCSS_SCALER_GRAPHICS_UP_RATIO_FP \
+               ((1 << 13) / DCSS_SCALER_GRAPHICS_RATIO)
+
+static const struct dcss_scaler_ratios {
+       u16 downscale_ratio;
+       u16 upscale_ratio;
+} dcss_scaler_ratios_map[] = {
+       {DCSS_SCALER_GRAPHICS_DOWN_RATIO_FP, DCSS_SCALER_GRAPHICS_UP_RATIO_FP},
+       {DCSS_SCALER_VIDEO_DOWN_RATIO_FP,    DCSS_SCALER_VIDEO_UP_RATIO_FP},
+       {DCSS_SCALER_VIDEO_DOWN_RATIO_FP,    DCSS_SCALER_VIDEO_UP_RATIO_FP},
+};
+
+bool dcss_scaler_can_scale(struct dcss_soc *dcss, int ch_num,
+                          int src_xres, int src_yres,
+                          int dst_xres, int dst_yres)
+{
+       u32 vscale_fp, hscale_fp;
+
+       /* Convert to fixed point. Easier to work with. */
+       vscale_fp = (src_yres << 13) / dst_yres;
+       hscale_fp = (src_xres << 13) / dst_xres;
+
+       return vscale_fp <= dcss_scaler_ratios_map[ch_num].downscale_ratio &&
+              vscale_fp >= dcss_scaler_ratios_map[ch_num].upscale_ratio   &&
+              hscale_fp <= dcss_scaler_ratios_map[ch_num].downscale_ratio &&
+              hscale_fp >= dcss_scaler_ratios_map[ch_num].upscale_ratio;
+}
+EXPORT_SYMBOL(dcss_scaler_can_scale);
+
 static void dcss_scaler_coef_clr(struct dcss_soc *dcss, int ch_num)
 {
        int i;
index 75db61f..6f0eec4 100644 (file)
@@ -77,6 +77,9 @@ void dcss_ss_enable(struct dcss_soc *dcss, bool en);
 void dcss_scaler_enable(struct dcss_soc *dcss, int ch_num, bool en);
 void dcss_scaler_setup(struct dcss_soc *dcss, int ch_num, u32 pix_format,
                       int src_xres, int src_yres, int dst_xres, int dst_yres);
+bool dcss_scaler_can_scale(struct dcss_soc *dcss, int ch_num,
+                          int src_xres, int src_yres,
+                          int dst_xres, int dst_yres);
 
 /* CTXLD */
 int dcss_ctxld_enable(struct dcss_soc *dcss);