From: Akash Goel <akash.goel@xxxxxxxxx> 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.goel@xxxxxxxxx> Signed-off-by: Pallavi G<pallavi.g@xxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx