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)
committerNitin Garg <nitin.garg@nxp.com>
Tue, 20 Mar 2018 19:51:00 +0000 (14:51 -0500)
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 2c65143..f1902ef 100644 (file)
@@ -120,6 +120,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;
@@ -146,6 +147,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 36f927b..af0784e 100644 (file)
@@ -338,6 +338,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);