From patchwork Fri Apr 11 00:24:36 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Roper X-Patchwork-Id: 3965491 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 55C389F336 for ; Fri, 11 Apr 2014 00:22:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CCBDC20824 for ; Fri, 11 Apr 2014 00:22:18 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 355D9207F3 for ; Fri, 11 Apr 2014 00:22:14 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 196CC6E320; Thu, 10 Apr 2014 17:22:13 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTP id 0773C6E320 for ; Thu, 10 Apr 2014 17:22:11 -0700 (PDT) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 10 Apr 2014 17:22:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.97,837,1389772800"; d="scan'208";a="518661876" Received: from mdroper-hswdev.fm.intel.com (HELO mdroper-hswdev) ([10.1.134.215]) by fmsmga002.fm.intel.com with ESMTP; 10 Apr 2014 17:22:11 -0700 Received: from mattrope by mdroper-hswdev with local (Exim 4.82) (envelope-from ) id 1WYPGq-0000qU-4z; Thu, 10 Apr 2014 17:24:40 -0700 From: Matt Roper To: intel-gfx@lists.freedesktop.org Date: Thu, 10 Apr 2014 17:24:36 -0700 Message-Id: <1397175876-3216-1-git-send-email-matthew.d.roper@intel.com> X-Mailer: git-send-email 1.8.5.1 Subject: [Intel-gfx] [PATCH] drm/i915: Intel-specific primary plane handling (v2) X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 Intel hardware allows the primary plane to be disabled independently of the CRTC. Provide custom primary plane handling to allow this. v2: - Unpin fb properly on primary plane disable - Provide an Intel-specific set of primary plane formats - Additional sanity checks on setplane (in line with the checks currently being done by the DRM core primary plane helper) Signed-off-by: Matt Roper --- This patch was previously part of my universal plane series on dri-devel (http://lists.freedesktop.org/archives/dri-devel/2014-March/055852.html) but I dropped it in v4 and v5 of that series to focus on the DRM core changes. Now that universal planes have been merged, we can start building on that framework to provide i915-specific functionality. Some i-g-t changes to test this will be sent shortly. Matt drivers/gpu/drm/i915/intel_display.c | 165 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 164 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1af1d14..a0bc251 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -39,8 +39,24 @@ #include "i915_trace.h" #include #include +#include #include +const static uint32_t intel_primary_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ABGR2101010, +}; + static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); @@ -10553,17 +10569,162 @@ static void intel_shared_dpll_init(struct drm_device *dev) BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); } +static int +intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_framebuffer *tmpfb; + struct drm_rect dest = { + .x1 = crtc_x, + .y1 = crtc_y, + .x2 = crtc_x + crtc_w, + .y2 = crtc_y + crtc_h, + }; + struct drm_rect clip = { + .x2 = crtc->mode.hdisplay, + .y2 = crtc->mode.vdisplay, + }; + int ret; + + /* setplane API takes shifted source rectangle values; unshift them */ + src_x >>= 16; + src_y >>= 16; + src_w >>= 16; + src_h >>= 16; + + /* + * Current hardware can't reposition the primary plane or scale it + * (although this could change in the future). + */ + drm_rect_intersect(&dest, &clip); + if (dest.x1 != 0 || dest.y1 != 0 || + dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) { + DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n"); + return -EINVAL; + } + + if (crtc_w != src_w || crtc_h != src_h) { + DRM_DEBUG_KMS("Can't scale primary plane\n"); + return -EINVAL; + } + + /* Primary planes are locked to their owning CRTC */ + if (plane->possible_crtcs != drm_crtc_mask(crtc)) { + DRM_DEBUG_KMS("Cannot change primary plane CRTC\n"); + return -EINVAL; + } + + /* Framebuffer must be big enough to cover entire plane */ + ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb); + if (ret) + return ret; + + /* + * pipe_set_base() adjusts crtc->primary->fb; however the DRM setplane + * code that called us expects to handle the framebuffer update and + * reference counting; save and restore the current fb before + * calling it. + */ + tmpfb = plane->fb; + ret = intel_pipe_set_base(crtc, src_x, src_y, fb); + if (ret) + return ret; + plane->fb = tmpfb; + + if (!intel_crtc->primary_enabled) + intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane, + intel_crtc->pipe); + + return 0; +} + +static int +intel_primary_plane_disable(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_crtc *intel_crtc; + + if (!plane->fb) + return 0; + + if (WARN_ON(!plane->crtc)) + return -EINVAL; + + intel_crtc = to_intel_crtc(plane->crtc); + if (intel_crtc->primary_enabled) + intel_disable_primary_hw_plane(dev_priv, intel_plane->plane, + intel_plane->pipe); + + /* + * N.B. The DRM setplane code will update the plane->fb pointer after + * we finish here. + */ + intel_unpin_fb_obj(to_intel_framebuffer(plane->fb)->obj); + + return 0; +} + +static void intel_primary_plane_destroy(struct drm_plane *plane) +{ + struct intel_plane *intel_plane = to_intel_plane(plane); + intel_primary_plane_disable(plane); + drm_plane_cleanup(plane); + kfree(intel_plane); +} + +static const struct drm_plane_funcs intel_primary_plane_funcs = { + .update_plane = intel_primary_plane_setplane, + .disable_plane = intel_primary_plane_disable, + .destroy = intel_primary_plane_destroy, +}; + +static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, + int pipe) +{ + struct intel_plane *primary; + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (primary == NULL) + return NULL; + + primary->can_scale = false; + primary->pipe = pipe; + primary->plane = pipe; + + drm_plane_init(dev, &primary->base, 0, + &intel_primary_plane_funcs, intel_primary_formats, + ARRAY_SIZE(intel_primary_formats), + DRM_PLANE_TYPE_PRIMARY); + return &primary->base; +} + static void intel_crtc_init(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc; - int i; + struct drm_plane *primary; + int i, ret; intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL); if (intel_crtc == NULL) return; - drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); + primary = intel_primary_plane_create(dev, pipe); + ret = drm_crtc_init_with_planes(dev, &intel_crtc->base, primary, + NULL, &intel_crtc_funcs); + if (ret) { + drm_crtc_cleanup(&intel_crtc->base); + kfree(intel_crtc); + return; + } drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); for (i = 0; i < 256; i++) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c551472..2ce9cc3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -363,6 +363,7 @@ struct intel_crtc { bool active; unsigned long enabled_power_domains; bool eld_vld; + struct intel_plane *primary_plane; bool primary_enabled; /* is the primary plane (partially) visible? */ bool lowfreq_avail; struct intel_overlay *overlay;