From patchwork Tue Mar 11 12:54:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: akash.goel@intel.com X-Patchwork-Id: 3812311 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id B0C40BF540 for ; Tue, 11 Mar 2014 12:52:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8AB5720219 for ; Tue, 11 Mar 2014 12:52:38 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 660FB2021A for ; Tue, 11 Mar 2014 12:52:37 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D1221FACA5; Tue, 11 Mar 2014 05:52:35 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id 04C26FAC94 for ; Tue, 11 Mar 2014 05:52:27 -0700 (PDT) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga101.fm.intel.com with ESMTP; 11 Mar 2014 05:52:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.97,630,1389772800"; d="scan'208";a="489748414" Received: from akashgoe-desktop.iind.intel.com ([10.223.82.34]) by fmsmga001.fm.intel.com with ESMTP; 11 Mar 2014 05:52:25 -0700 From: akash.goel@intel.com To: intel-gfx@lists.freedesktop.org Date: Tue, 11 Mar 2014 18:24:21 +0530 Message-Id: <1394542461-22198-4-git-send-email-akash.goel@intel.com> X-Mailer: git-send-email 1.8.5.2 In-Reply-To: <1394542461-22198-1-git-send-email-akash.goel@intel.com> References: <20140310051329.GA1328@phenom.ffwll.local> <1394542461-22198-1-git-send-email-akash.goel@intel.com> Cc: Akash Goel Subject: [Intel-gfx] [PATCH v2 3/3] drm/i915: New drm crtc property for varying the size of borders X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Akash Goel This patch adds a new drm crtc property for varying the size of the horizontal & vertical borers of the output/display window. This will control the output of Panel fitter. v2: Added a new check for the invalid border size input Testcase: igt/kms_panel_fitter_test Signed-off-by: Akash Goel --- drivers/gpu/drm/i915/i915_drv.h | 7 ++ drivers/gpu/drm/i915/intel_display.c | 28 +++++- drivers/gpu/drm/i915/intel_drv.h | 4 + drivers/gpu/drm/i915/intel_panel.c | 159 +++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6f3af15..eec32ed 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1614,6 +1614,13 @@ typedef struct drm_i915_private { */ struct drm_property *input_size_property; + /* + * Property to dynamically vary the size of the + * borders. This will indirectly control the size + * of the display window i.e Panel fitter output + */ + struct drm_property *output_border_property; + uint32_t hw_context_size; struct list_head context_list; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8772390..68ec5b5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10447,7 +10447,16 @@ static int intel_crtc_set_property(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int ret = -ENOENT; + + if (property == dev_priv->output_border_property) { + if (val == (uint64_t)intel_crtc->border_size) + return 0; + + intel_crtc->border_size = (uint32_t)val; + intel_crtc->border_size_changed = 1; + + goto done; + } if (property == dev_priv->input_size_property) { int new_width = (int)((val >> 16) & 0xffff); @@ -10483,7 +10492,13 @@ static int intel_crtc_set_property(struct drm_crtc *crtc, return 0; } - return ret; + return -EINVAL; + +done: + if (crtc) + intel_crtc_restore_mode(crtc); + + return 0; } static const struct drm_crtc_funcs intel_crtc_funcs = { @@ -10642,6 +10657,15 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) drm_object_attach_property(&intel_crtc->base.base, dev_priv->input_size_property, 0); + + if (!dev_priv->output_border_property) + dev_priv->output_border_property = + drm_property_create_range(dev, 0, "border size", 0, 0xFFFFFFFF); + + if (dev_priv->output_border_property) + drm_object_attach_property(&intel_crtc->base.base, + dev_priv->output_border_property, + 0); } enum pipe intel_get_pipe_from_connector(struct intel_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5360d16..68eec38 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -387,6 +387,10 @@ struct intel_crtc { bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; + /* border info for the output/display window */ + bool border_size_changed; + uint32_t border_size; + /* per-pipe watermark state */ struct { /* watermarks currently being used */ diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index cb05840..1d8444d 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -42,6 +42,63 @@ intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, drm_mode_set_crtcinfo(adjusted_mode, 0); } +void +intel_pch_manual_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_display_mode *adjusted_mode; + int x, y; + u32 tot_width, tot_height; + u32 dst_width, dst_height; + + adjusted_mode = &pipe_config->adjusted_mode; + + tot_width = adjusted_mode->crtc_hdisplay; + tot_height = adjusted_mode->crtc_vdisplay; + + /* + * Having non zero borders will reduce the size of 'HACTIVE/VACTIVE' + * region. So (HACTIVE - Left border - Right Border) * + * (VACTIVE - Top Border - Bottom border) will effectively be the + * output rectangle on screen + */ + dst_width = tot_width - + (((intel_crtc->border_size >> 16) & 0xffff) * 2); + dst_height = tot_height - + ((intel_crtc->border_size & 0xffff) * 2); + + if ((dst_width == 0) || (dst_height == 0)) { + DRM_ERROR("Invalid border size input\n"); + goto out; + } + + x = y = 0; + + if (tot_width < dst_width) { + DRM_ERROR("width is too big\n"); + goto out; + } else if (dst_width & 1) { + DRM_ERROR("width must be even\n"); + goto out; + } else if (tot_height < dst_height) { + DRM_ERROR("height is too big\n"); + goto out; + } else if (dst_height & 1) { + DRM_ERROR("height must be even\n"); + goto out; + } + + x = (adjusted_mode->hdisplay - dst_width + 1)/2; + y = (adjusted_mode->vdisplay - dst_height + 1)/2; + + pipe_config->pch_pfit.pos = (x << 16) | y; + pipe_config->pch_pfit.size = (dst_width << 16) | dst_height; + pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; + +out: + intel_crtc->border_size_changed = 0; +} + /* adjusted_mode has been preset to be the panel's fixed mode */ void intel_pch_panel_fitting(struct intel_crtc *intel_crtc, @@ -55,6 +112,13 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, x = y = width = height = 0; + /* check if size of borders has changed and border size is + not zero, otherwise fall through the regular path */ + if (intel_crtc->border_size_changed && + intel_crtc->border_size) + return intel_pch_manual_panel_fitting(intel_crtc, + pipe_config); + /* Native modes don't need fitting */ if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && adjusted_mode->vdisplay == pipe_config->pipe_src_h) @@ -247,6 +311,94 @@ static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config, } } +void intel_gmch_manual_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = intel_crtc->base.dev; + u32 pfit_control = 0, border = 0; + u32 pf_horizontal_ratio, pf_vertical_ratio; + struct drm_display_mode *adjusted_mode; + u32 tot_width, tot_height; + u32 src_width, src_height; /* pipesrc.x, pipesrc.y */ + u32 dst_width, dst_height; + + adjusted_mode = &pipe_config->adjusted_mode; + + src_width = pipe_config->pipe_src_w; + src_height = pipe_config->pipe_src_h; + + tot_width = adjusted_mode->crtc_hdisplay; + tot_height = adjusted_mode->crtc_vdisplay; + + /* + * Having non zero borders will reduce the size of 'HACTIVE/VACTIVE' + * region. So (HACTIVE - Left border - Right Border) * + * (VACTIVE - Top Border - Bottom border) will effectively be the + * output rectangle on screen + */ + dst_width = tot_width - + (((intel_crtc->border_size >> 16) & 0xffff) * 2); + dst_height = tot_height - + ((intel_crtc->border_size & 0xffff) * 2); + + if ((dst_width == 0) || (dst_height == 0)) { + DRM_ERROR("Invalid border size input\n"); + goto out; + } + + pf_horizontal_ratio = panel_fitter_scaling(src_width, dst_width); + pf_vertical_ratio = panel_fitter_scaling(src_height, dst_height); + +/* Max Downscale ratio of 1.125, expressed in 1.12 fixed point format */ +#define MAX_DOWNSCALE_RATIO (0x9 << 9) + + if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) { + DRM_ERROR("width is too small\n"); + goto out; + } else if (tot_width < dst_width) { + DRM_ERROR("width is too big\n"); + goto out; + } else if (dst_width & 1) { + DRM_ERROR("width must be even\n"); + goto out; + } else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) { + DRM_ERROR("height is too small\n"); + goto out; + } else if (tot_height < dst_height) { + DRM_ERROR("height is too big\n"); + goto out; + } else if (dst_height & 1) { + DRM_ERROR("height must be even\n"); + goto out; + } + + if (dst_width != tot_width) + centre_horizontally(adjusted_mode, dst_width); + if (dst_height != tot_height) + centre_vertically(adjusted_mode, dst_height); + border = LVDS_BORDER_ENABLE; + + if (INTEL_INFO(dev)->gen >= 4) { + /* PFIT_SCALING_PROGRAMMED is de-featured on BYT */ + pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; + pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | PFIT_FILTER_FUZZY); + } else { + pfit_control |= (PFIT_ENABLE | + VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR); + } + + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + + pipe_config->gmch_pfit.control = pfit_control; + pipe_config->gmch_pfit.lvds_border_bits = border; + +out: + intel_crtc->border_size_changed = 0; +} + void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, struct intel_crtc_config *pipe_config, int fitting_mode) @@ -257,6 +409,13 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, adjusted_mode = &pipe_config->adjusted_mode; + /* check if size of borders has changed and border size is + not zero, otherwise fall through the regular path */ + if (intel_crtc->border_size_changed && + intel_crtc->border_size) + return intel_gmch_manual_panel_fitting(intel_crtc, + pipe_config); + /* Native modes don't need fitting */ if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && adjusted_mode->vdisplay == pipe_config->pipe_src_h)