From: Akash Goel <akash.g...@intel.com>

This patch adds a check on the Max down scale ratio supported by the
Panel fitter. If Source width/height is too big, that the downscale
ratio of more than 1.125 is needed to fit into the Output window,
then that configuration will be rejected.

Signed-off-by: Akash Goel <akash.g...@intel.com>
Signed-off-by: Pallavi G<pallav...@intel.com>
---
 drivers/gpu/drm/i915/intel_panel.c | 113 ++++++++++++++++++++++++++++++-------
 1 file changed, 93 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_panel.c 
b/drivers/gpu/drm/i915/intel_panel.c
index 15f2979..350e94d 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -33,6 +33,22 @@
 #include <linux/moduleparam.h>
 #include "intel_drv.h"
 
+/* Max Downscale ratio of 1.125, expressed in 1.12 fixed point format */
+#define MAX_DOWNSCALE_RATIO  (0x9 << 9)
+
+static inline u32 panel_fitter_scaling(u32 source, u32 target)
+{
+       /*
+        * Floating point operation is not supported. So the FACTOR
+        * is defined, which can avoid the floating point computation
+        * when calculating the panel ratio.
+        */
+#define ACCURACY 12
+#define FACTOR (1 << ACCURACY)
+       u32 ratio = source * FACTOR / target;
+       return (FACTOR * ratio + FACTOR/2) / FACTOR;
+}
+
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
                       struct drm_display_mode *adjusted_mode)
@@ -103,6 +119,7 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
 {
        struct drm_display_mode *adjusted_mode;
        int x, y, width, height;
+       u32 pf_horizontal_ratio, pf_vertical_ratio;
 
        adjusted_mode = &pipe_config->adjusted_mode;
 
@@ -161,6 +178,19 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
                return false;
        }
 
+       pf_horizontal_ratio = panel_fitter_scaling(pipe_config->pipe_src_w,
+                               width);
+       pf_vertical_ratio = panel_fitter_scaling(pipe_config->pipe_src_h,
+                               height);
+
+       if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) {
+               DRM_DEBUG_KMS("Src width is too big to downscale\n");
+               return false;
+       } else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) {
+               DRM_DEBUG_KMS("Src height is too big to downscale\n");
+               return false;
+       }
+
 done:
        pipe_config->pch_pfit.pos = (x << 16) | y;
        pipe_config->pch_pfit.size = (width << 16) | height;
@@ -211,21 +241,9 @@ centre_vertically(struct drm_display_mode *mode,
        mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
 }
 
-static inline u32 panel_fitter_scaling(u32 source, u32 target)
-{
-       /*
-        * Floating point operation is not supported. So the FACTOR
-        * is defined, which can avoid the floating point computation
-        * when calculating the panel ratio.
-        */
-#define ACCURACY 12
-#define FACTOR (1 << ACCURACY)
-       u32 ratio = source * FACTOR / target;
-       return (FACTOR * ratio + FACTOR/2) / FACTOR;
-}
-
 static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
-                             u32 *pfit_control)
+                             u32 *pfit_control,
+                             u32 *pf_horizontal_ratio, u32 *pf_vertical_ratio)
 {
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        u32 scaled_width = adjusted_mode->hdisplay *
@@ -234,19 +252,39 @@ static void i965_scale_aspect(struct intel_crtc_config 
*pipe_config,
                adjusted_mode->vdisplay;
 
        /* 965+ is easy, it does everything in hw */
-       if (scaled_width > scaled_height)
+       if (scaled_width > scaled_height) {
                *pfit_control |= PFIT_ENABLE |
                        PFIT_SCALING_PILLAR;
-       else if (scaled_width < scaled_height)
+               *pf_horizontal_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_w,
+                                     scaled_height / pipe_config->pipe_src_h);
+               *pf_vertical_ratio = 
panel_fitter_scaling(pipe_config->pipe_src_h,
+                                           adjusted_mode->vdisplay);
+       }
+       else if (scaled_width < scaled_height) {
                *pfit_control |= PFIT_ENABLE |
                        PFIT_SCALING_LETTER;
-       else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w)
+               *pf_vertical_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_h,
+                                     scaled_width / pipe_config->pipe_src_w);
+               *pf_horizontal_ratio = 
panel_fitter_scaling(pipe_config->pipe_src_w,
+                                               adjusted_mode->hdisplay);
+       }
+       else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) {
                *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
+               *pf_horizontal_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_w,
+                               adjusted_mode->hdisplay);
+               *pf_vertical_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_h,
+                               adjusted_mode->vdisplay);
+       }
 }
 
 static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
                              u32 *pfit_control, u32 *pfit_pgm_ratios,
-                             u32 *border)
+                             u32 *border,
+                             u32 *pf_horizontal_ratio, u32 *pf_vertical_ratio)
 {
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        u32 scaled_width = adjusted_mode->hdisplay *
@@ -264,11 +302,15 @@ static void i9xx_scale_aspect(struct intel_crtc_config 
*pipe_config,
                centre_horizontally(adjusted_mode,
                                    scaled_height /
                                    pipe_config->pipe_src_h);
+               *pf_horizontal_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_w,
+                                   scaled_height / pipe_config->pipe_src_h);
 
                *border = LVDS_BORDER_ENABLE;
                if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) {
                        bits = panel_fitter_scaling(pipe_config->pipe_src_h,
                                                    adjusted_mode->vdisplay);
+                       *pf_vertical_ratio = bits;
 
                        *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
                                             bits << PFIT_VERT_SCALE_SHIFT);
@@ -280,11 +322,15 @@ static void i9xx_scale_aspect(struct intel_crtc_config 
*pipe_config,
                centre_vertically(adjusted_mode,
                                  scaled_width /
                                  pipe_config->pipe_src_w);
+               *pf_vertical_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_h,
+                                   scaled_width / pipe_config->pipe_src_w);
 
                *border = LVDS_BORDER_ENABLE;
                if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
                        bits = panel_fitter_scaling(pipe_config->pipe_src_w,
                                                    adjusted_mode->hdisplay);
+                       *pf_horizontal_ratio = bits;
 
                        *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
                                             bits << PFIT_VERT_SCALE_SHIFT);
@@ -298,6 +344,13 @@ static void i9xx_scale_aspect(struct intel_crtc_config 
*pipe_config,
                                  VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
                                  VERT_INTERP_BILINEAR |
                                  HORIZ_INTERP_BILINEAR);
+
+               *pf_horizontal_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_w,
+                               adjusted_mode->hdisplay);
+               *pf_vertical_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_h,
+                               adjusted_mode->vdisplay);
        }
 }
 
@@ -308,6 +361,7 @@ bool intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
        struct drm_device *dev = intel_crtc->base.dev;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
        struct drm_display_mode *adjusted_mode;
+       u32 pf_horizontal_ratio = 0, pf_vertical_ratio = 0;
 
        adjusted_mode = &pipe_config->adjusted_mode;
 
@@ -325,20 +379,31 @@ bool intel_gmch_panel_fitting(struct intel_crtc 
*intel_crtc,
                centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
                centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
                border = LVDS_BORDER_ENABLE;
+               /* 1:1 scaling */
+               pf_horizontal_ratio = pf_vertical_ratio = 1;
                break;
        case DRM_MODE_SCALE_ASPECT:
                /* Scale but preserve the aspect ratio */
                if (INTEL_INFO(dev)->gen >= 4)
-                       i965_scale_aspect(pipe_config, &pfit_control);
+                       i965_scale_aspect(pipe_config, &pfit_control,
+                                &pf_horizontal_ratio, &pf_vertical_ratio);
                else
                        i9xx_scale_aspect(pipe_config, &pfit_control,
-                                         &pfit_pgm_ratios, &border);
+                                         &pfit_pgm_ratios, &border,
+                                         &pf_horizontal_ratio,
+                                         &pf_vertical_ratio);
                break;
        case DRM_MODE_SCALE_FULLSCREEN:
                /*
                 * Full scaling, even if it changes the aspect ratio.
                 * Fortunately this is all done for us in hw.
                 */
+               pf_horizontal_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_w,
+                               adjusted_mode->hdisplay);
+               pf_vertical_ratio =
+                               panel_fitter_scaling(pipe_config->pipe_src_h,
+                               adjusted_mode->vdisplay);
                if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
                    pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
                        pfit_control |= PFIT_ENABLE;
@@ -356,6 +421,14 @@ bool intel_gmch_panel_fitting(struct intel_crtc 
*intel_crtc,
                return false;
        }
 
+       if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) {
+               DRM_DEBUG_KMS("Src width is too big to downscale\n");
+               return false;
+       } else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) {
+               DRM_DEBUG_KMS("Src height is too big to downscale\n");
+               return false;
+       }
+
        /* 965+ wants fuzzy fitting */
        /* FIXME: handle multiple panels by failing gracefully */
        if (INTEL_INFO(dev)->gen >= 4)
-- 
1.9.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to