aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_psr.c
diff options
context:
space:
mode:
authorLinus Torvalds <[email protected]>2020-12-14 11:07:56 -0800
committerLinus Torvalds <[email protected]>2020-12-14 11:07:56 -0800
commit1d36dffa5d887715dacca0f717f4519b7be5e498 (patch)
treea68f7c00dbb3036a67806ed6c6b8cc61c3cff60d /drivers/gpu/drm/i915/display/intel_psr.c
parent2c85ebc57b3e1817b6ce1a6b703928e113a90442 (diff)
parentb10733527bfd864605c33ab2e9a886eec317ec39 (diff)
Merge tag 'drm-next-2020-12-11' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie: "Not a huge amount of big things here, AMD has support for a few new HW variants (vangogh, green sardine, dimgrey cavefish), Intel has some more DG1 enablement. We have a few big reworks of the TTM layers and interfaces, GEM and atomic internal API reworks cross tree. fbdev is marked orphaned in here as well to reflect the current reality. core: - documentation updates - deprecate DRM_FORMAT_MOD_NONE - atomic crtc enable/disable rework - GEM convert drivers to gem object functions - remove SCATTER_LIST_MAX_SEGMENT sched: - avoid infinite waits ttm: - remove AGP support - don't modify caching for swapout - ttm pinning rework - major TTM reworks - new backend allocator - multihop support vram-helper: - top down BO placement fix - TTM changes - GEM object support displayport: - DP 2.0 DPCD prep work - DP MST extended DPCD caps fbdev: - mark as orphaned amdgpu: - Initial Vangogh support - Green Sardine support - Dimgrey Cavefish support - SG display support for renoir - SMU7 improvements - gfx9+ modiifier support - CI BACO fixes radeon: - expose voltage via hwmon on SUMO amdkfd: - fix unique id handling i915: - more DG1 enablement - bigjoiner support - integer scaling filter support - async flip support - ICL+ DSI command mode - Improve display shutdown - Display refactoring - eLLC machine fbdev loading fix - dma scatterlist fixes - TGL hang fixes - eLLC display buffer caching on SKL+ - MOCS PTE seeting for gen9+ msm: - Shutdown hook - GPU cooling device support - DSI 7nm and 10nm phy/pll updates - sm8150/sm2850 DPU support - GEM locking re-work - LLCC system cache support aspeed: - sysfs output config support ast: - LUT fix - new display mode gma500: - remove 2d framebuffer accel panfrost: - move gpu reset to a worker exynos: - new HDMI mode support mediatek: - MT8167 support - yaml bindings - MIPI DSI phy code moved etnaviv: - new perf counter - more lockdep annotation hibmc: - i2c DDC support ingenic: - pixel clock reset fix - reserved memory support - allow both DMA channels at once - different pixel format support - 30/24/8-bit palette modes tilcdc: - don't keep vblank irq enabled vc4: - new maintainer added - DSI registration fix virtio: - blob resource support - host visible and cross-device support - uuid api support" * tag 'drm-next-2020-12-11' of git://anongit.freedesktop.org/drm/drm: (1754 commits) drm/amdgpu: Initialise drm_gem_object_funcs for imported BOs drm/amdgpu: fix size calculation with stolen vga memory drm/amdgpu: remove amdgpu_ttm_late_init and amdgpu_bo_late_init drm/amdgpu: free the pre-OS console framebuffer after the first modeset drm/amdgpu: enable runtime pm using BACO on CI dGPUs drm/amdgpu/cik: enable BACO reset on Bonaire drm/amd/pm: update smu10.h WORKLOAD_PPLIB setting for raven drm/amd/pm: remove one unsupported smu function for vangogh drm/amd/display: setup system context for APUs drm/amd/display: add S/G support for Vangogh drm/amdkfd: Fix leak in dmabuf import drm/amdgpu: use AMDGPU_NUM_VMID when possible drm/amdgpu: fix sdma instance fw version and feature version init drm/amd/pm: update driver if version for dimgrey_cavefish drm/amd/display: 3.2.115 drm/amd/display: [FW Promotion] Release 0.0.45 drm/amd/display: Revert DCN2.1 dram_clock_change_latency update drm/amd/display: Enable gpu_vm_support for dcn3.01 drm/amd/display: Fixed the audio noise during mode switching with HDCP mode on drm/amd/display: Add wm table for Renoir ...
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_psr.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c249
1 files changed, 169 insertions, 80 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 40e9cb29233d..b3631b722de3 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -91,19 +91,14 @@ static bool psr_global_enabled(struct drm_i915_private *i915)
}
}
-static bool intel_psr2_enabled(struct drm_i915_private *dev_priv,
- const struct intel_crtc_state *crtc_state)
+static bool psr2_global_enabled(struct drm_i915_private *dev_priv)
{
- /* Cannot enable DSC and PSR2 simultaneously */
- drm_WARN_ON(&dev_priv->drm, crtc_state->dsc.compression_enable &&
- crtc_state->has_psr2);
-
switch (dev_priv->psr.debug & I915_PSR_DEBUG_MODE_MASK) {
case I915_PSR_DEBUG_DISABLE:
case I915_PSR_DEBUG_FORCE_PSR1:
return false;
default:
- return crtc_state->has_psr2;
+ return true;
}
}
@@ -729,6 +724,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
return false;
}
+ if (!psr2_global_enabled(dev_priv)) {
+ drm_dbg_kms(&dev_priv->drm, "PSR2 disabled by flag\n");
+ return false;
+ }
+
/*
* DSC and PSR2 cannot be enabled simultaneously. If a requested
* resolution requires DSC to be enabled, priority is given to DSC
@@ -817,8 +817,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
if (intel_dp != dev_priv->psr.dp)
return;
- if (!psr_global_enabled(dev_priv))
+ if (!psr_global_enabled(dev_priv)) {
+ drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
return;
+ }
+
/*
* HSW spec explicitly says PSR is tied to port A.
* BDW+ platforms have a instance of PSR registers per transcoder but
@@ -942,7 +945,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
intel_de_write(dev_priv, EXITLINE(cpu_transcoder), val);
}
- if (HAS_PSR_HW_TRACKING(dev_priv))
+ if (HAS_PSR_HW_TRACKING(dev_priv) && HAS_PSR2_SEL_FETCH(dev_priv))
intel_de_rmw(dev_priv, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING,
dev_priv->psr.psr2_sel_fetch_enabled ?
IGNORE_PSR2_HW_TRACKING : 0);
@@ -959,7 +962,7 @@ static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
drm_WARN_ON(&dev_priv->drm, dev_priv->psr.enabled);
- dev_priv->psr.psr2_enabled = intel_psr2_enabled(dev_priv, crtc_state);
+ dev_priv->psr.psr2_enabled = crtc_state->has_psr2;
dev_priv->psr.busy_frontbuffer_bits = 0;
dev_priv->psr.pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
dev_priv->psr.dc3co_enabled = !!crtc_state->dc3co_exitline;
@@ -1021,23 +1024,13 @@ void intel_psr_enable(struct intel_dp *intel_dp,
if (!CAN_PSR(dev_priv) || dev_priv->psr.dp != intel_dp)
return;
- dev_priv->psr.force_mode_changed = false;
-
if (!crtc_state->has_psr)
return;
drm_WARN_ON(&dev_priv->drm, dev_priv->drrs.dp);
mutex_lock(&dev_priv->psr.lock);
-
- if (!psr_global_enabled(dev_priv)) {
- drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
- goto unlock;
- }
-
intel_psr_enable_locked(dev_priv, crtc_state, conn_state);
-
-unlock:
mutex_unlock(&dev_priv->psr.lock);
}
@@ -1152,7 +1145,21 @@ void intel_psr_disable(struct intel_dp *intel_dp,
static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 9)
+ if (IS_TIGERLAKE(dev_priv))
+ /*
+ * Writes to CURSURFLIVE in TGL are causing IOMMU errors and
+ * visual glitches that are often reproduced when executing
+ * CPU intensive workloads while a eDP 4K panel is attached.
+ *
+ * Manually exiting PSR causes the frontbuffer to be updated
+ * without glitches and the IOMMU errors are also gone but
+ * this comes at the cost of less time with PSR active.
+ *
+ * So using this workaround until this issue is root caused
+ * and a better fix is found.
+ */
+ intel_psr_exit(dev_priv);
+ else if (INTEL_GEN(dev_priv) >= 9)
/*
* Display WA #0884: skl+
* This documented WA for bxt can be safely applied
@@ -1171,6 +1178,38 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv)
intel_psr_exit(dev_priv);
}
+void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state,
+ int color_plane)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ enum pipe pipe = plane->pipe;
+ u32 val;
+
+ if (!crtc_state->enable_psr2_sel_fetch)
+ return;
+
+ val = plane_state ? plane_state->ctl : 0;
+ val &= plane->id == PLANE_CURSOR ? val : PLANE_SEL_FETCH_CTL_ENABLE;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), val);
+ if (!val || plane->id == PLANE_CURSOR)
+ return;
+
+ val = plane_state->uapi.dst.y1 << 16 | plane_state->uapi.dst.x1;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_POS(pipe, plane->id), val);
+
+ val = plane_state->color_plane[color_plane].y << 16;
+ val |= plane_state->color_plane[color_plane].x;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_OFFSET(pipe, plane->id),
+ val);
+
+ /* Sizes are 0 based */
+ val = ((drm_rect_height(&plane_state->uapi.src) >> 16) - 1) << 16;
+ val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val);
+}
+
void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -1185,16 +1224,91 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st
crtc_state->psr2_man_track_ctl);
}
-void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
+static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
+ struct drm_rect *clip, bool full_update)
+{
+ u32 val = PSR2_MAN_TRK_CTL_ENABLE;
+
+ if (full_update) {
+ val |= PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
+ goto exit;
+ }
+
+ if (clip->y1 == -1)
+ goto exit;
+
+ val |= PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE;
+ val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1 / 4 + 1);
+ val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(DIV_ROUND_UP(clip->y2, 4) + 1);
+exit:
+ crtc_state->psr2_man_track_ctl = val;
+}
+
+static void clip_area_update(struct drm_rect *overlap_damage_area,
+ struct drm_rect *damage_area)
+{
+ if (overlap_damage_area->y1 == -1) {
+ overlap_damage_area->y1 = damage_area->y1;
+ overlap_damage_area->y2 = damage_area->y2;
+ return;
+ }
+
+ if (damage_area->y1 < overlap_damage_area->y1)
+ overlap_damage_area->y1 = damage_area->y1;
+
+ if (damage_area->y2 > overlap_damage_area->y2)
+ overlap_damage_area->y2 = damage_area->y2;
+}
+
+int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
+ struct intel_plane_state *new_plane_state, *old_plane_state;
+ struct drm_rect pipe_clip = { .y1 = -1 };
+ struct intel_plane *plane;
+ bool full_update = false;
+ int i, ret;
if (!crtc_state->enable_psr2_sel_fetch)
- return;
+ return 0;
- crtc_state->psr2_man_track_ctl = PSR2_MAN_TRK_CTL_ENABLE |
- PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
+ ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
+ if (ret)
+ return ret;
+
+ for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
+ new_plane_state, i) {
+ struct drm_rect temp;
+
+ if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+ continue;
+
+ /*
+ * TODO: Not clear how to handle planes with negative position,
+ * also planes are not updated if they have a negative X
+ * position so for now doing a full update in this cases
+ */
+ if (new_plane_state->uapi.dst.y1 < 0 ||
+ new_plane_state->uapi.dst.x1 < 0) {
+ full_update = true;
+ break;
+ }
+
+ if (!new_plane_state->uapi.visible)
+ continue;
+
+ /*
+ * For now doing a selective fetch in the whole plane area,
+ * optimizations will come in the future.
+ */
+ temp.y1 = new_plane_state->uapi.dst.y1;
+ temp.y2 = new_plane_state->uapi.dst.y2;
+ clip_area_update(&pipe_clip, &temp);
+ }
+
+ psr2_man_trk_ctl_calc(crtc_state, &pipe_clip, full_update);
+ return 0;
}
/**
@@ -1218,12 +1332,10 @@ void intel_psr_update(struct intel_dp *intel_dp,
if (!CAN_PSR(dev_priv) || READ_ONCE(psr->dp) != intel_dp)
return;
- dev_priv->psr.force_mode_changed = false;
-
mutex_lock(&dev_priv->psr.lock);
- enable = crtc_state->has_psr && psr_global_enabled(dev_priv);
- psr2_enable = intel_psr2_enabled(dev_priv, crtc_state);
+ enable = crtc_state->has_psr;
+ psr2_enable = crtc_state->has_psr2;
if (enable == psr->enabled && psr2_enable == psr->psr2_enabled) {
/* Force a PSR exit when enabling CRC to avoid CRC timeouts */
@@ -1320,11 +1432,12 @@ static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv)
static int intel_psr_fastset_force(struct drm_i915_private *dev_priv)
{
+ struct drm_connector_list_iter conn_iter;
struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx ctx;
struct drm_atomic_state *state;
- struct intel_crtc *crtc;
- int err;
+ struct drm_connector *conn;
+ int err = 0;
state = drm_atomic_state_alloc(dev);
if (!state)
@@ -1334,25 +1447,38 @@ static int intel_psr_fastset_force(struct drm_i915_private *dev_priv)
state->acquire_ctx = &ctx;
retry:
- for_each_intel_crtc(dev, crtc) {
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- err = PTR_ERR(crtc_state);
- goto error;
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(conn, &conn_iter) {
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+
+ if (conn->connector_type != DRM_MODE_CONNECTOR_eDP)
+ continue;
+
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ if (IS_ERR(conn_state)) {
+ err = PTR_ERR(conn_state);
+ break;
}
- if (crtc_state->hw.active && crtc_state->has_psr) {
- /* Mark mode as changed to trigger a pipe->update() */
- crtc_state->uapi.mode_changed = true;
+ if (!conn_state->crtc)
+ continue;
+
+ crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
+ if (IS_ERR(crtc_state)) {
+ err = PTR_ERR(crtc_state);
break;
}
+
+ /* Mark mode as changed to trigger a pipe->update() */
+ crtc_state->mode_changed = true;
}
+ drm_connector_list_iter_end(&conn_iter);
- err = drm_atomic_commit(state);
+ if (err == 0)
+ err = drm_atomic_commit(state);
-error:
if (err == -EDEADLK) {
drm_atomic_state_clear(state);
err = drm_modeset_backoff(&ctx);
@@ -1739,40 +1865,3 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
return ret;
}
-
-void intel_psr_atomic_check(struct drm_connector *connector,
- struct drm_connector_state *old_state,
- struct drm_connector_state *new_state)
-{
- struct drm_i915_private *dev_priv = to_i915(connector->dev);
- struct intel_connector *intel_connector;
- struct intel_digital_port *dig_port;
- struct drm_crtc_state *crtc_state;
-
- if (!CAN_PSR(dev_priv) || !new_state->crtc ||
- !dev_priv->psr.force_mode_changed)
- return;
-
- intel_connector = to_intel_connector(connector);
- dig_port = enc_to_dig_port(to_intel_encoder(new_state->best_encoder));
- if (dev_priv->psr.dp != &dig_port->dp)
- return;
-
- crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
- new_state->crtc);
- crtc_state->mode_changed = true;
-}
-
-void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp)
-{
- struct drm_i915_private *dev_priv;
-
- if (!intel_dp)
- return;
-
- dev_priv = dp_to_i915(intel_dp);
- if (!CAN_PSR(dev_priv) || intel_dp != dev_priv->psr.dp)
- return;
-
- dev_priv->psr.force_mode_changed = true;
-}