summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_cursor.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_cursor.c650
1 files changed, 476 insertions, 174 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 966e020331fb..a10b2425b94d 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -6,66 +6,66 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
-#include <drm/drm_plane_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
#include "intel_atomic.h"
-#include "intel_atomic_plane.h"
#include "intel_cursor.h"
+#include "intel_cursor_regs.h"
#include "intel_de.h"
-#include "intel_display_types.h"
#include "intel_display.h"
+#include "intel_display_types.h"
+#include "intel_display_utils.h"
#include "intel_fb.h"
-
+#include "intel_fb_pin.h"
#include "intel_frontbuffer.h"
-#include "intel_pm.h"
+#include "intel_plane.h"
#include "intel_psr.h"
-#include "intel_sprite.h"
+#include "intel_psr_regs.h"
+#include "intel_vblank.h"
+#include "skl_watermark.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 u32 intel_cursor_base(const struct intel_plane_state *plane_state)
+static u32 intel_cursor_surf_offset(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->view.color_plane[0].offset;
+ return plane_state->view.color_plane[0].offset;
}
-static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
+static u32 intel_cursor_position(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state,
+ bool early_tpt)
{
int x = plane_state->uapi.dst.x1;
int y = plane_state->uapi.dst.y1;
u32 pos = 0;
+ /*
+ * Formula from Bspec:
+ * MAX(-1 * <Cursor vertical size from CUR_CTL base on cursor mode
+ * select setting> + 1, CUR_POS Y Position - Update region Y position
+ */
+ if (early_tpt)
+ y = max(-1 * drm_rect_height(&plane_state->uapi.dst) + 1,
+ y - crtc_state->psr2_su_area.y1);
+
if (x < 0) {
- pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+ pos |= CURSOR_POS_X_SIGN;
x = -x;
}
- pos |= x << CURSOR_X_SHIFT;
+ pos |= CURSOR_POS_X(x);
if (y < 0) {
- pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+ pos |= CURSOR_POS_Y_SIGN;
y = -y;
}
- pos |= y << CURSOR_Y_SHIFT;
+ pos |= CURSOR_POS_Y(y);
return pos;
}
@@ -83,8 +83,8 @@ static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
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);
+ struct intel_display *display = to_intel_display(plane_state);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
unsigned int rotation = plane_state->hw.rotation;
int src_x, src_y;
u32 offset;
@@ -105,8 +105,9 @@ static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
plane_state, 0);
if (src_x != 0 || src_y != 0) {
- drm_dbg_kms(&dev_priv->drm,
- "Arbitrary cursor panning not supported\n");
+ drm_dbg_kms(display->drm,
+ "[PLANE:%d:%s] arbitrary cursor panning not supported\n",
+ plane->base.base.id, plane->base.name);
return -EINVAL;
}
@@ -118,7 +119,7 @@ static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
src_x << 16, src_y << 16);
/* ILK+ do this automagically in hardware */
- if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
+ if (HAS_GMCH(display) && 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;
@@ -136,21 +137,23 @@ static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
static int intel_check_cursor(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
+ struct intel_display *display = to_intel_display(plane_state);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
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");
+ drm_dbg_kms(display->drm, "[PLANE:%d:%s] cursor cannot be tiled\n",
+ plane->base.base.id, plane->base.name);
return -EINVAL;
}
- ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true);
+ ret = intel_plane_check_clipping(plane_state, crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ true);
if (ret)
return ret;
@@ -158,6 +161,11 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
plane_state->uapi.src = src;
plane_state->uapi.dst = dst;
+ /* final plane coordinates will be relative to the plane's pipe */
+ drm_rect_translate(&plane_state->uapi.dst,
+ -crtc_state->pipe_src.x1,
+ -crtc_state->pipe_src.y1);
+
ret = intel_cursor_check_surface(plane_state);
if (ret)
return ret;
@@ -174,28 +182,34 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
static unsigned int
i845_cursor_max_stride(struct intel_plane *plane,
- u32 pixel_format, u64 modifier,
- unsigned int rotation)
+ const struct drm_format_info *info,
+ u64 modifier, unsigned int rotation)
{
return 2048;
}
+static unsigned int i845_cursor_min_alignment(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane)
+{
+ return 32;
+}
+
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;
+ cntl |= CURSOR_PIPE_GAMMA_ENABLE;
return cntl;
}
-static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
+static u32 i845_cursor_ctl(const struct intel_plane_state *plane_state)
{
return CURSOR_ENABLE |
CURSOR_FORMAT_ARGB |
- CURSOR_STRIDE(plane_state->view.color_plane[0].stride);
+ CURSOR_STRIDE(plane_state->view.color_plane[0].mapping_stride);
}
static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
@@ -212,8 +226,9 @@ static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
static int i845_check_cursor(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
+ struct intel_display *display = to_intel_display(plane_state);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
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);
@@ -226,15 +241,16 @@ static int i845_check_cursor(struct intel_crtc_state *crtc_state,
/* 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_dbg_kms(display->drm,
+ "[PLANE:%d:%s] cursor dimension %dx%d not supported\n",
+ plane->base.base.id, plane->base.name,
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->view.color_plane[0].stride != fb->pitches[0]);
+ drm_WARN_ON(display->drm, plane_state->uapi.visible &&
+ plane_state->view.color_plane[0].mapping_stride != fb->pitches[0]);
switch (fb->pitches[0]) {
case 256:
@@ -243,23 +259,25 @@ static int i845_check_cursor(struct intel_crtc_state *crtc_state,
case 2048:
break;
default:
- drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
+ drm_dbg_kms(display->drm, "[PLANE:%d:%s] invalid cursor stride (%u)\n",
+ plane->base.base.id, plane->base.name,
fb->pitches[0]);
return -EINVAL;
}
- plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
+ plane_state->ctl = i845_cursor_ctl(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)
+/* TODO: split into noarm+arm pair */
+static void i845_cursor_update_arm(struct intel_dsb *dsb,
+ 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);
+ struct intel_display *display = to_intel_display(plane);
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);
@@ -268,101 +286,123 @@ static void i845_update_cursor(struct intel_plane *plane,
cntl = plane_state->ctl |
i845_cursor_ctl_crtc(crtc_state);
- size = (height << 12) | width;
+ size = CURSOR_HEIGHT(height) | CURSOR_WIDTH(width);
- base = intel_cursor_base(plane_state);
- pos = intel_cursor_position(plane_state);
+ base = plane_state->surf;
+ pos = intel_cursor_position(crtc_state, plane_state, false);
}
- 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);
+ intel_de_write_fw(display, CURCNTR(display, PIPE_A), 0);
+ intel_de_write_fw(display, CURBASE(display, PIPE_A), base);
+ intel_de_write_fw(display, CURSIZE(display, PIPE_A), size);
+ intel_de_write_fw(display, CURPOS(display, PIPE_A), pos);
+ intel_de_write_fw(display, CURCNTR(display, 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);
+ intel_de_write_fw(display, CURPOS(display, 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)
+static void i845_cursor_disable_arm(struct intel_dsb *dsb,
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
{
- i845_update_cursor(plane, crtc_state, NULL);
+ i845_cursor_update_arm(dsb, 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);
+ struct intel_display *display = to_intel_display(plane);
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);
+ wakeref = intel_display_power_get_if_enabled(display, power_domain);
if (!wakeref)
return false;
- ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
+ ret = intel_de_read(display, CURCNTR(display, PIPE_A)) & CURSOR_ENABLE;
*pipe = PIPE_A;
- intel_display_power_put(dev_priv, power_domain, wakeref);
+ intel_display_power_put(display, power_domain, wakeref);
return ret;
}
static unsigned int
i9xx_cursor_max_stride(struct intel_plane *plane,
- u32 pixel_format, u64 modifier,
- unsigned int rotation)
+ const struct drm_format_info *info,
+ u64 modifier, unsigned int rotation)
{
return plane->base.dev->mode_config.cursor_width * 4;
}
+static unsigned int i830_cursor_min_alignment(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane)
+{
+ /* "AlmadorM Errata – Requires 32-bpp cursor data to be 16KB aligned." */
+ return 16 * 1024; /* physical */
+}
+
+static unsigned int i85x_cursor_min_alignment(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane)
+{
+ return 256; /* physical */
+}
+
+static unsigned int i9xx_cursor_min_alignment(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane)
+{
+ struct intel_display *display = to_intel_display(plane);
+
+ if (intel_scanout_needs_vtd_wa(display))
+ return 64 * 1024;
+
+ return 4 * 1024; /* physical for i915/i945 */
+}
+
static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
+ struct intel_display *display = to_intel_display(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 (DISPLAY_VER(dev_priv) >= 11)
+ if (DISPLAY_VER(display) >= 11)
return cntl;
if (crtc_state->gamma_enable)
- cntl = MCURSOR_GAMMA_ENABLE;
+ cntl = MCURSOR_PIPE_GAMMA_ENABLE;
if (crtc_state->csc_enable)
cntl |= MCURSOR_PIPE_CSC_ENABLE;
- if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv))
- cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
+ if (DISPLAY_VER(display) < 5 && !display->platform.g4x)
+ cntl |= MCURSOR_PIPE_SEL(crtc->pipe);
return cntl;
}
-static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
+static u32 i9xx_cursor_ctl(const struct intel_plane_state *plane_state)
{
- struct drm_i915_private *dev_priv =
- to_i915(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
u32 cntl = 0;
- if (IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv))
+ if (display->platform.sandybridge || display->platform.ivybridge)
cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
switch (drm_rect_width(&plane_state->uapi.dst)) {
@@ -383,8 +423,8 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
cntl |= MCURSOR_ROTATE_180;
- /* Wa_22012358565:adlp */
- if (DISPLAY_VER(dev_priv) == 13)
+ /* Wa_22012358565:adl-p */
+ if (DISPLAY_VER(display) == 13)
cntl |= MCURSOR_ARB_SLOTS(1);
return cntl;
@@ -392,8 +432,7 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
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);
+ struct intel_display *display = to_intel_display(plane_state);
int width = drm_rect_width(&plane_state->uapi.dst);
int height = drm_rect_height(&plane_state->uapi.dst);
@@ -416,7 +455,7 @@ static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
* cursor is not rotated. Everything else requires square
* cursors.
*/
- if (HAS_CUR_FBC(dev_priv) &&
+ if (HAS_CUR_FBC(display) &&
plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
if (height < 8 || height > width)
return false;
@@ -431,8 +470,8 @@ static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
+ struct intel_display *display = to_intel_display(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;
@@ -447,22 +486,23 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
/* 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));
+ drm_dbg_kms(display->drm,
+ "[PLANE:%d:%s] cursor dimension %dx%d not supported\n",
+ plane->base.base.id, plane->base.name,
+ 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->view.color_plane[0].stride != fb->pitches[0]);
+ drm_WARN_ON(display->drm, plane_state->uapi.visible &&
+ plane_state->view.color_plane[0].mapping_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));
+ drm_dbg_kms(display->drm,
+ "[PLANE:%d:%s] invalid cursor stride (%u) (cursor width %d)\n",
+ plane->base.base.id, plane->base.name,
+ fb->pitches[0], drm_rect_width(&plane_state->uapi.dst));
return -EINVAL;
}
@@ -476,26 +516,144 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
* 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 &&
+ if (display->platform.cherryview && 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");
+ drm_dbg_kms(display->drm,
+ "[PLANE:%d:%s] cursor not allowed to straddle the left screen edge\n",
+ plane->base.base.id, plane->base.name);
return -EINVAL;
}
- plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
+ plane_state->ctl = i9xx_cursor_ctl(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)
+static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb,
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_display *display = to_intel_display(plane);
+ enum pipe pipe = plane->pipe;
+
+ if (!crtc_state->enable_psr2_sel_fetch)
+ return;
+
+ intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0);
+}
+
+static void wa_16021440873(struct intel_dsb *dsb,
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ struct intel_display *display = to_intel_display(plane);
+ u32 ctl = plane_state->ctl;
+ int et_y_position = drm_rect_height(&crtc_state->pipe_src) + 1;
+ enum pipe pipe = plane->pipe;
+
+ ctl &= ~MCURSOR_MODE_MASK;
+ ctl |= MCURSOR_MODE_64_2B;
+
+ intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), ctl);
+
+ intel_de_write_dsb(display, dsb, CURPOS_ERLY_TPT(display, pipe),
+ CURSOR_POS_Y(et_y_position));
+}
+
+static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb,
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ struct intel_display *display = to_intel_display(plane);
+ enum pipe pipe = plane->pipe;
+
+ if (!crtc_state->enable_psr2_sel_fetch)
+ return;
+
+ if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) {
+ if (crtc_state->enable_psr2_su_region_et) {
+ u32 val = intel_cursor_position(crtc_state, plane_state,
+ true);
+
+ intel_de_write_dsb(display, dsb, CURPOS_ERLY_TPT(display, pipe), val);
+ }
+
+ intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), plane_state->ctl);
+ } else {
+ /* Wa_16021440873 */
+ if (crtc_state->enable_psr2_su_region_et)
+ wa_16021440873(dsb, plane, crtc_state, plane_state);
+ else
+ i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
+ }
+}
+
+static u32 skl_cursor_ddb_reg_val(const struct skl_ddb_entry *entry)
+{
+ if (!entry->end)
+ return 0;
+
+ return CUR_BUF_END(entry->end - 1) |
+ CUR_BUF_START(entry->start);
+}
+
+static u32 skl_cursor_wm_reg_val(const struct skl_wm_level *level)
+{
+ u32 val = 0;
+
+ if (level->enable)
+ val |= CUR_WM_EN;
+ if (level->ignore_lines)
+ val |= CUR_WM_IGNORE_LINES;
+ val |= REG_FIELD_PREP(CUR_WM_BLOCKS_MASK, level->blocks);
+ val |= REG_FIELD_PREP(CUR_WM_LINES_MASK, level->lines);
+
+ return val;
+}
+
+static void skl_write_cursor_wm(struct intel_dsb *dsb,
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_display *display = to_intel_display(plane->base.dev);
+ enum plane_id plane_id = plane->id;
+ enum pipe pipe = plane->pipe;
+ const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
+ const struct skl_ddb_entry *ddb =
+ &crtc_state->wm.skl.plane_ddb[plane_id];
+ int level;
+
+ for (level = 0; level < display->wm.num_levels; level++)
+ intel_de_write_dsb(display, dsb, CUR_WM(pipe, level),
+ skl_cursor_wm_reg_val(skl_plane_wm_level(pipe_wm, plane_id, level)));
+
+ intel_de_write_dsb(display, dsb, CUR_WM_TRANS(pipe),
+ skl_cursor_wm_reg_val(skl_plane_trans_wm(pipe_wm, plane_id)));
+
+ if (HAS_HW_SAGV_WM(display)) {
+ const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
+
+ intel_de_write_dsb(display, dsb, CUR_WM_SAGV(pipe),
+ skl_cursor_wm_reg_val(&wm->sagv.wm0));
+ intel_de_write_dsb(display, dsb, CUR_WM_SAGV_TRANS(pipe),
+ skl_cursor_wm_reg_val(&wm->sagv.trans_wm));
+ }
+
+ intel_de_write_dsb(display, dsb, CUR_BUF_CFG(pipe),
+ skl_cursor_ddb_reg_val(ddb));
+}
+
+/* TODO: split into noarm+arm pair */
+static void i9xx_cursor_update_arm(struct intel_dsb *dsb,
+ 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);
+ struct intel_display *display = to_intel_display(plane);
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) {
int width = drm_rect_width(&plane_state->uapi.dst);
@@ -504,15 +662,13 @@ static void i9xx_update_cursor(struct intel_plane *plane,
cntl = plane_state->ctl |
i9xx_cursor_ctl_crtc(crtc_state);
- if (width != height)
- fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
+ if (DISPLAY_VER(display) < 14 && width != height)
+ fbc_ctl = CUR_FBC_EN | CUR_FBC_HEIGHT(height - 1);
- base = intel_cursor_base(plane_state);
- pos = intel_cursor_position(plane_state);
+ base = plane_state->surf;
+ pos = intel_cursor_position(crtc_state, plane_state, false);
}
- 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.
@@ -521,7 +677,7 @@ static void i9xx_update_cursor(struct intel_plane *plane,
* CURPOS.
*
* On other platforms CURPOS always requires the
- * CURBASE write to arm the update. Additonally
+ * CURBASE write to arm the update. Additionally
* 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
@@ -533,43 +689,43 @@ static void i9xx_update_cursor(struct intel_plane *plane,
* the CURCNTR write arms the update.
*/
- if (DISPLAY_VER(dev_priv) >= 9)
- skl_write_cursor_wm(plane, crtc_state);
+ if (DISPLAY_VER(display) >= 9)
+ skl_write_cursor_wm(dsb, plane, crtc_state);
- if (!intel_crtc_needs_modeset(crtc_state))
- intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
+ if (plane_state)
+ i9xx_cursor_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state);
+ else
+ i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
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);
+ if (HAS_CUR_FBC(display))
+ intel_de_write_dsb(display, dsb, CUR_FBC_CTL(display, pipe), fbc_ctl);
+ intel_de_write_dsb(display, dsb, CURCNTR(display, pipe), cntl);
+ intel_de_write_dsb(display, dsb, CURPOS(display, pipe), pos);
+ intel_de_write_dsb(display, dsb, CURBASE(display, 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);
+ intel_de_write_dsb(display, dsb, CURPOS(display, pipe), pos);
+ intel_de_write_dsb(display, dsb, CURBASE(display, 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)
+static void i9xx_cursor_disable_arm(struct intel_dsb *dsb,
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
{
- i9xx_update_cursor(plane, crtc_state, NULL);
+ i9xx_cursor_update_arm(dsb, 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);
+ struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
intel_wakeref_t wakeref;
bool ret;
@@ -581,30 +737,63 @@ static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
* display power wells.
*/
power_domain = POWER_DOMAIN_PIPE(plane->pipe);
- wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+ wakeref = intel_display_power_get_if_enabled(display, power_domain);
if (!wakeref)
return false;
- val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
+ val = intel_de_read(display, CURCNTR(display, plane->pipe));
- ret = val & MCURSOR_MODE;
+ ret = val & MCURSOR_MODE_MASK;
- if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))
+ if (DISPLAY_VER(display) >= 5 || display->platform.g4x)
*pipe = plane->pipe;
else
- *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
- MCURSOR_PIPE_SELECT_SHIFT;
+ *pipe = REG_FIELD_GET(MCURSOR_PIPE_SEL_MASK, val);
- intel_display_power_put(dev_priv, power_domain, wakeref);
+ intel_display_power_put(display, power_domain, wakeref);
return ret;
}
+static void g4x_cursor_capture_error(struct intel_crtc *crtc,
+ struct intel_plane *plane,
+ struct intel_plane_error *error)
+{
+ struct intel_display *display = to_intel_display(plane);
+
+ error->ctl = intel_de_read(display, CURCNTR(display, crtc->pipe));
+ error->surf = intel_de_read(display, CURBASE(display, crtc->pipe));
+ error->surflive = intel_de_read(display, CURSURFLIVE(display, crtc->pipe));
+}
+
+static void i9xx_cursor_capture_error(struct intel_crtc *crtc,
+ struct intel_plane *plane,
+ struct intel_plane_error *error)
+{
+ struct intel_display *display = to_intel_display(plane);
+
+ error->ctl = intel_de_read(display, CURCNTR(display, crtc->pipe));
+ error->surf = intel_de_read(display, CURBASE(display, crtc->pipe));
+}
+
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;
+ if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
+ return false;
+
+ return format == DRM_FORMAT_ARGB8888;
+}
+
+void intel_cursor_unpin_work(struct kthread_work *base)
+{
+ struct drm_vblank_work *work = to_drm_vblank_work(base);
+ struct intel_plane_state *plane_state =
+ container_of(work, typeof(*plane_state), unpin_work);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+
+ intel_plane_unpin_fb(plane_state);
+ intel_plane_destroy_state(&plane->base, &plane_state->uapi);
}
static int
@@ -619,22 +808,29 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
{
struct intel_plane *plane = to_intel_plane(_plane);
struct intel_crtc *crtc = to_intel_crtc(_crtc);
+ struct intel_display *display = to_intel_display(plane);
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;
+ struct intel_vblank_evade_ctx evade;
int ret;
/*
* When crtc is inactive or there is a modeset pending,
- * wait for it to complete in the slowpath
+ * wait for it to complete in the slowpath.
+ * PSR2 selective fetch also requires the slow path as
+ * PSR2 plane and transcoder registers can only be updated during
+ * vblank.
*
- * FIXME bigjoiner fastpath would be good
+ * FIXME joiner fastpath would be good
*/
- if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) ||
- crtc_state->update_pipe || crtc_state->bigjoiner)
+ if (!crtc_state->hw.active ||
+ intel_crtc_needs_modeset(crtc_state) ||
+ intel_crtc_needs_fastset(crtc_state) ||
+ crtc_state->joiner_pipes)
goto slow;
/*
@@ -687,12 +883,12 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
if (ret)
goto out_free;
- ret = intel_plane_pin_fb(new_plane_state);
+ ret = intel_plane_pin_fb(new_plane_state, old_plane_state);
if (ret)
goto out_free;
intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
- ORIGIN_FLIP);
+ ORIGIN_CURSOR_UPDATE);
intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
to_intel_frontbuffer(new_plane_state->hw.fb),
plane->frontbuffer_bit);
@@ -712,19 +908,56 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
*/
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_vblank_evade_init(crtc_state, crtc_state, &evade);
+
+ intel_psr_lock(crtc_state);
- intel_plane_unpin_fb(old_plane_state);
+ if (!drm_WARN_ON(display->drm, drm_crtc_vblank_get(&crtc->base))) {
+ /*
+ * TODO: maybe check if we're still in PSR
+ * and skip the vblank evasion entirely?
+ */
+ intel_psr_wait_for_idle_locked(crtc_state);
+
+ local_irq_disable();
+
+ intel_vblank_evade(&evade);
+
+ drm_crtc_vblank_put(&crtc->base);
+ } else {
+ local_irq_disable();
+ }
+
+ if (new_plane_state->uapi.visible) {
+ intel_plane_update_noarm(NULL, plane, crtc_state, new_plane_state);
+ intel_plane_update_arm(NULL, plane, crtc_state, new_plane_state);
+ } else {
+ intel_plane_disable_arm(NULL, plane, crtc_state);
+ }
+
+ local_irq_enable();
+
+ intel_psr_unlock(crtc_state);
+
+ if (old_plane_state->ggtt_vma != new_plane_state->ggtt_vma) {
+ drm_vblank_work_init(&old_plane_state->unpin_work, &crtc->base,
+ intel_cursor_unpin_work);
+
+ drm_vblank_work_schedule(&old_plane_state->unpin_work,
+ drm_crtc_accurate_vblank_count(&crtc->base) + 1,
+ false);
+
+ old_plane_state = NULL;
+ } else {
+ 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
+ else if (old_plane_state)
intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
return ret;
@@ -743,12 +976,35 @@ static const struct drm_plane_funcs intel_cursor_plane_funcs = {
.format_mod_supported = intel_cursor_format_mod_supported,
};
+static void intel_cursor_add_size_hints_property(struct intel_plane *plane)
+{
+ struct intel_display *display = to_intel_display(plane);
+ const struct drm_mode_config *config = &display->drm->mode_config;
+ struct drm_plane_size_hint hints[4];
+ int size, max_size, num_hints = 0;
+
+ max_size = min(config->cursor_width, config->cursor_height);
+
+ /* for simplicity only enumerate the supported square+POT sizes */
+ for (size = 64; size <= max_size; size *= 2) {
+ if (drm_WARN_ON(display->drm, num_hints >= ARRAY_SIZE(hints)))
+ break;
+
+ hints[num_hints].width = size;
+ hints[num_hints].height = size;
+ num_hints++;
+ }
+
+ drm_plane_add_size_hints_property(&plane->base, hints, num_hints);
+}
+
struct intel_plane *
-intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+intel_cursor_plane_create(struct intel_display *display,
enum pipe pipe)
{
struct intel_plane *cursor;
int ret, zpos;
+ u64 *modifiers;
cursor = intel_plane_alloc();
if (IS_ERR(cursor))
@@ -759,49 +1015,75 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
cursor->id = PLANE_CURSOR;
cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
- if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+ if (display->platform.i845g || display->platform.i865g) {
cursor->max_stride = i845_cursor_max_stride;
- cursor->update_plane = i845_update_cursor;
- cursor->disable_plane = i845_disable_cursor;
+ cursor->min_alignment = i845_cursor_min_alignment;
+ cursor->update_arm = i845_cursor_update_arm;
+ cursor->disable_arm = i845_cursor_disable_arm;
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;
+
+ if (display->platform.i830)
+ cursor->min_alignment = i830_cursor_min_alignment;
+ else if (display->platform.i85x)
+ cursor->min_alignment = i85x_cursor_min_alignment;
+ else
+ cursor->min_alignment = i9xx_cursor_min_alignment;
+
+ if (intel_scanout_needs_vtd_wa(display))
+ cursor->vtd_guard = 2;
+
+ cursor->update_arm = i9xx_cursor_update_arm;
+ cursor->disable_arm = i9xx_cursor_disable_arm;
cursor->get_hw_state = i9xx_cursor_get_hw_state;
cursor->check_plane = i9xx_check_cursor;
}
+ cursor->surf_offset = intel_cursor_surf_offset;
+
+ if (DISPLAY_VER(display) >= 5 || display->platform.g4x)
+ cursor->capture_error = g4x_cursor_capture_error;
+ else
+ cursor->capture_error = i9xx_cursor_capture_error;
+
cursor->cursor.base = ~0;
cursor->cursor.cntl = ~0;
- if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
+ if (display->platform.i845g || display->platform.i865g || HAS_CUR_FBC(display))
cursor->cursor.size = ~0;
- ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
+ modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_NONE);
+
+ ret = drm_universal_plane_init(display->drm, &cursor->base,
0, &intel_cursor_plane_funcs,
intel_cursor_formats,
ARRAY_SIZE(intel_cursor_formats),
- cursor_format_modifiers,
+ modifiers,
DRM_PLANE_TYPE_CURSOR,
"cursor %c", pipe_name(pipe));
+
+ kfree(modifiers);
+
if (ret)
goto fail;
- if (DISPLAY_VER(dev_priv) >= 4)
+ if (DISPLAY_VER(display) >= 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;
+ intel_cursor_add_size_hints_property(cursor);
+
+ zpos = DISPLAY_RUNTIME_INFO(display)->num_sprites[pipe] + 1;
drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
- if (DISPLAY_VER(dev_priv) >= 12)
+ if (DISPLAY_VER(display) >= 12)
drm_plane_enable_fb_damage_clips(&cursor->base);
- drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
+ intel_plane_helper_add(cursor);
return cursor;
@@ -810,3 +1092,23 @@ fail:
return ERR_PTR(ret);
}
+
+void intel_cursor_mode_config_init(struct intel_display *display)
+{
+ struct drm_mode_config *mode_config = &display->drm->mode_config;
+
+ if (display->platform.i845g) {
+ mode_config->cursor_width = 64;
+ mode_config->cursor_height = 1023;
+ } else if (display->platform.i865g) {
+ mode_config->cursor_width = 512;
+ mode_config->cursor_height = 1023;
+ } else if (display->platform.i830 || display->platform.i85x ||
+ display->platform.i915g || display->platform.i915gm) {
+ mode_config->cursor_width = 64;
+ mode_config->cursor_height = 64;
+ } else {
+ mode_config->cursor_width = 256;
+ mode_config->cursor_height = 256;
+ }
+}