* [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c
@ 2020-12-09 0:51 Dave Airlie
2020-12-09 1:05 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for " Patchwork
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Dave Airlie @ 2020-12-09 0:51 UTC (permalink / raw)
To: intel-gfx
From: Dave Airlie <airlied@redhat.com>
This file is a monster, let's start simple, the cursor plane code
seems pretty standalone, and splits out easily enough.
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/display/intel_cursor.c | 837 +++++++++++++++++++
drivers/gpu/drm/i915/display/intel_display.c | 786 +----------------
drivers/gpu/drm/i915/display/intel_display.h | 12 +
4 files changed, 856 insertions(+), 780 deletions(-)
create mode 100644 drivers/gpu/drm/i915/display/intel_cursor.c
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e5574e506a5c..98a35b939052 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -197,6 +197,7 @@ i915-y += \
display/intel_combo_phy.o \
display/intel_connector.o \
display/intel_csr.o \
+ display/intel_cursor.o \
display/intel_display.o \
display/intel_display_power.o \
display/intel_dpio_phy.o \
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
new file mode 100644
index 000000000000..d50e712f9113
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_fourcc.h>
+
+#include "intel_atomic.h"
+#include "intel_atomic_plane.h"
+#include "intel_display_types.h"
+#include "intel_display.h"
+
+#include "intel_frontbuffer.h"
+#include "intel_pm.h"
+#include "intel_psr.h"
+#include "intel_sprite.h"
+
+/* Cursor formats */
+static const u32 intel_cursor_formats[] = {
+ DRM_FORMAT_ARGB8888,
+};
+
+static const u64 cursor_format_modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+static bool
+needs_modeset(const struct intel_crtc_state *state)
+{
+ return drm_atomic_crtc_needs_modeset(&state->uapi);
+}
+
+static struct intel_frontbuffer *
+to_intel_frontbuffer(struct drm_framebuffer *fb)
+{
+ return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
+}
+
+static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv =
+ to_i915(plane_state->uapi.plane->dev);
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
+ const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ u32 base;
+
+ if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
+ base = sg_dma_address(obj->mm.pages->sgl);
+ else
+ base = intel_plane_ggtt_offset(plane_state);
+
+ return base + plane_state->color_plane[0].offset;
+}
+
+static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
+{
+ int x = plane_state->uapi.dst.x1;
+ int y = plane_state->uapi.dst.y1;
+ u32 pos = 0;
+
+ if (x < 0) {
+ pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+ x = -x;
+ }
+ pos |= x << CURSOR_X_SHIFT;
+
+ if (y < 0) {
+ pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+ y = -y;
+ }
+ pos |= y << CURSOR_Y_SHIFT;
+
+ return pos;
+}
+
+static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+ const struct drm_mode_config *config =
+ &plane_state->uapi.plane->dev->mode_config;
+ int width = drm_rect_width(&plane_state->uapi.dst);
+ int height = drm_rect_height(&plane_state->uapi.dst);
+
+ return width > 0 && width <= config->cursor_width &&
+ height > 0 && height <= config->cursor_height;
+}
+
+static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv =
+ to_i915(plane_state->uapi.plane->dev);
+ unsigned int rotation = plane_state->hw.rotation;
+ int src_x, src_y;
+ u32 offset;
+ int ret;
+
+ ret = intel_plane_compute_gtt(plane_state);
+ if (ret)
+ return ret;
+
+ if (!plane_state->uapi.visible)
+ return 0;
+
+ src_x = plane_state->uapi.src.x1 >> 16;
+ src_y = plane_state->uapi.src.y1 >> 16;
+
+ intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
+ offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
+ plane_state, 0);
+
+ if (src_x != 0 || src_y != 0) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Arbitrary cursor panning not supported\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Put the final coordinates back so that the src
+ * coordinate checks will see the right values.
+ */
+ drm_rect_translate_to(&plane_state->uapi.src,
+ src_x << 16, src_y << 16);
+
+ /* ILK+ do this automagically in hardware */
+ if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
+ int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
+ int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
+
+ offset += (src_h * src_w - 1) * fb->format->cpp[0];
+ }
+
+ plane_state->color_plane[0].offset = offset;
+ plane_state->color_plane[0].x = src_x;
+ plane_state->color_plane[0].y = src_y;
+
+ return 0;
+}
+
+static int intel_check_cursor(struct intel_crtc_state *crtc_state,
+ struct intel_plane_state *plane_state)
+{
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
+ struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+ const struct drm_rect src = plane_state->uapi.src;
+ const struct drm_rect dst = plane_state->uapi.dst;
+ int ret;
+
+ if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+ drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n");
+ return -EINVAL;
+ }
+
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ true);
+ if (ret)
+ return ret;
+
+ /* Use the unclipped src/dst rectangles, which we program to hw */
+ plane_state->uapi.src = src;
+ plane_state->uapi.dst = dst;
+
+ ret = intel_cursor_check_surface(plane_state);
+ if (ret)
+ return ret;
+
+ if (!plane_state->uapi.visible)
+ return 0;
+
+ ret = intel_plane_check_src_coordinates(plane_state);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static unsigned int
+i845_cursor_max_stride(struct intel_plane *plane,
+ u32 pixel_format, u64 modifier,
+ unsigned int rotation)
+{
+ return 2048;
+}
+
+static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
+{
+ u32 cntl = 0;
+
+ if (crtc_state->gamma_enable)
+ cntl |= CURSOR_GAMMA_ENABLE;
+
+ return cntl;
+}
+
+static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ return CURSOR_ENABLE |
+ CURSOR_FORMAT_ARGB |
+ CURSOR_STRIDE(plane_state->color_plane[0].stride);
+}
+
+static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+ int width = drm_rect_width(&plane_state->uapi.dst);
+
+ /*
+ * 845g/865g are only limited by the width of their cursors,
+ * the height is arbitrary up to the precision of the register.
+ */
+ return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
+}
+
+static int i845_check_cursor(struct intel_crtc_state *crtc_state,
+ struct intel_plane_state *plane_state)
+{
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
+ struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+ int ret;
+
+ ret = intel_check_cursor(crtc_state, plane_state);
+ if (ret)
+ return ret;
+
+ /* if we want to turn off the cursor ignore width and height */
+ if (!fb)
+ return 0;
+
+ /* Check for which cursor types we support */
+ if (!i845_cursor_size_ok(plane_state)) {
+ drm_dbg_kms(&i915->drm,
+ "Cursor dimension %dx%d not supported\n",
+ drm_rect_width(&plane_state->uapi.dst),
+ drm_rect_height(&plane_state->uapi.dst));
+ return -EINVAL;
+ }
+
+ drm_WARN_ON(&i915->drm, plane_state->uapi.visible &&
+ plane_state->color_plane[0].stride != fb->pitches[0]);
+
+ switch (fb->pitches[0]) {
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ break;
+ default:
+ drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
+ fb->pitches[0]);
+ return -EINVAL;
+ }
+
+ plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
+
+ return 0;
+}
+
+static void i845_update_cursor(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ u32 cntl = 0, base = 0, pos = 0, size = 0;
+ unsigned long irqflags;
+
+ if (plane_state && plane_state->uapi.visible) {
+ unsigned int width = drm_rect_width(&plane_state->uapi.dst);
+ unsigned int height = drm_rect_height(&plane_state->uapi.dst);
+
+ cntl = plane_state->ctl |
+ i845_cursor_ctl_crtc(crtc_state);
+
+ size = (height << 12) | width;
+
+ base = intel_cursor_base(plane_state);
+ pos = intel_cursor_position(plane_state);
+ }
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+ /* On these chipsets we can only modify the base/size/stride
+ * whilst the cursor is disabled.
+ */
+ if (plane->cursor.base != base ||
+ plane->cursor.size != size ||
+ plane->cursor.cntl != cntl) {
+ intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0);
+ intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base);
+ intel_de_write_fw(dev_priv, CURSIZE, size);
+ intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
+ intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl);
+
+ plane->cursor.base = base;
+ plane->cursor.size = size;
+ plane->cursor.cntl = cntl;
+ } else {
+ intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
+ }
+
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i845_disable_cursor(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
+{
+ i845_update_cursor(plane, crtc_state, NULL);
+}
+
+static bool i845_cursor_get_hw_state(struct intel_plane *plane,
+ enum pipe *pipe)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ enum intel_display_power_domain power_domain;
+ intel_wakeref_t wakeref;
+ bool ret;
+
+ power_domain = POWER_DOMAIN_PIPE(PIPE_A);
+ wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+ if (!wakeref)
+ return false;
+
+ ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
+
+ *pipe = PIPE_A;
+
+ intel_display_power_put(dev_priv, power_domain, wakeref);
+
+ return ret;
+}
+
+static unsigned int
+i9xx_cursor_max_stride(struct intel_plane *plane,
+ u32 pixel_format, u64 modifier,
+ unsigned int rotation)
+{
+ return plane->base.dev->mode_config.cursor_width * 4;
+}
+
+static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ u32 cntl = 0;
+
+ if (INTEL_GEN(dev_priv) >= 11)
+ return cntl;
+
+ if (crtc_state->gamma_enable)
+ cntl = MCURSOR_GAMMA_ENABLE;
+
+ if (crtc_state->csc_enable)
+ cntl |= MCURSOR_PIPE_CSC_ENABLE;
+
+ if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
+ cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
+
+ return cntl;
+}
+
+static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv =
+ to_i915(plane_state->uapi.plane->dev);
+ u32 cntl = 0;
+
+ if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
+ cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
+
+ switch (drm_rect_width(&plane_state->uapi.dst)) {
+ case 64:
+ cntl |= MCURSOR_MODE_64_ARGB_AX;
+ break;
+ case 128:
+ cntl |= MCURSOR_MODE_128_ARGB_AX;
+ break;
+ case 256:
+ cntl |= MCURSOR_MODE_256_ARGB_AX;
+ break;
+ default:
+ MISSING_CASE(drm_rect_width(&plane_state->uapi.dst));
+ return 0;
+ }
+
+ if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
+ cntl |= MCURSOR_ROTATE_180;
+
+ return cntl;
+}
+
+static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv =
+ to_i915(plane_state->uapi.plane->dev);
+ int width = drm_rect_width(&plane_state->uapi.dst);
+ int height = drm_rect_height(&plane_state->uapi.dst);
+
+ if (!intel_cursor_size_ok(plane_state))
+ return false;
+
+ /* Cursor width is limited to a few power-of-two sizes */
+ switch (width) {
+ case 256:
+ case 128:
+ case 64:
+ break;
+ default:
+ return false;
+ }
+
+ /*
+ * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
+ * height from 8 lines up to the cursor width, when the
+ * cursor is not rotated. Everything else requires square
+ * cursors.
+ */
+ if (HAS_CUR_FBC(dev_priv) &&
+ plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
+ if (height < 8 || height > width)
+ return false;
+ } else {
+ if (height != width)
+ return false;
+ }
+
+ return true;
+}
+
+static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
+ struct intel_plane_state *plane_state)
+{
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
+ enum pipe pipe = plane->pipe;
+ int ret;
+
+ ret = intel_check_cursor(crtc_state, plane_state);
+ if (ret)
+ return ret;
+
+ /* if we want to turn off the cursor ignore width and height */
+ if (!fb)
+ return 0;
+
+ /* Check for which cursor types we support */
+ if (!i9xx_cursor_size_ok(plane_state)) {
+ drm_dbg(&dev_priv->drm,
+ "Cursor dimension %dx%d not supported\n",
+ drm_rect_width(&plane_state->uapi.dst),
+ drm_rect_height(&plane_state->uapi.dst));
+ return -EINVAL;
+ }
+
+ drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible &&
+ plane_state->color_plane[0].stride != fb->pitches[0]);
+
+ if (fb->pitches[0] !=
+ drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Invalid cursor stride (%u) (cursor width %d)\n",
+ fb->pitches[0],
+ drm_rect_width(&plane_state->uapi.dst));
+ return -EINVAL;
+ }
+
+ /*
+ * There's something wrong with the cursor on CHV pipe C.
+ * If it straddles the left edge of the screen then
+ * moving it away from the edge or disabling it often
+ * results in a pipe underrun, and often that can lead to
+ * dead pipe (constant underrun reported, and it scans
+ * out just a solid color). To recover from that, the
+ * display power well must be turned off and on again.
+ * Refuse the put the cursor into that compromised position.
+ */
+ if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
+ plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) {
+ drm_dbg_kms(&dev_priv->drm,
+ "CHV cursor C not allowed to straddle the left screen edge\n");
+ return -EINVAL;
+ }
+
+ plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
+
+ return 0;
+}
+
+static void i9xx_update_cursor(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ enum pipe pipe = plane->pipe;
+ u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
+ unsigned long irqflags;
+
+ if (plane_state && plane_state->uapi.visible) {
+ unsigned width = drm_rect_width(&plane_state->uapi.dst);
+ unsigned height = drm_rect_height(&plane_state->uapi.dst);
+
+ cntl = plane_state->ctl |
+ i9xx_cursor_ctl_crtc(crtc_state);
+
+ if (width != height)
+ fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
+
+ base = intel_cursor_base(plane_state);
+ pos = intel_cursor_position(plane_state);
+ }
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+ /*
+ * On some platforms writing CURCNTR first will also
+ * cause CURPOS to be armed by the CURBASE write.
+ * Without the CURCNTR write the CURPOS write would
+ * arm itself. Thus we always update CURCNTR before
+ * CURPOS.
+ *
+ * On other platforms CURPOS always requires the
+ * CURBASE write to arm the update. Additonally
+ * a write to any of the cursor register will cancel
+ * an already armed cursor update. Thus leaving out
+ * the CURBASE write after CURPOS could lead to a
+ * cursor that doesn't appear to move, or even change
+ * shape. Thus we always write CURBASE.
+ *
+ * The other registers are armed by by the CURBASE write
+ * except when the plane is getting enabled at which time
+ * the CURCNTR write arms the update.
+ */
+
+ if (INTEL_GEN(dev_priv) >= 9)
+ skl_write_cursor_wm(plane, crtc_state);
+
+ if (!needs_modeset(crtc_state))
+ intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
+
+ if (plane->cursor.base != base ||
+ plane->cursor.size != fbc_ctl ||
+ plane->cursor.cntl != cntl) {
+ if (HAS_CUR_FBC(dev_priv))
+ intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe),
+ fbc_ctl);
+ intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl);
+ intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
+ intel_de_write_fw(dev_priv, CURBASE(pipe), base);
+
+ plane->cursor.base = base;
+ plane->cursor.size = fbc_ctl;
+ plane->cursor.cntl = cntl;
+ } else {
+ intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
+ intel_de_write_fw(dev_priv, CURBASE(pipe), base);
+ }
+
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i9xx_disable_cursor(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
+{
+ i9xx_update_cursor(plane, crtc_state, NULL);
+}
+
+static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
+ enum pipe *pipe)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ enum intel_display_power_domain power_domain;
+ intel_wakeref_t wakeref;
+ bool ret;
+ u32 val;
+
+ /*
+ * Not 100% correct for planes that can move between pipes,
+ * but that's only the case for gen2-3 which don't have any
+ * display power wells.
+ */
+ power_domain = POWER_DOMAIN_PIPE(plane->pipe);
+ wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+ if (!wakeref)
+ return false;
+
+ val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
+
+ ret = val & MCURSOR_MODE;
+
+ if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+ *pipe = plane->pipe;
+ else
+ *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
+ MCURSOR_PIPE_SELECT_SHIFT;
+
+ intel_display_power_put(dev_priv, power_domain, wakeref);
+
+ return ret;
+}
+
+static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
+ u32 format, u64 modifier)
+{
+ return modifier == DRM_FORMAT_MOD_LINEAR &&
+ format == DRM_FORMAT_ARGB8888;
+}
+
+static int
+intel_legacy_cursor_update(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,
+ u32 src_x, u32 src_y,
+ u32 src_w, u32 src_h,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct intel_plane *plane = to_intel_plane(_plane);
+ struct intel_crtc *crtc = to_intel_crtc(_crtc);
+ struct intel_plane_state *old_plane_state =
+ to_intel_plane_state(plane->base.state);
+ struct intel_plane_state *new_plane_state;
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+ struct intel_crtc_state *new_crtc_state;
+ int ret;
+
+ /*
+ * When crtc is inactive or there is a modeset pending,
+ * wait for it to complete in the slowpath
+ *
+ * FIXME bigjoiner fastpath would be good
+ */
+ if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
+ crtc_state->update_pipe || crtc_state->bigjoiner)
+ goto slow;
+
+ /*
+ * Don't do an async update if there is an outstanding commit modifying
+ * the plane. This prevents our async update's changes from getting
+ * overridden by a previous synchronous update's state.
+ */
+ if (old_plane_state->uapi.commit &&
+ !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
+ goto slow;
+
+ /*
+ * If any parameters change that may affect watermarks,
+ * take the slowpath. Only changing fb or position should be
+ * in the fastpath.
+ */
+ if (old_plane_state->uapi.crtc != &crtc->base ||
+ old_plane_state->uapi.src_w != src_w ||
+ old_plane_state->uapi.src_h != src_h ||
+ old_plane_state->uapi.crtc_w != crtc_w ||
+ old_plane_state->uapi.crtc_h != crtc_h ||
+ !old_plane_state->uapi.fb != !fb)
+ goto slow;
+
+ new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
+ if (!new_plane_state)
+ return -ENOMEM;
+
+ new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
+ if (!new_crtc_state) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
+
+ new_plane_state->uapi.src_x = src_x;
+ new_plane_state->uapi.src_y = src_y;
+ new_plane_state->uapi.src_w = src_w;
+ new_plane_state->uapi.src_h = src_h;
+ new_plane_state->uapi.crtc_x = crtc_x;
+ new_plane_state->uapi.crtc_y = crtc_y;
+ new_plane_state->uapi.crtc_w = crtc_w;
+ new_plane_state->uapi.crtc_h = crtc_h;
+
+ intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
+
+ ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
+ old_plane_state, new_plane_state);
+ if (ret)
+ goto out_free;
+
+ ret = intel_plane_pin_fb(new_plane_state);
+ if (ret)
+ goto out_free;
+
+ intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
+ ORIGIN_FLIP);
+ intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
+ to_intel_frontbuffer(new_plane_state->hw.fb),
+ plane->frontbuffer_bit);
+
+ /* Swap plane state */
+ plane->base.state = &new_plane_state->uapi;
+
+ /*
+ * We cannot swap crtc_state as it may be in use by an atomic commit or
+ * page flip that's running simultaneously. If we swap crtc_state and
+ * destroy the old state, we will cause a use-after-free there.
+ *
+ * Only update active_planes, which is needed for our internal
+ * bookkeeping. Either value will do the right thing when updating
+ * planes atomically. If the cursor was part of the atomic update then
+ * we would have taken the slowpath.
+ */
+ crtc_state->active_planes = new_crtc_state->active_planes;
+
+ if (new_plane_state->uapi.visible)
+ intel_update_plane(plane, crtc_state, new_plane_state);
+ else
+ intel_disable_plane(plane, crtc_state);
+
+ intel_plane_unpin_fb(old_plane_state);
+
+out_free:
+ if (new_crtc_state)
+ intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
+ if (ret)
+ intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
+ else
+ intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
+ return ret;
+
+slow:
+ return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb,
+ crtc_x, crtc_y, crtc_w, crtc_h,
+ src_x, src_y, src_w, src_h, ctx);
+}
+
+static const struct drm_plane_funcs intel_cursor_plane_funcs = {
+ .update_plane = intel_legacy_cursor_update,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = intel_plane_destroy,
+ .atomic_duplicate_state = intel_plane_duplicate_state,
+ .atomic_destroy_state = intel_plane_destroy_state,
+ .format_mod_supported = intel_cursor_format_mod_supported,
+};
+
+struct intel_plane *
+intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
+{
+ struct intel_plane *cursor;
+ int ret, zpos;
+
+ cursor = intel_plane_alloc();
+ if (IS_ERR(cursor))
+ return cursor;
+
+ cursor->pipe = pipe;
+ cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
+ cursor->id = PLANE_CURSOR;
+ cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
+
+ if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+ cursor->max_stride = i845_cursor_max_stride;
+ cursor->update_plane = i845_update_cursor;
+ cursor->disable_plane = i845_disable_cursor;
+ cursor->get_hw_state = i845_cursor_get_hw_state;
+ cursor->check_plane = i845_check_cursor;
+ } else {
+ cursor->max_stride = i9xx_cursor_max_stride;
+ cursor->update_plane = i9xx_update_cursor;
+ cursor->disable_plane = i9xx_disable_cursor;
+ cursor->get_hw_state = i9xx_cursor_get_hw_state;
+ cursor->check_plane = i9xx_check_cursor;
+ }
+
+ cursor->cursor.base = ~0;
+ cursor->cursor.cntl = ~0;
+
+ if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
+ cursor->cursor.size = ~0;
+
+ ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
+ 0, &intel_cursor_plane_funcs,
+ intel_cursor_formats,
+ ARRAY_SIZE(intel_cursor_formats),
+ cursor_format_modifiers,
+ DRM_PLANE_TYPE_CURSOR,
+ "cursor %c", pipe_name(pipe));
+ if (ret)
+ goto fail;
+
+ if (INTEL_GEN(dev_priv) >= 4)
+ drm_plane_create_rotation_property(&cursor->base,
+ DRM_MODE_ROTATE_0,
+ DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_180);
+
+ zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1;
+ drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
+
+ if (INTEL_GEN(dev_priv) >= 12)
+ drm_plane_enable_fb_damage_clips(&cursor->base);
+
+ drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
+
+ return cursor;
+
+fail:
+ intel_plane_free(cursor);
+
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index c567c0cada7e..0f163c2dc621 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -2533,9 +2533,9 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
return offset_aligned;
}
-static u32 intel_plane_compute_aligned_offset(int *x, int *y,
- const struct intel_plane_state *state,
- int color_plane)
+u32 intel_plane_compute_aligned_offset(int *x, int *y,
+ const struct intel_plane_state *state,
+ int color_plane)
{
struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
@@ -3272,7 +3272,7 @@ intel_plane_remap_gtt(struct intel_plane_state *plane_state)
}
}
-static int
+int
intel_plane_compute_gtt(struct intel_plane_state *plane_state)
{
const struct intel_framebuffer *fb =
@@ -11547,569 +11547,6 @@ static bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state)
return true;
}
-static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv =
- to_i915(plane_state->uapi.plane->dev);
- const struct drm_framebuffer *fb = plane_state->hw.fb;
- const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- u32 base;
-
- if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
- base = sg_dma_address(obj->mm.pages->sgl);
- else
- base = intel_plane_ggtt_offset(plane_state);
-
- return base + plane_state->color_plane[0].offset;
-}
-
-static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
-{
- int x = plane_state->uapi.dst.x1;
- int y = plane_state->uapi.dst.y1;
- u32 pos = 0;
-
- if (x < 0) {
- pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
- x = -x;
- }
- pos |= x << CURSOR_X_SHIFT;
-
- if (y < 0) {
- pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
- y = -y;
- }
- pos |= y << CURSOR_Y_SHIFT;
-
- return pos;
-}
-
-static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
-{
- const struct drm_mode_config *config =
- &plane_state->uapi.plane->dev->mode_config;
- int width = drm_rect_width(&plane_state->uapi.dst);
- int height = drm_rect_height(&plane_state->uapi.dst);
-
- return width > 0 && width <= config->cursor_width &&
- height > 0 && height <= config->cursor_height;
-}
-
-static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv =
- to_i915(plane_state->uapi.plane->dev);
- unsigned int rotation = plane_state->hw.rotation;
- int src_x, src_y;
- u32 offset;
- int ret;
-
- ret = intel_plane_compute_gtt(plane_state);
- if (ret)
- return ret;
-
- if (!plane_state->uapi.visible)
- return 0;
-
- src_x = plane_state->uapi.src.x1 >> 16;
- src_y = plane_state->uapi.src.y1 >> 16;
-
- intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
- offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
- plane_state, 0);
-
- if (src_x != 0 || src_y != 0) {
- drm_dbg_kms(&dev_priv->drm,
- "Arbitrary cursor panning not supported\n");
- return -EINVAL;
- }
-
- /*
- * Put the final coordinates back so that the src
- * coordinate checks will see the right values.
- */
- drm_rect_translate_to(&plane_state->uapi.src,
- src_x << 16, src_y << 16);
-
- /* ILK+ do this automagically in hardware */
- if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
- const struct drm_framebuffer *fb = plane_state->hw.fb;
- int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
- int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
-
- offset += (src_h * src_w - 1) * fb->format->cpp[0];
- }
-
- plane_state->color_plane[0].offset = offset;
- plane_state->color_plane[0].x = src_x;
- plane_state->color_plane[0].y = src_y;
-
- return 0;
-}
-
-static int intel_check_cursor(struct intel_crtc_state *crtc_state,
- struct intel_plane_state *plane_state)
-{
- const struct drm_framebuffer *fb = plane_state->hw.fb;
- struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
- const struct drm_rect src = plane_state->uapi.src;
- const struct drm_rect dst = plane_state->uapi.dst;
- int ret;
-
- if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
- drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n");
- return -EINVAL;
- }
-
- ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true);
- if (ret)
- return ret;
-
- /* Use the unclipped src/dst rectangles, which we program to hw */
- plane_state->uapi.src = src;
- plane_state->uapi.dst = dst;
-
- ret = intel_cursor_check_surface(plane_state);
- if (ret)
- return ret;
-
- if (!plane_state->uapi.visible)
- return 0;
-
- ret = intel_plane_check_src_coordinates(plane_state);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static unsigned int
-i845_cursor_max_stride(struct intel_plane *plane,
- u32 pixel_format, u64 modifier,
- unsigned int rotation)
-{
- return 2048;
-}
-
-static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
-{
- u32 cntl = 0;
-
- if (crtc_state->gamma_enable)
- cntl |= CURSOR_GAMMA_ENABLE;
-
- return cntl;
-}
-
-static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
-{
- return CURSOR_ENABLE |
- CURSOR_FORMAT_ARGB |
- CURSOR_STRIDE(plane_state->color_plane[0].stride);
-}
-
-static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
-{
- int width = drm_rect_width(&plane_state->uapi.dst);
-
- /*
- * 845g/865g are only limited by the width of their cursors,
- * the height is arbitrary up to the precision of the register.
- */
- return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
-}
-
-static int i845_check_cursor(struct intel_crtc_state *crtc_state,
- struct intel_plane_state *plane_state)
-{
- const struct drm_framebuffer *fb = plane_state->hw.fb;
- struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
- int ret;
-
- ret = intel_check_cursor(crtc_state, plane_state);
- if (ret)
- return ret;
-
- /* if we want to turn off the cursor ignore width and height */
- if (!fb)
- return 0;
-
- /* Check for which cursor types we support */
- if (!i845_cursor_size_ok(plane_state)) {
- drm_dbg_kms(&i915->drm,
- "Cursor dimension %dx%d not supported\n",
- drm_rect_width(&plane_state->uapi.dst),
- drm_rect_height(&plane_state->uapi.dst));
- return -EINVAL;
- }
-
- drm_WARN_ON(&i915->drm, plane_state->uapi.visible &&
- plane_state->color_plane[0].stride != fb->pitches[0]);
-
- switch (fb->pitches[0]) {
- case 256:
- case 512:
- case 1024:
- case 2048:
- break;
- default:
- drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
- fb->pitches[0]);
- return -EINVAL;
- }
-
- plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
-
- return 0;
-}
-
-static void i845_update_cursor(struct intel_plane *plane,
- const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
- u32 cntl = 0, base = 0, pos = 0, size = 0;
- unsigned long irqflags;
-
- if (plane_state && plane_state->uapi.visible) {
- unsigned int width = drm_rect_width(&plane_state->uapi.dst);
- unsigned int height = drm_rect_height(&plane_state->uapi.dst);
-
- cntl = plane_state->ctl |
- i845_cursor_ctl_crtc(crtc_state);
-
- size = (height << 12) | width;
-
- base = intel_cursor_base(plane_state);
- pos = intel_cursor_position(plane_state);
- }
-
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- /* On these chipsets we can only modify the base/size/stride
- * whilst the cursor is disabled.
- */
- if (plane->cursor.base != base ||
- plane->cursor.size != size ||
- plane->cursor.cntl != cntl) {
- intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0);
- intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base);
- intel_de_write_fw(dev_priv, CURSIZE, size);
- intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
- intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl);
-
- plane->cursor.base = base;
- plane->cursor.size = size;
- plane->cursor.cntl = cntl;
- } else {
- intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
- }
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void i845_disable_cursor(struct intel_plane *plane,
- const struct intel_crtc_state *crtc_state)
-{
- i845_update_cursor(plane, crtc_state, NULL);
-}
-
-static bool i845_cursor_get_hw_state(struct intel_plane *plane,
- enum pipe *pipe)
-{
- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
- enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
- bool ret;
-
- power_domain = POWER_DOMAIN_PIPE(PIPE_A);
- wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
- if (!wakeref)
- return false;
-
- ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
-
- *pipe = PIPE_A;
-
- intel_display_power_put(dev_priv, power_domain, wakeref);
-
- return ret;
-}
-
-static unsigned int
-i9xx_cursor_max_stride(struct intel_plane *plane,
- u32 pixel_format, u64 modifier,
- unsigned int rotation)
-{
- return plane->base.dev->mode_config.cursor_width * 4;
-}
-
-static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
-{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- u32 cntl = 0;
-
- if (INTEL_GEN(dev_priv) >= 11)
- return cntl;
-
- if (crtc_state->gamma_enable)
- cntl = MCURSOR_GAMMA_ENABLE;
-
- if (crtc_state->csc_enable)
- cntl |= MCURSOR_PIPE_CSC_ENABLE;
-
- if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
- cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
-
- return cntl;
-}
-
-static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv =
- to_i915(plane_state->uapi.plane->dev);
- u32 cntl = 0;
-
- if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
- cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
-
- switch (drm_rect_width(&plane_state->uapi.dst)) {
- case 64:
- cntl |= MCURSOR_MODE_64_ARGB_AX;
- break;
- case 128:
- cntl |= MCURSOR_MODE_128_ARGB_AX;
- break;
- case 256:
- cntl |= MCURSOR_MODE_256_ARGB_AX;
- break;
- default:
- MISSING_CASE(drm_rect_width(&plane_state->uapi.dst));
- return 0;
- }
-
- if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
- cntl |= MCURSOR_ROTATE_180;
-
- return cntl;
-}
-
-static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv =
- to_i915(plane_state->uapi.plane->dev);
- int width = drm_rect_width(&plane_state->uapi.dst);
- int height = drm_rect_height(&plane_state->uapi.dst);
-
- if (!intel_cursor_size_ok(plane_state))
- return false;
-
- /* Cursor width is limited to a few power-of-two sizes */
- switch (width) {
- case 256:
- case 128:
- case 64:
- break;
- default:
- return false;
- }
-
- /*
- * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
- * height from 8 lines up to the cursor width, when the
- * cursor is not rotated. Everything else requires square
- * cursors.
- */
- if (HAS_CUR_FBC(dev_priv) &&
- plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
- if (height < 8 || height > width)
- return false;
- } else {
- if (height != width)
- return false;
- }
-
- return true;
-}
-
-static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
- struct intel_plane_state *plane_state)
-{
- struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
- const struct drm_framebuffer *fb = plane_state->hw.fb;
- enum pipe pipe = plane->pipe;
- int ret;
-
- ret = intel_check_cursor(crtc_state, plane_state);
- if (ret)
- return ret;
-
- /* if we want to turn off the cursor ignore width and height */
- if (!fb)
- return 0;
-
- /* Check for which cursor types we support */
- if (!i9xx_cursor_size_ok(plane_state)) {
- drm_dbg(&dev_priv->drm,
- "Cursor dimension %dx%d not supported\n",
- drm_rect_width(&plane_state->uapi.dst),
- drm_rect_height(&plane_state->uapi.dst));
- return -EINVAL;
- }
-
- drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible &&
- plane_state->color_plane[0].stride != fb->pitches[0]);
-
- if (fb->pitches[0] !=
- drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) {
- drm_dbg_kms(&dev_priv->drm,
- "Invalid cursor stride (%u) (cursor width %d)\n",
- fb->pitches[0],
- drm_rect_width(&plane_state->uapi.dst));
- return -EINVAL;
- }
-
- /*
- * There's something wrong with the cursor on CHV pipe C.
- * If it straddles the left edge of the screen then
- * moving it away from the edge or disabling it often
- * results in a pipe underrun, and often that can lead to
- * dead pipe (constant underrun reported, and it scans
- * out just a solid color). To recover from that, the
- * display power well must be turned off and on again.
- * Refuse the put the cursor into that compromised position.
- */
- if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
- plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) {
- drm_dbg_kms(&dev_priv->drm,
- "CHV cursor C not allowed to straddle the left screen edge\n");
- return -EINVAL;
- }
-
- plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
-
- return 0;
-}
-
-static void i9xx_update_cursor(struct intel_plane *plane,
- const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
- enum pipe pipe = plane->pipe;
- u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
- unsigned long irqflags;
-
- if (plane_state && plane_state->uapi.visible) {
- unsigned width = drm_rect_width(&plane_state->uapi.dst);
- unsigned height = drm_rect_height(&plane_state->uapi.dst);
-
- cntl = plane_state->ctl |
- i9xx_cursor_ctl_crtc(crtc_state);
-
- if (width != height)
- fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
-
- base = intel_cursor_base(plane_state);
- pos = intel_cursor_position(plane_state);
- }
-
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- /*
- * On some platforms writing CURCNTR first will also
- * cause CURPOS to be armed by the CURBASE write.
- * Without the CURCNTR write the CURPOS write would
- * arm itself. Thus we always update CURCNTR before
- * CURPOS.
- *
- * On other platforms CURPOS always requires the
- * CURBASE write to arm the update. Additonally
- * a write to any of the cursor register will cancel
- * an already armed cursor update. Thus leaving out
- * the CURBASE write after CURPOS could lead to a
- * cursor that doesn't appear to move, or even change
- * shape. Thus we always write CURBASE.
- *
- * The other registers are armed by by the CURBASE write
- * except when the plane is getting enabled at which time
- * the CURCNTR write arms the update.
- */
-
- if (INTEL_GEN(dev_priv) >= 9)
- skl_write_cursor_wm(plane, crtc_state);
-
- if (!needs_modeset(crtc_state))
- intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
-
- if (plane->cursor.base != base ||
- plane->cursor.size != fbc_ctl ||
- plane->cursor.cntl != cntl) {
- if (HAS_CUR_FBC(dev_priv))
- intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe),
- fbc_ctl);
- intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl);
- intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
- intel_de_write_fw(dev_priv, CURBASE(pipe), base);
-
- plane->cursor.base = base;
- plane->cursor.size = fbc_ctl;
- plane->cursor.cntl = cntl;
- } else {
- intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
- intel_de_write_fw(dev_priv, CURBASE(pipe), base);
- }
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void i9xx_disable_cursor(struct intel_plane *plane,
- const struct intel_crtc_state *crtc_state)
-{
- i9xx_update_cursor(plane, crtc_state, NULL);
-}
-
-static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
- enum pipe *pipe)
-{
- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
- enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
- bool ret;
- u32 val;
-
- /*
- * Not 100% correct for planes that can move between pipes,
- * but that's only the case for gen2-3 which don't have any
- * display power wells.
- */
- power_domain = POWER_DOMAIN_PIPE(plane->pipe);
- wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
- if (!wakeref)
- return false;
-
- val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
-
- ret = val & MCURSOR_MODE;
-
- if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
- *pipe = plane->pipe;
- else
- *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
- MCURSOR_PIPE_SELECT_SHIFT;
-
- intel_display_power_put(dev_priv, power_domain, wakeref);
-
- return ret;
-}
-
/* VESA 640x480x72Hz mode to set on the pipe */
static const struct drm_display_mode load_detect_mode = {
DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
@@ -16620,7 +16057,7 @@ static void add_rps_boost_after_vblank(struct drm_crtc *crtc,
add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait);
}
-static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
+int intel_plane_pin_fb(struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
@@ -16650,7 +16087,7 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
return 0;
}
-static void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
+void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
{
struct i915_vma *vma;
@@ -16886,13 +16323,6 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
}
}
-static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
- u32 format, u64 modifier)
-{
- return modifier == DRM_FORMAT_MOD_LINEAR &&
- format == DRM_FORMAT_ARGB8888;
-}
-
static const struct drm_plane_funcs i965_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@@ -16911,142 +16341,6 @@ static const struct drm_plane_funcs i8xx_plane_funcs = {
.format_mod_supported = i8xx_plane_format_mod_supported,
};
-static int
-intel_legacy_cursor_update(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,
- u32 src_x, u32 src_y,
- u32 src_w, u32 src_h,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct intel_plane *plane = to_intel_plane(_plane);
- struct intel_crtc *crtc = to_intel_crtc(_crtc);
- struct intel_plane_state *old_plane_state =
- to_intel_plane_state(plane->base.state);
- struct intel_plane_state *new_plane_state;
- struct intel_crtc_state *crtc_state =
- to_intel_crtc_state(crtc->base.state);
- struct intel_crtc_state *new_crtc_state;
- int ret;
-
- /*
- * When crtc is inactive or there is a modeset pending,
- * wait for it to complete in the slowpath
- *
- * FIXME bigjoiner fastpath would be good
- */
- if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
- crtc_state->update_pipe || crtc_state->bigjoiner)
- goto slow;
-
- /*
- * Don't do an async update if there is an outstanding commit modifying
- * the plane. This prevents our async update's changes from getting
- * overridden by a previous synchronous update's state.
- */
- if (old_plane_state->uapi.commit &&
- !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
- goto slow;
-
- /*
- * If any parameters change that may affect watermarks,
- * take the slowpath. Only changing fb or position should be
- * in the fastpath.
- */
- if (old_plane_state->uapi.crtc != &crtc->base ||
- old_plane_state->uapi.src_w != src_w ||
- old_plane_state->uapi.src_h != src_h ||
- old_plane_state->uapi.crtc_w != crtc_w ||
- old_plane_state->uapi.crtc_h != crtc_h ||
- !old_plane_state->uapi.fb != !fb)
- goto slow;
-
- new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
- if (!new_plane_state)
- return -ENOMEM;
-
- new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
- if (!new_crtc_state) {
- ret = -ENOMEM;
- goto out_free;
- }
-
- drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
-
- new_plane_state->uapi.src_x = src_x;
- new_plane_state->uapi.src_y = src_y;
- new_plane_state->uapi.src_w = src_w;
- new_plane_state->uapi.src_h = src_h;
- new_plane_state->uapi.crtc_x = crtc_x;
- new_plane_state->uapi.crtc_y = crtc_y;
- new_plane_state->uapi.crtc_w = crtc_w;
- new_plane_state->uapi.crtc_h = crtc_h;
-
- intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
-
- ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
- old_plane_state, new_plane_state);
- if (ret)
- goto out_free;
-
- ret = intel_plane_pin_fb(new_plane_state);
- if (ret)
- goto out_free;
-
- intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
- ORIGIN_FLIP);
- intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
- to_intel_frontbuffer(new_plane_state->hw.fb),
- plane->frontbuffer_bit);
-
- /* Swap plane state */
- plane->base.state = &new_plane_state->uapi;
-
- /*
- * We cannot swap crtc_state as it may be in use by an atomic commit or
- * page flip that's running simultaneously. If we swap crtc_state and
- * destroy the old state, we will cause a use-after-free there.
- *
- * Only update active_planes, which is needed for our internal
- * bookkeeping. Either value will do the right thing when updating
- * planes atomically. If the cursor was part of the atomic update then
- * we would have taken the slowpath.
- */
- crtc_state->active_planes = new_crtc_state->active_planes;
-
- if (new_plane_state->uapi.visible)
- intel_update_plane(plane, crtc_state, new_plane_state);
- else
- intel_disable_plane(plane, crtc_state);
-
- intel_plane_unpin_fb(old_plane_state);
-
-out_free:
- if (new_crtc_state)
- intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
- if (ret)
- intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
- else
- intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
- return ret;
-
-slow:
- return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb,
- crtc_x, crtc_y, crtc_w, crtc_h,
- src_x, src_y, src_w, src_h, ctx);
-}
-
-static const struct drm_plane_funcs intel_cursor_plane_funcs = {
- .update_plane = intel_legacy_cursor_update,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
- .atomic_duplicate_state = intel_plane_duplicate_state,
- .atomic_destroy_state = intel_plane_destroy_state,
- .format_mod_supported = intel_cursor_format_mod_supported,
-};
-
static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
enum i9xx_plane_id i9xx_plane)
{
@@ -17198,74 +16492,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
return ERR_PTR(ret);
}
-static struct intel_plane *
-intel_cursor_plane_create(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- struct intel_plane *cursor;
- int ret, zpos;
-
- cursor = intel_plane_alloc();
- if (IS_ERR(cursor))
- return cursor;
-
- cursor->pipe = pipe;
- cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
- cursor->id = PLANE_CURSOR;
- cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
-
- if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
- cursor->max_stride = i845_cursor_max_stride;
- cursor->update_plane = i845_update_cursor;
- cursor->disable_plane = i845_disable_cursor;
- cursor->get_hw_state = i845_cursor_get_hw_state;
- cursor->check_plane = i845_check_cursor;
- } else {
- cursor->max_stride = i9xx_cursor_max_stride;
- cursor->update_plane = i9xx_update_cursor;
- cursor->disable_plane = i9xx_disable_cursor;
- cursor->get_hw_state = i9xx_cursor_get_hw_state;
- cursor->check_plane = i9xx_check_cursor;
- }
-
- cursor->cursor.base = ~0;
- cursor->cursor.cntl = ~0;
-
- if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
- cursor->cursor.size = ~0;
-
- ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
- 0, &intel_cursor_plane_funcs,
- intel_cursor_formats,
- ARRAY_SIZE(intel_cursor_formats),
- cursor_format_modifiers,
- DRM_PLANE_TYPE_CURSOR,
- "cursor %c", pipe_name(pipe));
- if (ret)
- goto fail;
-
- if (INTEL_GEN(dev_priv) >= 4)
- drm_plane_create_rotation_property(&cursor->base,
- DRM_MODE_ROTATE_0,
- DRM_MODE_ROTATE_0 |
- DRM_MODE_ROTATE_180);
-
- zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1;
- drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
-
- if (INTEL_GEN(dev_priv) >= 12)
- drm_plane_enable_fb_damage_clips(&cursor->base);
-
- drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
-
- return cursor;
-
-fail:
- intel_plane_free(cursor);
-
- return ERR_PTR(ret);
-}
-
static int intel_crtc_late_register(struct drm_crtc *crtc)
{
intel_crtc_debugfs_add(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index a5771bfecba6..f0a5bf69656f 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -647,6 +647,18 @@ bool
intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
uint64_t modifier);
+int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
+u32 intel_plane_compute_aligned_offset(int *x, int *y,
+ const struct intel_plane_state *state,
+ int color_plane);
+int intel_plane_pin_fb(struct intel_plane_state *plane_state);
+void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
+
+/* cursor */
+struct intel_plane *
+intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+ enum pipe pipe);
+
/* modesetting */
void intel_modeset_init_hw(struct drm_i915_private *i915);
int intel_modeset_init_noirq(struct drm_i915_private *i915);
--
2.27.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 5+ messages in thread* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: refactor cursor code out of i915_display.c 2020-12-09 0:51 [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c Dave Airlie @ 2020-12-09 1:05 ` Patchwork 2020-12-09 1:37 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork 2020-12-09 11:48 ` [Intel-gfx] [PATCH] " Ville Syrjälä 2 siblings, 0 replies; 5+ messages in thread From: Patchwork @ 2020-12-09 1:05 UTC (permalink / raw) To: Dave Airlie; +Cc: intel-gfx == Series Details == Series: drm/i915: refactor cursor code out of i915_display.c URL : https://patchwork.freedesktop.org/series/84707/ State : warning == Summary == $ dim checkpatch origin/drm-tip c5d8edc678f0 drm/i915: refactor cursor code out of i915_display.c -:24: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating? #24: new file mode 100644 -:29: WARNING:SPDX_LICENSE_TAG: Missing or malformed SPDX-License-Identifier tag in line 1 #29: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:1: +/* -:554: WARNING:UNSPECIFIED_INT: Prefer 'unsigned int' to bare use of 'unsigned' #554: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:526: + unsigned width = drm_rect_width(&plane_state->uapi.dst); -:555: WARNING:UNSPECIFIED_INT: Prefer 'unsigned int' to bare use of 'unsigned' #555: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:527: + unsigned height = drm_rect_height(&plane_state->uapi.dst); -:584: WARNING:REPEATED_WORD: Possible repeated word: 'by' #584: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:556: + * The other registers are armed by by the CURBASE write -:811: CHECK:SPACING: No space is necessary after a cast #811: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:783: + cursor->i9xx_plane = (enum i9xx_plane_id) pipe; total: 0 errors, 5 warnings, 1 checks, 1696 lines checked _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 5+ messages in thread
* [Intel-gfx] ✗ Fi.CI.BAT: failure for drm/i915: refactor cursor code out of i915_display.c 2020-12-09 0:51 [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c Dave Airlie 2020-12-09 1:05 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for " Patchwork @ 2020-12-09 1:37 ` Patchwork 2020-12-09 11:48 ` [Intel-gfx] [PATCH] " Ville Syrjälä 2 siblings, 0 replies; 5+ messages in thread From: Patchwork @ 2020-12-09 1:37 UTC (permalink / raw) To: Dave Airlie; +Cc: intel-gfx [-- Attachment #1.1: Type: text/plain, Size: 4916 bytes --] == Series Details == Series: drm/i915: refactor cursor code out of i915_display.c URL : https://patchwork.freedesktop.org/series/84707/ State : failure == Summary == CI Bug Log - changes from CI_DRM_9463 -> Patchwork_19084 ==================================================== Summary ------- **FAILURE** Serious unknown changes coming with Patchwork_19084 absolutely need to be verified manually. If you think the reported changes have nothing to do with the changes introduced in Patchwork_19084, please notify your bug team to allow them to document this new failure mode, which will reduce false positives in CI. External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/index.html Possible new issues ------------------- Here are the unknown changes that may have been introduced in Patchwork_19084: ### IGT changes ### #### Possible regressions #### * igt@gem_exec_suspend@basic-s3: - fi-snb-2600: [PASS][1] -> [DMESG-WARN][2] [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-snb-2600/igt@gem_exec_suspend@basic-s3.html [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-snb-2600/igt@gem_exec_suspend@basic-s3.html New tests --------- New tests have been introduced between CI_DRM_9463 and Patchwork_19084: ### New CI tests (1) ### * boot: - Statuses : 1 fail(s) 39 pass(s) - Exec time: [0.0] s Known issues ------------ Here are the changes found in Patchwork_19084 that come from known issues: ### IGT changes ### #### Issues hit #### * igt@amdgpu/amd_basic@semaphore: - fi-icl-y: NOTRUN -> [SKIP][3] ([fdo#109315]) +17 similar issues [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-icl-y/igt@amdgpu/amd_basic@semaphore.html * igt@gem_exec_suspend@basic-s0: - fi-tgl-u2: [PASS][4] -> [FAIL][5] ([i915#1888]) [4]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-tgl-u2/igt@gem_exec_suspend@basic-s0.html [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-tgl-u2/igt@gem_exec_suspend@basic-s0.html * igt@i915_getparams_basic@basic-subslice-total: - fi-tgl-y: [PASS][6] -> [DMESG-WARN][7] ([i915#402]) +2 similar issues [6]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-tgl-y/igt@i915_getparams_basic@basic-subslice-total.html [7]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-tgl-y/igt@i915_getparams_basic@basic-subslice-total.html * igt@i915_pm_rpm@module-reload: - fi-kbl-guc: [PASS][8] -> [FAIL][9] ([i915#138]) [8]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-kbl-guc/igt@i915_pm_rpm@module-reload.html [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-kbl-guc/igt@i915_pm_rpm@module-reload.html * igt@runner@aborted: - fi-snb-2600: NOTRUN -> [FAIL][10] ([i915#698]) [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-snb-2600/igt@runner@aborted.html #### Possible fixes #### * igt@gem_flink_basic@double-flink: - fi-tgl-y: [DMESG-WARN][11] ([i915#402]) -> [PASS][12] +1 similar issue [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-tgl-y/igt@gem_flink_basic@double-flink.html [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-tgl-y/igt@gem_flink_basic@double-flink.html * igt@i915_selftest@live@execlists: - fi-icl-y: [INCOMPLETE][13] ([i915#1037] / [i915#2276]) -> [PASS][14] [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-icl-y/igt@i915_selftest@live@execlists.html [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/fi-icl-y/igt@i915_selftest@live@execlists.html [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315 [i915#1037]: https://gitlab.freedesktop.org/drm/intel/issues/1037 [i915#138]: https://gitlab.freedesktop.org/drm/intel/issues/138 [i915#1888]: https://gitlab.freedesktop.org/drm/intel/issues/1888 [i915#2276]: https://gitlab.freedesktop.org/drm/intel/issues/2276 [i915#402]: https://gitlab.freedesktop.org/drm/intel/issues/402 [i915#698]: https://gitlab.freedesktop.org/drm/intel/issues/698 Participating hosts (43 -> 40) ------------------------------ Missing (3): fi-ilk-m540 fi-bdw-samus fi-hsw-4200u Build changes ------------- * Linux: CI_DRM_9463 -> Patchwork_19084 CI-20190529: 20190529 CI_DRM_9463: 1c64d5d72bcd4e6ccf2d0ba6e6ab3644497846b5 @ git://anongit.freedesktop.org/gfx-ci/linux IGT_5885: d99f644b1868b9c92435b05ebfafa230721cd677 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools Patchwork_19084: c5d8edc678f0283d6fdc7cd6e82bc0378c299b2c @ git://anongit.freedesktop.org/gfx-ci/linux == Linux commits == c5d8edc678f0 drm/i915: refactor cursor code out of i915_display.c == Logs == For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19084/index.html [-- Attachment #1.2: Type: text/html, Size: 5822 bytes --] [-- Attachment #2: Type: text/plain, Size: 160 bytes --] _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c 2020-12-09 0:51 [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c Dave Airlie 2020-12-09 1:05 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for " Patchwork 2020-12-09 1:37 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork @ 2020-12-09 11:48 ` Ville Syrjälä 2020-12-10 0:10 ` Dave Airlie 2 siblings, 1 reply; 5+ messages in thread From: Ville Syrjälä @ 2020-12-09 11:48 UTC (permalink / raw) To: Dave Airlie; +Cc: intel-gfx On Wed, Dec 09, 2020 at 10:51:52AM +1000, Dave Airlie wrote: > From: Dave Airlie <airlied@redhat.com> > > This file is a monster, let's start simple, the cursor plane code > seems pretty standalone, and splits out easily enough. Is this different from https://patchwork.freedesktop.org/series/83704/ ? > > Signed-off-by: Dave Airlie <airlied@redhat.com> > --- > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/display/intel_cursor.c | 837 +++++++++++++++++++ > drivers/gpu/drm/i915/display/intel_display.c | 786 +---------------- > drivers/gpu/drm/i915/display/intel_display.h | 12 + > 4 files changed, 856 insertions(+), 780 deletions(-) > create mode 100644 drivers/gpu/drm/i915/display/intel_cursor.c > > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile > index e5574e506a5c..98a35b939052 100644 > --- a/drivers/gpu/drm/i915/Makefile > +++ b/drivers/gpu/drm/i915/Makefile > @@ -197,6 +197,7 @@ i915-y += \ > display/intel_combo_phy.o \ > display/intel_connector.o \ > display/intel_csr.o \ > + display/intel_cursor.o \ > display/intel_display.o \ > display/intel_display_power.o \ > display/intel_dpio_phy.o \ > diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c > new file mode 100644 > index 000000000000..d50e712f9113 > --- /dev/null > +++ b/drivers/gpu/drm/i915/display/intel_cursor.c > @@ -0,0 +1,837 @@ > +/* > + * Copyright © 2006-2007 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + * > + */ > + > +#include <linux/kernel.h> > + > +#include <drm/drm_atomic_helper.h> > +#include <drm/drm_atomic_uapi.h> > +#include <drm/drm_damage_helper.h> > +#include <drm/drm_plane_helper.h> > +#include <drm/drm_fourcc.h> > + > +#include "intel_atomic.h" > +#include "intel_atomic_plane.h" > +#include "intel_display_types.h" > +#include "intel_display.h" > + > +#include "intel_frontbuffer.h" > +#include "intel_pm.h" > +#include "intel_psr.h" > +#include "intel_sprite.h" > + > +/* Cursor formats */ > +static const u32 intel_cursor_formats[] = { > + DRM_FORMAT_ARGB8888, > +}; > + > +static const u64 cursor_format_modifiers[] = { > + DRM_FORMAT_MOD_LINEAR, > + DRM_FORMAT_MOD_INVALID > +}; > + > +static bool > +needs_modeset(const struct intel_crtc_state *state) > +{ > + return drm_atomic_crtc_needs_modeset(&state->uapi); > +} > + > +static struct intel_frontbuffer * > +to_intel_frontbuffer(struct drm_framebuffer *fb) > +{ > + return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL; > +} > + > +static u32 intel_cursor_base(const struct intel_plane_state *plane_state) > +{ > + struct drm_i915_private *dev_priv = > + to_i915(plane_state->uapi.plane->dev); > + const struct drm_framebuffer *fb = plane_state->hw.fb; > + const struct drm_i915_gem_object *obj = intel_fb_obj(fb); > + u32 base; > + > + if (INTEL_INFO(dev_priv)->display.cursor_needs_physical) > + base = sg_dma_address(obj->mm.pages->sgl); > + else > + base = intel_plane_ggtt_offset(plane_state); > + > + return base + plane_state->color_plane[0].offset; > +} > + > +static u32 intel_cursor_position(const struct intel_plane_state *plane_state) > +{ > + int x = plane_state->uapi.dst.x1; > + int y = plane_state->uapi.dst.y1; > + u32 pos = 0; > + > + if (x < 0) { > + pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; > + x = -x; > + } > + pos |= x << CURSOR_X_SHIFT; > + > + if (y < 0) { > + pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; > + y = -y; > + } > + pos |= y << CURSOR_Y_SHIFT; > + > + return pos; > +} > + > +static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state) > +{ > + const struct drm_mode_config *config = > + &plane_state->uapi.plane->dev->mode_config; > + int width = drm_rect_width(&plane_state->uapi.dst); > + int height = drm_rect_height(&plane_state->uapi.dst); > + > + return width > 0 && width <= config->cursor_width && > + height > 0 && height <= config->cursor_height; > +} > + > +static int intel_cursor_check_surface(struct intel_plane_state *plane_state) > +{ > + struct drm_i915_private *dev_priv = > + to_i915(plane_state->uapi.plane->dev); > + unsigned int rotation = plane_state->hw.rotation; > + int src_x, src_y; > + u32 offset; > + int ret; > + > + ret = intel_plane_compute_gtt(plane_state); > + if (ret) > + return ret; > + > + if (!plane_state->uapi.visible) > + return 0; > + > + src_x = plane_state->uapi.src.x1 >> 16; > + src_y = plane_state->uapi.src.y1 >> 16; > + > + intel_add_fb_offsets(&src_x, &src_y, plane_state, 0); > + offset = intel_plane_compute_aligned_offset(&src_x, &src_y, > + plane_state, 0); > + > + if (src_x != 0 || src_y != 0) { > + drm_dbg_kms(&dev_priv->drm, > + "Arbitrary cursor panning not supported\n"); > + return -EINVAL; > + } > + > + /* > + * Put the final coordinates back so that the src > + * coordinate checks will see the right values. > + */ > + drm_rect_translate_to(&plane_state->uapi.src, > + src_x << 16, src_y << 16); > + > + /* ILK+ do this automagically in hardware */ > + if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) { > + const struct drm_framebuffer *fb = plane_state->hw.fb; > + int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; > + int src_h = drm_rect_height(&plane_state->uapi.src) >> 16; > + > + offset += (src_h * src_w - 1) * fb->format->cpp[0]; > + } > + > + plane_state->color_plane[0].offset = offset; > + plane_state->color_plane[0].x = src_x; > + plane_state->color_plane[0].y = src_y; > + > + return 0; > +} > + > +static int intel_check_cursor(struct intel_crtc_state *crtc_state, > + struct intel_plane_state *plane_state) > +{ > + const struct drm_framebuffer *fb = plane_state->hw.fb; > + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); > + const struct drm_rect src = plane_state->uapi.src; > + const struct drm_rect dst = plane_state->uapi.dst; > + int ret; > + > + if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) { > + drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n"); > + return -EINVAL; > + } > + > + ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, > + DRM_PLANE_HELPER_NO_SCALING, > + DRM_PLANE_HELPER_NO_SCALING, > + true); > + if (ret) > + return ret; > + > + /* Use the unclipped src/dst rectangles, which we program to hw */ > + plane_state->uapi.src = src; > + plane_state->uapi.dst = dst; > + > + ret = intel_cursor_check_surface(plane_state); > + if (ret) > + return ret; > + > + if (!plane_state->uapi.visible) > + return 0; > + > + ret = intel_plane_check_src_coordinates(plane_state); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static unsigned int > +i845_cursor_max_stride(struct intel_plane *plane, > + u32 pixel_format, u64 modifier, > + unsigned int rotation) > +{ > + return 2048; > +} > + > +static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state) > +{ > + u32 cntl = 0; > + > + if (crtc_state->gamma_enable) > + cntl |= CURSOR_GAMMA_ENABLE; > + > + return cntl; > +} > + > +static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, > + const struct intel_plane_state *plane_state) > +{ > + return CURSOR_ENABLE | > + CURSOR_FORMAT_ARGB | > + CURSOR_STRIDE(plane_state->color_plane[0].stride); > +} > + > +static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state) > +{ > + int width = drm_rect_width(&plane_state->uapi.dst); > + > + /* > + * 845g/865g are only limited by the width of their cursors, > + * the height is arbitrary up to the precision of the register. > + */ > + return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64); > +} > + > +static int i845_check_cursor(struct intel_crtc_state *crtc_state, > + struct intel_plane_state *plane_state) > +{ > + const struct drm_framebuffer *fb = plane_state->hw.fb; > + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); > + int ret; > + > + ret = intel_check_cursor(crtc_state, plane_state); > + if (ret) > + return ret; > + > + /* if we want to turn off the cursor ignore width and height */ > + if (!fb) > + return 0; > + > + /* Check for which cursor types we support */ > + if (!i845_cursor_size_ok(plane_state)) { > + drm_dbg_kms(&i915->drm, > + "Cursor dimension %dx%d not supported\n", > + drm_rect_width(&plane_state->uapi.dst), > + drm_rect_height(&plane_state->uapi.dst)); > + return -EINVAL; > + } > + > + drm_WARN_ON(&i915->drm, plane_state->uapi.visible && > + plane_state->color_plane[0].stride != fb->pitches[0]); > + > + switch (fb->pitches[0]) { > + case 256: > + case 512: > + case 1024: > + case 2048: > + break; > + default: > + drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n", > + fb->pitches[0]); > + return -EINVAL; > + } > + > + plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state); > + > + return 0; > +} > + > +static void i845_update_cursor(struct intel_plane *plane, > + const struct intel_crtc_state *crtc_state, > + const struct intel_plane_state *plane_state) > +{ > + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > + u32 cntl = 0, base = 0, pos = 0, size = 0; > + unsigned long irqflags; > + > + if (plane_state && plane_state->uapi.visible) { > + unsigned int width = drm_rect_width(&plane_state->uapi.dst); > + unsigned int height = drm_rect_height(&plane_state->uapi.dst); > + > + cntl = plane_state->ctl | > + i845_cursor_ctl_crtc(crtc_state); > + > + size = (height << 12) | width; > + > + base = intel_cursor_base(plane_state); > + pos = intel_cursor_position(plane_state); > + } > + > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > + > + /* On these chipsets we can only modify the base/size/stride > + * whilst the cursor is disabled. > + */ > + if (plane->cursor.base != base || > + plane->cursor.size != size || > + plane->cursor.cntl != cntl) { > + intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0); > + intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base); > + intel_de_write_fw(dev_priv, CURSIZE, size); > + intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos); > + intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl); > + > + plane->cursor.base = base; > + plane->cursor.size = size; > + plane->cursor.cntl = cntl; > + } else { > + intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos); > + } > + > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > +} > + > +static void i845_disable_cursor(struct intel_plane *plane, > + const struct intel_crtc_state *crtc_state) > +{ > + i845_update_cursor(plane, crtc_state, NULL); > +} > + > +static bool i845_cursor_get_hw_state(struct intel_plane *plane, > + enum pipe *pipe) > +{ > + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > + enum intel_display_power_domain power_domain; > + intel_wakeref_t wakeref; > + bool ret; > + > + power_domain = POWER_DOMAIN_PIPE(PIPE_A); > + wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); > + if (!wakeref) > + return false; > + > + ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE; > + > + *pipe = PIPE_A; > + > + intel_display_power_put(dev_priv, power_domain, wakeref); > + > + return ret; > +} > + > +static unsigned int > +i9xx_cursor_max_stride(struct intel_plane *plane, > + u32 pixel_format, u64 modifier, > + unsigned int rotation) > +{ > + return plane->base.dev->mode_config.cursor_width * 4; > +} > + > +static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > + u32 cntl = 0; > + > + if (INTEL_GEN(dev_priv) >= 11) > + return cntl; > + > + if (crtc_state->gamma_enable) > + cntl = MCURSOR_GAMMA_ENABLE; > + > + if (crtc_state->csc_enable) > + cntl |= MCURSOR_PIPE_CSC_ENABLE; > + > + if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) > + cntl |= MCURSOR_PIPE_SELECT(crtc->pipe); > + > + return cntl; > +} > + > +static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, > + const struct intel_plane_state *plane_state) > +{ > + struct drm_i915_private *dev_priv = > + to_i915(plane_state->uapi.plane->dev); > + u32 cntl = 0; > + > + if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) > + cntl |= MCURSOR_TRICKLE_FEED_DISABLE; > + > + switch (drm_rect_width(&plane_state->uapi.dst)) { > + case 64: > + cntl |= MCURSOR_MODE_64_ARGB_AX; > + break; > + case 128: > + cntl |= MCURSOR_MODE_128_ARGB_AX; > + break; > + case 256: > + cntl |= MCURSOR_MODE_256_ARGB_AX; > + break; > + default: > + MISSING_CASE(drm_rect_width(&plane_state->uapi.dst)); > + return 0; > + } > + > + if (plane_state->hw.rotation & DRM_MODE_ROTATE_180) > + cntl |= MCURSOR_ROTATE_180; > + > + return cntl; > +} > + > +static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state) > +{ > + struct drm_i915_private *dev_priv = > + to_i915(plane_state->uapi.plane->dev); > + int width = drm_rect_width(&plane_state->uapi.dst); > + int height = drm_rect_height(&plane_state->uapi.dst); > + > + if (!intel_cursor_size_ok(plane_state)) > + return false; > + > + /* Cursor width is limited to a few power-of-two sizes */ > + switch (width) { > + case 256: > + case 128: > + case 64: > + break; > + default: > + return false; > + } > + > + /* > + * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor > + * height from 8 lines up to the cursor width, when the > + * cursor is not rotated. Everything else requires square > + * cursors. > + */ > + if (HAS_CUR_FBC(dev_priv) && > + plane_state->hw.rotation & DRM_MODE_ROTATE_0) { > + if (height < 8 || height > width) > + return false; > + } else { > + if (height != width) > + return false; > + } > + > + return true; > +} > + > +static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, > + struct intel_plane_state *plane_state) > +{ > + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); > + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > + const struct drm_framebuffer *fb = plane_state->hw.fb; > + enum pipe pipe = plane->pipe; > + int ret; > + > + ret = intel_check_cursor(crtc_state, plane_state); > + if (ret) > + return ret; > + > + /* if we want to turn off the cursor ignore width and height */ > + if (!fb) > + return 0; > + > + /* Check for which cursor types we support */ > + if (!i9xx_cursor_size_ok(plane_state)) { > + drm_dbg(&dev_priv->drm, > + "Cursor dimension %dx%d not supported\n", > + drm_rect_width(&plane_state->uapi.dst), > + drm_rect_height(&plane_state->uapi.dst)); > + return -EINVAL; > + } > + > + drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible && > + plane_state->color_plane[0].stride != fb->pitches[0]); > + > + if (fb->pitches[0] != > + drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) { > + drm_dbg_kms(&dev_priv->drm, > + "Invalid cursor stride (%u) (cursor width %d)\n", > + fb->pitches[0], > + drm_rect_width(&plane_state->uapi.dst)); > + return -EINVAL; > + } > + > + /* > + * There's something wrong with the cursor on CHV pipe C. > + * If it straddles the left edge of the screen then > + * moving it away from the edge or disabling it often > + * results in a pipe underrun, and often that can lead to > + * dead pipe (constant underrun reported, and it scans > + * out just a solid color). To recover from that, the > + * display power well must be turned off and on again. > + * Refuse the put the cursor into that compromised position. > + */ > + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C && > + plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) { > + drm_dbg_kms(&dev_priv->drm, > + "CHV cursor C not allowed to straddle the left screen edge\n"); > + return -EINVAL; > + } > + > + plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state); > + > + return 0; > +} > + > +static void i9xx_update_cursor(struct intel_plane *plane, > + const struct intel_crtc_state *crtc_state, > + const struct intel_plane_state *plane_state) > +{ > + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > + enum pipe pipe = plane->pipe; > + u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0; > + unsigned long irqflags; > + > + if (plane_state && plane_state->uapi.visible) { > + unsigned width = drm_rect_width(&plane_state->uapi.dst); > + unsigned height = drm_rect_height(&plane_state->uapi.dst); > + > + cntl = plane_state->ctl | > + i9xx_cursor_ctl_crtc(crtc_state); > + > + if (width != height) > + fbc_ctl = CUR_FBC_CTL_EN | (height - 1); > + > + base = intel_cursor_base(plane_state); > + pos = intel_cursor_position(plane_state); > + } > + > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > + > + /* > + * On some platforms writing CURCNTR first will also > + * cause CURPOS to be armed by the CURBASE write. > + * Without the CURCNTR write the CURPOS write would > + * arm itself. Thus we always update CURCNTR before > + * CURPOS. > + * > + * On other platforms CURPOS always requires the > + * CURBASE write to arm the update. Additonally > + * a write to any of the cursor register will cancel > + * an already armed cursor update. Thus leaving out > + * the CURBASE write after CURPOS could lead to a > + * cursor that doesn't appear to move, or even change > + * shape. Thus we always write CURBASE. > + * > + * The other registers are armed by by the CURBASE write > + * except when the plane is getting enabled at which time > + * the CURCNTR write arms the update. > + */ > + > + if (INTEL_GEN(dev_priv) >= 9) > + skl_write_cursor_wm(plane, crtc_state); > + > + if (!needs_modeset(crtc_state)) > + intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0); > + > + if (plane->cursor.base != base || > + plane->cursor.size != fbc_ctl || > + plane->cursor.cntl != cntl) { > + if (HAS_CUR_FBC(dev_priv)) > + intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe), > + fbc_ctl); > + intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl); > + intel_de_write_fw(dev_priv, CURPOS(pipe), pos); > + intel_de_write_fw(dev_priv, CURBASE(pipe), base); > + > + plane->cursor.base = base; > + plane->cursor.size = fbc_ctl; > + plane->cursor.cntl = cntl; > + } else { > + intel_de_write_fw(dev_priv, CURPOS(pipe), pos); > + intel_de_write_fw(dev_priv, CURBASE(pipe), base); > + } > + > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > +} > + > +static void i9xx_disable_cursor(struct intel_plane *plane, > + const struct intel_crtc_state *crtc_state) > +{ > + i9xx_update_cursor(plane, crtc_state, NULL); > +} > + > +static bool i9xx_cursor_get_hw_state(struct intel_plane *plane, > + enum pipe *pipe) > +{ > + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > + enum intel_display_power_domain power_domain; > + intel_wakeref_t wakeref; > + bool ret; > + u32 val; > + > + /* > + * Not 100% correct for planes that can move between pipes, > + * but that's only the case for gen2-3 which don't have any > + * display power wells. > + */ > + power_domain = POWER_DOMAIN_PIPE(plane->pipe); > + wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); > + if (!wakeref) > + return false; > + > + val = intel_de_read(dev_priv, CURCNTR(plane->pipe)); > + > + ret = val & MCURSOR_MODE; > + > + if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) > + *pipe = plane->pipe; > + else > + *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >> > + MCURSOR_PIPE_SELECT_SHIFT; > + > + intel_display_power_put(dev_priv, power_domain, wakeref); > + > + return ret; > +} > + > +static bool intel_cursor_format_mod_supported(struct drm_plane *_plane, > + u32 format, u64 modifier) > +{ > + return modifier == DRM_FORMAT_MOD_LINEAR && > + format == DRM_FORMAT_ARGB8888; > +} > + > +static int > +intel_legacy_cursor_update(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, > + u32 src_x, u32 src_y, > + u32 src_w, u32 src_h, > + struct drm_modeset_acquire_ctx *ctx) > +{ > + struct intel_plane *plane = to_intel_plane(_plane); > + struct intel_crtc *crtc = to_intel_crtc(_crtc); > + struct intel_plane_state *old_plane_state = > + to_intel_plane_state(plane->base.state); > + struct intel_plane_state *new_plane_state; > + struct intel_crtc_state *crtc_state = > + to_intel_crtc_state(crtc->base.state); > + struct intel_crtc_state *new_crtc_state; > + int ret; > + > + /* > + * When crtc is inactive or there is a modeset pending, > + * wait for it to complete in the slowpath > + * > + * FIXME bigjoiner fastpath would be good > + */ > + if (!crtc_state->hw.active || needs_modeset(crtc_state) || > + crtc_state->update_pipe || crtc_state->bigjoiner) > + goto slow; > + > + /* > + * Don't do an async update if there is an outstanding commit modifying > + * the plane. This prevents our async update's changes from getting > + * overridden by a previous synchronous update's state. > + */ > + if (old_plane_state->uapi.commit && > + !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done)) > + goto slow; > + > + /* > + * If any parameters change that may affect watermarks, > + * take the slowpath. Only changing fb or position should be > + * in the fastpath. > + */ > + if (old_plane_state->uapi.crtc != &crtc->base || > + old_plane_state->uapi.src_w != src_w || > + old_plane_state->uapi.src_h != src_h || > + old_plane_state->uapi.crtc_w != crtc_w || > + old_plane_state->uapi.crtc_h != crtc_h || > + !old_plane_state->uapi.fb != !fb) > + goto slow; > + > + new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base)); > + if (!new_plane_state) > + return -ENOMEM; > + > + new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base)); > + if (!new_crtc_state) { > + ret = -ENOMEM; > + goto out_free; > + } > + > + drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb); > + > + new_plane_state->uapi.src_x = src_x; > + new_plane_state->uapi.src_y = src_y; > + new_plane_state->uapi.src_w = src_w; > + new_plane_state->uapi.src_h = src_h; > + new_plane_state->uapi.crtc_x = crtc_x; > + new_plane_state->uapi.crtc_y = crtc_y; > + new_plane_state->uapi.crtc_w = crtc_w; > + new_plane_state->uapi.crtc_h = crtc_h; > + > + intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc); > + > + ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state, > + old_plane_state, new_plane_state); > + if (ret) > + goto out_free; > + > + ret = intel_plane_pin_fb(new_plane_state); > + if (ret) > + goto out_free; > + > + intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb), > + ORIGIN_FLIP); > + intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb), > + to_intel_frontbuffer(new_plane_state->hw.fb), > + plane->frontbuffer_bit); > + > + /* Swap plane state */ > + plane->base.state = &new_plane_state->uapi; > + > + /* > + * We cannot swap crtc_state as it may be in use by an atomic commit or > + * page flip that's running simultaneously. If we swap crtc_state and > + * destroy the old state, we will cause a use-after-free there. > + * > + * Only update active_planes, which is needed for our internal > + * bookkeeping. Either value will do the right thing when updating > + * planes atomically. If the cursor was part of the atomic update then > + * we would have taken the slowpath. > + */ > + crtc_state->active_planes = new_crtc_state->active_planes; > + > + if (new_plane_state->uapi.visible) > + intel_update_plane(plane, crtc_state, new_plane_state); > + else > + intel_disable_plane(plane, crtc_state); > + > + intel_plane_unpin_fb(old_plane_state); > + > +out_free: > + if (new_crtc_state) > + intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi); > + if (ret) > + intel_plane_destroy_state(&plane->base, &new_plane_state->uapi); > + else > + intel_plane_destroy_state(&plane->base, &old_plane_state->uapi); > + return ret; > + > +slow: > + return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb, > + crtc_x, crtc_y, crtc_w, crtc_h, > + src_x, src_y, src_w, src_h, ctx); > +} > + > +static const struct drm_plane_funcs intel_cursor_plane_funcs = { > + .update_plane = intel_legacy_cursor_update, > + .disable_plane = drm_atomic_helper_disable_plane, > + .destroy = intel_plane_destroy, > + .atomic_duplicate_state = intel_plane_duplicate_state, > + .atomic_destroy_state = intel_plane_destroy_state, > + .format_mod_supported = intel_cursor_format_mod_supported, > +}; > + > +struct intel_plane * > +intel_cursor_plane_create(struct drm_i915_private *dev_priv, > + enum pipe pipe) > +{ > + struct intel_plane *cursor; > + int ret, zpos; > + > + cursor = intel_plane_alloc(); > + if (IS_ERR(cursor)) > + return cursor; > + > + cursor->pipe = pipe; > + cursor->i9xx_plane = (enum i9xx_plane_id) pipe; > + cursor->id = PLANE_CURSOR; > + cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id); > + > + if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) { > + cursor->max_stride = i845_cursor_max_stride; > + cursor->update_plane = i845_update_cursor; > + cursor->disable_plane = i845_disable_cursor; > + cursor->get_hw_state = i845_cursor_get_hw_state; > + cursor->check_plane = i845_check_cursor; > + } else { > + cursor->max_stride = i9xx_cursor_max_stride; > + cursor->update_plane = i9xx_update_cursor; > + cursor->disable_plane = i9xx_disable_cursor; > + cursor->get_hw_state = i9xx_cursor_get_hw_state; > + cursor->check_plane = i9xx_check_cursor; > + } > + > + cursor->cursor.base = ~0; > + cursor->cursor.cntl = ~0; > + > + if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv)) > + cursor->cursor.size = ~0; > + > + ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base, > + 0, &intel_cursor_plane_funcs, > + intel_cursor_formats, > + ARRAY_SIZE(intel_cursor_formats), > + cursor_format_modifiers, > + DRM_PLANE_TYPE_CURSOR, > + "cursor %c", pipe_name(pipe)); > + if (ret) > + goto fail; > + > + if (INTEL_GEN(dev_priv) >= 4) > + drm_plane_create_rotation_property(&cursor->base, > + DRM_MODE_ROTATE_0, > + DRM_MODE_ROTATE_0 | > + DRM_MODE_ROTATE_180); > + > + zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1; > + drm_plane_create_zpos_immutable_property(&cursor->base, zpos); > + > + if (INTEL_GEN(dev_priv) >= 12) > + drm_plane_enable_fb_damage_clips(&cursor->base); > + > + drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs); > + > + return cursor; > + > +fail: > + intel_plane_free(cursor); > + > + return ERR_PTR(ret); > +} > diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c > index c567c0cada7e..0f163c2dc621 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.c > +++ b/drivers/gpu/drm/i915/display/intel_display.c > @@ -2533,9 +2533,9 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv, > return offset_aligned; > } > > -static u32 intel_plane_compute_aligned_offset(int *x, int *y, > - const struct intel_plane_state *state, > - int color_plane) > +u32 intel_plane_compute_aligned_offset(int *x, int *y, > + const struct intel_plane_state *state, > + int color_plane) > { > struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane); > struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); > @@ -3272,7 +3272,7 @@ intel_plane_remap_gtt(struct intel_plane_state *plane_state) > } > } > > -static int > +int > intel_plane_compute_gtt(struct intel_plane_state *plane_state) > { > const struct intel_framebuffer *fb = > @@ -11547,569 +11547,6 @@ static bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state) > return true; > } > > -static u32 intel_cursor_base(const struct intel_plane_state *plane_state) > -{ > - struct drm_i915_private *dev_priv = > - to_i915(plane_state->uapi.plane->dev); > - const struct drm_framebuffer *fb = plane_state->hw.fb; > - const struct drm_i915_gem_object *obj = intel_fb_obj(fb); > - u32 base; > - > - if (INTEL_INFO(dev_priv)->display.cursor_needs_physical) > - base = sg_dma_address(obj->mm.pages->sgl); > - else > - base = intel_plane_ggtt_offset(plane_state); > - > - return base + plane_state->color_plane[0].offset; > -} > - > -static u32 intel_cursor_position(const struct intel_plane_state *plane_state) > -{ > - int x = plane_state->uapi.dst.x1; > - int y = plane_state->uapi.dst.y1; > - u32 pos = 0; > - > - if (x < 0) { > - pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; > - x = -x; > - } > - pos |= x << CURSOR_X_SHIFT; > - > - if (y < 0) { > - pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; > - y = -y; > - } > - pos |= y << CURSOR_Y_SHIFT; > - > - return pos; > -} > - > -static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state) > -{ > - const struct drm_mode_config *config = > - &plane_state->uapi.plane->dev->mode_config; > - int width = drm_rect_width(&plane_state->uapi.dst); > - int height = drm_rect_height(&plane_state->uapi.dst); > - > - return width > 0 && width <= config->cursor_width && > - height > 0 && height <= config->cursor_height; > -} > - > -static int intel_cursor_check_surface(struct intel_plane_state *plane_state) > -{ > - struct drm_i915_private *dev_priv = > - to_i915(plane_state->uapi.plane->dev); > - unsigned int rotation = plane_state->hw.rotation; > - int src_x, src_y; > - u32 offset; > - int ret; > - > - ret = intel_plane_compute_gtt(plane_state); > - if (ret) > - return ret; > - > - if (!plane_state->uapi.visible) > - return 0; > - > - src_x = plane_state->uapi.src.x1 >> 16; > - src_y = plane_state->uapi.src.y1 >> 16; > - > - intel_add_fb_offsets(&src_x, &src_y, plane_state, 0); > - offset = intel_plane_compute_aligned_offset(&src_x, &src_y, > - plane_state, 0); > - > - if (src_x != 0 || src_y != 0) { > - drm_dbg_kms(&dev_priv->drm, > - "Arbitrary cursor panning not supported\n"); > - return -EINVAL; > - } > - > - /* > - * Put the final coordinates back so that the src > - * coordinate checks will see the right values. > - */ > - drm_rect_translate_to(&plane_state->uapi.src, > - src_x << 16, src_y << 16); > - > - /* ILK+ do this automagically in hardware */ > - if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) { > - const struct drm_framebuffer *fb = plane_state->hw.fb; > - int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; > - int src_h = drm_rect_height(&plane_state->uapi.src) >> 16; > - > - offset += (src_h * src_w - 1) * fb->format->cpp[0]; > - } > - > - plane_state->color_plane[0].offset = offset; > - plane_state->color_plane[0].x = src_x; > - plane_state->color_plane[0].y = src_y; > - > - return 0; > -} > - > -static int intel_check_cursor(struct intel_crtc_state *crtc_state, > - struct intel_plane_state *plane_state) > -{ > - const struct drm_framebuffer *fb = plane_state->hw.fb; > - struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); > - const struct drm_rect src = plane_state->uapi.src; > - const struct drm_rect dst = plane_state->uapi.dst; > - int ret; > - > - if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) { > - drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n"); > - return -EINVAL; > - } > - > - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, > - DRM_PLANE_HELPER_NO_SCALING, > - DRM_PLANE_HELPER_NO_SCALING, > - true); > - if (ret) > - return ret; > - > - /* Use the unclipped src/dst rectangles, which we program to hw */ > - plane_state->uapi.src = src; > - plane_state->uapi.dst = dst; > - > - ret = intel_cursor_check_surface(plane_state); > - if (ret) > - return ret; > - > - if (!plane_state->uapi.visible) > - return 0; > - > - ret = intel_plane_check_src_coordinates(plane_state); > - if (ret) > - return ret; > - > - return 0; > -} > - > -static unsigned int > -i845_cursor_max_stride(struct intel_plane *plane, > - u32 pixel_format, u64 modifier, > - unsigned int rotation) > -{ > - return 2048; > -} > - > -static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state) > -{ > - u32 cntl = 0; > - > - if (crtc_state->gamma_enable) > - cntl |= CURSOR_GAMMA_ENABLE; > - > - return cntl; > -} > - > -static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, > - const struct intel_plane_state *plane_state) > -{ > - return CURSOR_ENABLE | > - CURSOR_FORMAT_ARGB | > - CURSOR_STRIDE(plane_state->color_plane[0].stride); > -} > - > -static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state) > -{ > - int width = drm_rect_width(&plane_state->uapi.dst); > - > - /* > - * 845g/865g are only limited by the width of their cursors, > - * the height is arbitrary up to the precision of the register. > - */ > - return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64); > -} > - > -static int i845_check_cursor(struct intel_crtc_state *crtc_state, > - struct intel_plane_state *plane_state) > -{ > - const struct drm_framebuffer *fb = plane_state->hw.fb; > - struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); > - int ret; > - > - ret = intel_check_cursor(crtc_state, plane_state); > - if (ret) > - return ret; > - > - /* if we want to turn off the cursor ignore width and height */ > - if (!fb) > - return 0; > - > - /* Check for which cursor types we support */ > - if (!i845_cursor_size_ok(plane_state)) { > - drm_dbg_kms(&i915->drm, > - "Cursor dimension %dx%d not supported\n", > - drm_rect_width(&plane_state->uapi.dst), > - drm_rect_height(&plane_state->uapi.dst)); > - return -EINVAL; > - } > - > - drm_WARN_ON(&i915->drm, plane_state->uapi.visible && > - plane_state->color_plane[0].stride != fb->pitches[0]); > - > - switch (fb->pitches[0]) { > - case 256: > - case 512: > - case 1024: > - case 2048: > - break; > - default: > - drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n", > - fb->pitches[0]); > - return -EINVAL; > - } > - > - plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state); > - > - return 0; > -} > - > -static void i845_update_cursor(struct intel_plane *plane, > - const struct intel_crtc_state *crtc_state, > - const struct intel_plane_state *plane_state) > -{ > - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > - u32 cntl = 0, base = 0, pos = 0, size = 0; > - unsigned long irqflags; > - > - if (plane_state && plane_state->uapi.visible) { > - unsigned int width = drm_rect_width(&plane_state->uapi.dst); > - unsigned int height = drm_rect_height(&plane_state->uapi.dst); > - > - cntl = plane_state->ctl | > - i845_cursor_ctl_crtc(crtc_state); > - > - size = (height << 12) | width; > - > - base = intel_cursor_base(plane_state); > - pos = intel_cursor_position(plane_state); > - } > - > - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > - > - /* On these chipsets we can only modify the base/size/stride > - * whilst the cursor is disabled. > - */ > - if (plane->cursor.base != base || > - plane->cursor.size != size || > - plane->cursor.cntl != cntl) { > - intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0); > - intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base); > - intel_de_write_fw(dev_priv, CURSIZE, size); > - intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos); > - intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl); > - > - plane->cursor.base = base; > - plane->cursor.size = size; > - plane->cursor.cntl = cntl; > - } else { > - intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos); > - } > - > - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > -} > - > -static void i845_disable_cursor(struct intel_plane *plane, > - const struct intel_crtc_state *crtc_state) > -{ > - i845_update_cursor(plane, crtc_state, NULL); > -} > - > -static bool i845_cursor_get_hw_state(struct intel_plane *plane, > - enum pipe *pipe) > -{ > - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > - enum intel_display_power_domain power_domain; > - intel_wakeref_t wakeref; > - bool ret; > - > - power_domain = POWER_DOMAIN_PIPE(PIPE_A); > - wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); > - if (!wakeref) > - return false; > - > - ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE; > - > - *pipe = PIPE_A; > - > - intel_display_power_put(dev_priv, power_domain, wakeref); > - > - return ret; > -} > - > -static unsigned int > -i9xx_cursor_max_stride(struct intel_plane *plane, > - u32 pixel_format, u64 modifier, > - unsigned int rotation) > -{ > - return plane->base.dev->mode_config.cursor_width * 4; > -} > - > -static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state) > -{ > - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > - u32 cntl = 0; > - > - if (INTEL_GEN(dev_priv) >= 11) > - return cntl; > - > - if (crtc_state->gamma_enable) > - cntl = MCURSOR_GAMMA_ENABLE; > - > - if (crtc_state->csc_enable) > - cntl |= MCURSOR_PIPE_CSC_ENABLE; > - > - if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) > - cntl |= MCURSOR_PIPE_SELECT(crtc->pipe); > - > - return cntl; > -} > - > -static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, > - const struct intel_plane_state *plane_state) > -{ > - struct drm_i915_private *dev_priv = > - to_i915(plane_state->uapi.plane->dev); > - u32 cntl = 0; > - > - if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) > - cntl |= MCURSOR_TRICKLE_FEED_DISABLE; > - > - switch (drm_rect_width(&plane_state->uapi.dst)) { > - case 64: > - cntl |= MCURSOR_MODE_64_ARGB_AX; > - break; > - case 128: > - cntl |= MCURSOR_MODE_128_ARGB_AX; > - break; > - case 256: > - cntl |= MCURSOR_MODE_256_ARGB_AX; > - break; > - default: > - MISSING_CASE(drm_rect_width(&plane_state->uapi.dst)); > - return 0; > - } > - > - if (plane_state->hw.rotation & DRM_MODE_ROTATE_180) > - cntl |= MCURSOR_ROTATE_180; > - > - return cntl; > -} > - > -static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state) > -{ > - struct drm_i915_private *dev_priv = > - to_i915(plane_state->uapi.plane->dev); > - int width = drm_rect_width(&plane_state->uapi.dst); > - int height = drm_rect_height(&plane_state->uapi.dst); > - > - if (!intel_cursor_size_ok(plane_state)) > - return false; > - > - /* Cursor width is limited to a few power-of-two sizes */ > - switch (width) { > - case 256: > - case 128: > - case 64: > - break; > - default: > - return false; > - } > - > - /* > - * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor > - * height from 8 lines up to the cursor width, when the > - * cursor is not rotated. Everything else requires square > - * cursors. > - */ > - if (HAS_CUR_FBC(dev_priv) && > - plane_state->hw.rotation & DRM_MODE_ROTATE_0) { > - if (height < 8 || height > width) > - return false; > - } else { > - if (height != width) > - return false; > - } > - > - return true; > -} > - > -static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, > - struct intel_plane_state *plane_state) > -{ > - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); > - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > - const struct drm_framebuffer *fb = plane_state->hw.fb; > - enum pipe pipe = plane->pipe; > - int ret; > - > - ret = intel_check_cursor(crtc_state, plane_state); > - if (ret) > - return ret; > - > - /* if we want to turn off the cursor ignore width and height */ > - if (!fb) > - return 0; > - > - /* Check for which cursor types we support */ > - if (!i9xx_cursor_size_ok(plane_state)) { > - drm_dbg(&dev_priv->drm, > - "Cursor dimension %dx%d not supported\n", > - drm_rect_width(&plane_state->uapi.dst), > - drm_rect_height(&plane_state->uapi.dst)); > - return -EINVAL; > - } > - > - drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible && > - plane_state->color_plane[0].stride != fb->pitches[0]); > - > - if (fb->pitches[0] != > - drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) { > - drm_dbg_kms(&dev_priv->drm, > - "Invalid cursor stride (%u) (cursor width %d)\n", > - fb->pitches[0], > - drm_rect_width(&plane_state->uapi.dst)); > - return -EINVAL; > - } > - > - /* > - * There's something wrong with the cursor on CHV pipe C. > - * If it straddles the left edge of the screen then > - * moving it away from the edge or disabling it often > - * results in a pipe underrun, and often that can lead to > - * dead pipe (constant underrun reported, and it scans > - * out just a solid color). To recover from that, the > - * display power well must be turned off and on again. > - * Refuse the put the cursor into that compromised position. > - */ > - if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C && > - plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) { > - drm_dbg_kms(&dev_priv->drm, > - "CHV cursor C not allowed to straddle the left screen edge\n"); > - return -EINVAL; > - } > - > - plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state); > - > - return 0; > -} > - > -static void i9xx_update_cursor(struct intel_plane *plane, > - const struct intel_crtc_state *crtc_state, > - const struct intel_plane_state *plane_state) > -{ > - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > - enum pipe pipe = plane->pipe; > - u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0; > - unsigned long irqflags; > - > - if (plane_state && plane_state->uapi.visible) { > - unsigned width = drm_rect_width(&plane_state->uapi.dst); > - unsigned height = drm_rect_height(&plane_state->uapi.dst); > - > - cntl = plane_state->ctl | > - i9xx_cursor_ctl_crtc(crtc_state); > - > - if (width != height) > - fbc_ctl = CUR_FBC_CTL_EN | (height - 1); > - > - base = intel_cursor_base(plane_state); > - pos = intel_cursor_position(plane_state); > - } > - > - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > - > - /* > - * On some platforms writing CURCNTR first will also > - * cause CURPOS to be armed by the CURBASE write. > - * Without the CURCNTR write the CURPOS write would > - * arm itself. Thus we always update CURCNTR before > - * CURPOS. > - * > - * On other platforms CURPOS always requires the > - * CURBASE write to arm the update. Additonally > - * a write to any of the cursor register will cancel > - * an already armed cursor update. Thus leaving out > - * the CURBASE write after CURPOS could lead to a > - * cursor that doesn't appear to move, or even change > - * shape. Thus we always write CURBASE. > - * > - * The other registers are armed by by the CURBASE write > - * except when the plane is getting enabled at which time > - * the CURCNTR write arms the update. > - */ > - > - if (INTEL_GEN(dev_priv) >= 9) > - skl_write_cursor_wm(plane, crtc_state); > - > - if (!needs_modeset(crtc_state)) > - intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0); > - > - if (plane->cursor.base != base || > - plane->cursor.size != fbc_ctl || > - plane->cursor.cntl != cntl) { > - if (HAS_CUR_FBC(dev_priv)) > - intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe), > - fbc_ctl); > - intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl); > - intel_de_write_fw(dev_priv, CURPOS(pipe), pos); > - intel_de_write_fw(dev_priv, CURBASE(pipe), base); > - > - plane->cursor.base = base; > - plane->cursor.size = fbc_ctl; > - plane->cursor.cntl = cntl; > - } else { > - intel_de_write_fw(dev_priv, CURPOS(pipe), pos); > - intel_de_write_fw(dev_priv, CURBASE(pipe), base); > - } > - > - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > -} > - > -static void i9xx_disable_cursor(struct intel_plane *plane, > - const struct intel_crtc_state *crtc_state) > -{ > - i9xx_update_cursor(plane, crtc_state, NULL); > -} > - > -static bool i9xx_cursor_get_hw_state(struct intel_plane *plane, > - enum pipe *pipe) > -{ > - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > - enum intel_display_power_domain power_domain; > - intel_wakeref_t wakeref; > - bool ret; > - u32 val; > - > - /* > - * Not 100% correct for planes that can move between pipes, > - * but that's only the case for gen2-3 which don't have any > - * display power wells. > - */ > - power_domain = POWER_DOMAIN_PIPE(plane->pipe); > - wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); > - if (!wakeref) > - return false; > - > - val = intel_de_read(dev_priv, CURCNTR(plane->pipe)); > - > - ret = val & MCURSOR_MODE; > - > - if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) > - *pipe = plane->pipe; > - else > - *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >> > - MCURSOR_PIPE_SELECT_SHIFT; > - > - intel_display_power_put(dev_priv, power_domain, wakeref); > - > - return ret; > -} > - > /* VESA 640x480x72Hz mode to set on the pipe */ > static const struct drm_display_mode load_detect_mode = { > DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, > @@ -16620,7 +16057,7 @@ static void add_rps_boost_after_vblank(struct drm_crtc *crtc, > add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait); > } > > -static int intel_plane_pin_fb(struct intel_plane_state *plane_state) > +int intel_plane_pin_fb(struct intel_plane_state *plane_state) > { > struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); > struct drm_i915_private *dev_priv = to_i915(plane->base.dev); > @@ -16650,7 +16087,7 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state) > return 0; > } > > -static void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) > +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) > { > struct i915_vma *vma; > > @@ -16886,13 +16323,6 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane, > } > } > > -static bool intel_cursor_format_mod_supported(struct drm_plane *_plane, > - u32 format, u64 modifier) > -{ > - return modifier == DRM_FORMAT_MOD_LINEAR && > - format == DRM_FORMAT_ARGB8888; > -} > - > static const struct drm_plane_funcs i965_plane_funcs = { > .update_plane = drm_atomic_helper_update_plane, > .disable_plane = drm_atomic_helper_disable_plane, > @@ -16911,142 +16341,6 @@ static const struct drm_plane_funcs i8xx_plane_funcs = { > .format_mod_supported = i8xx_plane_format_mod_supported, > }; > > -static int > -intel_legacy_cursor_update(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, > - u32 src_x, u32 src_y, > - u32 src_w, u32 src_h, > - struct drm_modeset_acquire_ctx *ctx) > -{ > - struct intel_plane *plane = to_intel_plane(_plane); > - struct intel_crtc *crtc = to_intel_crtc(_crtc); > - struct intel_plane_state *old_plane_state = > - to_intel_plane_state(plane->base.state); > - struct intel_plane_state *new_plane_state; > - struct intel_crtc_state *crtc_state = > - to_intel_crtc_state(crtc->base.state); > - struct intel_crtc_state *new_crtc_state; > - int ret; > - > - /* > - * When crtc is inactive or there is a modeset pending, > - * wait for it to complete in the slowpath > - * > - * FIXME bigjoiner fastpath would be good > - */ > - if (!crtc_state->hw.active || needs_modeset(crtc_state) || > - crtc_state->update_pipe || crtc_state->bigjoiner) > - goto slow; > - > - /* > - * Don't do an async update if there is an outstanding commit modifying > - * the plane. This prevents our async update's changes from getting > - * overridden by a previous synchronous update's state. > - */ > - if (old_plane_state->uapi.commit && > - !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done)) > - goto slow; > - > - /* > - * If any parameters change that may affect watermarks, > - * take the slowpath. Only changing fb or position should be > - * in the fastpath. > - */ > - if (old_plane_state->uapi.crtc != &crtc->base || > - old_plane_state->uapi.src_w != src_w || > - old_plane_state->uapi.src_h != src_h || > - old_plane_state->uapi.crtc_w != crtc_w || > - old_plane_state->uapi.crtc_h != crtc_h || > - !old_plane_state->uapi.fb != !fb) > - goto slow; > - > - new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base)); > - if (!new_plane_state) > - return -ENOMEM; > - > - new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base)); > - if (!new_crtc_state) { > - ret = -ENOMEM; > - goto out_free; > - } > - > - drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb); > - > - new_plane_state->uapi.src_x = src_x; > - new_plane_state->uapi.src_y = src_y; > - new_plane_state->uapi.src_w = src_w; > - new_plane_state->uapi.src_h = src_h; > - new_plane_state->uapi.crtc_x = crtc_x; > - new_plane_state->uapi.crtc_y = crtc_y; > - new_plane_state->uapi.crtc_w = crtc_w; > - new_plane_state->uapi.crtc_h = crtc_h; > - > - intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc); > - > - ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state, > - old_plane_state, new_plane_state); > - if (ret) > - goto out_free; > - > - ret = intel_plane_pin_fb(new_plane_state); > - if (ret) > - goto out_free; > - > - intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb), > - ORIGIN_FLIP); > - intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb), > - to_intel_frontbuffer(new_plane_state->hw.fb), > - plane->frontbuffer_bit); > - > - /* Swap plane state */ > - plane->base.state = &new_plane_state->uapi; > - > - /* > - * We cannot swap crtc_state as it may be in use by an atomic commit or > - * page flip that's running simultaneously. If we swap crtc_state and > - * destroy the old state, we will cause a use-after-free there. > - * > - * Only update active_planes, which is needed for our internal > - * bookkeeping. Either value will do the right thing when updating > - * planes atomically. If the cursor was part of the atomic update then > - * we would have taken the slowpath. > - */ > - crtc_state->active_planes = new_crtc_state->active_planes; > - > - if (new_plane_state->uapi.visible) > - intel_update_plane(plane, crtc_state, new_plane_state); > - else > - intel_disable_plane(plane, crtc_state); > - > - intel_plane_unpin_fb(old_plane_state); > - > -out_free: > - if (new_crtc_state) > - intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi); > - if (ret) > - intel_plane_destroy_state(&plane->base, &new_plane_state->uapi); > - else > - intel_plane_destroy_state(&plane->base, &old_plane_state->uapi); > - return ret; > - > -slow: > - return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb, > - crtc_x, crtc_y, crtc_w, crtc_h, > - src_x, src_y, src_w, src_h, ctx); > -} > - > -static const struct drm_plane_funcs intel_cursor_plane_funcs = { > - .update_plane = intel_legacy_cursor_update, > - .disable_plane = drm_atomic_helper_disable_plane, > - .destroy = intel_plane_destroy, > - .atomic_duplicate_state = intel_plane_duplicate_state, > - .atomic_destroy_state = intel_plane_destroy_state, > - .format_mod_supported = intel_cursor_format_mod_supported, > -}; > - > static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv, > enum i9xx_plane_id i9xx_plane) > { > @@ -17198,74 +16492,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) > return ERR_PTR(ret); > } > > -static struct intel_plane * > -intel_cursor_plane_create(struct drm_i915_private *dev_priv, > - enum pipe pipe) > -{ > - struct intel_plane *cursor; > - int ret, zpos; > - > - cursor = intel_plane_alloc(); > - if (IS_ERR(cursor)) > - return cursor; > - > - cursor->pipe = pipe; > - cursor->i9xx_plane = (enum i9xx_plane_id) pipe; > - cursor->id = PLANE_CURSOR; > - cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id); > - > - if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) { > - cursor->max_stride = i845_cursor_max_stride; > - cursor->update_plane = i845_update_cursor; > - cursor->disable_plane = i845_disable_cursor; > - cursor->get_hw_state = i845_cursor_get_hw_state; > - cursor->check_plane = i845_check_cursor; > - } else { > - cursor->max_stride = i9xx_cursor_max_stride; > - cursor->update_plane = i9xx_update_cursor; > - cursor->disable_plane = i9xx_disable_cursor; > - cursor->get_hw_state = i9xx_cursor_get_hw_state; > - cursor->check_plane = i9xx_check_cursor; > - } > - > - cursor->cursor.base = ~0; > - cursor->cursor.cntl = ~0; > - > - if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv)) > - cursor->cursor.size = ~0; > - > - ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base, > - 0, &intel_cursor_plane_funcs, > - intel_cursor_formats, > - ARRAY_SIZE(intel_cursor_formats), > - cursor_format_modifiers, > - DRM_PLANE_TYPE_CURSOR, > - "cursor %c", pipe_name(pipe)); > - if (ret) > - goto fail; > - > - if (INTEL_GEN(dev_priv) >= 4) > - drm_plane_create_rotation_property(&cursor->base, > - DRM_MODE_ROTATE_0, > - DRM_MODE_ROTATE_0 | > - DRM_MODE_ROTATE_180); > - > - zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1; > - drm_plane_create_zpos_immutable_property(&cursor->base, zpos); > - > - if (INTEL_GEN(dev_priv) >= 12) > - drm_plane_enable_fb_damage_clips(&cursor->base); > - > - drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs); > - > - return cursor; > - > -fail: > - intel_plane_free(cursor); > - > - return ERR_PTR(ret); > -} > - > static int intel_crtc_late_register(struct drm_crtc *crtc) > { > intel_crtc_debugfs_add(crtc); > diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h > index a5771bfecba6..f0a5bf69656f 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.h > +++ b/drivers/gpu/drm/i915/display/intel_display.h > @@ -647,6 +647,18 @@ bool > intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, > uint64_t modifier); > > +int intel_plane_compute_gtt(struct intel_plane_state *plane_state); > +u32 intel_plane_compute_aligned_offset(int *x, int *y, > + const struct intel_plane_state *state, > + int color_plane); > +int intel_plane_pin_fb(struct intel_plane_state *plane_state); > +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state); > + > +/* cursor */ > +struct intel_plane * > +intel_cursor_plane_create(struct drm_i915_private *dev_priv, > + enum pipe pipe); > + > /* modesetting */ > void intel_modeset_init_hw(struct drm_i915_private *i915); > int intel_modeset_init_noirq(struct drm_i915_private *i915); > -- > 2.27.0 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Ville Syrjälä Intel _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c 2020-12-09 11:48 ` [Intel-gfx] [PATCH] " Ville Syrjälä @ 2020-12-10 0:10 ` Dave Airlie 0 siblings, 0 replies; 5+ messages in thread From: Dave Airlie @ 2020-12-10 0:10 UTC (permalink / raw) To: Ville Syrjälä; +Cc: Intel Graphics Development On Wed, 9 Dec 2020 at 21:48, Ville Syrjälä <ville.syrjala@linux.intel.com> wrote: > > On Wed, Dec 09, 2020 at 10:51:52AM +1000, Dave Airlie wrote: > > From: Dave Airlie <airlied@redhat.com> > > > > This file is a monster, let's start simple, the cursor plane code > > seems pretty standalone, and splits out easily enough. > > Is this different from > https://patchwork.freedesktop.org/series/83704/ ? Shouldn't be too much, I thought I was only going to have time for one cleanup, but then decided to keep going :-P Dave. _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-12-10 0:10 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-12-09 0:51 [Intel-gfx] [PATCH] drm/i915: refactor cursor code out of i915_display.c Dave Airlie 2020-12-09 1:05 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for " Patchwork 2020-12-09 1:37 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork 2020-12-09 11:48 ` [Intel-gfx] [PATCH] " Ville Syrjälä 2020-12-10 0:10 ` Dave Airlie
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.