summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-14 11:07:56 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-14 11:07:56 -0800
commit1d36dffa5d887715dacca0f717f4519b7be5e498 (patch)
treea68f7c00dbb3036a67806ed6c6b8cc61c3cff60d /drivers/gpu/drm/i915
parent2c85ebc57b3e1817b6ce1a6b703928e113a90442 (diff)
parentb10733527bfd864605c33ab2e9a886eec317ec39 (diff)
downloadlinux-1d36dffa5d887715dacca0f717f4519b7be5e498.tar.bz2
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')
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi.c79
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.c138
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c58
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c52
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.c124
-rw-r--r--drivers/gpu/drm/i915/display/intel_combo_phy.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_csr.c12
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c1009
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c1689
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.h43
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c39
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c116
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h140
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c798
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h23
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c554
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.h17
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c40
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.c23
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c221
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h28
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c15
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp.c89
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c20
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.c64
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_lspcon.c97
-rw-r--r--drivers/gpu/drm/i915/display/intel_lspcon.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_lvds.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c249
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.h14
-rw-r--r--drivers/gpu/drm/i915/display/intel_sprite.c235
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_vbt_defs.h13
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.c201
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.h6
-rw-r--r--drivers/gpu/drm/i915/display/vlv_dsi.c8
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_client_blt.c18
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c13
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.c23
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.h23
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object_types.h17
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_pages.c21
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_stolen.c48
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c18
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c14
-rw-r--r--drivers/gpu/drm/i915/gt/gen6_ppgtt.c6
-rw-r--r--drivers/gpu/drm/i915/gt/gen8_ppgtt.c17
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_cs.c39
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_pm.c37
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt.c6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt.c11
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gtt.c10
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gtt.h2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.c129
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.h4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc_reg.h3
-rw-r--r--drivers/gpu/drm/i915/gt/intel_mocs.c45
-rw-r--r--drivers/gpu/drm/i915/gt/intel_reset.c8
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ring_submission.c1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.c58
-rw-r--r--drivers/gpu/drm/i915/gt/intel_sseu.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_workarounds.c143
-rw-r--r--drivers/gpu/drm/i915/gt/mock_engine.c29
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c13
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_rps.c8
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_timeline.c378
-rw-r--r--drivers/gpu/drm/i915/gt/sysfs_engines.c10
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.c24
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c132
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c1
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c31
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h80
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h5
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc.c6
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c28
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h2
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h6
-rw-r--r--drivers/gpu/drm/i915/gvt/display.c194
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.c64
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.h4
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.c13
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.h5
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c58
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.c5
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.h4
-rw-r--r--drivers/gpu/drm/i915/gvt/mpt.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/reg.h4
-rw-r--r--drivers/gpu/drm/i915/gvt/vgpu.c2
-rw-r--r--drivers/gpu/drm/i915/i915_cmd_parser.c67
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c74
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h17
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c68
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.h10
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c810
-rw-r--r--drivers/gpu/drm/i915/i915_irq.h3
-rw-r--r--drivers/gpu/drm/i915/i915_pci.c28
-rw-r--r--drivers/gpu/drm/i915/i915_perf.c8
-rw-r--r--drivers/gpu/drm/i915/i915_pmu.c96
-rw-r--r--drivers/gpu/drm/i915/i915_pmu.h10
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h454
-rw-r--r--drivers/gpu/drm/i915/i915_scatterlist.h19
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c80
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.h4
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.c1
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.h1
-rw-r--r--drivers/gpu/drm/i915/intel_dram.c23
-rw-r--r--drivers/gpu/drm/i915/intel_gvt.c15
-rw-r--r--drivers/gpu/drm/i915/intel_gvt.h5
-rw-r--r--drivers/gpu/drm/i915/intel_memory_region.c2
-rw-r--r--drivers/gpu/drm/i915/intel_pch.c6
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c309
-rw-r--r--drivers/gpu/drm/i915/intel_pm.h2
-rw-r--r--drivers/gpu/drm/i915/intel_sideband.c15
-rw-r--r--drivers/gpu/drm/i915/intel_sideband.h2
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c207
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.h4
-rw-r--r--drivers/gpu/drm/i915/selftests/mock_gem_device.c5
133 files changed, 7438 insertions, 3056 deletions
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index 520715b7d5b5..a9439b415603 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -205,6 +205,32 @@ static int dsi_send_pkt_payld(struct intel_dsi_host *host,
return 0;
}
+void icl_dsi_frame_update(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 tmp, mode_flags;
+ enum port port;
+
+ mode_flags = crtc_state->mode_flags;
+
+ /*
+ * case 1 also covers dual link
+ * In case of dual link, frame update should be set on
+ * DSI_0
+ */
+ if (mode_flags & I915_MODE_FLAG_DSI_USE_TE0)
+ port = PORT_A;
+ else if (mode_flags & I915_MODE_FLAG_DSI_USE_TE1)
+ port = PORT_B;
+ else
+ return;
+
+ tmp = intel_de_read(dev_priv, DSI_CMD_FRMCTL(port));
+ tmp |= DSI_FRAME_UPDATE_REQUEST;
+ intel_de_write(dev_priv, DSI_CMD_FRMCTL(port), tmp);
+}
+
static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -429,7 +455,7 @@ static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
intel_de_write(dev_priv, ICL_PORT_TX_DW2_GRP(phy), tmp);
/* For EHL, TGL, set latency optimization for PCS_DW1 lanes */
- if (IS_ELKHARTLAKE(dev_priv) || (INTEL_GEN(dev_priv) >= 12)) {
+ if (IS_JSL_EHL(dev_priv) || (INTEL_GEN(dev_priv) >= 12)) {
tmp = intel_de_read(dev_priv,
ICL_PORT_PCS_DW1_AUX(phy));
tmp &= ~LATENCY_OPTIM_MASK;
@@ -586,7 +612,7 @@ gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder,
}
}
- if (IS_ELKHARTLAKE(dev_priv)) {
+ if (IS_JSL_EHL(dev_priv)) {
for_each_dsi_phy(phy, intel_dsi->phys) {
tmp = intel_de_read(dev_priv, ICL_DPHY_CHKN(phy));
tmp |= ICL_DPHY_CHKN_AFE_OVER_PPI_STRAP;
@@ -1447,6 +1473,18 @@ static bool gen11_dsi_is_periodic_cmd_mode(struct intel_dsi *intel_dsi)
return (val & DSI_PERIODIC_FRAME_UPDATE_ENABLE);
}
+static void gen11_dsi_get_cmd_mode_config(struct intel_dsi *intel_dsi,
+ struct intel_crtc_state *pipe_config)
+{
+ if (intel_dsi->ports == (BIT(PORT_B) | BIT(PORT_A)))
+ pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE1 |
+ I915_MODE_FLAG_DSI_USE_TE0;
+ else if (intel_dsi->ports == BIT(PORT_B))
+ pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE1;
+ else
+ pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE0;
+}
+
static void gen11_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
@@ -1454,11 +1492,10 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- intel_dsc_get_config(encoder, pipe_config);
-
/* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */
pipe_config->port_clock = intel_dpll_get_freq(i915,
- pipe_config->shared_dpll);
+ pipe_config->shared_dpll,
+ &pipe_config->dpll_hw_state);
pipe_config->hw.adjusted_mode.crtc_clock = intel_dsi->pclk;
if (intel_dsi->dual_link)
@@ -1468,6 +1505,10 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
+ /* Get the details on which TE should be enabled */
+ if (is_cmd_mode(intel_dsi))
+ gen11_dsi_get_cmd_mode_config(intel_dsi, pipe_config);
+
if (gen11_dsi_is_periodic_cmd_mode(intel_dsi))
pipe_config->mode_flags |= I915_MODE_FLAG_DSI_PERIODIC_CMD_MODE;
}
@@ -1562,18 +1603,8 @@ static int gen11_dsi_compute_config(struct intel_encoder *encoder,
* receive TE from the slave if
* dual link is enabled
*/
- if (is_cmd_mode(intel_dsi)) {
- if (intel_dsi->ports == (BIT(PORT_B) | BIT(PORT_A)))
- pipe_config->mode_flags |=
- I915_MODE_FLAG_DSI_USE_TE1 |
- I915_MODE_FLAG_DSI_USE_TE0;
- else if (intel_dsi->ports == BIT(PORT_B))
- pipe_config->mode_flags |=
- I915_MODE_FLAG_DSI_USE_TE1;
- else
- pipe_config->mode_flags |=
- I915_MODE_FLAG_DSI_USE_TE0;
- }
+ if (is_cmd_mode(intel_dsi))
+ gen11_dsi_get_cmd_mode_config(intel_dsi, pipe_config);
return 0;
}
@@ -1636,6 +1667,19 @@ out:
return ret;
}
+static bool gen11_dsi_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->dsc.compression_enable) {
+ drm_dbg_kms(encoder->base.dev, "Forcing full modeset due to DSC being enabled\n");
+ crtc_state->uapi.mode_changed = true;
+
+ return false;
+ }
+
+ return true;
+}
+
static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
{
intel_encoder_destroy(encoder);
@@ -1891,6 +1935,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
encoder->update_pipe = intel_panel_update_backlight;
encoder->compute_config = gen11_dsi_compute_config;
encoder->get_hw_state = gen11_dsi_get_hw_state;
+ encoder->initial_fastset_check = gen11_dsi_initial_fastset_check;
encoder->type = INTEL_OUTPUT_DSI;
encoder->cloneable = 0;
encoder->pipe_mask = ~0;
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 86be032bcf96..e00fdc47c0eb 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -133,7 +133,6 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
struct drm_crtc_state *crtc_state;
intel_hdcp_atomic_check(conn, old_state, new_state);
- intel_psr_atomic_check(conn, old_state, new_state);
if (!new_state->crtc)
return 0;
@@ -270,14 +269,15 @@ void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state)
intel_crtc_put_color_blobs(crtc_state);
}
-void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state)
+void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state,
+ const struct intel_crtc_state *from_crtc_state)
{
drm_property_replace_blob(&crtc_state->hw.degamma_lut,
- crtc_state->uapi.degamma_lut);
+ from_crtc_state->uapi.degamma_lut);
drm_property_replace_blob(&crtc_state->hw.gamma_lut,
- crtc_state->uapi.gamma_lut);
+ from_crtc_state->uapi.gamma_lut);
drm_property_replace_blob(&crtc_state->hw.ctm,
- crtc_state->uapi.ctm);
+ from_crtc_state->uapi.ctm);
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.h b/drivers/gpu/drm/i915/display/intel_atomic.h
index 285de07011dc..62a3365ed5e6 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.h
+++ b/drivers/gpu/drm/i915/display/intel_atomic.h
@@ -43,7 +43,8 @@ struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
void intel_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state);
-void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state);
+void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state,
+ const struct intel_crtc_state *from_crtc_state);
struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev);
void intel_atomic_state_free(struct drm_atomic_state *state);
void intel_atomic_state_clear(struct drm_atomic_state *state);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index 79032701873a..7e9f84b00859 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -247,11 +247,19 @@ static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
}
void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
- const struct intel_plane_state *from_plane_state)
+ const struct intel_plane_state *from_plane_state,
+ struct intel_crtc *crtc)
{
intel_plane_clear_hw_state(plane_state);
- plane_state->hw.crtc = from_plane_state->uapi.crtc;
+ /*
+ * For the bigjoiner slave uapi.crtc will point at
+ * the master crtc. So we explicitly assign the right
+ * slave crtc to hw.crtc. uapi.crtc!=NULL simply indicates
+ * the plane is logically enabled on the uapi level.
+ */
+ plane_state->hw.crtc = from_plane_state->uapi.crtc ? &crtc->base : NULL;
+
plane_state->hw.fb = from_plane_state->uapi.fb;
if (plane_state->hw.fb)
drm_framebuffer_get(plane_state->hw.fb);
@@ -262,6 +270,22 @@ void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
plane_state->hw.rotation = from_plane_state->uapi.rotation;
plane_state->hw.color_encoding = from_plane_state->uapi.color_encoding;
plane_state->hw.color_range = from_plane_state->uapi.color_range;
+ plane_state->hw.scaling_filter = from_plane_state->uapi.scaling_filter;
+
+ plane_state->uapi.src = drm_plane_state_src(&from_plane_state->uapi);
+ plane_state->uapi.dst = drm_plane_state_dest(&from_plane_state->uapi);
+}
+
+void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
+ const struct intel_plane_state *from_plane_state)
+{
+ intel_plane_clear_hw_state(plane_state);
+
+ memcpy(&plane_state->hw, &from_plane_state->hw,
+ sizeof(plane_state->hw));
+
+ if (plane_state->hw.fb)
+ drm_framebuffer_get(plane_state->hw.fb);
}
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
@@ -318,15 +342,16 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
old_plane_state, new_plane_state);
}
-static struct intel_crtc *
-get_crtc_from_states(const struct intel_plane_state *old_plane_state,
- const struct intel_plane_state *new_plane_state)
+static struct intel_plane *
+intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id)
{
- if (new_plane_state->uapi.crtc)
- return to_intel_crtc(new_plane_state->uapi.crtc);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_plane *plane;
- if (old_plane_state->uapi.crtc)
- return to_intel_crtc(old_plane_state->uapi.crtc);
+ for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) {
+ if (plane->id == plane_id)
+ return plane;
+ }
return NULL;
}
@@ -334,23 +359,37 @@ get_crtc_from_states(const struct intel_plane_state *old_plane_state,
int intel_plane_atomic_check(struct intel_atomic_state *state,
struct intel_plane *plane)
{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
struct intel_plane_state *new_plane_state =
intel_atomic_get_new_plane_state(state, plane);
const struct intel_plane_state *old_plane_state =
intel_atomic_get_old_plane_state(state, plane);
- struct intel_crtc *crtc =
- get_crtc_from_states(old_plane_state, new_plane_state);
- const struct intel_crtc_state *old_crtc_state;
- struct intel_crtc_state *new_crtc_state;
+ const struct intel_plane_state *new_master_plane_state;
+ struct intel_crtc *crtc = intel_get_crtc_for_pipe(i915, plane->pipe);
+ const struct intel_crtc_state *old_crtc_state =
+ intel_atomic_get_old_crtc_state(state, crtc);
+ struct intel_crtc_state *new_crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+
+ if (new_crtc_state && new_crtc_state->bigjoiner_slave) {
+ struct intel_plane *master_plane =
+ intel_crtc_get_plane(new_crtc_state->bigjoiner_linked_crtc,
+ plane->id);
+
+ new_master_plane_state =
+ intel_atomic_get_new_plane_state(state, master_plane);
+ } else {
+ new_master_plane_state = new_plane_state;
+ }
+
+ intel_plane_copy_uapi_to_hw_state(new_plane_state,
+ new_master_plane_state,
+ crtc);
- intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state);
new_plane_state->uapi.visible = false;
- if (!crtc)
+ if (!new_crtc_state)
return 0;
- old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
- new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
-
return intel_plane_atomic_check_with_state(old_crtc_state,
new_crtc_state,
old_plane_state,
@@ -408,7 +447,11 @@ void intel_update_plane(struct intel_plane *plane,
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
trace_intel_update_plane(&plane->base, crtc);
- plane->update_plane(plane, crtc_state, plane_state);
+
+ if (crtc_state->uapi.async_flip && plane->async_flip)
+ plane->async_flip(plane, crtc_state, plane_state);
+ else
+ plane->update_plane(plane, crtc_state, plane_state);
}
void intel_disable_plane(struct intel_plane *plane,
@@ -474,6 +517,63 @@ void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
}
}
+int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
+ struct intel_crtc_state *crtc_state,
+ int min_scale, int max_scale,
+ bool can_position)
+{
+ struct drm_framebuffer *fb = plane_state->hw.fb;
+ struct drm_rect *src = &plane_state->uapi.src;
+ struct drm_rect *dst = &plane_state->uapi.dst;
+ unsigned int rotation = plane_state->hw.rotation;
+ struct drm_rect clip = {};
+ int hscale, vscale;
+
+ if (!fb) {
+ plane_state->uapi.visible = false;
+ return 0;
+ }
+
+ drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
+
+ /* Check scaling */
+ hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
+ vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
+ if (hscale < 0 || vscale < 0) {
+ DRM_DEBUG_KMS("Invalid scaling of plane\n");
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
+ return -ERANGE;
+ }
+
+ if (crtc_state->hw.enable) {
+ clip.x2 = crtc_state->pipe_src_w;
+ clip.y2 = crtc_state->pipe_src_h;
+ }
+
+ /* right side of the image is on the slave crtc, adjust dst to match */
+ if (crtc_state->bigjoiner_slave)
+ drm_rect_translate(dst, -crtc_state->pipe_src_w, 0);
+
+ /*
+ * FIXME: This might need further adjustment for seamless scaling
+ * with phase information, for the 2p2 and 2p1 scenarios.
+ */
+ plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, &clip);
+
+ drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
+
+ if (!can_position && plane_state->uapi.visible &&
+ !drm_rect_equals(dst, &clip)) {
+ DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
+ drm_rect_debug_print("dst: ", dst, false);
+ drm_rect_debug_print("clip: ", &clip, false);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
.prepare_fb = intel_prepare_plane_fb,
.cleanup_fb = intel_cleanup_plane_fb,
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
index 59dd1fbb02ea..5c78a087ed86 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
@@ -24,7 +24,10 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
- const struct intel_plane_state *from_plane_state);
+ const struct intel_plane_state *from_plane_state,
+ struct intel_crtc *crtc);
+void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
+ const struct intel_plane_state *from_plane_state);
void intel_update_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
@@ -52,6 +55,10 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
struct intel_plane *plane,
bool *need_cdclk_calc);
+int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
+ struct intel_crtc_state *crtc_state,
+ int min_scale, int max_scale,
+ bool can_position);
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state);
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 4716484af62d..4cc949b228f2 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -425,6 +425,7 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv,
const struct bdb_lfp_backlight_data *backlight_data;
const struct lfp_backlight_data_entry *entry;
int panel_type = dev_priv->vbt.panel_type;
+ u16 level;
backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
if (!backlight_data)
@@ -459,14 +460,39 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv,
dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;
- dev_priv->vbt.backlight.min_brightness = entry->min_brightness;
+
+ if (bdb->version >= 234) {
+ u16 min_level;
+ bool scale;
+
+ level = backlight_data->brightness_level[panel_type].level;
+ min_level = backlight_data->brightness_min_level[panel_type].level;
+
+ if (bdb->version >= 236)
+ scale = backlight_data->brightness_precision_bits[panel_type] == 16;
+ else
+ scale = level > 255;
+
+ if (scale)
+ min_level = min_level / 255;
+
+ if (min_level > 255) {
+ drm_warn(&dev_priv->drm, "Brightness min level > 255\n");
+ level = 255;
+ }
+ dev_priv->vbt.backlight.min_brightness = min_level;
+ } else {
+ level = backlight_data->level[panel_type];
+ dev_priv->vbt.backlight.min_brightness = entry->min_brightness;
+ }
+
drm_dbg_kms(&dev_priv->drm,
"VBT backlight PWM modulation frequency %u Hz, "
"active %s, min brightness %u, level %u, controller %u\n",
dev_priv->vbt.backlight.pwm_freq_hz,
dev_priv->vbt.backlight.active_low_pwm ? "low" : "high",
dev_priv->vbt.backlight.min_brightness,
- backlight_data->level[panel_type],
+ level,
dev_priv->vbt.backlight.controller);
}
@@ -1602,7 +1628,9 @@ static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin)
const u8 *ddc_pin_map;
int n_entries;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) {
+ return vbt_pin;
+ } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
ddc_pin_map = icp_ddc_pin_map;
n_entries = ARRAY_SIZE(icp_ddc_pin_map);
} else if (HAS_PCH_CNP(dev_priv)) {
@@ -1660,20 +1688,18 @@ static enum port dvo_port_to_port(struct drm_i915_private *dev_priv,
[PORT_I] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 },
};
/*
- * Bspec lists the ports as A, B, C, D - however internally in our
- * driver we keep them as PORT_A, PORT_B, PORT_D and PORT_E so the
- * registers in Display Engine match the right offsets. Apply the
- * mapping here to translate from VBT to internal convention.
+ * RKL VBT uses PHY based mapping. Combo PHYs A,B,C,D
+ * map to DDI A,B,TC1,TC2 respectively.
*/
static const int rkl_port_mapping[][3] = {
[PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 },
[PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 },
[PORT_C] = { -1 },
- [PORT_D] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
- [PORT_E] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
+ [PORT_TC1] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
+ [PORT_TC2] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
};
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
return __dvo_port_to_port(ARRAY_SIZE(rkl_port_mapping),
ARRAY_SIZE(rkl_port_mapping[0]),
rkl_port_mapping,
@@ -1889,7 +1915,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
expected_size = 37;
} else if (bdb->version <= 215) {
expected_size = 38;
- } else if (bdb->version <= 229) {
+ } else if (bdb->version <= 237) {
expected_size = 39;
} else {
expected_size = sizeof(*child);
@@ -2638,10 +2664,16 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv,
aux_ch = AUX_CH_B;
break;
case DP_AUX_C:
- aux_ch = IS_ROCKETLAKE(dev_priv) ? AUX_CH_D : AUX_CH_C;
+ /*
+ * RKL/DG1 VBT uses PHY based mapping. Combo PHYs A,B,C,D
+ * map to DDI A,B,TC1,TC2 respectively.
+ */
+ aux_ch = (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) ?
+ AUX_CH_USBC1 : AUX_CH_C;
break;
case DP_AUX_D:
- aux_ch = IS_ROCKETLAKE(dev_priv) ? AUX_CH_E : AUX_CH_D;
+ aux_ch = (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) ?
+ AUX_CH_USBC2 : AUX_CH_D;
break;
case DP_AUX_E:
aux_ch = AUX_CH_E;
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index cb93f6cf6d37..c449d28d0560 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -1233,6 +1233,30 @@ static const struct intel_cdclk_vals icl_cdclk_table[] = {
{}
};
+static const struct intel_cdclk_vals rkl_cdclk_table[] = {
+ { .refclk = 19200, .cdclk = 172800, .divider = 4, .ratio = 36 },
+ { .refclk = 19200, .cdclk = 192000, .divider = 4, .ratio = 40 },
+ { .refclk = 19200, .cdclk = 307200, .divider = 4, .ratio = 64 },
+ { .refclk = 19200, .cdclk = 326400, .divider = 8, .ratio = 136 },
+ { .refclk = 19200, .cdclk = 556800, .divider = 4, .ratio = 116 },
+ { .refclk = 19200, .cdclk = 652800, .divider = 4, .ratio = 136 },
+
+ { .refclk = 24000, .cdclk = 180000, .divider = 4, .ratio = 30 },
+ { .refclk = 24000, .cdclk = 192000, .divider = 4, .ratio = 32 },
+ { .refclk = 24000, .cdclk = 312000, .divider = 4, .ratio = 52 },
+ { .refclk = 24000, .cdclk = 324000, .divider = 8, .ratio = 108 },
+ { .refclk = 24000, .cdclk = 552000, .divider = 4, .ratio = 92 },
+ { .refclk = 24000, .cdclk = 648000, .divider = 4, .ratio = 108 },
+
+ { .refclk = 38400, .cdclk = 172800, .divider = 4, .ratio = 18 },
+ { .refclk = 38400, .cdclk = 192000, .divider = 4, .ratio = 20 },
+ { .refclk = 38400, .cdclk = 307200, .divider = 4, .ratio = 32 },
+ { .refclk = 38400, .cdclk = 326400, .divider = 8, .ratio = 68 },
+ { .refclk = 38400, .cdclk = 556800, .divider = 4, .ratio = 58 },
+ { .refclk = 38400, .cdclk = 652800, .divider = 4, .ratio = 68 },
+ {}
+};
+
static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
{
const struct intel_cdclk_vals *table = dev_priv->cdclk.table;
@@ -2588,7 +2612,7 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
*/
void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
{
- if (IS_ELKHARTLAKE(dev_priv)) {
+ if (IS_JSL_EHL(dev_priv)) {
if (dev_priv->cdclk.hw.ref == 24000)
dev_priv->max_cdclk_freq = 552000;
else
@@ -2680,6 +2704,18 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv)
DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000));
}
+static int dg1_rawclk(struct drm_i915_private *dev_priv)
+{
+ /*
+ * DG1 always uses a 38.4 MHz rawclk. The bspec tells us
+ * "Program Numerator=2, Denominator=4, Divider=37 decimal."
+ */
+ I915_WRITE(PCH_RAWCLK_FREQ,
+ CNP_RAWCLK_DEN(4) | CNP_RAWCLK_DIV(37) | ICP_RAWCLK_NUM(2));
+
+ return 38400;
+}
+
static int cnp_rawclk(struct drm_i915_private *dev_priv)
{
u32 rawclk;
@@ -2788,7 +2824,9 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
{
u32 freq;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ freq = dg1_rawclk(dev_priv);
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
freq = cnp_rawclk(dev_priv);
else if (HAS_PCH_SPLIT(dev_priv))
freq = pch_rawclk(dev_priv);
@@ -2809,13 +2847,19 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
*/
void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (IS_ROCKETLAKE(dev_priv)) {
+ dev_priv->display.set_cdclk = bxt_set_cdclk;
+ dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
+ dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
+ dev_priv->display.calc_voltage_level = tgl_calc_voltage_level;
+ dev_priv->cdclk.table = rkl_cdclk_table;
+ } else if (INTEL_GEN(dev_priv) >= 12) {
dev_priv->display.set_cdclk = bxt_set_cdclk;
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
dev_priv->display.calc_voltage_level = tgl_calc_voltage_level;
dev_priv->cdclk.table = icl_cdclk_table;
- } else if (IS_ELKHARTLAKE(dev_priv)) {
+ } else if (IS_JSL_EHL(dev_priv)) {
dev_priv->display.set_cdclk = bxt_set_cdclk;
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index 945bb03bdd4d..172d398081ee 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -638,10 +638,17 @@ static void ilk_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
ilk_load_lut_8(crtc, gamma_lut);
- else
+ break;
+ case GAMMA_MODE_MODE_10BIT:
ilk_load_lut_10(crtc, gamma_lut);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
static int ivb_lut_10_size(u32 prec_index)
@@ -745,21 +752,27 @@ static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
+ const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) {
- ilk_load_lut_8(crtc, gamma_lut);
- } else if (crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) {
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ ilk_load_lut_8(crtc, blob);
+ break;
+ case GAMMA_MODE_MODE_SPLIT:
ivb_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
ivb_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
- } else {
- const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
-
+ break;
+ case GAMMA_MODE_MODE_10BIT:
ivb_load_lut_10(crtc, blob,
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
@@ -768,21 +781,28 @@ static void bdw_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
+ const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) {
- ilk_load_lut_8(crtc, gamma_lut);
- } else if (crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) {
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ ilk_load_lut_8(crtc, blob);
+ break;
+ case GAMMA_MODE_MODE_SPLIT:
bdw_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
- } else {
- const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
+ break;
+ case GAMMA_MODE_MODE_10BIT:
bdw_load_lut_10(crtc, blob,
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
@@ -818,12 +838,14 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state)
* as compared to just 16 to achieve this.
*/
intel_de_write(dev_priv, PRE_CSC_GAMC_DATA(pipe),
- lut[i].green);
+ lut[i].green);
}
/* Clamp values > 1.0. */
while (i++ < 35)
intel_de_write(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
+
+ intel_de_write(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
}
static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_state)
@@ -851,6 +873,8 @@ static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_stat
/* Clamp values > 1.0. */
while (i++ < 35)
intel_de_write(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
+
+ intel_de_write(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
}
static void glk_load_luts(const struct intel_crtc_state *crtc_state)
@@ -871,11 +895,17 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state)
else
glk_load_degamma_lut_linear(crtc_state);
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) {
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
ilk_load_lut_8(crtc, gamma_lut);
- } else {
+ break;
+ case GAMMA_MODE_MODE_10BIT:
bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
@@ -1007,9 +1037,13 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state)
icl_program_gamma_superfine_segment(crtc_state);
icl_program_gamma_multi_segment(crtc_state);
break;
- default:
+ case GAMMA_MODE_MODE_10BIT:
bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
intel_dsb_commit(crtc_state);
@@ -1026,13 +1060,6 @@ static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color)
return drm_color_lut_extract(color->red, 14);
}
-static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
-{
- entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_MASK, ldw), 10);
- entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_MASK, ldw), 10);
- entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_MASK, udw), 10);
-}
-
static void chv_load_cgm_degamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
@@ -1060,6 +1087,13 @@ static u32 chv_cgm_gamma_udw(const struct drm_color_lut *color)
return drm_color_lut_extract(color->red, 10);
}
+static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
+{
+ entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_MASK, ldw), 10);
+ entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_MASK, ldw), 10);
+ entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_MASK, udw), 10);
+}
+
static void chv_load_cgm_gamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
@@ -1733,7 +1767,7 @@ bool intel_color_lut_equal(struct drm_property_blob *blob1,
break;
default:
MISSING_CASE(gamma_mode);
- return false;
+ return false;
}
return true;
@@ -1913,23 +1947,34 @@ static void ilk_read_luts(struct intel_crtc_state *crtc_state)
if ((crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0)
return;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
- else
+ break;
+ case GAMMA_MODE_MODE_10BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_10(crtc);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
-static struct drm_property_blob *glk_read_lut_10(struct intel_crtc *crtc,
+/* On BDW+ the index auto increment mode actually works */
+static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
u32 prec_index)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
int i, hw_lut_size = ivb_lut_10_size(prec_index);
+ int lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
+ drm_WARN_ON(&dev_priv->drm, lut_size != hw_lut_size);
+
blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * hw_lut_size,
+ sizeof(struct drm_color_lut) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1939,7 +1984,7 @@ static struct drm_property_blob *glk_read_lut_10(struct intel_crtc *crtc,
intel_de_write(dev_priv, PREC_PAL_INDEX(pipe),
prec_index | PAL_PREC_AUTO_INCREMENT);
- for (i = 0; i < hw_lut_size; i++) {
+ for (i = 0; i < lut_size; i++) {
u32 val = intel_de_read(dev_priv, PREC_PAL_DATA(pipe));
ilk_lut_10_pack(&lut[i], val);
@@ -1957,10 +2002,17 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state)
if (!crtc_state->gamma_enable)
return;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
- else
- crtc_state->hw.gamma_lut = glk_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
+ case GAMMA_MODE_MODE_10BIT:
+ crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
static struct drm_property_blob *
@@ -2012,11 +2064,15 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
case GAMMA_MODE_MODE_8BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
break;
+ case GAMMA_MODE_MODE_10BIT:
+ crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
crtc_state->hw.gamma_lut = icl_read_lut_multi_segment(crtc);
break;
default:
- crtc_state->hw.gamma_lut = glk_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c
index 157d8c8c605a..d5ad61e4083e 100644
--- a/drivers/gpu/drm/i915/display/intel_combo_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c
@@ -188,8 +188,9 @@ static bool has_phy_misc(struct drm_i915_private *i915, enum phy phy)
* PHY-B and may not even have instances of the register for the
* other combo PHY's.
*/
- if (IS_ELKHARTLAKE(i915) ||
- IS_ROCKETLAKE(i915))
+ if (IS_JSL_EHL(i915) ||
+ IS_ROCKETLAKE(i915) ||
+ IS_DG1(i915))
return phy < PHY_C;
return true;
@@ -242,14 +243,14 @@ static bool phy_is_master(struct drm_i915_private *dev_priv, enum phy phy)
*
* ICL,TGL:
* A(master) -> B(slave), C(slave)
- * RKL:
+ * RKL,DG1:
* A(master) -> B(slave)
* C(master) -> D(slave)
*
* We must set the IREFGEN bit for any PHY acting as a master
* to another PHY.
*/
- if (IS_ROCKETLAKE(dev_priv) && phy == PHY_C)
+ if ((IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) && phy == PHY_C)
return true;
return phy == PHY_A;
@@ -282,7 +283,7 @@ static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW8(phy),
IREFGEN, IREFGEN);
- if (IS_ELKHARTLAKE(dev_priv)) {
+ if (IS_JSL_EHL(dev_priv)) {
if (ehl_vbt_ddi_d_present(dev_priv))
expected_val = ICL_PHY_MISC_MUX_DDID;
@@ -376,7 +377,7 @@ static void icl_combo_phys_init(struct drm_i915_private *dev_priv)
* "internal" child devices.
*/
val = intel_de_read(dev_priv, ICL_PHY_MISC(phy));
- if (IS_ELKHARTLAKE(dev_priv) && phy == PHY_A) {
+ if (IS_JSL_EHL(dev_priv) && phy == PHY_A) {
val &= ~ICL_PHY_MISC_MUX_DDID;
if (ehl_vbt_ddi_d_present(dev_priv))
diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c
index d5db16764619..67dc64df78a5 100644
--- a/drivers/gpu/drm/i915/display/intel_csr.c
+++ b/drivers/gpu/drm/i915/display/intel_csr.c
@@ -40,13 +40,16 @@
#define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE
+#define DG1_CSR_PATH "i915/dg1_dmc_ver2_02.bin"
+#define DG1_CSR_VERSION_REQUIRED CSR_VERSION(2, 2)
+MODULE_FIRMWARE(DG1_CSR_PATH);
+
#define RKL_CSR_PATH "i915/rkl_dmc_ver2_02.bin"
#define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 2)
MODULE_FIRMWARE(RKL_CSR_PATH);
#define TGL_CSR_PATH "i915/tgl_dmc_ver2_08.bin"
#define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 8)
-#define TGL_CSR_MAX_FW_SIZE 0x6000
MODULE_FIRMWARE(TGL_CSR_PATH);
#define ICL_CSR_PATH "i915/icl_dmc_ver1_09.bin"
@@ -686,14 +689,17 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
*/
intel_csr_runtime_pm_get(dev_priv);
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ csr->fw_path = DG1_CSR_PATH;
+ csr->required_version = DG1_CSR_VERSION_REQUIRED;
+ csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
+ } else if (IS_ROCKETLAKE(dev_priv)) {
csr->fw_path = RKL_CSR_PATH;
csr->required_version = RKL_CSR_VERSION_REQUIRED;
csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
} else if (INTEL_GEN(dev_priv) >= 12) {
csr->fw_path = TGL_CSR_PATH;
csr->required_version = TGL_CSR_VERSION_REQUIRED;
- /* Allow to load fw via parameter using the last known size */
csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
} else if (IS_GEN(dev_priv, 11)) {
csr->fw_path = ICL_CSR_PATH;
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index cdcb7b1034ae..92940a0c5ef8 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -28,6 +28,7 @@
#include <drm/drm_scdc_helper.h>
#include "i915_drv.h"
+#include "i915_trace.h"
#include "intel_audio.h"
#include "intel_combo_phy.h"
#include "intel_connector.h"
@@ -582,6 +583,34 @@ static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = {
{ 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */
};
+static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr[] = {
+ /* NT mV Trans mV db */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */
+ { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */
+ { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */
+ { 0xA, 0x35, 0x36, 0x00, 0x09 }, /* 200 350 4.9 */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */
+ { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */
+ { 0xA, 0x35, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */
+ { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */
+ { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */
+ { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
+};
+
+static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2[] = {
+ /* NT mV Trans mV db */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 250 1.9 */
+ { 0x1, 0x7F, 0x3D, 0x00, 0x02 }, /* 200 300 3.5 */
+ { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 200 350 4.9 */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */
+ { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 300 1.6 */
+ { 0xA, 0x35, 0x3A, 0x00, 0x05 }, /* 250 350 2.9 */
+ { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */
+ { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */
+ { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
+};
+
struct icl_mg_phy_ddi_buf_trans {
u32 cri_txdeemph_override_11_6;
u32 cri_txdeemph_override_5_0;
@@ -1034,133 +1063,286 @@ cnl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries)
}
static const struct cnl_ddi_buf_trans *
-icl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+icl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+icl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
+ return icl_combo_phy_ddi_translations_dp_hbr2;
+}
+
+static const struct cnl_ddi_buf_trans *
+icl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- if (type == INTEL_OUTPUT_HDMI) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
- return icl_combo_phy_ddi_translations_hdmi;
- } else if (rate > 540000 && type == INTEL_OUTPUT_EDP) {
+ if (crtc_state->port_clock > 540000) {
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
return icl_combo_phy_ddi_translations_edp_hbr3;
- } else if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) {
+ } else if (dev_priv->vbt.edp.low_vswing) {
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
return icl_combo_phy_ddi_translations_edp_hbr2;
}
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
- return icl_combo_phy_ddi_translations_dp_hbr2;
+ return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+icl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return icl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
}
static const struct icl_mg_phy_ddi_buf_trans *
-icl_get_mg_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+icl_get_mg_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
- if (type == INTEL_OUTPUT_HDMI) {
- *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi);
- return icl_mg_phy_ddi_translations_hdmi;
- } else if (rate > 270000) {
+ *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi);
+ return icl_mg_phy_ddi_translations_hdmi;
+}
+
+static const struct icl_mg_phy_ddi_buf_trans *
+icl_get_mg_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (crtc_state->port_clock > 270000) {
*n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hbr2_hbr3);
return icl_mg_phy_ddi_translations_hbr2_hbr3;
+ } else {
+ *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr);
+ return icl_mg_phy_ddi_translations_rbr_hbr;
}
+}
+
+static const struct icl_mg_phy_ddi_buf_trans *
+icl_get_mg_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return icl_get_mg_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else
+ return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries);
+}
- *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr);
- return icl_mg_phy_ddi_translations_rbr_hbr;
+static const struct cnl_ddi_buf_trans *
+ehl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
}
static const struct cnl_ddi_buf_trans *
-ehl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+ehl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp);
+ return ehl_combo_phy_ddi_translations_dp;
+}
+
+static const struct cnl_ddi_buf_trans *
+ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- switch (type) {
- case INTEL_OUTPUT_HDMI:
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
- return icl_combo_phy_ddi_translations_hdmi;
- case INTEL_OUTPUT_EDP:
- if (dev_priv->vbt.edp.low_vswing) {
- if (rate > 540000) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
- return icl_combo_phy_ddi_translations_edp_hbr3;
- } else {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
- return icl_combo_phy_ddi_translations_edp_hbr2;
- }
- }
- /* fall through */
- default:
- /* All combo DP and eDP ports that do not support low_vswing */
- *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp);
- return ehl_combo_phy_ddi_translations_dp;
+ if (dev_priv->vbt.edp.low_vswing) {
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
+ return icl_combo_phy_ddi_translations_edp_hbr2;
}
+
+ return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
}
static const struct cnl_ddi_buf_trans *
-tgl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
+ehl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
int *n_entries)
{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return ehl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
+ return icl_combo_phy_ddi_translations_dp_hbr2;
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- switch (type) {
- case INTEL_OUTPUT_HDMI:
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
- return icl_combo_phy_ddi_translations_hdmi;
- case INTEL_OUTPUT_EDP:
- if (dev_priv->vbt.edp.hobl) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- if (!intel_dp->hobl_failed && rate <= 540000) {
- /* Same table applies to TGL, RKL and DG1 */
- *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
- return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
- }
+ if (dev_priv->vbt.edp.low_vswing) {
+ if (crtc_state->port_clock > 270000) {
+ *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr2);
+ return jsl_combo_phy_ddi_translations_edp_hbr2;
+ } else {
+ *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr);
+ return jsl_combo_phy_ddi_translations_edp_hbr;
}
+ }
- if (rate > 540000) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
- return icl_combo_phy_ddi_translations_edp_hbr3;
- } else if (dev_priv->vbt.edp.low_vswing) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
- return icl_combo_phy_ddi_translations_edp_hbr2;
- }
- /* fall through */
- default:
- /* All combo DP and eDP ports that do not support low_vswing */
- if (rate > 270000) {
- if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
- *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
- return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
- }
+ return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return jsl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (crtc_state->port_clock > 270000) {
+ if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
+ *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
+ return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
+ } else {
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
return tgl_combo_phy_ddi_translations_dp_hbr2;
}
-
+ } else {
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr);
return tgl_combo_phy_ddi_translations_dp_hbr;
}
}
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ if (crtc_state->port_clock > 540000) {
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
+ return icl_combo_phy_ddi_translations_edp_hbr3;
+ } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) {
+ *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
+ return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
+ } else if (dev_priv->vbt.edp.low_vswing) {
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
+ return icl_combo_phy_ddi_translations_edp_hbr2;
+ }
+
+ return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
static const struct tgl_dkl_phy_ddi_buf_trans *
-tgl_get_dkl_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+tgl_get_dkl_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans);
+ return tgl_dkl_phy_hdmi_ddi_trans;
+}
+
+static const struct tgl_dkl_phy_ddi_buf_trans *
+tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
- if (type == INTEL_OUTPUT_HDMI) {
- *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans);
- return tgl_dkl_phy_hdmi_ddi_trans;
- } else if (rate > 270000) {
+ if (crtc_state->port_clock > 270000) {
*n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans_hbr2);
return tgl_dkl_phy_dp_ddi_trans_hbr2;
+ } else {
+ *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans);
+ return tgl_dkl_phy_dp_ddi_trans;
}
+}
- *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans);
- return tgl_dkl_phy_dp_ddi_trans;
+static const struct tgl_dkl_phy_ddi_buf_trans *
+tgl_get_dkl_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else
+ return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries);
}
-static int intel_ddi_hdmi_level(struct intel_encoder *encoder)
+static int intel_ddi_hdmi_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
int n_entries, level, default_entry;
@@ -1168,19 +1350,15 @@ static int intel_ddi_hdmi_level(struct intel_encoder *encoder)
if (INTEL_GEN(dev_priv) >= 12) {
if (intel_phy_is_combo(dev_priv, phy))
- tgl_get_combo_buf_trans(encoder, INTEL_OUTPUT_HDMI,
- 0, &n_entries);
+ tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries);
else
- tgl_get_dkl_buf_trans(encoder, INTEL_OUTPUT_HDMI, 0,
- &n_entries);
+ tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries);
default_entry = n_entries - 1;
} else if (INTEL_GEN(dev_priv) == 11) {
if (intel_phy_is_combo(dev_priv, phy))
- icl_get_combo_buf_trans(encoder, INTEL_OUTPUT_HDMI,
- 0, &n_entries);
+ icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries);
else
- icl_get_mg_buf_trans(encoder, INTEL_OUTPUT_HDMI, 0,
- &n_entries);
+ icl_get_mg_buf_trans_hdmi(encoder, crtc_state, &n_entries);
default_entry = n_entries - 1;
} else if (IS_CANNONLAKE(dev_priv)) {
cnl_get_buf_trans_hdmi(encoder, &n_entries);
@@ -1507,14 +1685,15 @@ void hsw_fdi_link_train(struct intel_encoder *encoder,
DP_TP_CTL_ENABLE);
}
-static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
+static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
intel_dp->DP = dig_port->saved_port_bits |
DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
- intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
+ intel_dp->DP |= DDI_PORT_WIDTH(crtc_state->lane_count);
}
static int icl_calc_tbt_pll_link(struct drm_i915_private *dev_priv,
@@ -1577,7 +1756,8 @@ static void intel_ddi_clock_get(struct intel_encoder *encoder,
encoder->port);
else
pipe_config->port_clock =
- intel_dpll_get_freq(dev_priv, pipe_config->shared_dpll);
+ intel_dpll_get_freq(dev_priv, pipe_config->shared_dpll,
+ &pipe_config->dpll_hw_state);
ddi_dotclock_get(pipe_config);
}
@@ -2117,13 +2297,6 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
intel_phy_is_tc(dev_priv, phy))
intel_display_power_get(dev_priv,
intel_ddi_main_link_aux_domain(dig_port));
-
- /*
- * VDSC power is needed when DSC is enabled
- */
- if (crtc_state->dsc.compression_enable)
- intel_display_power_get(dev_priv,
- intel_dsc_power_domain(crtc_state));
}
void intel_ddi_enable_pipe_clock(struct intel_encoder *encoder,
@@ -2178,13 +2351,14 @@ static void _skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
}
static void skl_ddi_set_iboost(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
u8 iboost;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
iboost = intel_bios_hdmi_boost_level(encoder);
else
iboost = intel_bios_dp_boost_level(encoder);
@@ -2193,14 +2367,12 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder,
const struct ddi_buf_trans *ddi_translations;
int n_entries;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
ddi_translations = intel_ddi_get_buf_trans_hdmi(encoder, &n_entries);
- else if (type == INTEL_OUTPUT_EDP)
- ddi_translations = intel_ddi_get_buf_trans_edp(encoder,
- &n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ ddi_translations = intel_ddi_get_buf_trans_edp(encoder, &n_entries);
else
- ddi_translations = intel_ddi_get_buf_trans_dp(encoder,
- &n_entries);
+ ddi_translations = intel_ddi_get_buf_trans_dp(encoder, &n_entries);
if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
return;
@@ -2223,16 +2395,17 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder,
}
static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
const struct bxt_ddi_buf_trans *ddi_translations;
enum port port = encoder->port;
int n_entries;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
ddi_translations = bxt_get_buf_trans_hdmi(encoder, &n_entries);
- else if (type == INTEL_OUTPUT_EDP)
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
ddi_translations = bxt_get_buf_trans_edp(encoder, &n_entries);
else
ddi_translations = bxt_get_buf_trans_dp(encoder, &n_entries);
@@ -2249,7 +2422,8 @@ static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
ddi_translations[level].deemphasis);
}
-static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp)
+static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2259,33 +2433,30 @@ static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp)
if (INTEL_GEN(dev_priv) >= 12) {
if (intel_phy_is_combo(dev_priv, phy))
- tgl_get_combo_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ tgl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else
- tgl_get_dkl_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
} else if (INTEL_GEN(dev_priv) == 11) {
- if (IS_ELKHARTLAKE(dev_priv))
- ehl_get_combo_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ if (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE))
+ jsl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
+ else if (IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE))
+ ehl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else if (intel_phy_is_combo(dev_priv, phy))
- icl_get_combo_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ icl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else
- icl_get_mg_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
} else if (IS_CANNONLAKE(dev_priv)) {
- if (encoder->type == INTEL_OUTPUT_EDP)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
cnl_get_buf_trans_edp(encoder, &n_entries);
else
cnl_get_buf_trans_dp(encoder, &n_entries);
} else if (IS_GEN9_LP(dev_priv)) {
- if (encoder->type == INTEL_OUTPUT_EDP)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
bxt_get_buf_trans_edp(encoder, &n_entries);
else
bxt_get_buf_trans_dp(encoder, &n_entries);
} else {
- if (encoder->type == INTEL_OUTPUT_EDP)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
intel_ddi_get_buf_trans_edp(encoder, &n_entries);
else
intel_ddi_get_buf_trans_dp(encoder, &n_entries);
@@ -2312,7 +2483,8 @@ static u8 intel_ddi_dp_preemph_max(struct intel_dp *intel_dp)
}
static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
const struct cnl_ddi_buf_trans *ddi_translations;
@@ -2320,9 +2492,9 @@ static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
int n_entries, ln;
u32 val;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
ddi_translations = cnl_get_buf_trans_hdmi(encoder, &n_entries);
- else if (type == INTEL_OUTPUT_EDP)
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
ddi_translations = cnl_get_buf_trans_edp(encoder, &n_entries);
else
ddi_translations = cnl_get_buf_trans_dp(encoder, &n_entries);
@@ -2376,22 +2548,16 @@ static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
}
static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum port port = encoder->port;
int width, rate, ln;
u32 val;
- if (type == INTEL_OUTPUT_HDMI) {
- width = 4;
- rate = 0; /* Rate is always < than 6GHz for HDMI */
- } else {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- width = intel_dp->lane_count;
- rate = intel_dp->link_rate;
- }
+ width = crtc_state->lane_count;
+ rate = crtc_state->port_clock;
/*
* 1. If port type is eDP or DP,
@@ -2399,10 +2565,10 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
* else clear to 0b.
*/
val = intel_de_read(dev_priv, CNL_PORT_PCS_DW1_LN0(port));
- if (type != INTEL_OUTPUT_HDMI)
- val |= COMMON_KEEPER_EN;
- else
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
val &= ~COMMON_KEEPER_EN;
+ else
+ val |= COMMON_KEEPER_EN;
intel_de_write(dev_priv, CNL_PORT_PCS_DW1_GRP(port), val);
/* 2. Program loadgen select */
@@ -2434,7 +2600,7 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
intel_de_write(dev_priv, CNL_PORT_TX_DW5_GRP(port), val);
/* 5. Program swing and de-emphasis */
- cnl_ddi_vswing_program(encoder, level, type);
+ cnl_ddi_vswing_program(encoder, crtc_state, level);
/* 6. Set training enable to trigger update */
val = intel_de_read(dev_priv, CNL_PORT_TX_DW5_LN0(port));
@@ -2443,23 +2609,23 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
}
static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
- u32 level, int type, int rate)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ const struct cnl_ddi_buf_trans *ddi_translations;
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
- const struct cnl_ddi_buf_trans *ddi_translations = NULL;
- u32 n_entries, val;
- int ln;
+ int n_entries, ln;
+ u32 val;
if (INTEL_GEN(dev_priv) >= 12)
- ddi_translations = tgl_get_combo_buf_trans(encoder, type, rate,
- &n_entries);
- else if (IS_ELKHARTLAKE(dev_priv))
- ddi_translations = ehl_get_combo_buf_trans(encoder, type, rate,
- &n_entries);
+ ddi_translations = tgl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
+ else if (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE))
+ ddi_translations = jsl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
+ else if (IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE))
+ ddi_translations = ehl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else
- ddi_translations = icl_get_combo_buf_trans(encoder, type, rate,
- &n_entries);
+ ddi_translations = icl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
if (!ddi_translations)
return;
@@ -2470,7 +2636,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
level = n_entries - 1;
}
- if (type == INTEL_OUTPUT_EDP) {
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
val = EDP4K2K_MODE_OVRD_EN | EDP4K2K_MODE_OVRD_OPTIMIZED;
@@ -2518,25 +2684,16 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
}
static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
- u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
- int width = 0;
- int rate = 0;
+ int width, rate, ln;
u32 val;
- int ln = 0;
- if (type == INTEL_OUTPUT_HDMI) {
- width = 4;
- /* Rate is always < than 6GHz for HDMI */
- } else {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- width = intel_dp->lane_count;
- rate = intel_dp->link_rate;
- }
+ width = crtc_state->lane_count;
+ rate = crtc_state->port_clock;
/*
* 1. If port type is eDP or DP,
@@ -2544,7 +2701,7 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
* else clear to 0b.
*/
val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN0(phy));
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
val &= ~COMMON_KEEPER_EN;
else
val |= COMMON_KEEPER_EN;
@@ -2579,7 +2736,7 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val);
/* 5. Program swing and de-emphasis */
- icl_ddi_combo_vswing_program(encoder, level, type, rate);
+ icl_ddi_combo_vswing_program(encoder, crtc_state, level);
/* 6. Set training enable to trigger update */
val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy));
@@ -2588,23 +2745,16 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
}
static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
- int link_clock, u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port);
const struct icl_mg_phy_ddi_buf_trans *ddi_translations;
- u32 n_entries, val;
- int ln, rate = 0;
-
- if (type != INTEL_OUTPUT_HDMI) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- rate = intel_dp->link_rate;
- }
+ int n_entries, ln;
+ u32 val;
- ddi_translations = icl_get_mg_buf_trans(encoder, type, rate,
- &n_entries);
+ ddi_translations = icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
/* The table does not have values for level 3 and level 9. */
if (level >= n_entries || level == 3 || level == 9) {
drm_dbg_kms(&dev_priv->drm,
@@ -2671,7 +2821,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
*/
for (ln = 0; ln < 2; ln++) {
val = intel_de_read(dev_priv, MG_CLKHUB(ln, tc_port));
- if (link_clock < 300000)
+ if (crtc_state->port_clock < 300000)
val |= CFG_LOW_RATE_LKREN_EN;
else
val &= ~CFG_LOW_RATE_LKREN_EN;
@@ -2682,7 +2832,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
for (ln = 0; ln < 2; ln++) {
val = intel_de_read(dev_priv, MG_TX1_DCC(ln, tc_port));
val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
- if (link_clock <= 500000) {
+ if (crtc_state->port_clock <= 500000) {
val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
} else {
val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
@@ -2692,7 +2842,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
val = intel_de_read(dev_priv, MG_TX2_DCC(ln, tc_port));
val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
- if (link_clock <= 500000) {
+ if (crtc_state->port_clock <= 500000) {
val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
} else {
val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
@@ -2718,38 +2868,30 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
}
static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
- int link_clock,
- u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
if (intel_phy_is_combo(dev_priv, phy))
- icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
+ icl_combo_phy_ddi_vswing_sequence(encoder, crtc_state, level);
else
- icl_mg_phy_ddi_vswing_sequence(encoder, link_clock, level,
- type);
+ icl_mg_phy_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int link_clock,
- u32 level, enum intel_output_type type)
+tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port);
const struct tgl_dkl_phy_ddi_buf_trans *ddi_translations;
- u32 n_entries, val, ln, dpcnt_mask, dpcnt_val;
- int rate = 0;
-
- if (type != INTEL_OUTPUT_HDMI) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- rate = intel_dp->link_rate;
- }
+ u32 val, dpcnt_mask, dpcnt_val;
+ int n_entries, ln;
- ddi_translations = tgl_get_dkl_buf_trans(encoder, encoder->type, rate,
- &n_entries);
+ ddi_translations = tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
if (level >= n_entries)
level = n_entries - 1;
@@ -2785,20 +2927,20 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int link_clock,
}
static void tgl_ddi_vswing_sequence(struct intel_encoder *encoder,
- int link_clock,
- u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
if (intel_phy_is_combo(dev_priv, phy))
- icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
+ icl_combo_phy_ddi_vswing_sequence(encoder, crtc_state, level);
else
- tgl_dkl_phy_ddi_vswing_sequence(encoder, link_clock, level, type);
+ tgl_dkl_phy_ddi_vswing_sequence(encoder, crtc_state, level);
}
-static u32 translate_signal_level(struct intel_dp *intel_dp, int signal_levels)
+static int translate_signal_level(struct intel_dp *intel_dp,
+ u8 signal_levels)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int i;
@@ -2815,55 +2957,58 @@ static u32 translate_signal_level(struct intel_dp *intel_dp, int signal_levels)
return 0;
}
-static u32 intel_ddi_dp_level(struct intel_dp *intel_dp)
+static int intel_ddi_dp_level(struct intel_dp *intel_dp)
{
u8 train_set = intel_dp->train_set[0];
- int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
- DP_TRAIN_PRE_EMPHASIS_MASK);
+ u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+ DP_TRAIN_PRE_EMPHASIS_MASK);
return translate_signal_level(intel_dp, signal_levels);
}
static void
-tgl_set_signal_levels(struct intel_dp *intel_dp)
+tgl_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- tgl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
- level, encoder->type);
+ tgl_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-icl_set_signal_levels(struct intel_dp *intel_dp)
+icl_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- icl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
- level, encoder->type);
+ icl_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-cnl_set_signal_levels(struct intel_dp *intel_dp)
+cnl_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- cnl_ddi_vswing_sequence(encoder, level, encoder->type);
+ cnl_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-bxt_set_signal_levels(struct intel_dp *intel_dp)
+bxt_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- bxt_ddi_vswing_sequence(encoder, level, encoder->type);
+ bxt_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-hsw_set_signal_levels(struct intel_dp *intel_dp)
+hsw_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2880,7 +3025,7 @@ hsw_set_signal_levels(struct intel_dp *intel_dp)
intel_dp->DP |= signal_levels;
if (IS_GEN9_BC(dev_priv))
- skl_ddi_set_iboost(encoder, level, encoder->type);
+ skl_ddi_set_iboost(encoder, crtc_state, level);
intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
intel_de_posting_read(dev_priv, DDI_BUF_CTL(port));
@@ -2903,6 +3048,40 @@ static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv,
return 0;
}
+static void dg1_map_plls_to_ports(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+ enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
+ u32 val;
+
+ /*
+ * If we fail this, something went very wrong: first 2 PLLs should be
+ * used by first 2 phys and last 2 PLLs by last phys
+ */
+ if (drm_WARN_ON(&dev_priv->drm,
+ (pll->info->id < DPLL_ID_DG1_DPLL2 && phy >= PHY_C) ||
+ (pll->info->id >= DPLL_ID_DG1_DPLL2 && phy < PHY_C)))
+ return;
+
+ mutex_lock(&dev_priv->dpll.lock);
+
+ val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy));
+ drm_WARN_ON(&dev_priv->drm,
+ (val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)) == 0);
+
+ val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ val |= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy);
+ intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val);
+ intel_de_posting_read(dev_priv, DG1_DPCLKA_CFGCR0(phy));
+
+ val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+ intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val);
+
+ mutex_unlock(&dev_priv->dpll.lock);
+}
+
static void icl_map_plls_to_ports(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
@@ -2950,6 +3129,19 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder,
mutex_unlock(&dev_priv->dpll.lock);
}
+static void dg1_unmap_plls_to_ports(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
+
+ mutex_lock(&dev_priv->dpll.lock);
+
+ intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), 0,
+ DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy));
+
+ mutex_unlock(&dev_priv->dpll.lock);
+}
+
static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2965,6 +3157,37 @@ static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpll.lock);
}
+static void dg1_sanitize_port_clk_off(struct drm_i915_private *dev_priv,
+ u32 port_mask, bool ddi_clk_needed)
+{
+ enum port port;
+ u32 val;
+
+ for_each_port_masked(port, port_mask) {
+ enum phy phy = intel_port_to_phy(dev_priv, port);
+ bool ddi_clk_off;
+
+ val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy));
+ ddi_clk_off = val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+
+ if (ddi_clk_needed == !ddi_clk_off)
+ continue;
+
+ /*
+ * Punt on the case now where clock is gated, but it would
+ * be needed by the port. Something else is really broken then.
+ */
+ if (drm_WARN_ON(&dev_priv->drm, ddi_clk_needed))
+ continue;
+
+ drm_notice(&dev_priv->drm,
+ "PHY %c is disabled with an ungated DDI clock, gate it\n",
+ phy_name(phy));
+ val |= DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+ intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val);
+ }
+}
+
static void icl_sanitize_port_clk_off(struct drm_i915_private *dev_priv,
u32 port_mask, bool ddi_clk_needed)
{
@@ -3047,7 +3270,10 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder)
ddi_clk_needed = false;
}
- icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed);
+ if (IS_DG1(dev_priv))
+ dg1_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed);
+ else
+ icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed);
}
static void intel_ddi_clk_select(struct intel_encoder *encoder,
@@ -3068,7 +3294,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,
if (!intel_phy_is_combo(dev_priv, phy))
intel_de_write(dev_priv, DDI_CLK_SEL(port),
icl_pll_to_ddi_clk_sel(encoder, crtc_state));
- else if (IS_ELKHARTLAKE(dev_priv) && port >= PORT_C)
+ else if (IS_JSL_EHL(dev_priv) && port >= PORT_C)
/*
* MG does not exist but the programming is required
* to ungate DDIC and DDID
@@ -3117,7 +3343,7 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder)
if (INTEL_GEN(dev_priv) >= 11) {
if (!intel_phy_is_combo(dev_priv, phy) ||
- (IS_ELKHARTLAKE(dev_priv) && port >= PORT_C))
+ (IS_JSL_EHL(dev_priv) && port >= PORT_C))
intel_de_write(dev_priv, DDI_CLK_SEL(port),
DDI_CLK_SEL_NONE);
} else if (IS_CANNONLAKE(dev_priv)) {
@@ -3223,6 +3449,37 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port,
}
}
+static enum transcoder
+tgl_dp_tp_transcoder(const struct intel_crtc_state *crtc_state)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
+ return crtc_state->mst_master_transcoder;
+ else
+ return crtc_state->cpu_transcoder;
+}
+
+i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (INTEL_GEN(dev_priv) >= 12)
+ return TGL_DP_TP_CTL(tgl_dp_tp_transcoder(crtc_state));
+ else
+ return DP_TP_CTL(encoder->port);
+}
+
+i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (INTEL_GEN(dev_priv) >= 12)
+ return TGL_DP_TP_STATUS(tgl_dp_tp_transcoder(crtc_state));
+ else
+ return DP_TP_STATUS(encoder->port);
+}
+
static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
@@ -3247,11 +3504,12 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder,
return;
intel_dp = enc_to_intel_dp(encoder);
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val |= DP_TP_CTL_FEC_ENABLE;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
- if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
+ if (intel_de_wait_for_set(dev_priv,
+ dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_FEC_ENABLE_LIVE, 1))
drm_err(&dev_priv->drm,
"Timed out waiting for FEC Enable Status\n");
@@ -3268,10 +3526,10 @@ static void intel_ddi_disable_fec_state(struct intel_encoder *encoder,
return;
intel_dp = enc_to_intel_dp(encoder);
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val &= ~DP_TP_CTL_FEC_ENABLE;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
- intel_de_posting_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
+ intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
}
static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3285,13 +3543,10 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
int level = intel_ddi_dp_level(intel_dp);
- enum transcoder transcoder = crtc_state->cpu_transcoder;
- intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
- crtc_state->lane_count, is_mst);
-
- intel_dp->regs.dp_tp_ctl = TGL_DP_TP_CTL(transcoder);
- intel_dp->regs.dp_tp_status = TGL_DP_TP_STATUS(transcoder);
+ intel_dp_set_link_params(intel_dp,
+ crtc_state->port_clock,
+ crtc_state->lane_count);
/*
* 1. Enable Power Wells
@@ -3360,8 +3615,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
*/
/* 7.e Configure voltage swing and related IO settings */
- tgl_ddi_vswing_sequence(encoder, crtc_state->port_clock, level,
- encoder->type);
+ tgl_ddi_vswing_sequence(encoder, crtc_state, level);
/*
* 7.f Combo PHY: Configure PORT_CL_DW10 Static Power Down to power up
@@ -3384,10 +3638,10 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
* We only configure what the register value will be here. Actual
* enabling happens during link training farther down.
*/
- intel_ddi_init_dp_buf_reg(encoder);
+ intel_ddi_init_dp_buf_reg(encoder, crtc_state);
if (!is_mst)
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
/*
@@ -3404,15 +3658,16 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
* Pattern, wait for 5 idle patterns (DP_TP_STATUS Min_Idles_Sent)
* (timeout after 800 us)
*/
- intel_dp_start_link_train(intel_dp);
+ intel_dp_start_link_train(intel_dp, crtc_state);
/* 7.k Set DP_TP_CTL link training to Normal */
if (!is_trans_port_sync_mode(crtc_state))
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
/* 7.l Configure and enable FEC if needed */
intel_ddi_enable_fec(encoder, crtc_state);
- intel_dsc_enable(encoder, crtc_state);
+ if (!crtc_state->bigjoiner)
+ intel_dsc_enable(encoder, crtc_state);
}
static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3434,8 +3689,9 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
else
drm_WARN_ON(&dev_priv->drm, is_mst && port == PORT_A);
- intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
- crtc_state->lane_count, is_mst);
+ intel_dp_set_link_params(intel_dp,
+ crtc_state->port_clock,
+ crtc_state->lane_count);
intel_edp_panel_on(intel_dp);
@@ -3449,12 +3705,11 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
icl_program_mg_dp_mode(dig_port, crtc_state);
if (INTEL_GEN(dev_priv) >= 11)
- icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
- level, encoder->type);
+ icl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_CANNONLAKE(dev_priv))
- cnl_ddi_vswing_sequence(encoder, level, encoder->type);
+ cnl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_GEN9_LP(dev_priv))
- bxt_ddi_vswing_sequence(encoder, level, encoder->type);
+ bxt_ddi_vswing_sequence(encoder, crtc_state, level);
else
intel_prepare_dp_ddi_buffers(encoder, crtc_state);
@@ -3467,24 +3722,25 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
lane_reversal);
}
- intel_ddi_init_dp_buf_reg(encoder);
+ intel_ddi_init_dp_buf_reg(encoder, crtc_state);
if (!is_mst)
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
true);
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
- intel_dp_start_link_train(intel_dp);
+ intel_dp_start_link_train(intel_dp, crtc_state);
if ((port != PORT_A || INTEL_GEN(dev_priv) >= 9) &&
!is_trans_port_sync_mode(crtc_state))
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
intel_ddi_enable_fec(encoder, crtc_state);
if (!is_mst)
intel_ddi_enable_pipe_clock(encoder, crtc_state);
- intel_dsc_enable(encoder, crtc_state);
+ if (!crtc_state->bigjoiner)
+ intel_dsc_enable(encoder, crtc_state);
}
static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3517,7 +3773,7 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state,
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- int level = intel_ddi_hdmi_level(encoder);
+ int level = intel_ddi_hdmi_level(encoder, crtc_state);
intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
intel_ddi_clk_select(encoder, crtc_state);
@@ -3527,20 +3783,18 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state,
icl_program_mg_dp_mode(dig_port, crtc_state);
if (INTEL_GEN(dev_priv) >= 12)
- tgl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
- level, INTEL_OUTPUT_HDMI);
+ tgl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (INTEL_GEN(dev_priv) == 11)
- icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
- level, INTEL_OUTPUT_HDMI);
+ icl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_CANNONLAKE(dev_priv))
- cnl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+ cnl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_GEN9_LP(dev_priv))
- bxt_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+ bxt_ddi_vswing_sequence(encoder, crtc_state, level);
else
intel_prepare_hdmi_ddi_buffers(encoder, level);
if (IS_GEN9_BC(dev_priv))
- skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI);
+ skl_ddi_set_iboost(encoder, crtc_state, level);
intel_ddi_enable_pipe_clock(encoder, crtc_state);
@@ -3573,7 +3827,9 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state,
drm_WARN_ON(&dev_priv->drm, crtc_state->has_pch_encoder);
- if (INTEL_GEN(dev_priv) >= 11)
+ if (IS_DG1(dev_priv))
+ dg1_map_plls_to_ports(encoder, crtc_state);
+ else if (INTEL_GEN(dev_priv) >= 11)
icl_map_plls_to_ports(encoder, crtc_state);
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
@@ -3612,12 +3868,10 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,
}
if (intel_crtc_has_dp_encoder(crtc_state)) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
val |= DP_TP_CTL_LINK_TRAIN_PAT1;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
}
/* Disable FEC in DP Sink */
@@ -3647,7 +3901,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
* Power down sink before disabling the port, otherwise we end
* up getting interrupts from the sink on detecting link loss.
*/
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D3);
if (INTEL_GEN(dev_priv) >= 12) {
if (is_mst) {
@@ -3737,6 +3991,21 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
ilk_pfit_disable(old_crtc_state);
}
+ if (old_crtc_state->bigjoiner_linked_crtc) {
+ struct intel_atomic_state *state =
+ to_intel_atomic_state(old_crtc_state->uapi.state);
+ struct intel_crtc *slave =
+ old_crtc_state->bigjoiner_linked_crtc;
+ const struct intel_crtc_state *old_slave_crtc_state =
+ intel_atomic_get_old_crtc_state(state, slave);
+
+ intel_crtc_vblank_off(old_slave_crtc_state);
+ trace_intel_pipe_disable(slave);
+
+ intel_dsc_disable(old_slave_crtc_state);
+ skl_scaler_disable(old_slave_crtc_state);
+ }
+
/*
* When called from DP MST code:
* - old_conn_state will be NULL
@@ -3757,7 +4026,9 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
intel_ddi_post_disable_dp(state, encoder, old_crtc_state,
old_conn_state);
- if (INTEL_GEN(dev_priv) >= 11)
+ if (IS_DG1(dev_priv))
+ dg1_unmap_plls_to_ports(encoder);
+ else if (INTEL_GEN(dev_priv) >= 11)
icl_unmap_plls_to_ports(encoder);
if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port)
@@ -3830,12 +4101,14 @@ static void trans_port_sync_stop_link_train(struct intel_atomic_state *state,
crtc_state->cpu_transcoder)
continue;
- intel_dp_stop_link_train(enc_to_intel_dp(slave_encoder));
+ intel_dp_stop_link_train(enc_to_intel_dp(slave_encoder),
+ slave_crtc_state);
}
usleep_range(200, 400);
- intel_dp_stop_link_train(enc_to_intel_dp(encoder));
+ intel_dp_stop_link_train(enc_to_intel_dp(encoder),
+ crtc_state);
}
static void intel_enable_ddi_dp(struct intel_atomic_state *state,
@@ -3848,7 +4121,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
enum port port = encoder->port;
if (port == PORT_A && INTEL_GEN(dev_priv) < 9)
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
intel_edp_backlight_on(crtc_state, conn_state);
intel_psr_enable(intel_dp, crtc_state, conn_state);
@@ -3951,7 +4224,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
{
drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
- intel_ddi_enable_transcoder_func(encoder, crtc_state);
+ if (!crtc_state->bigjoiner_slave)
+ intel_ddi_enable_transcoder_func(encoder, crtc_state);
intel_enable_pipe(crtc_state);
@@ -4109,15 +4383,16 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state,
crtc_state->lane_lat_optim_mask);
}
-static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
+static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
- struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
- enum port port = dig_port->base.port;
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum port port = encoder->port;
u32 dp_tp_ctl, ddi_buf_ctl;
bool wait = false;
- dp_tp_ctl = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ dp_tp_ctl = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
if (dp_tp_ctl & DP_TP_CTL_ENABLE) {
ddi_buf_ctl = intel_de_read(dev_priv, DDI_BUF_CTL(port));
@@ -4129,23 +4404,23 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
dp_tp_ctl &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
dp_tp_ctl |= DP_TP_CTL_LINK_TRAIN_PAT1;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, dp_tp_ctl);
- intel_de_posting_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl);
+ intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
if (wait)
intel_wait_ddi_buf_idle(dev_priv, port);
}
dp_tp_ctl = DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT1;
- if (intel_dp->link_mst)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
dp_tp_ctl |= DP_TP_CTL_MODE_MST;
- else {
+ } else {
dp_tp_ctl |= DP_TP_CTL_MODE_SST;
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
}
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, dp_tp_ctl);
- intel_de_posting_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl);
+ intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
intel_dp->DP |= DDI_BUF_CTL_ENABLE;
intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
@@ -4155,16 +4430,17 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
}
static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
u32 temp;
- temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ temp = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
- switch (dp_train_pat & train_pat_mask) {
+ switch (intel_dp_training_pattern_symbol(dp_train_pat)) {
case DP_TRAINING_PATTERN_DISABLE:
temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
break;
@@ -4182,20 +4458,21 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
break;
}
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, temp);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), temp);
}
-static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp)
+static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum port port = encoder->port;
u32 val;
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val &= ~DP_TP_CTL_LINK_TRAIN_MASK;
val |= DP_TP_CTL_LINK_TRAIN_IDLE;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
/*
* Until TGL on PORT_A we can have only eDP in SST mode. There the only
@@ -4207,7 +4484,8 @@ static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp)
if (port == PORT_A && INTEL_GEN(dev_priv) < 12)
return;
- if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
+ if (intel_de_wait_for_set(dev_priv,
+ dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_IDLE_DONE, 1))
drm_err(&dev_priv->drm,
"Timed out waiting for DP idle patterns\n");
@@ -4231,7 +4509,7 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
{
if (INTEL_GEN(dev_priv) >= 12 && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 2;
- else if (IS_ELKHARTLAKE(dev_priv) && crtc_state->port_clock > 594000)
+ else if (IS_JSL_EHL(dev_priv) && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 3;
else if (INTEL_GEN(dev_priv) >= 11 && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 1;
@@ -4299,21 +4577,14 @@ static void bdw_get_trans_port_sync_config(struct intel_crtc_state *crtc_state)
crtc_state->sync_mode_slaves_mask);
}
-void intel_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *pipe_config)
+static void intel_ddi_read_func_ctl(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc);
enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
u32 temp, flags = 0;
- /* XXX: DSI transcoder paranoia */
- if (drm_WARN_ON(&dev_priv->drm, transcoder_is_dsi(cpu_transcoder)))
- return;
-
- intel_dsc_get_config(encoder, pipe_config);
-
temp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (temp & TRANS_DDI_PHSYNC)
flags |= DRM_MODE_FLAG_PHSYNC;
@@ -4375,12 +4646,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
intel_dp_get_m_n(intel_crtc, pipe_config);
if (INTEL_GEN(dev_priv) >= 11) {
- i915_reg_t dp_tp_ctl;
-
- if (IS_GEN(dev_priv, 11))
- dp_tp_ctl = DP_TP_CTL(encoder->port);
- else
- dp_tp_ctl = TGL_DP_TP_CTL(pipe_config->cpu_transcoder);
+ i915_reg_t dp_tp_ctl = dp_tp_ctl_reg(encoder, pipe_config);
pipe_config->fec_enable =
intel_de_read(dev_priv, dp_tp_ctl) & DP_TP_CTL_FEC_ENABLE;
@@ -4412,15 +4678,29 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
default:
break;
}
+}
- if (INTEL_GEN(dev_priv) >= 12) {
- enum transcoder transcoder =
- intel_dp_mst_is_slave_trans(pipe_config) ?
- pipe_config->mst_master_transcoder :
- pipe_config->cpu_transcoder;
+void intel_ddi_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
- intel_dp->regs.dp_tp_ctl = TGL_DP_TP_CTL(transcoder);
- intel_dp->regs.dp_tp_status = TGL_DP_TP_STATUS(transcoder);
+ /* XXX: DSI transcoder paranoia */
+ if (drm_WARN_ON(&dev_priv->drm, transcoder_is_dsi(cpu_transcoder)))
+ return;
+
+ if (pipe_config->bigjoiner_slave) {
+ /* read out pipe settings from master */
+ enum transcoder save = pipe_config->cpu_transcoder;
+
+ /* Our own transcoder needs to be disabled when reading it in intel_ddi_read_func_ctl() */
+ WARN_ON(pipe_config->output_types);
+ pipe_config->cpu_transcoder = (enum transcoder)pipe_config->bigjoiner_linked_crtc->pipe;
+ intel_ddi_read_func_ctl(encoder, pipe_config);
+ pipe_config->cpu_transcoder = save;
+ } else {
+ intel_ddi_read_func_ctl(encoder, pipe_config);
}
pipe_config->has_audio =
@@ -4447,7 +4727,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
}
- intel_ddi_clock_get(encoder, pipe_config);
+ if (!pipe_config->bigjoiner_slave)
+ intel_ddi_clock_get(encoder, pipe_config);
if (IS_GEN9_LP(dev_priv))
pipe_config->lane_lat_optim_mask =
@@ -4477,6 +4758,22 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
}
+static void intel_ddi_sync_state(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ if (intel_crtc_has_dp_encoder(crtc_state))
+ intel_dp_sync_state(encoder, crtc_state);
+}
+
+static bool intel_ddi_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ if (intel_crtc_has_dp_encoder(crtc_state))
+ return intel_dp_initial_fastset_check(encoder, crtc_state);
+
+ return true;
+}
+
static enum intel_output_type
intel_ddi_compute_output_type(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
@@ -4687,11 +4984,6 @@ intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
dig_port->dp.voltage_max = intel_ddi_dp_voltage_max;
dig_port->dp.preemph_max = intel_ddi_dp_preemph_max;
- if (INTEL_GEN(dev_priv) < 12) {
- dig_port->dp.regs.dp_tp_ctl = DP_TP_CTL(port);
- dig_port->dp.regs.dp_tp_status = DP_TP_STATUS(port);
- }
-
if (!intel_dp_init_connector(dig_port, connector)) {
kfree(connector);
return NULL;
@@ -4974,11 +5266,20 @@ static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
i915->hti_state & HDPORT_PHY_USED_HDMI(phy));
}
+static enum hpd_pin dg1_hpd_pin(struct drm_i915_private *dev_priv,
+ enum port port)
+{
+ if (port >= PORT_TC1)
+ return HPD_PORT_C + port - PORT_TC1;
+ else
+ return HPD_PORT_A + port - PORT_A;
+}
+
static enum hpd_pin tgl_hpd_pin(struct drm_i915_private *dev_priv,
enum port port)
{
- if (port >= PORT_D)
- return HPD_PORT_TC1 + port - PORT_D;
+ if (port >= PORT_TC1)
+ return HPD_PORT_TC1 + port - PORT_TC1;
else
return HPD_PORT_A + port - PORT_A;
}
@@ -4989,8 +5290,8 @@ static enum hpd_pin rkl_hpd_pin(struct drm_i915_private *dev_priv,
if (HAS_PCH_TGP(dev_priv))
return tgl_hpd_pin(dev_priv, port);
- if (port >= PORT_D)
- return HPD_PORT_C + port - PORT_D;
+ if (port >= PORT_TC1)
+ return HPD_PORT_C + port - PORT_TC1;
else
return HPD_PORT_A + port - PORT_A;
}
@@ -5025,11 +5326,14 @@ static enum hpd_pin cnl_hpd_pin(struct drm_i915_private *dev_priv,
return HPD_PORT_A + port - PORT_A;
}
+#define port_tc_name(port) ((port) - PORT_TC1 + '1')
+#define tc_port_name(tc_port) ((tc_port) - TC_PORT_1 + '1')
+
void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
{
struct intel_digital_port *dig_port;
struct intel_encoder *encoder;
- bool init_hdmi, init_dp, init_lspcon = false;
+ bool init_hdmi, init_dp;
enum phy phy = intel_port_to_phy(dev_priv, port);
/*
@@ -5055,7 +5359,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
* is initialized before lspcon.
*/
init_dp = true;
- init_lspcon = true;
init_hdmi = false;
drm_dbg_kms(&dev_priv->drm, "VBT says port %c has lspcon\n",
port_name(port));
@@ -5074,8 +5377,31 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
encoder = &dig_port->base;
- drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
- DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
+ if (INTEL_GEN(dev_priv) >= 12) {
+ enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS,
+ "DDI %s%c/PHY %s%c",
+ port >= PORT_TC1 ? "TC" : "",
+ port >= PORT_TC1 ? port_tc_name(port) : port_name(port),
+ tc_port != TC_PORT_NONE ? "TC" : "",
+ tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
+ } else if (INTEL_GEN(dev_priv) >= 11) {
+ enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS,
+ "DDI %c%s/PHY %s%c",
+ port_name(port),
+ port >= PORT_C ? " (TC)" : "",
+ tc_port != TC_PORT_NONE ? "TC" : "",
+ tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
+ } else {
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS,
+ "DDI %c/PHY %c", port_name(port), phy_name(phy));
+ }
mutex_init(&dig_port->hdcp_mutex);
dig_port->num_hdcp_streams = 0;
@@ -5092,7 +5418,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
encoder->update_pipe = intel_ddi_update_pipe;
encoder->get_hw_state = intel_ddi_get_hw_state;
encoder->get_config = intel_ddi_get_config;
+ encoder->sync_state = intel_ddi_sync_state;
+ encoder->initial_fastset_check = intel_ddi_initial_fastset_check;
encoder->suspend = intel_dp_encoder_suspend;
+ encoder->shutdown = intel_dp_encoder_shutdown;
encoder->get_power_domains = intel_ddi_get_power_domains;
encoder->type = INTEL_OUTPUT_DDI;
@@ -5101,11 +5430,13 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
encoder->cloneable = 0;
encoder->pipe_mask = ~0;
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv))
+ encoder->hpd_pin = dg1_hpd_pin(dev_priv, port);
+ else if (IS_ROCKETLAKE(dev_priv))
encoder->hpd_pin = rkl_hpd_pin(dev_priv, port);
else if (INTEL_GEN(dev_priv) >= 12)
encoder->hpd_pin = tgl_hpd_pin(dev_priv, port);
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
encoder->hpd_pin = ehl_hpd_pin(dev_priv, port);
else if (IS_GEN(dev_priv, 11))
encoder->hpd_pin = icl_hpd_pin(dev_priv, port);
@@ -5156,22 +5487,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
goto err;
}
- if (init_lspcon) {
- if (lspcon_init(dig_port))
- /* TODO: handle hdmi info frame part */
- drm_dbg_kms(&dev_priv->drm,
- "LSPCON init success on port %c\n",
- port_name(port));
- else
- /*
- * LSPCON init faied, but DP init was success, so
- * lets try to drive as DP++ port.
- */
- drm_err(&dev_priv->drm,
- "LSPCON init failed on port %c\n",
- port_name(port));
- }
-
if (INTEL_GEN(dev_priv) >= 11) {
if (intel_phy_is_tc(dev_priv, phy))
dig_port->connected = intel_tc_port_connected;
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h
index f5fb62fc9400..dcc711cfe4fe 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.h
+++ b/drivers/gpu/drm/i915/display/intel_ddi.h
@@ -7,6 +7,7 @@
#define __INTEL_DDI_H__
#include "intel_display.h"
+#include "i915_reg.h"
struct drm_connector_state;
struct drm_i915_private;
@@ -18,6 +19,10 @@ struct intel_dpll_hw_state;
struct intel_encoder;
enum transcoder;
+i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
void intel_ddi_fdi_post_disable(struct intel_atomic_state *state,
struct intel_encoder *intel_encoder,
const struct intel_crtc_state *old_crtc_state,
@@ -41,8 +46,10 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
bool state);
void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
struct intel_crtc_state *crtc_state);
-u32 bxt_signal_levels(struct intel_dp *intel_dp);
-u32 ddi_signal_levels(struct intel_dp *intel_dp);
+u32 bxt_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+u32 ddi_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
enum transcoder cpu_transcoder,
bool enable);
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index aabf09f89cad..53a00cf3fa32 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -154,7 +154,7 @@ static void ilk_pch_clock_get(struct intel_crtc *crtc,
static int intel_framebuffer_init(struct intel_framebuffer *ifb,
struct drm_i915_gem_object *obj,
struct drm_mode_fb_cmd2 *mode_cmd);
-static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state);
+static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state);
static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state);
static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
const struct intel_link_m_n *m_n,
@@ -1808,6 +1808,17 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ u32 mode_flags = crtc->mode_flags;
+
+ /*
+ * From Gen 11, In case of dsi cmd mode, frame counter wouldnt
+ * have updated at the beginning of TE, if we want to use
+ * the hw counter, then we would find it updated in only
+ * the next TE, hence switching to sw counter.
+ */
+ if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
+ return 0;
/*
* On i965gm the hardware frame counter reads
@@ -1990,13 +2001,17 @@ static int ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
return ccs_plane - fb->format->num_planes / 2;
}
-/* Return either the main plane's CCS or - if not a CCS FB - UV plane */
int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
{
+ struct drm_i915_private *i915 = to_i915(fb->dev);
+
if (is_ccs_modifier(fb->modifier))
return main_to_ccs_plane(fb, main_plane);
-
- return 1;
+ else if (INTEL_GEN(i915) < 11 &&
+ intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
+ return 1;
+ else
+ return 0;
}
bool
@@ -3616,6 +3631,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
struct intel_plane *intel_plane = to_intel_plane(primary);
struct intel_plane_state *intel_state =
to_intel_plane_state(plane_state);
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(intel_crtc->base.state);
struct drm_framebuffer *fb;
struct i915_vma *vma;
@@ -3638,7 +3655,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
if (c == &intel_crtc->base)
continue;
- if (!to_intel_crtc(c)->active)
+ if (!to_intel_crtc_state(c->state)->uapi.active)
continue;
state = to_intel_plane_state(c->primary->state);
@@ -3660,6 +3677,11 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
* pretend the BIOS never had it enabled.
*/
intel_plane_disable_noatomic(intel_crtc, intel_plane);
+ if (crtc_state->bigjoiner) {
+ struct intel_crtc *slave =
+ crtc_state->bigjoiner_linked_crtc;
+ intel_plane_disable_noatomic(slave, to_intel_plane(slave->base.primary));
+ }
return;
@@ -3696,7 +3718,8 @@ valid_fb:
drm_framebuffer_get(fb);
plane_state->crtc = &intel_crtc->base;
- intel_plane_copy_uapi_to_hw_state(intel_state, intel_state);
+ intel_plane_copy_uapi_to_hw_state(intel_state, intel_state,
+ intel_crtc);
intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
@@ -3704,127 +3727,6 @@ valid_fb:
&to_intel_frontbuffer(fb)->bits);
}
-static int skl_max_plane_width(const struct drm_framebuffer *fb,
- int color_plane,
- unsigned int rotation)
-{
- int cpp = fb->format->cpp[color_plane];
-
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_LINEAR:
- case I915_FORMAT_MOD_X_TILED:
- /*
- * Validated limit is 4k, but has 5k should
- * work apart from the following features:
- * - Ytile (already limited to 4k)
- * - FP16 (already limited to 4k)
- * - render compression (already limited to 4k)
- * - KVMR sprite and cursor (don't care)
- * - horizontal panning (TODO verify this)
- * - pipe and plane scaling (TODO verify this)
- */
- if (cpp == 8)
- return 4096;
- else
- return 5120;
- case I915_FORMAT_MOD_Y_TILED_CCS:
- case I915_FORMAT_MOD_Yf_TILED_CCS:
- case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
- /* FIXME AUX plane? */
- case I915_FORMAT_MOD_Y_TILED:
- case I915_FORMAT_MOD_Yf_TILED:
- if (cpp == 8)
- return 2048;
- else
- return 4096;
- default:
- MISSING_CASE(fb->modifier);
- return 2048;
- }
-}
-
-static int glk_max_plane_width(const struct drm_framebuffer *fb,
- int color_plane,
- unsigned int rotation)
-{
- int cpp = fb->format->cpp[color_plane];
-
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_LINEAR:
- case I915_FORMAT_MOD_X_TILED:
- if (cpp == 8)
- return 4096;
- else
- return 5120;
- case I915_FORMAT_MOD_Y_TILED_CCS:
- case I915_FORMAT_MOD_Yf_TILED_CCS:
- /* FIXME AUX plane? */
- case I915_FORMAT_MOD_Y_TILED:
- case I915_FORMAT_MOD_Yf_TILED:
- if (cpp == 8)
- return 2048;
- else
- return 5120;
- default:
- MISSING_CASE(fb->modifier);
- return 2048;
- }
-}
-
-static int icl_min_plane_width(const struct drm_framebuffer *fb)
-{
- /* Wa_14011264657, Wa_14011050563: gen11+ */
- switch (fb->format->format) {
- case DRM_FORMAT_C8:
- return 18;
- case DRM_FORMAT_RGB565:
- return 10;
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ARGB2101010:
- case DRM_FORMAT_ABGR2101010:
- case DRM_FORMAT_XVYU2101010:
- case DRM_FORMAT_Y212:
- case DRM_FORMAT_Y216:
- return 6;
- case DRM_FORMAT_NV12:
- return 20;
- case DRM_FORMAT_P010:
- case DRM_FORMAT_P012:
- case DRM_FORMAT_P016:
- return 12;
- case DRM_FORMAT_XRGB16161616F:
- case DRM_FORMAT_XBGR16161616F:
- case DRM_FORMAT_ARGB16161616F:
- case DRM_FORMAT_ABGR16161616F:
- case DRM_FORMAT_XVYU12_16161616:
- case DRM_FORMAT_XVYU16161616:
- return 4;
- default:
- return 1;
- }
-}
-
-static int icl_max_plane_width(const struct drm_framebuffer *fb,
- int color_plane,
- unsigned int rotation)
-{
- return 5120;
-}
-
-static int skl_max_plane_height(void)
-{
- return 4096;
-}
-
-static int icl_max_plane_height(void)
-{
- return 4320;
-}
static bool
skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
@@ -3882,35 +3784,55 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state)
return y;
}
+static int intel_plane_min_width(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ if (plane->min_width)
+ return plane->min_width(fb, color_plane, rotation);
+ else
+ return 1;
+}
+
+static int intel_plane_max_width(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ if (plane->max_width)
+ return plane->max_width(fb, color_plane, rotation);
+ else
+ return INT_MAX;
+}
+
+static int intel_plane_max_height(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ if (plane->max_height)
+ return plane->max_height(fb, color_plane, rotation);
+ else
+ return INT_MAX;
+}
+
static int skl_check_main_surface(struct intel_plane_state *plane_state)
{
- struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev);
+ 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;
unsigned int rotation = plane_state->hw.rotation;
int x = plane_state->uapi.src.x1 >> 16;
int y = plane_state->uapi.src.y1 >> 16;
int w = drm_rect_width(&plane_state->uapi.src) >> 16;
int h = drm_rect_height(&plane_state->uapi.src) >> 16;
- int max_width, min_width, max_height;
- u32 alignment, offset;
+ int min_width = intel_plane_min_width(plane, fb, 0, rotation);
+ int max_width = intel_plane_max_width(plane, fb, 0, rotation);
+ int max_height = intel_plane_max_height(plane, fb, 0, rotation);
int aux_plane = intel_main_to_aux_plane(fb, 0);
u32 aux_offset = plane_state->color_plane[aux_plane].offset;
-
- if (INTEL_GEN(dev_priv) >= 11) {
- max_width = icl_max_plane_width(fb, 0, rotation);
- min_width = icl_min_plane_width(fb);
- } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
- max_width = glk_max_plane_width(fb, 0, rotation);
- min_width = 1;
- } else {
- max_width = skl_max_plane_width(fb, 0, rotation);
- min_width = 1;
- }
-
- if (INTEL_GEN(dev_priv) >= 11)
- max_height = icl_max_plane_height();
- else
- max_height = skl_max_plane_height();
+ u32 alignment, offset;
if (w > max_width || w < min_width || h > max_height) {
drm_dbg_kms(&dev_priv->drm,
@@ -3930,7 +3852,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
* main surface offset, and it must be non-negative. Make
* sure that is what we will get.
*/
- if (offset > aux_offset)
+ if (aux_plane && offset > aux_offset)
offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
offset, aux_offset & ~(alignment - 1));
@@ -3993,22 +3915,19 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
{
- struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ struct drm_i915_private *i915 = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1;
- int max_width = skl_max_plane_width(fb, uv_plane, rotation);
- int max_height = 4096;
+ int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation);
+ int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation);
int x = plane_state->uapi.src.x1 >> 17;
int y = plane_state->uapi.src.y1 >> 17;
int w = drm_rect_width(&plane_state->uapi.src) >> 17;
int h = drm_rect_height(&plane_state->uapi.src) >> 17;
u32 offset;
- intel_add_fb_offsets(&x, &y, plane_state, uv_plane);
- offset = intel_plane_compute_aligned_offset(&x, &y,
- plane_state, uv_plane);
-
/* FIXME not quite sure how/if these apply to the chroma plane */
if (w > max_width || h > max_height) {
drm_dbg_kms(&i915->drm,
@@ -4017,10 +3936,14 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
return -EINVAL;
}
+ intel_add_fb_offsets(&x, &y, plane_state, uv_plane);
+ offset = intel_plane_compute_aligned_offset(&x, &y,
+ plane_state, uv_plane);
+
if (is_ccs_modifier(fb->modifier)) {
int ccs_plane = main_to_ccs_plane(fb, uv_plane);
- int aux_offset = plane_state->color_plane[ccs_plane].offset;
- int alignment = intel_surf_alignment(fb, uv_plane);
+ u32 aux_offset = plane_state->color_plane[ccs_plane].offset;
+ u32 alignment = intel_surf_alignment(fb, uv_plane);
if (offset > aux_offset)
offset = intel_plane_adjust_aligned_offset(&x, &y,
@@ -4128,7 +4051,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
}
for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) {
- plane_state->color_plane[i].offset = ~0xfff;
+ plane_state->color_plane[i].offset = 0;
plane_state->color_plane[i].x = 0;
plane_state->color_plane[i].y = 0;
}
@@ -4392,12 +4315,10 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state,
if (ret)
return ret;
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- i9xx_plane_has_windowing(plane),
- true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ i9xx_plane_has_windowing(plane));
if (ret)
return ret;
@@ -4786,6 +4707,9 @@ u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
u32 plane_ctl = 0;
+ if (crtc_state->uapi.async_flip)
+ plane_ctl |= PLANE_CTL_ASYNC_FLIP;
+
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
return plane_ctl;
@@ -4933,13 +4857,16 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
intel_has_gpu_reset(&dev_priv->gt));
}
-void intel_prepare_reset(struct drm_i915_private *dev_priv)
+void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
struct drm_atomic_state *state;
int ret;
+ if (!HAS_DISPLAY(dev_priv))
+ return;
+
/* reset doesn't touch the display */
if (!dev_priv->params.force_reset_modeset_test &&
!gpu_reset_clobbers_display(dev_priv))
@@ -4993,13 +4920,16 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
state->acquire_ctx = ctx;
}
-void intel_finish_reset(struct drm_i915_private *dev_priv)
+void intel_display_finish_reset(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
struct drm_atomic_state *state;
int ret;
+ if (!HAS_DISPLAY(dev_priv))
+ return;
+
/* reset doesn't touch the display */
if (!test_bit(I915_RESET_MODESET, &dev_priv->gt.reset.flags))
return;
@@ -5023,18 +4953,14 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
intel_pps_unlock_regs_wa(dev_priv);
intel_modeset_init_hw(dev_priv);
intel_init_clock_gating(dev_priv);
-
- spin_lock_irq(&dev_priv->irq_lock);
- if (dev_priv->display.hpd_irq_setup)
- dev_priv->display.hpd_irq_setup(dev_priv);
- spin_unlock_irq(&dev_priv->irq_lock);
+ intel_hpd_init(dev_priv);
ret = __intel_display_resume(dev, state, ctx);
if (ret)
drm_err(&dev_priv->drm,
"Restoring old state failed with %i\n", ret);
- intel_hpd_init(dev_priv);
+ intel_hpd_poll_disable(dev_priv);
}
drm_atomic_state_put(state);
@@ -6153,18 +6079,16 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
static int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
int width, height;
if (crtc_state->pch_pfit.enabled) {
width = drm_rect_width(&crtc_state->pch_pfit.dst);
height = drm_rect_height(&crtc_state->pch_pfit.dst);
} else {
- width = adjusted_mode->crtc_hdisplay;
- height = adjusted_mode->crtc_vdisplay;
+ width = pipe_mode->crtc_hdisplay;
+ height = pipe_mode->crtc_vdisplay;
}
-
return skl_update_scaler(crtc_state, !crtc_state->hw.active,
SKL_CRTC_INDEX,
&crtc_state->scaler_state.scaler_id,
@@ -6275,6 +6199,105 @@ void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state)
skl_detach_scaler(crtc, i);
}
+static int cnl_coef_tap(int i)
+{
+ return i % 7;
+}
+
+static u16 cnl_nearest_filter_coef(int t)
+{
+ return t == 3 ? 0x0800 : 0x3000;
+}
+
+/*
+ * Theory behind setting nearest-neighbor integer scaling:
+ *
+ * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set.
+ * The letter represents the filter tap (D is the center tap) and the number
+ * represents the coefficient set for a phase (0-16).
+ *
+ * +------------+------------------------+------------------------+
+ * |Index value | Data value coeffient 1 | Data value coeffient 2 |
+ * +------------+------------------------+------------------------+
+ * | 00h | B0 | A0 |
+ * +------------+------------------------+------------------------+
+ * | 01h | D0 | C0 |
+ * +------------+------------------------+------------------------+
+ * | 02h | F0 | E0 |
+ * +------------+------------------------+------------------------+
+ * | 03h | A1 | G0 |
+ * +------------+------------------------+------------------------+
+ * | 04h | C1 | B1 |
+ * +------------+------------------------+------------------------+
+ * | ... | ... | ... |
+ * +------------+------------------------+------------------------+
+ * | 38h | B16 | A16 |
+ * +------------+------------------------+------------------------+
+ * | 39h | D16 | C16 |
+ * +------------+------------------------+------------------------+
+ * | 3Ah | F16 | C16 |
+ * +------------+------------------------+------------------------+
+ * | 3Bh | Reserved | G16 |
+ * +------------+------------------------+------------------------+
+ *
+ * To enable nearest-neighbor scaling: program scaler coefficents with
+ * the center tap (Dxx) values set to 1 and all other values set to 0 as per
+ * SCALER_COEFFICIENT_FORMAT
+ *
+ */
+
+static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv,
+ enum pipe pipe, int id, int set)
+{
+ int i;
+
+ intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set),
+ PS_COEE_INDEX_AUTO_INC);
+
+ for (i = 0; i < 17 * 7; i += 2) {
+ u32 tmp;
+ int t;
+
+ t = cnl_coef_tap(i);
+ tmp = cnl_nearest_filter_coef(t);
+
+ t = cnl_coef_tap(i + 1);
+ tmp |= cnl_nearest_filter_coef(t) << 16;
+
+ intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set),
+ tmp);
+ }
+
+ intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0);
+}
+
+inline u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set)
+{
+ if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) {
+ return (PS_FILTER_PROGRAMMED |
+ PS_Y_VERT_FILTER_SELECT(set) |
+ PS_Y_HORZ_FILTER_SELECT(set) |
+ PS_UV_VERT_FILTER_SELECT(set) |
+ PS_UV_HORZ_FILTER_SELECT(set));
+ }
+
+ return PS_FILTER_MEDIUM;
+}
+
+void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
+ int id, int set, enum drm_scaling_filter filter)
+{
+ switch (filter) {
+ case DRM_SCALING_FILTER_DEFAULT:
+ break;
+ case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
+ cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set);
+ break;
+ default:
+ MISSING_CASE(filter);
+ }
+}
+
static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -6295,6 +6318,7 @@ static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
int hscale, vscale;
unsigned long irqflags;
int id;
+ u32 ps_ctrl;
if (!crtc_state->pch_pfit.enabled)
return;
@@ -6311,10 +6335,16 @@ static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
id = scaler_state->scaler_id;
+ ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
+ ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode;
+
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), PS_SCALER_EN |
- PS_FILTER_MEDIUM | scaler_state->scalers[id].mode);
+ skl_scaler_setup_filter(dev_priv, pipe, id, 0,
+ crtc_state->hw.scaling_filter);
+
+ intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl);
+
intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id),
PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id),
@@ -6560,6 +6590,43 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
icl_wa_scalerclkgating(dev_priv, pipe, false);
}
+static void skl_disable_async_flip_wa(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ const struct intel_crtc_state *new_crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_plane *plane;
+ struct intel_plane_state *new_plane_state;
+ int i;
+
+ for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
+ u32 update_mask = new_crtc_state->update_planes;
+ u32 plane_ctl, surf_addr;
+ enum plane_id plane_id;
+ unsigned long irqflags;
+ enum pipe pipe;
+
+ if (crtc->pipe != plane->pipe ||
+ !(update_mask & BIT(plane->id)))
+ continue;
+
+ plane_id = plane->id;
+ pipe = plane->pipe;
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ plane_ctl = intel_de_read_fw(dev_priv, PLANE_CTL(pipe, plane_id));
+ surf_addr = intel_de_read_fw(dev_priv, PLANE_SURF(pipe, plane_id));
+
+ plane_ctl &= ~PLANE_CTL_ASYNC_FLIP;
+
+ intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
+ intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), surf_addr);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
+ intel_wait_for_vblank(dev_priv, crtc->pipe);
+}
+
static void intel_pre_plane_update(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -6645,6 +6712,15 @@ static void intel_pre_plane_update(struct intel_atomic_state *state,
*/
if (IS_GEN(dev_priv, 2) && planes_disabling(old_crtc_state, new_crtc_state))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
+ /*
+ * WA for platforms where async address update enable bit
+ * is double buffered and only latched at start of vblank.
+ */
+ if (old_crtc_state->uapi.async_flip &&
+ !new_crtc_state->uapi.async_flip &&
+ IS_GEN_RANGE(dev_priv, 9, 10))
+ skl_disable_async_flip_wa(state, crtc, new_crtc_state);
}
static void intel_crtc_disable_planes(struct intel_atomic_state *state,
@@ -6944,7 +7020,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state,
if (intel_crtc_has_dp_encoder(new_crtc_state))
intel_dp_set_m_n(new_crtc_state, M1_N1);
- intel_set_pipe_timings(new_crtc_state);
+ intel_set_transcoder_timings(new_crtc_state);
intel_set_pipe_src_size(new_crtc_state);
if (new_crtc_state->has_pch_encoder)
@@ -7068,6 +7144,45 @@ static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, reg, val);
}
+static void icl_ddi_bigjoiner_pre_enable(struct intel_atomic_state *state,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *master = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_crtc_state *master_crtc_state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *conn;
+ struct intel_encoder *encoder = NULL;
+ int i;
+
+ if (crtc_state->bigjoiner_slave)
+ master = crtc_state->bigjoiner_linked_crtc;
+
+ master_crtc_state = intel_atomic_get_new_crtc_state(state, master);
+
+ for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
+ if (conn_state->crtc != &master->base)
+ continue;
+
+ encoder = to_intel_encoder(conn_state->best_encoder);
+ break;
+ }
+
+ if (!crtc_state->bigjoiner_slave) {
+ /* need to enable VDSC, which we skipped in pre-enable */
+ intel_dsc_enable(encoder, crtc_state);
+ } else {
+ /*
+ * Enable sequence steps 1-7 on bigjoiner master
+ */
+ intel_encoders_pre_pll_enable(state, master);
+ intel_enable_shared_dpll(master_crtc_state);
+ intel_encoders_pre_enable(state, master);
+
+ /* and DSC on slave */
+ intel_dsc_enable(NULL, crtc_state);
+ }
+}
+
static void hsw_crtc_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -7081,34 +7196,37 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (drm_WARN_ON(&dev_priv->drm, crtc->active))
return;
- intel_encoders_pre_pll_enable(state, crtc);
-
- if (new_crtc_state->shared_dpll)
- intel_enable_shared_dpll(new_crtc_state);
+ if (!new_crtc_state->bigjoiner) {
+ intel_encoders_pre_pll_enable(state, crtc);
- intel_encoders_pre_enable(state, crtc);
+ if (new_crtc_state->shared_dpll)
+ intel_enable_shared_dpll(new_crtc_state);
- if (!transcoder_is_dsi(cpu_transcoder))
- intel_set_pipe_timings(new_crtc_state);
+ intel_encoders_pre_enable(state, crtc);
+ } else {
+ icl_ddi_bigjoiner_pre_enable(state, new_crtc_state);
+ }
intel_set_pipe_src_size(new_crtc_state);
+ if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
+ bdw_set_pipemisc(new_crtc_state);
- if (cpu_transcoder != TRANSCODER_EDP &&
- !transcoder_is_dsi(cpu_transcoder))
- intel_de_write(dev_priv, PIPE_MULT(cpu_transcoder),
- new_crtc_state->pixel_multiplier - 1);
+ if (!new_crtc_state->bigjoiner_slave && !transcoder_is_dsi(cpu_transcoder)) {
+ intel_set_transcoder_timings(new_crtc_state);
- if (new_crtc_state->has_pch_encoder)
- intel_cpu_transcoder_set_m_n(new_crtc_state,
- &new_crtc_state->fdi_m_n, NULL);
+ if (cpu_transcoder != TRANSCODER_EDP)
+ intel_de_write(dev_priv, PIPE_MULT(cpu_transcoder),
+ new_crtc_state->pixel_multiplier - 1);
+
+ if (new_crtc_state->has_pch_encoder)
+ intel_cpu_transcoder_set_m_n(new_crtc_state,
+ &new_crtc_state->fdi_m_n, NULL);
- if (!transcoder_is_dsi(cpu_transcoder)) {
hsw_set_frame_start_delay(new_crtc_state);
- hsw_set_pipeconf(new_crtc_state);
}
- if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
- bdw_set_pipemisc(new_crtc_state);
+ if (!transcoder_is_dsi(cpu_transcoder))
+ hsw_set_pipeconf(new_crtc_state);
crtc->active = true;
@@ -7144,6 +7262,11 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (INTEL_GEN(dev_priv) >= 11)
icl_pipe_mbus_enable(crtc);
+ if (new_crtc_state->bigjoiner_slave) {
+ trace_intel_pipe_enable(crtc);
+ intel_crtc_vblank_on(new_crtc_state);
+ }
+
intel_encoders_enable(state, crtc);
if (psl_clkgate_wa) {
@@ -7273,9 +7396,9 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy)
{
if (phy == PHY_NONE)
return false;
- else if (IS_ROCKETLAKE(dev_priv))
+ else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
return phy <= PHY_D;
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
return phy <= PHY_C;
else if (INTEL_GEN(dev_priv) >= 11)
return phy <= PHY_B;
@@ -7285,11 +7408,11 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy)
bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy)
{
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
return false;
else if (INTEL_GEN(dev_priv) >= 12)
return phy >= PHY_D && phy <= PHY_I;
- else if (INTEL_GEN(dev_priv) >= 11 && !IS_ELKHARTLAKE(dev_priv))
+ else if (INTEL_GEN(dev_priv) >= 11 && !IS_JSL_EHL(dev_priv))
return phy >= PHY_C && phy <= PHY_F;
else
return false;
@@ -7297,23 +7420,23 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy)
enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port)
{
- if (IS_ROCKETLAKE(i915) && port >= PORT_D)
- return (enum phy)port - 1;
- else if (IS_ELKHARTLAKE(i915) && port == PORT_D)
+ if ((IS_DG1(i915) || IS_ROCKETLAKE(i915)) && port >= PORT_TC1)
+ return PHY_C + port - PORT_TC1;
+ else if (IS_JSL_EHL(i915) && port == PORT_D)
return PHY_A;
- return (enum phy)port;
+ return PHY_A + port - PORT_A;
}
enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, enum port port)
{
if (!intel_phy_is_tc(dev_priv, intel_port_to_phy(dev_priv, port)))
- return PORT_TC_NONE;
+ return TC_PORT_NONE;
if (INTEL_GEN(dev_priv) >= 12)
- return port - PORT_D;
-
- return port - PORT_C;
+ return TC_PORT_1 + port - PORT_TC1;
+ else
+ return TC_PORT_1 + port - PORT_C;
}
enum intel_display_power_domain intel_port_to_power_domain(enum port port)
@@ -7438,6 +7561,9 @@ static u64 get_crtc_power_domains(struct intel_crtc_state *crtc_state)
if (crtc_state->shared_dpll)
mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE);
+ if (crtc_state->dsc.compression_enable)
+ mask |= BIT_ULL(intel_dsc_power_domain(crtc_state));
+
return mask;
}
@@ -7484,7 +7610,7 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state,
if (intel_crtc_has_dp_encoder(new_crtc_state))
intel_dp_set_m_n(new_crtc_state, M1_N1);
- intel_set_pipe_timings(new_crtc_state);
+ intel_set_transcoder_timings(new_crtc_state);
intel_set_pipe_src_size(new_crtc_state);
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
@@ -7552,7 +7678,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state,
if (intel_crtc_has_dp_encoder(new_crtc_state))
intel_dp_set_m_n(new_crtc_state, M1_N1);
- intel_set_pipe_timings(new_crtc_state);
+ intel_set_transcoder_timings(new_crtc_state);
intel_set_pipe_src_size(new_crtc_state);
i9xx_set_pipeconf(new_crtc_state);
@@ -8026,7 +8152,7 @@ static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state)
{
- u32 pixel_rate = crtc_state->hw.adjusted_mode.crtc_clock;
+ u32 pixel_rate = crtc_state->hw.pipe_mode.crtc_clock;
unsigned int pipe_w, pipe_h, pfit_w, pfit_h;
/*
@@ -8056,6 +8182,27 @@ static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state)
pfit_w * pfit_h);
}
+static void intel_mode_from_crtc_timings(struct drm_display_mode *mode,
+ const struct drm_display_mode *timings)
+{
+ mode->hdisplay = timings->crtc_hdisplay;
+ mode->htotal = timings->crtc_htotal;
+ mode->hsync_start = timings->crtc_hsync_start;
+ mode->hsync_end = timings->crtc_hsync_end;
+
+ mode->vdisplay = timings->crtc_vdisplay;
+ mode->vtotal = timings->crtc_vtotal;
+ mode->vsync_start = timings->crtc_vsync_start;
+ mode->vsync_end = timings->crtc_vsync_end;
+
+ mode->flags = timings->flags;
+ mode->type = DRM_MODE_TYPE_DRIVER;
+
+ mode->clock = timings->crtc_clock;
+
+ drm_mode_set_name(mode);
+}
+
static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
@@ -8063,19 +8210,75 @@ static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
if (HAS_GMCH(dev_priv))
/* FIXME calculate proper pipe pixel rate for GMCH pfit */
crtc_state->pixel_rate =
- crtc_state->hw.adjusted_mode.crtc_clock;
+ crtc_state->hw.pipe_mode.crtc_clock;
else
crtc_state->pixel_rate =
ilk_pipe_pixel_rate(crtc_state);
}
+static void intel_crtc_readout_derived_state(struct intel_crtc_state *crtc_state)
+{
+ struct drm_display_mode *mode = &crtc_state->hw.mode;
+ struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
+ struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+
+ drm_mode_copy(pipe_mode, adjusted_mode);
+
+ if (crtc_state->bigjoiner) {
+ /*
+ * transcoder is programmed to the full mode,
+ * but pipe timings are half of the transcoder mode
+ */
+ pipe_mode->crtc_hdisplay /= 2;
+ pipe_mode->crtc_hblank_start /= 2;
+ pipe_mode->crtc_hblank_end /= 2;
+ pipe_mode->crtc_hsync_start /= 2;
+ pipe_mode->crtc_hsync_end /= 2;
+ pipe_mode->crtc_htotal /= 2;
+ pipe_mode->crtc_clock /= 2;
+ }
+
+ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
+ intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode);
+
+ intel_crtc_compute_pixel_rate(crtc_state);
+
+ drm_mode_copy(mode, adjusted_mode);
+ mode->hdisplay = crtc_state->pipe_src_w << crtc_state->bigjoiner;
+ mode->vdisplay = crtc_state->pipe_src_h;
+}
+
+static void intel_encoder_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ encoder->get_config(encoder, crtc_state);
+
+ intel_crtc_readout_derived_state(crtc_state);
+}
+
static int intel_crtc_compute_config(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
+ struct drm_display_mode *pipe_mode = &pipe_config->hw.pipe_mode;
int clock_limit = dev_priv->max_dotclk_freq;
+ drm_mode_copy(pipe_mode, &pipe_config->hw.adjusted_mode);
+
+ /* Adjust pipe_mode for bigjoiner, with half the horizontal mode */
+ if (pipe_config->bigjoiner) {
+ pipe_mode->crtc_clock /= 2;
+ pipe_mode->crtc_hdisplay /= 2;
+ pipe_mode->crtc_hblank_start /= 2;
+ pipe_mode->crtc_hblank_end /= 2;
+ pipe_mode->crtc_hsync_start /= 2;
+ pipe_mode->crtc_hsync_end /= 2;
+ pipe_mode->crtc_htotal /= 2;
+ pipe_config->pipe_src_w /= 2;
+ }
+
+ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
+
if (INTEL_GEN(dev_priv) < 4) {
clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
@@ -8084,16 +8287,16 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
* is > 90% of the (display) core speed.
*/
if (intel_crtc_supports_double_wide(crtc) &&
- adjusted_mode->crtc_clock > clock_limit) {
+ pipe_mode->crtc_clock > clock_limit) {
clock_limit = dev_priv->max_dotclk_freq;
pipe_config->double_wide = true;
}
}
- if (adjusted_mode->crtc_clock > clock_limit) {
+ if (pipe_mode->crtc_clock > clock_limit) {
drm_dbg_kms(&dev_priv->drm,
"requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
- adjusted_mode->crtc_clock, clock_limit,
+ pipe_mode->crtc_clock, clock_limit,
yesno(pipe_config->double_wide));
return -EINVAL;
}
@@ -8136,7 +8339,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
* WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
*/
if ((INTEL_GEN(dev_priv) > 4 || IS_G4X(dev_priv)) &&
- adjusted_mode->crtc_hsync_start == adjusted_mode->crtc_hdisplay)
+ pipe_mode->crtc_hsync_start == pipe_mode->crtc_hdisplay)
return -EINVAL;
intel_crtc_compute_pixel_rate(pipe_config);
@@ -8806,7 +9009,7 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
crtc_state->dpll_hw_state.dpll = dpll;
}
-static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state)
+static void intel_set_transcoder_timings(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);
@@ -8892,8 +9095,8 @@ static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state)
return intel_de_read(dev_priv, PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK;
}
-static void intel_get_pipe_timings(struct intel_crtc *crtc,
- struct intel_crtc_state *pipe_config)
+static void intel_get_transcoder_timings(struct intel_crtc *crtc,
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
@@ -8947,30 +9150,6 @@ static void intel_get_pipe_src_size(struct intel_crtc *crtc,
tmp = intel_de_read(dev_priv, PIPESRC(crtc->pipe));
pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1;
-
- pipe_config->hw.mode.vdisplay = pipe_config->pipe_src_h;
- pipe_config->hw.mode.hdisplay = pipe_config->pipe_src_w;
-}
-
-void intel_mode_from_pipe_config(struct drm_display_mode *mode,
- struct intel_crtc_state *pipe_config)
-{
- mode->hdisplay = pipe_config->hw.adjusted_mode.crtc_hdisplay;
- mode->htotal = pipe_config->hw.adjusted_mode.crtc_htotal;
- mode->hsync_start = pipe_config->hw.adjusted_mode.crtc_hsync_start;
- mode->hsync_end = pipe_config->hw.adjusted_mode.crtc_hsync_end;
-
- mode->vdisplay = pipe_config->hw.adjusted_mode.crtc_vdisplay;
- mode->vtotal = pipe_config->hw.adjusted_mode.crtc_vtotal;
- mode->vsync_start = pipe_config->hw.adjusted_mode.crtc_vsync_start;
- mode->vsync_end = pipe_config->hw.adjusted_mode.crtc_vsync_end;
-
- mode->flags = pipe_config->hw.adjusted_mode.flags;
- mode->type = DRM_MODE_TYPE_DRIVER;
-
- mode->clock = pipe_config->hw.adjusted_mode.crtc_clock;
-
- drm_mode_set_name(mode);
}
static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state)
@@ -9516,7 +9695,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
if (INTEL_GEN(dev_priv) < 4)
pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
- intel_get_pipe_timings(crtc, pipe_config);
+ intel_get_transcoder_timings(crtc, pipe_config);
intel_get_pipe_src_size(crtc, pipe_config);
i9xx_get_pfit_config(pipe_config);
@@ -10537,6 +10716,7 @@ static void
skl_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
+ struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
@@ -10553,6 +10733,12 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
drm_WARN_ON(dev, pipe != crtc->pipe);
+ if (crtc_state->bigjoiner) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Unsupported bigjoiner configuration for initial FB\n");
+ return;
+ }
+
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb) {
drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");
@@ -10761,6 +10947,7 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
if (intel_de_read(dev_priv, PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
struct intel_shared_dpll *pll;
enum intel_dpll_id pll_id;
+ bool pll_active;
pipe_config->has_pch_encoder = true;
@@ -10788,8 +10975,9 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
intel_get_shared_dpll_by_id(dev_priv, pll_id);
pll = pipe_config->shared_dpll;
- drm_WARN_ON(dev, !pll->info->funcs->get_hw_state(dev_priv, pll,
- &pipe_config->dpll_hw_state));
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(dev, !pll_active);
tmp = pipe_config->dpll_hw_state.dpll;
pipe_config->pixel_multiplier =
@@ -10801,7 +10989,7 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
pipe_config->pixel_multiplier = 1;
}
- intel_get_pipe_timings(crtc, pipe_config);
+ intel_get_transcoder_timings(crtc, pipe_config);
intel_get_pipe_src_size(crtc, pipe_config);
ilk_get_pfit_config(pipe_config);
@@ -10837,19 +11025,32 @@ static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
return 0;
}
-static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
+static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
struct intel_crtc_state *pipe_config)
{
+ enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT;
+ enum phy phy = intel_port_to_phy(dev_priv, port);
+ struct icl_port_dpll *port_dpll;
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
- u32 temp;
+ bool pll_active;
+ u32 clk_sel;
- temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
- id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
+ clk_sel = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)) & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ id = DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy);
- if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2))
+ if (WARN_ON(id > DPLL_ID_DG1_DPLL3))
return;
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+ port_dpll = &pipe_config->icl_port_dplls[port_dpll_id];
+
+ port_dpll->pll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &port_dpll->hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
+
+ icl_set_active_port_dpll(pipe_config, port_dpll_id);
}
static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
@@ -10857,7 +11058,10 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
{
enum phy phy = intel_port_to_phy(dev_priv, port);
enum icl_port_dpll_id port_dpll_id;
+ struct icl_port_dpll *port_dpll;
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
+ bool pll_active;
u32 temp;
if (intel_phy_is_combo(dev_priv, phy)) {
@@ -10892,17 +11096,46 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
return;
}
- pipe_config->icl_port_dplls[port_dpll_id].pll =
- intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+ port_dpll = &pipe_config->icl_port_dplls[port_dpll_id];
+
+ port_dpll->pll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &port_dpll->hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
icl_set_active_port_dpll(pipe_config, port_dpll_id);
}
+static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
+ struct intel_crtc_state *pipe_config)
+{
+ struct intel_shared_dpll *pll;
+ enum intel_dpll_id id;
+ bool pll_active;
+ u32 temp;
+
+ temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+ id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
+
+ if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2))
+ return;
+
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
+}
+
static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_state *pipe_config)
{
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
+ bool pll_active;
switch (port) {
case PORT_A:
@@ -10919,13 +11152,20 @@ static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
return;
}
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
}
static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
struct intel_crtc_state *pipe_config)
{
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
+ bool pll_active;
u32 temp;
temp = intel_de_read(dev_priv, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
@@ -10934,14 +11174,21 @@ static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL3))
return;
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
}
static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
struct intel_crtc_state *pipe_config)
{
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
u32 ddi_pll_sel = intel_de_read(dev_priv, PORT_CLK_SEL(port));
+ bool pll_active;
switch (ddi_pll_sel) {
case PORT_CLK_SEL_WRPLL1:
@@ -10969,7 +11216,12 @@ static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
return;
}
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
}
static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
@@ -11129,7 +11381,6 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc,
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
- struct intel_shared_dpll *pll;
enum port port;
u32 tmp;
@@ -11139,30 +11390,27 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc,
} else {
tmp = intel_de_read(dev_priv,
TRANS_DDI_FUNC_CTL(cpu_transcoder));
+ if (!(tmp & TRANS_DDI_FUNC_ENABLE))
+ return;
if (INTEL_GEN(dev_priv) >= 12)
port = TGL_TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp);
else
port = TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp);
}
- if (INTEL_GEN(dev_priv) >= 11)
+ if (IS_DG1(dev_priv))
+ dg1_get_ddi_pll(dev_priv, port, pipe_config);
+ else if (INTEL_GEN(dev_priv) >= 11)
icl_get_ddi_pll(dev_priv, port, pipe_config);
else if (IS_CANNONLAKE(dev_priv))
cnl_get_ddi_pll(dev_priv, port, pipe_config);
- else if (IS_GEN9_BC(dev_priv))
- skl_get_ddi_pll(dev_priv, port, pipe_config);
else if (IS_GEN9_LP(dev_priv))
bxt_get_ddi_pll(dev_priv, port, pipe_config);
+ else if (IS_GEN9_BC(dev_priv))
+ skl_get_ddi_pll(dev_priv, port, pipe_config);
else
hsw_get_ddi_pll(dev_priv, port, pipe_config);
- pll = pipe_config->shared_dpll;
- if (pll) {
- drm_WARN_ON(&dev_priv->drm,
- !pll->info->funcs->get_hw_state(dev_priv, pll,
- &pipe_config->dpll_hw_state));
- }
-
/*
* Haswell has only FDI/PCH transcoder A. It is which is connected to
* DDI E. So just check whether this pipe is wired to DDI E and whether
@@ -11212,13 +11460,22 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
active = true;
}
- if (!active)
- goto out;
+ intel_dsc_get_config(pipe_config);
- if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
+ if (!active) {
+ /* bigjoiner slave doesn't enable transcoder */
+ if (!pipe_config->bigjoiner_slave)
+ goto out;
+
+ active = true;
+ pipe_config->pixel_multiplier = 1;
+
+ /* we cannot read out most state, so don't bother.. */
+ pipe_config->quirks |= PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE;
+ } else if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
INTEL_GEN(dev_priv) >= 11) {
hsw_get_ddi_port_state(crtc, pipe_config);
- intel_get_pipe_timings(crtc, pipe_config);
+ intel_get_transcoder_timings(crtc, pipe_config);
}
intel_get_pipe_src_size(crtc, pipe_config);
@@ -11234,18 +11491,6 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
} else {
pipe_config->output_format =
bdw_get_pipemisc_output_format(crtc);
-
- /*
- * Currently there is no interface defined to
- * check user preference between RGB/YCBCR444
- * or YCBCR420. So the only possible case for
- * YCBCR444 usage is driving YCBCR420 output
- * with LSPCON, when pipe is configured for
- * YCBCR444 output and LSPCON takes care of
- * downsampling it.
- */
- pipe_config->lspcon_downsampling =
- pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR444;
}
pipe_config->gamma_mode = intel_de_read(dev_priv,
@@ -11302,7 +11547,10 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
}
}
- if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
+ if (pipe_config->bigjoiner_slave) {
+ /* Cannot be read out as a slave, set to 0. */
+ pipe_config->pixel_multiplier = 0;
+ } else if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
pipe_config->pixel_multiplier =
intel_de_read(dev_priv,
@@ -11319,6 +11567,21 @@ out:
return active;
}
+static bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+
+ if (!i915->display.get_pipe_config(crtc, crtc_state))
+ return false;
+
+ crtc_state->hw.active = true;
+
+ intel_crtc_readout_derived_state(crtc_state);
+
+ return true;
+}
+
static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
@@ -11424,6 +11687,8 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_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) {
@@ -11431,17 +11696,16 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
return -EINVAL;
}
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true, true);
+ 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 = drm_plane_state_src(&plane_state->uapi);
- plane_state->uapi.dst = drm_plane_state_dest(&plane_state->uapi);
+ plane_state->uapi.src = src;
+ plane_state->uapi.dst = dst;
ret = intel_cursor_check_surface(plane_state);
if (ret)
@@ -11817,6 +12081,9 @@ static void i9xx_update_cursor(struct intel_plane *plane,
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) {
@@ -12312,15 +12579,15 @@ intel_encoder_current_mode(struct intel_encoder *encoder)
return NULL;
}
- if (!dev_priv->display.get_pipe_config(crtc, crtc_state)) {
+ if (!intel_crtc_get_pipe_config(crtc_state)) {
kfree(crtc_state);
kfree(mode);
return NULL;
}
- encoder->get_config(encoder, crtc_state);
+ intel_encoder_get_config(encoder, crtc_state);
- intel_mode_from_pipe_config(mode, crtc_state);
+ intel_mode_from_crtc_timings(mode, &crtc_state->hw.adjusted_mode);
kfree(crtc_state);
@@ -12506,7 +12773,7 @@ static bool encoders_cloneable(const struct intel_encoder *a,
b->cloneable & (1 << a->type));
}
-static bool check_single_encoder_cloning(struct drm_atomic_state *state,
+static bool check_single_encoder_cloning(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_encoder *encoder)
{
@@ -12515,7 +12782,7 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
struct drm_connector_state *connector_state;
int i;
- for_each_new_connector_in_state(state, connector, connector_state, i) {
+ for_each_new_connector_in_state(&state->base, connector, connector_state, i) {
if (connector_state->crtc != &crtc->base)
continue;
@@ -12630,7 +12897,7 @@ static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state)
memcpy(linked_state->color_plane, plane_state->color_plane,
sizeof(linked_state->color_plane));
- intel_plane_copy_uapi_to_hw_state(linked_state, plane_state);
+ intel_plane_copy_hw_state(linked_state, plane_state);
linked_state->uapi.src = plane_state->uapi.src;
linked_state->uapi.dst = plane_state->uapi.dst;
@@ -12664,15 +12931,15 @@ static bool c8_planes_changed(const struct intel_crtc_state *new_crtc_state)
static u16 hsw_linetime_wm(const struct intel_crtc_state *crtc_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
int linetime_wm;
if (!crtc_state->hw.enable)
return 0;
- linetime_wm = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
- adjusted_mode->crtc_clock);
+ linetime_wm = DIV_ROUND_CLOSEST(pipe_mode->crtc_htotal * 1000 * 8,
+ pipe_mode->crtc_clock);
return min(linetime_wm, 0x1ff);
}
@@ -12680,14 +12947,14 @@ static u16 hsw_linetime_wm(const struct intel_crtc_state *crtc_state)
static u16 hsw_ips_linetime_wm(const struct intel_crtc_state *crtc_state,
const struct intel_cdclk_state *cdclk_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
int linetime_wm;
if (!crtc_state->hw.enable)
return 0;
- linetime_wm = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
+ linetime_wm = DIV_ROUND_CLOSEST(pipe_mode->crtc_htotal * 1000 * 8,
cdclk_state->logical.cdclk);
return min(linetime_wm, 0x1ff);
@@ -12697,14 +12964,14 @@ static u16 skl_linetime_wm(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);
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
int linetime_wm;
if (!crtc_state->hw.enable)
return 0;
- linetime_wm = DIV_ROUND_UP(adjusted_mode->crtc_htotal * 1000 * 8,
+ linetime_wm = DIV_ROUND_UP(pipe_mode->crtc_htotal * 1000 * 8,
crtc_state->pixel_rate);
/* Display WA #1135: BXT:ALL GLK:ALL */
@@ -12755,6 +13022,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
if (mode_changed && crtc_state->hw.enable &&
dev_priv->display.crtc_compute_clock &&
+ !crtc_state->bigjoiner_slave &&
!drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll)) {
ret = dev_priv->display.crtc_compute_clock(crtc, crtc_state);
if (ret)
@@ -12828,8 +13096,11 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
}
- if (!mode_changed)
- intel_psr2_sel_fetch_update(state, crtc);
+ if (!mode_changed) {
+ ret = intel_psr2_sel_fetch_update(state, crtc);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -13059,11 +13330,11 @@ static void intel_dump_plane_state(const struct intel_plane_state *plane_state)
}
drm_dbg_kms(&i915->drm,
- "[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %s, visible: %s\n",
+ "[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %s modifier = 0x%llx, visible: %s\n",
plane->base.base.id, plane->base.name,
fb->base.id, fb->width, fb->height,
drm_get_format_name(fb->format->format, &format_name),
- yesno(plane_state->uapi.visible));
+ fb->modifier, yesno(plane_state->uapi.visible));
drm_dbg_kms(&i915->drm, "\trotation: 0x%x, scaler: %d\n",
plane_state->hw.rotation, plane_state->scaler_id);
if (plane_state->uapi.visible)
@@ -13103,11 +13374,18 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
transcoder_name(pipe_config->cpu_transcoder),
pipe_config->pipe_bpp, pipe_config->dither);
+ drm_dbg_kms(&dev_priv->drm, "MST master transcoder: %s\n",
+ transcoder_name(pipe_config->mst_master_transcoder));
+
drm_dbg_kms(&dev_priv->drm,
"port sync: master transcoder: %s, slave transcoder bitmask = 0x%x\n",
transcoder_name(pipe_config->master_transcoder),
pipe_config->sync_mode_slaves_mask);
+ drm_dbg_kms(&dev_priv->drm, "bigjoiner: %s\n",
+ pipe_config->bigjoiner_slave ? "slave" :
+ pipe_config->bigjoiner ? "master" : "no");
+
if (pipe_config->has_pch_encoder)
intel_dump_m_n_config(pipe_config, "fdi",
pipe_config->fdi_lanes,
@@ -13155,6 +13433,9 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
drm_dbg_kms(&dev_priv->drm, "adjusted mode:\n");
drm_mode_debug_printmodeline(&pipe_config->hw.adjusted_mode);
intel_dump_crtc_timings(dev_priv, &pipe_config->hw.adjusted_mode);
+ drm_dbg_kms(&dev_priv->drm, "pipe mode:\n");
+ drm_mode_debug_printmodeline(&pipe_config->hw.pipe_mode);
+ intel_dump_crtc_timings(dev_priv, &pipe_config->hw.pipe_mode);
drm_dbg_kms(&dev_priv->drm,
"port clock: %d, pipe src size: %dx%d, pixel rate %d\n",
pipe_config->port_clock,
@@ -13200,8 +13481,11 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
pipe_config->csc_mode, pipe_config->gamma_mode,
pipe_config->gamma_enable, pipe_config->csc_enable);
- drm_dbg_kms(&dev_priv->drm, "MST master transcoder: %s\n",
- transcoder_name(pipe_config->mst_master_transcoder));
+ drm_dbg_kms(&dev_priv->drm, "degamma lut: %d entries, gamma lut: %d entries\n",
+ pipe_config->hw.degamma_lut ?
+ drm_color_lut_size(pipe_config->hw.degamma_lut) : 0,
+ pipe_config->hw.gamma_lut ?
+ drm_color_lut_size(pipe_config->hw.gamma_lut) : 0);
dump_planes:
if (!state)
@@ -13283,29 +13567,48 @@ static bool check_digital_port_conflicts(struct intel_atomic_state *state)
}
static void
-intel_crtc_copy_uapi_to_hw_state_nomodeset(struct intel_crtc_state *crtc_state)
+intel_crtc_copy_uapi_to_hw_state_nomodeset(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
- intel_crtc_copy_color_blobs(crtc_state);
+ const struct intel_crtc_state *from_crtc_state = crtc_state;
+
+ if (crtc_state->bigjoiner_slave) {
+ from_crtc_state = intel_atomic_get_new_crtc_state(state,
+ crtc_state->bigjoiner_linked_crtc);
+
+ /* No need to copy state if the master state is unchanged */
+ if (!from_crtc_state)
+ return;
+ }
+
+ intel_crtc_copy_color_blobs(crtc_state, from_crtc_state);
}
static void
-intel_crtc_copy_uapi_to_hw_state(struct intel_crtc_state *crtc_state)
+intel_crtc_copy_uapi_to_hw_state(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
crtc_state->hw.enable = crtc_state->uapi.enable;
crtc_state->hw.active = crtc_state->uapi.active;
crtc_state->hw.mode = crtc_state->uapi.mode;
crtc_state->hw.adjusted_mode = crtc_state->uapi.adjusted_mode;
- intel_crtc_copy_uapi_to_hw_state_nomodeset(crtc_state);
+ crtc_state->hw.scaling_filter = crtc_state->uapi.scaling_filter;
+
+ intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc_state);
}
static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state)
{
+ if (crtc_state->bigjoiner_slave)
+ return;
+
crtc_state->uapi.enable = crtc_state->hw.enable;
crtc_state->uapi.active = crtc_state->hw.active;
drm_WARN_ON(crtc_state->uapi.crtc->dev,
drm_atomic_set_mode_for_crtc(&crtc_state->uapi, &crtc_state->hw.mode) < 0);
crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
+ crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter;
/* copy color blobs to uapi */
drm_property_replace_blob(&crtc_state->uapi.degamma_lut,
@@ -13317,7 +13620,49 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state
}
static int
-intel_crtc_prepare_cleared_state(struct intel_crtc_state *crtc_state)
+copy_bigjoiner_crtc_state(struct intel_crtc_state *crtc_state,
+ const struct intel_crtc_state *from_crtc_state)
+{
+ struct intel_crtc_state *saved_state;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+ saved_state = kmemdup(from_crtc_state, sizeof(*saved_state), GFP_KERNEL);
+ if (!saved_state)
+ return -ENOMEM;
+
+ saved_state->uapi = crtc_state->uapi;
+ saved_state->scaler_state = crtc_state->scaler_state;
+ saved_state->shared_dpll = crtc_state->shared_dpll;
+ saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
+ saved_state->crc_enabled = crtc_state->crc_enabled;
+
+ intel_crtc_free_hw_state(crtc_state);
+ memcpy(crtc_state, saved_state, sizeof(*crtc_state));
+ kfree(saved_state);
+
+ /* Re-init hw state */
+ memset(&crtc_state->hw, 0, sizeof(saved_state->hw));
+ crtc_state->hw.enable = from_crtc_state->hw.enable;
+ crtc_state->hw.active = from_crtc_state->hw.active;
+ crtc_state->hw.pipe_mode = from_crtc_state->hw.pipe_mode;
+ crtc_state->hw.adjusted_mode = from_crtc_state->hw.adjusted_mode;
+
+ /* Some fixups */
+ crtc_state->uapi.mode_changed = from_crtc_state->uapi.mode_changed;
+ crtc_state->uapi.connectors_changed = from_crtc_state->uapi.connectors_changed;
+ crtc_state->uapi.active_changed = from_crtc_state->uapi.active_changed;
+ crtc_state->nv12_planes = crtc_state->c8_planes = crtc_state->update_planes = 0;
+ crtc_state->bigjoiner_linked_crtc = to_intel_crtc(from_crtc_state->uapi.crtc);
+ crtc_state->bigjoiner_slave = true;
+ crtc_state->cpu_transcoder = (enum transcoder)crtc->pipe;
+ crtc_state->has_audio = false;
+
+ return 0;
+}
+
+static int
+intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
+ 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);
@@ -13349,16 +13694,16 @@ intel_crtc_prepare_cleared_state(struct intel_crtc_state *crtc_state)
memcpy(crtc_state, saved_state, sizeof(*crtc_state));
kfree(saved_state);
- intel_crtc_copy_uapi_to_hw_state(crtc_state);
+ intel_crtc_copy_uapi_to_hw_state(state, crtc_state);
return 0;
}
static int
-intel_modeset_pipe_config(struct intel_crtc_state *pipe_config)
+intel_modeset_pipe_config(struct intel_atomic_state *state,
+ struct intel_crtc_state *pipe_config)
{
struct drm_crtc *crtc = pipe_config->uapi.crtc;
- struct drm_atomic_state *state = pipe_config->uapi.state;
struct drm_i915_private *i915 = to_i915(pipe_config->uapi.crtc->dev);
struct drm_connector *connector;
struct drm_connector_state *connector_state;
@@ -13400,7 +13745,7 @@ intel_modeset_pipe_config(struct intel_crtc_state *pipe_config)
&pipe_config->pipe_src_w,
&pipe_config->pipe_src_h);
- for_each_new_connector_in_state(state, connector, connector_state, i) {
+ for_each_new_connector_in_state(&state->base, connector, connector_state, i) {
struct intel_encoder *encoder =
to_intel_encoder(connector_state->best_encoder);
@@ -13438,7 +13783,7 @@ encoder_retry:
* adjust it according to limitations or connector properties, and also
* a chance to reject the mode entirely.
*/
- for_each_new_connector_in_state(state, connector, connector_state, i) {
+ for_each_new_connector_in_state(&state->base, connector, connector_state, i) {
struct intel_encoder *encoder =
to_intel_encoder(connector_state->best_encoder);
@@ -13898,21 +14243,53 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_X(output_types);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hdisplay);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_htotal);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_end);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_end);
-
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vdisplay);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vtotal);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_end);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_end);
-
- PIPE_CONF_CHECK_I(pixel_multiplier);
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE)) {
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hsync_end);
+
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vsync_end);
+
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_end);
+
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_end);
+
+ PIPE_CONF_CHECK_I(pixel_multiplier);
+
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_INTERLACE);
+
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_PHSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_NHSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_PVSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_NVSYNC);
+ }
+ }
+
PIPE_CONF_CHECK_I(output_format);
PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
@@ -13922,24 +14299,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(hdmi_scrambling);
PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio);
PIPE_CONF_CHECK_BOOL(has_infoframe);
- PIPE_CONF_CHECK_BOOL(fec_enable);
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE))
+ PIPE_CONF_CHECK_BOOL(fec_enable);
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_INTERLACE);
-
- if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_PHSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_NHSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_PVSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_NVSYNC);
- }
-
PIPE_CONF_CHECK_X(gmch_pfit.control);
/* pfit ratios are autocomputed by the hw on gen4+ */
if (INTEL_GEN(dev_priv) < 4)
@@ -13965,7 +14330,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
}
PIPE_CONF_CHECK_I(scaler_state.scaler_id);
- PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE))
+ PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
PIPE_CONF_CHECK_X(gamma_mode);
if (IS_CHERRYVIEW(dev_priv))
@@ -13986,48 +14353,53 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(double_wide);
PIPE_CONF_CHECK_P(shared_dpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
- PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
- PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
- PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.spll);
- PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
- PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
- PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
- PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
-
- PIPE_CONF_CHECK_X(dsi_pll.ctrl);
- PIPE_CONF_CHECK_X(dsi_pll.div);
-
- if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
- PIPE_CONF_CHECK_I(pipe_bpp);
-
- PIPE_CONF_CHECK_CLOCK_FUZZY(hw.adjusted_mode.crtc_clock);
- PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
-
- PIPE_CONF_CHECK_I(min_voltage_level);
+
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE)) {
+ PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
+ PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.spll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
+
+ PIPE_CONF_CHECK_X(dsi_pll.ctrl);
+ PIPE_CONF_CHECK_X(dsi_pll.div);
+
+ if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
+ PIPE_CONF_CHECK_I(pipe_bpp);
+
+ PIPE_CONF_CHECK_CLOCK_FUZZY(hw.pipe_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(hw.adjusted_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
+
+ PIPE_CONF_CHECK_I(min_voltage_level);
+ }
PIPE_CONF_CHECK_X(infoframes.enable);
PIPE_CONF_CHECK_X(infoframes.gcp);
@@ -14039,6 +14411,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_X(sync_mode_slaves_mask);
PIPE_CONF_CHECK_I(master_transcoder);
+ PIPE_CONF_CHECK_BOOL(bigjoiner);
+ PIPE_CONF_CHECK_BOOL(bigjoiner_slave);
+ PIPE_CONF_CHECK_P(bigjoiner_linked_crtc);
PIPE_CONF_CHECK_I(dsc.compression_enable);
PIPE_CONF_CHECK_I(dsc.dsc_split);
@@ -14310,6 +14685,7 @@ verify_crtc_state(struct intel_crtc *crtc,
struct intel_encoder *encoder;
struct intel_crtc_state *pipe_config = old_crtc_state;
struct drm_atomic_state *state = old_crtc_state->uapi.state;
+ struct intel_crtc *master = crtc;
__drm_atomic_helper_crtc_destroy_state(&old_crtc_state->uapi);
intel_crtc_free_hw_state(old_crtc_state);
@@ -14321,8 +14697,7 @@ verify_crtc_state(struct intel_crtc *crtc,
pipe_config->hw.enable = new_crtc_state->hw.enable;
- pipe_config->hw.active =
- dev_priv->display.get_pipe_config(crtc, pipe_config);
+ intel_crtc_get_pipe_config(pipe_config);
/* we keep both pipes enabled on 830 */
if (IS_I830(dev_priv) && pipe_config->hw.active)
@@ -14338,7 +14713,10 @@ verify_crtc_state(struct intel_crtc *crtc,
"(expected %i, found %i)\n",
new_crtc_state->hw.active, crtc->active);
- for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+ if (new_crtc_state->bigjoiner_slave)
+ master = new_crtc_state->bigjoiner_linked_crtc;
+
+ for_each_encoder_on_crtc(dev, &master->base, encoder) {
enum pipe pipe;
bool active;
@@ -14348,16 +14726,14 @@ verify_crtc_state(struct intel_crtc *crtc,
encoder->base.base.id, active,
new_crtc_state->hw.active);
- I915_STATE_WARN(active && crtc->pipe != pipe,
+ I915_STATE_WARN(active && master->pipe != pipe,
"Encoder connected to wrong pipe %c\n",
pipe_name(pipe));
if (active)
- encoder->get_config(encoder, pipe_config);
+ intel_encoder_get_config(encoder, pipe_config);
}
- intel_crtc_compute_pixel_rate(pipe_config);
-
if (!new_crtc_state->hw.active)
return;
@@ -14398,7 +14774,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv,
drm_dbg_kms(&dev_priv->drm, "%s\n", pll->info->name);
- active = pll->info->funcs->get_hw_state(dev_priv, pll, &dpll_hw_state);
+ active = intel_dpll_get_hw_state(dev_priv, pll, &dpll_hw_state);
if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) {
I915_STATE_WARN(!pll->on && pll->active_mask,
@@ -14734,6 +15110,44 @@ static bool active_planes_affects_min_cdclk(struct drm_i915_private *dev_priv)
IS_IVYBRIDGE(dev_priv) || (INTEL_GEN(dev_priv) >= 11);
}
+static int intel_crtc_add_bigjoiner_planes(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_crtc *other)
+{
+ const struct intel_plane_state *plane_state;
+ struct intel_plane *plane;
+ u8 plane_ids = 0;
+ int i;
+
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+ if (plane->pipe == crtc->pipe)
+ plane_ids |= BIT(plane->id);
+ }
+
+ return intel_crtc_add_planes_to_state(state, other, plane_ids);
+}
+
+static int intel_bigjoiner_add_affected_planes(struct intel_atomic_state *state)
+{
+ const struct intel_crtc_state *crtc_state;
+ struct intel_crtc *crtc;
+ int i;
+
+ for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
+ int ret;
+
+ if (!crtc_state->bigjoiner)
+ continue;
+
+ ret = intel_crtc_add_bigjoiner_planes(state, crtc,
+ crtc_state->bigjoiner_linked_crtc);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int intel_atomic_check_planes(struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
@@ -14747,6 +15161,10 @@ static int intel_atomic_check_planes(struct intel_atomic_state *state)
if (ret)
return ret;
+ ret = intel_bigjoiner_add_affected_planes(state);
+ if (ret)
+ return ret;
+
for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
ret = intel_plane_atomic_check(state, plane);
if (ret) {
@@ -14853,8 +15271,10 @@ static int intel_atomic_check_crtcs(struct intel_atomic_state *state)
int i;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
- int ret = intel_crtc_atomic_check(state, crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ int ret;
+
+ ret = intel_crtc_atomic_check(state, crtc);
if (ret) {
drm_dbg_atomic(&i915->drm,
"[CRTC:%d:%s] atomic driver check failed\n",
@@ -14883,6 +15303,229 @@ static bool intel_cpu_transcoders_need_modeset(struct intel_atomic_state *state,
return false;
}
+static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_crtc_state *old_crtc_state,
+ struct intel_crtc_state *new_crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *slave_crtc_state, *master_crtc_state;
+ struct intel_crtc *slave, *master;
+
+ /* slave being enabled, is master is still claiming this crtc? */
+ if (old_crtc_state->bigjoiner_slave) {
+ slave = crtc;
+ master = old_crtc_state->bigjoiner_linked_crtc;
+ master_crtc_state = intel_atomic_get_new_crtc_state(state, master);
+ if (!master_crtc_state || !needs_modeset(master_crtc_state))
+ goto claimed;
+ }
+
+ if (!new_crtc_state->bigjoiner)
+ return 0;
+
+ if (1 + crtc->pipe >= INTEL_NUM_PIPES(dev_priv)) {
+ DRM_DEBUG_KMS("[CRTC:%d:%s] Big joiner configuration requires "
+ "CRTC + 1 to be used, doesn't exist\n",
+ crtc->base.base.id, crtc->base.name);
+ return -EINVAL;
+ }
+
+ slave = new_crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+ slave_crtc_state = intel_atomic_get_crtc_state(&state->base, slave);
+ master = crtc;
+ if (IS_ERR(slave_crtc_state))
+ return PTR_ERR(slave_crtc_state);
+
+ /* master being enabled, slave was already configured? */
+ if (slave_crtc_state->uapi.enable)
+ goto claimed;
+
+ DRM_DEBUG_KMS("[CRTC:%d:%s] Used as slave for big joiner\n",
+ slave->base.base.id, slave->base.name);
+
+ return copy_bigjoiner_crtc_state(slave_crtc_state, new_crtc_state);
+
+claimed:
+ DRM_DEBUG_KMS("[CRTC:%d:%s] Slave is enabled as normal CRTC, but "
+ "[CRTC:%d:%s] claiming this CRTC for bigjoiner.\n",
+ slave->base.base.id, slave->base.name,
+ master->base.base.id, master->base.name);
+ return -EINVAL;
+}
+
+static int kill_bigjoiner_slave(struct intel_atomic_state *state,
+ struct intel_crtc_state *master_crtc_state)
+{
+ struct intel_crtc_state *slave_crtc_state =
+ intel_atomic_get_crtc_state(&state->base,
+ master_crtc_state->bigjoiner_linked_crtc);
+
+ if (IS_ERR(slave_crtc_state))
+ return PTR_ERR(slave_crtc_state);
+
+ slave_crtc_state->bigjoiner = master_crtc_state->bigjoiner = false;
+ slave_crtc_state->bigjoiner_slave = master_crtc_state->bigjoiner_slave = false;
+ slave_crtc_state->bigjoiner_linked_crtc = master_crtc_state->bigjoiner_linked_crtc = NULL;
+ intel_crtc_copy_uapi_to_hw_state(state, slave_crtc_state);
+ return 0;
+}
+
+/**
+ * DOC: asynchronous flip implementation
+ *
+ * Asynchronous page flip is the implementation for the DRM_MODE_PAGE_FLIP_ASYNC
+ * flag. Currently async flip is only supported via the drmModePageFlip IOCTL.
+ * Correspondingly, support is currently added for primary plane only.
+ *
+ * Async flip can only change the plane surface address, so anything else
+ * changing is rejected from the intel_atomic_check_async() function.
+ * Once this check is cleared, flip done interrupt is enabled using
+ * the skl_enable_flip_done() function.
+ *
+ * As soon as the surface address register is written, flip done interrupt is
+ * generated and the requested events are sent to the usersapce in the interrupt
+ * handler itself. The timestamp and sequence sent during the flip done event
+ * correspond to the last vblank and have no relation to the actual time when
+ * the flip done event was sent.
+ */
+static int intel_atomic_check_async(struct intel_atomic_state *state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ const struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+ const struct intel_plane_state *new_plane_state, *old_plane_state;
+ struct intel_crtc *crtc;
+ struct intel_plane *plane;
+ int i;
+
+ for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+ new_crtc_state, i) {
+ if (needs_modeset(new_crtc_state)) {
+ drm_dbg_kms(&i915->drm, "Modeset Required. Async flip not supported\n");
+ return -EINVAL;
+ }
+
+ if (!new_crtc_state->hw.active) {
+ drm_dbg_kms(&i915->drm, "CRTC inactive\n");
+ return -EINVAL;
+ }
+ if (old_crtc_state->active_planes != new_crtc_state->active_planes) {
+ drm_dbg_kms(&i915->drm,
+ "Active planes cannot be changed during async flip\n");
+ return -EINVAL;
+ }
+ }
+
+ for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
+ new_plane_state, i) {
+ /*
+ * TODO: Async flip is only supported through the page flip IOCTL
+ * as of now. So support currently added for primary plane only.
+ * Support for other planes on platforms on which supports
+ * this(vlv/chv and icl+) should be added when async flip is
+ * enabled in the atomic IOCTL path.
+ */
+ if (plane->id != PLANE_PRIMARY)
+ return -EINVAL;
+
+ /*
+ * FIXME: This check is kept generic for all platforms.
+ * Need to verify this for all gen9 and gen10 platforms to enable
+ * this selectively if required.
+ */
+ switch (new_plane_state->hw.fb->modifier) {
+ case I915_FORMAT_MOD_X_TILED:
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Yf_TILED:
+ break;
+ default:
+ drm_dbg_kms(&i915->drm,
+ "Linear memory/CCS does not support async flips\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->color_plane[0].stride !=
+ new_plane_state->color_plane[0].stride) {
+ drm_dbg_kms(&i915->drm, "Stride cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.fb->modifier !=
+ new_plane_state->hw.fb->modifier) {
+ drm_dbg_kms(&i915->drm,
+ "Framebuffer modifiers cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.fb->format !=
+ new_plane_state->hw.fb->format) {
+ drm_dbg_kms(&i915->drm,
+ "Framebuffer format cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.rotation !=
+ new_plane_state->hw.rotation) {
+ drm_dbg_kms(&i915->drm, "Rotation cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (!drm_rect_equals(&old_plane_state->uapi.src, &new_plane_state->uapi.src) ||
+ !drm_rect_equals(&old_plane_state->uapi.dst, &new_plane_state->uapi.dst)) {
+ drm_dbg_kms(&i915->drm,
+ "Plane size/co-ordinates cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.alpha != new_plane_state->hw.alpha) {
+ drm_dbg_kms(&i915->drm, "Alpha value cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.pixel_blend_mode !=
+ new_plane_state->hw.pixel_blend_mode) {
+ drm_dbg_kms(&i915->drm,
+ "Pixel blend mode cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.color_encoding != new_plane_state->hw.color_encoding) {
+ drm_dbg_kms(&i915->drm,
+ "Color encoding cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.color_range != new_plane_state->hw.color_range) {
+ drm_dbg_kms(&i915->drm, "Color range cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int intel_bigjoiner_add_affected_crtcs(struct intel_atomic_state *state)
+{
+ const struct intel_crtc_state *crtc_state;
+ struct intel_crtc *crtc;
+ int i;
+
+ for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
+ struct intel_crtc_state *linked_crtc_state;
+
+ if (!crtc_state->bigjoiner)
+ continue;
+
+ linked_crtc_state = intel_atomic_get_crtc_state(&state->base,
+ crtc_state->bigjoiner_linked_crtc);
+ if (IS_ERR(linked_crtc_state))
+ return PTR_ERR(linked_crtc_state);
+ }
+
+ return 0;
+}
+
/**
* intel_atomic_check - validate state object
* @dev: drm device
@@ -14908,23 +15551,44 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
goto fail;
+ ret = intel_bigjoiner_add_affected_crtcs(state);
+ if (ret)
+ goto fail;
+
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
if (!needs_modeset(new_crtc_state)) {
/* Light copy */
- intel_crtc_copy_uapi_to_hw_state_nomodeset(new_crtc_state);
+ intel_crtc_copy_uapi_to_hw_state_nomodeset(state, new_crtc_state);
+
+ continue;
+ }
+
+ /* Kill old bigjoiner link, we may re-establish afterwards */
+ if (old_crtc_state->bigjoiner && !old_crtc_state->bigjoiner_slave) {
+ ret = kill_bigjoiner_slave(state, new_crtc_state);
+ if (ret)
+ goto fail;
+ }
+ if (!new_crtc_state->uapi.enable) {
+ if (!new_crtc_state->bigjoiner_slave) {
+ intel_crtc_copy_uapi_to_hw_state(state, new_crtc_state);
+ any_ms = true;
+ }
continue;
}
- ret = intel_crtc_prepare_cleared_state(new_crtc_state);
+ ret = intel_crtc_prepare_cleared_state(state, new_crtc_state);
if (ret)
goto fail;
- if (!new_crtc_state->hw.enable)
- continue;
+ ret = intel_modeset_pipe_config(state, new_crtc_state);
+ if (ret)
+ goto fail;
- ret = intel_modeset_pipe_config(new_crtc_state);
+ ret = intel_atomic_check_bigjoiner(state, crtc, old_crtc_state,
+ new_crtc_state);
if (ret)
goto fail;
}
@@ -15051,6 +15715,12 @@ static int intel_atomic_check(struct drm_device *dev,
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
+ if (new_crtc_state->uapi.async_flip) {
+ ret = intel_atomic_check_async(state);
+ if (ret)
+ goto fail;
+ }
+
if (!needs_modeset(new_crtc_state) &&
!new_crtc_state->update_pipe)
continue;
@@ -15220,6 +15890,9 @@ static void intel_enable_crtc(struct intel_atomic_state *state,
dev_priv->display.crtc_enable(state, crtc);
+ if (new_crtc_state->bigjoiner_slave)
+ return;
+
/* vblanks work again, re-enable pipe CRC. */
intel_crtc_enable_pipe_crc(crtc);
}
@@ -15274,7 +15947,6 @@ static void intel_update_crtc(struct intel_atomic_state *state,
intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
}
-
static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *new_crtc_state,
@@ -15282,9 +15954,22 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ drm_WARN_ON(&dev_priv->drm, old_crtc_state->bigjoiner_slave);
+
intel_crtc_disable_planes(state, crtc);
/*
+ * We still need special handling for disabling bigjoiner master
+ * and slaves since for slave we do not have encoder or plls
+ * so we dont need to disable those.
+ */
+ if (old_crtc_state->bigjoiner) {
+ intel_crtc_disable_planes(state,
+ old_crtc_state->bigjoiner_linked_crtc);
+ old_crtc_state->bigjoiner_linked_crtc->active = false;
+ }
+
+ /*
* We need to disable pipe CRC before disabling the pipe,
* or we race against vblank off.
*/
@@ -15312,7 +15997,7 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
/* Only disable port sync and MST slaves */
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
- if (!needs_modeset(new_crtc_state))
+ if (!needs_modeset(new_crtc_state) || old_crtc_state->bigjoiner)
continue;
if (!old_crtc_state->hw.active)
@@ -15337,10 +16022,18 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
if (!needs_modeset(new_crtc_state) ||
- (handled & BIT(crtc->pipe)))
+ (handled & BIT(crtc->pipe)) ||
+ old_crtc_state->bigjoiner_slave)
continue;
intel_pre_plane_update(state, crtc);
+ if (old_crtc_state->bigjoiner) {
+ struct intel_crtc *slave =
+ old_crtc_state->bigjoiner_linked_crtc;
+
+ intel_pre_plane_update(state, slave);
+ }
+
if (old_crtc_state->hw.active)
intel_old_crtc_state_disables(state, old_crtc_state,
new_crtc_state, crtc);
@@ -15438,7 +16131,8 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
continue;
if (intel_dp_mst_is_slave_trans(new_crtc_state) ||
- is_trans_port_sync_master(new_crtc_state))
+ is_trans_port_sync_master(new_crtc_state) ||
+ (new_crtc_state->bigjoiner && !new_crtc_state->bigjoiner_slave))
continue;
modeset_pipes &= ~BIT(pipe);
@@ -15448,7 +16142,7 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
/*
* Then we enable all remaining pipes that depend on other
- * pipes: MST slaves and port sync masters.
+ * pipes: MST slaves and port sync masters, big joiner master
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
enum pipe pipe = crtc->pipe;
@@ -15616,6 +16310,11 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_dbuf_pre_plane_update(state);
+ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+ if (new_crtc_state->uapi.async_flip)
+ skl_enable_flip_done(crtc);
+ }
+
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
dev_priv->display.commit_modeset_enables(state);
@@ -15637,6 +16336,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
drm_atomic_helper_wait_for_flip_done(dev, &state->base);
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+ if (new_crtc_state->uapi.async_flip)
+ skl_disable_flip_done(crtc);
+
if (new_crtc_state->hw.active &&
!needs_modeset(new_crtc_state) &&
!new_crtc_state->preload_luts &&
@@ -16232,9 +16934,11 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
/*
* 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->update_pipe || crtc_state->bigjoiner)
goto slow;
/*
@@ -16280,7 +16984,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
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);
+ 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);
@@ -16751,6 +17455,11 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
}
+ if (INTEL_GEN(dev_priv) >= 10)
+ drm_crtc_create_scaling_filter_property(&crtc->base,
+ BIT(DRM_SCALING_FILTER_DEFAULT) |
+ BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
+
intel_color_init(crtc);
intel_crtc_crc_init(crtc);
@@ -16892,22 +17601,22 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
if (!HAS_DISPLAY(dev_priv))
return;
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) {
intel_ddi_init(dev_priv, PORT_A);
intel_ddi_init(dev_priv, PORT_B);
- intel_ddi_init(dev_priv, PORT_D); /* DDI TC1 */
- intel_ddi_init(dev_priv, PORT_E); /* DDI TC2 */
+ intel_ddi_init(dev_priv, PORT_TC1);
+ intel_ddi_init(dev_priv, PORT_TC2);
} else if (INTEL_GEN(dev_priv) >= 12) {
intel_ddi_init(dev_priv, PORT_A);
intel_ddi_init(dev_priv, PORT_B);
- intel_ddi_init(dev_priv, PORT_D);
- intel_ddi_init(dev_priv, PORT_E);
- intel_ddi_init(dev_priv, PORT_F);
- intel_ddi_init(dev_priv, PORT_G);
- intel_ddi_init(dev_priv, PORT_H);
- intel_ddi_init(dev_priv, PORT_I);
+ intel_ddi_init(dev_priv, PORT_TC1);
+ intel_ddi_init(dev_priv, PORT_TC2);
+ intel_ddi_init(dev_priv, PORT_TC3);
+ intel_ddi_init(dev_priv, PORT_TC4);
+ intel_ddi_init(dev_priv, PORT_TC5);
+ intel_ddi_init(dev_priv, PORT_TC6);
icl_dsi_init(dev_priv);
- } else if (IS_ELKHARTLAKE(dev_priv)) {
+ } else if (IS_JSL_EHL(dev_priv)) {
intel_ddi_init(dev_priv, PORT_A);
intel_ddi_init(dev_priv, PORT_B);
intel_ddi_init(dev_priv, PORT_C);
@@ -17432,7 +18141,8 @@ intel_mode_valid(struct drm_device *dev,
enum drm_mode_status
intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
- const struct drm_display_mode *mode)
+ const struct drm_display_mode *mode,
+ bool bigjoiner)
{
int plane_width_max, plane_height_max;
@@ -17449,7 +18159,7 @@ intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
* too big for that.
*/
if (INTEL_GEN(dev_priv) >= 11) {
- plane_width_max = 5120;
+ plane_width_max = 5120 << bigjoiner;
plane_height_max = 4320;
} else {
plane_width_max = 5120;
@@ -17742,6 +18452,8 @@ retry:
}
if (crtc_state->hw.active) {
+ struct intel_encoder *encoder;
+
/*
* We've not yet detected sink capabilities
* (audio,infoframes,etc.) and thus we don't want to
@@ -17763,22 +18475,15 @@ retry:
*/
crtc_state->uapi.color_mgmt_changed = true;
- /*
- * FIXME hack to force full modeset when DSC is being
- * used.
- *
- * As long as we do not have full state readout and
- * config comparison of crtc_state->dsc, we have no way
- * to ensure reliable fastset. Remove once we have
- * readout for DSC.
- */
- if (crtc_state->dsc.compression_enable) {
- ret = drm_atomic_add_affected_connectors(state,
- &crtc->base);
- if (ret)
- goto out;
- crtc_state->uapi.mode_changed = true;
- drm_dbg_kms(dev, "Force full modeset for DSC\n");
+ for_each_intel_encoder_mask(dev, encoder,
+ crtc_state->uapi.encoder_mask) {
+ if (encoder->initial_fastset_check &&
+ !encoder->initial_fastset_check(encoder, crtc_state)) {
+ ret = drm_atomic_add_affected_connectors(state,
+ &crtc->base);
+ if (ret)
+ goto out;
+ }
}
}
}
@@ -17817,6 +18522,9 @@ static void intel_mode_config_init(struct drm_i915_private *i915)
mode_config->funcs = &intel_mode_funcs;
+ if (INTEL_GEN(i915) >= 9)
+ mode_config->async_page_flip = true;
+
/*
* Maximum framebuffer dimensions, chosen to match
* the maximum render engine surface size on gen4+.
@@ -17992,7 +18700,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
for_each_intel_crtc(dev, crtc) {
struct intel_initial_plane_config plane_config = {};
- if (!crtc->active)
+ if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
continue;
/*
@@ -18050,11 +18758,10 @@ int intel_modeset_init(struct drm_i915_private *i915)
/* Only enable hotplug handling once the fbdev is fully set up. */
intel_hpd_init(i915);
+ intel_hpd_poll_disable(i915);
intel_init_ipc(i915);
- intel_psr_set_force_mode_changed(i915->psr.dp);
-
return 0;
}
@@ -18304,7 +19011,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
/* Adjust the state of the output pipe according to whether we
* have active connectors/encoders. */
- if (crtc_state->hw.active && !intel_crtc_has_encoders(crtc))
+ if (crtc_state->hw.active && !intel_crtc_has_encoders(crtc) &&
+ !crtc_state->bigjoiner_slave)
intel_crtc_disable_noatomic(crtc, ctx);
if (crtc_state->hw.active || HAS_GMCH(dev_priv)) {
@@ -18483,8 +19191,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
intel_crtc_free_hw_state(crtc_state);
intel_crtc_state_reset(crtc_state, crtc);
- crtc_state->hw.active = crtc_state->hw.enable =
- dev_priv->display.get_pipe_config(crtc, crtc_state);
+ intel_crtc_get_pipe_config(crtc_state);
+
+ crtc_state->hw.enable = crtc_state->hw.active;
crtc->base.enabled = crtc_state->hw.enable;
crtc->active = crtc_state->hw.active;
@@ -18515,7 +19224,19 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
crtc_state = to_intel_crtc_state(crtc->base.state);
encoder->base.crtc = &crtc->base;
- encoder->get_config(encoder, crtc_state);
+ intel_encoder_get_config(encoder, crtc_state);
+ if (encoder->sync_state)
+ encoder->sync_state(encoder, crtc_state);
+
+ /* read out to slave crtc as well for bigjoiner */
+ if (crtc_state->bigjoiner) {
+ /* encoder should read be linked to bigjoiner master */
+ WARN_ON(crtc_state->bigjoiner_slave);
+
+ crtc = crtc_state->bigjoiner_linked_crtc;
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+ intel_encoder_get_config(encoder, crtc_state);
+ }
} else {
encoder->base.crtc = NULL;
}
@@ -18571,16 +19292,10 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
struct intel_plane *plane;
int min_cdclk = 0;
- if (crtc_state->hw.active) {
- struct drm_display_mode *mode = &crtc_state->hw.mode;
-
- intel_mode_from_pipe_config(&crtc_state->hw.adjusted_mode,
- crtc_state);
-
- *mode = crtc_state->hw.adjusted_mode;
- mode->hdisplay = crtc_state->pipe_src_w;
- mode->vdisplay = crtc_state->pipe_src_h;
+ if (crtc_state->bigjoiner_slave)
+ continue;
+ if (crtc_state->hw.active) {
/*
* The initial mode needs to be set in order to keep
* the atomic core happy. It wants a valid mode if the
@@ -18592,8 +19307,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
*/
crtc_state->inherited = true;
- intel_crtc_compute_pixel_rate(crtc_state);
-
intel_crtc_update_active_timings(crtc_state);
intel_crtc_copy_hw_to_uapi_state(crtc_state);
@@ -18642,6 +19355,39 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
intel_bw_crtc_update(bw_state, crtc_state);
intel_pipe_config_sanity_check(dev_priv, crtc_state);
+
+ /* discard our incomplete slave state, copy it from master */
+ if (crtc_state->bigjoiner && crtc_state->hw.active) {
+ struct intel_crtc *slave = crtc_state->bigjoiner_linked_crtc;
+ struct intel_crtc_state *slave_crtc_state =
+ to_intel_crtc_state(slave->base.state);
+
+ copy_bigjoiner_crtc_state(slave_crtc_state, crtc_state);
+ slave->base.mode = crtc->base.mode;
+
+ cdclk_state->min_cdclk[slave->pipe] = min_cdclk;
+ cdclk_state->min_voltage_level[slave->pipe] =
+ crtc_state->min_voltage_level;
+
+ for_each_intel_plane_on_crtc(&dev_priv->drm, slave, plane) {
+ const struct intel_plane_state *plane_state =
+ to_intel_plane_state(plane->base.state);
+
+ /*
+ * FIXME don't have the fb yet, so can't
+ * use intel_plane_data_rate() :(
+ */
+ if (plane_state->uapi.visible)
+ crtc_state->data_rate[plane->id] =
+ 4 * crtc_state->pixel_rate;
+ else
+ crtc_state->data_rate[plane->id] = 0;
+ }
+
+ intel_bw_crtc_update(bw_state, slave_crtc_state);
+ drm_calc_timestamping_constants(&slave->base,
+ &slave_crtc_state->hw.adjusted_mode);
+ }
}
}
@@ -18686,6 +19432,15 @@ static void intel_early_display_was(struct drm_i915_private *dev_priv)
intel_de_write(dev_priv, CHICKEN_PAR1_1,
intel_de_read(dev_priv, CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
}
+
+ if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv)) {
+ /* Display WA #1142:kbl,cfl,cml */
+ intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
+ KBL_ARB_FILL_SPARE_22, KBL_ARB_FILL_SPARE_22);
+ intel_de_rmw(dev_priv, CHICKEN_MISC_2,
+ KBL_ARB_FILL_SPARE_13 | KBL_ARB_FILL_SPARE_14,
+ KBL_ARB_FILL_SPARE_14);
+ }
}
static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index d10b7c8cde3f..5e0d42d82c11 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -28,6 +28,7 @@
#include <drm/drm_util.h>
enum link_m_n_set;
+enum drm_scaling_filter;
struct dpll;
struct drm_connector;
struct drm_device;
@@ -207,6 +208,14 @@ enum port {
PORT_H,
PORT_I,
+ /* tgl+ */
+ PORT_TC1 = PORT_D,
+ PORT_TC2,
+ PORT_TC3,
+ PORT_TC4,
+ PORT_TC5,
+ PORT_TC6,
+
I915_MAX_PORTS
};
@@ -243,14 +252,14 @@ static inline const char *port_identifier(enum port port)
}
enum tc_port {
- PORT_TC_NONE = -1,
+ TC_PORT_NONE = -1,
- PORT_TC1 = 0,
- PORT_TC2,
- PORT_TC3,
- PORT_TC4,
- PORT_TC5,
- PORT_TC6,
+ TC_PORT_1 = 0,
+ TC_PORT_2,
+ TC_PORT_3,
+ TC_PORT_4,
+ TC_PORT_5,
+ TC_PORT_6,
I915_MAX_TC_PORTS
};
@@ -282,6 +291,14 @@ enum aux_ch {
AUX_CH_G,
AUX_CH_H,
AUX_CH_I,
+
+ /* tgl+ */
+ AUX_CH_USBC1 = AUX_CH_D,
+ AUX_CH_USBC2,
+ AUX_CH_USBC3,
+ AUX_CH_USBC4,
+ AUX_CH_USBC5,
+ AUX_CH_USBC6,
};
#define aux_ch_name(a) ((a) + 'A')
@@ -496,7 +513,8 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
bool intel_plane_can_remap(const struct intel_plane_state *plane_state);
enum drm_mode_status
intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
- const struct drm_display_mode *mode);
+ const struct drm_display_mode *mode,
+ bool bigjoiner);
enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port);
bool is_trans_port_sync_mode(const struct intel_crtc_state *state);
@@ -573,8 +591,8 @@ void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe);
int lpt_get_iclkip(struct drm_i915_private *dev_priv);
bool intel_fuzzy_clock_check(int clock1, int clock2);
-void intel_prepare_reset(struct drm_i915_private *dev_priv);
-void intel_finish_reset(struct drm_i915_private *dev_priv);
+void intel_display_prepare_reset(struct drm_i915_private *dev_priv);
+void intel_display_finish_reset(struct drm_i915_private *dev_priv);
void intel_dp_get_m_n(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state,
@@ -592,13 +610,14 @@ enum intel_display_power_domain
intel_aux_power_domain(struct intel_digital_port *dig_port);
enum intel_display_power_domain
intel_legacy_aux_to_power_domain(enum aux_ch aux_ch);
-void intel_mode_from_pipe_config(struct drm_display_mode *mode,
- struct intel_crtc_state *pipe_config);
void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state);
u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_center);
void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state);
+u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set);
+void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
+ int id, int set, enum drm_scaling_filter filter);
void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 0bf31f9a8af5..ca41e8c00ad7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -518,8 +518,13 @@ static int i915_dmc_info(struct seq_file *m, void *unused)
CSR_VERSION_MINOR(csr->version));
if (INTEL_GEN(dev_priv) >= 12) {
- dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
- dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
+ if (IS_DGFX(dev_priv)) {
+ dc5_reg = DG1_DMC_DEBUG_DC5_COUNT;
+ } else {
+ dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
+ dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
+ }
+
/*
* NOTE: DMC_DEBUG3 is a general purpose reg.
* According to B.Specs:49196 DMC f/w reuses DC5/6 counter
@@ -750,6 +755,17 @@ static void plane_rotation(char *buf, size_t bufsize, unsigned int rotation)
rotation);
}
+static const char *plane_visibility(const struct intel_plane_state *plane_state)
+{
+ if (plane_state->uapi.visible)
+ return "visible";
+
+ if (plane_state->planar_slave)
+ return "planar-slave";
+
+ return "hidden";
+}
+
static void intel_plane_uapi_info(struct seq_file *m, struct intel_plane *plane)
{
const struct intel_plane_state *plane_state =
@@ -768,12 +784,19 @@ static void intel_plane_uapi_info(struct seq_file *m, struct intel_plane *plane)
plane_rotation(rot_str, sizeof(rot_str),
plane_state->uapi.rotation);
- seq_printf(m, "\t\tuapi: fb=%d,%s,%dx%d, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
+ seq_printf(m, "\t\tuapi: [FB:%d] %s,0x%llx,%dx%d, visible=%s, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
fb ? fb->base.id : 0, fb ? format_name.str : "n/a",
+ fb ? fb->modifier : 0,
fb ? fb->width : 0, fb ? fb->height : 0,
+ plane_visibility(plane_state),
DRM_RECT_FP_ARG(&src),
DRM_RECT_ARG(&dst),
rot_str);
+
+ if (plane_state->planar_linked_plane)
+ seq_printf(m, "\t\tplanar: Linked to [PLANE:%d:%s] as a %s\n",
+ plane_state->planar_linked_plane->base.base.id, plane_state->planar_linked_plane->base.name,
+ plane_state->planar_slave ? "slave" : "master");
}
static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane)
@@ -792,9 +815,9 @@ static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane)
plane_rotation(rot_str, sizeof(rot_str),
plane_state->hw.rotation);
- seq_printf(m, "\t\thw: fb=%d,%s,%dx%d, visible=%s, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
+ seq_printf(m, "\t\thw: [FB:%d] %s,0x%llx,%dx%d, visible=%s, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
fb->base.id, format_name.str,
- fb->width, fb->height,
+ fb->modifier, fb->width, fb->height,
yesno(plane_state->uapi.visible),
DRM_RECT_FP_ARG(&plane_state->uapi.src),
DRM_RECT_ARG(&plane_state->uapi.dst),
@@ -869,6 +892,12 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc)
intel_scaler_info(m, crtc);
}
+ if (crtc_state->bigjoiner)
+ seq_printf(m, "\tLinked to [CRTC:%d:%s] as a %s\n",
+ crtc_state->bigjoiner_linked_crtc->base.base.id,
+ crtc_state->bigjoiner_linked_crtc->base.name,
+ crtc_state->bigjoiner_slave ? "slave" : "master");
+
for_each_intel_encoder_mask(&dev_priv->drm, encoder,
crtc_state->uapi.encoder_mask)
intel_encoder_info(m, crtc, encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 7277e58b01f1..fe2d90bba536 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -1424,6 +1424,7 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
return;
intel_hpd_init(dev_priv);
+ intel_hpd_poll_disable(dev_priv);
/* Re-enable the ADPA, if we have one */
for_each_intel_encoder(&dev_priv->drm, encoder) {
@@ -1449,7 +1450,7 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
/* Prevent us from re-enabling polling on accident in late suspend */
if (!dev_priv->drm.dev->power.is_suspended)
- intel_hpd_poll_init(dev_priv);
+ intel_hpd_poll_enable(dev_priv);
}
static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
@@ -3650,7 +3651,7 @@ static const struct i915_power_well_desc cnl_power_wells[] = {
.name = "DDI F IO power well",
.domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = DISP_PW_ID_NONE,
+ .id = CNL_DISP_PW_DDI_F_IO,
{
.hsw.regs = &hsw_power_well_regs,
.hsw.idx = CNL_PW_CTL_IDX_DDI_F,
@@ -3660,7 +3661,7 @@ static const struct i915_power_well_desc cnl_power_wells[] = {
.name = "AUX F",
.domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = DISP_PW_ID_NONE,
+ .id = CNL_DISP_PW_DDI_F_AUX,
{
.hsw.regs = &hsw_power_well_regs,
.hsw.idx = CNL_PW_CTL_IDX_AUX_F,
@@ -4150,7 +4151,7 @@ static const struct i915_power_well_desc tgl_power_wells[] = {
.name = "TC cold off",
.domains = TGL_TC_COLD_OFF_POWER_DOMAINS,
.ops = &tgl_tc_cold_off_ops,
- .id = DISP_PW_ID_NONE,
+ .id = TGL_DISP_PW_TC_COLD_OFF,
},
{
.name = "AUX A",
@@ -4491,27 +4492,24 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
int requested_dc;
int max_dc;
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (IS_DG1(dev_priv))
+ max_dc = 3;
+ else if (INTEL_GEN(dev_priv) >= 12)
max_dc = 4;
- /*
- * DC9 has a separate HW flow from the rest of the DC states,
- * not depending on the DMC firmware. It's needed by system
- * suspend/resume, so allow it unconditionally.
- */
- mask = DC_STATE_EN_DC9;
- } else if (IS_GEN(dev_priv, 11)) {
- max_dc = 2;
- mask = DC_STATE_EN_DC9;
- } else if (IS_GEN(dev_priv, 10) || IS_GEN9_BC(dev_priv)) {
+ else if (INTEL_GEN(dev_priv) >= 10 || IS_GEN9_BC(dev_priv))
max_dc = 2;
- mask = 0;
- } else if (IS_GEN9_LP(dev_priv)) {
+ else if (IS_GEN9_LP(dev_priv))
max_dc = 1;
- mask = DC_STATE_EN_DC9;
- } else {
+ else
max_dc = 0;
- mask = 0;
- }
+
+ /*
+ * DC9 has a separate HW flow from the rest of the DC states,
+ * not depending on the DMC firmware. It's needed by system
+ * suspend/resume, so allow it unconditionally.
+ */
+ mask = IS_GEN9_LP(dev_priv) || INTEL_GEN(dev_priv) >= 11 ?
+ DC_STATE_EN_DC9 : 0;
if (!dev_priv->params.disable_power_well)
max_dc = 0;
@@ -4554,13 +4552,18 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
static int
__set_power_wells(struct i915_power_domains *power_domains,
const struct i915_power_well_desc *power_well_descs,
- int power_well_count)
+ int power_well_descs_sz, u64 skip_mask)
{
struct drm_i915_private *i915 = container_of(power_domains,
struct drm_i915_private,
power_domains);
u64 power_well_ids = 0;
- int i;
+ int power_well_count = 0;
+ int i, plt_idx = 0;
+
+ for (i = 0; i < power_well_descs_sz; i++)
+ if (!(BIT_ULL(power_well_descs[i].id) & skip_mask))
+ power_well_count++;
power_domains->power_well_count = power_well_count;
power_domains->power_wells =
@@ -4570,10 +4573,14 @@ __set_power_wells(struct i915_power_domains *power_domains,
if (!power_domains->power_wells)
return -ENOMEM;
- for (i = 0; i < power_well_count; i++) {
+ for (i = 0; i < power_well_descs_sz; i++) {
enum i915_power_well_id id = power_well_descs[i].id;
- power_domains->power_wells[i].desc = &power_well_descs[i];
+ if (BIT_ULL(id) & skip_mask)
+ continue;
+
+ power_domains->power_wells[plt_idx++].desc =
+ &power_well_descs[i];
if (id == DISP_PW_ID_NONE)
continue;
@@ -4586,9 +4593,12 @@ __set_power_wells(struct i915_power_domains *power_domains,
return 0;
}
-#define set_power_wells(power_domains, __power_well_descs) \
+#define set_power_wells_mask(power_domains, __power_well_descs, skip_mask) \
__set_power_wells(power_domains, __power_well_descs, \
- ARRAY_SIZE(__power_well_descs))
+ ARRAY_SIZE(__power_well_descs), skip_mask)
+
+#define set_power_wells(power_domains, __power_well_descs) \
+ set_power_wells_mask(power_domains, __power_well_descs, 0)
/**
* intel_power_domains_init - initializes the power domain structures
@@ -4622,23 +4632,21 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
* The enabling order will be from lower to higher indexed wells,
* the disabling order is reversed.
*/
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ err = set_power_wells_mask(power_domains, tgl_power_wells,
+ BIT_ULL(TGL_DISP_PW_TC_COLD_OFF));
+ } else if (IS_ROCKETLAKE(dev_priv)) {
err = set_power_wells(power_domains, rkl_power_wells);
} else if (IS_GEN(dev_priv, 12)) {
err = set_power_wells(power_domains, tgl_power_wells);
} else if (IS_GEN(dev_priv, 11)) {
err = set_power_wells(power_domains, icl_power_wells);
- } else if (IS_CANNONLAKE(dev_priv)) {
+ } else if (IS_CNL_WITH_PORT_F(dev_priv)) {
err = set_power_wells(power_domains, cnl_power_wells);
-
- /*
- * DDI and Aux IO are getting enabled for all ports
- * regardless the presence or use. So, in order to avoid
- * timeouts, lets remove them from the list
- * for the SKUs without port F.
- */
- if (!IS_CNL_WITH_PORT_F(dev_priv))
- power_domains->power_well_count -= 2;
+ } else if (IS_CANNONLAKE(dev_priv)) {
+ err = set_power_wells_mask(power_domains, cnl_power_wells,
+ BIT_ULL(CNL_DISP_PW_DDI_F_IO) |
+ BIT_ULL(CNL_DISP_PW_DDI_F_AUX));
} else if (IS_GEMINILAKE(dev_priv)) {
err = set_power_wells(power_domains, glk_power_wells);
} else if (IS_BROXTON(dev_priv)) {
@@ -4758,6 +4766,17 @@ static void gen9_dbuf_disable(struct drm_i915_private *dev_priv)
gen9_dbuf_slices_update(dev_priv, 0);
}
+static void gen12_dbuf_slices_config(struct drm_i915_private *dev_priv)
+{
+ const int num_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
+ enum dbuf_slice slice;
+
+ for (slice = DBUF_S1; slice < (DBUF_S1 + num_slices); slice++)
+ intel_de_rmw(dev_priv, DBUF_CTL_S(slice),
+ DBUF_TRACKER_STATE_SERVICE_MASK,
+ DBUF_TRACKER_STATE_SERVICE(8));
+}
+
static void icl_mbus_init(struct drm_i915_private *dev_priv)
{
unsigned long abox_regs = INTEL_INFO(dev_priv)->abox_mask;
@@ -5263,8 +5282,9 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv)
unsigned long abox_mask = INTEL_INFO(dev_priv)->abox_mask;
int config, i;
- if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0))
- /* Wa_1409767108: tgl */
+ if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0) ||
+ IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0))
+ /* Wa_1409767108:tgl,dg1 */
table = wa_1409767108_buddy_page_masks;
else
table = tgl_buddy_page_masks;
@@ -5326,6 +5346,9 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
/* 4. Enable CDCLK. */
intel_cdclk_init_hw(dev_priv);
+ if (INTEL_GEN(dev_priv) >= 12)
+ gen12_dbuf_slices_config(dev_priv);
+
/* 5. Enable DBUF. */
gen9_dbuf_enable(dev_priv);
@@ -5829,10 +5852,15 @@ static void intel_power_domains_verify_state(struct drm_i915_private *i915)
void intel_display_power_suspend_late(struct drm_i915_private *i915)
{
- if (INTEL_GEN(i915) >= 11 || IS_GEN9_LP(i915))
+ if (INTEL_GEN(i915) >= 11 || IS_GEN9_LP(i915)) {
bxt_enable_dc9(i915);
- else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
+ /* Tweaked Wa_14010685332:icp,jsp,mcc */
+ if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC)
+ intel_de_rmw(i915, SOUTH_CHICKEN1,
+ SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS);
+ } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
hsw_enable_pc8(i915);
+ }
}
void intel_display_power_resume_early(struct drm_i915_private *i915)
@@ -5840,6 +5868,10 @@ void intel_display_power_resume_early(struct drm_i915_private *i915)
if (INTEL_GEN(i915) >= 11 || IS_GEN9_LP(i915)) {
gen9_sanitize_dc_state(i915);
bxt_disable_dc9(i915);
+ /* Tweaked Wa_14010685332:icp,jsp,mcc */
+ if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC)
+ intel_de_rmw(i915, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, 0);
+
} else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
hsw_disable_pc8(i915);
}
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 54c20c76057e..4aa0a09cf14f 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -101,8 +101,11 @@ enum i915_power_well_id {
SKL_DISP_PW_MISC_IO,
SKL_DISP_PW_1,
SKL_DISP_PW_2,
+ CNL_DISP_PW_DDI_F_IO,
+ CNL_DISP_PW_DDI_F_AUX,
ICL_DISP_PW_3,
SKL_DISP_DC_OFF,
+ TGL_DISP_PW_TC_COLD_OFF,
};
#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 3d4bf9b6a0a2..ce82d654d0f2 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -187,6 +187,21 @@ struct intel_encoder {
* be set correctly before calling this function. */
void (*get_config)(struct intel_encoder *,
struct intel_crtc_state *pipe_config);
+
+ /*
+ * Optional hook called during init/resume to sync any state
+ * stored in the encoder (eg. DP link parameters) wrt. the HW state.
+ */
+ void (*sync_state)(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+
+ /*
+ * Optional hook, returning true if this encoder allows a fastset
+ * during the initial commit, false otherwise.
+ */
+ bool (*initial_fastset_check)(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state);
+
/*
* Acquires the power domains needed for an active encoder during
* hardware state readout.
@@ -199,6 +214,11 @@ struct intel_encoder {
* device interrupts are disabled.
*/
void (*suspend)(struct intel_encoder *);
+ /*
+ * Called during system reboot/shutdown after all the
+ * encoders have been disabled and suspended.
+ */
+ void (*shutdown)(struct intel_encoder *encoder);
enum hpd_pin hpd_pin;
enum intel_display_power_domain power_domain;
/* for communication with audio component; protected by av_mutex */
@@ -515,6 +535,7 @@ struct intel_plane_state {
unsigned int rotation;
enum drm_color_encoding color_encoding;
enum drm_color_range color_range;
+ enum drm_scaling_filter scaling_filter;
} hw;
struct i915_ggtt_view view;
@@ -665,6 +686,7 @@ struct skl_wm_level {
u8 plane_res_l;
bool plane_en;
bool ignore_lines;
+ bool can_sagv;
};
struct skl_plane_wm {
@@ -716,24 +738,35 @@ struct g4x_wm_state {
struct intel_crtc_wm_state {
union {
+ /*
+ * raw:
+ * The "raw" watermark values produced by the formula
+ * given the plane's current state. They do not consider
+ * how much FIFO is actually allocated for each plane.
+ *
+ * optimal:
+ * The "optimal" watermark values given the current
+ * state of the planes and the amount of FIFO
+ * allocated to each, ignoring any previous state
+ * of the planes.
+ *
+ * intermediate:
+ * The "intermediate" watermark values when transitioning
+ * between the old and new "optimal" values. Used when
+ * the watermark registers are single buffered and hence
+ * their state changes asynchronously with regards to the
+ * actual plane registers. These are essentially the
+ * worst case combination of the old and new "optimal"
+ * watermarks, which are therefore safe to use when the
+ * plane is in either its old or new state.
+ */
struct {
- /*
- * Intermediate watermarks; these can be
- * programmed immediately since they satisfy
- * both the current configuration we're
- * switching away from and the new
- * configuration we're switching to.
- */
struct intel_pipe_wm intermediate;
-
- /*
- * Optimal watermarks, programmed post-vblank
- * when this state is committed.
- */
struct intel_pipe_wm optimal;
} ilk;
struct {
+ struct skl_pipe_wm raw;
/* gen9+ only needs 1-step wm programming */
struct skl_pipe_wm optimal;
struct skl_ddb_entry ddb;
@@ -742,22 +775,15 @@ struct intel_crtc_wm_state {
} skl;
struct {
- /* "raw" watermarks (not inverted) */
- struct g4x_pipe_wm raw[NUM_VLV_WM_LEVELS];
- /* intermediate watermarks (inverted) */
- struct vlv_wm_state intermediate;
- /* optimal watermarks (inverted) */
- struct vlv_wm_state optimal;
- /* display FIFO split */
+ struct g4x_pipe_wm raw[NUM_VLV_WM_LEVELS]; /* not inverted */
+ struct vlv_wm_state intermediate; /* inverted */
+ struct vlv_wm_state optimal; /* inverted */
struct vlv_fifo_state fifo_state;
} vlv;
struct {
- /* "raw" watermarks */
struct g4x_pipe_wm raw[NUM_G4X_WM_LEVELS];
- /* intermediate watermarks */
struct g4x_wm_state intermediate;
- /* optimal watermarks */
struct g4x_wm_state optimal;
} g4x;
};
@@ -796,15 +822,23 @@ struct intel_crtc_state {
* The following members are used to verify the hardware state:
* - enable
* - active
- * - mode / adjusted_mode
+ * - mode / pipe_mode / adjusted_mode
* - color property blobs.
*
* During initial hw readout, they need to be copied to uapi.
+ *
+ * Bigjoiner will allow a transcoder mode that spans 2 pipes;
+ * Use the pipe_mode for calculations like watermarks, pipe
+ * scaler, and bandwidth.
+ *
+ * Use adjusted_mode for things that need to know the full
+ * mode on the transcoder, which spans all pipes.
*/
struct {
bool active, enable;
struct drm_property_blob *degamma_lut, *gamma_lut, *ctm;
- struct drm_display_mode mode, adjusted_mode;
+ struct drm_display_mode mode, pipe_mode, adjusted_mode;
+ enum drm_scaling_filter scaling_filter;
} hw;
/**
@@ -816,6 +850,7 @@ struct intel_crtc_state {
* accordingly.
*/
#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
+#define PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE (1<<1) /* bigjoiner slave, partial readout */
unsigned long quirks;
unsigned fb_bits; /* framebuffers to flip */
@@ -997,6 +1032,10 @@ struct intel_crtc_state {
u32 data_rate[I915_MAX_PLANES];
+ /* FIXME unify with data_rate[] */
+ u64 plane_data_rate[I915_MAX_PLANES];
+ u64 uv_plane_data_rate[I915_MAX_PLANES];
+
/* Gamma mode programmed on the pipe */
u32 gamma_mode;
@@ -1035,15 +1074,21 @@ struct intel_crtc_state {
/* Output format RGB/YCBCR etc */
enum intel_output_format output_format;
- /* Output down scaling is done in LSPCON device */
- bool lspcon_downsampling;
-
/* enable pipe gamma? */
bool gamma_enable;
/* enable pipe csc? */
bool csc_enable;
+ /* enable pipe big joiner? */
+ bool bigjoiner;
+
+ /* big joiner slave crtc? */
+ bool bigjoiner_slave;
+
+ /* linked crtc for bigjoiner, either slave or master */
+ struct intel_crtc *bigjoiner_linked_crtc;
+
/* Display Stream compression state */
struct {
bool compression_enable;
@@ -1170,6 +1215,15 @@ struct intel_plane {
* the intel_plane_state structure and accessed via plane_state.
*/
+ int (*min_width)(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation);
+ int (*max_width)(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation);
+ int (*max_height)(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation);
unsigned int (*max_stride)(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation);
@@ -1183,6 +1237,9 @@ struct intel_plane {
struct intel_plane_state *plane_state);
int (*min_cdclk)(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
+ void (*async_flip)(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state);
};
struct intel_watermark_params {
@@ -1270,7 +1327,6 @@ struct intel_dp {
int link_rate;
u8 lane_count;
u8 sink_count;
- bool link_mst;
bool link_trained;
bool has_hdmi_sink;
bool has_audio;
@@ -1280,6 +1336,8 @@ struct intel_dp {
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
+ u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
+ u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
u8 fec_capable;
/* source rates */
int num_source_rates;
@@ -1312,8 +1370,6 @@ struct intel_dp {
unsigned long last_backlight_off;
ktime_t panel_power_off_time;
- struct notifier_block edp_notifier;
-
/*
* Pipe whose power sequencer is currently locked into
* this port. Only relevant on VLV/CHV.
@@ -1336,14 +1392,6 @@ struct intel_dp {
bool is_mst;
int active_mst_links;
- /*
- * DP_TP_* registers may be either on port or transcoder register space.
- */
- struct {
- i915_reg_t dp_tp_ctl;
- i915_reg_t dp_tp_status;
- } regs;
-
/* connector directly attached - won't be use for modeset in mst world */
struct intel_connector *attached_connector;
@@ -1363,13 +1411,19 @@ struct intel_dp {
i915_reg_t (*aux_ch_data_reg)(struct intel_dp *dp, int index);
/* This is called before a link training is starterd */
- void (*prepare_link_retrain)(struct intel_dp *intel_dp);
- void (*set_link_train)(struct intel_dp *intel_dp, u8 dp_train_pat);
- void (*set_idle_link_train)(struct intel_dp *intel_dp);
- void (*set_signal_levels)(struct intel_dp *intel_dp);
+ void (*prepare_link_retrain)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+ void (*set_link_train)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ u8 dp_train_pat);
+ void (*set_idle_link_train)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+ void (*set_signal_levels)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
u8 (*preemph_max)(struct intel_dp *intel_dp);
- u8 (*voltage_max)(struct intel_dp *intel_dp);
+ u8 (*voltage_max)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
/* Displayport compliance testing */
struct intel_dp_compliance compliance;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 9bc59fd2f95f..2165398d2c7c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -28,7 +28,6 @@
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -161,6 +160,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
162000, 270000, 540000, 810000
};
int i, max_rate;
+ int max_lttpr_rate;
if (drm_dp_has_quirk(&intel_dp->desc, 0,
DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
@@ -174,6 +174,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
}
max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+ max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
+ if (max_lttpr_rate)
+ max_rate = min(max_rate, max_lttpr_rate);
for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
if (dp_rates[i] > max_rate)
@@ -219,6 +222,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
int source_max = dig_port->max_lanes;
int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
int fia_max = intel_tc_port_fia_max_lane_count(dig_port);
+ int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps);
+
+ if (lttpr_max)
+ sink_max = min(sink_max, lttpr_max);
return min3(source_max, sink_max, fia_max);
}
@@ -247,6 +254,17 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
return max_link_clock * max_lanes;
}
+bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct intel_encoder *encoder = &intel_dig_port->base;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ return INTEL_GEN(dev_priv) >= 12 ||
+ (INTEL_GEN(dev_priv) == 11 &&
+ encoder->port != PORT_A);
+}
+
static int cnl_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@@ -277,13 +295,20 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_phy_is_combo(dev_priv, phy) &&
- !IS_ELKHARTLAKE(dev_priv) &&
!intel_dp_is_edp(intel_dp))
return 540000;
return 810000;
}
+static int ehl_max_source_rate(struct intel_dp *intel_dp)
+{
+ if (intel_dp_is_edp(intel_dp))
+ return 540000;
+
+ return 810000;
+}
+
static void
intel_dp_set_source_rates(struct intel_dp *intel_dp)
{
@@ -318,6 +343,8 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
size = ARRAY_SIZE(cnl_rates);
if (IS_GEN(dev_priv, 10))
max_rate = cnl_max_source_rate(intel_dp);
+ else if (IS_JSL_EHL(dev_priv))
+ max_rate = ehl_max_source_rate(intel_dp);
else
max_rate = icl_max_source_rate(intel_dp);
} else if (IS_GEN9_LP(dev_priv)) {
@@ -503,7 +530,8 @@ small_joiner_ram_size_bits(struct drm_i915_private *i915)
static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
u32 link_clock, u32 lane_count,
- u32 mode_clock, u32 mode_hdisplay)
+ u32 mode_clock, u32 mode_hdisplay,
+ bool bigjoiner)
{
u32 bits_per_pixel, max_bpp_small_joiner_ram;
int i;
@@ -521,6 +549,10 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
/* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */
max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) /
mode_hdisplay;
+
+ if (bigjoiner)
+ max_bpp_small_joiner_ram *= 2;
+
drm_dbg_kms(&i915->drm, "Max small joiner bpp: %u\n",
max_bpp_small_joiner_ram);
@@ -530,6 +562,15 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
*/
bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram);
+ if (bigjoiner) {
+ u32 max_bpp_bigjoiner =
+ i915->max_cdclk_freq * 48 /
+ intel_dp_mode_to_fec_clock(mode_clock);
+
+ DRM_DEBUG_KMS("Max big joiner bpp: %u\n", max_bpp_bigjoiner);
+ bits_per_pixel = min(bits_per_pixel, max_bpp_bigjoiner);
+ }
+
/* Error out if the max bpp is less than smallest allowed valid bpp */
if (bits_per_pixel < valid_dsc_bpp[0]) {
drm_dbg_kms(&i915->drm, "Unsupported BPP %u, min %u\n",
@@ -552,7 +593,8 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
}
static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
- int mode_clock, int mode_hdisplay)
+ int mode_clock, int mode_hdisplay,
+ bool bigjoiner)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
u8 min_slice_count, i;
@@ -579,12 +621,18 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
/* Find the closest match to the valid slice count values */
for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) {
- if (valid_dsc_slicecount[i] >
- drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
- false))
+ u8 test_slice_count = valid_dsc_slicecount[i] << bigjoiner;
+
+ if (test_slice_count >
+ drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, false))
break;
- if (min_slice_count <= valid_dsc_slicecount[i])
- return valid_dsc_slicecount[i];
+
+ /* big joiner needs small joiner to be enabled */
+ if (bigjoiner && test_slice_count < 4)
+ continue;
+
+ if (min_slice_count <= test_slice_count)
+ return test_slice_count;
}
drm_dbg_kms(&i915->drm, "Unsupported Slice Count %d\n",
@@ -592,6 +640,54 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
return 0;
}
+static enum intel_output_format
+intel_dp_output_format(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector));
+ const struct drm_display_info *info = &connector->display_info;
+
+ if (!connector->ycbcr_420_allowed ||
+ !drm_mode_is_420_only(info, mode))
+ return INTEL_OUTPUT_FORMAT_RGB;
+
+ if (intel_dp->dfp.ycbcr_444_to_420)
+ return INTEL_OUTPUT_FORMAT_YCBCR444;
+ else
+ return INTEL_OUTPUT_FORMAT_YCBCR420;
+}
+
+int intel_dp_min_bpp(enum intel_output_format output_format)
+{
+ if (output_format == INTEL_OUTPUT_FORMAT_RGB)
+ return 6 * 3;
+ else
+ return 8 * 3;
+}
+
+static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp)
+{
+ /*
+ * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
+ * format of the number of bytes per pixel will be half the number
+ * of bytes of RGB pixel.
+ */
+ if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+ bpp /= 2;
+
+ return bpp;
+}
+
+static int
+intel_dp_mode_min_output_bpp(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ enum intel_output_format output_format =
+ intel_dp_output_format(connector, mode);
+
+ return intel_dp_output_bpp(output_format, intel_dp_min_bpp(output_format));
+}
+
static bool intel_dp_hdisplay_bad(struct drm_i915_private *dev_priv,
int hdisplay)
{
@@ -653,10 +749,14 @@ intel_dp_mode_valid(struct drm_connector *connector,
u16 dsc_max_output_bpp = 0;
u8 dsc_slice_count = 0;
enum drm_mode_status status;
+ bool dsc = false, bigjoiner = false;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ return MODE_H_ILLEGAL;
+
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
if (mode->hdisplay > fixed_mode->hdisplay)
return MODE_PANEL;
@@ -667,11 +767,23 @@ intel_dp_mode_valid(struct drm_connector *connector,
target_clock = fixed_mode->clock;
}
+ if (mode->clock < 10000)
+ return MODE_CLOCK_LOW;
+
+ if ((target_clock > max_dotclk || mode->hdisplay > 5120) &&
+ intel_dp_can_bigjoiner(intel_dp)) {
+ bigjoiner = true;
+ max_dotclk *= 2;
+ }
+ if (target_clock > max_dotclk)
+ return MODE_CLOCK_HIGH;
+
max_link_clock = intel_dp_max_link_rate(intel_dp);
max_lanes = intel_dp_max_lane_count(intel_dp);
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
- mode_rate = intel_dp_link_required(target_clock, 18);
+ mode_rate = intel_dp_link_required(target_clock,
+ intel_dp_mode_min_output_bpp(connector, mode));
if (intel_dp_hdisplay_bad(dev_priv, mode->hdisplay))
return MODE_H_ILLEGAL;
@@ -694,30 +806,31 @@ intel_dp_mode_valid(struct drm_connector *connector,
max_link_clock,
max_lanes,
target_clock,
- mode->hdisplay) >> 4;
+ mode->hdisplay,
+ bigjoiner) >> 4;
dsc_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
target_clock,
- mode->hdisplay);
+ mode->hdisplay,
+ bigjoiner);
}
+
+ dsc = dsc_max_output_bpp && dsc_slice_count;
}
- if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) ||
- target_clock > max_dotclk)
+ /* big joiner configuration needs DSC */
+ if (bigjoiner && !dsc)
return MODE_CLOCK_HIGH;
- if (mode->clock < 10000)
- return MODE_CLOCK_LOW;
-
- if (mode->flags & DRM_MODE_FLAG_DBLCLK)
- return MODE_H_ILLEGAL;
+ if (mode_rate > max_rate && !dsc)
+ return MODE_CLOCK_HIGH;
status = intel_dp_mode_valid_downstream(intel_connector,
mode, target_clock);
if (status != MODE_OK)
return status;
- return intel_mode_valid_max_plane_size(dev_priv, mode);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, bigjoiner);
}
u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
@@ -1143,41 +1256,6 @@ _pp_stat_reg(struct intel_dp *intel_dp)
return regs.pp_stat;
}
-/* Reboot notifier handler to shutdown panel power to guarantee T12 timing
- This function only applicable when panel PM state is not to be tracked */
-static int edp_notify_handler(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp),
- edp_notifier);
- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- intel_wakeref_t wakeref;
-
- if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART)
- return 0;
-
- with_pps_lock(intel_dp, wakeref) {
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
- i915_reg_t pp_ctrl_reg, pp_div_reg;
- u32 pp_div;
-
- pp_ctrl_reg = PP_CONTROL(pipe);
- pp_div_reg = PP_DIVISOR(pipe);
- pp_div = intel_de_read(dev_priv, pp_div_reg);
- pp_div &= PP_REFERENCE_DIVIDER_MASK;
-
- /* 0x1F write to PP_DIV_REG sets max cycle delay */
- intel_de_write(dev_priv, pp_div_reg, pp_div | 0x1F);
- intel_de_write(dev_priv, pp_ctrl_reg,
- PANEL_UNLOCK_REGS);
- msleep(intel_dp->panel_power_cycle_delay);
- }
- }
-
- return 0;
-}
-
static bool edp_have_panel_power(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1744,7 +1822,6 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
case AUX_CH_D:
case AUX_CH_E:
case AUX_CH_F:
- case AUX_CH_G:
return DP_AUX_CH_CTL(aux_ch);
default:
MISSING_CASE(aux_ch);
@@ -1765,7 +1842,52 @@ static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
case AUX_CH_D:
case AUX_CH_E:
case AUX_CH_F:
- case AUX_CH_G:
+ return DP_AUX_CH_DATA(aux_ch, index);
+ default:
+ MISSING_CASE(aux_ch);
+ return DP_AUX_CH_DATA(AUX_CH_A, index);
+ }
+}
+
+static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ enum aux_ch aux_ch = dig_port->aux_ch;
+
+ switch (aux_ch) {
+ case AUX_CH_A:
+ case AUX_CH_B:
+ case AUX_CH_C:
+ case AUX_CH_USBC1:
+ case AUX_CH_USBC2:
+ case AUX_CH_USBC3:
+ case AUX_CH_USBC4:
+ case AUX_CH_USBC5:
+ case AUX_CH_USBC6:
+ return DP_AUX_CH_CTL(aux_ch);
+ default:
+ MISSING_CASE(aux_ch);
+ return DP_AUX_CH_CTL(AUX_CH_A);
+ }
+}
+
+static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index)
+{
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ enum aux_ch aux_ch = dig_port->aux_ch;
+
+ switch (aux_ch) {
+ case AUX_CH_A:
+ case AUX_CH_B:
+ case AUX_CH_C:
+ case AUX_CH_USBC1:
+ case AUX_CH_USBC2:
+ case AUX_CH_USBC3:
+ case AUX_CH_USBC4:
+ case AUX_CH_USBC5:
+ case AUX_CH_USBC6:
return DP_AUX_CH_DATA(aux_ch, index);
default:
MISSING_CASE(aux_ch);
@@ -1785,8 +1907,12 @@ intel_dp_aux_init(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct intel_encoder *encoder = &dig_port->base;
+ enum aux_ch aux_ch = dig_port->aux_ch;
- if (INTEL_GEN(dev_priv) >= 9) {
+ if (INTEL_GEN(dev_priv) >= 12) {
+ intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg;
+ intel_dp->aux_ch_data_reg = tgl_aux_data_reg;
+ } else if (INTEL_GEN(dev_priv) >= 9) {
intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
intel_dp->aux_ch_data_reg = skl_aux_data_reg;
} else if (HAS_PCH_SPLIT(dev_priv)) {
@@ -1814,9 +1940,15 @@ intel_dp_aux_init(struct intel_dp *intel_dp)
drm_dp_aux_init(&intel_dp->aux);
/* Failure to allocate our preferred name is not critical */
- intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/port %c",
- aux_ch_name(dig_port->aux_ch),
- port_name(encoder->port));
+ if (INTEL_GEN(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1)
+ intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s",
+ aux_ch - AUX_CH_USBC1 + '1',
+ encoder->base.name);
+ else
+ intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
+ aux_ch_name(aux_ch),
+ encoder->base.name);
+
intel_dp->aux.transfer = intel_dp_aux_transfer;
}
@@ -1968,12 +2100,10 @@ static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
- struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-
- if (!intel_dp_is_edp(intel_dp) && !crtc_state->fec_enable)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP) && !crtc_state->fec_enable)
return false;
- return intel_dsc_source_support(encoder, crtc_state) &&
+ return intel_dsc_source_support(crtc_state) &&
drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
}
@@ -2095,19 +2225,6 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
}
}
-static int intel_dp_output_bpp(const struct intel_crtc_state *crtc_state, int bpp)
-{
- /*
- * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
- * format of the number of bytes per pixel will be half the number
- * of bytes of RGB pixel.
- */
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
- bpp /= 2;
-
- return bpp;
-}
-
/* Optimize link config in order: max bpp, min clock, min lanes */
static int
intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
@@ -2119,7 +2236,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
int mode_rate, link_clock, link_avail;
for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
- int output_bpp = intel_dp_output_bpp(pipe_config, bpp);
+ int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp);
mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
output_bpp);
@@ -2280,11 +2397,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
pipe_config->port_clock,
pipe_config->lane_count,
adjusted_mode->crtc_clock,
- adjusted_mode->crtc_hdisplay);
+ adjusted_mode->crtc_hdisplay,
+ pipe_config->bigjoiner);
dsc_dp_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
adjusted_mode->crtc_clock,
- adjusted_mode->crtc_hdisplay);
+ adjusted_mode->crtc_hdisplay,
+ pipe_config->bigjoiner);
if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
drm_dbg_kms(&dev_priv->drm,
"Compressed BPP/Slice Count not supported\n");
@@ -2300,14 +2419,15 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
* is greater than the maximum Cdclock and if slice count is even
* then we need to use 2 VDSC instances.
*/
- if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
- if (pipe_config->dsc.slice_count > 1) {
- pipe_config->dsc.dsc_split = true;
- } else {
+ if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq ||
+ pipe_config->bigjoiner) {
+ if (pipe_config->dsc.slice_count < 2) {
drm_dbg_kms(&dev_priv->drm,
"Cannot split stream to use 2 VDSC instances\n");
return -EINVAL;
}
+
+ pipe_config->dsc.dsc_split = true;
}
ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config);
@@ -2330,14 +2450,6 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
return 0;
}
-int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state)
-{
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
- return 6 * 3;
- else
- return 8 * 3;
-}
-
static int
intel_dp_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -2363,7 +2475,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
limits.min_lane_count = 1;
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
- limits.min_bpp = intel_dp_min_bpp(pipe_config);
+ limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format);
limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config);
if (intel_dp_is_edp(intel_dp)) {
@@ -2386,6 +2498,11 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
intel_dp->common_rates[limits.max_clock],
limits.max_bpp, adjusted_mode->crtc_clock);
+ if ((adjusted_mode->crtc_clock > i915->max_dotclk_freq ||
+ adjusted_mode->crtc_hdisplay > 5120) &&
+ intel_dp_can_bigjoiner(intel_dp))
+ pipe_config->bigjoiner = true;
+
/*
* Optimize for slow and wide. This is the place to add alternative
* optimization policy.
@@ -2394,7 +2511,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
/* enable compression if the mode doesn't fit available BW */
drm_dbg_kms(&i915->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en);
- if (ret || intel_dp->force_dsc_en) {
+ if (ret || intel_dp->force_dsc_en || pipe_config->bigjoiner) {
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
conn_state, &limits);
if (ret < 0)
@@ -2429,32 +2546,6 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
return 0;
}
-static int
-intel_dp_ycbcr420_config(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state)
-{
- struct drm_connector *connector = conn_state->connector;
- const struct drm_display_info *info = &connector->display_info;
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
-
- if (!connector->ycbcr_420_allowed)
- return 0;
-
- if (!drm_mode_is_420_only(info, adjusted_mode))
- return 0;
-
- if (intel_dp->dfp.ycbcr_444_to_420) {
- crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
- return 0;
- }
-
- crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
-
- return intel_pch_panel_fitting(crtc_state, conn_state);
-}
-
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
@@ -2693,7 +2784,6 @@ intel_dp_compute_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
enum port port = encoder->port;
struct intel_connector *intel_connector = intel_dp->attached_connector;
struct intel_digital_connector_state *intel_conn_state =
@@ -2705,15 +2795,14 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
pipe_config->has_pch_encoder = true;
- pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+ pipe_config->output_format = intel_dp_output_format(&intel_connector->base,
+ adjusted_mode);
- if (lspcon->active)
- lspcon_ycbcr420_config(&intel_connector->base, pipe_config);
- else
- ret = intel_dp_ycbcr420_config(intel_dp, pipe_config,
- conn_state);
- if (ret)
- return ret;
+ if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
+ ret = intel_pch_panel_fitting(pipe_config, conn_state);
+ if (ret)
+ return ret;
+ }
if (!intel_dp_port_has_audio(dev_priv, port))
pipe_config->has_audio = false;
@@ -2757,7 +2846,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (pipe_config->dsc.compression_enable)
output_bpp = pipe_config->dsc.compressed_bpp;
else
- output_bpp = intel_dp_output_bpp(pipe_config, pipe_config->pipe_bpp);
+ output_bpp = intel_dp_output_bpp(pipe_config->output_format,
+ pipe_config->pipe_bpp);
intel_link_compute_m_n(output_bpp,
pipe_config->lane_count,
@@ -2779,13 +2869,11 @@ intel_dp_compute_config(struct intel_encoder *encoder,
}
void intel_dp_set_link_params(struct intel_dp *intel_dp,
- int link_rate, u8 lane_count,
- bool link_mst)
+ int link_rate, int lane_count)
{
intel_dp->link_trained = false;
intel_dp->link_rate = link_rate;
intel_dp->lane_count = lane_count;
- intel_dp->link_mst = link_mst;
}
static void intel_dp_prepare(struct intel_encoder *encoder,
@@ -2797,10 +2885,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
- pipe_config->lane_count,
- intel_crtc_has_type(pipe_config,
- INTEL_OUTPUT_DP_MST));
+ intel_dp_set_link_params(intel_dp,
+ pipe_config->port_clock,
+ pipe_config->lane_count);
/*
* There are four kinds of DP registers:
@@ -3492,32 +3579,33 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
enable ? "enable" : "disable");
}
-/* If the sink supports it, try to set the power state appropriately */
-void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
+/* If the device supports it, try to set the power state appropriately */
+void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
int ret, i;
/* Should have a valid DPCD by this point */
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
return;
- if (mode != DRM_MODE_DPMS_ON) {
+ if (mode != DP_SET_POWER_D0) {
if (downstream_hpd_needs_d0(intel_dp))
return;
- ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
- DP_SET_POWER_D3);
+ ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode);
} else {
struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+ lspcon_resume(dp_to_dig_port(intel_dp));
+
/*
* When turning on, we need to retry for 1ms to give the sink
* time to wake up.
*/
for (i = 0; i < 3; i++) {
- ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
- DP_SET_POWER_D0);
+ ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode);
if (ret == 1)
break;
msleep(1);
@@ -3528,8 +3616,9 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
}
if (ret != 1)
- drm_dbg_kms(&i915->drm, "failed to %s sink power state\n",
- mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Set power to %s failed\n",
+ encoder->base.base.id, encoder->base.name,
+ mode == DP_SET_POWER_D0 ? "D0" : "D3");
}
static bool cpt_dp_port_selected(struct drm_i915_private *dev_priv,
@@ -3686,6 +3775,72 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
}
}
+static bool
+intel_dp_get_dpcd(struct intel_dp *intel_dp);
+
+/**
+ * intel_dp_sync_state - sync the encoder state during init/resume
+ * @encoder: intel encoder to sync
+ * @crtc_state: state for the CRTC connected to the encoder
+ *
+ * Sync any state stored in the encoder wrt. HW state during driver init
+ * and system resume.
+ */
+void intel_dp_sync_state(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ /*
+ * Don't clobber DPCD if it's been already read out during output
+ * setup (eDP) or detect.
+ */
+ if (intel_dp->dpcd[DP_DPCD_REV] == 0)
+ intel_dp_get_dpcd(intel_dp);
+
+ intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
+ intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
+}
+
+bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ /*
+ * If BIOS has set an unsupported or non-standard link rate for some
+ * reason force an encoder recompute and full modeset.
+ */
+ if (intel_dp_rate_index(intel_dp->source_rates, intel_dp->num_source_rates,
+ crtc_state->port_clock) < 0) {
+ drm_dbg_kms(&i915->drm, "Forcing full modeset due to unsupported link rate\n");
+ crtc_state->uapi.connectors_changed = true;
+ return false;
+ }
+
+ /*
+ * FIXME hack to force full modeset when DSC is being used.
+ *
+ * As long as we do not have full state readout and config comparison
+ * of crtc_state->dsc, we have no way to ensure reliable fastset.
+ * Remove once we have readout for DSC.
+ */
+ if (crtc_state->dsc.compression_enable) {
+ drm_dbg_kms(&i915->drm, "Forcing full modeset due to DSC being enabled\n");
+ crtc_state->uapi.mode_changed = true;
+ return false;
+ }
+
+ if (CAN_PSR(i915) && intel_dp_is_edp(intel_dp)) {
+ drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n");
+ crtc_state->uapi.mode_changed = true;
+ return false;
+ }
+
+ return true;
+}
+
static void intel_disable_dp(struct intel_atomic_state *state,
struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
@@ -3703,7 +3858,7 @@ static void intel_disable_dp(struct intel_atomic_state *state,
* ensure that we have vdd while we switch off the panel. */
intel_edp_panel_vdd_on(intel_dp);
intel_edp_backlight_off(old_conn_state);
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D3);
intel_edp_panel_off(intel_dp);
}
@@ -3771,6 +3926,7 @@ static void chv_post_disable_dp(struct intel_atomic_state *state,
static void
cpt_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -3778,7 +3934,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
*DP &= ~DP_LINK_TRAIN_MASK_CPT;
- switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+ switch (intel_dp_training_pattern_symbol(dp_train_pat)) {
case DP_TRAINING_PATTERN_DISABLE:
*DP |= DP_LINK_TRAIN_OFF_CPT;
break;
@@ -3801,6 +3957,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
static void
g4x_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -3808,7 +3965,7 @@ g4x_set_link_train(struct intel_dp *intel_dp,
*DP &= ~DP_LINK_TRAIN_MASK;
- switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+ switch (intel_dp_training_pattern_symbol(dp_train_pat)) {
case DP_TRAINING_PATTERN_DISABLE:
*DP |= DP_LINK_TRAIN_OFF;
break;
@@ -3830,13 +3987,14 @@ g4x_set_link_train(struct intel_dp *intel_dp,
}
static void intel_dp_enable_port(struct intel_dp *intel_dp,
- const struct intel_crtc_state *old_crtc_state)
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
/* enable with pattern 1 (as per spec) */
- intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
+ intel_dp_program_link_training_pattern(intel_dp, crtc_state,
+ DP_TRAINING_PATTERN_1);
/*
* Magic for VLV/CHV. We _must_ first set up the register
@@ -3845,7 +4003,7 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp,
* fail when the power sequencer is freshly used for this port.
*/
intel_dp->DP |= DP_PORT_EN;
- if (old_crtc_state->has_audio)
+ if (crtc_state->has_audio)
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP);
@@ -3925,10 +4083,10 @@ static void intel_enable_dp(struct intel_atomic_state *state,
lane_mask);
}
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp);
- intel_dp_start_link_train(intel_dp);
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_start_link_train(intel_dp, pipe_config);
+ intel_dp_stop_link_train(intel_dp, pipe_config);
if (pipe_config->has_audio) {
drm_dbg(&dev_priv->drm, "Enabling DP audio on pipe %c\n",
@@ -4126,38 +4284,30 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state,
chv_phy_post_pll_disable(encoder, old_crtc_state);
}
-/*
- * Fetch AUX CH registers 0x202 - 0x207 which contain
- * link status information
- */
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
-{
- return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
- DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
-}
-
-static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp)
+static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
}
-static u8 intel_dp_voltage_max_3(struct intel_dp *intel_dp)
+static u8 intel_dp_voltage_max_3(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
}
-static u8 intel_dp_pre_empemph_max_2(struct intel_dp *intel_dp)
+static u8 intel_dp_preemph_max_2(struct intel_dp *intel_dp)
{
return DP_TRAIN_PRE_EMPH_LEVEL_2;
}
-static u8 intel_dp_pre_empemph_max_3(struct intel_dp *intel_dp)
+static u8 intel_dp_preemph_max_3(struct intel_dp *intel_dp)
{
return DP_TRAIN_PRE_EMPH_LEVEL_3;
}
-static void vlv_set_signal_levels(struct intel_dp *intel_dp)
+static void vlv_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
unsigned long demph_reg_value, preemph_reg_value,
@@ -4237,11 +4387,13 @@ static void vlv_set_signal_levels(struct intel_dp *intel_dp)
return;
}
- vlv_set_phy_signal_level(encoder, demph_reg_value, preemph_reg_value,
+ vlv_set_phy_signal_level(encoder, crtc_state,
+ demph_reg_value, preemph_reg_value,
uniqtranscale_reg_value, 0);
}
-static void chv_set_signal_levels(struct intel_dp *intel_dp)
+static void chv_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
u32 deemph_reg_value, margin_reg_value;
@@ -4318,8 +4470,9 @@ static void chv_set_signal_levels(struct intel_dp *intel_dp)
return;
}
- chv_set_phy_signal_level(encoder, deemph_reg_value,
- margin_reg_value, uniq_trans_scale);
+ chv_set_phy_signal_level(encoder, crtc_state,
+ deemph_reg_value, margin_reg_value,
+ uniq_trans_scale);
}
static u32 g4x_signal_levels(u8 train_set)
@@ -4360,7 +4513,8 @@ static u32 g4x_signal_levels(u8 train_set)
}
static void
-g4x_set_signal_levels(struct intel_dp *intel_dp)
+g4x_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4407,7 +4561,8 @@ static u32 snb_cpu_edp_signal_levels(u8 train_set)
}
static void
-snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp)
+snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4458,7 +4613,8 @@ static u32 ivb_cpu_edp_signal_levels(u8 train_set)
}
static void
-ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp)
+ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4476,7 +4632,8 @@ ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp)
intel_de_posting_read(dev_priv, intel_dp->output_reg);
}
-void intel_dp_set_signal_levels(struct intel_dp *intel_dp)
+void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4490,28 +4647,23 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp)
train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ?
" (max)" : "");
- intel_dp->set_signal_levels(intel_dp);
+ intel_dp->set_signal_levels(intel_dp, crtc_state);
}
void
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
- if (dp_train_pat & train_pat_mask)
+ if ((intel_dp_training_pattern_symbol(dp_train_pat)) !=
+ DP_TRAINING_PATTERN_DISABLE)
drm_dbg_kms(&dev_priv->drm,
"Using DP training pattern TPS%d\n",
- dp_train_pat & train_pat_mask);
-
- intel_dp->set_link_train(intel_dp, dp_train_pat);
-}
+ intel_dp_training_pattern_symbol(dp_train_pat));
-void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
-{
- if (intel_dp->set_idle_link_train)
- intel_dp->set_idle_link_train(intel_dp);
+ intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat);
}
static void
@@ -4732,6 +4884,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
{
int ret;
+ intel_dp_lttpr_init(intel_dp);
+
if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd))
return false;
@@ -5404,33 +5558,14 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
return test_result;
}
-static u8 intel_dp_prepare_phytest(struct intel_dp *intel_dp)
-{
- struct drm_dp_phy_test_params *data =
- &intel_dp->compliance.test_data.phytest;
-
- if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) {
- DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
- return DP_TEST_NAK;
- }
-
- /*
- * link_mst is set to false to avoid executing mst related code
- * during compliance testing.
- */
- intel_dp->link_mst = false;
-
- return DP_TEST_ACK;
-}
-
-static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp)
+static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv =
to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
- struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_dp_phy_test_params *data =
&intel_dp->compliance.test_data.phytest;
- struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
u32 pattern_val;
@@ -5490,7 +5625,8 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp)
}
static void
-intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp)
+intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
@@ -5516,7 +5652,8 @@ intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp)
}
static void
-intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt)
+intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
@@ -5542,27 +5679,30 @@ intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt)
trans_ddi_func_ctl_value);
}
-void intel_dp_process_phy_request(struct intel_dp *intel_dp)
+static void intel_dp_process_phy_request(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_dp_phy_test_params *data =
&intel_dp->compliance.test_data.phytest;
u8 link_status[DP_LINK_STATUS_SIZE];
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
+ link_status) < 0) {
DRM_DEBUG_KMS("failed to get link status\n");
return;
}
/* retrieve vswing & pre-emphasis setting */
- intel_dp_get_adjust_train(intel_dp, link_status);
+ intel_dp_get_adjust_train(intel_dp, crtc_state, DP_PHY_DPRX,
+ link_status);
- intel_dp_autotest_phy_ddi_disable(intel_dp);
+ intel_dp_autotest_phy_ddi_disable(intel_dp, crtc_state);
- intel_dp_set_signal_levels(intel_dp);
+ intel_dp_set_signal_levels(intel_dp, crtc_state);
- intel_dp_phy_pattern_update(intel_dp);
+ intel_dp_phy_pattern_update(intel_dp, crtc_state);
- intel_dp_autotest_phy_ddi_enable(intel_dp, data->num_lanes);
+ intel_dp_autotest_phy_ddi_enable(intel_dp, crtc_state);
drm_dp_set_phy_test_pattern(&intel_dp->aux, data,
link_status[DP_DPCD_REV]);
@@ -5570,15 +5710,18 @@ void intel_dp_process_phy_request(struct intel_dp *intel_dp)
static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
{
- u8 test_result;
+ struct drm_dp_phy_test_params *data =
+ &intel_dp->compliance.test_data.phytest;
- test_result = intel_dp_prepare_phytest(intel_dp);
- if (test_result != DP_TEST_ACK)
- DRM_ERROR("Phy test preparation failed\n");
+ if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) {
+ DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
+ return DP_TEST_NAK;
+ }
- intel_dp_process_phy_request(intel_dp);
+ /* Set test active flag here so userspace doesn't interrupt things */
+ intel_dp->compliance.test_active = true;
- return test_result;
+ return DP_TEST_ACK;
}
static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
@@ -5709,12 +5852,17 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
if (intel_psr_enabled(intel_dp))
return false;
- if (!intel_dp_get_link_status(intel_dp, link_status))
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
+ link_status) < 0)
return false;
/*
* Validate the cached values of intel_dp->link_rate and
* intel_dp->lane_count before attempting to retrain.
+ *
+ * FIXME would be nice to user the crtc state here, but since
+ * we need to call this from the short HPD handler that seems
+ * a bit hard.
*/
if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
intel_dp->lane_count))
@@ -5848,8 +5996,20 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
intel_crtc_pch_transcoder(crtc), false);
}
- intel_dp_start_link_train(intel_dp);
- intel_dp_stop_link_train(intel_dp);
+ for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+
+ /* retrain on the MST master transcoder */
+ if (INTEL_GEN(dev_priv) >= 12 &&
+ intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) &&
+ !intel_dp_mst_is_master_trans(crtc_state))
+ continue;
+
+ intel_dp_start_link_train(intel_dp, crtc_state);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
+ break;
+ }
for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) {
const struct intel_crtc_state *crtc_state =
@@ -5867,6 +6027,118 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
return 0;
}
+static int intel_dp_prep_phy_test(struct intel_dp *intel_dp,
+ struct drm_modeset_acquire_ctx *ctx,
+ u32 *crtc_mask)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct drm_connector_list_iter conn_iter;
+ struct intel_connector *connector;
+ int ret = 0;
+
+ *crtc_mask = 0;
+
+ drm_connector_list_iter_begin(&i915->drm, &conn_iter);
+ for_each_intel_connector_iter(connector, &conn_iter) {
+ struct drm_connector_state *conn_state =
+ connector->base.state;
+ struct intel_crtc_state *crtc_state;
+ struct intel_crtc *crtc;
+
+ if (!intel_dp_has_connector(intel_dp, conn_state))
+ continue;
+
+ crtc = to_intel_crtc(conn_state->crtc);
+ if (!crtc)
+ continue;
+
+ ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+ if (ret)
+ break;
+
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+
+ drm_WARN_ON(&i915->drm, !intel_crtc_has_dp_encoder(crtc_state));
+
+ if (!crtc_state->hw.active)
+ continue;
+
+ if (conn_state->commit &&
+ !try_wait_for_completion(&conn_state->commit->hw_done))
+ continue;
+
+ *crtc_mask |= drm_crtc_mask(&crtc->base);
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return ret;
+}
+
+static int intel_dp_do_phy_test(struct intel_encoder *encoder,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct intel_crtc *crtc;
+ u32 crtc_mask;
+ int ret;
+
+ ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
+ ctx);
+ if (ret)
+ return ret;
+
+ ret = intel_dp_prep_phy_test(intel_dp, ctx, &crtc_mask);
+ if (ret)
+ return ret;
+
+ if (crtc_mask == 0)
+ return 0;
+
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] PHY test\n",
+ encoder->base.base.id, encoder->base.name);
+
+ for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+
+ /* test on the MST master transcoder */
+ if (INTEL_GEN(dev_priv) >= 12 &&
+ intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) &&
+ !intel_dp_mst_is_master_trans(crtc_state))
+ continue;
+
+ intel_dp_process_phy_request(intel_dp, crtc_state);
+ break;
+ }
+
+ return 0;
+}
+
+static void intel_dp_phy_test(struct intel_encoder *encoder)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ int ret;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ for (;;) {
+ ret = intel_dp_do_phy_test(encoder, &ctx);
+
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ continue;
+ }
+
+ break;
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_WARN(encoder->base.dev, ret,
+ "Acquiring modeset locks failed with %i\n", ret);
+}
+
/*
* If display is now connected check links status,
* there has been known issues of link loss triggering
@@ -5883,10 +6155,18 @@ static enum intel_hotplug_state
intel_dp_hotplug(struct intel_encoder *encoder,
struct intel_connector *connector)
{
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_modeset_acquire_ctx ctx;
enum intel_hotplug_state state;
int ret;
+ if (intel_dp->compliance.test_active &&
+ intel_dp->compliance.test_type == DP_TEST_LINK_PHY_TEST_PATTERN) {
+ intel_dp_phy_test(encoder);
+ /* just do the PHY test and nothing else */
+ return INTEL_HOTPLUG_UNCHANGED;
+ }
+
state = intel_encoder_hotplug(encoder, connector);
drm_modeset_acquire_init(&ctx, 0);
@@ -5991,11 +6271,23 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
intel_psr_short_pulse(intel_dp);
- if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
+ switch (intel_dp->compliance.test_type) {
+ case DP_TEST_LINK_TRAINING:
drm_dbg_kms(&dev_priv->drm,
"Link Training Compliance Test requested\n");
/* Send a Hotplug Uevent to userspace to start modeset */
drm_kms_helper_hotplug_event(&dev_priv->drm);
+ break;
+ case DP_TEST_LINK_PHY_TEST_PATTERN:
+ drm_dbg_kms(&dev_priv->drm,
+ "PHY test pattern Compliance Test requested\n");
+ /*
+ * Schedule long hpd to do the test
+ *
+ * FIXME get rid of the ad-hoc phy test modeset code
+ * and properly incorporate it into the normal modeset.
+ */
+ return false;
}
return true;
@@ -6006,15 +6298,14 @@ static enum drm_connector_status
intel_dp_detect_dpcd(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
u8 *dpcd = intel_dp->dpcd;
u8 type;
if (drm_WARN_ON(&i915->drm, intel_dp_is_edp(intel_dp)))
return connector_status_connected;
- if (lspcon->active)
- lspcon_resume(lspcon);
+ lspcon_resume(dig_port);
if (!intel_dp_get_dpcd(intel_dp))
return connector_status_disconnected;
@@ -6220,7 +6511,9 @@ intel_dp_update_420(struct intel_dp *intel_dp)
ycbcr_420_passthrough =
drm_dp_downstream_420_passthrough(intel_dp->dpcd,
intel_dp->downstream_ports);
+ /* on-board LSPCON always assumed to support 4:4:4->4:2:0 conversion */
ycbcr_444_to_420 =
+ dp_to_dig_port(intel_dp)->lspcon.active ||
drm_dp_downstream_444_to_420_conversion(intel_dp->dpcd,
intel_dp->downstream_ports);
@@ -6523,11 +6816,6 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
*/
with_pps_lock(intel_dp, wakeref)
edp_panel_vdd_off_sync(intel_dp);
-
- if (intel_dp->edp_notifier.notifier_call) {
- unregister_reboot_notifier(&intel_dp->edp_notifier);
- intel_dp->edp_notifier.notifier_call = NULL;
- }
}
intel_dp_aux_fini(intel_dp);
@@ -6558,6 +6846,18 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
edp_panel_vdd_off_sync(intel_dp);
}
+void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder);
+ intel_wakeref_t wakeref;
+
+ if (!intel_dp_is_edp(intel_dp))
+ return;
+
+ with_pps_lock(intel_dp, wakeref)
+ wait_panel_power_cycle(intel_dp);
+}
+
static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -6598,15 +6898,11 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->dev);
struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder));
- struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
intel_wakeref_t wakeref;
if (!HAS_DDI(dev_priv))
intel_dp->DP = intel_de_read(dev_priv, intel_dp->output_reg);
- if (lspcon->active)
- lspcon_resume(lspcon);
-
intel_dp->reset_link_params = true;
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
@@ -7671,9 +7967,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
mutex_unlock(&dev->mode_config.mutex);
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- intel_dp->edp_notifier.notifier_call = edp_notify_handler;
- register_reboot_notifier(&intel_dp->edp_notifier);
-
/*
* Figure out the current pipe for the initial backlight setup.
* If the current pipe isn't valid, try the PPS pipe, and if that
@@ -7892,8 +8185,11 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
intel_encoder->compute_config = intel_dp_compute_config;
intel_encoder->get_hw_state = intel_dp_get_hw_state;
intel_encoder->get_config = intel_dp_get_config;
+ intel_encoder->sync_state = intel_dp_sync_state;
+ intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check;
intel_encoder->update_pipe = intel_panel_update_backlight;
intel_encoder->suspend = intel_dp_encoder_suspend;
+ intel_encoder->shutdown = intel_dp_encoder_shutdown;
if (IS_CHERRYVIEW(dev_priv)) {
intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
intel_encoder->pre_enable = chv_pre_enable_dp;
@@ -7933,17 +8229,15 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) ||
(HAS_PCH_SPLIT(dev_priv) && port != PORT_A)) {
- dig_port->dp.preemph_max = intel_dp_pre_empemph_max_3;
+ dig_port->dp.preemph_max = intel_dp_preemph_max_3;
dig_port->dp.voltage_max = intel_dp_voltage_max_3;
} else {
- dig_port->dp.preemph_max = intel_dp_pre_empemph_max_2;
+ dig_port->dp.preemph_max = intel_dp_preemph_max_2;
dig_port->dp.voltage_max = intel_dp_voltage_max_2;
}
dig_port->dp.output_reg = output_reg;
dig_port->max_lanes = 4;
- dig_port->dp.regs.dp_tp_ctl = DP_TP_CTL(port);
- dig_port->dp.regs.dp_tp_status = DP_TP_STATUS(port);
intel_encoder->type = INTEL_OUTPUT_DP;
intel_encoder->power_domain = intel_port_to_power_domain(port);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 08a1c0aa8b94..b871a09b6901 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -10,6 +10,7 @@
#include "i915_reg.h"
+enum intel_output_format;
enum pipe;
enum port;
struct drm_connector_state;
@@ -35,7 +36,7 @@ void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
struct link_config_limits *limits);
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
-int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state);
+int intel_dp_min_bpp(enum intel_output_format output_format);
bool intel_dp_port_enabled(struct drm_i915_private *dev_priv,
i915_reg_t dp_reg, enum port port,
enum pipe *pipe);
@@ -44,19 +45,19 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg,
bool intel_dp_init_connector(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector);
void intel_dp_set_link_params(struct intel_dp *intel_dp,
- int link_rate, u8 lane_count,
- bool link_mst);
+ int link_rate, int lane_count);
int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
int link_rate, u8 lane_count);
int intel_dp_retrain_link(struct intel_encoder *encoder,
struct drm_modeset_acquire_ctx *ctx);
-void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
+void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp);
void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
bool enable);
void intel_dp_encoder_reset(struct drm_encoder *encoder);
void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
+void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder);
void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
int intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -92,20 +93,20 @@ void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
void
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat);
void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp);
-void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
+intel_dp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
u8 *link_bw, u8 *rate_select);
bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
int intel_dp_link_required(int pixel_clock, int bpp);
int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
+bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp);
bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
@@ -122,7 +123,6 @@ void intel_read_dp_sdp(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
unsigned int type);
bool intel_digital_port_connected(struct intel_encoder *encoder);
-void intel_dp_process_phy_request(struct intel_dp *intel_dp);
static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
{
@@ -139,4 +139,9 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state,
int intel_dp_init_hdcp(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector);
+bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state);
+void intel_dp_sync_state(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+
#endif /* __INTEL_DP_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
index 036f504ac7db..51d27fc98d48 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
@@ -343,8 +343,7 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector)
* the panel can support backlight control over the aux channel
*/
if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
- (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) &&
- !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
+ (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) {
drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
return true;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index f2c8b56be9ea..91d3979902d0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -34,6 +34,152 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
link_status[3], link_status[4], link_status[5]);
}
+static int intel_dp_lttpr_count(struct intel_dp *intel_dp)
+{
+ int count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps);
+
+ /*
+ * Pretend no LTTPRs in case of LTTPR detection error, or
+ * if too many (>8) LTTPRs are detected. This translates to link
+ * training in transparent mode.
+ */
+ return count <= 0 ? 0 : count;
+}
+
+static void intel_dp_reset_lttpr_count(struct intel_dp *intel_dp)
+{
+ intel_dp->lttpr_common_caps[DP_PHY_REPEATER_CNT -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV] = 0;
+}
+
+static const char *intel_dp_phy_name(enum drm_dp_phy dp_phy,
+ char *buf, size_t buf_size)
+{
+ if (dp_phy == DP_PHY_DPRX)
+ snprintf(buf, buf_size, "DPRX");
+ else
+ snprintf(buf, buf_size, "LTTPR %d", dp_phy - DP_PHY_LTTPR1 + 1);
+
+ return buf;
+}
+
+static u8 *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ return intel_dp->lttpr_phy_caps[dp_phy - DP_PHY_LTTPR1];
+}
+
+static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+ char phy_name[10];
+
+ intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name));
+
+ if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) {
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "failed to read the PHY caps for %s\n",
+ phy_name);
+ return;
+ }
+
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "%s PHY capabilities: %*ph\n",
+ phy_name,
+ (int)sizeof(intel_dp->lttpr_phy_caps[0]),
+ phy_caps);
+}
+
+static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp)
+{
+ if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
+ intel_dp->lttpr_common_caps) < 0) {
+ memset(intel_dp->lttpr_common_caps, 0,
+ sizeof(intel_dp->lttpr_common_caps));
+ return false;
+ }
+
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "LTTPR common capabilities: %*ph\n",
+ (int)sizeof(intel_dp->lttpr_common_caps),
+ intel_dp->lttpr_common_caps);
+
+ return true;
+}
+
+static bool
+intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
+{
+ u8 val = enable ? DP_PHY_REPEATER_MODE_TRANSPARENT :
+ DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
+
+ return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
+}
+
+/**
+ * intel_dp_lttpr_init - detect LTTPRs and init the LTTPR link training mode
+ * @intel_dp: Intel DP struct
+ *
+ * Read the LTTPR common capabilities, switch to non-transparent link training
+ * mode if any is detected and read the PHY capabilities for all detected
+ * LTTPRs. In case of an LTTPR detection error or if the number of
+ * LTTPRs is more than is supported (8), fall back to the no-LTTPR,
+ * transparent mode link training mode.
+ *
+ * Returns:
+ * >0 if LTTPRs were detected and the non-transparent LT mode was set
+ * 0 if no LTTPRs or more than 8 LTTPRs were detected or in case of a
+ * detection failure and the transparent LT mode was set
+ */
+int intel_dp_lttpr_init(struct intel_dp *intel_dp)
+{
+ int lttpr_count;
+ bool ret;
+ int i;
+
+ if (intel_dp_is_edp(intel_dp))
+ return 0;
+
+ ret = intel_dp_read_lttpr_common_caps(intel_dp);
+
+ /*
+ * See DP Standard v2.0 3.6.6.1. about the explicit disabling of
+ * non-transparent mode and the disable->enable non-transparent mode
+ * sequence.
+ */
+ intel_dp_set_lttpr_transparent_mode(intel_dp, true);
+
+ if (!ret)
+ return 0;
+
+ lttpr_count = intel_dp_lttpr_count(intel_dp);
+
+ /*
+ * In case of unsupported number of LTTPRs or failing to switch to
+ * non-transparent mode fall-back to transparent link training mode,
+ * still taking into account any LTTPR common lane- rate/count limits.
+ */
+ if (lttpr_count == 0)
+ return 0;
+
+ if (!intel_dp_set_lttpr_transparent_mode(intel_dp, false)) {
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "Switching to LTTPR non-transparent LT mode failed, fall-back to transparent mode\n");
+
+ intel_dp_set_lttpr_transparent_mode(intel_dp, true);
+ intel_dp_reset_lttpr_count(intel_dp);
+
+ return 0;
+ }
+
+ for (i = 0; i < lttpr_count; i++)
+ intel_dp_read_lttpr_phy_caps(intel_dp, DP_PHY_LTTPR(i));
+
+ return lttpr_count;
+}
+EXPORT_SYMBOL(intel_dp_lttpr_init);
+
static u8 dp_voltage_max(u8 preemph)
{
switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
@@ -49,36 +195,109 @@ static u8 dp_voltage_max(u8 preemph)
}
}
-void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
- const u8 link_status[DP_LINK_STATUS_SIZE])
+static u8 intel_dp_lttpr_voltage_max(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+ if (drm_dp_lttpr_voltage_swing_level_3_supported(phy_caps))
+ return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+ else
+ return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+}
+
+static u8 intel_dp_lttpr_preemph_max(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+ if (drm_dp_lttpr_pre_emphasis_level_3_supported(phy_caps))
+ return DP_TRAIN_PRE_EMPH_LEVEL_3;
+ else
+ return DP_TRAIN_PRE_EMPH_LEVEL_2;
+}
+
+static bool
+intel_dp_phy_is_downstream_of_source(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ int lttpr_count = intel_dp_lttpr_count(intel_dp);
+
+ drm_WARN_ON_ONCE(&i915->drm, lttpr_count == 0 && dp_phy != DP_PHY_DPRX);
+
+ return lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1);
+}
+
+static u8 intel_dp_phy_voltage_max(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ u8 voltage_max;
+
+ /*
+ * Get voltage_max from the DPTX_PHY (source or LTTPR) upstream from
+ * the DPRX_PHY we train.
+ */
+ if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
+ voltage_max = intel_dp->voltage_max(intel_dp, crtc_state);
+ else
+ voltage_max = intel_dp_lttpr_voltage_max(intel_dp, dp_phy + 1);
+
+ drm_WARN_ON_ONCE(&i915->drm,
+ voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
+ voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
+
+ return voltage_max;
+}
+
+static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ u8 preemph_max;
+
+ /*
+ * Get preemph_max from the DPTX_PHY (source or LTTPR) upstream from
+ * the DPRX_PHY we train.
+ */
+ if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
+ preemph_max = intel_dp->preemph_max(intel_dp);
+ else
+ preemph_max = intel_dp_lttpr_preemph_max(intel_dp, dp_phy + 1);
+
+ drm_WARN_ON_ONCE(&i915->drm,
+ preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
+ preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
+
+ return preemph_max;
+}
+
+void
+intel_dp_get_adjust_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
+ const u8 link_status[DP_LINK_STATUS_SIZE])
+{
u8 v = 0;
u8 p = 0;
int lane;
u8 voltage_max;
u8 preemph_max;
- for (lane = 0; lane < intel_dp->lane_count; lane++) {
+ for (lane = 0; lane < crtc_state->lane_count; lane++) {
v = max(v, drm_dp_get_adjust_request_voltage(link_status, lane));
p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane));
}
- preemph_max = intel_dp->preemph_max(intel_dp);
- drm_WARN_ON_ONCE(&i915->drm,
- preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
- preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
-
+ preemph_max = intel_dp_phy_preemph_max(intel_dp, dp_phy);
if (p >= preemph_max)
p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
v = min(v, dp_voltage_max(p));
- voltage_max = intel_dp->voltage_max(intel_dp);
- drm_WARN_ON_ONCE(&i915->drm,
- voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
- voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
-
+ voltage_max = intel_dp_phy_voltage_max(intel_dp, crtc_state, dp_phy);
if (v >= voltage_max)
v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
@@ -86,59 +305,70 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
intel_dp->train_set[lane] = v | p;
}
+static int intel_dp_training_pattern_set_reg(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ return dp_phy == DP_PHY_DPRX ?
+ DP_TRAINING_PATTERN_SET :
+ DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
+}
+
static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
u8 dp_train_pat)
{
+ int reg = intel_dp_training_pattern_set_reg(intel_dp, dp_phy);
u8 buf[sizeof(intel_dp->train_set) + 1];
- int ret, len;
+ int len;
- intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
+ intel_dp_program_link_training_pattern(intel_dp, crtc_state,
+ dp_train_pat);
buf[0] = dp_train_pat;
- if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
- DP_TRAINING_PATTERN_DISABLE) {
- /* don't write DP_TRAINING_LANEx_SET on disable */
- len = 1;
- } else {
- /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
- memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
- len = intel_dp->lane_count + 1;
- }
-
- ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
- buf, len);
+ /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
+ memcpy(buf + 1, intel_dp->train_set, crtc_state->lane_count);
+ len = crtc_state->lane_count + 1;
- return ret == len;
+ return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
}
static bool
intel_dp_reset_link_train(struct intel_dp *intel_dp,
- u8 dp_train_pat)
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
+ u8 dp_train_pat)
{
memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
- intel_dp_set_signal_levels(intel_dp);
- return intel_dp_set_link_train(intel_dp, dp_train_pat);
+ intel_dp_set_signal_levels(intel_dp, crtc_state);
+ return intel_dp_set_link_train(intel_dp, crtc_state, dp_phy, dp_train_pat);
}
static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp)
+intel_dp_update_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
+ int reg = dp_phy == DP_PHY_DPRX ?
+ DP_TRAINING_LANE0_SET :
+ DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
int ret;
- intel_dp_set_signal_levels(intel_dp);
+ intel_dp_set_signal_levels(intel_dp, crtc_state);
- ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
- intel_dp->train_set, intel_dp->lane_count);
+ ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
+ intel_dp->train_set, crtc_state->lane_count);
- return ret == intel_dp->lane_count;
+ return ret == crtc_state->lane_count;
}
-static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
int lane;
- for (lane = 0; lane < intel_dp->lane_count; lane++)
+ for (lane = 0; lane < crtc_state->lane_count; lane++)
if ((intel_dp->train_set[lane] &
DP_TRAIN_MAX_SWING_REACHED) == 0)
return false;
@@ -146,21 +376,22 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
return true;
}
-/* Enable corresponding port and start training pattern 1 */
+/*
+ * Prepare link training by configuring the link parameters. On DDI platforms
+ * also enable the port here.
+ */
static bool
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+intel_dp_prepare_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- u8 voltage;
- int voltage_tries, cr_tries, max_cr_tries;
- bool max_vswing_reached = false;
u8 link_config[2];
u8 link_bw, rate_select;
if (intel_dp->prepare_link_retrain)
- intel_dp->prepare_link_retrain(intel_dp);
+ intel_dp->prepare_link_retrain(intel_dp, crtc_state);
- intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
+ intel_dp_compute_rate(intel_dp, crtc_state->port_clock,
&link_bw, &rate_select);
if (link_bw)
@@ -172,7 +403,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
/* Write the link configuration data */
link_config[0] = link_bw;
- link_config[1] = intel_dp->lane_count;
+ link_config[1] = crtc_state->lane_count;
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
@@ -188,8 +419,34 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
intel_dp->DP |= DP_PORT_EN;
+ return true;
+}
+
+static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ if (dp_phy == DP_PHY_DPRX)
+ drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+ else
+ drm_dp_lttpr_link_train_clock_recovery_delay();
+}
+
+/*
+ * Perform the link training clock recovery phase on the given DP PHY using
+ * training pattern 1.
+ */
+static bool
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ u8 voltage;
+ int voltage_tries, cr_tries, max_cr_tries;
+ bool max_vswing_reached = false;
+
/* clock recovery */
- if (!intel_dp_reset_link_train(intel_dp,
+ if (!intel_dp_reset_link_train(intel_dp, crtc_state, dp_phy,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE)) {
drm_err(&i915->drm, "failed to enable link training\n");
@@ -213,14 +470,15 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
u8 link_status[DP_LINK_STATUS_SIZE];
- drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+ intel_dp_link_training_clock_recovery_delay(intel_dp, dp_phy);
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy,
+ link_status) < 0) {
drm_err(&i915->drm, "failed to get link status\n");
return false;
}
- if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+ if (drm_dp_clock_recovery_ok(link_status, crtc_state->lane_count)) {
drm_dbg_kms(&i915->drm, "clock recovery OK\n");
return true;
}
@@ -239,8 +497,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Update training set as requested by target */
- intel_dp_get_adjust_train(intel_dp, link_status);
- if (!intel_dp_update_link_train(intel_dp)) {
+ intel_dp_get_adjust_train(intel_dp, crtc_state, dp_phy,
+ link_status);
+ if (!intel_dp_update_link_train(intel_dp, crtc_state, dp_phy)) {
drm_err(&i915->drm,
"failed to update link training\n");
return false;
@@ -252,7 +511,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
else
voltage_tries = 1;
- if (intel_dp_link_max_vswing_reached(intel_dp))
+ if (intel_dp_link_max_vswing_reached(intel_dp, crtc_state))
max_vswing_reached = true;
}
@@ -266,7 +525,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
* or for 1.4 devices that support it, training Pattern 3 for HBR2
* or 1.2 devices that support it, Training Pattern 2 otherwise.
*/
-static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
+static u32 intel_dp_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
bool source_tps3, sink_tps3, source_tps4, sink_tps4;
@@ -275,12 +536,14 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
* for all downstream devices that support HBR3. There are no known eDP
* panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
* specification.
+ * LTTPRs must support TPS4.
*/
source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
- sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
+ sink_tps4 = dp_phy != DP_PHY_DPRX ||
+ drm_dp_tps4_supported(intel_dp->dpcd);
if (source_tps4 && sink_tps4) {
return DP_TRAINING_PATTERN_4;
- } else if (intel_dp->link_rate == 810000) {
+ } else if (crtc_state->port_clock == 810000) {
if (!source_tps4)
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
"8.1 Gbps link rate without source HBR3/TPS4 support\n");
@@ -294,10 +557,11 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
* all sinks follow the spec.
*/
source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
- sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
+ sink_tps3 = dp_phy != DP_PHY_DPRX ||
+ drm_dp_tps3_supported(intel_dp->dpcd);
if (source_tps3 && sink_tps3) {
return DP_TRAINING_PATTERN_3;
- } else if (intel_dp->link_rate >= 540000) {
+ } else if (crtc_state->port_clock >= 540000) {
if (!source_tps3)
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n");
@@ -309,8 +573,28 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
return DP_TRAINING_PATTERN_2;
}
+static void
+intel_dp_link_training_channel_equalization_delay(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ if (dp_phy == DP_PHY_DPRX) {
+ drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
+ } else {
+ const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+ drm_dp_lttpr_link_train_channel_eq_delay(phy_caps);
+ }
+}
+
+/*
+ * Perform the link training channel equalization phase on the given DP PHY
+ * using one of training pattern 2, 3 or 4 depending on the source and
+ * sink capabilities.
+ */
static bool
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int tries;
@@ -318,22 +602,23 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
u8 link_status[DP_LINK_STATUS_SIZE];
bool channel_eq = false;
- training_pattern = intel_dp_training_pattern(intel_dp);
+ training_pattern = intel_dp_training_pattern(intel_dp, crtc_state, dp_phy);
/* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
if (training_pattern != DP_TRAINING_PATTERN_4)
training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
/* channel equalization */
- if (!intel_dp_set_link_train(intel_dp,
+ if (!intel_dp_set_link_train(intel_dp, crtc_state, dp_phy,
training_pattern)) {
drm_err(&i915->drm, "failed to start channel equalization\n");
return false;
}
for (tries = 0; tries < 5; tries++) {
-
- drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ intel_dp_link_training_channel_equalization_delay(intel_dp,
+ dp_phy);
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy,
+ link_status) < 0) {
drm_err(&i915->drm,
"failed to get link status\n");
break;
@@ -341,7 +626,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
/* Make sure clock is still ok */
if (!drm_dp_clock_recovery_ok(link_status,
- intel_dp->lane_count)) {
+ crtc_state->lane_count)) {
intel_dp_dump_link_status(link_status);
drm_dbg_kms(&i915->drm,
"Clock recovery check failed, cannot "
@@ -350,7 +635,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
}
if (drm_dp_channel_eq_ok(link_status,
- intel_dp->lane_count)) {
+ crtc_state->lane_count)) {
channel_eq = true;
drm_dbg_kms(&i915->drm, "Channel EQ done. DP Training "
"successful\n");
@@ -358,8 +643,9 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
}
/* Update training set as requested by target */
- intel_dp_get_adjust_train(intel_dp, link_status);
- if (!intel_dp_update_link_train(intel_dp)) {
+ intel_dp_get_adjust_train(intel_dp, crtc_state, dp_phy,
+ link_status);
+ if (!intel_dp_update_link_train(intel_dp, crtc_state, dp_phy)) {
drm_err(&i915->drm,
"failed to update link training\n");
break;
@@ -373,54 +659,142 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
"Channel equalization failed 5 times\n");
}
- intel_dp_set_idle_link_train(intel_dp);
-
return channel_eq;
+}
+static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ int reg = intel_dp_training_pattern_set_reg(intel_dp, dp_phy);
+ u8 val = DP_TRAINING_PATTERN_DISABLE;
+
+ return drm_dp_dpcd_write(&intel_dp->aux, reg, &val, 1) == 1;
}
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+/**
+ * intel_dp_stop_link_train - stop link training
+ * @intel_dp: DP struct
+ * @crtc_state: state for CRTC attached to the encoder
+ *
+ * Stop the link training of the @intel_dp port, disabling the test pattern
+ * symbol generation on the port and disabling the training pattern in
+ * the sink's DPCD.
+ *
+ * What symbols are output on the port after this point is
+ * platform specific: On DDI/VLV/CHV platforms it will be the idle pattern
+ * with the pipe being disabled, on older platforms it's HW specific if/how an
+ * idle pattern is generated, as the pipe is already enabled here for those.
+ *
+ * This function must be called after intel_dp_start_link_train().
+ */
+void intel_dp_stop_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
intel_dp->link_trained = true;
- intel_dp_set_link_train(intel_dp,
- DP_TRAINING_PATTERN_DISABLE);
+ intel_dp_program_link_training_pattern(intel_dp,
+ crtc_state,
+ DP_TRAINING_PATTERN_DISABLE);
+ intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX);
}
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
+static bool
+intel_dp_link_train_phy(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
struct intel_connector *intel_connector = intel_dp->attached_connector;
+ char phy_name[10];
+ bool ret = false;
- if (!intel_dp_link_training_clock_recovery(intel_dp))
- goto failure_handling;
- if (!intel_dp_link_training_channel_equalization(intel_dp))
- goto failure_handling;
+ if (!intel_dp_link_training_clock_recovery(intel_dp, crtc_state, dp_phy))
+ goto out;
- drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
- "[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
- intel_connector->base.base.id,
- intel_connector->base.name,
- intel_dp->link_rate, intel_dp->lane_count);
- return;
+ if (!intel_dp_link_training_channel_equalization(intel_dp, crtc_state, dp_phy))
+ goto out;
+
+ ret = true;
- failure_handling:
+out:
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
- "[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
+ "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s",
intel_connector->base.base.id,
intel_connector->base.name,
- intel_dp->link_rate, intel_dp->lane_count);
+ ret ? "passed" : "failed",
+ crtc_state->port_clock, crtc_state->lane_count,
+ intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
+
+ return ret;
+}
+
+static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_connector *intel_connector = intel_dp->attached_connector;
if (intel_dp->hobl_active) {
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
"Link Training failed with HOBL active, not enabling it from now on");
intel_dp->hobl_failed = true;
} else if (intel_dp_get_link_train_fallback_values(intel_dp,
- intel_dp->link_rate,
- intel_dp->lane_count)) {
+ crtc_state->port_clock,
+ crtc_state->lane_count)) {
return;
}
/* Schedule a Hotplug Uevent to userspace to start modeset */
schedule_work(&intel_connector->modeset_retry_work);
}
+
+/* Perform the link training on all LTTPRs and the DPRX on a link. */
+static bool
+intel_dp_link_train_all_phys(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ int lttpr_count)
+{
+ bool ret = true;
+ int i;
+
+ intel_dp_prepare_link_train(intel_dp, crtc_state);
+
+ for (i = lttpr_count - 1; i >= 0; i--) {
+ enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
+
+ ret = intel_dp_link_train_phy(intel_dp, crtc_state, dp_phy);
+ intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
+
+ if (!ret)
+ break;
+ }
+
+ if (ret)
+ intel_dp_link_train_phy(intel_dp, crtc_state, DP_PHY_DPRX);
+
+ if (intel_dp->set_idle_link_train)
+ intel_dp->set_idle_link_train(intel_dp, crtc_state);
+
+ return ret;
+}
+
+/**
+ * intel_dp_start_link_train - start link training
+ * @intel_dp: DP struct
+ * @crtc_state: state for CRTC attached to the encoder
+ *
+ * Start the link training of the @intel_dp port, scheduling a fallback
+ * retraining with reduced link rate/lane parameters if the link training
+ * fails.
+ * After calling this function intel_dp_stop_link_train() must be called.
+ */
+void intel_dp_start_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
+{
+ /*
+ * TODO: Reiniting LTTPRs here won't be needed once proper connector
+ * HW state readout is added.
+ */
+ int lttpr_count = intel_dp_lttpr_init(intel_dp);
+
+ if (!intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count))
+ intel_dp_schedule_fallback_link_training(intel_dp, crtc_state);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 01f1dabbb060..86905aa24db7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -8,11 +8,24 @@
#include <drm/drm_dp_helper.h>
+struct intel_crtc_state;
struct intel_dp;
+int intel_dp_lttpr_init(struct intel_dp *intel_dp);
+
void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
const u8 link_status[DP_LINK_STATUS_SIZE]);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
-void intel_dp_stop_link_train(struct intel_dp *intel_dp);
+void intel_dp_start_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+void intel_dp_stop_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+
+/* Get the TPSx symbol type of the value programmed to DP_TRAINING_PATTERN_SET */
+static inline u8 intel_dp_training_pattern_symbol(u8 pattern)
+{
+ return pattern & ~DP_LINK_SCRAMBLING_DISABLE;
+}
#endif /* __INTEL_DP_LINK_TRAINING_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 64d885539e94..0c8684634fca 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -130,7 +130,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
limits.min_lane_count =
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
- limits.min_bpp = intel_dp_min_bpp(pipe_config);
+ limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format);
/*
* FIXME: If all the streams can't fit into the link with
* their current pipe_bpp we should reduce pipe_bpp across
@@ -318,19 +318,23 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
return ret;
}
-static void clear_act_sent(struct intel_dp *intel_dp)
+static void clear_act_sent(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
- intel_de_write(i915, intel_dp->regs.dp_tp_status,
+ intel_de_write(i915, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_ACT_SENT);
}
-static void wait_for_act_sent(struct intel_dp *intel_dp)
+static void wait_for_act_sent(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+ struct intel_dp *intel_dp = &intel_mst->primary->dp;
- if (intel_de_wait_for_set(i915, intel_dp->regs.dp_tp_status,
+ if (intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_ACT_SENT, 1))
drm_err(&i915->drm, "Timed out waiting for ACT sent\n");
@@ -392,7 +396,7 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
- clear_act_sent(intel_dp);
+ clear_act_sent(encoder, old_crtc_state);
val = intel_de_read(dev_priv,
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder));
@@ -401,7 +405,7 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
val);
- wait_for_act_sent(intel_dp);
+ wait_for_act_sent(encoder, old_crtc_state);
drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
@@ -488,7 +492,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state,
intel_dp->active_mst_links);
if (first_mst_stream)
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true);
@@ -535,7 +539,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder);
- clear_act_sent(intel_dp);
+ clear_act_sent(encoder, pipe_config);
intel_ddi_enable_transcoder_func(encoder, pipe_config);
@@ -549,7 +553,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
drm_dbg_kms(&dev_priv->drm, "active links %d\n",
intel_dp->active_mst_links);
- wait_for_act_sent(intel_dp);
+ wait_for_act_sent(encoder, pipe_config);
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
@@ -587,6 +591,15 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
intel_ddi_get_config(&dig_port->base, pipe_config);
}
+static bool intel_dp_mst_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+ struct intel_digital_port *dig_port = intel_mst->primary;
+
+ return intel_dp_initial_fastset_check(&dig_port->base, crtc_state);
+}
+
static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -701,7 +714,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
return 0;
}
- *status = intel_mode_valid_max_plane_size(dev_priv, mode);
+ *status = intel_mode_valid_max_plane_size(dev_priv, mode, false);
return 0;
}
@@ -893,6 +906,7 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *dig_port, enum pipe
intel_encoder->enable = intel_mst_enable_dp;
intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
intel_encoder->get_config = intel_dp_mst_enc_get_config;
+ intel_encoder->initial_fastset_check = intel_dp_mst_initial_fastset_check;
return intel_mst;
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
index 7910522273b2..514c4a7adffc 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
@@ -644,16 +644,16 @@ bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
return mask;
}
-
void chv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 deemph_reg_value, u32 margin_reg_value,
bool uniq_trans_scale)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum dpio_channel ch = vlv_dig_port_to_channel(dig_port);
- enum pipe pipe = intel_crtc->pipe;
+ enum pipe pipe = crtc->pipe;
u32 val;
int i;
@@ -666,7 +666,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
- if (intel_crtc->config->lane_count > 2) {
+ if (crtc_state->lane_count > 2) {
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
@@ -679,7 +679,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val);
- if (intel_crtc->config->lane_count > 2) {
+ if (crtc_state->lane_count > 2) {
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
@@ -687,7 +687,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
}
/* Program swing deemph */
- for (i = 0; i < intel_crtc->config->lane_count; i++) {
+ for (i = 0; i < crtc_state->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
val &= ~DPIO_SWING_DEEMPH9P5_MASK;
val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT;
@@ -695,7 +695,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
}
/* Program swing margin */
- for (i = 0; i < intel_crtc->config->lane_count; i++) {
+ for (i = 0; i < crtc_state->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
val &= ~DPIO_SWING_MARGIN000_MASK;
@@ -718,7 +718,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
* For now, for this unique transition scale selection, set bit
* 27 for ch0 and ch1.
*/
- for (i = 0; i < intel_crtc->config->lane_count; i++) {
+ for (i = 0; i < crtc_state->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
if (uniq_trans_scale)
val |= DPIO_TX_UNIQ_TRANS_SCALE_EN;
@@ -732,7 +732,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
- if (intel_crtc->config->lane_count > 2) {
+ if (crtc_state->lane_count > 2) {
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
@@ -992,14 +992,15 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder,
}
void vlv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 demph_reg_value, u32 preemph_reg_value,
u32 uniqtranscale_reg_value, u32 tx3_demph)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum dpio_channel port = vlv_dig_port_to_channel(dig_port);
- enum pipe pipe = intel_crtc->pipe;
+ enum pipe pipe = crtc->pipe;
vlv_dpio_get(dev_priv);
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h
index f418aab90b7e..6473440e7457 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h
@@ -32,6 +32,7 @@ void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder);
void chv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 deemph_reg_value, u32 margin_reg_value,
bool uniq_trans_scale);
void chv_data_lane_soft_reset(struct intel_encoder *encoder,
@@ -46,6 +47,7 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state);
void vlv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 demph_reg_value, u32 preemph_reg_value,
u32 uniqtranscale_reg_value, u32 tx3_demph);
void vlv_phy_pre_pll_enable(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index e08684e34078..f6ad257a260e 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -141,7 +141,7 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
"asserting DPLL %s with no DPLL\n", onoff(state)))
return;
- cur_state = pll->info->funcs->get_hw_state(dev_priv, pll, &hw_state);
+ cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state);
I915_STATE_WARN(cur_state != state,
"%s assertion failure (expected %s, current %s)\n",
pll->info->name, onoff(state), onoff(cur_state));
@@ -151,14 +151,14 @@ static i915_reg_t
intel_combo_pll_enable_reg(struct drm_i915_private *i915,
struct intel_shared_dpll *pll)
{
-
- if (IS_ELKHARTLAKE(i915) && (pll->info->id == DPLL_ID_EHL_DPLL4))
+ if (IS_DG1(i915))
+ return DG1_DPLL_ENABLE(pll->info->id);
+ else if (IS_JSL_EHL(i915) && (pll->info->id == DPLL_ID_EHL_DPLL4))
return MG_PLL_ENABLE(0);
return CNL_DPLL_ENABLE(pll->info->id);
-
-
}
+
/**
* intel_prepare_shared_dpll - call a dpll's prepare hook
* @crtc_state: CRTC, and its state, which has a shared dpll
@@ -891,11 +891,12 @@ hsw_ddi_wrpll_get_dpll(struct intel_atomic_state *state,
}
static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int refclk;
int n, p, r;
- u32 wrpll = pll->state.hw_state.wrpll;
+ u32 wrpll = pll_state->wrpll;
switch (wrpll & WRPLL_REF_MASK) {
case WRPLL_REF_SPECIAL_HSW:
@@ -962,7 +963,8 @@ hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state)
}
static int hsw_ddi_lcpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
@@ -1002,11 +1004,12 @@ hsw_ddi_spll_get_dpll(struct intel_atomic_state *state,
}
static int hsw_ddi_spll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
- switch (pll->state.hw_state.spll & SPLL_FREQ_MASK) {
+ switch (pll_state->spll & SPLL_FREQ_MASK) {
case SPLL_FREQ_810MHz:
link_clock = 81000;
break;
@@ -1577,9 +1580,9 @@ static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
}
static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
int ref_clock = i915->dpll.ref_clks.nssc;
u32 p0, p1, p2, dco_freq;
@@ -1602,9 +1605,19 @@ static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
case DPLL_CFGCR2_PDIV_3:
p0 = 3;
break;
+ case DPLL_CFGCR2_PDIV_7_INVALID:
+ /*
+ * Incorrect ASUS-Z170M BIOS setting, the HW seems to ignore bit#0,
+ * handling it the same way as PDIV_7.
+ */
+ drm_dbg_kms(&i915->drm, "Invalid WRPLL PDIV divider value, fixing it.\n");
+ fallthrough;
case DPLL_CFGCR2_PDIV_7:
p0 = 7;
break;
+ default:
+ MISSING_CASE(p0);
+ return 0;
}
switch (p2) {
@@ -1620,6 +1633,9 @@ static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
case DPLL_CFGCR2_KDIV_1:
p2 = 1;
break;
+ default:
+ MISSING_CASE(p2);
+ return 0;
}
dco_freq = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK) *
@@ -1675,12 +1691,12 @@ skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
}
static int skl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
- switch ((pll->state.hw_state.ctrl1 &
- DPLL_CTRL1_LINK_RATE_MASK(0)) >>
+ switch ((pll_state->ctrl1 & DPLL_CTRL1_LINK_RATE_MASK(0)) >>
DPLL_CTRL1_LINK_RATE_SHIFT(0)) {
case DPLL_CTRL1_LINK_RATE_810:
link_clock = 81000;
@@ -1758,16 +1774,17 @@ static bool skl_get_dpll(struct intel_atomic_state *state,
}
static int skl_ddi_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
/*
* ctrl1 register is already shifted for each pll, just use 0 to get
* the internal shift for each field
*/
- if (pll->state.hw_state.ctrl1 & DPLL_CTRL1_HDMI_MODE(0))
- return skl_ddi_wrpll_get_freq(i915, pll);
+ if (pll_state->ctrl1 & DPLL_CTRL1_HDMI_MODE(0))
+ return skl_ddi_wrpll_get_freq(i915, pll, pll_state);
else
- return skl_ddi_lcpll_get_freq(i915, pll);
+ return skl_ddi_lcpll_get_freq(i915, pll, pll_state);
}
static void skl_update_dpll_ref_clks(struct drm_i915_private *i915)
@@ -2205,9 +2222,9 @@ bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
}
static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
struct dpll clock;
clock.m1 = 2;
@@ -2622,11 +2639,25 @@ static bool cnl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
return true;
}
+/*
+ * Display WA #22010492432: ehl, tgl
+ * Program half of the nominal DCO divider fraction value.
+ */
+static bool
+ehl_combo_pll_div_frac_wa_needed(struct drm_i915_private *i915)
+{
+ return ((IS_PLATFORM(i915, INTEL_ELKHARTLAKE) &&
+ IS_JSL_EHL_REVID(i915, EHL_REVID_B0, REVID_FOREVER)) ||
+ IS_TIGERLAKE(i915)) &&
+ i915->dpll.ref_clks.nssc == 38400;
+}
+
static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state,
int ref_clock)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
+ u32 dco_fraction;
u32 p0, p1, p2, dco_freq;
p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
@@ -2669,8 +2700,13 @@ static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) *
ref_clock;
- dco_freq += (((pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
- DPLL_CFGCR0_DCO_FRACTION_SHIFT) * ref_clock) / 0x8000;
+ dco_fraction = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
+ DPLL_CFGCR0_DCO_FRACTION_SHIFT;
+
+ if (ehl_combo_pll_div_frac_wa_needed(dev_priv))
+ dco_fraction *= 2;
+
+ dco_freq += (dco_fraction * ref_clock) / 0x8000;
if (drm_WARN_ON(&dev_priv->drm, p0 == 0 || p1 == 0 || p2 == 0))
return 0;
@@ -2679,9 +2715,11 @@ static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
}
static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- return __cnl_ddi_wrpll_get_freq(i915, pll, i915->dpll.ref_clks.nssc);
+ return __cnl_ddi_wrpll_get_freq(i915, pll, pll_state,
+ i915->dpll.ref_clks.nssc);
}
static bool
@@ -2730,11 +2768,12 @@ cnl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
}
static int cnl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
- switch (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_LINK_RATE_MASK) {
+ switch (pll_state->cfgcr0 & DPLL_CFGCR0_LINK_RATE_MASK) {
case DPLL_CFGCR0_LINK_RATE_810:
link_clock = 81000;
break;
@@ -2817,12 +2856,13 @@ static bool cnl_get_dpll(struct intel_atomic_state *state,
}
static int cnl_ddi_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- if (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_HDMI_MODE)
- return cnl_ddi_wrpll_get_freq(i915, pll);
+ if (pll_state->cfgcr0 & DPLL_CFGCR0_HDMI_MODE)
+ return cnl_ddi_wrpll_get_freq(i915, pll, pll_state);
else
- return cnl_ddi_lcpll_get_freq(i915, pll);
+ return cnl_ddi_lcpll_get_freq(i915, pll, pll_state);
}
static void cnl_update_dpll_ref_clks(struct drm_i915_private *i915)
@@ -2948,16 +2988,6 @@ static const struct skl_wrpll_params tgl_tbt_pll_24MHz_values = {
/* the following params are unused */
};
-/*
- * Display WA #22010492432: tgl
- * Divide the nominal .dco_fraction value by 2.
- */
-static const struct skl_wrpll_params tgl_tbt_pll_38_4MHz_values = {
- .dco_integer = 0x54, .dco_fraction = 0x1800,
- /* the following params are unused */
- .pdiv = 0, .kdiv = 0, .qdiv_mode = 0, .qdiv_ratio = 0,
-};
-
static bool icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
struct skl_wrpll_params *pll_params)
{
@@ -2991,14 +3021,12 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
MISSING_CASE(dev_priv->dpll.ref_clks.nssc);
fallthrough;
case 19200:
+ case 38400:
*pll_params = tgl_tbt_pll_19_2MHz_values;
break;
case 24000:
*pll_params = tgl_tbt_pll_24MHz_values;
break;
- case 38400:
- *pll_params = tgl_tbt_pll_38_4MHz_values;
- break;
}
} else {
switch (dev_priv->dpll.ref_clks.nssc) {
@@ -3019,7 +3047,8 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
}
static int icl_ddi_tbt_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
/*
* The PLL outputs multiple frequencies at the same time, selection is
@@ -3055,9 +3084,10 @@ icl_calc_wrpll(struct intel_crtc_state *crtc_state,
}
static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- return __cnl_ddi_wrpll_get_freq(i915, pll,
+ return __cnl_ddi_wrpll_get_freq(i915, pll, pll_state,
icl_wrpll_ref_clock(i915));
}
@@ -3065,9 +3095,14 @@ static void icl_calc_dpll_state(struct drm_i915_private *i915,
const struct skl_wrpll_params *pll_params,
struct intel_dpll_hw_state *pll_state)
{
+ u32 dco_fraction = pll_params->dco_fraction;
+
memset(pll_state, 0, sizeof(*pll_state));
- pll_state->cfgcr0 = DPLL_CFGCR0_DCO_FRACTION(pll_params->dco_fraction) |
+ if (ehl_combo_pll_div_frac_wa_needed(i915))
+ dco_fraction = DIV_ROUND_CLOSEST(dco_fraction, 2);
+
+ pll_state->cfgcr0 = DPLL_CFGCR0_DCO_FRACTION(dco_fraction) |
pll_params->dco_integer;
pll_state->cfgcr1 = DPLL_CFGCR1_QDIV_RATIO(pll_params->qdiv_ratio) |
@@ -3377,9 +3412,9 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
}
static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
u32 m1, m2_int, m2_frac, div1, div2, ref_clock;
u64 tmp;
@@ -3524,12 +3559,22 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ if (port == PORT_D || port == PORT_E) {
+ dpll_mask =
+ BIT(DPLL_ID_DG1_DPLL2) |
+ BIT(DPLL_ID_DG1_DPLL3);
+ } else {
+ dpll_mask =
+ BIT(DPLL_ID_DG1_DPLL0) |
+ BIT(DPLL_ID_DG1_DPLL1);
+ }
+ } else if (IS_ROCKETLAKE(dev_priv)) {
dpll_mask =
BIT(DPLL_ID_EHL_DPLL4) |
BIT(DPLL_ID_ICL_DPLL1) |
BIT(DPLL_ID_ICL_DPLL0);
- } else if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A) {
+ } else if (IS_JSL_EHL(dev_priv) && port != PORT_A) {
dpll_mask =
BIT(DPLL_ID_EHL_DPLL4) |
BIT(DPLL_ID_ICL_DPLL1) |
@@ -3820,7 +3865,10 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
if (!(val & PLL_ENABLE))
goto out;
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ hw_state->cfgcr0 = intel_de_read(dev_priv, DG1_DPLL_CFGCR0(id));
+ hw_state->cfgcr1 = intel_de_read(dev_priv, DG1_DPLL_CFGCR1(id));
+ } else if (IS_ROCKETLAKE(dev_priv)) {
hw_state->cfgcr0 = intel_de_read(dev_priv,
RKL_DPLL_CFGCR0(id));
hw_state->cfgcr1 = intel_de_read(dev_priv,
@@ -3831,7 +3879,7 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
hw_state->cfgcr1 = intel_de_read(dev_priv,
TGL_DPLL_CFGCR1(id));
} else {
- if (IS_ELKHARTLAKE(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
+ if (IS_JSL_EHL(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
hw_state->cfgcr0 = intel_de_read(dev_priv,
ICL_DPLL_CFGCR0(4));
hw_state->cfgcr1 = intel_de_read(dev_priv,
@@ -3873,14 +3921,17 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv,
const enum intel_dpll_id id = pll->info->id;
i915_reg_t cfgcr0_reg, cfgcr1_reg;
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ cfgcr0_reg = DG1_DPLL_CFGCR0(id);
+ cfgcr1_reg = DG1_DPLL_CFGCR1(id);
+ } else if (IS_ROCKETLAKE(dev_priv)) {
cfgcr0_reg = RKL_DPLL_CFGCR0(id);
cfgcr1_reg = RKL_DPLL_CFGCR1(id);
} else if (INTEL_GEN(dev_priv) >= 12) {
cfgcr0_reg = TGL_DPLL_CFGCR0(id);
cfgcr1_reg = TGL_DPLL_CFGCR1(id);
} else {
- if (IS_ELKHARTLAKE(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
+ if (IS_JSL_EHL(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
cfgcr0_reg = ICL_DPLL_CFGCR0(4);
cfgcr1_reg = ICL_DPLL_CFGCR1(4);
} else {
@@ -4054,7 +4105,7 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv,
{
i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
- if (IS_ELKHARTLAKE(dev_priv) &&
+ if (IS_JSL_EHL(dev_priv) &&
pll->info->id == DPLL_ID_EHL_DPLL4) {
/*
@@ -4167,7 +4218,7 @@ static void combo_pll_disable(struct drm_i915_private *dev_priv,
icl_pll_disable(dev_priv, pll, enable_reg);
- if (IS_ELKHARTLAKE(dev_priv) &&
+ if (IS_JSL_EHL(dev_priv) &&
pll->info->id == DPLL_ID_EHL_DPLL4)
intel_display_power_put(dev_priv, POWER_DOMAIN_DPLL_DC_OFF,
pll->wakeref);
@@ -4317,6 +4368,22 @@ static const struct intel_dpll_mgr rkl_pll_mgr = {
.dump_hw_state = icl_dump_hw_state,
};
+static const struct dpll_info dg1_plls[] = {
+ { "DPLL 0", &combo_pll_funcs, DPLL_ID_DG1_DPLL0, 0 },
+ { "DPLL 1", &combo_pll_funcs, DPLL_ID_DG1_DPLL1, 0 },
+ { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 },
+ { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 },
+ { },
+};
+
+static const struct intel_dpll_mgr dg1_pll_mgr = {
+ .dpll_info = dg1_plls,
+ .get_dplls = icl_get_dplls,
+ .put_dplls = icl_put_dplls,
+ .update_ref_clks = icl_update_dpll_ref_clks,
+ .dump_hw_state = icl_dump_hw_state,
+};
+
/**
* intel_shared_dpll_init - Initialize shared DPLLs
* @dev: drm device
@@ -4330,11 +4397,13 @@ void intel_shared_dpll_init(struct drm_device *dev)
const struct dpll_info *dpll_info;
int i;
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv))
+ dpll_mgr = &dg1_pll_mgr;
+ else if (IS_ROCKETLAKE(dev_priv))
dpll_mgr = &rkl_pll_mgr;
else if (INTEL_GEN(dev_priv) >= 12)
dpll_mgr = &tgl_pll_mgr;
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
dpll_mgr = &ehl_pll_mgr;
else if (INTEL_GEN(dev_priv) >= 11)
dpll_mgr = &icl_pll_mgr;
@@ -4456,16 +4525,33 @@ void intel_update_active_dpll(struct intel_atomic_state *state,
* intel_dpll_get_freq - calculate the DPLL's output frequency
* @i915: i915 device
* @pll: DPLL for which to calculate the output frequency
+ * @pll_state: DPLL state from which to calculate the output frequency
*
- * Return the output frequency corresponding to @pll's current state.
+ * Return the output frequency corresponding to @pll's passed in @pll_state.
*/
int intel_dpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
if (drm_WARN_ON(&i915->drm, !pll->info->funcs->get_freq))
return 0;
- return pll->info->funcs->get_freq(i915, pll);
+ return pll->info->funcs->get_freq(i915, pll, pll_state);
+}
+
+/**
+ * intel_dpll_get_hw_state - readout the DPLL's hardware state
+ * @i915: i915 device
+ * @pll: DPLL for which to calculate the output frequency
+ * @hw_state: DPLL's hardware state
+ *
+ * Read out @pll's hardware state into @hw_state.
+ */
+bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ return pll->info->funcs->get_hw_state(i915, pll, hw_state);
}
static void readout_dpll_hw_state(struct drm_i915_private *i915,
@@ -4473,10 +4559,9 @@ static void readout_dpll_hw_state(struct drm_i915_private *i915,
{
struct intel_crtc *crtc;
- pll->on = pll->info->funcs->get_hw_state(i915, pll,
- &pll->state.hw_state);
+ pll->on = intel_dpll_get_hw_state(i915, pll, &pll->state.hw_state);
- if (IS_ELKHARTLAKE(i915) && pll->on &&
+ if (IS_JSL_EHL(i915) && pll->on &&
pll->info->id == DPLL_ID_EHL_DPLL4) {
pll->wakeref = intel_display_power_get(i915,
POWER_DOMAIN_DPLL_DC_OFF);
@@ -4531,7 +4616,7 @@ void intel_dpll_sanitize_state(struct drm_i915_private *i915)
}
/**
- * intel_shared_dpll_dump_hw_state - write hw_state to dmesg
+ * intel_dpll_dump_hw_state - write hw_state to dmesg
* @dev_priv: i915 drm device
* @hw_state: hw state to be written to the log
*
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index 5d9a2bc371e7..2eb7618ef957 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -154,6 +154,23 @@ enum intel_dpll_id {
* @DPLL_ID_TGL_MGPLL6: TGL TC PLL port 6 (TC6)
*/
DPLL_ID_TGL_MGPLL6 = 8,
+
+ /**
+ * @DPLL_ID_DG1_DPLL0: DG1 combo PHY DPLL0
+ */
+ DPLL_ID_DG1_DPLL0 = 0,
+ /**
+ * @DPLL_ID_DG1_DPLL1: DG1 combo PHY DPLL1
+ */
+ DPLL_ID_DG1_DPLL1 = 1,
+ /**
+ * @DPLL_ID_DG1_DPLL2: DG1 combo PHY DPLL2
+ */
+ DPLL_ID_DG1_DPLL2 = 2,
+ /**
+ * @DPLL_ID_DG1_DPLL3: DG1 combo PHY DPLL3
+ */
+ DPLL_ID_DG1_DPLL3 = 3,
};
#define I915_NUM_PLLS 9
@@ -283,10 +300,11 @@ struct intel_shared_dpll_funcs {
* @get_freq:
*
* Hook for calculating the pll's output frequency based on its
- * current state.
+ * passed in state.
*/
int (*get_freq)(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll);
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state);
};
/**
@@ -382,7 +400,11 @@ void intel_update_active_dpll(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_encoder *encoder);
int intel_dpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll);
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state);
+bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c
index afa4e6817e8c..f453ceb8d149 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi.c
+++ b/drivers/gpu/drm/i915/display/intel_dsi.c
@@ -75,7 +75,7 @@ enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
return MODE_CLOCK_HIGH;
}
- return intel_mode_valid_max_plane_size(dev_priv, mode);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, false);
}
struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h
index 19f78a4022d3..625f2f1ae061 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi.h
+++ b/drivers/gpu/drm/i915/display/intel_dsi.h
@@ -167,6 +167,7 @@ static inline u16 intel_dsi_encoder_ports(struct intel_encoder *encoder)
/* icl_dsi.c */
void icl_dsi_init(struct drm_i915_private *dev_priv);
+void icl_dsi_frame_update(struct intel_crtc_state *crtc_state);
/* intel_dsi.c */
int intel_dsi_bitrate(const struct intel_dsi *intel_dsi);
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 135f5e8a4d70..a5b072816a7b 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -907,6 +907,13 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
return false;
}
+ /* Wa_22010751166: icl, ehl, tgl, dg1, rkl */
+ if (INTEL_GEN(dev_priv) >= 11 &&
+ (cache->plane.src_h + cache->plane.adjusted_y) % 4) {
+ fbc->no_fbc_reason = "plane height + offset is non-modulo of 4";
+ return false;
+ }
+
return true;
}
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index e6b8d6dfb598..b0d71bbbf2ad 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -90,11 +90,20 @@ static const struct gmbus_pin gmbus_pins_icp[] = {
[GMBUS_PIN_14_TC6_TGP] = { "tc6", GPIOO },
};
+static const struct gmbus_pin gmbus_pins_dg1[] = {
+ [GMBUS_PIN_1_BXT] = { "dpa", GPIOB },
+ [GMBUS_PIN_2_BXT] = { "dpb", GPIOC },
+ [GMBUS_PIN_3_BXT] = { "dpc", GPIOD },
+ [GMBUS_PIN_4_CNP] = { "dpd", GPIOE },
+};
+
/* pin is expected to be valid */
static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
unsigned int pin)
{
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ return &gmbus_pins_dg1[pin];
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
return &gmbus_pins_icp[pin];
else if (HAS_PCH_CNP(dev_priv))
return &gmbus_pins_cnp[pin];
@@ -113,7 +122,9 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
{
unsigned int size;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ size = ARRAY_SIZE(gmbus_pins_dg1);
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
size = ARRAY_SIZE(gmbus_pins_icp);
else if (HAS_PCH_CNP(dev_priv))
size = ARRAY_SIZE(gmbus_pins_cnp);
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 5492076d1ae0..b2a4bbcfdcd2 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -1445,10 +1445,9 @@ static int hdcp2_session_key_exchange(struct intel_connector *connector)
}
static
-int hdcp2_propagate_stream_management_info(struct intel_connector *connector)
+int _hdcp2_propagate_stream_management_info(struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
union {
struct hdcp2_rep_stream_manage stream_manage;
@@ -1457,6 +1456,9 @@ int hdcp2_propagate_stream_management_info(struct intel_connector *connector)
const struct intel_hdcp_shim *shim = hdcp->shim;
int ret;
+ if (connector->hdcp.seq_num_m > HDCP_2_2_SEQ_NUM_MAX)
+ return -ERANGE;
+
/* Prepare RepeaterAuth_Stream_Manage msg */
msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE;
drm_hdcp_cpu_to_be24(msgs.stream_manage.seq_num_m, hdcp->seq_num_m);
@@ -1472,28 +1474,21 @@ int hdcp2_propagate_stream_management_info(struct intel_connector *connector)
ret = shim->write_2_2_msg(dig_port, &msgs.stream_manage,
sizeof(msgs.stream_manage));
if (ret < 0)
- return ret;
+ goto out;
ret = shim->read_2_2_msg(dig_port, HDCP_2_2_REP_STREAM_READY,
&msgs.stream_ready, sizeof(msgs.stream_ready));
if (ret < 0)
- return ret;
+ goto out;
hdcp->port_data.seq_num_m = hdcp->seq_num_m;
hdcp->port_data.streams[0].stream_type = hdcp->content_type;
-
ret = hdcp2_verify_mprime(connector, &msgs.stream_ready);
- if (ret < 0)
- return ret;
+out:
hdcp->seq_num_m++;
- if (hdcp->seq_num_m > HDCP_2_2_SEQ_NUM_MAX) {
- drm_dbg_kms(&i915->drm, "seq_num_m roll over.\n");
- return -1;
- }
-
- return 0;
+ return ret;
}
static
@@ -1564,17 +1559,6 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
return 0;
}
-static int hdcp2_authenticate_repeater(struct intel_connector *connector)
-{
- int ret;
-
- ret = hdcp2_authenticate_repeater_topology(connector);
- if (ret < 0)
- return ret;
-
- return hdcp2_propagate_stream_management_info(connector);
-}
-
static int hdcp2_authenticate_sink(struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
@@ -1611,7 +1595,7 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector)
}
if (hdcp->is_repeater) {
- ret = hdcp2_authenticate_repeater(connector);
+ ret = hdcp2_authenticate_repeater_topology(connector);
if (ret < 0) {
drm_dbg_kms(&i915->drm,
"Repeater Auth Failed. Err: %d\n", ret);
@@ -1619,11 +1603,6 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector)
}
}
- hdcp->port_data.streams[0].stream_type = hdcp->content_type;
- ret = hdcp2_authenticate_port(connector);
- if (ret < 0)
- return ret;
-
return ret;
}
@@ -1704,15 +1683,59 @@ static int hdcp2_disable_encryption(struct intel_connector *connector)
return ret;
}
+static int
+hdcp2_propagate_stream_management_info(struct intel_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ int i, tries = 3, ret;
+
+ if (!connector->hdcp.is_repeater)
+ return 0;
+
+ for (i = 0; i < tries; i++) {
+ ret = _hdcp2_propagate_stream_management_info(connector);
+ if (!ret)
+ break;
+
+ /* Lets restart the auth incase of seq_num_m roll over */
+ if (connector->hdcp.seq_num_m > HDCP_2_2_SEQ_NUM_MAX) {
+ drm_dbg_kms(&i915->drm,
+ "seq_num_m roll over.(%d)\n", ret);
+ break;
+ }
+
+ drm_dbg_kms(&i915->drm,
+ "HDCP2 stream management %d of %d Failed.(%d)\n",
+ i + 1, tries, ret);
+ }
+
+ return ret;
+}
+
static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_hdcp *hdcp = &connector->hdcp;
int ret, i, tries = 3;
for (i = 0; i < tries; i++) {
ret = hdcp2_authenticate_sink(connector);
- if (!ret)
- break;
+ if (!ret) {
+ ret = hdcp2_propagate_stream_management_info(connector);
+ if (ret) {
+ drm_dbg_kms(&i915->drm,
+ "Stream management failed.(%d)\n",
+ ret);
+ break;
+ }
+ hdcp->port_data.streams[0].stream_type =
+ hdcp->content_type;
+ ret = hdcp2_authenticate_port(connector);
+ if (!ret)
+ break;
+ drm_dbg_kms(&i915->drm, "HDCP2 port auth failed.(%d)\n",
+ ret);
+ }
/* Clearing the mei hdcp session */
drm_dbg_kms(&i915->drm, "HDCP2.2 Auth %d of %d Failed.(%d)\n",
@@ -1721,7 +1744,7 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
drm_dbg_kms(&i915->drm, "Port deauth failed.\n");
}
- if (i != tries) {
+ if (!ret) {
/*
* Ensuring the required 200mSec min time interval between
* Session Key Exchange and encryption.
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 3f2008d845c2..82674a8853c6 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2274,7 +2274,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
if (status != MODE_OK)
return status;
- return intel_mode_valid_max_plane_size(dev_priv, mode);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, false);
}
bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
@@ -2775,8 +2775,9 @@ static void vlv_hdmi_pre_enable(struct intel_atomic_state *state,
vlv_phy_pre_encoder_enable(encoder, pipe_config);
/* HDMI 1.0V-2dB */
- vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
- 0x2b247878);
+ vlv_set_phy_signal_level(encoder, pipe_config,
+ 0x2b245f5f, 0x00002000,
+ 0x5578b83a, 0x2b247878);
dig_port->set_infoframes(encoder,
pipe_config->has_infoframe,
@@ -2853,7 +2854,7 @@ static void chv_hdmi_pre_enable(struct intel_atomic_state *state,
/* FIXME: Program the support xxx V-dB */
/* Use 800mV-0dB */
- chv_set_phy_signal_level(encoder, 128, 102, false);
+ chv_set_phy_signal_level(encoder, pipe_config, 128, 102, false);
dig_port->set_infoframes(encoder,
pipe_config->has_infoframe,
@@ -3139,6 +3140,11 @@ static u8 rkl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
return GMBUS_PIN_1_BXT + phy;
}
+static u8 dg1_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
+{
+ return intel_port_to_phy(dev_priv, port) + 1;
+}
+
static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv,
enum port port)
{
@@ -3176,7 +3182,9 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder)
return ddc_pin;
}
- if (IS_ROCKETLAKE(dev_priv))
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ ddc_pin = dg1_port_to_ddc_pin(dev_priv, port);
+ else if (IS_ROCKETLAKE(dev_priv))
ddc_pin = rkl_port_to_ddc_pin(dev_priv, port);
else if (HAS_PCH_MCC(dev_priv))
ddc_pin = mcc_port_to_ddc_pin(dev_priv, port);
@@ -3214,7 +3222,7 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
dig_port->set_infoframes = g4x_set_infoframes;
dig_port->infoframes_enabled = g4x_infoframes_enabled;
} else if (HAS_DDI(dev_priv)) {
- if (dig_port->lspcon.active) {
+ if (intel_bios_is_lspcon_present(dev_priv, dig_port->base.port)) {
dig_port->write_infoframe = lspcon_write_infoframe;
dig_port->read_infoframe = lspcon_read_infoframe;
dig_port->set_infoframes = lspcon_set_infoframes;
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index 5c58c1ed6493..f46a1b7190b8 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -213,6 +213,12 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
}
}
+static void intel_hpd_irq_setup(struct drm_i915_private *i915)
+{
+ if (i915->display_irqs_enabled && i915->display.hpd_irq_setup)
+ i915->display.hpd_irq_setup(i915);
+}
+
static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
{
struct drm_i915_private *dev_priv =
@@ -248,8 +254,7 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
dev_priv->hotplug.stats[pin].state = HPD_ENABLED;
}
- if (dev_priv->display_irqs_enabled && dev_priv->display.hpd_irq_setup)
- dev_priv->display.hpd_irq_setup(dev_priv);
+ intel_hpd_irq_setup(dev_priv);
spin_unlock_irq(&dev_priv->irq_lock);
@@ -556,8 +561,8 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
* Disable any IRQs that storms were detected on. Polling enablement
* happens later in our hotplug work.
*/
- if (storm_detected && dev_priv->display_irqs_enabled)
- dev_priv->display.hpd_irq_setup(dev_priv);
+ if (storm_detected)
+ intel_hpd_irq_setup(dev_priv);
spin_unlock(&dev_priv->irq_lock);
/*
@@ -584,7 +589,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
* This is a separate step from interrupt enabling to simplify the locking rules
* in the driver load and resume code.
*
- * Also see: intel_hpd_poll_init(), which enables connector polling
+ * Also see: intel_hpd_poll_enable() and intel_hpd_poll_disable().
*/
void intel_hpd_init(struct drm_i915_private *dev_priv)
{
@@ -595,19 +600,13 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
dev_priv->hotplug.stats[i].state = HPD_ENABLED;
}
- WRITE_ONCE(dev_priv->hotplug.poll_enabled, false);
- schedule_work(&dev_priv->hotplug.poll_init_work);
-
/*
* Interrupt setup is already guaranteed to be single-threaded, this is
* just to make the assert_spin_locked checks happy.
*/
- if (dev_priv->display_irqs_enabled && dev_priv->display.hpd_irq_setup) {
- spin_lock_irq(&dev_priv->irq_lock);
- if (dev_priv->display_irqs_enabled)
- dev_priv->display.hpd_irq_setup(dev_priv);
- spin_unlock_irq(&dev_priv->irq_lock);
- }
+ spin_lock_irq(&dev_priv->irq_lock);
+ intel_hpd_irq_setup(dev_priv);
+ spin_unlock_irq(&dev_priv->irq_lock);
}
static void i915_hpd_poll_init_work(struct work_struct *work)
@@ -654,12 +653,12 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
}
/**
- * intel_hpd_poll_init - enables/disables polling for connectors with hpd
+ * intel_hpd_poll_enable - enable polling for connectors with hpd
* @dev_priv: i915 device instance
*
- * This function enables polling for all connectors, regardless of whether or
- * not they support hotplug detection. Under certain conditions HPD may not be
- * functional. On most Intel GPUs, this happens when we enter runtime suspend.
+ * This function enables polling for all connectors which support HPD.
+ * Under certain conditions HPD may not be functional. On most Intel GPUs,
+ * this happens when we enter runtime suspend.
* On Valleyview and Cherryview systems, this also happens when we shut off all
* of the powerwells.
*
@@ -667,9 +666,9 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
* dev->mode_config.mutex, we do the actual hotplug enabling in a seperate
* worker.
*
- * Also see: intel_hpd_init(), which restores hpd handling.
+ * Also see: intel_hpd_init() and intel_hpd_poll_disable().
*/
-void intel_hpd_poll_init(struct drm_i915_private *dev_priv)
+void intel_hpd_poll_enable(struct drm_i915_private *dev_priv)
{
WRITE_ONCE(dev_priv->hotplug.poll_enabled, true);
@@ -682,6 +681,31 @@ void intel_hpd_poll_init(struct drm_i915_private *dev_priv)
schedule_work(&dev_priv->hotplug.poll_init_work);
}
+/**
+ * intel_hpd_poll_disable - disable polling for connectors with hpd
+ * @dev_priv: i915 device instance
+ *
+ * This function disables polling for all connectors which support HPD.
+ * Under certain conditions HPD may not be functional. On most Intel GPUs,
+ * this happens when we enter runtime suspend.
+ * On Valleyview and Cherryview systems, this also happens when we shut off all
+ * of the powerwells.
+ *
+ * Since this function can get called in contexts where we're already holding
+ * dev->mode_config.mutex, we do the actual hotplug enabling in a seperate
+ * worker.
+ *
+ * Also used during driver init to initialize connector->polled
+ * appropriately for all connectors.
+ *
+ * Also see: intel_hpd_init() and intel_hpd_poll_enable().
+ */
+void intel_hpd_poll_disable(struct drm_i915_private *dev_priv)
+{
+ WRITE_ONCE(dev_priv->hotplug.poll_enabled, false);
+ schedule_work(&dev_priv->hotplug.poll_init_work);
+}
+
void intel_hpd_init_work(struct drm_i915_private *dev_priv)
{
INIT_DELAYED_WORK(&dev_priv->hotplug.hotplug_work,
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h
index a704d7c94d16..b87e95d606e6 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.h
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.h
@@ -14,7 +14,8 @@ struct intel_digital_port;
struct intel_encoder;
enum port;
-void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
+void intel_hpd_poll_enable(struct drm_i915_private *dev_priv);
+void intel_hpd_poll_disable(struct drm_i915_private *dev_priv);
enum intel_hotplug_state intel_encoder_hotplug(struct intel_encoder *encoder,
struct intel_connector *connector);
void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c
index dc1b35559afd..e37d45e531df 100644
--- a/drivers/gpu/drm/i915/display/intel_lspcon.c
+++ b/drivers/gpu/drm/i915/display/intel_lspcon.c
@@ -184,21 +184,6 @@ static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
return true;
}
-void lspcon_ycbcr420_config(struct drm_connector *connector,
- struct intel_crtc_state *crtc_state)
-{
- const struct drm_display_info *info = &connector->display_info;
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
-
- if (drm_mode_is_420_only(info, adjusted_mode) &&
- connector->ycbcr_420_allowed) {
- crtc_state->port_clock /= 2;
- crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
- crtc_state->lspcon_downsampling = true;
- }
-}
-
static bool lspcon_probe(struct intel_lspcon *lspcon)
{
int retry;
@@ -492,14 +477,19 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
return;
}
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
- if (crtc_state->lspcon_downsampling)
- frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
- else
- frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
- } else {
+ /*
+ * Currently there is no interface defined to
+ * check user preference between RGB/YCBCR444
+ * or YCBCR420. So the only possible case for
+ * YCBCR444 usage is driving YCBCR420 output
+ * with LSPCON, when pipe is configured for
+ * YCBCR444 output and LSPCON takes care of
+ * downsampling it.
+ */
+ if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
+ else
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
- }
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
conn_state->connector,
@@ -525,44 +515,17 @@ u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
return 0;
}
-void lspcon_resume(struct intel_lspcon *lspcon)
-{
- enum drm_lspcon_mode expected_mode;
-
- if (lspcon_wake_native_aux_ch(lspcon)) {
- expected_mode = DRM_LSPCON_MODE_PCON;
- lspcon_resume_in_pcon_wa(lspcon);
- } else {
- expected_mode = DRM_LSPCON_MODE_LS;
- }
-
- if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
- return;
-
- if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
- DRM_ERROR("LSPCON resume failed\n");
- else
- DRM_DEBUG_KMS("LSPCON resume success\n");
-}
-
void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
{
lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
}
-bool lspcon_init(struct intel_digital_port *dig_port)
+static bool lspcon_init(struct intel_digital_port *dig_port)
{
struct intel_dp *dp = &dig_port->dp;
struct intel_lspcon *lspcon = &dig_port->lspcon;
- struct drm_device *dev = dig_port->base.base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_connector *connector = &dp->attached_connector->base;
- if (!HAS_LSPCON(dev_priv)) {
- DRM_ERROR("LSPCON is not supported on this platform\n");
- return false;
- }
-
lspcon->active = false;
lspcon->mode = DRM_LSPCON_MODE_INVALID;
@@ -586,3 +549,37 @@ bool lspcon_init(struct intel_digital_port *dig_port)
DRM_DEBUG_KMS("Success: LSPCON init\n");
return true;
}
+
+void lspcon_resume(struct intel_digital_port *dig_port)
+{
+ struct intel_lspcon *lspcon = &dig_port->lspcon;
+ struct drm_device *dev = dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ enum drm_lspcon_mode expected_mode;
+
+ if (!intel_bios_is_lspcon_present(dev_priv, dig_port->base.port))
+ return;
+
+ if (!lspcon->active) {
+ if (!lspcon_init(dig_port)) {
+ DRM_ERROR("LSPCON init failed on port %c\n",
+ port_name(dig_port->base.port));
+ return;
+ }
+ }
+
+ if (lspcon_wake_native_aux_ch(lspcon)) {
+ expected_mode = DRM_LSPCON_MODE_PCON;
+ lspcon_resume_in_pcon_wa(lspcon);
+ } else {
+ expected_mode = DRM_LSPCON_MODE_LS;
+ }
+
+ if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
+ return;
+
+ if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
+ DRM_ERROR("LSPCON resume failed\n");
+ else
+ DRM_DEBUG_KMS("LSPCON resume success\n");
+}
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.h b/drivers/gpu/drm/i915/display/intel_lspcon.h
index 1cffe8a42a08..b03dcb7076d8 100644
--- a/drivers/gpu/drm/i915/display/intel_lspcon.h
+++ b/drivers/gpu/drm/i915/display/intel_lspcon.h
@@ -15,8 +15,7 @@ struct intel_digital_port;
struct intel_encoder;
struct intel_lspcon;
-bool lspcon_init(struct intel_digital_port *dig_port);
-void lspcon_resume(struct intel_lspcon *lspcon);
+void lspcon_resume(struct intel_digital_port *dig_port);
void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
void lspcon_write_infoframe(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
@@ -32,7 +31,5 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
const struct drm_connector_state *conn_state);
u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config);
-void lspcon_ycbcr420_config(struct drm_connector *connector,
- struct intel_crtc_state *crtc_state);
#endif /* __INTEL_LSPCON_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index e65c2de522c3..c6c7c0b9989b 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -371,6 +371,15 @@ static void pch_post_disable_lvds(struct intel_atomic_state *state,
intel_disable_lvds(state, encoder, old_crtc_state, old_conn_state);
}
+static void intel_lvds_shutdown(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (intel_de_wait_for_clear(dev_priv, PP_STATUS(0), PP_CYCLE_DELAY_ACTIVE, 5000))
+ drm_err(&dev_priv->drm,
+ "timed out waiting for panel power cycle delay\n");
+}
+
static enum drm_mode_status
intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
@@ -897,6 +906,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
intel_encoder->get_config = intel_lvds_get_config;
intel_encoder->update_pipe = intel_panel_update_backlight;
+ intel_encoder->shutdown = intel_lvds_shutdown;
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector_attach_encoder(intel_connector, intel_encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
index de995362f428..4f77cf849171 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -1007,12 +1007,8 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
int ret;
ret = swsci(dev_priv, SWSCI_GBDA_PANEL_DETAILS, 0x0, &panel_details);
- if (ret) {
- drm_dbg_kms(&dev_priv->drm,
- "Failed to get panel details from OpRegion (%d)\n",
- ret);
+ if (ret)
return ret;
- }
ret = (panel_details >> 8) & 0xff;
if (ret > 0x10) {
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;
-}
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
index 6a83c8e682e6..0a517978e8af 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -15,6 +15,8 @@ struct intel_crtc_state;
struct intel_dp;
struct intel_crtc;
struct intel_atomic_state;
+struct intel_plane_state;
+struct intel_plane;
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
void intel_psr_init_dpcd(struct intel_dp *intel_dp);
@@ -41,12 +43,12 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp);
int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state,
u32 *out_value);
bool intel_psr_enabled(struct intel_dp *intel_dp);
-void intel_psr_atomic_check(struct drm_connector *connector,
- struct drm_connector_state *old_state,
- struct drm_connector_state *new_state);
-void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp);
-void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
- struct intel_crtc *crtc);
+int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state);
+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);
#endif /* __INTEL_PSR_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 63040cb0d4e1..019a2d6d807a 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -47,6 +47,7 @@
#include "intel_frontbuffer.h"
#include "intel_pm.h"
#include "intel_psr.h"
+#include "intel_dsi.h"
#include "intel_sprite.h"
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
@@ -93,6 +94,9 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
DEFINE_WAIT(wait);
u32 psr_status;
+ if (new_crtc_state->uapi.async_flip)
+ return;
+
vblank_start = adjusted_mode->crtc_vblank_start;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
vblank_start = DIV_ROUND_UP(vblank_start, 2);
@@ -200,8 +204,19 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
ktime_t end_vbl_time = ktime_get();
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ if (new_crtc_state->uapi.async_flip)
+ return;
+
trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end);
+ /*
+ * Incase of mipi dsi command mode, we need to set frame update
+ * request for every commit.
+ */
+ if (INTEL_GEN(dev_priv) >= 11 &&
+ intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI))
+ icl_dsi_frame_update(new_crtc_state);
+
/* We're still in the vblank-evade critical section, this can't race.
* Would be slightly nice to just grab the vblank count and arm the
* event outside of the critical section - the spinlock might spin for a
@@ -393,6 +408,134 @@ static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
return DIV_ROUND_UP(pixel_rate * num, den);
}
+static int skl_plane_max_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ int cpp = fb->format->cpp[color_plane];
+
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case I915_FORMAT_MOD_X_TILED:
+ /*
+ * Validated limit is 4k, but has 5k should
+ * work apart from the following features:
+ * - Ytile (already limited to 4k)
+ * - FP16 (already limited to 4k)
+ * - render compression (already limited to 4k)
+ * - KVMR sprite and cursor (don't care)
+ * - horizontal panning (TODO verify this)
+ * - pipe and plane scaling (TODO verify this)
+ */
+ if (cpp == 8)
+ return 4096;
+ else
+ return 5120;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+ /* FIXME AUX plane? */
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Yf_TILED:
+ if (cpp == 8)
+ return 2048;
+ else
+ return 4096;
+ default:
+ MISSING_CASE(fb->modifier);
+ return 2048;
+ }
+}
+
+static int glk_plane_max_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ int cpp = fb->format->cpp[color_plane];
+
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case I915_FORMAT_MOD_X_TILED:
+ if (cpp == 8)
+ return 4096;
+ else
+ return 5120;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ /* FIXME AUX plane? */
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Yf_TILED:
+ if (cpp == 8)
+ return 2048;
+ else
+ return 5120;
+ default:
+ MISSING_CASE(fb->modifier);
+ return 2048;
+ }
+}
+
+static int icl_plane_min_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ /* Wa_14011264657, Wa_14011050563: gen11+ */
+ switch (fb->format->format) {
+ case DRM_FORMAT_C8:
+ return 18;
+ case DRM_FORMAT_RGB565:
+ return 10;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_XVYU2101010:
+ case DRM_FORMAT_Y212:
+ case DRM_FORMAT_Y216:
+ return 6;
+ case DRM_FORMAT_NV12:
+ return 20;
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ return 12;
+ case DRM_FORMAT_XRGB16161616F:
+ case DRM_FORMAT_XBGR16161616F:
+ case DRM_FORMAT_ARGB16161616F:
+ case DRM_FORMAT_ABGR16161616F:
+ case DRM_FORMAT_XVYU12_16161616:
+ case DRM_FORMAT_XVYU16161616:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+static int icl_plane_max_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ return 5120;
+}
+
+static int skl_plane_max_height(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ return 4096;
+}
+
+static int icl_plane_max_height(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ return 4320;
+}
+
static unsigned int
skl_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
@@ -429,6 +572,7 @@ skl_program_scaler(struct intel_plane *plane,
u16 y_hphase, uv_rgb_hphase;
u16 y_vphase, uv_rgb_vphase;
int hscale, vscale;
+ u32 ps_ctrl;
hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
&plane_state->uapi.dst,
@@ -455,8 +599,13 @@ skl_program_scaler(struct intel_plane *plane,
uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
}
- intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id),
- PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode);
+ ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0);
+ ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode;
+
+ skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0,
+ plane_state->hw.scaling_filter);
+
+ intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl);
intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id),
PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id),
@@ -604,6 +753,29 @@ icl_program_input_csc(struct intel_plane *plane,
}
static void
+skl_plane_async_flip(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);
+ unsigned long irqflags;
+ enum plane_id plane_id = plane->id;
+ enum pipe pipe = plane->pipe;
+ u32 surf_addr = plane_state->color_plane[0].offset;
+ u32 plane_ctl = plane_state->ctl;
+
+ plane_ctl |= skl_plane_ctl_crtc(crtc_state);
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+ intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
+ intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
+ intel_plane_ggtt_offset(plane_state) + surf_addr);
+
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void
skl_program_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
@@ -617,8 +789,6 @@ skl_program_plane(struct intel_plane *plane,
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_plane = intel_main_to_aux_plane(fb, color_plane);
- u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
- u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
u32 x = plane_state->color_plane[color_plane].x;
@@ -626,7 +796,7 @@ skl_program_plane(struct intel_plane *plane,
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u8 alpha = plane_state->hw.alpha >> 8;
- u32 plane_color_ctl = 0;
+ u32 plane_color_ctl = 0, aux_dist = 0;
unsigned long irqflags;
u32 keymsk, keymax;
u32 plane_ctl = plane_state->ctl;
@@ -653,6 +823,13 @@ skl_program_plane(struct intel_plane *plane,
crtc_y = 0;
}
+ if (aux_plane) {
+ aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
+
+ if (INTEL_GEN(dev_priv) < 12)
+ aux_dist |= skl_plane_stride(plane_state, aux_plane);
+ }
+
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride);
@@ -661,8 +838,6 @@ skl_program_plane(struct intel_plane *plane,
intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
(src_h << 16) | src_w);
- if (INTEL_GEN(dev_priv) < 12)
- aux_dist |= aux_stride;
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist);
if (icl_is_hdr_plane(dev_priv, plane_id))
@@ -690,6 +865,9 @@ skl_program_plane(struct intel_plane *plane,
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id),
(plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x);
+ if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi))
+ intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane);
+
/*
* The control register self-arms if the plane was previously
* disabled. Try to make the plane enable atomic by writing
@@ -2009,10 +2187,8 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state,
}
}
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- min_scale, max_scale,
- true, true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ min_scale, max_scale, true);
if (ret)
return ret;
@@ -2067,11 +2243,10 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state,
if (ret)
return ret;
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true, true);
+ 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;
@@ -2278,10 +2453,8 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state,
max_scale = skl_plane_max_scale(dev_priv, fb);
}
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- min_scale, max_scale,
- true, true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ min_scale, max_scale, true);
if (ret)
return ret;
@@ -2842,8 +3015,8 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
- /* Wa_14010477008:tgl[a0..c0],rkl[all] */
- if (IS_ROCKETLAKE(dev_priv) ||
+ /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) ||
IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0))
return false;
@@ -3083,12 +3256,25 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
}
+ if (INTEL_GEN(dev_priv) >= 11) {
+ plane->min_width = icl_plane_min_width;
+ plane->max_width = icl_plane_max_width;
+ plane->max_height = icl_plane_max_height;
+ } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
+ plane->max_width = glk_plane_max_width;
+ plane->max_height = skl_plane_max_height;
+ } else {
+ plane->max_width = skl_plane_max_width;
+ plane->max_height = skl_plane_max_height;
+ }
+
plane->max_stride = skl_plane_max_stride;
plane->update_plane = skl_update_plane;
plane->disable_plane = skl_disable_plane;
plane->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check;
plane->min_cdclk = skl_plane_min_cdclk;
+ plane->async_flip = skl_plane_async_flip;
if (INTEL_GEN(dev_priv) >= 11)
formats = icl_get_plane_formats(dev_priv, pipe,
@@ -3160,6 +3346,11 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
if (INTEL_GEN(dev_priv) >= 12)
drm_plane_enable_fb_damage_clips(&plane->base);
+ if (INTEL_GEN(dev_priv) >= 10)
+ drm_plane_create_scaling_filter_property(&plane->base,
+ BIT(DRM_SCALING_FILTER_DEFAULT) |
+ BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
+
drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
return plane;
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index 8f67aef18b2d..4346bc1a747a 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -228,9 +228,9 @@ static void tc_port_fixup_legacy_flag(struct intel_digital_port *dig_port,
return;
/* If live status mismatches the VBT flag, trust the live status. */
- drm_err(&i915->drm,
- "Port %s: live status %08x mismatches the legacy port flag, fix flag\n",
- dig_port->tc_port_name, live_status_mask);
+ drm_dbg_kms(&i915->drm,
+ "Port %s: live status %08x mismatches the legacy port flag %08x, fixing flag\n",
+ dig_port->tc_port_name, live_status_mask, valid_hpd_mask);
dig_port->tc_legacy_port = !dig_port->tc_legacy_port;
}
@@ -652,7 +652,7 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)
enum port port = dig_port->base.port;
enum tc_port tc_port = intel_port_to_tc(i915, port);
- if (drm_WARN_ON(&i915->drm, tc_port == PORT_TC_NONE))
+ if (drm_WARN_ON(&i915->drm, tc_port == TC_PORT_NONE))
return;
snprintf(dig_port->tc_port_name, sizeof(dig_port->tc_port_name),
diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
index 54bcc6a6947c..49b4b5fca941 100644
--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
@@ -782,7 +782,7 @@ struct lfp_backlight_data_entry {
u8 active_low_pwm:1;
u8 obsolete1:5;
u16 pwm_freq_hz;
- u8 min_brightness;
+ u8 min_brightness; /* Obsolete from 234+ */
u8 obsolete2;
u8 obsolete3;
} __packed;
@@ -792,11 +792,19 @@ struct lfp_backlight_control_method {
u8 controller:4;
} __packed;
+struct lfp_brightness_level {
+ u16 level;
+ u16 reserved;
+} __packed;
+
struct bdb_lfp_backlight_data {
u8 entry_size;
struct lfp_backlight_data_entry data[16];
- u8 level[16];
+ u8 level[16]; /* Obsolete from 234+ */
struct lfp_backlight_control_method backlight_control[16];
+ struct lfp_brightness_level brightness_level[16]; /* 234+ */
+ struct lfp_brightness_level brightness_min_level[16]; /* 234+ */
+ u8 brightness_precision_bits[16]; /* 236+ */
} __packed;
/*
@@ -827,6 +835,7 @@ struct bdb_lfp_power {
u16 lace_enabled_status;
struct agressiveness_profile_entry aggressivenes[16];
u16 hobl; /* 232+ */
+ u16 vrr_feature_enabled; /* 233+ */
} __packed;
/*
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index c5735c365659..e2716a67b281 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -332,11 +332,10 @@ static const struct rc_parameters *get_rc_params(u16 compressed_bpp,
return &rc_parameters[row_index][column_index];
}
-bool intel_dsc_source_support(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state)
{
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum pipe pipe = crtc->pipe;
@@ -490,11 +489,10 @@ intel_dsc_power_domain(const struct intel_crtc_state *crtc_state)
return POWER_DOMAIN_TRANSCODER_VDSC_PW2;
}
-static void intel_dsc_pps_configure(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+static void intel_dsc_pps_configure(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(encoder->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
enum pipe pipe = crtc->pipe;
u32 pps_val = 0;
@@ -503,6 +501,9 @@ static void intel_dsc_pps_configure(struct intel_encoder *encoder,
u8 num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1;
int i = 0;
+ if (crtc_state->bigjoiner)
+ num_vdsc_instances *= 2;
+
/* Populate PICTURE_PARAMETER_SET_0 registers */
pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor <<
DSC_VER_MIN_SHIFT |
@@ -973,55 +974,6 @@ static void intel_dsc_pps_configure(struct intel_encoder *encoder,
}
}
-void intel_dsc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state)
-{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- enum pipe pipe = crtc->pipe;
- enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
- u32 dss_ctl1, dss_ctl2, val;
-
- if (!intel_dsc_source_support(encoder, crtc_state))
- return;
-
- power_domain = intel_dsc_power_domain(crtc_state);
-
- wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
- if (!wakeref)
- return;
-
- if (!is_pipe_dsc(crtc_state)) {
- dss_ctl1 = intel_de_read(dev_priv, DSS_CTL1);
- dss_ctl2 = intel_de_read(dev_priv, DSS_CTL2);
- } else {
- dss_ctl1 = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL1(pipe));
- dss_ctl2 = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL2(pipe));
- }
-
- crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE;
- if (!crtc_state->dsc.compression_enable)
- goto out;
-
- crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) &&
- (dss_ctl1 & JOINER_ENABLE);
-
- /* FIXME: add more state readout as needed */
-
- /* PPS1 */
- if (!is_pipe_dsc(crtc_state))
- val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1);
- else
- val = intel_de_read(dev_priv,
- ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe));
- vdsc_cfg->bits_per_pixel = val;
- crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4;
-out:
- intel_display_power_put(dev_priv, power_domain, wakeref);
-}
-
static void intel_dsc_dsi_pps_write(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
@@ -1060,77 +1012,126 @@ static void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
sizeof(dp_dsc_pps_sdp));
}
+static i915_reg_t dss_ctl1_reg(const struct intel_crtc_state *crtc_state)
+{
+ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+ if (crtc_state->cpu_transcoder == TRANSCODER_EDP)
+ return DSS_CTL1;
+
+ return ICL_PIPE_DSS_CTL1(pipe);
+}
+
+static i915_reg_t dss_ctl2_reg(const struct intel_crtc_state *crtc_state)
+{
+ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+ if (crtc_state->cpu_transcoder == TRANSCODER_EDP)
+ return DSS_CTL2;
+
+ return ICL_PIPE_DSS_CTL2(pipe);
+}
+
void intel_dsc_enable(struct intel_encoder *encoder,
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(encoder->base.dev);
- enum pipe pipe = crtc->pipe;
- i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dss_ctl1_val = 0;
u32 dss_ctl2_val = 0;
if (!crtc_state->dsc.compression_enable)
return;
- /* Enable Power wells for VDSC/joining */
- intel_display_power_get(dev_priv,
- intel_dsc_power_domain(crtc_state));
-
- intel_dsc_pps_configure(encoder, crtc_state);
+ intel_dsc_pps_configure(crtc_state);
- if (encoder->type == INTEL_OUTPUT_DSI)
- intel_dsc_dsi_pps_write(encoder, crtc_state);
- else
- intel_dsc_dp_pps_write(encoder, crtc_state);
-
- if (!is_pipe_dsc(crtc_state)) {
- dss_ctl1_reg = DSS_CTL1;
- dss_ctl2_reg = DSS_CTL2;
- } else {
- dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
- dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+ if (!crtc_state->bigjoiner_slave) {
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
+ intel_dsc_dsi_pps_write(encoder, crtc_state);
+ else
+ intel_dsc_dp_pps_write(encoder, crtc_state);
}
+
dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE;
if (crtc_state->dsc.dsc_split) {
dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
dss_ctl1_val |= JOINER_ENABLE;
}
- intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1_val);
- intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2_val);
+ if (crtc_state->bigjoiner) {
+ dss_ctl1_val |= BIG_JOINER_ENABLE;
+ if (!crtc_state->bigjoiner_slave)
+ dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE;
+ }
+ intel_de_write(dev_priv, dss_ctl1_reg(crtc_state), dss_ctl1_val);
+ intel_de_write(dev_priv, dss_ctl2_reg(crtc_state), dss_ctl2_val);
}
void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
- i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
- u32 dss_ctl1_val = 0, dss_ctl2_val = 0;
if (!old_crtc_state->dsc.compression_enable)
return;
- if (!is_pipe_dsc(old_crtc_state)) {
- dss_ctl1_reg = DSS_CTL1;
- dss_ctl2_reg = DSS_CTL2;
- } else {
- dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
- dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+ intel_de_write(dev_priv, dss_ctl1_reg(old_crtc_state), 0);
+ intel_de_write(dev_priv, dss_ctl2_reg(old_crtc_state), 0);
+}
+
+void intel_dsc_get_config(struct intel_crtc_state *crtc_state)
+{
+ struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+ enum intel_display_power_domain power_domain;
+ intel_wakeref_t wakeref;
+ u32 dss_ctl1, dss_ctl2, val;
+
+ if (!intel_dsc_source_support(crtc_state))
+ return;
+
+ power_domain = intel_dsc_power_domain(crtc_state);
+
+ wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+ if (!wakeref)
+ return;
+
+ dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc_state));
+ dss_ctl2 = intel_de_read(dev_priv, dss_ctl2_reg(crtc_state));
+
+ crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE;
+ if (!crtc_state->dsc.compression_enable)
+ goto out;
+
+ crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) &&
+ (dss_ctl1 & JOINER_ENABLE);
+
+ if (dss_ctl1 & BIG_JOINER_ENABLE) {
+ crtc_state->bigjoiner = true;
+
+ if (!(dss_ctl1 & MASTER_BIG_JOINER_ENABLE)) {
+ crtc_state->bigjoiner_slave = true;
+ if (!WARN_ON(crtc->pipe == PIPE_A))
+ crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe - 1);
+ } else {
+ if (!WARN_ON(INTEL_NUM_PIPES(dev_priv) == crtc->pipe + 1))
+ crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+ }
}
- dss_ctl1_val = intel_de_read(dev_priv, dss_ctl1_reg);
- if (dss_ctl1_val & JOINER_ENABLE)
- dss_ctl1_val &= ~JOINER_ENABLE;
- intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1_val);
-
- dss_ctl2_val = intel_de_read(dev_priv, dss_ctl2_reg);
- if (dss_ctl2_val & LEFT_BRANCH_VDSC_ENABLE ||
- dss_ctl2_val & RIGHT_BRANCH_VDSC_ENABLE)
- dss_ctl2_val &= ~(LEFT_BRANCH_VDSC_ENABLE |
- RIGHT_BRANCH_VDSC_ENABLE);
- intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2_val);
-
- /* Disable Power wells for VDSC/joining */
- intel_display_power_put_unchecked(dev_priv,
- intel_dsc_power_domain(old_crtc_state));
+
+ /* FIXME: add more state readout as needed */
+
+ /* PPS1 */
+ if (!is_pipe_dsc(crtc_state))
+ val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1);
+ else
+ val = intel_de_read(dev_priv,
+ ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe));
+ vdsc_cfg->bits_per_pixel = val;
+ crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4;
+out:
+ intel_display_power_put(dev_priv, power_domain, wakeref);
}
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h
index e56a3254c214..65d301c23580 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.h
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.h
@@ -11,15 +11,13 @@
struct intel_encoder;
struct intel_crtc_state;
-bool intel_dsc_source_support(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state);
+bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state);
void intel_dsc_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
int intel_dsc_compute_params(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config);
-void intel_dsc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state);
+void intel_dsc_get_config(struct intel_crtc_state *crtc_state);
enum intel_display_power_domain
intel_dsc_power_domain(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index 5e5522923b1e..d52f9c177908 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -985,6 +985,13 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state,
intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
}
+static void intel_dsi_shutdown(struct intel_encoder *encoder)
+{
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+
+ intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
+}
+
static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
@@ -1843,6 +1850,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
intel_encoder->get_hw_state = intel_dsi_get_hw_state;
intel_encoder->get_config = intel_dsi_get_config;
intel_encoder->update_pipe = intel_panel_update_backlight;
+ intel_encoder->shutdown = intel_dsi_shutdown;
intel_connector->get_hw_state = intel_connector_get_hw_state;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c
index 272cf3ea68d5..44821d94544f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c
@@ -202,12 +202,6 @@ retry:
if (unlikely(err))
goto out_request;
- if (w->ce->engine->emit_init_breadcrumb) {
- err = w->ce->engine->emit_init_breadcrumb(rq);
- if (unlikely(err))
- goto out_request;
- }
-
/*
* w->dma is already exported via (vma|obj)->resv we need only
* keep track of the GPU activity within this vma/request, and
@@ -217,9 +211,15 @@ retry:
if (err)
goto out_request;
- err = w->ce->engine->emit_bb_start(rq,
- batch->node.start, batch->node.size,
- 0);
+ if (rq->engine->emit_init_breadcrumb) {
+ err = rq->engine->emit_init_breadcrumb(rq);
+ if (unlikely(err))
+ goto out_request;
+ }
+
+ err = rq->engine->emit_bb_start(rq,
+ batch->node.start, batch->node.size,
+ 0);
out_request:
if (unlikely(err)) {
i915_request_set_error_once(rq, err);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
index 8dd295dbe241..0dd477e56573 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -77,14 +77,21 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
i915_gem_object_unpin_pages(obj);
}
-static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
+static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
{
struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
+ void *vaddr;
- return i915_gem_object_pin_map(obj, I915_MAP_WB);
+ vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
+ if (IS_ERR(vaddr))
+ return PTR_ERR(vaddr);
+
+ dma_buf_map_set_vaddr(map, vaddr);
+
+ return 0;
}
-static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
+static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
{
struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index c8421fd9d2dc..00d24000b5e8 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -39,9 +39,18 @@ static struct i915_global_object {
struct kmem_cache *slab_objects;
} global;
+static const struct drm_gem_object_funcs i915_gem_object_funcs;
+
struct drm_i915_gem_object *i915_gem_object_alloc(void)
{
- return kmem_cache_zalloc(global.slab_objects, GFP_KERNEL);
+ struct drm_i915_gem_object *obj;
+
+ obj = kmem_cache_zalloc(global.slab_objects, GFP_KERNEL);
+ if (!obj)
+ return NULL;
+ obj->base.funcs = &i915_gem_object_funcs;
+
+ return obj;
}
void i915_gem_object_free(struct drm_i915_gem_object *obj)
@@ -73,6 +82,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
obj->mm.madv = I915_MADV_WILLNEED;
INIT_RADIX_TREE(&obj->mm.get_page.radix, GFP_KERNEL | __GFP_NOWARN);
mutex_init(&obj->mm.get_page.lock);
+ INIT_RADIX_TREE(&obj->mm.get_dma_page.radix, GFP_KERNEL | __GFP_NOWARN);
+ mutex_init(&obj->mm.get_dma_page.lock);
if (IS_ENABLED(CONFIG_LOCKDEP) && i915_gem_object_is_shrinkable(obj))
i915_gem_shrinker_taints_mutex(to_i915(obj->base.dev),
@@ -101,7 +112,7 @@ void i915_gem_object_set_cache_coherency(struct drm_i915_gem_object *obj,
!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE);
}
-void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
+static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
{
struct drm_i915_gem_object *obj = to_intel_bo(gem);
struct drm_i915_file_private *fpriv = file->driver_priv;
@@ -264,7 +275,7 @@ static void __i915_gem_free_work(struct work_struct *work)
i915_gem_flush_free_objects(i915);
}
-void i915_gem_free_object(struct drm_gem_object *gem_obj)
+static void i915_gem_free_object(struct drm_gem_object *gem_obj)
{
struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
struct drm_i915_private *i915 = to_i915(obj->base.dev);
@@ -403,6 +414,12 @@ int __init i915_global_objects_init(void)
return 0;
}
+static const struct drm_gem_object_funcs i915_gem_object_funcs = {
+ .free = i915_gem_free_object,
+ .close = i915_gem_close_object,
+ .export = i915_gem_prime_export,
+};
+
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/huge_gem_object.c"
#include "selftests/huge_pages.c"
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index d46db8d8f38e..be14486f63a7 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -38,9 +38,6 @@ void __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj,
int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align);
-void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file);
-void i915_gem_free_object(struct drm_gem_object *obj);
-
void i915_gem_flush_free_objects(struct drm_i915_private *i915);
struct sg_table *
@@ -275,8 +272,26 @@ int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
unsigned int tiling, unsigned int stride);
struct scatterlist *
+__i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
+ struct i915_gem_object_page_iter *iter,
+ unsigned int n,
+ unsigned int *offset);
+
+static inline struct scatterlist *
i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
- unsigned int n, unsigned int *offset);
+ unsigned int n,
+ unsigned int *offset)
+{
+ return __i915_gem_object_get_sg(obj, &obj->mm.get_page, n, offset);
+}
+
+static inline struct scatterlist *
+i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj,
+ unsigned int n,
+ unsigned int *offset)
+{
+ return __i915_gem_object_get_sg(obj, &obj->mm.get_dma_page, n, offset);
+}
struct page *
i915_gem_object_get_page(struct drm_i915_gem_object *obj,
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
index d6711caa7f39..e2d9b7e1e152 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -82,6 +82,14 @@ struct i915_mmap_offset {
struct rb_node offset;
};
+struct i915_gem_object_page_iter {
+ struct scatterlist *sg_pos;
+ unsigned int sg_idx; /* in pages, but 32bit eek! */
+
+ struct radix_tree_root radix;
+ struct mutex lock; /* protects this cache */
+};
+
struct drm_i915_gem_object {
struct drm_gem_object base;
@@ -248,13 +256,8 @@ struct drm_i915_gem_object {
I915_SELFTEST_DECLARE(unsigned int page_mask);
- struct i915_gem_object_page_iter {
- struct scatterlist *sg_pos;
- unsigned int sg_idx; /* in pages, but 32bit eek! */
-
- struct radix_tree_root radix;
- struct mutex lock; /* protects this cache */
- } get_page;
+ struct i915_gem_object_page_iter get_page;
+ struct i915_gem_object_page_iter get_dma_page;
/**
* Element within i915->mm.unbound_list or i915->mm.bound_list,
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
index f60ca6dc911f..e2c7b2a7895f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -33,6 +33,8 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
obj->mm.get_page.sg_pos = pages->sgl;
obj->mm.get_page.sg_idx = 0;
+ obj->mm.get_dma_page.sg_pos = pages->sgl;
+ obj->mm.get_dma_page.sg_idx = 0;
obj->mm.pages = pages;
@@ -155,6 +157,8 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj)
rcu_read_lock();
radix_tree_for_each_slot(slot, &obj->mm.get_page.radix, &iter, 0)
radix_tree_delete(&obj->mm.get_page.radix, iter.index);
+ radix_tree_for_each_slot(slot, &obj->mm.get_dma_page.radix, &iter, 0)
+ radix_tree_delete(&obj->mm.get_dma_page.radix, iter.index);
rcu_read_unlock();
}
@@ -438,11 +442,12 @@ void __i915_gem_object_release_map(struct drm_i915_gem_object *obj)
}
struct scatterlist *
-i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
- unsigned int n,
- unsigned int *offset)
+__i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
+ struct i915_gem_object_page_iter *iter,
+ unsigned int n,
+ unsigned int *offset)
{
- struct i915_gem_object_page_iter *iter = &obj->mm.get_page;
+ const bool dma = iter == &obj->mm.get_dma_page;
struct scatterlist *sg;
unsigned int idx, count;
@@ -471,7 +476,7 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
sg = iter->sg_pos;
idx = iter->sg_idx;
- count = __sg_page_count(sg);
+ count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg);
while (idx + count <= n) {
void *entry;
@@ -499,7 +504,7 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
idx += count;
sg = ____sg_next(sg);
- count = __sg_page_count(sg);
+ count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg);
}
scan:
@@ -517,7 +522,7 @@ scan:
while (idx + count <= n) {
idx += count;
sg = ____sg_next(sg);
- count = __sg_page_count(sg);
+ count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg);
}
*offset = n - idx;
@@ -584,7 +589,7 @@ i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
struct scatterlist *sg;
unsigned int offset;
- sg = i915_gem_object_get_sg(obj, n, &offset);
+ sg = i915_gem_object_get_sg_dma(obj, n, &offset);
if (len)
*len = sg_dma_len(sg) - (offset << PAGE_SHIFT);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
index 84b2707d8b17..29bffc6afcc1 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
@@ -497,6 +497,43 @@ static int i915_gem_init_stolen(struct drm_i915_private *i915)
return 0;
}
+static void dbg_poison(struct i915_ggtt *ggtt,
+ dma_addr_t addr, resource_size_t size,
+ u8 x)
+{
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
+ if (!drm_mm_node_allocated(&ggtt->error_capture))
+ return;
+
+ if (ggtt->vm.bind_async_flags & I915_VMA_GLOBAL_BIND)
+ return; /* beware stop_machine() inversion */
+
+ GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
+
+ mutex_lock(&ggtt->error_mutex);
+ while (size) {
+ void __iomem *s;
+
+ ggtt->vm.insert_page(&ggtt->vm, addr,
+ ggtt->error_capture.start,
+ I915_CACHE_NONE, 0);
+ mb();
+
+ s = io_mapping_map_wc(&ggtt->iomap,
+ ggtt->error_capture.start,
+ PAGE_SIZE);
+ memset_io(s, x, PAGE_SIZE);
+ io_mapping_unmap(s);
+
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ mb();
+ ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
+ mutex_unlock(&ggtt->error_mutex);
+#endif
+}
+
static struct sg_table *
i915_pages_create_for_stolen(struct drm_device *dev,
resource_size_t offset, resource_size_t size)
@@ -540,6 +577,11 @@ static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
if (IS_ERR(pages))
return PTR_ERR(pages);
+ dbg_poison(&to_i915(obj->base.dev)->ggtt,
+ sg_dma_address(pages->sgl),
+ sg_dma_len(pages->sgl),
+ POISON_INUSE);
+
__i915_gem_object_set_pages(obj, pages, obj->stolen->size);
return 0;
@@ -549,6 +591,12 @@ static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
/* Should only be called from i915_gem_object_release_stolen() */
+
+ dbg_poison(&to_i915(obj->base.dev)->ggtt,
+ sg_dma_address(pages->sgl),
+ sg_dma_len(pages->sgl),
+ POISON_FREE);
+
sg_free_table(pages);
kfree(pages);
}
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c
index 0845ce1ae37c..b6d43880b0c1 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c
@@ -82,6 +82,7 @@ static int igt_dmabuf_import(void *arg)
struct drm_i915_gem_object *obj;
struct dma_buf *dmabuf;
void *obj_map, *dma_map;
+ struct dma_buf_map map;
u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };
int err, i;
@@ -110,7 +111,8 @@ static int igt_dmabuf_import(void *arg)
goto out_obj;
}
- dma_map = dma_buf_vmap(dmabuf);
+ err = dma_buf_vmap(dmabuf, &map);
+ dma_map = err ? NULL : map.vaddr;
if (!dma_map) {
pr_err("dma_buf_vmap failed\n");
err = -ENOMEM;
@@ -150,7 +152,7 @@ static int igt_dmabuf_import(void *arg)
err = 0;
out_dma_map:
- dma_buf_vunmap(dmabuf, dma_map);
+ dma_buf_vunmap(dmabuf, &map);
out_obj:
i915_gem_object_put(obj);
out_dmabuf:
@@ -163,6 +165,7 @@ static int igt_dmabuf_import_ownership(void *arg)
struct drm_i915_private *i915 = arg;
struct drm_i915_gem_object *obj;
struct dma_buf *dmabuf;
+ struct dma_buf_map map;
void *ptr;
int err;
@@ -170,7 +173,8 @@ static int igt_dmabuf_import_ownership(void *arg)
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
- ptr = dma_buf_vmap(dmabuf);
+ err = dma_buf_vmap(dmabuf, &map);
+ ptr = err ? NULL : map.vaddr;
if (!ptr) {
pr_err("dma_buf_vmap failed\n");
err = -ENOMEM;
@@ -178,7 +182,7 @@ static int igt_dmabuf_import_ownership(void *arg)
}
memset(ptr, 0xc5, PAGE_SIZE);
- dma_buf_vunmap(dmabuf, ptr);
+ dma_buf_vunmap(dmabuf, &map);
obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
if (IS_ERR(obj)) {
@@ -212,6 +216,7 @@ static int igt_dmabuf_export_vmap(void *arg)
struct drm_i915_private *i915 = arg;
struct drm_i915_gem_object *obj;
struct dma_buf *dmabuf;
+ struct dma_buf_map map;
void *ptr;
int err;
@@ -228,7 +233,8 @@ static int igt_dmabuf_export_vmap(void *arg)
}
i915_gem_object_put(obj);
- ptr = dma_buf_vmap(dmabuf);
+ err = dma_buf_vmap(dmabuf, &map);
+ ptr = err ? NULL : map.vaddr;
if (!ptr) {
pr_err("dma_buf_vmap failed\n");
err = -ENOMEM;
@@ -244,7 +250,7 @@ static int igt_dmabuf_export_vmap(void *arg)
memset(ptr, 0xc5, dmabuf->size);
err = 0;
- dma_buf_vunmap(dmabuf, ptr);
+ dma_buf_vunmap(dmabuf, &map);
out:
dma_buf_put(dmabuf);
return err;
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
index be30b27e2926..2855d11c7a51 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
@@ -61,18 +61,24 @@ static void mock_dmabuf_release(struct dma_buf *dma_buf)
kfree(mock);
}
-static void *mock_dmabuf_vmap(struct dma_buf *dma_buf)
+static int mock_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
{
struct mock_dmabuf *mock = to_mock(dma_buf);
+ void *vaddr;
- return vm_map_ram(mock->pages, mock->npages, 0);
+ vaddr = vm_map_ram(mock->pages, mock->npages, 0);
+ if (!vaddr)
+ return -ENOMEM;
+ dma_buf_map_set_vaddr(map, vaddr);
+
+ return 0;
}
-static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
+static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
{
struct mock_dmabuf *mock = to_mock(dma_buf);
- vm_unmap_ram(vaddr, mock->npages);
+ vm_unmap_ram(map->vaddr, mock->npages);
}
static int mock_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
index c30adc05fa98..680bd9442eb0 100644
--- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
@@ -131,17 +131,17 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
vaddr = kmap_atomic_px(i915_pt_entry(pd, act_pt));
do {
- GEM_BUG_ON(iter.sg->length < I915_GTT_PAGE_SIZE);
+ GEM_BUG_ON(sg_dma_len(iter.sg) < I915_GTT_PAGE_SIZE);
vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma);
iter.dma += I915_GTT_PAGE_SIZE;
if (iter.dma == iter.max) {
iter.sg = __sg_next(iter.sg);
- if (!iter.sg)
+ if (!iter.sg || sg_dma_len(iter.sg) == 0)
break;
iter.dma = sg_dma_address(iter.sg);
- iter.max = iter.dma + iter.sg->length;
+ iter.max = iter.dma + sg_dma_len(iter.sg);
}
if (++act_pte == GEN6_PTES) {
diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
index 38c7069b7749..a37c968ef8f7 100644
--- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
@@ -372,19 +372,19 @@ gen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt,
pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2));
vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
do {
- GEM_BUG_ON(iter->sg->length < I915_GTT_PAGE_SIZE);
+ GEM_BUG_ON(sg_dma_len(iter->sg) < I915_GTT_PAGE_SIZE);
vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma;
iter->dma += I915_GTT_PAGE_SIZE;
if (iter->dma >= iter->max) {
iter->sg = __sg_next(iter->sg);
- if (!iter->sg) {
+ if (!iter->sg || sg_dma_len(iter->sg) == 0) {
idx = 0;
break;
}
iter->dma = sg_dma_address(iter->sg);
- iter->max = iter->dma + iter->sg->length;
+ iter->max = iter->dma + sg_dma_len(iter->sg);
}
if (gen8_pd_index(++idx, 0) == 0) {
@@ -413,8 +413,8 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
u32 flags)
{
const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags);
+ unsigned int rem = sg_dma_len(iter->sg);
u64 start = vma->node.start;
- dma_addr_t rem = iter->sg->length;
GEM_BUG_ON(!i915_vm_is_4lvl(vma->vm));
@@ -456,7 +456,7 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
}
do {
- GEM_BUG_ON(iter->sg->length < page_size);
+ GEM_BUG_ON(sg_dma_len(iter->sg) < page_size);
vaddr[index++] = encode | iter->dma;
start += page_size;
@@ -467,7 +467,10 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
if (!iter->sg)
break;
- rem = iter->sg->length;
+ rem = sg_dma_len(iter->sg);
+ if (!rem)
+ break;
+
iter->dma = sg_dma_address(iter->sg);
iter->max = iter->dma + rem;
@@ -525,7 +528,7 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
}
vma->page_sizes.gtt |= page_size;
- } while (iter->sg);
+ } while (iter->sg && sg_dma_len(iter->sg));
}
static void gen8_ppgtt_insert(struct i915_address_space *vm,
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index efdeb7b7b2a0..0b31670343f5 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -305,8 +305,9 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id)
engine->i915 = i915;
engine->gt = gt;
engine->uncore = gt->uncore;
- engine->hw_id = engine->guc_id = info->hw_id;
engine->mmio_base = __engine_mmio_base(i915, info->mmio_bases);
+ engine->hw_id = info->hw_id;
+ engine->guc_id = MAKE_GUC_ID(info->class, info->instance);
engine->class = info->class;
engine->instance = info->instance;
@@ -1600,6 +1601,41 @@ static unsigned long list_count(struct list_head *list)
return count;
}
+static unsigned long read_ul(void *p, size_t x)
+{
+ return *(unsigned long *)(p + x);
+}
+
+static void print_properties(struct intel_engine_cs *engine,
+ struct drm_printer *m)
+{
+ static const struct pmap {
+ size_t offset;
+ const char *name;
+ } props[] = {
+#define P(x) { \
+ .offset = offsetof(typeof(engine->props), x), \
+ .name = #x \
+}
+ P(heartbeat_interval_ms),
+ P(max_busywait_duration_ns),
+ P(preempt_timeout_ms),
+ P(stop_timeout_ms),
+ P(timeslice_duration_ms),
+
+ {},
+#undef P
+ };
+ const struct pmap *p;
+
+ drm_printf(m, "\tProperties:\n");
+ for (p = props; p->name; p++)
+ drm_printf(m, "\t\t%s: %lu [default %lu]\n",
+ p->name,
+ read_ul(&engine->props, p->offset),
+ read_ul(&engine->defaults, p->offset));
+}
+
void intel_engine_dump(struct intel_engine_cs *engine,
struct drm_printer *m,
const char *header, ...)
@@ -1642,6 +1678,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
drm_printf(m, "\tReset count: %d (global %d)\n",
i915_reset_engine_count(error, engine),
i915_reset_count(error));
+ print_properties(engine, m);
drm_printf(m, "\tRequests:\n");
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
index 5067d0524d4b..9060385cd69e 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
@@ -41,6 +41,8 @@ static void idle_pulse(struct intel_engine_cs *engine, struct i915_request *rq)
{
engine->wakeref_serial = READ_ONCE(engine->serial) + 1;
i915_request_add_active_barriers(rq);
+ if (!engine->heartbeat.systole && intel_engine_has_heartbeat(engine))
+ engine->heartbeat.systole = i915_request_get(rq);
}
static void show_heartbeat(const struct i915_request *rq,
@@ -144,8 +146,6 @@ static void heartbeat(struct work_struct *wrk)
goto unlock;
idle_pulse(engine, rq);
- if (engine->i915->params.enable_hangcheck)
- engine->heartbeat.systole = i915_request_get(rq);
__i915_request_commit(rq);
__i915_request_queue(rq, &attr);
@@ -153,7 +153,7 @@ static void heartbeat(struct work_struct *wrk)
unlock:
mutex_unlock(&ce->timeline->mutex);
out:
- if (!next_heartbeat(engine))
+ if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine))
i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
intel_engine_pm_put(engine);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
index f7b2e07e2229..499b09cb4acf 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
@@ -17,6 +17,25 @@
#include "intel_ring.h"
#include "shmem_utils.h"
+static void dbg_poison_ce(struct intel_context *ce)
+{
+ if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
+ return;
+
+ if (ce->state) {
+ struct drm_i915_gem_object *obj = ce->state->obj;
+ int type = i915_coherent_map_type(ce->engine->i915);
+ void *map;
+
+ map = i915_gem_object_pin_map(obj, type);
+ if (!IS_ERR(map)) {
+ memset(map, CONTEXT_REDZONE, obj->base.size);
+ i915_gem_object_flush_map(obj);
+ i915_gem_object_unpin_map(obj);
+ }
+ }
+}
+
static int __engine_unpark(struct intel_wakeref *wf)
{
struct intel_engine_cs *engine =
@@ -32,20 +51,14 @@ static int __engine_unpark(struct intel_wakeref *wf)
if (ce) {
GEM_BUG_ON(test_bit(CONTEXT_VALID_BIT, &ce->flags));
+ /* Flush all pending HW writes before we touch the context */
+ while (unlikely(intel_context_inflight(ce)))
+ intel_engine_flush_submission(engine);
+
/* First poison the image to verify we never fully trust it */
- if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && ce->state) {
- struct drm_i915_gem_object *obj = ce->state->obj;
- int type = i915_coherent_map_type(engine->i915);
- void *map;
-
- map = i915_gem_object_pin_map(obj, type);
- if (!IS_ERR(map)) {
- memset(map, CONTEXT_REDZONE, obj->base.size);
- i915_gem_object_flush_map(obj);
- i915_gem_object_unpin_map(obj);
- }
- }
+ dbg_poison_ce(ce);
+ /* Scrub the context image after our loss of control */
ce->ops->reset(ce);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 81c05f551b9c..cf94525be2c1 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -835,7 +835,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
u16 snb_gmch_ctl;
/* TODO: We're not aware of mappable constraints on gen8 yet */
- if (!IS_DGFX(i915)) {
+ if (!HAS_LMEM(i915)) {
ggtt->gmadr = pci_resource(pdev, 2);
ggtt->mappable_end = resource_size(&ggtt->gmadr);
}
@@ -1383,7 +1383,7 @@ intel_partial_pages(const struct i915_ggtt_view *view,
if (ret)
goto err_sg_alloc;
- iter = i915_gem_object_get_sg(obj, view->partial.offset, &offset);
+ iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset);
GEM_BUG_ON(!iter);
sg = st->sgl;
@@ -1391,7 +1391,7 @@ intel_partial_pages(const struct i915_ggtt_view *view,
do {
unsigned int len;
- len = min(iter->length - (offset << PAGE_SHIFT),
+ len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT),
count << PAGE_SHIFT);
sg_set_page(sg, NULL, len, 0);
sg_dma_address(sg) =
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
index 39b428c5049c..44f1d51e5ae5 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -614,6 +614,8 @@ void intel_gt_driver_remove(struct intel_gt *gt)
void intel_gt_driver_unregister(struct intel_gt *gt)
{
+ intel_wakeref_t wakeref;
+
intel_rps_driver_unregister(&gt->rps);
/*
@@ -622,16 +624,15 @@ void intel_gt_driver_unregister(struct intel_gt *gt)
* resources.
*/
intel_gt_set_wedged(gt);
+
+ /* Scrub all HW state upon release */
+ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+ __intel_gt_reset(gt, ALL_ENGINES);
}
void intel_gt_driver_release(struct intel_gt *gt)
{
struct i915_address_space *vm;
- intel_wakeref_t wakeref;
-
- /* Scrub all HW state upon release */
- with_intel_runtime_pm(gt->uncore->rpm, wakeref)
- __intel_gt_reset(gt, ALL_ENGINES);
vm = fetch_and_zero(&gt->vm);
if (vm) /* FIXME being called twice on error paths :( */
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 3f1114b58b01..7bfe9072be9a 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -324,7 +324,7 @@ static void cnl_setup_private_ppat(struct intel_uncore *uncore)
GEN8_PPAT_WC | GEN8_PPAT_LLCELLC);
intel_uncore_write(uncore,
GEN10_PAT_INDEX(2),
- GEN8_PPAT_WT | GEN8_PPAT_LLCELLC);
+ GEN8_PPAT_WB | GEN8_PPAT_ELLC_OVERRIDE);
intel_uncore_write(uncore,
GEN10_PAT_INDEX(3),
GEN8_PPAT_UC);
@@ -349,17 +349,23 @@ static void cnl_setup_private_ppat(struct intel_uncore *uncore)
*/
static void bdw_setup_private_ppat(struct intel_uncore *uncore)
{
+ struct drm_i915_private *i915 = uncore->i915;
u64 pat;
pat = GEN8_PPAT(0, GEN8_PPAT_WB | GEN8_PPAT_LLC) | /* for normal objects, no eLLC */
GEN8_PPAT(1, GEN8_PPAT_WC | GEN8_PPAT_LLCELLC) | /* for something pointing to ptes? */
- GEN8_PPAT(2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC) | /* for scanout with eLLC */
GEN8_PPAT(3, GEN8_PPAT_UC) | /* Uncached objects, mostly for scanout */
GEN8_PPAT(4, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(0)) |
GEN8_PPAT(5, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(1)) |
GEN8_PPAT(6, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(2)) |
GEN8_PPAT(7, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3));
+ /* for scanout with eLLC */
+ if (INTEL_GEN(i915) >= 9)
+ pat |= GEN8_PPAT(2, GEN8_PPAT_WB | GEN8_PPAT_ELLC_OVERRIDE);
+ else
+ pat |= GEN8_PPAT(2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC);
+
intel_uncore_write(uncore, GEN8_PRIVATE_PAT_LO, lower_32_bits(pat));
intel_uncore_write(uncore, GEN8_PRIVATE_PAT_HI, upper_32_bits(pat));
}
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index c13c650ced22..8a33940a71f3 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -580,7 +580,7 @@ static inline struct sgt_dma {
struct scatterlist *sg = vma->pages->sgl;
dma_addr_t addr = sg_dma_address(sg);
- return (struct sgt_dma){ sg, addr, addr + sg->length };
+ return (struct sgt_dma){ sg, addr, addr + sg_dma_len(sg) };
}
#endif
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index 724b2cb897d3..7614a3d24fca 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -1216,7 +1216,8 @@ static void intel_engine_context_out(struct intel_engine_cs *engine)
static void
execlists_check_context(const struct intel_context *ce,
- const struct intel_engine_cs *engine)
+ const struct intel_engine_cs *engine,
+ const char *when)
{
const struct intel_ring *ring = ce->ring;
u32 *regs = ce->lrc_reg_state;
@@ -1251,7 +1252,7 @@ execlists_check_context(const struct intel_context *ce,
valid = false;
}
- WARN_ONCE(!valid, "Invalid lrc state found before submission\n");
+ WARN_ONCE(!valid, "Invalid lrc state found %s submission\n", when);
}
static void restore_default_state(struct intel_context *ce,
@@ -1347,7 +1348,7 @@ __execlists_schedule_in(struct i915_request *rq)
reset_active(rq, engine);
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
- execlists_check_context(ce, engine);
+ execlists_check_context(ce, engine, "before");
if (ce->tag) {
/* Use a fixed tag for OA and friends */
@@ -1418,6 +1419,9 @@ __execlists_schedule_out(struct i915_request *rq,
* refrain from doing non-trivial work here.
*/
+ if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
+ execlists_check_context(ce, engine, "after");
+
/*
* If we have just completed this context, the engine may now be
* idle and we want to re-enter powersaving.
@@ -2496,25 +2500,11 @@ invalidate_csb_entries(const u64 *first, const u64 *last)
* bits 47-57: sw context id of the lrc the GT switched away from
* bits 58-63: sw counter of the lrc the GT switched away from
*/
-static inline bool gen12_csb_parse(const u64 *csb)
+static inline bool gen12_csb_parse(const u64 csb)
{
- bool ctx_away_valid;
- bool new_queue;
- u64 entry;
-
- /* HSD#22011248461 */
- entry = READ_ONCE(*csb);
- if (unlikely(entry == -1)) {
- preempt_disable();
- if (wait_for_atomic_us((entry = READ_ONCE(*csb)) != -1, 50))
- GEM_WARN_ON("50us CSB timeout");
- preempt_enable();
- }
- WRITE_ONCE(*(u64 *)csb, -1);
-
- ctx_away_valid = GEN12_CSB_CTX_VALID(upper_32_bits(entry));
- new_queue =
- lower_32_bits(entry) & GEN12_CTX_STATUS_SWITCHED_TO_NEW_QUEUE;
+ bool ctx_away_valid = GEN12_CSB_CTX_VALID(upper_32_bits(csb));
+ bool new_queue =
+ lower_32_bits(csb) & GEN12_CTX_STATUS_SWITCHED_TO_NEW_QUEUE;
/*
* The context switch detail is not guaranteed to be 5 when a preemption
@@ -2524,7 +2514,7 @@ static inline bool gen12_csb_parse(const u64 *csb)
* would require some extra handling, but we don't support that.
*/
if (!ctx_away_valid || new_queue) {
- GEM_BUG_ON(!GEN12_CSB_CTX_VALID(lower_32_bits(entry)));
+ GEM_BUG_ON(!GEN12_CSB_CTX_VALID(lower_32_bits(csb)));
return true;
}
@@ -2533,19 +2523,79 @@ static inline bool gen12_csb_parse(const u64 *csb)
* context switch on an unsuccessful wait instruction since we always
* use polling mode.
*/
- GEM_BUG_ON(GEN12_CTX_SWITCH_DETAIL(upper_32_bits(entry)));
+ GEM_BUG_ON(GEN12_CTX_SWITCH_DETAIL(upper_32_bits(csb)));
return false;
}
-static inline bool gen8_csb_parse(const u64 *csb)
+static inline bool gen8_csb_parse(const u64 csb)
+{
+ return csb & (GEN8_CTX_STATUS_IDLE_ACTIVE | GEN8_CTX_STATUS_PREEMPTED);
+}
+
+static noinline u64
+wa_csb_read(const struct intel_engine_cs *engine, u64 * const csb)
{
- return *csb & (GEN8_CTX_STATUS_IDLE_ACTIVE | GEN8_CTX_STATUS_PREEMPTED);
+ u64 entry;
+
+ /*
+ * Reading from the HWSP has one particular advantage: we can detect
+ * a stale entry. Since the write into HWSP is broken, we have no reason
+ * to trust the HW at all, the mmio entry may equally be unordered, so
+ * we prefer the path that is self-checking and as a last resort,
+ * return the mmio value.
+ *
+ * tgl,dg1:HSDES#22011327657
+ */
+ preempt_disable();
+ if (wait_for_atomic_us((entry = READ_ONCE(*csb)) != -1, 10)) {
+ int idx = csb - engine->execlists.csb_status;
+ int status;
+
+ status = GEN8_EXECLISTS_STATUS_BUF;
+ if (idx >= 6) {
+ status = GEN11_EXECLISTS_STATUS_BUF2;
+ idx -= 6;
+ }
+ status += sizeof(u64) * idx;
+
+ entry = intel_uncore_read64(engine->uncore,
+ _MMIO(engine->mmio_base + status));
+ }
+ preempt_enable();
+
+ return entry;
+}
+
+static inline u64
+csb_read(const struct intel_engine_cs *engine, u64 * const csb)
+{
+ u64 entry = READ_ONCE(*csb);
+
+ /*
+ * Unfortunately, the GPU does not always serialise its write
+ * of the CSB entries before its write of the CSB pointer, at least
+ * from the perspective of the CPU, using what is known as a Global
+ * Observation Point. We may read a new CSB tail pointer, but then
+ * read the stale CSB entries, causing us to misinterpret the
+ * context-switch events, and eventually declare the GPU hung.
+ *
+ * icl:HSDES#1806554093
+ * tgl:HSDES#22011248461
+ */
+ if (unlikely(entry == -1))
+ entry = wa_csb_read(engine, csb);
+
+ /* Consume this entry so that we can spot its future reuse. */
+ WRITE_ONCE(*csb, -1);
+
+ /* ELSP is an implicit wmb() before the GPU wraps and overwrites csb */
+ return entry;
}
static void process_csb(struct intel_engine_cs *engine)
{
struct intel_engine_execlists * const execlists = &engine->execlists;
- const u64 * const buf = execlists->csb_status;
+ u64 * const buf = execlists->csb_status;
const u8 num_entries = execlists->csb_size;
u8 head, tail;
@@ -2603,6 +2653,7 @@ static void process_csb(struct intel_engine_cs *engine)
rmb();
do {
bool promote;
+ u64 csb;
if (++head == num_entries)
head = 0;
@@ -2625,15 +2676,14 @@ static void process_csb(struct intel_engine_cs *engine)
* status notifier.
*/
+ csb = csb_read(engine, buf + head);
ENGINE_TRACE(engine, "csb[%d]: status=0x%08x:0x%08x\n",
- head,
- upper_32_bits(buf[head]),
- lower_32_bits(buf[head]));
+ head, upper_32_bits(csb), lower_32_bits(csb));
if (INTEL_GEN(engine->i915) >= 12)
- promote = gen12_csb_parse(buf + head);
+ promote = gen12_csb_parse(csb);
else
- promote = gen8_csb_parse(buf + head);
+ promote = gen8_csb_parse(csb);
if (promote) {
struct i915_request * const *old = execlists->active;
@@ -2991,6 +3041,8 @@ static struct execlists_capture *capture_regs(struct intel_engine_cs *engine)
if (!cap->error->gt->engine)
goto err_gt;
+ cap->error->gt->engine->hung = true;
+
return cap;
err_gt:
@@ -4053,6 +4105,8 @@ static void reset_csb_pointers(struct intel_engine_cs *engine)
static void execlists_sanitize(struct intel_engine_cs *engine)
{
+ GEM_BUG_ON(execlists_active(&engine->execlists));
+
/*
* Poison residual state on resume, in case the suspend didn't!
*
@@ -4382,6 +4436,7 @@ static void execlists_reset_cancel(struct intel_engine_cs *engine)
/* Mark all executing requests as skipped. */
list_for_each_entry(rq, &engine->active.requests, sched.link)
mark_eio(rq);
+ intel_engine_signal_breadcrumbs(engine);
/* Flush the queued requests to the timeline list (for retiring). */
while ((rb = rb_first_cached(&execlists->queue))) {
@@ -5974,18 +6029,6 @@ int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
return 0;
}
-struct intel_engine_cs *
-intel_virtual_engine_get_sibling(struct intel_engine_cs *engine,
- unsigned int sibling)
-{
- struct virtual_engine *ve = to_virtual_engine(engine);
-
- if (sibling >= ve->num_siblings)
- return NULL;
-
- return ve->siblings[sibling];
-}
-
void intel_execlists_show_requests(struct intel_engine_cs *engine,
struct drm_printer *m,
void (*show_request)(struct drm_printer *m,
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.h b/drivers/gpu/drm/i915/gt/intel_lrc.h
index 91fd8e452d9b..c2d287f25497 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.h
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.h
@@ -121,10 +121,6 @@ int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
const struct intel_engine_cs *master,
const struct intel_engine_cs *sibling);
-struct intel_engine_cs *
-intel_virtual_engine_get_sibling(struct intel_engine_cs *engine,
- unsigned int sibling);
-
bool
intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine);
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc_reg.h b/drivers/gpu/drm/i915/gt/intel_lrc_reg.h
index 93cb6c460508..1b51f7b9a5c3 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc_reg.h
+++ b/drivers/gpu/drm/i915/gt/intel_lrc_reg.h
@@ -49,4 +49,7 @@
#define GEN11_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x1A
#define GEN12_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0xD
+#define GEN8_EXECLISTS_STATUS_BUF 0x370
+#define GEN11_EXECLISTS_STATUS_BUF2 0x3c0
+
#endif /* _INTEL_LRC_REG_H_ */
diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c
index 413dadfac2d1..ab6870242e18 100644
--- a/drivers/gpu/drm/i915/gt/intel_mocs.c
+++ b/drivers/gpu/drm/i915/gt/intel_mocs.c
@@ -108,7 +108,7 @@ struct drm_i915_mocs_table {
* they will be initialized to PTE. Gen >= 12 onwards don't have a setting for
* PTE and will be initialized to an invalid value.
*
- * The last two entries are reserved by the hardware. For ICL+ they
+ * The last few entries are reserved by the hardware. For ICL+ they
* should be initialized according to bspec and never used, for older
* platforms they should never be written to.
*
@@ -123,7 +123,7 @@ struct drm_i915_mocs_table {
LE_1_UC | LE_TC_2_LLC_ELLC, \
L3_1_UC), \
MOCS_ENTRY(I915_MOCS_PTE, \
- LE_0_PAGETABLE | LE_TC_2_LLC_ELLC | LE_LRUM(3), \
+ LE_0_PAGETABLE | LE_TC_0_PAGETABLE | LE_LRUM(3), \
L3_3_WB)
static const struct drm_i915_mocs_entry skl_mocs_table[] = {
@@ -292,12 +292,45 @@ static const struct drm_i915_mocs_entry icl_mocs_table[] = {
L3_1_UC),
/* Base - L3 + LeCC:PAT (Deprecated) */
MOCS_ENTRY(I915_MOCS_PTE,
- LE_0_PAGETABLE | LE_TC_1_LLC,
+ LE_0_PAGETABLE | LE_TC_0_PAGETABLE,
L3_3_WB),
GEN11_MOCS_ENTRIES
};
+static const struct drm_i915_mocs_entry dg1_mocs_table[] = {
+ /* Error */
+ MOCS_ENTRY(0, 0, L3_0_DIRECT),
+
+ /* UC */
+ MOCS_ENTRY(1, 0, L3_1_UC),
+
+ /* Reserved */
+ MOCS_ENTRY(2, 0, L3_0_DIRECT),
+ MOCS_ENTRY(3, 0, L3_0_DIRECT),
+ MOCS_ENTRY(4, 0, L3_0_DIRECT),
+
+ /* WB - L3 */
+ MOCS_ENTRY(5, 0, L3_3_WB),
+ /* WB - L3 50% */
+ MOCS_ENTRY(6, 0, L3_ESC(1) | L3_SCC(1) | L3_3_WB),
+ /* WB - L3 25% */
+ MOCS_ENTRY(7, 0, L3_ESC(1) | L3_SCC(3) | L3_3_WB),
+ /* WB - L3 12.5% */
+ MOCS_ENTRY(8, 0, L3_ESC(1) | L3_SCC(7) | L3_3_WB),
+
+ /* HDC:L1 + L3 */
+ MOCS_ENTRY(48, 0, L3_3_WB),
+ /* HDC:L1 */
+ MOCS_ENTRY(49, 0, L3_1_UC),
+
+ /* HW Reserved */
+ MOCS_ENTRY(60, 0, L3_1_UC),
+ MOCS_ENTRY(61, 0, L3_1_UC),
+ MOCS_ENTRY(62, 0, L3_1_UC),
+ MOCS_ENTRY(63, 0, L3_1_UC),
+};
+
enum {
HAS_GLOBAL_MOCS = BIT(0),
HAS_ENGINE_MOCS = BIT(1),
@@ -324,7 +357,11 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915,
{
unsigned int flags;
- if (INTEL_GEN(i915) >= 12) {
+ if (IS_DG1(i915)) {
+ table->size = ARRAY_SIZE(dg1_mocs_table);
+ table->table = dg1_mocs_table;
+ table->n_entries = GEN9_NUM_MOCS_ENTRIES;
+ } else if (INTEL_GEN(i915) >= 12) {
table->size = ARRAY_SIZE(tgl_mocs_table);
table->table = tgl_mocs_table;
table->n_entries = GEN9_NUM_MOCS_ENTRIES;
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
index ac36b67fb46b..3654c955e6be 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -19,6 +19,7 @@
#include "intel_engine_pm.h"
#include "intel_gt.h"
#include "intel_gt_pm.h"
+#include "intel_gt_requests.h"
#include "intel_reset.h"
#include "uc/intel_guc.h"
@@ -1190,14 +1191,14 @@ static void intel_gt_reset_global(struct intel_gt *gt,
/* Use a watchdog to ensure that our reset completes */
intel_wedge_on_timeout(&w, gt, 5 * HZ) {
- intel_prepare_reset(gt->i915);
+ intel_display_prepare_reset(gt->i915);
/* Flush everyone using a resource about to be clobbered */
synchronize_srcu_expedited(&gt->reset.backoff_srcu);
intel_gt_reset(gt, engine_mask, reason);
- intel_finish_reset(gt->i915);
+ intel_display_finish_reset(gt->i915);
}
if (!test_bit(I915_WEDGED, &gt->reset.flags))
@@ -1250,7 +1251,7 @@ void intel_gt_handle_error(struct intel_gt *gt,
engine_mask &= gt->info.engine_mask;
if (flags & I915_ERROR_CAPTURE) {
- i915_capture_error_state(gt->i915);
+ i915_capture_error_state(gt, engine_mask);
intel_gt_clear_error_registers(gt, engine_mask);
}
@@ -1370,6 +1371,7 @@ void intel_gt_set_wedged_on_fini(struct intel_gt *gt)
{
intel_gt_set_wedged(gt);
set_bit(I915_WEDGED_ON_FINI, &gt->reset.flags);
+ intel_gt_retire_requests(gt); /* cleanup any wedged requests */
}
void intel_gt_init_reset(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
index 16b48e72c369..a41b43f445b8 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
@@ -444,6 +444,7 @@ static void reset_cancel(struct intel_engine_cs *engine)
i915_request_set_error_once(request, -EIO);
i915_request_mark_complete(request);
}
+ intel_engine_signal_breadcrumbs(engine);
/* Remaining _unready_ requests will be nop'ed when submitted */
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c
index c1c9cc0ad3b9..b629eeb14002 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.c
+++ b/drivers/gpu/drm/i915/gt/intel_rps.c
@@ -390,6 +390,16 @@ static void gen5_rps_update(struct intel_rps *rps)
spin_unlock_irq(&mchdev_lock);
}
+static unsigned int gen5_invert_freq(struct intel_rps *rps,
+ unsigned int val)
+{
+ /* Invert the frequency bin into an ips delay */
+ val = rps->max_freq - val;
+ val = rps->min_freq + val;
+
+ return val;
+}
+
static bool gen5_rps_set(struct intel_rps *rps, u8 val)
{
struct intel_uncore *uncore = rps_to_uncore(rps);
@@ -404,8 +414,7 @@ static bool gen5_rps_set(struct intel_rps *rps, u8 val)
}
/* Invert the frequency bin into an ips delay */
- val = rps->max_freq - val;
- val = rps->min_freq + val;
+ val = gen5_invert_freq(rps, val);
rgvswctl =
(MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
@@ -500,6 +509,7 @@ static unsigned int init_emon(struct intel_uncore *uncore)
static bool gen5_rps_enable(struct intel_rps *rps)
{
+ struct drm_i915_private *i915 = rps_to_i915(rps);
struct intel_uncore *uncore = rps_to_uncore(rps);
u8 fstart, vstart;
u32 rgvmodectl;
@@ -557,6 +567,10 @@ static bool gen5_rps_enable(struct intel_rps *rps)
rps->ips.last_count2 = intel_uncore_read(uncore, GFXEC);
rps->ips.last_time2 = ktime_get_raw_ns();
+ spin_lock(&i915->irq_lock);
+ ilk_enable_display_irq(i915, DE_PCU_EVENT);
+ spin_unlock(&i915->irq_lock);
+
spin_unlock_irq(&mchdev_lock);
rps->ips.corr = init_emon(uncore);
@@ -566,11 +580,16 @@ static bool gen5_rps_enable(struct intel_rps *rps)
static void gen5_rps_disable(struct intel_rps *rps)
{
+ struct drm_i915_private *i915 = rps_to_i915(rps);
struct intel_uncore *uncore = rps_to_uncore(rps);
u16 rgvswctl;
spin_lock_irq(&mchdev_lock);
+ spin_lock(&i915->irq_lock);
+ ilk_disable_display_irq(i915, DE_PCU_EVENT);
+ spin_unlock(&i915->irq_lock);
+
rgvswctl = intel_uncore_read16(uncore, MEMSWCTL);
/* Ack interrupts, disable EFC interrupt */
@@ -578,11 +597,6 @@ static void gen5_rps_disable(struct intel_rps *rps)
intel_uncore_read(uncore, MEMINTREN) &
~MEMINT_EVAL_CHG_EN);
intel_uncore_write(uncore, MEMINTRSTS, MEMINT_EVAL_CHG);
- intel_uncore_write(uncore, DEIER,
- intel_uncore_read(uncore, DEIER) & ~DE_PCU_EVENT);
- intel_uncore_write(uncore, DEIIR, DE_PCU_EVENT);
- intel_uncore_write(uncore, DEIMR,
- intel_uncore_read(uncore, DEIMR) | DE_PCU_EVENT);
/* Go back to the starting frequency */
gen5_rps_set(rps, rps->idle_freq);
@@ -1276,8 +1290,9 @@ static unsigned long __ips_gfx_val(struct intel_ips *ips)
{
struct intel_rps *rps = container_of(ips, typeof(*rps), ips);
struct intel_uncore *uncore = rps_to_uncore(rps);
- unsigned long t, corr, state1, corr2, state2;
+ unsigned int t, state1, state2;
u32 pxvid, ext_v;
+ u64 corr, corr2;
lockdep_assert_held(&mchdev_lock);
@@ -1298,11 +1313,10 @@ static unsigned long __ips_gfx_val(struct intel_ips *ips)
else /* < 50 */
corr = t * 301 + 1004;
- corr = corr * 150142 * state1 / 10000 - 78642;
- corr /= 100000;
- corr2 = corr * ips->corr;
+ corr = div_u64(corr * 150142 * state1, 10000) - 78642;
+ corr2 = div_u64(corr, 100000) * ips->corr;
- state2 = corr2 * state1 / 10000;
+ state2 = div_u64(corr2 * state1, 10000);
state2 /= 100; /* convert to mW */
__gen5_ips_update(ips);
@@ -1436,8 +1450,10 @@ int intel_gpu_freq(struct intel_rps *rps, int val)
return chv_gpu_freq(rps, val);
else if (IS_VALLEYVIEW(i915))
return byt_gpu_freq(rps, val);
- else
+ else if (INTEL_GEN(i915) >= 6)
return val * GT_FREQUENCY_MULTIPLIER;
+ else
+ return val;
}
int intel_freq_opcode(struct intel_rps *rps, int val)
@@ -1451,8 +1467,10 @@ int intel_freq_opcode(struct intel_rps *rps, int val)
return chv_freq_opcode(rps, val);
else if (IS_VALLEYVIEW(i915))
return byt_freq_opcode(rps, val);
- else
+ else if (INTEL_GEN(i915) >= 6)
return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
+ else
+ return val;
}
static void vlv_init_gpll_ref_freq(struct intel_rps *rps)
@@ -1868,8 +1886,11 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat)
cagf = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT;
else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
- else
+ else if (INTEL_GEN(i915) >= 6)
cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
+ else
+ cagf = gen5_invert_freq(rps, (rpstat & MEMSTAT_PSTATE_MASK) >>
+ MEMSTAT_PSTATE_SHIFT);
return cagf;
}
@@ -1877,14 +1898,17 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat)
static u32 read_cagf(struct intel_rps *rps)
{
struct drm_i915_private *i915 = rps_to_i915(rps);
+ struct intel_uncore *uncore = rps_to_uncore(rps);
u32 freq;
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
vlv_punit_get(i915);
freq = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
vlv_punit_put(i915);
+ } else if (INTEL_GEN(i915) >= 6) {
+ freq = intel_uncore_read(uncore, GEN6_RPSTAT1);
} else {
- freq = intel_uncore_read(rps_to_uncore(rps), GEN6_RPSTAT1);
+ freq = intel_uncore_read(uncore, MEMSTAT_ILK);
}
return intel_rps_get_cagf(rps, freq);
@@ -1953,7 +1977,7 @@ static struct drm_i915_private *mchdev_get(void)
rcu_read_lock();
i915 = rcu_dereference(ips_mchdev);
- if (!kref_get_unless_zero(&i915->drm.ref))
+ if (i915 && !kref_get_unless_zero(&i915->drm.ref))
i915 = NULL;
rcu_read_unlock();
diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c
index f1c039e1b5ad..8a72e0fe34ca 100644
--- a/drivers/gpu/drm/i915/gt/intel_sseu.c
+++ b/drivers/gpu/drm/i915/gt/intel_sseu.c
@@ -169,7 +169,7 @@ static void gen11_sseu_info_init(struct intel_gt *gt)
u8 eu_en;
u8 s_en;
- if (IS_ELKHARTLAKE(gt->i915))
+ if (IS_JSL_EHL(gt->i915))
intel_sseu_set_info(sseu, 1, 4, 8);
else
intel_sseu_set_info(sseu, 1, 8, 8);
diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
index 4a3bde7c9f21..adc9a8ea410a 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
@@ -674,6 +674,20 @@ static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
0);
}
+static void dg1_ctx_workarounds_init(struct intel_engine_cs *engine,
+ struct i915_wa_list *wal)
+{
+ gen12_ctx_workarounds_init(engine, wal);
+
+ /* Wa_1409044764 */
+ WA_CLR_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3,
+ DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN);
+
+ /* Wa_22010493298 */
+ WA_SET_BIT_MASKED(HIZ_CHICKEN,
+ DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE);
+}
+
static void
__intel_engine_init_ctx_wa(struct intel_engine_cs *engine,
struct i915_wa_list *wal,
@@ -686,7 +700,9 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine,
wa_init_start(wal, name, engine->name);
- if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915))
+ if (IS_DG1(i915))
+ dg1_ctx_workarounds_init(engine, wal);
+ else if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915))
tgl_ctx_workarounds_init(engine, wal);
else if (IS_GEN(i915, 12))
gen12_ctx_workarounds_init(engine, wal);
@@ -1214,7 +1230,7 @@ icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
/* Wa_1607087056:icl,ehl,jsl */
if (IS_ICELAKE(i915) ||
- IS_EHL_REVID(i915, EHL_REVID_A0, EHL_REVID_A0)) {
+ IS_JSL_EHL_REVID(i915, EHL_REVID_A0, EHL_REVID_A0)) {
wa_write_or(wal,
SLICE_UNIT_LEVEL_CLKGATE,
L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS);
@@ -1247,9 +1263,35 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
}
static void
+dg1_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
+{
+ gen12_gt_workarounds_init(i915, wal);
+
+ /* Wa_1607087056:dg1 */
+ if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0))
+ wa_write_or(wal,
+ SLICE_UNIT_LEVEL_CLKGATE,
+ L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS);
+
+ /* Wa_1409420604:dg1 */
+ if (IS_DG1(i915))
+ wa_write_or(wal,
+ SUBSLICE_UNIT_LEVEL_CLKGATE2,
+ CPSSUNIT_CLKGATE_DIS);
+
+ /* Wa_1408615072:dg1 */
+ /* Empirical testing shows this register is unaffected by engine reset. */
+ if (IS_DG1(i915))
+ wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE2,
+ VSUNIT_CLKGATE_DIS_TGL);
+}
+
+static void
gt_init_workarounds(struct drm_i915_private *i915, struct i915_wa_list *wal)
{
- if (IS_TIGERLAKE(i915))
+ if (IS_DG1(i915))
+ dg1_gt_workarounds_init(i915, wal);
+ else if (IS_TIGERLAKE(i915))
tgl_gt_workarounds_init(i915, wal);
else if (IS_GEN(i915, 12))
gen12_gt_workarounds_init(i915, wal);
@@ -1614,6 +1656,20 @@ static void tgl_whitelist_build(struct intel_engine_cs *engine)
}
}
+static void dg1_whitelist_build(struct intel_engine_cs *engine)
+{
+ struct i915_wa_list *w = &engine->whitelist;
+
+ tgl_whitelist_build(engine);
+
+ /* GEN:BUG:1409280441:dg1 */
+ if (IS_DG1_REVID(engine->i915, DG1_REVID_A0, DG1_REVID_A0) &&
+ (engine->class == RENDER_CLASS ||
+ engine->class == COPY_ENGINE_CLASS))
+ whitelist_reg_ext(w, RING_ID(engine->mmio_base),
+ RING_FORCE_TO_NONPRIV_ACCESS_RD);
+}
+
void intel_engine_init_whitelist(struct intel_engine_cs *engine)
{
struct drm_i915_private *i915 = engine->i915;
@@ -1621,7 +1677,9 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine)
wa_init_start(w, "whitelist", engine->name);
- if (IS_GEN(i915, 12))
+ if (IS_DG1(i915))
+ dg1_whitelist_build(engine);
+ else if (IS_GEN(i915, 12))
tgl_whitelist_build(engine);
else if (IS_GEN(i915, 11))
icl_whitelist_build(engine);
@@ -1675,15 +1733,18 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
{
struct drm_i915_private *i915 = engine->i915;
- if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) {
+ if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) ||
+ IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) {
/*
- * Wa_1607138336:tgl
- * Wa_1607063988:tgl
+ * Wa_1607138336:tgl[a0],dg1[a0]
+ * Wa_1607063988:tgl[a0],dg1[a0]
*/
wa_write_or(wal,
GEN9_CTX_PREEMPT_REG,
GEN12_DISABLE_POSH_BUSY_FF_DOP_CG);
+ }
+ if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) {
/*
* Wa_1606679103:tgl
* (see also Wa_1606682166:icl)
@@ -1697,35 +1758,41 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
VSUNIT_CLKGATE_DIS_TGL);
}
- if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) {
- /* Wa_1606931601:tgl,rkl */
+ if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) {
+ /* Wa_1606931601:tgl,rkl,dg1 */
wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ);
- /* Wa_1409804808:tgl,rkl */
+ /*
+ * Wa_1407928979:tgl A*
+ * Wa_18011464164:tgl[B0+],dg1[B0+]
+ * Wa_22010931296:tgl[B0+],dg1[B0+]
+ * Wa_14010919138:rkl, dg1
+ */
+ wa_write_or(wal, GEN7_FF_THREAD_MODE,
+ GEN12_FF_TESSELATION_DOP_GATE_DISABLE);
+ }
+
+ if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) ||
+ IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) {
+ /* Wa_1409804808:tgl,rkl,dg1[a0] */
wa_masked_en(wal, GEN7_ROW_CHICKEN2,
GEN12_PUSH_CONST_DEREF_HOLD_DIS);
/*
* Wa_1409085225:tgl
- * Wa_14010229206:tgl,rkl
+ * Wa_14010229206:tgl,rkl,dg1[a0]
*/
wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH);
/*
- * Wa_1407928979:tgl A*
- * Wa_18011464164:tgl B0+
- * Wa_22010931296:tgl B0+
- * Wa_14010919138:rkl,tgl
- */
- wa_write_or(wal, GEN7_FF_THREAD_MODE,
- GEN12_FF_TESSELATION_DOP_GATE_DISABLE);
-
- /*
* Wa_1607030317:tgl
* Wa_1607186500:tgl
- * Wa_1607297627:tgl,rkl there are multiple entries for this
- * WA in the BSpec; some indicate this is an A0-only WA,
- * others indicate it applies to all steppings.
+ * Wa_1607297627:tgl,rkl,dg1[a0]
+ *
+ * On TGL and RKL there are multiple entries for this WA in the
+ * BSpec; some indicate this is an A0-only WA, others indicate
+ * it applies to all steppings so we trust the "all steppings."
+ * For DG1 this only applies to A0.
*/
wa_masked_en(wal,
GEN6_RC_SLEEP_PSMI_CONTROL,
@@ -1841,7 +1908,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
GEN12_FF_TESSELATION_DOP_GATE_DISABLE);
/* Wa_22010271021:ehl */
- if (IS_ELKHARTLAKE(i915))
+ if (IS_JSL_EHL(i915))
wa_masked_en(wal,
GEN9_CS_DEBUG_MODE1,
FF_DOP_CLOCK_GATE_DISABLE);
@@ -2033,10 +2100,12 @@ err_obj:
return ERR_PTR(err);
}
-static const struct {
+struct mcr_range {
u32 start;
u32 end;
-} mcr_ranges_gen8[] = {
+};
+
+static const struct mcr_range mcr_ranges_gen8[] = {
{ .start = 0x5500, .end = 0x55ff },
{ .start = 0x7000, .end = 0x7fff },
{ .start = 0x9400, .end = 0x97ff },
@@ -2045,11 +2114,25 @@ static const struct {
{},
};
+static const struct mcr_range mcr_ranges_gen12[] = {
+ { .start = 0x8150, .end = 0x815f },
+ { .start = 0x9520, .end = 0x955f },
+ { .start = 0xb100, .end = 0xb3ff },
+ { .start = 0xde80, .end = 0xe8ff },
+ { .start = 0x24a00, .end = 0x24a7f },
+ {},
+};
+
static bool mcr_range(struct drm_i915_private *i915, u32 offset)
{
+ const struct mcr_range *mcr_ranges;
int i;
- if (INTEL_GEN(i915) < 8)
+ if (INTEL_GEN(i915) >= 12)
+ mcr_ranges = mcr_ranges_gen12;
+ else if (INTEL_GEN(i915) >= 8)
+ mcr_ranges = mcr_ranges_gen8;
+ else
return false;
/*
@@ -2057,9 +2140,9 @@ static bool mcr_range(struct drm_i915_private *i915, u32 offset)
* which only controls CPU initiated MMIO. Routing does not
* work for CS access so we cannot verify them on this path.
*/
- for (i = 0; mcr_ranges_gen8[i].start; i++)
- if (offset >= mcr_ranges_gen8[i].start &&
- offset <= mcr_ranges_gen8[i].end)
+ for (i = 0; mcr_ranges[i].start; i++)
+ if (offset >= mcr_ranges[i].start &&
+ offset <= mcr_ranges[i].end)
return true;
return false;
diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c
index dfd1cfb8a7ec..2f830017c51d 100644
--- a/drivers/gpu/drm/i915/gt/mock_engine.c
+++ b/drivers/gpu/drm/i915/gt/mock_engine.c
@@ -245,18 +245,39 @@ static void mock_reset_rewind(struct intel_engine_cs *engine, bool stalled)
GEM_BUG_ON(stalled);
}
+static void mark_eio(struct i915_request *rq)
+{
+ if (i915_request_completed(rq))
+ return;
+
+ GEM_BUG_ON(i915_request_signaled(rq));
+
+ i915_request_set_error_once(rq, -EIO);
+ i915_request_mark_complete(rq);
+}
+
static void mock_reset_cancel(struct intel_engine_cs *engine)
{
- struct i915_request *request;
+ struct mock_engine *mock =
+ container_of(engine, typeof(*mock), base);
+ struct i915_request *rq;
unsigned long flags;
+ del_timer_sync(&mock->hw_delay);
+
spin_lock_irqsave(&engine->active.lock, flags);
/* Mark all submitted requests as skipped. */
- list_for_each_entry(request, &engine->active.requests, sched.link) {
- i915_request_set_error_once(request, -EIO);
- i915_request_mark_complete(request);
+ list_for_each_entry(rq, &engine->active.requests, sched.link)
+ mark_eio(rq);
+ intel_engine_signal_breadcrumbs(engine);
+
+ /* Cancel and submit all pending requests. */
+ list_for_each_entry(rq, &mock->hw_queue, mock.link) {
+ mark_eio(rq);
+ __i915_request_submit(rq);
}
+ INIT_LIST_HEAD(&mock->hw_queue);
spin_unlock_irqrestore(&engine->active.lock, flags);
}
diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c
index e73854dd2fe0..b88aa35ad75b 100644
--- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c
+++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c
@@ -215,16 +215,17 @@ static int __live_heartbeat_fast(struct intel_engine_cs *engine)
goto err_pm;
for (i = 0; i < ARRAY_SIZE(times); i++) {
- /* Manufacture a tick */
do {
- while (READ_ONCE(engine->heartbeat.systole))
- flush_delayed_work(&engine->heartbeat.work);
+ /* Manufacture a tick */
+ intel_engine_park_heartbeat(engine);
+ GEM_BUG_ON(engine->heartbeat.systole);
+ engine->serial++; /* pretend we are not idle! */
+ intel_engine_unpark_heartbeat(engine);
- engine->serial++; /* quick, pretend we are not idle! */
flush_delayed_work(&engine->heartbeat.work);
if (!delayed_work_pending(&engine->heartbeat.work)) {
- pr_err("%s: heartbeat did not start\n",
- engine->name);
+ pr_err("%s: heartbeat %d did not start\n",
+ engine->name, i);
err = -EINVAL;
goto err_pm;
}
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c
index 3540ba9bd459..aa5675ecb5cc 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -219,7 +219,7 @@ int live_rps_clock_interval(void *arg)
struct igt_spinner spin;
int err = 0;
- if (!intel_rps_is_enabled(rps))
+ if (!intel_rps_is_enabled(rps) || INTEL_GEN(gt->i915) < 6)
return 0;
if (igt_spinner_init(&spin, gt))
@@ -1028,7 +1028,7 @@ int live_rps_interrupt(void *arg)
* First, let's check whether or not we are receiving interrupts.
*/
- if (!intel_rps_has_interrupts(rps))
+ if (!intel_rps_has_interrupts(rps) || INTEL_GEN(gt->i915) < 6)
return 0;
intel_gt_pm_get(gt);
@@ -1133,7 +1133,7 @@ int live_rps_power(void *arg)
* that theory.
*/
- if (!intel_rps_is_enabled(rps))
+ if (!intel_rps_is_enabled(rps) || INTEL_GEN(gt->i915) < 6)
return 0;
if (!librapl_energy_uJ())
@@ -1237,7 +1237,7 @@ int live_rps_dynamic(void *arg)
* moving parts into dynamic reclocking based on load.
*/
- if (!intel_rps_is_enabled(rps))
+ if (!intel_rps_is_enabled(rps) || INTEL_GEN(gt->i915) < 6)
return 0;
if (igt_spinner_init(&spin, gt))
diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
index 19c2cb166e7c..2edf2b15885f 100644
--- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
+++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
@@ -17,8 +17,9 @@
#include "../selftests/i915_random.h"
#include "../i915_selftest.h"
-#include "../selftests/igt_flush_test.h"
-#include "../selftests/mock_gem_device.h"
+#include "selftests/igt_flush_test.h"
+#include "selftests/lib_sw_fence.h"
+#include "selftests/mock_gem_device.h"
#include "selftests/mock_timeline.h"
static struct page *hwsp_page(struct intel_timeline *tl)
@@ -755,6 +756,378 @@ out_free:
return err;
}
+static int emit_read_hwsp(struct i915_request *rq,
+ u32 seqno, u32 hwsp,
+ u32 *addr)
+{
+ const u32 gpr = i915_mmio_reg_offset(GEN8_RING_CS_GPR(rq->engine->mmio_base, 0));
+ u32 *cs;
+
+ cs = intel_ring_begin(rq, 12);
+ if (IS_ERR(cs))
+ return PTR_ERR(cs);
+
+ *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
+ *cs++ = *addr;
+ *cs++ = 0;
+ *cs++ = seqno;
+ *addr += 4;
+
+ *cs++ = MI_LOAD_REGISTER_MEM_GEN8 | MI_USE_GGTT;
+ *cs++ = gpr;
+ *cs++ = hwsp;
+ *cs++ = 0;
+
+ *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
+ *cs++ = gpr;
+ *cs++ = *addr;
+ *cs++ = 0;
+ *addr += 4;
+
+ intel_ring_advance(rq, cs);
+
+ return 0;
+}
+
+struct hwsp_watcher {
+ struct i915_vma *vma;
+ struct i915_request *rq;
+ u32 addr;
+ u32 *map;
+};
+
+static bool cmp_lt(u32 a, u32 b)
+{
+ return a < b;
+}
+
+static bool cmp_gte(u32 a, u32 b)
+{
+ return a >= b;
+}
+
+static int setup_watcher(struct hwsp_watcher *w, struct intel_gt *gt)
+{
+ struct drm_i915_gem_object *obj;
+ struct i915_vma *vma;
+
+ obj = i915_gem_object_create_internal(gt->i915, SZ_2M);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ w->map = i915_gem_object_pin_map(obj, I915_MAP_WB);
+ if (IS_ERR(w->map)) {
+ i915_gem_object_put(obj);
+ return PTR_ERR(w->map);
+ }
+
+ vma = i915_gem_object_ggtt_pin_ww(obj, NULL, NULL, 0, 0, 0);
+ if (IS_ERR(vma)) {
+ i915_gem_object_put(obj);
+ return PTR_ERR(vma);
+ }
+
+ w->vma = vma;
+ w->addr = i915_ggtt_offset(vma);
+ return 0;
+}
+
+static int create_watcher(struct hwsp_watcher *w,
+ struct intel_engine_cs *engine,
+ int ringsz)
+{
+ struct intel_context *ce;
+ struct intel_timeline *tl;
+
+ ce = intel_context_create(engine);
+ if (IS_ERR(ce))
+ return PTR_ERR(ce);
+
+ ce->ring = __intel_context_ring_size(ringsz);
+ w->rq = intel_context_create_request(ce);
+ intel_context_put(ce);
+ if (IS_ERR(w->rq))
+ return PTR_ERR(w->rq);
+
+ w->addr = i915_ggtt_offset(w->vma);
+ tl = w->rq->context->timeline;
+
+ /* some light mutex juggling required; think co-routines */
+ lockdep_unpin_lock(&tl->mutex, w->rq->cookie);
+ mutex_unlock(&tl->mutex);
+
+ return 0;
+}
+
+static int check_watcher(struct hwsp_watcher *w, const char *name,
+ bool (*op)(u32 hwsp, u32 seqno))
+{
+ struct i915_request *rq = fetch_and_zero(&w->rq);
+ struct intel_timeline *tl = rq->context->timeline;
+ u32 offset, end;
+ int err;
+
+ GEM_BUG_ON(w->addr - i915_ggtt_offset(w->vma) > w->vma->size);
+
+ i915_request_get(rq);
+ mutex_lock(&tl->mutex);
+ rq->cookie = lockdep_pin_lock(&tl->mutex);
+ i915_request_add(rq);
+
+ if (i915_request_wait(rq, 0, HZ) < 0) {
+ err = -ETIME;
+ goto out;
+ }
+
+ err = 0;
+ offset = 0;
+ end = (w->addr - i915_ggtt_offset(w->vma)) / sizeof(*w->map);
+ while (offset < end) {
+ if (!op(w->map[offset + 1], w->map[offset])) {
+ pr_err("Watcher '%s' found HWSP value %x for seqno %x\n",
+ name, w->map[offset + 1], w->map[offset]);
+ err = -EINVAL;
+ }
+
+ offset += 2;
+ }
+
+out:
+ i915_request_put(rq);
+ return err;
+}
+
+static void cleanup_watcher(struct hwsp_watcher *w)
+{
+ if (w->rq) {
+ struct intel_timeline *tl = w->rq->context->timeline;
+
+ mutex_lock(&tl->mutex);
+ w->rq->cookie = lockdep_pin_lock(&tl->mutex);
+
+ i915_request_add(w->rq);
+ }
+
+ i915_vma_unpin_and_release(&w->vma, I915_VMA_RELEASE_MAP);
+}
+
+static bool retire_requests(struct intel_timeline *tl)
+{
+ struct i915_request *rq, *rn;
+
+ mutex_lock(&tl->mutex);
+ list_for_each_entry_safe(rq, rn, &tl->requests, link)
+ if (!i915_request_retire(rq))
+ break;
+ mutex_unlock(&tl->mutex);
+
+ return !i915_active_fence_isset(&tl->last_request);
+}
+
+static struct i915_request *wrap_timeline(struct i915_request *rq)
+{
+ struct intel_context *ce = rq->context;
+ struct intel_timeline *tl = ce->timeline;
+ u32 seqno = rq->fence.seqno;
+
+ while (tl->seqno >= seqno) { /* Cause a wrap */
+ i915_request_put(rq);
+ rq = intel_context_create_request(ce);
+ if (IS_ERR(rq))
+ return rq;
+
+ i915_request_get(rq);
+ i915_request_add(rq);
+ }
+
+ i915_request_put(rq);
+ rq = intel_context_create_request(ce);
+ if (IS_ERR(rq))
+ return rq;
+
+ i915_request_get(rq);
+ i915_request_add(rq);
+
+ return rq;
+}
+
+static int live_hwsp_read(void *arg)
+{
+ struct intel_gt *gt = arg;
+ struct hwsp_watcher watcher[2] = {};
+ struct intel_engine_cs *engine;
+ struct intel_timeline *tl;
+ enum intel_engine_id id;
+ int err = 0;
+ int i;
+
+ /*
+ * If we take a reference to the HWSP for reading on the GPU, that
+ * read may be arbitrarily delayed (either by foreign fence or
+ * priority saturation) and a wrap can happen within 30 minutes.
+ * When the GPU read is finally submitted it should be correct,
+ * even across multiple wraps.
+ */
+
+ if (INTEL_GEN(gt->i915) < 8) /* CS convenience [SRM/LRM] */
+ return 0;
+
+ tl = intel_timeline_create(gt);
+ if (IS_ERR(tl))
+ return PTR_ERR(tl);
+
+ if (!tl->hwsp_cacheline)
+ goto out_free;
+
+ for (i = 0; i < ARRAY_SIZE(watcher); i++) {
+ err = setup_watcher(&watcher[i], gt);
+ if (err)
+ goto out;
+ }
+
+ for_each_engine(engine, gt, id) {
+ struct intel_context *ce;
+ unsigned long count = 0;
+ IGT_TIMEOUT(end_time);
+
+ /* Create a request we can use for remote reading of the HWSP */
+ err = create_watcher(&watcher[1], engine, SZ_512K);
+ if (err)
+ goto out;
+
+ do {
+ struct i915_sw_fence *submit;
+ struct i915_request *rq;
+ u32 hwsp;
+
+ submit = heap_fence_create(GFP_KERNEL);
+ if (!submit) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = create_watcher(&watcher[0], engine, SZ_4K);
+ if (err)
+ goto out;
+
+ ce = intel_context_create(engine);
+ if (IS_ERR(ce)) {
+ err = PTR_ERR(ce);
+ goto out;
+ }
+
+ /* Skip to the end, saving 30 minutes of nops */
+ tl->seqno = -10u + 2 * (count & 3);
+ WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno);
+ ce->timeline = intel_timeline_get(tl);
+
+ rq = intel_context_create_request(ce);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ intel_context_put(ce);
+ goto out;
+ }
+
+ err = i915_sw_fence_await_dma_fence(&rq->submit,
+ &watcher[0].rq->fence, 0,
+ GFP_KERNEL);
+ if (err < 0) {
+ i915_request_add(rq);
+ intel_context_put(ce);
+ goto out;
+ }
+
+ mutex_lock(&watcher[0].rq->context->timeline->mutex);
+ err = intel_timeline_read_hwsp(rq, watcher[0].rq, &hwsp);
+ if (err == 0)
+ err = emit_read_hwsp(watcher[0].rq, /* before */
+ rq->fence.seqno, hwsp,
+ &watcher[0].addr);
+ mutex_unlock(&watcher[0].rq->context->timeline->mutex);
+ if (err) {
+ i915_request_add(rq);
+ intel_context_put(ce);
+ goto out;
+ }
+
+ mutex_lock(&watcher[1].rq->context->timeline->mutex);
+ err = intel_timeline_read_hwsp(rq, watcher[1].rq, &hwsp);
+ if (err == 0)
+ err = emit_read_hwsp(watcher[1].rq, /* after */
+ rq->fence.seqno, hwsp,
+ &watcher[1].addr);
+ mutex_unlock(&watcher[1].rq->context->timeline->mutex);
+ if (err) {
+ i915_request_add(rq);
+ intel_context_put(ce);
+ goto out;
+ }
+
+ i915_request_get(rq);
+ i915_request_add(rq);
+
+ rq = wrap_timeline(rq);
+ intel_context_put(ce);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ goto out;
+ }
+
+ err = i915_sw_fence_await_dma_fence(&watcher[1].rq->submit,
+ &rq->fence, 0,
+ GFP_KERNEL);
+ if (err < 0) {
+ i915_request_put(rq);
+ goto out;
+ }
+
+ err = check_watcher(&watcher[0], "before", cmp_lt);
+ i915_sw_fence_commit(submit);
+ heap_fence_put(submit);
+ if (err) {
+ i915_request_put(rq);
+ goto out;
+ }
+ count++;
+
+ if (8 * watcher[1].rq->ring->emit >
+ 3 * watcher[1].rq->ring->size) {
+ i915_request_put(rq);
+ break;
+ }
+
+ /* Flush the timeline before manually wrapping again */
+ if (i915_request_wait(rq,
+ I915_WAIT_INTERRUPTIBLE,
+ HZ) < 0) {
+ err = -ETIME;
+ i915_request_put(rq);
+ goto out;
+ }
+
+ retire_requests(tl);
+ i915_request_put(rq);
+ } while (!__igt_timeout(end_time, NULL));
+ WRITE_ONCE(*(u32 *)tl->hwsp_seqno, 0xdeadbeef);
+
+ pr_info("%s: simulated %lu wraps\n", engine->name, count);
+ err = check_watcher(&watcher[1], "after", cmp_gte);
+ if (err)
+ goto out;
+ }
+
+out:
+ for (i = 0; i < ARRAY_SIZE(watcher); i++)
+ cleanup_watcher(&watcher[i]);
+
+ if (igt_flush_test(gt->i915))
+ err = -EIO;
+
+out_free:
+ intel_timeline_put(tl);
+ return err;
+}
+
static int live_hwsp_rollover_kernel(void *arg)
{
struct intel_gt *gt = arg;
@@ -998,6 +1371,7 @@ int intel_timeline_live_selftests(struct drm_i915_private *i915)
SUBTEST(live_hwsp_engine),
SUBTEST(live_hwsp_alternate),
SUBTEST(live_hwsp_wrap),
+ SUBTEST(live_hwsp_read),
SUBTEST(live_hwsp_rollover_kernel),
SUBTEST(live_hwsp_rollover_user),
};
diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c
index 535cc1169e54..967031056202 100644
--- a/drivers/gpu/drm/i915/gt/sysfs_engines.c
+++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c
@@ -79,14 +79,12 @@ static ssize_t repr_trim(char *buf, ssize_t len)
static ssize_t
__caps_show(struct intel_engine_cs *engine,
- u32 caps, char *buf, bool show_unknown)
+ unsigned long caps, char *buf, bool show_unknown)
{
const char * const *repr;
int count, n;
ssize_t len;
- BUILD_BUG_ON(!typecheck(typeof(caps), engine->uabi_capabilities));
-
switch (engine->class) {
case VIDEO_DECODE_CLASS:
repr = vcs_caps;
@@ -103,12 +101,10 @@ __caps_show(struct intel_engine_cs *engine,
count = 0;
break;
}
- GEM_BUG_ON(count > BITS_PER_TYPE(typeof(caps)));
+ GEM_BUG_ON(count > BITS_PER_LONG);
len = 0;
- for_each_set_bit(n,
- (unsigned long *)&caps,
- show_unknown ? BITS_PER_TYPE(typeof(caps)) : count) {
+ for_each_set_bit(n, &caps, show_unknown ? BITS_PER_LONG : count) {
if (n >= count || !repr[n]) {
if (GEM_WARN_ON(show_unknown))
len += snprintf(buf + len, PAGE_SIZE - len,
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
index 942c7c187adb..2a343a977987 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
@@ -213,23 +213,6 @@ static u32 guc_ctl_feature_flags(struct intel_guc *guc)
return flags;
}
-static u32 guc_ctl_ctxinfo_flags(struct intel_guc *guc)
-{
- u32 flags = 0;
-
- if (intel_guc_submission_is_used(guc)) {
- u32 ctxnum, base;
-
- base = intel_guc_ggtt_offset(guc, guc->stage_desc_pool);
- ctxnum = GUC_MAX_STAGE_DESCRIPTORS / 16;
-
- base >>= PAGE_SHIFT;
- flags |= (base << GUC_CTL_BASE_ADDR_SHIFT) |
- (ctxnum << GUC_CTL_CTXNUM_IN16_SHIFT);
- }
- return flags;
-}
-
static u32 guc_ctl_log_params_flags(struct intel_guc *guc)
{
u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT;
@@ -291,7 +274,6 @@ static void guc_init_params(struct intel_guc *guc)
BUILD_BUG_ON(sizeof(guc->params) != GUC_CTL_MAX_DWORDS * sizeof(u32));
- params[GUC_CTL_CTXINFO] = guc_ctl_ctxinfo_flags(guc);
params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc);
params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc);
params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc);
@@ -312,18 +294,18 @@ void intel_guc_write_params(struct intel_guc *guc)
int i;
/*
- * All SOFT_SCRATCH registers are in FORCEWAKE_BLITTER domain and
+ * All SOFT_SCRATCH registers are in FORCEWAKE_GT domain and
* they are power context saved so it's ok to release forcewake
* when we are done here and take it again at xfer time.
*/
- intel_uncore_forcewake_get(uncore, FORCEWAKE_BLITTER);
+ intel_uncore_forcewake_get(uncore, FORCEWAKE_GT);
intel_uncore_write(uncore, SOFT_SCRATCH(0), 0);
for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
intel_uncore_write(uncore, SOFT_SCRATCH(1 + i), guc->params[i]);
- intel_uncore_forcewake_put(uncore, FORCEWAKE_BLITTER);
+ intel_uncore_forcewake_put(uncore, FORCEWAKE_GT);
}
int intel_guc_init(struct intel_guc *guc)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index d44061033f23..5212ff844292 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -10,11 +10,52 @@
/*
* The Additional Data Struct (ADS) has pointers for different buffers used by
- * the GuC. One single gem object contains the ADS struct itself (guc_ads), the
- * scheduling policies (guc_policies), a structure describing a collection of
- * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save
- * its internal state for sleep.
+ * the GuC. One single gem object contains the ADS struct itself (guc_ads) and
+ * all the extra buffers indirectly linked via the ADS struct's entries.
+ *
+ * Layout of the ADS blob allocated for the GuC:
+ *
+ * +---------------------------------------+ <== base
+ * | guc_ads |
+ * +---------------------------------------+
+ * | guc_policies |
+ * +---------------------------------------+
+ * | guc_gt_system_info |
+ * +---------------------------------------+
+ * | guc_clients_info |
+ * +---------------------------------------+
+ * | guc_ct_pool_entry[size] |
+ * +---------------------------------------+
+ * | padding |
+ * +---------------------------------------+ <== 4K aligned
+ * | private data |
+ * +---------------------------------------+
+ * | padding |
+ * +---------------------------------------+ <== 4K aligned
*/
+struct __guc_ads_blob {
+ struct guc_ads ads;
+ struct guc_policies policies;
+ struct guc_gt_system_info system_info;
+ struct guc_clients_info clients_info;
+ struct guc_ct_pool_entry ct_pool[GUC_CT_POOL_SIZE];
+} __packed;
+
+static u32 guc_ads_private_data_size(struct intel_guc *guc)
+{
+ return PAGE_ALIGN(guc->fw.private_data_size);
+}
+
+static u32 guc_ads_private_data_offset(struct intel_guc *guc)
+{
+ return PAGE_ALIGN(sizeof(struct __guc_ads_blob));
+}
+
+static u32 guc_ads_blob_size(struct intel_guc *guc)
+{
+ return guc_ads_private_data_offset(guc) +
+ guc_ads_private_data_size(guc);
+}
static void guc_policy_init(struct guc_policy *policy)
{
@@ -48,26 +89,37 @@ static void guc_ct_pool_entries_init(struct guc_ct_pool_entry *pool, u32 num)
memset(pool, 0, num * sizeof(*pool));
}
+static void guc_mapping_table_init(struct intel_gt *gt,
+ struct guc_gt_system_info *system_info)
+{
+ unsigned int i, j;
+ struct intel_engine_cs *engine;
+ enum intel_engine_id id;
+
+ /* Table must be set to invalid values for entries not used */
+ for (i = 0; i < GUC_MAX_ENGINE_CLASSES; ++i)
+ for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; ++j)
+ system_info->mapping_table[i][j] =
+ GUC_MAX_INSTANCES_PER_CLASS;
+
+ for_each_engine(engine, gt, id) {
+ u8 guc_class = engine->class;
+
+ system_info->mapping_table[guc_class][engine->instance] =
+ engine->instance;
+ }
+}
+
/*
* The first 80 dwords of the register state context, containing the
* execlists and ppgtt registers.
*/
#define LR_HW_CONTEXT_SIZE (80 * sizeof(u32))
-/* The ads obj includes the struct itself and buffers passed to GuC */
-struct __guc_ads_blob {
- struct guc_ads ads;
- struct guc_policies policies;
- struct guc_mmio_reg_state reg_state;
- struct guc_gt_system_info system_info;
- struct guc_clients_info clients_info;
- struct guc_ct_pool_entry ct_pool[GUC_CT_POOL_SIZE];
- u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
-} __packed;
-
static void __guc_ads_init(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
+ struct drm_i915_private *i915 = gt->i915;
struct __guc_ads_blob *blob = guc->ads_blob;
const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
u32 base;
@@ -99,13 +151,25 @@ static void __guc_ads_init(struct intel_guc *guc)
}
/* System info */
- blob->system_info.slice_enabled = hweight8(gt->info.sseu.slice_mask);
- blob->system_info.rcs_enabled = 1;
- blob->system_info.bcs_enabled = 1;
+ blob->system_info.engine_enabled_masks[RENDER_CLASS] = 1;
+ blob->system_info.engine_enabled_masks[COPY_ENGINE_CLASS] = 1;
+ blob->system_info.engine_enabled_masks[VIDEO_DECODE_CLASS] = VDBOX_MASK(gt);
+ blob->system_info.engine_enabled_masks[VIDEO_ENHANCEMENT_CLASS] = VEBOX_MASK(gt);
+
+ blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED] =
+ hweight8(gt->info.sseu.slice_mask);
+ blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK] =
+ gt->info.vdbox_sfc_access;
+
+ if (INTEL_GEN(i915) >= 12 && !IS_DGFX(i915)) {
+ u32 distdbreg = intel_uncore_read(gt->uncore,
+ GEN12_DIST_DBS_POPULATED);
+ blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI] =
+ ((distdbreg >> GEN12_DOORBELLS_PER_SQIDI_SHIFT) &
+ GEN12_DOORBELLS_PER_SQIDI) + 1;
+ }
- blob->system_info.vdbox_enable_mask = VDBOX_MASK(gt);
- blob->system_info.vebox_enable_mask = VEBOX_MASK(gt);
- blob->system_info.vdbox_sfc_support_mask = gt->info.vdbox_sfc_access;
+ guc_mapping_table_init(guc_to_gt(guc), &blob->system_info);
base = intel_guc_ggtt_offset(guc, guc->ads_vma);
@@ -118,11 +182,12 @@ static void __guc_ads_init(struct intel_guc *guc)
/* ADS */
blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
- blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
- blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
blob->ads.clients_info = base + ptr_offset(blob, clients_info);
+ /* Private Data */
+ blob->ads.private_data = base + guc_ads_private_data_offset(guc);
+
i915_gem_object_flush_map(guc->ads_vma->obj);
}
@@ -135,14 +200,15 @@ static void __guc_ads_init(struct intel_guc *guc)
*/
int intel_guc_ads_create(struct intel_guc *guc)
{
- const u32 size = PAGE_ALIGN(sizeof(struct __guc_ads_blob));
+ u32 size;
int ret;
GEM_BUG_ON(guc->ads_vma);
+ size = guc_ads_blob_size(guc);
+
ret = intel_guc_allocate_and_map_vma(guc, size, &guc->ads_vma,
(void **)&guc->ads_blob);
-
if (ret)
return ret;
@@ -154,6 +220,19 @@ int intel_guc_ads_create(struct intel_guc *guc)
void intel_guc_ads_destroy(struct intel_guc *guc)
{
i915_vma_unpin_and_release(&guc->ads_vma, I915_VMA_RELEASE_MAP);
+ guc->ads_blob = NULL;
+}
+
+static void guc_ads_private_data_reset(struct intel_guc *guc)
+{
+ u32 size;
+
+ size = guc_ads_private_data_size(guc);
+ if (!size)
+ return;
+
+ memset((void *)guc->ads_blob + guc_ads_private_data_offset(guc), 0,
+ size);
}
/**
@@ -168,5 +247,8 @@ void intel_guc_ads_reset(struct intel_guc *guc)
{
if (!guc->ads_vma)
return;
+
__guc_ads_init(guc);
+
+ guc_ads_private_data_reset(guc);
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
index 11742fca0e9e..fa9e048cc65f 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
@@ -210,6 +210,7 @@ void intel_guc_ct_fini(struct intel_guc_ct *ct)
GEM_BUG_ON(ct->enabled);
i915_vma_unpin_and_release(&ct->vma, I915_VMA_RELEASE_MAP);
+ memset(ct, 0, sizeof(*ct));
}
/**
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
index d4a87f4c9421..f9d0907ea1a5 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
@@ -76,6 +76,7 @@ static inline bool guc_ready(struct intel_uncore *uncore, u32 *status)
static int guc_wait_ucode(struct intel_uncore *uncore)
{
+ struct drm_device *drm = &uncore->i915->drm;
u32 status;
int ret;
@@ -90,15 +91,27 @@ static int guc_wait_ucode(struct intel_uncore *uncore)
ret = wait_for(guc_ready(uncore, &status), 100);
DRM_DEBUG_DRIVER("GuC status %#x\n", status);
- if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) {
- DRM_ERROR("GuC firmware signature verification failed\n");
- ret = -ENOEXEC;
- }
-
- if ((status & GS_UKERNEL_MASK) == GS_UKERNEL_EXCEPTION) {
- DRM_ERROR("GuC firmware exception. EIP: %#x\n",
- intel_uncore_read(uncore, SOFT_SCRATCH(13)));
- ret = -ENXIO;
+ if (ret) {
+ drm_err(drm, "GuC load failed: status = 0x%08X\n", status);
+ drm_err(drm, "GuC load failed: status: Reset = %d, "
+ "BootROM = 0x%02X, UKernel = 0x%02X, "
+ "MIA = 0x%02X, Auth = 0x%02X\n",
+ REG_FIELD_GET(GS_MIA_IN_RESET, status),
+ REG_FIELD_GET(GS_BOOTROM_MASK, status),
+ REG_FIELD_GET(GS_UKERNEL_MASK, status),
+ REG_FIELD_GET(GS_MIA_MASK, status),
+ REG_FIELD_GET(GS_AUTH_STATUS_MASK, status));
+
+ if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) {
+ drm_err(drm, "GuC firmware signature verification failed\n");
+ ret = -ENOEXEC;
+ }
+
+ if ((status & GS_UKERNEL_MASK) == GS_UKERNEL_EXCEPTION) {
+ drm_err(drm, "GuC firmware exception. EIP: %#x\n",
+ intel_uncore_read(uncore, SOFT_SCRATCH(13)));
+ ret = -ENXIO;
+ }
}
return ret;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
index a6b733c146c9..79c560d9c0b6 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
@@ -26,8 +26,8 @@
#define GUC_VIDEO_ENGINE2 4
#define GUC_MAX_ENGINES_NUM (GUC_VIDEO_ENGINE2 + 1)
-#define GUC_MAX_ENGINE_CLASSES 5
-#define GUC_MAX_INSTANCES_PER_CLASS 16
+#define GUC_MAX_ENGINE_CLASSES 16
+#define GUC_MAX_INSTANCES_PER_CLASS 32
#define GUC_DOORBELL_INVALID 256
@@ -62,12 +62,7 @@
#define GUC_STAGE_DESC_ATTR_PCH BIT(6)
#define GUC_STAGE_DESC_ATTR_TERMINATED BIT(7)
-/* New GuC control data */
-#define GUC_CTL_CTXINFO 0
-#define GUC_CTL_CTXNUM_IN16_SHIFT 0
-#define GUC_CTL_BASE_ADDR_SHIFT 12
-
-#define GUC_CTL_LOG_PARAMS 1
+#define GUC_CTL_LOG_PARAMS 0
#define GUC_LOG_VALID (1 << 0)
#define GUC_LOG_NOTIFY_ON_HALF_FULL (1 << 1)
#define GUC_LOG_ALLOC_IN_MEGABYTE (1 << 3)
@@ -79,11 +74,11 @@
#define GUC_LOG_ISR_MASK (0x7 << GUC_LOG_ISR_SHIFT)
#define GUC_LOG_BUF_ADDR_SHIFT 12
-#define GUC_CTL_WA 2
-#define GUC_CTL_FEATURE 3
+#define GUC_CTL_WA 1
+#define GUC_CTL_FEATURE 2
#define GUC_CTL_DISABLE_SCHEDULER (1 << 14)
-#define GUC_CTL_DEBUG 4
+#define GUC_CTL_DEBUG 3
#define GUC_LOG_VERBOSITY_SHIFT 0
#define GUC_LOG_VERBOSITY_LOW (0 << GUC_LOG_VERBOSITY_SHIFT)
#define GUC_LOG_VERBOSITY_MED (1 << GUC_LOG_VERBOSITY_SHIFT)
@@ -97,12 +92,37 @@
#define GUC_LOG_DISABLED (1 << 6)
#define GUC_PROFILE_ENABLED (1 << 7)
-#define GUC_CTL_ADS 5
+#define GUC_CTL_ADS 4
#define GUC_ADS_ADDR_SHIFT 1
#define GUC_ADS_ADDR_MASK (0xFFFFF << GUC_ADS_ADDR_SHIFT)
#define GUC_CTL_MAX_DWORDS (SOFT_SCRATCH_COUNT - 2) /* [1..14] */
+/* Generic GT SysInfo data types */
+#define GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED 0
+#define GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK 1
+#define GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI 2
+#define GUC_GENERIC_GT_SYSINFO_MAX 16
+
+/*
+ * The class goes in bits [0..2] of the GuC ID, the instance in bits [3..6].
+ * Bit 7 can be used for operations that apply to all engine classes&instances.
+ */
+#define GUC_ENGINE_CLASS_SHIFT 0
+#define GUC_ENGINE_CLASS_MASK (0x7 << GUC_ENGINE_CLASS_SHIFT)
+#define GUC_ENGINE_INSTANCE_SHIFT 3
+#define GUC_ENGINE_INSTANCE_MASK (0xf << GUC_ENGINE_INSTANCE_SHIFT)
+#define GUC_ENGINE_ALL_INSTANCES BIT(7)
+
+#define MAKE_GUC_ID(class, instance) \
+ (((class) << GUC_ENGINE_CLASS_SHIFT) | \
+ ((instance) << GUC_ENGINE_INSTANCE_SHIFT))
+
+#define GUC_ID_TO_ENGINE_CLASS(guc_id) \
+ (((guc_id) & GUC_ENGINE_CLASS_MASK) >> GUC_ENGINE_CLASS_SHIFT)
+#define GUC_ID_TO_ENGINE_INSTANCE(guc_id) \
+ (((guc_id) & GUC_ENGINE_INSTANCE_MASK) >> GUC_ENGINE_INSTANCE_SHIFT)
+
/* Work item for submitting workloads into work queue of GuC. */
struct guc_wq_item {
u32 header;
@@ -336,11 +356,6 @@ struct guc_policies {
} __packed;
/* GuC MMIO reg state struct */
-
-
-#define GUC_REGSET_MAX_REGISTERS 64
-#define GUC_S3_SAVE_SPACE_PAGES 10
-
struct guc_mmio_reg {
u32 offset;
u32 value;
@@ -348,28 +363,18 @@ struct guc_mmio_reg {
#define GUC_REGSET_MASKED (1 << 0)
} __packed;
-struct guc_mmio_regset {
- struct guc_mmio_reg registers[GUC_REGSET_MAX_REGISTERS];
- u32 values_valid;
- u32 number_of_registers;
-} __packed;
-
/* GuC register sets */
-struct guc_mmio_reg_state {
- struct guc_mmio_regset engine_reg[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];
- u32 reserved[98];
+struct guc_mmio_reg_set {
+ u32 address;
+ u16 count;
+ u16 reserved;
} __packed;
/* HW info */
struct guc_gt_system_info {
- u32 slice_enabled;
- u32 rcs_enabled;
- u32 reserved0;
- u32 bcs_enabled;
- u32 vdbox_enable_mask;
- u32 vdbox_sfc_support_mask;
- u32 vebox_enable_mask;
- u32 reserved[9];
+ u8 mapping_table[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];
+ u32 engine_enabled_masks[GUC_MAX_ENGINE_CLASSES];
+ u32 generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_MAX];
} __packed;
/* Clients info */
@@ -390,15 +395,16 @@ struct guc_clients_info {
/* GuC Additional Data Struct */
struct guc_ads {
- u32 reg_state_addr;
- u32 reg_state_buffer;
+ struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];
+ u32 reserved0;
u32 scheduler_policies;
u32 gt_system_info;
u32 clients_info;
u32 control_data;
u32 golden_context_lrca[GUC_MAX_ENGINE_CLASSES];
u32 eng_state_size[GUC_MAX_ENGINE_CLASSES];
- u32 reserved[16];
+ u32 private_data;
+ u32 reserved[15];
} __packed;
/* GuC logging structures */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h
index 1949346e714e..b37fc2ffaef2 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h
@@ -118,6 +118,11 @@ struct guc_doorbell_info {
#define GEN8_DRB_VALID (1<<0)
#define GEN8_DRBREGU(x) _MMIO(0x1000 + (x) * 8 + 4)
+#define GEN12_DIST_DBS_POPULATED _MMIO(0xd08)
+#define GEN12_DOORBELLS_PER_SQIDI_SHIFT 16
+#define GEN12_DOORBELLS_PER_SQIDI (0xff)
+#define GEN12_SQIDIS_DOORBELL_EXIST (0xffff)
+
#define DE_GUCRMR _MMIO(0x44054)
#define GUC_BCS_RCS_IER _MMIO(0xC550)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
index d6f55f70889d..4e6070e95fe9 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
@@ -231,13 +231,15 @@ static int guc_enable_communication(struct intel_guc *guc)
intel_guc_ct_event_handler(&guc->ct);
spin_unlock_irq(&i915->irq_lock);
- DRM_INFO("GuC communication enabled\n");
+ drm_dbg(&i915->drm, "GuC communication enabled\n");
return 0;
}
static void guc_disable_communication(struct intel_guc *guc)
{
+ struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+
/*
* Events generated during or after CT disable are logged by guc in
* via mmio. Make sure the register is clear before disabling CT since
@@ -257,7 +259,7 @@ static void guc_disable_communication(struct intel_guc *guc)
*/
guc_get_mmio_msg(guc);
- DRM_INFO("GuC communication disabled\n");
+ drm_dbg(&i915->drm, "GuC communication disabled\n");
}
static void __uc_fetch_firmwares(struct intel_uc *uc)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index 80e8b6c3bc8c..180c23e2e25e 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -44,23 +44,20 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
* List of required GuC and HuC binaries per-platform.
* Must be ordered based on platform + revid, from newer to older.
*
- * TGL 35.2 is interface-compatible with 33.0 for previous Gens. The deltas
- * between 33.0 and 35.2 are only related to new additions to support new Gen12
- * features.
- *
* Note that RKL uses the same firmware as TGL.
*/
#define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
- fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \
- fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \
- fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl, 9, 0, 0)) \
- fw_def(ICELAKE, 0, guc_def(icl, 33, 0, 0), huc_def(icl, 9, 0, 0)) \
- fw_def(COMETLAKE, 5, guc_def(cml, 33, 0, 0), huc_def(cml, 4, 0, 0)) \
- fw_def(COFFEELAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) \
- fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 4, 0, 0)) \
- fw_def(KABYLAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) \
- fw_def(BROXTON, 0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 2, 0, 0)) \
- fw_def(SKYLAKE, 0, guc_def(skl, 33, 0, 0), huc_def(skl, 2, 0, 0))
+ fw_def(ROCKETLAKE, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \
+ fw_def(TIGERLAKE, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \
+ fw_def(JASPERLAKE, 0, guc_def(ehl, 49, 0, 1), huc_def(ehl, 9, 0, 0)) \
+ fw_def(ELKHARTLAKE, 0, guc_def(ehl, 49, 0, 1), huc_def(ehl, 9, 0, 0)) \
+ fw_def(ICELAKE, 0, guc_def(icl, 49, 0, 1), huc_def(icl, 9, 0, 0)) \
+ fw_def(COMETLAKE, 5, guc_def(cml, 49, 0, 1), huc_def(cml, 4, 0, 0)) \
+ fw_def(COFFEELAKE, 0, guc_def(kbl, 49, 0, 1), huc_def(kbl, 4, 0, 0)) \
+ fw_def(GEMINILAKE, 0, guc_def(glk, 49, 0, 1), huc_def(glk, 4, 0, 0)) \
+ fw_def(KABYLAKE, 0, guc_def(kbl, 49, 0, 1), huc_def(kbl, 4, 0, 0)) \
+ fw_def(BROXTON, 0, guc_def(bxt, 49, 0, 1), huc_def(bxt, 2, 0, 0)) \
+ fw_def(SKYLAKE, 0, guc_def(skl, 49, 0, 1), huc_def(skl, 2, 0, 0))
#define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_) \
"i915/" \
@@ -371,6 +368,9 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
}
}
+ if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
+ uc_fw->private_data_size = css->private_data_size;
+
obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
index 23d3a423ac0f..99bb1fe1af66 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
@@ -88,6 +88,8 @@ struct intel_uc_fw {
u32 rsa_size;
u32 ucode_size;
+
+ u32 private_data_size;
};
#ifdef CONFIG_DRM_I915_DEBUG_GUC
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
index 029214cdedd5..e41ffc7a7fbc 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
@@ -69,7 +69,11 @@ struct uc_css_header {
#define CSS_SW_VERSION_UC_MAJOR (0xFF << 16)
#define CSS_SW_VERSION_UC_MINOR (0xFF << 8)
#define CSS_SW_VERSION_UC_PATCH (0xFF << 0)
- u32 reserved[14];
+ u32 reserved0[13];
+ union {
+ u32 private_data_size; /* only applies to GuC */
+ u32 reserved1;
+ };
u32 header_info;
} __packed;
static_assert(sizeof(struct uc_css_header) == 128);
diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c
index d7898e87791f..a15f87539657 100644
--- a/drivers/gpu/drm/i915/gvt/display.c
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -173,23 +173,164 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
int pipe;
if (IS_BROXTON(dev_priv)) {
- vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= ~(BXT_DE_PORT_HP_DDIA |
- BXT_DE_PORT_HP_DDIB |
- BXT_DE_PORT_HP_DDIC);
+ enum transcoder trans;
+ enum port port;
+
+ /* Clear PIPE, DDI, PHY, HPD before setting new */
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+ ~(GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) |
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) |
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_C));
+
+ for_each_pipe(dev_priv, pipe) {
+ vgpu_vreg_t(vgpu, PIPECONF(pipe)) &=
+ ~(PIPECONF_ENABLE | I965_PIPECONF_ACTIVE);
+ vgpu_vreg_t(vgpu, DSPCNTR(pipe)) &= ~DISPLAY_PLANE_ENABLE;
+ vgpu_vreg_t(vgpu, SPRCTL(pipe)) &= ~SPRITE_ENABLE;
+ vgpu_vreg_t(vgpu, CURCNTR(pipe)) &= ~MCURSOR_MODE;
+ vgpu_vreg_t(vgpu, CURCNTR(pipe)) |= MCURSOR_MODE_DISABLE;
+ }
+
+ for (trans = TRANSCODER_A; trans <= TRANSCODER_EDP; trans++) {
+ vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(trans)) &=
+ ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
+ TRANS_DDI_PORT_MASK | TRANS_DDI_FUNC_ENABLE);
+ }
+ vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &=
+ ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
+ TRANS_DDI_PORT_MASK);
+
+ for (port = PORT_A; port <= PORT_C; port++) {
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) &=
+ ~BXT_PHY_LANE_ENABLED;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) |=
+ (BXT_PHY_CMNLANE_POWERDOWN_ACK |
+ BXT_PHY_LANE_POWERDOWN_ACK);
+
+ vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(port)) &=
+ ~(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+ PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+ PORT_PLL_ENABLE);
+
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) &=
+ ~(DDI_INIT_DISPLAY_DETECTED |
+ DDI_BUF_CTL_ENABLE);
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) |= DDI_BUF_IS_IDLE;
+ }
+
+ vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= ~(BIT(0) | BIT(1));
+ vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &=
+ ~PHY_POWER_GOOD;
+ vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &=
+ ~PHY_POWER_GOOD;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= ~BIT(30);
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= ~BIT(30);
+
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIB_DETECTED;
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIC_DETECTED;
+
+ /*
+ * Only 1 PIPE enabled in current vGPU display and PIPE_A is
+ * tied to TRANSCODER_A in HW, so it's safe to assume PIPE_A,
+ * TRANSCODER_A can be enabled. PORT_x depends on the input of
+ * setup_virtual_dp_monitor.
+ */
+ vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE;
+ vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= I965_PIPECONF_ACTIVE;
+
+ /*
+ * Golden M/N are calculated based on:
+ * 24 bpp, 4 lanes, 154000 pixel clk (from virtual EDID),
+ * DP link clk 1620 MHz and non-constant_n.
+ * TODO: calculate DP link symbol clk and stream clk m/n.
+ */
+ vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) = 63 << TU_SIZE_SHIFT;
+ vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) |= 0x5b425e;
+ vgpu_vreg_t(vgpu, PIPE_DATA_N1(TRANSCODER_A)) = 0x800000;
+ vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A)) = 0x3cd6e;
+ vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)) = 0x80000;
+ /* Enable per-DDI/PORT vreg */
if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+ vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(1);
+ vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) |=
+ PHY_POWER_GOOD;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) |=
+ BIT(30);
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |=
+ BXT_PHY_LANE_ENABLED;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &=
+ ~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+ BXT_PHY_LANE_POWERDOWN_ACK);
+ vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_A)) |=
+ (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+ PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+ PORT_PLL_ENABLE);
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) |=
+ (DDI_BUF_CTL_ENABLE | DDI_INIT_DISPLAY_DETECTED);
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) &=
+ ~DDI_BUF_IS_IDLE;
+ vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)) |=
+ (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+ TRANS_DDI_FUNC_ENABLE);
vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
- BXT_DE_PORT_HP_DDIA;
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
}
if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIB_DETECTED;
+ vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0);
+ vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |=
+ PHY_POWER_GOOD;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |=
+ BIT(30);
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |=
+ BXT_PHY_LANE_ENABLED;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &=
+ ~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+ BXT_PHY_LANE_POWERDOWN_ACK);
+ vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_B)) |=
+ (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+ PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+ PORT_PLL_ENABLE);
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) |=
+ DDI_BUF_CTL_ENABLE;
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) &=
+ ~DDI_BUF_IS_IDLE;
+ vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
+ (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+ (PORT_B << TRANS_DDI_PORT_SHIFT) |
+ TRANS_DDI_FUNC_ENABLE);
vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
- BXT_DE_PORT_HP_DDIB;
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_B);
}
if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED;
+ vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0);
+ vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |=
+ PHY_POWER_GOOD;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |=
+ BIT(30);
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=
+ BXT_PHY_LANE_ENABLED;
+ vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &=
+ ~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+ BXT_PHY_LANE_POWERDOWN_ACK);
+ vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_C)) |=
+ (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+ PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+ PORT_PLL_ENABLE);
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) |=
+ DDI_BUF_CTL_ENABLE;
+ vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) &=
+ ~DDI_BUF_IS_IDLE;
+ vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
+ (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+ (PORT_B << TRANS_DDI_PORT_SHIFT) |
+ TRANS_DDI_FUNC_ENABLE);
vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
- BXT_DE_PORT_HP_DDIC;
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_C);
}
return;
@@ -327,7 +468,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
if (IS_BROADWELL(dev_priv))
vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
- GEN8_PORT_DP_A_HOTPLUG;
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
else
vgpu_vreg_t(vgpu, SDEISR) |= SDE_PORTA_HOTPLUG_SPT;
@@ -519,6 +660,45 @@ void intel_vgpu_emulate_hotplug(struct intel_vgpu *vgpu, bool connected)
vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
PORTD_HOTPLUG_STATUS_MASK;
intel_vgpu_trigger_virtual_event(vgpu, DP_D_HOTPLUG);
+ } else if (IS_BROXTON(i915)) {
+ if (connected) {
+ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
+ }
+ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
+ SFUSE_STRAP_DDIB_DETECTED;
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_B);
+ }
+ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
+ SFUSE_STRAP_DDIC_DETECTED;
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_C);
+ }
+ } else {
+ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+ ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
+ }
+ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) &=
+ ~SFUSE_STRAP_DDIB_DETECTED;
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+ ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_B);
+ }
+ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+ vgpu_vreg_t(vgpu, SFUSE_STRAP) &=
+ ~SFUSE_STRAP_DDIC_DETECTED;
+ vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+ ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_C);
+ }
+ }
+ vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+ PORTB_HOTPLUG_STATUS_MASK;
+ intel_vgpu_trigger_virtual_event(vgpu, DP_B_HOTPLUG);
}
}
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
index a3a4305eda01..897c007ea96a 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.c
+++ b/drivers/gpu/drm/i915/gvt/gtt.c
@@ -636,9 +636,18 @@ static void ggtt_set_host_entry(struct intel_vgpu_mm *mm,
struct intel_gvt_gtt_entry *entry, unsigned long index)
{
struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
+ unsigned long offset = index;
GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
+ if (vgpu_gmadr_is_aperture(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) {
+ offset -= (vgpu_aperture_gmadr_base(mm->vgpu) >> PAGE_SHIFT);
+ mm->ggtt_mm.host_ggtt_aperture[offset] = entry->val64;
+ } else if (vgpu_gmadr_is_hidden(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) {
+ offset -= (vgpu_hidden_gmadr_base(mm->vgpu) >> PAGE_SHIFT);
+ mm->ggtt_mm.host_ggtt_hidden[offset] = entry->val64;
+ }
+
pte_ops->set_entry(NULL, entry, index, false, 0, mm->vgpu);
}
@@ -1944,6 +1953,21 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
return ERR_PTR(-ENOMEM);
}
+ mm->ggtt_mm.host_ggtt_aperture = vzalloc((vgpu_aperture_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64));
+ if (!mm->ggtt_mm.host_ggtt_aperture) {
+ vfree(mm->ggtt_mm.virtual_ggtt);
+ vgpu_free_mm(mm);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mm->ggtt_mm.host_ggtt_hidden = vzalloc((vgpu_hidden_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64));
+ if (!mm->ggtt_mm.host_ggtt_hidden) {
+ vfree(mm->ggtt_mm.host_ggtt_aperture);
+ vfree(mm->ggtt_mm.virtual_ggtt);
+ vgpu_free_mm(mm);
+ return ERR_PTR(-ENOMEM);
+ }
+
return mm;
}
@@ -1971,6 +1995,8 @@ void _intel_vgpu_mm_release(struct kref *mm_ref)
invalidate_ppgtt_mm(mm);
} else {
vfree(mm->ggtt_mm.virtual_ggtt);
+ vfree(mm->ggtt_mm.host_ggtt_aperture);
+ vfree(mm->ggtt_mm.host_ggtt_hidden);
}
vgpu_free_mm(mm);
@@ -2852,3 +2878,41 @@ void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu)
intel_vgpu_destroy_all_ppgtt_mm(vgpu);
intel_vgpu_reset_ggtt(vgpu, true);
}
+
+/**
+ * intel_gvt_restore_ggtt - restore all vGPU's ggtt entries
+ * @gvt: intel gvt device
+ *
+ * This function is called at driver resume stage to restore
+ * GGTT entries of every vGPU.
+ *
+ */
+void intel_gvt_restore_ggtt(struct intel_gvt *gvt)
+{
+ struct intel_vgpu *vgpu;
+ struct intel_vgpu_mm *mm;
+ int id;
+ gen8_pte_t pte;
+ u32 idx, num_low, num_hi, offset;
+
+ /* Restore dirty host ggtt for all vGPUs */
+ idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) {
+ mm = vgpu->gtt.ggtt_mm;
+
+ num_low = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT;
+ offset = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT;
+ for (idx = 0; idx < num_low; idx++) {
+ pte = mm->ggtt_mm.host_ggtt_aperture[idx];
+ if (pte & _PAGE_PRESENT)
+ write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte);
+ }
+
+ num_hi = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
+ offset = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT;
+ for (idx = 0; idx < num_hi; idx++) {
+ pte = mm->ggtt_mm.host_ggtt_hidden[idx];
+ if (pte & _PAGE_PRESENT)
+ write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h
index 52d0d88abd86..b0e173f2d990 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.h
+++ b/drivers/gpu/drm/i915/gvt/gtt.h
@@ -164,6 +164,9 @@ struct intel_vgpu_mm {
} ppgtt_mm;
struct {
void *virtual_ggtt;
+ /* Save/restore for PM */
+ u64 *host_ggtt_aperture;
+ u64 *host_ggtt_hidden;
struct list_head partial_pte_list;
} ggtt_mm;
};
@@ -280,5 +283,6 @@ int intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu,
unsigned int off, void *p_data, unsigned int bytes);
void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu);
+void intel_gvt_restore_ggtt(struct intel_gvt *gvt);
#endif /* _GVT_GTT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index c7c561237883..d1d8ee4a5f16 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -312,7 +312,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915)
gvt_dbg_core("init gvt device\n");
- idr_init(&gvt->vgpu_idr);
+ idr_init_base(&gvt->vgpu_idr, 1);
spin_lock_init(&gvt->scheduler.mmio_context_lock);
mutex_init(&gvt->lock);
mutex_init(&gvt->sched_lock);
@@ -406,7 +406,16 @@ out_clean_idr:
}
int
-intel_gvt_register_hypervisor(struct intel_gvt_mpt *m)
+intel_gvt_pm_resume(struct intel_gvt *gvt)
+{
+ intel_gvt_restore_fence(gvt);
+ intel_gvt_restore_mmio(gvt);
+ intel_gvt_restore_ggtt(gvt);
+ return 0;
+}
+
+int
+intel_gvt_register_hypervisor(const struct intel_gvt_mpt *m)
{
int ret;
void *gvt;
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index a81cf0f01e78..cf3578e3f4dd 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -56,7 +56,7 @@ struct intel_gvt_host {
struct device *dev;
bool initialized;
int hypervisor_type;
- struct intel_gvt_mpt *mpt;
+ const struct intel_gvt_mpt *mpt;
};
extern struct intel_gvt_host intel_gvt_host;
@@ -255,6 +255,8 @@ struct intel_gvt_mmio {
#define F_CMD_ACCESS (1 << 3)
/* This reg has been accessed by a VM */
#define F_ACCESSED (1 << 4)
+/* This reg requires save & restore during host PM suspend/resume */
+#define F_PM_SAVE (1 << 5)
/* This reg could be accessed by unaligned address */
#define F_UNALIGN (1 << 6)
/* This reg is in GVT's mmio save-restor list and in hardware
@@ -685,6 +687,7 @@ void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu);
void intel_gvt_debugfs_init(struct intel_gvt *gvt);
void intel_gvt_debugfs_clean(struct intel_gvt *gvt);
+int intel_gvt_pm_resume(struct intel_gvt *gvt);
#include "trace.h"
#include "mpt.h"
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index eb342a759943..aa7e75cb3e6a 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -290,8 +290,8 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu,
case FORCEWAKE_RENDER_GEN9_REG:
ack_reg_offset = FORCEWAKE_ACK_RENDER_GEN9_REG;
break;
- case FORCEWAKE_BLITTER_GEN9_REG:
- ack_reg_offset = FORCEWAKE_ACK_BLITTER_GEN9_REG;
+ case FORCEWAKE_GT_GEN9_REG:
+ ack_reg_offset = FORCEWAKE_ACK_GT_GEN9_REG;
break;
case FORCEWAKE_MEDIA_GEN9_REG:
ack_reg_offset = FORCEWAKE_ACK_MEDIA_GEN9_REG;
@@ -2238,9 +2238,9 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
MMIO_D(PF_VSCALE(PIPE_C), D_ALL);
MMIO_D(PF_HSCALE(PIPE_C), D_ALL);
- MMIO_D(WM0_PIPEA_ILK, D_ALL);
- MMIO_D(WM0_PIPEB_ILK, D_ALL);
- MMIO_D(WM0_PIPEC_IVB, D_ALL);
+ MMIO_D(WM0_PIPE_ILK(PIPE_A), D_ALL);
+ MMIO_D(WM0_PIPE_ILK(PIPE_B), D_ALL);
+ MMIO_D(WM0_PIPE_ILK(PIPE_C), D_ALL);
MMIO_D(WM1_LP_ILK, D_ALL);
MMIO_D(WM2_LP_ILK, D_ALL);
MMIO_D(WM3_LP_ILK, D_ALL);
@@ -2930,8 +2930,8 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
MMIO_DH(FORCEWAKE_RENDER_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write);
MMIO_DH(FORCEWAKE_ACK_RENDER_GEN9, D_SKL_PLUS, NULL, NULL);
- MMIO_DH(FORCEWAKE_BLITTER_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write);
- MMIO_DH(FORCEWAKE_ACK_BLITTER_GEN9, D_SKL_PLUS, NULL, NULL);
+ MMIO_DH(FORCEWAKE_GT_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write);
+ MMIO_DH(FORCEWAKE_ACK_GT_GEN9, D_SKL_PLUS, NULL, NULL);
MMIO_DH(FORCEWAKE_MEDIA_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write);
MMIO_DH(FORCEWAKE_ACK_MEDIA_GEN9, D_SKL_PLUS, NULL, NULL);
@@ -3120,9 +3120,10 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
MMIO_DFH(TRVATTL3PTRDW(2), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(TRVATTL3PTRDW(3), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(TRVADR, D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL);
- MMIO_DFH(TRTTE, D_SKL_PLUS, F_CMD_ACCESS,
- NULL, gen9_trtte_write);
- MMIO_DH(_MMIO(0x4dfc), D_SKL_PLUS, NULL, gen9_trtt_chicken_write);
+ MMIO_DFH(TRTTE, D_SKL_PLUS, F_CMD_ACCESS | F_PM_SAVE,
+ NULL, gen9_trtte_write);
+ MMIO_DFH(_MMIO(0x4dfc), D_SKL_PLUS, F_PM_SAVE,
+ NULL, gen9_trtt_chicken_write);
MMIO_D(_MMIO(0x46430), D_SKL_PLUS);
@@ -3671,3 +3672,40 @@ default_rw:
intel_vgpu_default_mmio_read(vgpu, offset, pdata, bytes) :
intel_vgpu_default_mmio_write(vgpu, offset, pdata, bytes);
}
+
+void intel_gvt_restore_fence(struct intel_gvt *gvt)
+{
+ struct intel_vgpu *vgpu;
+ int i, id;
+
+ idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) {
+ mmio_hw_access_pre(gvt->gt);
+ for (i = 0; i < vgpu_fence_sz(vgpu); i++)
+ intel_vgpu_write_fence(vgpu, i, vgpu_vreg64(vgpu, fence_num_to_offset(i)));
+ mmio_hw_access_post(gvt->gt);
+ }
+}
+
+static inline int mmio_pm_restore_handler(struct intel_gvt *gvt,
+ u32 offset, void *data)
+{
+ struct intel_vgpu *vgpu = data;
+ struct drm_i915_private *dev_priv = gvt->gt->i915;
+
+ if (gvt->mmio.mmio_attribute[offset >> 2] & F_PM_SAVE)
+ I915_WRITE(_MMIO(offset), vgpu_vreg(vgpu, offset));
+
+ return 0;
+}
+
+void intel_gvt_restore_mmio(struct intel_gvt *gvt)
+{
+ struct intel_vgpu *vgpu;
+ int id;
+
+ idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) {
+ mmio_hw_access_pre(gvt->gt);
+ intel_gvt_for_each_tracked_mmio(gvt, mmio_pm_restore_handler, vgpu);
+ mmio_hw_access_post(gvt->gt);
+ }
+}
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 778eb8cab610..60f1a386dd06 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -2101,7 +2101,7 @@ static bool kvmgt_is_valid_gfn(unsigned long handle, unsigned long gfn)
return ret;
}
-static struct intel_gvt_mpt kvmgt_mpt = {
+static const struct intel_gvt_mpt kvmgt_mpt = {
.type = INTEL_GVT_HYPERVISOR_KVM,
.host_init = kvmgt_host_init,
.host_exit = kvmgt_host_exit,
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index b6811f6a230d..24210b1eaec5 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.c
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -280,6 +280,11 @@ void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr)
vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=
BXT_PHY_CMNLANE_POWERDOWN_ACK |
BXT_PHY_LANE_POWERDOWN_ACK;
+ vgpu_vreg_t(vgpu, SKL_FUSE_STATUS) |=
+ SKL_FUSE_DOWNLOAD_STATUS |
+ SKL_FUSE_PG_DIST_STATUS(SKL_PG0) |
+ SKL_FUSE_PG_DIST_STATUS(SKL_PG1) |
+ SKL_FUSE_PG_DIST_STATUS(SKL_PG2);
}
} else {
#define GVT_GEN8_MMIO_RESET_OFFSET (0x44200)
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
index cc4812648bf4..9e862dc73579 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.h
+++ b/drivers/gpu/drm/i915/gvt/mmio.h
@@ -104,4 +104,8 @@ int intel_vgpu_mmio_reg_rw(struct intel_vgpu *vgpu, unsigned int offset,
int intel_vgpu_mask_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes);
+
+void intel_gvt_restore_fence(struct intel_gvt *gvt);
+void intel_gvt_restore_mmio(struct intel_gvt *gvt);
+
#endif
diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
index 9ad224df9c68..6f92cde71971 100644
--- a/drivers/gpu/drm/i915/gvt/mpt.h
+++ b/drivers/gpu/drm/i915/gvt/mpt.h
@@ -392,7 +392,7 @@ static inline bool intel_gvt_hypervisor_is_valid_gfn(
return intel_gvt_host.mpt->is_valid_gfn(vgpu->handle, gfn);
}
-int intel_gvt_register_hypervisor(struct intel_gvt_mpt *);
+int intel_gvt_register_hypervisor(const struct intel_gvt_mpt *);
void intel_gvt_unregister_hypervisor(void);
#endif /* _GVT_MPT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index b88e033cbed4..b58860dee970 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -101,8 +101,8 @@
#define FORCEWAKE_RENDER_GEN9_REG 0xa278
#define FORCEWAKE_ACK_RENDER_GEN9_REG 0x0D84
-#define FORCEWAKE_BLITTER_GEN9_REG 0xa188
-#define FORCEWAKE_ACK_BLITTER_GEN9_REG 0x130044
+#define FORCEWAKE_GT_GEN9_REG 0xa188
+#define FORCEWAKE_ACK_GT_GEN9_REG 0x130044
#define FORCEWAKE_MEDIA_GEN9_REG 0xa270
#define FORCEWAKE_ACK_MEDIA_GEN9_REG 0x0D88
#define FORCEWAKE_ACK_HSW_REG 0x130044
diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
index 399582aeeefb..e49944fde333 100644
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -393,7 +393,7 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
mutex_init(&vgpu->dmabuf_lock);
INIT_LIST_HEAD(&vgpu->dmabuf_obj_list_head);
INIT_RADIX_TREE(&vgpu->page_track_tree, GFP_KERNEL);
- idr_init(&vgpu->object_idr);
+ idr_init_base(&vgpu->object_idr, 1);
intel_vgpu_init_cfg_space(vgpu, param->primary);
vgpu->d3_entered = false;
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index e88970256e8e..93265951fdbb 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -1452,43 +1452,42 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
* space. Parsing should be faster in some cases this way.
*/
batch_end = cmd + batch_length / sizeof(*batch_end);
- do {
- u32 length;
-
- if (*cmd == MI_BATCH_BUFFER_END)
- break;
-
- desc = find_cmd(engine, *cmd, desc, &default_desc);
- if (!desc) {
- DRM_DEBUG("CMD: Unrecognized command: 0x%08X\n", *cmd);
- ret = -EINVAL;
- break;
- }
+ while (*cmd != MI_BATCH_BUFFER_END) {
+ u32 length = 1;
+
+ if (*cmd != MI_NOOP) { /* MI_NOOP == 0 */
+ desc = find_cmd(engine, *cmd, desc, &default_desc);
+ if (!desc) {
+ DRM_DEBUG("CMD: Unrecognized command: 0x%08X\n", *cmd);
+ ret = -EINVAL;
+ break;
+ }
- if (desc->flags & CMD_DESC_FIXED)
- length = desc->length.fixed;
- else
- length = (*cmd & desc->length.mask) + LENGTH_BIAS;
+ if (desc->flags & CMD_DESC_FIXED)
+ length = desc->length.fixed;
+ else
+ length = (*cmd & desc->length.mask) + LENGTH_BIAS;
- if ((batch_end - cmd) < length) {
- DRM_DEBUG("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n",
- *cmd,
- length,
- batch_end - cmd);
- ret = -EINVAL;
- break;
- }
+ if ((batch_end - cmd) < length) {
+ DRM_DEBUG("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n",
+ *cmd,
+ length,
+ batch_end - cmd);
+ ret = -EINVAL;
+ break;
+ }
- if (!check_cmd(engine, desc, cmd, length)) {
- ret = -EACCES;
- break;
- }
+ if (!check_cmd(engine, desc, cmd, length)) {
+ ret = -EACCES;
+ break;
+ }
- if (cmd_desc_is(desc, MI_BATCH_BUFFER_START)) {
- ret = check_bbstart(cmd, offset, length, batch_length,
- batch_addr, shadow_addr,
- jump_whitelist);
- break;
+ if (cmd_desc_is(desc, MI_BATCH_BUFFER_START)) {
+ ret = check_bbstart(cmd, offset, length, batch_length,
+ batch_addr, shadow_addr,
+ jump_whitelist);
+ break;
+ }
}
if (!IS_ERR_OR_NULL(jump_whitelist))
@@ -1501,7 +1500,7 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
ret = -EINVAL;
break;
}
- } while (1);
+ }
if (trampoline) {
/*
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index ea469168cd44..77e76b665098 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -725,7 +725,7 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file)
gpu = NULL;
with_intel_runtime_pm(&i915->runtime_pm, wakeref)
- gpu = i915_gpu_coredump(i915);
+ gpu = i915_gpu_coredump(&i915->gt, ALL_ENGINES);
if (IS_ERR(gpu))
return PTR_ERR(gpu);
@@ -786,7 +786,6 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
struct intel_uncore *uncore = &dev_priv->uncore;
struct intel_rps *rps = &dev_priv->gt.rps;
intel_wakeref_t wakeref;
- int ret = 0;
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
@@ -1009,7 +1008,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
seq_printf(m, "Max pixel clock frequency: %d kHz\n", dev_priv->max_dotclk_freq);
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
- return ret;
+ return 0;
}
static int i915_ring_freq_table(struct seq_file *m, void *unused)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index acc32066cec3..320856b665a1 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -84,9 +84,10 @@
#include "intel_gvt.h"
#include "intel_memory_region.h"
#include "intel_pm.h"
+#include "intel_sideband.h"
#include "vlv_suspend.h"
-static struct drm_driver driver;
+static const struct drm_driver driver;
static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
{
@@ -616,6 +617,8 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
*/
intel_dram_detect(dev_priv);
+ intel_pcode_init(dev_priv);
+
intel_bw_init_hw(dev_priv);
return 0;
@@ -668,7 +671,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
/* Reveal our presence to userspace */
if (drm_dev_register(dev, 0) == 0) {
i915_debugfs_register(dev_priv);
- intel_display_debugfs_register(dev_priv);
+ if (HAS_DISPLAY(dev_priv))
+ intel_display_debugfs_register(dev_priv);
i915_setup_sysfs(dev_priv);
/* Depends on sysfs having been initialized */
@@ -840,9 +844,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i915->params.fake_lmem_start) {
mkwrite_device_info(i915)->memory_regions =
REGION_SMEM | REGION_LMEM | REGION_STOLEN;
- mkwrite_device_info(i915)->is_dgfx = true;
GEM_BUG_ON(!HAS_LMEM(i915));
- GEM_BUG_ON(!IS_DGFX(i915));
}
}
#endif
@@ -1036,6 +1038,35 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
drm_modeset_unlock_all(dev);
}
+static void intel_shutdown_encoders(struct drm_i915_private *dev_priv)
+{
+ struct drm_device *dev = &dev_priv->drm;
+ struct intel_encoder *encoder;
+
+ drm_modeset_lock_all(dev);
+ for_each_intel_encoder(dev, encoder)
+ if (encoder->shutdown)
+ encoder->shutdown(encoder);
+ drm_modeset_unlock_all(dev);
+}
+
+void i915_driver_shutdown(struct drm_i915_private *i915)
+{
+ i915_gem_suspend(i915);
+
+ drm_kms_helper_poll_disable(&i915->drm);
+
+ drm_atomic_helper_shutdown(&i915->drm);
+
+ intel_dp_mst_suspend(i915);
+
+ intel_runtime_pm_disable_interrupts(i915);
+ intel_hpd_cancel_work(i915);
+
+ intel_suspend_encoders(i915);
+ intel_shutdown_encoders(i915);
+}
+
static bool suspend_to_idle(struct drm_i915_private *dev_priv)
{
#if IS_ENABLED(CONFIG_ACPI_SLEEP)
@@ -1089,7 +1120,7 @@ static int i915_drm_suspend(struct drm_device *dev)
i915_ggtt_suspend(&dev_priv->ggtt);
- i915_save_state(dev_priv);
+ i915_save_display(dev_priv);
opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold;
intel_opregion_suspend(dev_priv, opregion_target_state);
@@ -1202,7 +1233,7 @@ static int i915_drm_resume(struct drm_device *dev)
intel_csr_ucode_resume(dev_priv);
- i915_restore_state(dev_priv);
+ i915_restore_display(dev_priv);
intel_pps_unlock_regs_wa(dev_priv);
intel_init_pch_refclk(dev_priv);
@@ -1225,32 +1256,23 @@ static int i915_drm_resume(struct drm_device *dev)
intel_modeset_init_hw(dev_priv);
intel_init_clock_gating(dev_priv);
+ intel_hpd_init(dev_priv);
- spin_lock_irq(&dev_priv->irq_lock);
- if (dev_priv->display.hpd_irq_setup)
- dev_priv->display.hpd_irq_setup(dev_priv);
- spin_unlock_irq(&dev_priv->irq_lock);
-
+ /* MST sideband requires HPD interrupts enabled */
intel_dp_mst_resume(dev_priv);
-
intel_display_resume(dev);
+ intel_hpd_poll_disable(dev_priv);
drm_kms_helper_poll_enable(dev);
- /*
- * ... but also need to make sure that hotplug processing
- * doesn't cause havoc. Like in the driver load code we don't
- * bother with the tiny race here where we might lose hotplug
- * notifications.
- * */
- intel_hpd_init(dev_priv);
-
intel_opregion_resume(dev_priv);
intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false);
intel_power_domains_enable(dev_priv);
+ intel_gvt_resume(dev_priv);
+
enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
return 0;
@@ -1556,7 +1578,7 @@ static int intel_runtime_suspend(struct device *kdev)
assert_forcewakes_inactive(&dev_priv->uncore);
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
- intel_hpd_poll_init(dev_priv);
+ intel_hpd_poll_enable(dev_priv);
drm_dbg_kms(&dev_priv->drm, "Device suspended\n");
return 0;
@@ -1601,8 +1623,10 @@ static int intel_runtime_resume(struct device *kdev)
* power well, so hpd is reinitialized from there. For
* everyone else do it here.
*/
- if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
+ if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) {
intel_hpd_init(dev_priv);
+ intel_hpd_poll_disable(dev_priv);
+ }
intel_enable_ipc(dev_priv);
@@ -1737,7 +1761,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_VM_DESTROY, i915_gem_vm_destroy_ioctl, DRM_RENDER_ALLOW),
};
-static struct drm_driver driver = {
+static const struct drm_driver driver = {
/* Don't use MTRRs here; the Xserver or userspace app should
* deal with them for Intel hardware.
*/
@@ -1750,12 +1774,8 @@ static struct drm_driver driver = {
.lastclose = i915_driver_lastclose,
.postclose = i915_driver_postclose,
- .gem_close_object = i915_gem_close_object,
- .gem_free_object_unlocked = i915_gem_free_object,
-
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
- .gem_prime_export = i915_gem_prime_export,
.gem_prime_import = i915_gem_prime_import,
.dumb_create = i915_gem_dumb_create,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8426d5974669..15be8debae54 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -110,8 +110,8 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20200917"
-#define DRIVER_TIMESTAMP 1600375437
+#define DRIVER_DATE "20201103"
+#define DRIVER_TIMESTAMP 1604406085
struct drm_i915_gem_object;
@@ -508,7 +508,6 @@ struct i915_psr {
bool dc3co_enabled;
u32 dc3co_exit_delay;
struct delayed_work dc3co_work;
- bool force_mode_changed;
struct drm_dp_vsc_sdp vsc;
};
@@ -1419,7 +1418,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define IS_COMETLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_COMETLAKE)
#define IS_CANNONLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_CANNONLAKE)
#define IS_ICELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ICELAKE)
-#define IS_ELKHARTLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE)
+#define IS_JSL_EHL(dev_priv) (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE) || \
+ IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE))
#define IS_TIGERLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_TIGERLAKE)
#define IS_ROCKETLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ROCKETLAKE)
#define IS_DG1(dev_priv) IS_PLATFORM(dev_priv, INTEL_DG1)
@@ -1559,9 +1559,10 @@ extern const struct i915_rev_steppings kbl_revids[];
(IS_ICELAKE(p) && IS_REVID(p, since, until))
#define EHL_REVID_A0 0x0
+#define EHL_REVID_B0 0x1
-#define IS_EHL_REVID(p, since, until) \
- (IS_ELKHARTLAKE(p) && IS_REVID(p, since, until))
+#define IS_JSL_EHL_REVID(p, since, until) \
+ (IS_JSL_EHL(p) && IS_REVID(p, since, until))
enum {
TGL_REVID_A0,
@@ -1640,8 +1641,7 @@ tgl_revids_get(struct drm_i915_private *dev_priv)
#define HAS_SNOOP(dev_priv) (INTEL_INFO(dev_priv)->has_snoop)
#define HAS_EDRAM(dev_priv) ((dev_priv)->edram_size_mb)
#define HAS_SECURE_BATCHES(dev_priv) (INTEL_GEN(dev_priv) < 6)
-#define HAS_WT(dev_priv) ((IS_HASWELL(dev_priv) || \
- IS_BROADWELL(dev_priv)) && HAS_EDRAM(dev_priv))
+#define HAS_WT(dev_priv) HAS_EDRAM(dev_priv)
#define HWS_NEEDS_PHYSICAL(dev_priv) (INTEL_INFO(dev_priv)->hws_needs_physical)
@@ -1783,6 +1783,7 @@ extern const struct dev_pm_ops i915_pm_ops;
int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
void i915_driver_remove(struct drm_i915_private *i915);
+void i915_driver_shutdown(struct drm_i915_private *i915);
int i915_resume_switcheroo(struct drm_i915_private *i915);
int i915_suspend_switcheroo(struct drm_i915_private *i915, pm_message_t state);
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 6501939929d5..e1a66c8245b8 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -238,7 +238,7 @@ found:
}
/**
- * i915_gem_evict_for_vma - Evict vmas to make room for binding a new one
+ * i915_gem_evict_for_node - Evict vmas to make room for binding a new one
* @vm: address space to evict from
* @target: range (and color) to evict for
* @flags: additional flags to control the eviction algorithm
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index cf6e47adfde6..d8cac4c5881f 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -570,6 +570,7 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
ee->vm_info.pp_dir_base);
}
}
+ err_printf(m, " hung: %u\n", ee->hung);
err_printf(m, " engine reset count: %u\n", ee->reset_count);
for (n = 0; n < ee->num_ports; n++) {
@@ -1026,6 +1027,7 @@ i915_vma_coredump_create(const struct intel_gt *gt,
dma_addr_t dma;
for_each_sgt_daddr(dma, iter, vma->pages) {
+ mutex_lock(&ggtt->error_mutex);
ggtt->vm.insert_page(&ggtt->vm, dma, slot,
I915_CACHE_NONE, 0);
mb();
@@ -1035,6 +1037,10 @@ i915_vma_coredump_create(const struct intel_gt *gt,
(void __force *)s, dst,
true);
io_mapping_unmap(s);
+
+ mb();
+ ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE);
+ mutex_unlock(&ggtt->error_mutex);
if (ret)
break;
}
@@ -1451,6 +1457,7 @@ capture_engine(struct intel_engine_cs *engine,
static void
gt_record_engines(struct intel_gt_coredump *gt,
+ intel_engine_mask_t engine_mask,
struct i915_vma_compress *compress)
{
struct intel_engine_cs *engine;
@@ -1466,6 +1473,8 @@ gt_record_engines(struct intel_gt_coredump *gt,
if (!ee)
continue;
+ ee->hung = engine->mask & engine_mask;
+
gt->simulated |= ee->simulated;
if (ee->simulated) {
kfree(ee);
@@ -1505,25 +1514,6 @@ gt_record_uc(struct intel_gt_coredump *gt,
return error_uc;
}
-static void gt_capture_prepare(struct intel_gt_coredump *gt)
-{
- struct i915_ggtt *ggtt = gt->_gt->ggtt;
-
- mutex_lock(&ggtt->error_mutex);
-}
-
-static void gt_capture_finish(struct intel_gt_coredump *gt)
-{
- struct i915_ggtt *ggtt = gt->_gt->ggtt;
-
- if (drm_mm_node_allocated(&ggtt->error_capture))
- ggtt->vm.clear_range(&ggtt->vm,
- ggtt->error_capture.start,
- PAGE_SIZE);
-
- mutex_unlock(&ggtt->error_mutex);
-}
-
/* Capture all registers which don't fit into another category. */
static void gt_record_regs(struct intel_gt_coredump *gt)
{
@@ -1669,24 +1659,25 @@ static u32 generate_ecode(const struct intel_engine_coredump *ee)
static const char *error_msg(struct i915_gpu_coredump *error)
{
struct intel_engine_coredump *first = NULL;
+ unsigned int hung_classes = 0;
struct intel_gt_coredump *gt;
- intel_engine_mask_t engines;
int len;
- engines = 0;
for (gt = error->gt; gt; gt = gt->next) {
struct intel_engine_coredump *cs;
- if (gt->engine && !first)
- first = gt->engine;
-
- for (cs = gt->engine; cs; cs = cs->next)
- engines |= cs->engine->mask;
+ for (cs = gt->engine; cs; cs = cs->next) {
+ if (cs->hung) {
+ hung_classes |= BIT(cs->engine->uabi_class);
+ if (!first)
+ first = cs;
+ }
+ }
}
len = scnprintf(error->error_msg, sizeof(error->error_msg),
"GPU HANG: ecode %d:%x:%08x",
- INTEL_GEN(error->i915), engines,
+ INTEL_GEN(error->i915), hung_classes,
generate_ecode(first));
if (first && first->context.pid) {
/* Just show the first executing process, more is confusing */
@@ -1782,8 +1773,6 @@ i915_vma_capture_prepare(struct intel_gt_coredump *gt)
return NULL;
}
- gt_capture_prepare(gt);
-
return compress;
}
@@ -1793,14 +1782,14 @@ void i915_vma_capture_finish(struct intel_gt_coredump *gt,
if (!compress)
return;
- gt_capture_finish(gt);
-
compress_fini(compress);
kfree(compress);
}
-struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915)
+struct i915_gpu_coredump *
+i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
{
+ struct drm_i915_private *i915 = gt->i915;
struct i915_gpu_coredump *error;
/* Check if GPU capture has been disabled */
@@ -1812,7 +1801,7 @@ struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915)
if (!error)
return ERR_PTR(-ENOMEM);
- error->gt = intel_gt_coredump_alloc(&i915->gt, ALLOW_FAIL);
+ error->gt = intel_gt_coredump_alloc(gt, ALLOW_FAIL);
if (error->gt) {
struct i915_vma_compress *compress;
@@ -1824,7 +1813,7 @@ struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915)
}
gt_record_info(error->gt);
- gt_record_engines(error->gt, compress);
+ gt_record_engines(error->gt, engine_mask, compress);
if (INTEL_INFO(i915)->has_gt_uc)
error->gt->uc = gt_record_uc(error->gt, compress);
@@ -1871,20 +1860,23 @@ void i915_error_state_store(struct i915_gpu_coredump *error)
/**
* i915_capture_error_state - capture an error record for later analysis
- * @i915: i915 device
+ * @gt: intel_gt which originated the hang
+ * @engine_mask: hung engines
+ *
*
* Should be called when an error is detected (either a hang or an error
* interrupt) to capture error state from the time of the error. Fills
* out a structure which becomes available in debugfs for user level tools
* to pick up.
*/
-void i915_capture_error_state(struct drm_i915_private *i915)
+void i915_capture_error_state(struct intel_gt *gt,
+ intel_engine_mask_t engine_mask)
{
struct i915_gpu_coredump *error;
- error = i915_gpu_coredump(i915);
+ error = i915_gpu_coredump(gt, engine_mask);
if (IS_ERR(error)) {
- cmpxchg(&i915->gpu_error.first_error, NULL, error);
+ cmpxchg(&gt->i915->gpu_error.first_error, NULL, error);
return;
}
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
index 0220b0992808..16bc42de4b84 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.h
+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
@@ -59,6 +59,7 @@ struct i915_request_coredump {
struct intel_engine_coredump {
const struct intel_engine_cs *engine;
+ bool hung;
bool simulated;
u32 reset_count;
@@ -218,8 +219,10 @@ struct drm_i915_error_state_buf {
__printf(2, 3)
void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
-struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915);
-void i915_capture_error_state(struct drm_i915_private *i915);
+struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt,
+ intel_engine_mask_t engine_mask);
+void i915_capture_error_state(struct intel_gt *gt,
+ intel_engine_mask_t engine_mask);
struct i915_gpu_coredump *
i915_gpu_coredump_alloc(struct drm_i915_private *i915, gfp_t gfp);
@@ -271,7 +274,8 @@ void i915_disable_error_state(struct drm_i915_private *i915, int err);
#else
-static inline void i915_capture_error_state(struct drm_i915_private *i915)
+static inline void
+i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask)
{
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 759f523c6a6b..dc6febc63f1c 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -61,6 +61,8 @@
*/
typedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val);
+typedef u32 (*hotplug_enables_func)(struct drm_i915_private *i915,
+ enum hpd_pin pin);
static const u32 hpd_ilk[HPD_NUM_PINS] = {
[HPD_PORT_A] = DE_DP_A_HOTPLUG,
@@ -71,7 +73,7 @@ static const u32 hpd_ivb[HPD_NUM_PINS] = {
};
static const u32 hpd_bdw[HPD_NUM_PINS] = {
- [HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG,
+ [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A),
};
static const u32 hpd_ibx[HPD_NUM_PINS] = {
@@ -126,30 +128,37 @@ static const u32 hpd_status_i915[HPD_NUM_PINS] = {
};
static const u32 hpd_bxt[HPD_NUM_PINS] = {
- [HPD_PORT_A] = BXT_DE_PORT_HP_DDIA,
- [HPD_PORT_B] = BXT_DE_PORT_HP_DDIB,
- [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC,
+ [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A),
+ [HPD_PORT_B] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_B),
+ [HPD_PORT_C] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_C),
};
static const u32 hpd_gen11[HPD_NUM_PINS] = {
- [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(PORT_TC1) | GEN11_TBT_HOTPLUG(PORT_TC1),
- [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(PORT_TC2) | GEN11_TBT_HOTPLUG(PORT_TC2),
- [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(PORT_TC3) | GEN11_TBT_HOTPLUG(PORT_TC3),
- [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(PORT_TC4) | GEN11_TBT_HOTPLUG(PORT_TC4),
- [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(PORT_TC5) | GEN11_TBT_HOTPLUG(PORT_TC5),
- [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(PORT_TC6) | GEN11_TBT_HOTPLUG(PORT_TC6),
+ [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(HPD_PORT_TC1) | GEN11_TBT_HOTPLUG(HPD_PORT_TC1),
+ [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(HPD_PORT_TC2) | GEN11_TBT_HOTPLUG(HPD_PORT_TC2),
+ [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(HPD_PORT_TC3) | GEN11_TBT_HOTPLUG(HPD_PORT_TC3),
+ [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(HPD_PORT_TC4) | GEN11_TBT_HOTPLUG(HPD_PORT_TC4),
+ [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(HPD_PORT_TC5) | GEN11_TBT_HOTPLUG(HPD_PORT_TC5),
+ [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(HPD_PORT_TC6) | GEN11_TBT_HOTPLUG(HPD_PORT_TC6),
};
static const u32 hpd_icp[HPD_NUM_PINS] = {
- [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(PORT_A),
- [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B),
- [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C),
- [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
- [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
- [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
- [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
- [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(PORT_TC5),
- [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(PORT_TC6),
+ [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A),
+ [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B),
+ [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C),
+ [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1),
+ [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2),
+ [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3),
+ [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4),
+ [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC5),
+ [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC6),
+};
+
+static const u32 hpd_sde_dg1[HPD_NUM_PINS] = {
+ [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A),
+ [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B),
+ [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C),
+ [HPD_PORT_D] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_D),
};
static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
@@ -176,11 +185,14 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
else
hpd->hpd = hpd_ilk;
- if (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))
+ if ((INTEL_PCH_TYPE(dev_priv) < PCH_DG1) &&
+ (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv)))
return;
- if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
- HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
+ if (HAS_PCH_DG1(dev_priv))
+ hpd->pch_hpd = hpd_sde_dg1;
+ else if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
+ HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
hpd->pch_hpd = hpd_icp;
else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
hpd->pch_hpd = hpd_spt;
@@ -337,17 +349,14 @@ void ilk_update_display_irq(struct drm_i915_private *dev_priv,
u32 new_val;
lockdep_assert_held(&dev_priv->irq_lock);
-
drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
- if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
- return;
-
new_val = dev_priv->irq_mask;
new_val &= ~interrupt_mask;
new_val |= (~enabled_irq_mask & interrupt_mask);
- if (new_val != dev_priv->irq_mask) {
+ if (new_val != dev_priv->irq_mask &&
+ !drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv))) {
dev_priv->irq_mask = new_val;
I915_WRITE(DEIMR, dev_priv->irq_mask);
POSTING_READ(DEIMR);
@@ -682,8 +691,12 @@ u32 i915_get_vblank_counter(struct drm_crtc *crtc)
u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+ struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ if (!vblank->max_vblank_count)
+ return 0;
+
return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
}
@@ -1031,17 +1044,17 @@ static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
{
switch (pin) {
case HPD_PORT_TC1:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1);
+ return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC1);
case HPD_PORT_TC2:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2);
+ return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC2);
case HPD_PORT_TC3:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3);
+ return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC3);
case HPD_PORT_TC4:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
+ return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC4);
case HPD_PORT_TC5:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC5);
+ return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC5);
case HPD_PORT_TC6:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC6);
+ return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC6);
default:
return false;
}
@@ -1065,11 +1078,13 @@ static bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
{
switch (pin) {
case HPD_PORT_A:
- return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_A);
+ return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_A);
case HPD_PORT_B:
- return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_B);
+ return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_B);
case HPD_PORT_C:
- return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_C);
+ return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_C);
+ case HPD_PORT_D:
+ return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_D);
default:
return false;
}
@@ -1079,17 +1094,17 @@ static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
{
switch (pin) {
case HPD_PORT_TC1:
- return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1);
+ return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC1);
case HPD_PORT_TC2:
- return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2);
+ return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC2);
case HPD_PORT_TC3:
- return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3);
+ return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC3);
case HPD_PORT_TC4:
- return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
+ return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC4);
case HPD_PORT_TC5:
- return val & ICP_TC_HPD_LONG_DETECT(PORT_TC5);
+ return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC5);
case HPD_PORT_TC6:
- return val & ICP_TC_HPD_LONG_DETECT(PORT_TC6);
+ return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC6);
default:
return false;
}
@@ -1192,6 +1207,43 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv,
}
+static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
+ const u32 hpd[HPD_NUM_PINS])
+{
+ struct intel_encoder *encoder;
+ u32 enabled_irqs = 0;
+
+ for_each_intel_encoder(&dev_priv->drm, encoder)
+ if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
+ enabled_irqs |= hpd[encoder->hpd_pin];
+
+ return enabled_irqs;
+}
+
+static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
+ const u32 hpd[HPD_NUM_PINS])
+{
+ struct intel_encoder *encoder;
+ u32 hotplug_irqs = 0;
+
+ for_each_intel_encoder(&dev_priv->drm, encoder)
+ hotplug_irqs |= hpd[encoder->hpd_pin];
+
+ return hotplug_irqs;
+}
+
+static u32 intel_hpd_hotplug_enables(struct drm_i915_private *i915,
+ hotplug_enables_func hotplug_enables)
+{
+ struct intel_encoder *encoder;
+ u32 hotplug = 0;
+
+ for_each_intel_encoder(&i915->drm, encoder)
+ hotplug |= hotplug_enables(i915, encoder->hpd_pin);
+
+ return hotplug;
+}
+
static void gmbus_irq_handler(struct drm_i915_private *dev_priv)
{
wake_up_all(&dev_priv->gmbus_wait_queue);
@@ -1245,6 +1297,23 @@ display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
u32 crc4) {}
#endif
+static void flip_done_handler(struct drm_i915_private *i915,
+ enum pipe pipe)
+{
+ struct intel_crtc *crtc = intel_get_crtc_for_pipe(i915, pipe);
+ struct drm_crtc_state *crtc_state = crtc->base.state;
+ struct drm_pending_vblank_event *e = crtc_state->event;
+ struct drm_device *dev = &i915->drm;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev->event_lock, irqflags);
+
+ crtc_state->event = NULL;
+
+ drm_crtc_send_vblank_event(&crtc->base, e);
+
+ spin_unlock_irqrestore(&dev->event_lock, irqflags);
+}
static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
enum pipe pipe)
@@ -1840,27 +1909,10 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
{
- u32 ddi_hotplug_trigger, tc_hotplug_trigger;
+ u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP;
+ u32 tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_MASK_ICP;
u32 pin_mask = 0, long_mask = 0;
- if (HAS_PCH_TGP(dev_priv)) {
- ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
- tc_hotplug_trigger = pch_iir & SDE_TC_MASK_TGP;
- } else if (HAS_PCH_JSP(dev_priv)) {
- ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
- tc_hotplug_trigger = 0;
- } else if (HAS_PCH_MCC(dev_priv)) {
- ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
- tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1);
- } else {
- drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv),
- "Unrecognized PCH type 0x%x\n",
- INTEL_PCH_TYPE(dev_priv));
-
- ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
- tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP;
- }
-
if (ddi_hotplug_trigger) {
u32 dig_hotplug_reg;
@@ -2237,6 +2289,63 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n");
}
+static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv,
+ u32 te_trigger)
+{
+ enum pipe pipe = INVALID_PIPE;
+ enum transcoder dsi_trans;
+ enum port port;
+ u32 val, tmp;
+
+ /*
+ * Incase of dual link, TE comes from DSI_1
+ * this is to check if dual link is enabled
+ */
+ val = I915_READ(TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0));
+ val &= PORT_SYNC_MODE_ENABLE;
+
+ /*
+ * if dual link is enabled, then read DSI_0
+ * transcoder registers
+ */
+ port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ?
+ PORT_A : PORT_B;
+ dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1;
+
+ /* Check if DSI configured in command mode */
+ val = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans));
+ val = val & OP_MODE_MASK;
+
+ if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) {
+ drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n");
+ return;
+ }
+
+ /* Get PIPE for handling VBLANK event */
+ val = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+ switch (val & TRANS_DDI_EDP_INPUT_MASK) {
+ case TRANS_DDI_EDP_INPUT_A_ON:
+ pipe = PIPE_A;
+ break;
+ case TRANS_DDI_EDP_INPUT_B_ONOFF:
+ pipe = PIPE_B;
+ break;
+ case TRANS_DDI_EDP_INPUT_C_ONOFF:
+ pipe = PIPE_C;
+ break;
+ default:
+ drm_err(&dev_priv->drm, "Invalid PIPE\n");
+ return;
+ }
+
+ intel_handle_vblank(dev_priv, pipe);
+
+ /* clear TE in dsi IIR */
+ port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A;
+ tmp = I915_READ(DSI_INTR_IDENT_REG(port));
+ I915_WRITE(DSI_INTR_IDENT_REG(port), tmp);
+}
+
static irqreturn_t
gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
{
@@ -2271,7 +2380,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
if (master_ctl & GEN8_DE_PORT_IRQ) {
iir = I915_READ(GEN8_DE_PORT_IIR);
if (iir) {
- u32 tmp_mask;
bool found = false;
I915_WRITE(GEN8_DE_PORT_IIR, iir);
@@ -2283,15 +2391,17 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
}
if (IS_GEN9_LP(dev_priv)) {
- tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
- if (tmp_mask) {
- bxt_hpd_irq_handler(dev_priv, tmp_mask);
+ u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK;
+
+ if (hotplug_trigger) {
+ bxt_hpd_irq_handler(dev_priv, hotplug_trigger);
found = true;
}
} else if (IS_BROADWELL(dev_priv)) {
- tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
- if (tmp_mask) {
- ilk_hpd_irq_handler(dev_priv, tmp_mask);
+ u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK;
+
+ if (hotplug_trigger) {
+ ilk_hpd_irq_handler(dev_priv, hotplug_trigger);
found = true;
}
}
@@ -2301,6 +2411,15 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
found = true;
}
+ if (INTEL_GEN(dev_priv) >= 11) {
+ u32 te_trigger = iir & (DSI0_TE | DSI1_TE);
+
+ if (te_trigger) {
+ gen11_dsi_te_interrupt_handler(dev_priv, te_trigger);
+ found = true;
+ }
+ }
+
if (!found)
drm_err(&dev_priv->drm,
"Unexpected DE Port interrupt\n");
@@ -2329,6 +2448,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
if (iir & GEN8_PIPE_VBLANK)
intel_handle_vblank(dev_priv, pipe);
+ if (iir & GEN9_PIPE_PLANE1_FLIP_DONE)
+ flip_done_handler(dev_priv, pipe);
+
if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
hsw_pipe_crc_irq_handler(dev_priv, pipe);
@@ -2631,12 +2753,47 @@ int ilk_enable_vblank(struct drm_crtc *crtc)
return 0;
}
+static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc,
+ bool enable)
+{
+ struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+ enum port port;
+ u32 tmp;
+
+ if (!(intel_crtc->mode_flags &
+ (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0)))
+ return false;
+
+ /* for dual link cases we consider TE from slave */
+ if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1)
+ port = PORT_B;
+ else
+ port = PORT_A;
+
+ tmp = I915_READ(DSI_INTR_MASK_REG(port));
+ if (enable)
+ tmp &= ~DSI_TE_EVENT;
+ else
+ tmp |= DSI_TE_EVENT;
+
+ I915_WRITE(DSI_INTR_MASK_REG(port), tmp);
+
+ tmp = I915_READ(DSI_INTR_IDENT_REG(port));
+ I915_WRITE(DSI_INTR_IDENT_REG(port), tmp);
+
+ return true;
+}
+
int bdw_enable_vblank(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
- enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ enum pipe pipe = intel_crtc->pipe;
unsigned long irqflags;
+ if (gen11_dsi_configure_te(intel_crtc, true))
+ return 0;
+
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -2650,6 +2807,19 @@ int bdw_enable_vblank(struct drm_crtc *crtc)
return 0;
}
+void skl_enable_flip_done(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&i915->irq_lock, irqflags);
+
+ bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE);
+
+ spin_unlock_irqrestore(&i915->irq_lock, irqflags);
+}
+
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
@@ -2702,14 +2872,31 @@ void ilk_disable_vblank(struct drm_crtc *crtc)
void bdw_disable_vblank(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
- enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ enum pipe pipe = intel_crtc->pipe;
unsigned long irqflags;
+ if (gen11_dsi_configure_te(intel_crtc, false))
+ return;
+
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
+void skl_disable_flip_done(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&i915->irq_lock, irqflags);
+
+ bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE);
+
+ spin_unlock_irqrestore(&i915->irq_lock, irqflags);
+}
+
static void ibx_irq_reset(struct drm_i915_private *dev_priv)
{
struct intel_uncore *uncore = &dev_priv->uncore;
@@ -2723,24 +2910,6 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv)
I915_WRITE(SERR_INT, 0xffffffff);
}
-/*
- * SDEIER is also touched by the interrupt handler to work around missed PCH
- * interrupts. Hence we can't update it after the interrupt handler is enabled -
- * instead we unconditionally enable all PCH interrupt sources here, but then
- * only unmask them as needed with SDEIMR.
- *
- * This function needs to be called before interrupts are enabled.
- */
-static void ibx_irq_pre_postinstall(struct drm_i915_private *dev_priv)
-{
- if (HAS_PCH_NOP(dev_priv))
- return;
-
- drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0);
- I915_WRITE(SDEIER, 0xffffffff);
- POSTING_READ(SDEIER);
-}
-
static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
{
struct intel_uncore *uncore = &dev_priv->uncore;
@@ -2797,6 +2966,8 @@ static void ilk_irq_reset(struct drm_i915_private *dev_priv)
struct intel_uncore *uncore = &dev_priv->uncore;
GEN3_IRQ_RESET(uncore, DE);
+ dev_priv->irq_mask = ~0u;
+
if (IS_GEN(dev_priv, 7))
intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff);
@@ -2887,8 +3058,10 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv)
if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
GEN3_IRQ_RESET(uncore, SDE);
- /* Wa_14010685332:icl,jsl,ehl,tgl,rkl */
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
+ /* Wa_14010685332:cnp/cmp,tgp,adp */
+ if (INTEL_PCH_TYPE(dev_priv) == PCH_CNP ||
+ (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP &&
+ INTEL_PCH_TYPE(dev_priv) < PCH_DG1)) {
intel_uncore_rmw(uncore, SOUTH_CHICKEN1,
SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS);
intel_uncore_rmw(uncore, SOUTH_CHICKEN1,
@@ -2920,6 +3093,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
enum pipe pipe;
+ if (INTEL_GEN(dev_priv) >= 9)
+ extra_ier |= GEN9_PIPE_PLANE1_FLIP_DONE;
+
spin_lock_irq(&dev_priv->irq_lock);
if (!intel_irqs_enabled(dev_priv)) {
@@ -2974,29 +3150,29 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock);
}
-static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
- const u32 hpd[HPD_NUM_PINS])
+static u32 ibx_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
{
- struct intel_encoder *encoder;
- u32 enabled_irqs = 0;
-
- for_each_intel_encoder(&dev_priv->drm, encoder)
- if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
- enabled_irqs |= hpd[encoder->hpd_pin];
-
- return enabled_irqs;
-}
-
-static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
- const u32 hpd[HPD_NUM_PINS])
-{
- struct intel_encoder *encoder;
- u32 hotplug_irqs = 0;
-
- for_each_intel_encoder(&dev_priv->drm, encoder)
- hotplug_irqs |= hpd[encoder->hpd_pin];
-
- return hotplug_irqs;
+ switch (pin) {
+ case HPD_PORT_A:
+ /*
+ * When CPU and PCH are on the same package, port A
+ * HPD must be enabled in both north and south.
+ */
+ return HAS_PCH_LPT_LP(i915) ?
+ PORTA_HOTPLUG_ENABLE : 0;
+ case HPD_PORT_B:
+ return PORTB_HOTPLUG_ENABLE |
+ PORTB_PULSE_DURATION_2ms;
+ case HPD_PORT_C:
+ return PORTC_HOTPLUG_ENABLE |
+ PORTC_PULSE_DURATION_2ms;
+ case HPD_PORT_D:
+ return PORTD_HOTPLUG_ENABLE |
+ PORTD_PULSE_DURATION_2ms;
+ default:
+ return 0;
+ }
}
static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
@@ -3009,18 +3185,14 @@ static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
* The pulse duration bits are reserved on LPT+.
*/
hotplug = I915_READ(PCH_PORT_HOTPLUG);
- hotplug &= ~(PORTB_PULSE_DURATION_MASK |
+ hotplug &= ~(PORTA_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE |
+ PORTC_HOTPLUG_ENABLE |
+ PORTD_HOTPLUG_ENABLE |
+ PORTB_PULSE_DURATION_MASK |
PORTC_PULSE_DURATION_MASK |
PORTD_PULSE_DURATION_MASK);
- hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
- hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
- hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
- /*
- * When CPU and PCH are on the same package, port A
- * HPD must be enabled in both north and south.
- */
- if (HAS_PCH_LPT_LP(dev_priv))
- hotplug |= PORTA_HOTPLUG_ENABLE;
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables);
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
}
@@ -3036,28 +3208,65 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
ibx_hpd_detection_setup(dev_priv);
}
-static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv,
- u32 enable_mask)
+static u32 icp_ddi_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
+{
+ switch (pin) {
+ case HPD_PORT_A:
+ case HPD_PORT_B:
+ case HPD_PORT_C:
+ case HPD_PORT_D:
+ return SHOTPLUG_CTL_DDI_HPD_ENABLE(pin);
+ default:
+ return 0;
+ }
+}
+
+static u32 icp_tc_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
+{
+ switch (pin) {
+ case HPD_PORT_TC1:
+ case HPD_PORT_TC2:
+ case HPD_PORT_TC3:
+ case HPD_PORT_TC4:
+ case HPD_PORT_TC5:
+ case HPD_PORT_TC6:
+ return ICP_TC_HPD_ENABLE(pin);
+ default:
+ return 0;
+ }
+}
+
+static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
u32 hotplug;
hotplug = I915_READ(SHOTPLUG_CTL_DDI);
- hotplug |= enable_mask;
+ hotplug &= ~(SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) |
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) |
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) |
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D));
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables);
I915_WRITE(SHOTPLUG_CTL_DDI, hotplug);
}
-static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv,
- u32 enable_mask)
+static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
u32 hotplug;
hotplug = I915_READ(SHOTPLUG_CTL_TC);
- hotplug |= enable_mask;
+ hotplug &= ~(ICP_TC_HPD_ENABLE(HPD_PORT_TC1) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC2) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC3) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC4) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC5) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC6));
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables);
I915_WRITE(SHOTPLUG_CTL_TC, hotplug);
}
-static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
- u32 ddi_enable_mask, u32 tc_enable_mask)
+static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv)
{
u32 hotplug_irqs, enabled_irqs;
@@ -3069,52 +3278,67 @@ static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
- icp_ddi_hpd_detection_setup(dev_priv, ddi_enable_mask);
- if (tc_enable_mask)
- icp_tc_hpd_detection_setup(dev_priv, tc_enable_mask);
+ icp_ddi_hpd_detection_setup(dev_priv);
+ icp_tc_hpd_detection_setup(dev_priv);
}
-/*
- * EHL doesn't need most of gen11_hpd_irq_setup, it's handling only the
- * equivalent of SDE.
- */
-static void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv)
+static u32 gen11_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
{
- icp_hpd_irq_setup(dev_priv,
- ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE(PORT_TC1));
+ switch (pin) {
+ case HPD_PORT_TC1:
+ case HPD_PORT_TC2:
+ case HPD_PORT_TC3:
+ case HPD_PORT_TC4:
+ case HPD_PORT_TC5:
+ case HPD_PORT_TC6:
+ return GEN11_HOTPLUG_CTL_ENABLE(pin);
+ default:
+ return 0;
+ }
}
-/*
- * JSP behaves exactly the same as MCC above except that port C is mapped to
- * the DDI-C pins instead of the TC1 pins. This means we should follow TGP's
- * masks & tables rather than ICP's masks & tables.
- */
-static void jsp_hpd_irq_setup(struct drm_i915_private *dev_priv)
+static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv)
{
- icp_hpd_irq_setup(dev_priv,
- TGP_DDI_HPD_ENABLE_MASK, 0);
+ u32 val;
+
+ val = I915_READ(SOUTH_CHICKEN1);
+ val |= (INVERT_DDIA_HPD |
+ INVERT_DDIB_HPD |
+ INVERT_DDIC_HPD |
+ INVERT_DDID_HPD);
+ I915_WRITE(SOUTH_CHICKEN1, val);
+
+ icp_hpd_irq_setup(dev_priv);
}
-static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv)
+static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
u32 hotplug;
hotplug = I915_READ(GEN11_TC_HOTPLUG_CTL);
- hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
+ hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6));
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables);
I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug);
+}
+
+static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv)
+{
+ u32 hotplug;
hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL);
- hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
- GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
+ hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6));
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables);
I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug);
}
@@ -3132,14 +3356,39 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
I915_WRITE(GEN11_DE_HPD_IMR, val);
POSTING_READ(GEN11_DE_HPD_IMR);
- gen11_hpd_detection_setup(dev_priv);
+ gen11_tc_hpd_detection_setup(dev_priv);
+ gen11_tbt_hpd_detection_setup(dev_priv);
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP)
- icp_hpd_irq_setup(dev_priv,
- TGP_DDI_HPD_ENABLE_MASK, TGP_TC_HPD_ENABLE_MASK);
- else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
- icp_hpd_irq_setup(dev_priv,
- ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE_MASK);
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+ icp_hpd_irq_setup(dev_priv);
+}
+
+static u32 spt_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
+{
+ switch (pin) {
+ case HPD_PORT_A:
+ return PORTA_HOTPLUG_ENABLE;
+ case HPD_PORT_B:
+ return PORTB_HOTPLUG_ENABLE;
+ case HPD_PORT_C:
+ return PORTC_HOTPLUG_ENABLE;
+ case HPD_PORT_D:
+ return PORTD_HOTPLUG_ENABLE;
+ default:
+ return 0;
+ }
+}
+
+static u32 spt_hotplug2_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
+{
+ switch (pin) {
+ case HPD_PORT_E:
+ return PORTE_HOTPLUG_ENABLE;
+ default:
+ return 0;
+ }
}
static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
@@ -3156,14 +3405,16 @@ static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
/* Enable digital hotplug on the PCH */
hotplug = I915_READ(PCH_PORT_HOTPLUG);
- hotplug |= PORTA_HOTPLUG_ENABLE |
- PORTB_HOTPLUG_ENABLE |
- PORTC_HOTPLUG_ENABLE |
- PORTD_HOTPLUG_ENABLE;
+ hotplug &= ~(PORTA_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE |
+ PORTC_HOTPLUG_ENABLE |
+ PORTD_HOTPLUG_ENABLE);
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables);
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
hotplug = I915_READ(PCH_PORT_HOTPLUG2);
- hotplug |= PORTE_HOTPLUG_ENABLE;
+ hotplug &= ~PORTE_HOTPLUG_ENABLE;
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables);
I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
}
@@ -3182,6 +3433,18 @@ static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
spt_hpd_detection_setup(dev_priv);
}
+static u32 ilk_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
+{
+ switch (pin) {
+ case HPD_PORT_A:
+ return DIGITAL_PORTA_HOTPLUG_ENABLE |
+ DIGITAL_PORTA_PULSE_DURATION_2ms;
+ default:
+ return 0;
+ }
+}
+
static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
u32 hotplug;
@@ -3192,9 +3455,9 @@ static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
* The pulse duration bits are reserved on HSW+.
*/
hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
- hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK;
- hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE |
- DIGITAL_PORTA_PULSE_DURATION_2ms;
+ hotplug &= ~(DIGITAL_PORTA_HOTPLUG_ENABLE |
+ DIGITAL_PORTA_PULSE_DURATION_MASK);
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables);
I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
}
@@ -3215,41 +3478,45 @@ static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
ibx_hpd_irq_setup(dev_priv);
}
-static void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv,
- u32 enabled_irqs)
+static u32 bxt_hotplug_enables(struct drm_i915_private *i915,
+ enum hpd_pin pin)
{
u32 hotplug;
- hotplug = I915_READ(PCH_PORT_HOTPLUG);
- hotplug |= PORTA_HOTPLUG_ENABLE |
- PORTB_HOTPLUG_ENABLE |
- PORTC_HOTPLUG_ENABLE;
-
- drm_dbg_kms(&dev_priv->drm,
- "Invert bit setting: hp_ctl:%x hp_port:%x\n",
- hotplug, enabled_irqs);
- hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
-
- /*
- * For BXT invert bit has to be set based on AOB design
- * for HPD detection logic, update it based on VBT fields.
- */
- if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
- intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
- hotplug |= BXT_DDIA_HPD_INVERT;
- if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
- intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
- hotplug |= BXT_DDIB_HPD_INVERT;
- if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
- intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
- hotplug |= BXT_DDIC_HPD_INVERT;
-
- I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
+ switch (pin) {
+ case HPD_PORT_A:
+ hotplug = PORTA_HOTPLUG_ENABLE;
+ if (intel_bios_is_port_hpd_inverted(i915, PORT_A))
+ hotplug |= BXT_DDIA_HPD_INVERT;
+ return hotplug;
+ case HPD_PORT_B:
+ hotplug = PORTB_HOTPLUG_ENABLE;
+ if (intel_bios_is_port_hpd_inverted(i915, PORT_B))
+ hotplug |= BXT_DDIB_HPD_INVERT;
+ return hotplug;
+ case HPD_PORT_C:
+ hotplug = PORTC_HOTPLUG_ENABLE;
+ if (intel_bios_is_port_hpd_inverted(i915, PORT_C))
+ hotplug |= BXT_DDIC_HPD_INVERT;
+ return hotplug;
+ default:
+ return 0;
+ }
}
static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- __bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK);
+ u32 hotplug;
+
+ hotplug = I915_READ(PCH_PORT_HOTPLUG);
+ hotplug &= ~(PORTA_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE |
+ PORTC_HOTPLUG_ENABLE |
+ BXT_DDIA_HPD_INVERT |
+ BXT_DDIB_HPD_INVERT |
+ BXT_DDIC_HPD_INVERT);
+ hotplug |= intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables);
+ I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
}
static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3261,11 +3528,23 @@ static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
- __bxt_hpd_detection_setup(dev_priv, enabled_irqs);
+ bxt_hpd_detection_setup(dev_priv);
}
+/*
+ * SDEIER is also touched by the interrupt handler to work around missed PCH
+ * interrupts. Hence we can't update it after the interrupt handler is enabled -
+ * instead we unconditionally enable all PCH interrupt sources here, but then
+ * only unmask them as needed with SDEIMR.
+ *
+ * Note that we currently do this after installing the interrupt handler,
+ * but before we enable the master interrupt. That should be sufficient
+ * to avoid races with the irq handler, assuming we have MSI. Shared legacy
+ * interrupts could still race.
+ */
static void ibx_irq_postinstall(struct drm_i915_private *dev_priv)
{
+ struct intel_uncore *uncore = &dev_priv->uncore;
u32 mask;
if (HAS_PCH_NOP(dev_priv))
@@ -3278,14 +3557,7 @@ static void ibx_irq_postinstall(struct drm_i915_private *dev_priv)
else
mask = SDE_GMBUS_CPT;
- gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
- I915_WRITE(SDEIMR, ~mask);
-
- if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
- HAS_PCH_LPT(dev_priv))
- ibx_hpd_detection_setup(dev_priv);
- else
- spt_hpd_detection_setup(dev_priv);
+ GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff);
}
static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3303,7 +3575,7 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE |
DE_PIPEA_CRC_DONE | DE_POISON);
- extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+ extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK |
DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
DE_DP_A_HOTPLUG);
}
@@ -3313,29 +3585,17 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
display_mask |= DE_EDP_PSR_INT_HSW;
}
- dev_priv->irq_mask = ~display_mask;
+ if (IS_IRONLAKE_M(dev_priv))
+ extra_mask |= DE_PCU_EVENT;
- ibx_irq_pre_postinstall(dev_priv);
+ dev_priv->irq_mask = ~display_mask;
- GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask,
- display_mask | extra_mask);
+ ibx_irq_postinstall(dev_priv);
gen5_gt_irq_postinstall(&dev_priv->gt);
- ilk_hpd_detection_setup(dev_priv);
-
- ibx_irq_postinstall(dev_priv);
-
- if (IS_IRONLAKE_M(dev_priv)) {
- /* Enable PCU event interrupts
- *
- * spinlocking not required here for correctness since interrupt
- * setup is guaranteed to run in single-threaded context. But we
- * need it to make the assert_spin_locked happy. */
- spin_lock_irq(&dev_priv->irq_lock);
- ilk_enable_display_irq(dev_priv, DE_PCU_EVENT);
- spin_unlock_irq(&dev_priv->irq_lock);
- }
+ GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask,
+ display_mask | extra_mask);
}
void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
@@ -3400,14 +3660,24 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
if (IS_GEN9_LP(dev_priv))
de_port_masked |= BXT_DE_PORT_GMBUS;
+ if (INTEL_GEN(dev_priv) >= 11) {
+ enum port port;
+
+ if (intel_bios_is_dsi_present(dev_priv, &port))
+ de_port_masked |= DSI0_TE | DSI1_TE;
+ }
+
de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
GEN8_PIPE_FIFO_UNDERRUN;
+ if (INTEL_GEN(dev_priv) >= 9)
+ de_pipe_enables |= GEN9_PIPE_PLANE1_FLIP_DONE;
+
de_port_enables = de_port_masked;
if (IS_GEN9_LP(dev_priv))
de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK;
else if (IS_BROADWELL(dev_priv))
- de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
+ de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK;
if (INTEL_GEN(dev_priv) >= 12) {
enum transcoder trans;
@@ -3445,51 +3715,26 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked,
de_hpd_enables);
- gen11_hpd_detection_setup(dev_priv);
- } else if (IS_GEN9_LP(dev_priv)) {
- bxt_hpd_detection_setup(dev_priv);
- } else if (IS_BROADWELL(dev_priv)) {
- ilk_hpd_detection_setup(dev_priv);
}
}
static void gen8_irq_postinstall(struct drm_i915_private *dev_priv)
{
if (HAS_PCH_SPLIT(dev_priv))
- ibx_irq_pre_postinstall(dev_priv);
+ ibx_irq_postinstall(dev_priv);
gen8_gt_irq_postinstall(&dev_priv->gt);
gen8_de_irq_postinstall(dev_priv);
- if (HAS_PCH_SPLIT(dev_priv))
- ibx_irq_postinstall(dev_priv);
-
gen8_master_intr_enable(dev_priv->uncore.regs);
}
static void icp_irq_postinstall(struct drm_i915_private *dev_priv)
{
+ struct intel_uncore *uncore = &dev_priv->uncore;
u32 mask = SDE_GMBUS_ICP;
- drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0);
- I915_WRITE(SDEIER, 0xffffffff);
- POSTING_READ(SDEIER);
-
- gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
- I915_WRITE(SDEIMR, ~mask);
-
- if (HAS_PCH_TGP(dev_priv)) {
- icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
- icp_tc_hpd_detection_setup(dev_priv, TGP_TC_HPD_ENABLE_MASK);
- } else if (HAS_PCH_JSP(dev_priv)) {
- icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
- } else if (HAS_PCH_MCC(dev_priv)) {
- icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
- icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE(PORT_TC1));
- } else {
- icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
- icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE_MASK);
- }
+ GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff);
}
static void gen11_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3536,6 +3781,7 @@ static void i8xx_irq_reset(struct drm_i915_private *dev_priv)
i9xx_pipestat_irq_reset(dev_priv);
GEN2_IRQ_RESET(uncore);
+ dev_priv->irq_mask = ~0u;
}
static void i8xx_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3705,6 +3951,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv)
i9xx_pipestat_irq_reset(dev_priv);
GEN3_IRQ_RESET(uncore, GEN2_);
+ dev_priv->irq_mask = ~0u;
}
static void i915_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3811,6 +4058,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv)
i9xx_pipestat_irq_reset(dev_priv);
GEN3_IRQ_RESET(uncore, GEN2_);
+ dev_priv->irq_mask = ~0u;
}
static void i965_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3958,10 +4206,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
struct drm_device *dev = &dev_priv->drm;
int i;
- intel_hpd_init_pins(dev_priv);
-
- intel_hpd_init_work(dev_priv);
-
INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work);
for (i = 0; i < MAX_L3_SLICES; ++i)
dev_priv->l3_parity.remap_info[i] = NULL;
@@ -3970,6 +4214,13 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
if (HAS_GT_UC(dev_priv) && INTEL_GEN(dev_priv) < 11)
dev_priv->gt.pm_guc_events = GUC_INTR_GUC2HOST << 16;
+ if (!HAS_DISPLAY(dev_priv))
+ return;
+
+ intel_hpd_init_pins(dev_priv);
+
+ intel_hpd_init_work(dev_priv);
+
dev->vblank_disable_immediate = true;
/* Most platforms treat the display irq block as an always-on
@@ -3991,23 +4242,18 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
*/
dev_priv->hotplug.hpd_short_storm_enabled = !HAS_DP_MST(dev_priv);
- if (HAS_GMCH(dev_priv)) {
- if (I915_HAS_HOTPLUG(dev_priv))
- dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
- } else {
- if (HAS_PCH_JSP(dev_priv))
- dev_priv->display.hpd_irq_setup = jsp_hpd_irq_setup;
- else if (HAS_PCH_MCC(dev_priv))
- dev_priv->display.hpd_irq_setup = mcc_hpd_irq_setup;
- else if (INTEL_GEN(dev_priv) >= 11)
- dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup;
- else if (IS_GEN9_LP(dev_priv))
- dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup;
- else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
- dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
- else
- dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
- }
+ if (HAS_PCH_DG1(dev_priv))
+ dev_priv->display.hpd_irq_setup = dg1_hpd_irq_setup;
+ else if (INTEL_GEN(dev_priv) >= 11)
+ dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup;
+ else if (IS_GEN9_LP(dev_priv))
+ dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup;
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
+ dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
+ else if (HAS_GMCH(dev_priv) && I915_HAS_HOTPLUG(dev_priv))
+ dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
+ else
+ dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
}
/**
diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h
index 25f25cd95818..2efe609519ca 100644
--- a/drivers/gpu/drm/i915/i915_irq.h
+++ b/drivers/gpu/drm/i915/i915_irq.h
@@ -118,6 +118,9 @@ void i965_disable_vblank(struct drm_crtc *crtc);
void ilk_disable_vblank(struct drm_crtc *crtc);
void bdw_disable_vblank(struct drm_crtc *crtc);
+void skl_enable_flip_done(struct intel_crtc *crtc);
+void skl_disable_flip_done(struct intel_crtc *crtc);
+
void gen2_irq_reset(struct intel_uncore *uncore);
void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
i915_reg_t iir, i915_reg_t ier);
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index fb5e30de78c2..11fe790b1969 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -847,6 +847,14 @@ static const struct intel_device_info ehl_info = {
.ppgtt_size = 36,
};
+static const struct intel_device_info jsl_info = {
+ GEN11_FEATURES,
+ PLATFORM(INTEL_JASPERLAKE),
+ .require_force_probe = 1,
+ .platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(VCS0) | BIT(VECS0),
+ .ppgtt_size = 36,
+};
+
#define GEN12_FEATURES \
GEN11_FEATURES, \
GEN(12), \
@@ -901,6 +909,8 @@ static const struct intel_device_info rkl_info = {
GEN12_FEATURES, \
.memory_regions = REGION_SMEM | REGION_LMEM, \
.has_master_unit_irq = 1, \
+ .has_llc = 0, \
+ .has_snoop = 1, \
.is_dgfx = 1
static const struct intel_device_info dg1_info __maybe_unused = {
@@ -911,6 +921,8 @@ static const struct intel_device_info dg1_info __maybe_unused = {
.platform_engine_mask =
BIT(RCS0) | BIT(BCS0) | BIT(VECS0) |
BIT(VCS0) | BIT(VCS2),
+ /* Wa_16011227922 */
+ .ppgtt_size = 47,
};
#undef GEN
@@ -986,6 +998,7 @@ static const struct pci_device_id pciidlist[] = {
INTEL_CNL_IDS(&cnl_info),
INTEL_ICL_11_IDS(&icl_info),
INTEL_EHL_IDS(&ehl_info),
+ INTEL_JSL_IDS(&jsl_info),
INTEL_TGL_12_IDS(&tgl_info),
INTEL_RKL_IDS(&rkl_info),
{0, 0, 0}
@@ -1091,11 +1104,19 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
}
+static void i915_pci_shutdown(struct pci_dev *pdev)
+{
+ struct drm_i915_private *i915 = pci_get_drvdata(pdev);
+
+ i915_driver_shutdown(i915);
+}
+
static struct pci_driver i915_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = i915_pci_probe,
.remove = i915_pci_remove,
+ .shutdown = i915_pci_shutdown,
.driver.pm = &i915_pm_ops,
};
@@ -1130,9 +1151,13 @@ static int __init i915_init(void)
return 0;
}
+ i915_pmu_init();
+
err = pci_register_driver(&i915_pci_driver);
- if (err)
+ if (err) {
+ i915_pmu_exit();
return err;
+ }
i915_perf_sysctl_register();
return 0;
@@ -1146,6 +1171,7 @@ static void __exit i915_exit(void)
i915_perf_sysctl_unregister();
pci_unregister_driver(&i915_pci_driver);
i915_globals_exit();
+ i915_pmu_exit();
}
module_init(i915_init);
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 3640d0e229d2..3b12c8ff7182 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -625,7 +625,8 @@ static int append_oa_sample(struct i915_perf_stream *stream,
}
/**
- * Copies all buffered OA reports into userspace read() buffer.
+ * gen8_append_oa_reports - Copies all buffered OA reports into
+ * userspace read() buffer.
* @stream: An i915-perf stream opened for OA metrics
* @buf: destination buffer given by userspace
* @count: the number of bytes userspace wants to read
@@ -922,7 +923,8 @@ static int gen8_oa_read(struct i915_perf_stream *stream,
}
/**
- * Copies all buffered OA reports into userspace read() buffer.
+ * gen7_append_oa_reports - Copies all buffered OA reports into
+ * userspace read() buffer.
* @stream: An i915-perf stream opened for OA metrics
* @buf: destination buffer given by userspace
* @count: the number of bytes userspace wants to read
@@ -3232,7 +3234,7 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream,
}
/**
- * i915_perf_ioctl - support ioctl() usage with i915 perf stream FDs
+ * i915_perf_ioctl_locked - support ioctl() usage with i915 perf stream FDs
* @stream: An i915 perf stream
* @cmd: the ioctl request
* @arg: the ioctl data
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 69c0fa20eba1..cd786ad12be7 100644
--- a/drivers/gpu/drm/i915/i915_pmu.c
+++ b/drivers/gpu/drm/i915/i915_pmu.c
@@ -30,6 +30,7 @@
#define ENGINE_SAMPLE_BITS (1 << I915_PMU_SAMPLE_BITS)
static cpumask_t i915_pmu_cpumask;
+static unsigned int i915_pmu_target_cpu = -1;
static u8 engine_config_sample(u64 config)
{
@@ -445,6 +446,8 @@ static void i915_pmu_event_destroy(struct perf_event *event)
container_of(event->pmu, typeof(*i915), pmu.base);
drm_WARN_ON(&i915->drm, event->parent);
+
+ drm_dev_put(&i915->drm);
}
static int
@@ -510,8 +513,12 @@ static int i915_pmu_event_init(struct perf_event *event)
{
struct drm_i915_private *i915 =
container_of(event->pmu, typeof(*i915), pmu.base);
+ struct i915_pmu *pmu = &i915->pmu;
int ret;
+ if (pmu->closed)
+ return -ENODEV;
+
if (event->attr.type != event->pmu->type)
return -ENOENT;
@@ -536,8 +543,10 @@ static int i915_pmu_event_init(struct perf_event *event)
if (ret)
return ret;
- if (!event->parent)
+ if (!event->parent) {
+ drm_dev_get(&i915->drm);
event->destroy = i915_pmu_event_destroy;
+ }
return 0;
}
@@ -594,9 +603,16 @@ static u64 __i915_pmu_event_read(struct perf_event *event)
static void i915_pmu_event_read(struct perf_event *event)
{
+ struct drm_i915_private *i915 =
+ container_of(event->pmu, typeof(*i915), pmu.base);
struct hw_perf_event *hwc = &event->hw;
+ struct i915_pmu *pmu = &i915->pmu;
u64 prev, new;
+ if (pmu->closed) {
+ event->hw.state = PERF_HES_STOPPED;
+ return;
+ }
again:
prev = local64_read(&hwc->prev_count);
new = __i915_pmu_event_read(event);
@@ -724,6 +740,13 @@ static void i915_pmu_disable(struct perf_event *event)
static void i915_pmu_event_start(struct perf_event *event, int flags)
{
+ struct drm_i915_private *i915 =
+ container_of(event->pmu, typeof(*i915), pmu.base);
+ struct i915_pmu *pmu = &i915->pmu;
+
+ if (pmu->closed)
+ return;
+
i915_pmu_enable(event);
event->hw.state = 0;
}
@@ -738,6 +761,13 @@ static void i915_pmu_event_stop(struct perf_event *event, int flags)
static int i915_pmu_event_add(struct perf_event *event, int flags)
{
+ struct drm_i915_private *i915 =
+ container_of(event->pmu, typeof(*i915), pmu.base);
+ struct i915_pmu *pmu = &i915->pmu;
+
+ if (pmu->closed)
+ return -ENODEV;
+
if (flags & PERF_EF_START)
i915_pmu_event_start(event, flags);
@@ -1020,25 +1050,39 @@ static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
{
struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
- unsigned int target;
+ unsigned int target = i915_pmu_target_cpu;
GEM_BUG_ON(!pmu->base.event_init);
+ /*
+ * Unregistering an instance generates a CPU offline event which we must
+ * ignore to avoid incorrectly modifying the shared i915_pmu_cpumask.
+ */
+ if (pmu->closed)
+ return 0;
+
if (cpumask_test_and_clear_cpu(cpu, &i915_pmu_cpumask)) {
target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
+
/* Migrate events if there is a valid target */
if (target < nr_cpu_ids) {
cpumask_set_cpu(target, &i915_pmu_cpumask);
- perf_pmu_migrate_context(&pmu->base, cpu, target);
+ i915_pmu_target_cpu = target;
}
}
+ if (target < nr_cpu_ids && target != pmu->cpuhp.cpu) {
+ perf_pmu_migrate_context(&pmu->base, cpu, target);
+ pmu->cpuhp.cpu = target;
+ }
+
return 0;
}
-static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
+static enum cpuhp_state cpuhp_slot = CPUHP_INVALID;
+
+void i915_pmu_init(void)
{
- enum cpuhp_state slot;
int ret;
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
@@ -1046,27 +1090,29 @@ static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
i915_pmu_cpu_online,
i915_pmu_cpu_offline);
if (ret < 0)
- return ret;
+ pr_notice("Failed to setup cpuhp state for i915 PMU! (%d)\n",
+ ret);
+ else
+ cpuhp_slot = ret;
+}
- slot = ret;
- ret = cpuhp_state_add_instance(slot, &pmu->cpuhp.node);
- if (ret) {
- cpuhp_remove_multi_state(slot);
- return ret;
- }
+void i915_pmu_exit(void)
+{
+ if (cpuhp_slot != CPUHP_INVALID)
+ cpuhp_remove_multi_state(cpuhp_slot);
+}
- pmu->cpuhp.slot = slot;
- return 0;
+static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
+{
+ if (cpuhp_slot == CPUHP_INVALID)
+ return -EINVAL;
+
+ return cpuhp_state_add_instance(cpuhp_slot, &pmu->cpuhp.node);
}
static void i915_pmu_unregister_cpuhp_state(struct i915_pmu *pmu)
{
- struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu);
-
- drm_WARN_ON(&i915->drm, pmu->cpuhp.slot == CPUHP_INVALID);
- drm_WARN_ON(&i915->drm, cpuhp_state_remove_instance(pmu->cpuhp.slot, &pmu->cpuhp.node));
- cpuhp_remove_multi_state(pmu->cpuhp.slot);
- pmu->cpuhp.slot = CPUHP_INVALID;
+ cpuhp_state_remove_instance(cpuhp_slot, &pmu->cpuhp.node);
}
static bool is_igp(struct drm_i915_private *i915)
@@ -1100,7 +1146,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
spin_lock_init(&pmu->lock);
hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pmu->timer.function = i915_sample;
- pmu->cpuhp.slot = CPUHP_INVALID;
+ pmu->cpuhp.cpu = -1;
if (!is_igp(i915)) {
pmu->name = kasprintf(GFP_KERNEL,
@@ -1167,7 +1213,13 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
if (!pmu->base.event_init)
return;
- drm_WARN_ON(&i915->drm, pmu->enable);
+ /*
+ * "Disconnect" the PMU callbacks - since all are atomic synchronize_rcu
+ * ensures all currently executing ones will have exited before we
+ * proceed with unregistration.
+ */
+ pmu->closed = true;
+ synchronize_rcu();
hrtimer_cancel(&pmu->timer);
diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h
index 941f0c14037c..a24885ab415c 100644
--- a/drivers/gpu/drm/i915/i915_pmu.h
+++ b/drivers/gpu/drm/i915/i915_pmu.h
@@ -43,13 +43,17 @@ struct i915_pmu {
*/
struct {
struct hlist_node node;
- enum cpuhp_state slot;
+ unsigned int cpu;
} cpuhp;
/**
* @base: PMU base.
*/
struct pmu base;
/**
+ * @closed: i915 is unregistering.
+ */
+ bool closed;
+ /**
* @name: Name as registered with perf core.
*/
const char *name;
@@ -122,11 +126,15 @@ struct i915_pmu {
};
#ifdef CONFIG_PERF_EVENTS
+void i915_pmu_init(void);
+void i915_pmu_exit(void);
void i915_pmu_register(struct drm_i915_private *i915);
void i915_pmu_unregister(struct drm_i915_private *i915);
void i915_pmu_gt_parked(struct drm_i915_private *i915);
void i915_pmu_gt_unparked(struct drm_i915_private *i915);
#else
+static inline void i915_pmu_init(void) {}
+static inline void i915_pmu_exit(void) {}
static inline void i915_pmu_register(struct drm_i915_private *i915) {}
static inline void i915_pmu_unregister(struct drm_i915_private *i915) {}
static inline void i915_pmu_gt_parked(struct drm_i915_private *i915) {}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 5cd83eac940c..5375b219cc3b 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -230,19 +230,22 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b)
#define _PORT(port, a, b) _PICK_EVEN(port, a, b)
#define _PLL(pll, a, b) _PICK_EVEN(pll, a, b)
+#define _PHY(phy, a, b) _PICK_EVEN(phy, a, b)
#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
#define _MMIO_PLANE(plane, a, b) _MMIO(_PLANE(plane, a, b))
#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
#define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b))
+#define _MMIO_PHY(phy, a, b) _MMIO(_PHY(phy, a, b))
#define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__)
#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
#define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c))
-#define _MMIO_PLL3(pll, a, b, c) _MMIO(_PICK(pll, a, b, c))
+#define _MMIO_PLL3(pll, ...) _MMIO(_PICK(pll, __VA_ARGS__))
+
/*
* Device info offset array based helpers for groups of registers with unevenly
@@ -2529,6 +2532,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define RING_PSMI_CTL(base) _MMIO((base) + 0x50)
#define RING_MAX_IDLE(base) _MMIO((base) + 0x54)
#define RING_HWS_PGA(base) _MMIO((base) + 0x80)
+#define RING_ID(base) _MMIO((base) + 0x8c)
#define RING_HWS_PGA_GEN6(base) _MMIO((base) + 0x2080)
#define RING_RESET_CTL(base) _MMIO((base) + 0xd0)
#define RESET_CTL_CAT_ERROR REG_BIT(2)
@@ -4148,6 +4152,7 @@ enum {
#define GEN9_CLKGATE_DIS_3 _MMIO(0x46538)
#define TGL_VRH_GATING_DIS REG_BIT(31)
+#define DPT_GATING_DIS REG_BIT(22)
#define GEN9_CLKGATE_DIS_4 _MMIO(0x4653C)
#define BXT_GMBUS_GATING_DIS (1 << 14)
@@ -4620,6 +4625,110 @@ enum {
#define PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME REG_BIT(2)
#define PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE REG_BIT(1)
+/* Icelake DSC Rate Control Range Parameter Registers */
+#define DSCA_RC_RANGE_PARAMETERS_0 _MMIO(0x6B240)
+#define DSCA_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6B240 + 4)
+#define DSCC_RC_RANGE_PARAMETERS_0 _MMIO(0x6BA40)
+#define DSCC_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6BA40 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB (0x78208)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB (0x78208 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB (0x78308)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB (0x78308 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC (0x78408)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC (0x78408 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC (0x78508)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC (0x78508 + 4)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC)
+#define RC_BPG_OFFSET_SHIFT 10
+#define RC_MAX_QP_SHIFT 5
+#define RC_MIN_QP_SHIFT 0
+
+#define DSCA_RC_RANGE_PARAMETERS_1 _MMIO(0x6B248)
+#define DSCA_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6B248 + 4)
+#define DSCC_RC_RANGE_PARAMETERS_1 _MMIO(0x6BA48)
+#define DSCC_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6BA48 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB (0x78210)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB (0x78210 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB (0x78310)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB (0x78310 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC (0x78410)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC (0x78410 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC (0x78510)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC (0x78510 + 4)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC)
+
+#define DSCA_RC_RANGE_PARAMETERS_2 _MMIO(0x6B250)
+#define DSCA_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6B250 + 4)
+#define DSCC_RC_RANGE_PARAMETERS_2 _MMIO(0x6BA50)
+#define DSCC_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6BA50 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB (0x78218)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB (0x78218 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB (0x78318)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB (0x78318 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC (0x78418)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC (0x78418 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC (0x78518)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC (0x78518 + 4)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC)
+
+#define DSCA_RC_RANGE_PARAMETERS_3 _MMIO(0x6B258)
+#define DSCA_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6B258 + 4)
+#define DSCC_RC_RANGE_PARAMETERS_3 _MMIO(0x6BA58)
+#define DSCC_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6BA58 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB (0x78220)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB (0x78220 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB (0x78320)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB (0x78320 + 4)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC (0x78420)
+#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC (0x78420 + 4)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC (0x78520)
+#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC (0x78520 + 4)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC)
+#define ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB, \
+ _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC)
+#define ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB, \
+ _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC)
+
/* VGA port control */
#define ADPA _MMIO(0x61100)
#define PCH_ADPA _MMIO(0xe1100)
@@ -6329,15 +6438,16 @@ enum {
_MMIO(_PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe)))
/* define the Watermark register on Ironlake */
-#define WM0_PIPEA_ILK _MMIO(0x45100)
+#define _WM0_PIPEA_ILK 0x45100
+#define _WM0_PIPEB_ILK 0x45104
+#define _WM0_PIPEC_IVB 0x45200
+#define WM0_PIPE_ILK(pipe) _MMIO_PIPE3((pipe), _WM0_PIPEA_ILK, \
+ _WM0_PIPEB_ILK, _WM0_PIPEC_IVB)
#define WM0_PIPE_PLANE_MASK (0xffff << 16)
#define WM0_PIPE_PLANE_SHIFT 16
#define WM0_PIPE_SPRITE_MASK (0xff << 8)
#define WM0_PIPE_SPRITE_SHIFT 8
#define WM0_PIPE_CURSOR_MASK (0xff)
-
-#define WM0_PIPEB_ILK _MMIO(0x45104)
-#define WM0_PIPEC_IVB _MMIO(0x45200)
#define WM1_LP_ILK _MMIO(0x45108)
#define WM1_LP_SR_EN (1 << 31)
#define WM1_LP_LATENCY_SHIFT 24
@@ -6925,6 +7035,7 @@ enum {
#define PLANE_CTL_TILED_X (1 << 10)
#define PLANE_CTL_TILED_Y (4 << 10)
#define PLANE_CTL_TILED_YF (5 << 10)
+#define PLANE_CTL_ASYNC_FLIP (1 << 9)
#define PLANE_CTL_FLIP_HORIZONTAL (1 << 8)
#define PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE (1 << 4) /* TGL+ */
#define PLANE_CTL_ALPHA_MASK (0x3 << 4) /* Pre-GLK */
@@ -7381,6 +7492,7 @@ enum {
#define PS_PLANE_SEL(plane) (((plane) + 1) << 25)
#define PS_FILTER_MASK (3 << 23)
#define PS_FILTER_MEDIUM (0 << 23)
+#define PS_FILTER_PROGRAMMED (1 << 23)
#define PS_FILTER_EDGE_ENHANCE (2 << 23)
#define PS_FILTER_BILINEAR (3 << 23)
#define PS_VERT3TAP (1 << 21)
@@ -7395,6 +7507,10 @@ enum {
#define PS_VADAPT_MODE_MOST_ADAPT (3 << 5)
#define PS_PLANE_Y_SEL_MASK (7 << 5)
#define PS_PLANE_Y_SEL(plane) (((plane) + 1) << 5)
+#define PS_Y_VERT_FILTER_SELECT(set) ((set) << 4)
+#define PS_Y_HORZ_FILTER_SELECT(set) ((set) << 3)
+#define PS_UV_VERT_FILTER_SELECT(set) ((set) << 2)
+#define PS_UV_HORZ_FILTER_SELECT(set) ((set) << 1)
#define _PS_PWR_GATE_1A 0x68160
#define _PS_PWR_GATE_2A 0x68260
@@ -7457,6 +7573,17 @@ enum {
#define _PS_ECC_STAT_2B 0x68AD0
#define _PS_ECC_STAT_1C 0x691D0
+#define _PS_COEF_SET0_INDEX_1A 0x68198
+#define _PS_COEF_SET0_INDEX_2A 0x68298
+#define _PS_COEF_SET0_INDEX_1B 0x68998
+#define _PS_COEF_SET0_INDEX_2B 0x68A98
+#define PS_COEE_INDEX_AUTO_INC (1 << 10)
+
+#define _PS_COEF_SET0_DATA_1A 0x6819C
+#define _PS_COEF_SET0_DATA_2A 0x6829C
+#define _PS_COEF_SET0_DATA_1B 0x6899C
+#define _PS_COEF_SET0_DATA_2B 0x68A9C
+
#define _ID(id, a, b) _PICK_EVEN(id, a, b)
#define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_1A_CTRL, _PS_2A_CTRL), \
@@ -7485,7 +7612,13 @@ enum {
#define SKL_PS_ECC_STAT(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A), \
_ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B))
+#define CNL_PS_COEF_INDEX_SET(pipe, id, set) _MMIO_PIPE(pipe, \
+ _ID(id, _PS_COEF_SET0_INDEX_1A, _PS_COEF_SET0_INDEX_2A) + (set) * 8, \
+ _ID(id, _PS_COEF_SET0_INDEX_1B, _PS_COEF_SET0_INDEX_2B) + (set) * 8)
+#define CNL_PS_COEF_DATA_SET(pipe, id, set) _MMIO_PIPE(pipe, \
+ _ID(id, _PS_COEF_SET0_DATA_1A, _PS_COEF_SET0_DATA_2A) + (set) * 8, \
+ _ID(id, _PS_COEF_SET0_DATA_1B, _PS_COEF_SET0_DATA_2B) + (set) * 8)
/* legacy palette */
#define _LGC_PALETTE_A 0x4a000
#define _LGC_PALETTE_B 0x4a800
@@ -7534,6 +7667,7 @@ enum {
#define BXT_CSR_DC3_DC5_COUNT _MMIO(0x80038)
#define TGL_DMC_DEBUG_DC5_COUNT _MMIO(0x101084)
#define TGL_DMC_DEBUG_DC6_COUNT _MMIO(0x101088)
+#define DG1_DMC_DEBUG_DC5_COUNT _MMIO(0x134154)
#define DMC_DEBUG3 _MMIO(0x101090)
@@ -7683,6 +7817,9 @@ enum {
(GEN9_DE_PIPE_IRQ_FAULT_ERRORS | \
GEN11_PIPE_PLANE5_FAULT)
+#define _HPD_PIN_DDI(hpd_pin) ((hpd_pin) - HPD_PORT_A)
+#define _HPD_PIN_TC(hpd_pin) ((hpd_pin) - HPD_PORT_TC1)
+
#define GEN8_DE_PORT_ISR _MMIO(0x44440)
#define GEN8_DE_PORT_IMR _MMIO(0x44444)
#define GEN8_DE_PORT_IIR _MMIO(0x44448)
@@ -7696,13 +7833,11 @@ enum {
#define GEN9_AUX_CHANNEL_B (1 << 25)
#define DSI1_TE (1 << 24)
#define DSI0_TE (1 << 23)
-#define BXT_DE_PORT_HP_DDIC (1 << 5)
-#define BXT_DE_PORT_HP_DDIB (1 << 4)
-#define BXT_DE_PORT_HP_DDIA (1 << 3)
-#define BXT_DE_PORT_HOTPLUG_MASK (BXT_DE_PORT_HP_DDIA | \
- BXT_DE_PORT_HP_DDIB | \
- BXT_DE_PORT_HP_DDIC)
-#define GEN8_PORT_DP_A_HOTPLUG (1 << 3)
+#define GEN8_DE_PORT_HOTPLUG(hpd_pin) REG_BIT(3 + _HPD_PIN_DDI(hpd_pin))
+#define BXT_DE_PORT_HOTPLUG_MASK (GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) | \
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) | \
+ GEN8_DE_PORT_HOTPLUG(HPD_PORT_C))
+#define BDW_DE_PORT_HOTPLUG_MASK GEN8_DE_PORT_HOTPLUG(HPD_PORT_A)
#define BXT_DE_PORT_GMBUS (1 << 1)
#define GEN8_AUX_CHANNEL_A (1 << 0)
#define TGL_DE_PORT_AUX_USBC6 (1 << 13)
@@ -7761,27 +7896,27 @@ enum {
#define GEN11_DE_HPD_IMR _MMIO(0x44474)
#define GEN11_DE_HPD_IIR _MMIO(0x44478)
#define GEN11_DE_HPD_IER _MMIO(0x4447c)
-#define GEN11_TC_HOTPLUG(tc_port) (1 << ((tc_port) + 16))
-#define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC_HOTPLUG(PORT_TC6) | \
- GEN11_TC_HOTPLUG(PORT_TC5) | \
- GEN11_TC_HOTPLUG(PORT_TC4) | \
- GEN11_TC_HOTPLUG(PORT_TC3) | \
- GEN11_TC_HOTPLUG(PORT_TC2) | \
- GEN11_TC_HOTPLUG(PORT_TC1))
-#define GEN11_TBT_HOTPLUG(tc_port) (1 << (tc_port))
-#define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT_HOTPLUG(PORT_TC6) | \
- GEN11_TBT_HOTPLUG(PORT_TC5) | \
- GEN11_TBT_HOTPLUG(PORT_TC4) | \
- GEN11_TBT_HOTPLUG(PORT_TC3) | \
- GEN11_TBT_HOTPLUG(PORT_TC2) | \
- GEN11_TBT_HOTPLUG(PORT_TC1))
+#define GEN11_TC_HOTPLUG(hpd_pin) REG_BIT(16 + _HPD_PIN_TC(hpd_pin))
+#define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC_HOTPLUG(HPD_PORT_TC6) | \
+ GEN11_TC_HOTPLUG(HPD_PORT_TC5) | \
+ GEN11_TC_HOTPLUG(HPD_PORT_TC4) | \
+ GEN11_TC_HOTPLUG(HPD_PORT_TC3) | \
+ GEN11_TC_HOTPLUG(HPD_PORT_TC2) | \
+ GEN11_TC_HOTPLUG(HPD_PORT_TC1))
+#define GEN11_TBT_HOTPLUG(hpd_pin) REG_BIT(_HPD_PIN_TC(hpd_pin))
+#define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT_HOTPLUG(HPD_PORT_TC6) | \
+ GEN11_TBT_HOTPLUG(HPD_PORT_TC5) | \
+ GEN11_TBT_HOTPLUG(HPD_PORT_TC4) | \
+ GEN11_TBT_HOTPLUG(HPD_PORT_TC3) | \
+ GEN11_TBT_HOTPLUG(HPD_PORT_TC2) | \
+ GEN11_TBT_HOTPLUG(HPD_PORT_TC1))
#define GEN11_TBT_HOTPLUG_CTL _MMIO(0x44030)
#define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038)
-#define GEN11_HOTPLUG_CTL_ENABLE(tc_port) (8 << (tc_port) * 4)
-#define GEN11_HOTPLUG_CTL_LONG_DETECT(tc_port) (2 << (tc_port) * 4)
-#define GEN11_HOTPLUG_CTL_SHORT_DETECT(tc_port) (1 << (tc_port) * 4)
-#define GEN11_HOTPLUG_CTL_NO_DETECT(tc_port) (0 << (tc_port) * 4)
+#define GEN11_HOTPLUG_CTL_ENABLE(hpd_pin) (8 << (_HPD_PIN_TC(hpd_pin) * 4))
+#define GEN11_HOTPLUG_CTL_LONG_DETECT(hpd_pin) (2 << (_HPD_PIN_TC(hpd_pin) * 4))
+#define GEN11_HOTPLUG_CTL_SHORT_DETECT(hpd_pin) (1 << (_HPD_PIN_TC(hpd_pin) * 4))
+#define GEN11_HOTPLUG_CTL_NO_DETECT(hpd_pin) (0 << (_HPD_PIN_TC(hpd_pin) * 4))
#define GEN11_GT_INTR_DW0 _MMIO(0x190018)
#define GEN11_CSME (31)
@@ -7867,6 +8002,7 @@ enum {
# define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2)
#define CHICKEN_PAR1_1 _MMIO(0x42080)
+#define KBL_ARB_FILL_SPARE_22 REG_BIT(22)
#define DIS_RAM_BYPASS_PSR2_MAN_TRACK (1 << 16)
#define SKL_DE_COMPRESSED_HASH_MODE (1 << 15)
#define DPA_MASK_VBLANK_SRD (1 << 15)
@@ -7879,6 +8015,8 @@ enum {
#define CHICKEN_MISC_2 _MMIO(0x42084)
#define CNL_COMP_PWR_DOWN (1 << 23)
+#define KBL_ARB_FILL_SPARE_14 REG_BIT(14)
+#define KBL_ARB_FILL_SPARE_13 REG_BIT(13)
#define GLK_CL2_PWR_DOWN (1 << 12)
#define GLK_CL1_PWR_DOWN (1 << 11)
#define GLK_CL0_PWR_DOWN (1 << 10)
@@ -7921,11 +8059,15 @@ enum {
#define DISP_ARB_CTL2 _MMIO(0x45004)
#define DISP_DATA_PARTITION_5_6 (1 << 6)
#define DISP_IPC_ENABLE (1 << 3)
-#define _DBUF_CTL_S1 0x45008
-#define _DBUF_CTL_S2 0x44FE8
-#define DBUF_CTL_S(slice) _MMIO(_PICK_EVEN(slice, _DBUF_CTL_S1, _DBUF_CTL_S2))
-#define DBUF_POWER_REQUEST (1 << 31)
-#define DBUF_POWER_STATE (1 << 30)
+
+#define _DBUF_CTL_S1 0x45008
+#define _DBUF_CTL_S2 0x44FE8
+#define DBUF_CTL_S(slice) _MMIO(_PICK_EVEN(slice, _DBUF_CTL_S1, _DBUF_CTL_S2))
+#define DBUF_POWER_REQUEST REG_BIT(31)
+#define DBUF_POWER_STATE REG_BIT(30)
+#define DBUF_TRACKER_STATE_SERVICE_MASK REG_GENMASK(23, 19)
+#define DBUF_TRACKER_STATE_SERVICE(x) REG_FIELD_PREP(DBUF_TRACKER_STATE_SERVICE_MASK, x)
+
#define GEN7_MSG_CTL _MMIO(0x45010)
#define WAIT_FOR_PCH_RESET_ACK (1 << 1)
#define WAIT_FOR_PCH_FLR_ACK (1 << 0)
@@ -8016,13 +8158,15 @@ enum {
#define GEN8_L3CNTLREG _MMIO(0x7034)
#define GEN8_ERRDETBCTRL (1 << 9)
-#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304)
- #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC (1 << 11)
- #define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE (1 << 9)
+#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304)
+ #define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12)
+ #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11)
+ #define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9)
#define HIZ_CHICKEN _MMIO(0x7018)
-# define CHV_HZ_8X8_MODE_IN_1X (1 << 15)
-# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE (1 << 3)
+# define CHV_HZ_8X8_MODE_IN_1X REG_BIT(15)
+# define DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE REG_BIT(14)
+# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE REG_BIT(3)
#define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308)
#define DISABLE_PIXEL_MASK_CAMMING (1 << 14)
@@ -8210,23 +8354,18 @@ enum {
/* south display engine interrupt: ICP/TGP */
#define SDE_GMBUS_ICP (1 << 23)
-#define SDE_TC_HOTPLUG_ICP(tc_port) (1 << ((tc_port) + 24))
-#define SDE_DDI_HOTPLUG_ICP(port) (1 << ((port) + 16))
-#define SDE_DDI_MASK_ICP (SDE_DDI_HOTPLUG_ICP(PORT_B) | \
- SDE_DDI_HOTPLUG_ICP(PORT_A))
-#define SDE_TC_MASK_ICP (SDE_TC_HOTPLUG_ICP(PORT_TC4) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC3) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC2) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC1))
-#define SDE_DDI_MASK_TGP (SDE_DDI_HOTPLUG_ICP(PORT_C) | \
- SDE_DDI_HOTPLUG_ICP(PORT_B) | \
- SDE_DDI_HOTPLUG_ICP(PORT_A))
-#define SDE_TC_MASK_TGP (SDE_TC_HOTPLUG_ICP(PORT_TC6) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC5) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC4) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC3) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC2) | \
- SDE_TC_HOTPLUG_ICP(PORT_TC1))
+#define SDE_TC_HOTPLUG_ICP(hpd_pin) REG_BIT(24 + _HPD_PIN_TC(hpd_pin))
+#define SDE_DDI_HOTPLUG_ICP(hpd_pin) REG_BIT(16 + _HPD_PIN_DDI(hpd_pin))
+#define SDE_DDI_HOTPLUG_MASK_ICP (SDE_DDI_HOTPLUG_ICP(HPD_PORT_D) | \
+ SDE_DDI_HOTPLUG_ICP(HPD_PORT_C) | \
+ SDE_DDI_HOTPLUG_ICP(HPD_PORT_B) | \
+ SDE_DDI_HOTPLUG_ICP(HPD_PORT_A))
+#define SDE_TC_HOTPLUG_MASK_ICP (SDE_TC_HOTPLUG_ICP(HPD_PORT_TC6) | \
+ SDE_TC_HOTPLUG_ICP(HPD_PORT_TC5) | \
+ SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4) | \
+ SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3) | \
+ SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2) | \
+ SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1))
#define SDEISR _MMIO(0xc4000)
#define SDEIMR _MMIO(0xc4004)
@@ -8294,139 +8433,21 @@ enum {
*/
#define SHOTPLUG_CTL_DDI _MMIO(0xc4030)
-#define SHOTPLUG_CTL_DDI_HPD_ENABLE(port) (0x8 << (4 * (port)))
-#define SHOTPLUG_CTL_DDI_HPD_STATUS_MASK(port) (0x3 << (4 * (port)))
-#define SHOTPLUG_CTL_DDI_HPD_NO_DETECT(port) (0x0 << (4 * (port)))
-#define SHOTPLUG_CTL_DDI_HPD_SHORT_DETECT(port) (0x1 << (4 * (port)))
-#define SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(port) (0x2 << (4 * (port)))
-#define SHOTPLUG_CTL_DDI_HPD_SHORT_LONG_DETECT(port) (0x3 << (4 * (port)))
+#define SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin) (0x8 << (_HPD_PIN_DDI(hpd_pin) * 4))
+#define SHOTPLUG_CTL_DDI_HPD_STATUS_MASK(hpd_pin) (0x3 << (_HPD_PIN_DDI(hpd_pin) * 4))
+#define SHOTPLUG_CTL_DDI_HPD_NO_DETECT(hpd_pin) (0x0 << (_HPD_PIN_DDI(hpd_pin) * 4))
+#define SHOTPLUG_CTL_DDI_HPD_SHORT_DETECT(hpd_pin) (0x1 << (_HPD_PIN_DDI(hpd_pin) * 4))
+#define SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(hpd_pin) (0x2 << (_HPD_PIN_DDI(hpd_pin) * 4))
+#define SHOTPLUG_CTL_DDI_HPD_SHORT_LONG_DETECT(hpd_pin) (0x3 << (_HPD_PIN_DDI(hpd_pin) * 4))
#define SHOTPLUG_CTL_TC _MMIO(0xc4034)
-#define ICP_TC_HPD_ENABLE(tc_port) (8 << (tc_port) * 4)
+#define ICP_TC_HPD_ENABLE(hpd_pin) (8 << (_HPD_PIN_TC(hpd_pin) * 4))
+#define ICP_TC_HPD_LONG_DETECT(hpd_pin) (2 << (_HPD_PIN_TC(hpd_pin) * 4))
+#define ICP_TC_HPD_SHORT_DETECT(hpd_pin) (1 << (_HPD_PIN_TC(hpd_pin) * 4))
#define SHPD_FILTER_CNT _MMIO(0xc4038)
#define SHPD_FILTER_CNT_500_ADJ 0x001D9
-/* Icelake DSC Rate Control Range Parameter Registers */
-#define DSCA_RC_RANGE_PARAMETERS_0 _MMIO(0x6B240)
-#define DSCA_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6B240 + 4)
-#define DSCC_RC_RANGE_PARAMETERS_0 _MMIO(0x6BA40)
-#define DSCC_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6BA40 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB (0x78208)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB (0x78208 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB (0x78308)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB (0x78308 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC (0x78408)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC (0x78408 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC (0x78508)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC (0x78508 + 4)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC)
-#define RC_BPG_OFFSET_SHIFT 10
-#define RC_MAX_QP_SHIFT 5
-#define RC_MIN_QP_SHIFT 0
-
-#define DSCA_RC_RANGE_PARAMETERS_1 _MMIO(0x6B248)
-#define DSCA_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6B248 + 4)
-#define DSCC_RC_RANGE_PARAMETERS_1 _MMIO(0x6BA48)
-#define DSCC_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6BA48 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB (0x78210)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB (0x78210 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB (0x78310)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB (0x78310 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC (0x78410)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC (0x78410 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC (0x78510)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC (0x78510 + 4)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC)
-
-#define DSCA_RC_RANGE_PARAMETERS_2 _MMIO(0x6B250)
-#define DSCA_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6B250 + 4)
-#define DSCC_RC_RANGE_PARAMETERS_2 _MMIO(0x6BA50)
-#define DSCC_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6BA50 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB (0x78218)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB (0x78218 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB (0x78318)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB (0x78318 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC (0x78418)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC (0x78418 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC (0x78518)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC (0x78518 + 4)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC)
-
-#define DSCA_RC_RANGE_PARAMETERS_3 _MMIO(0x6B258)
-#define DSCA_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6B258 + 4)
-#define DSCC_RC_RANGE_PARAMETERS_3 _MMIO(0x6BA58)
-#define DSCC_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6BA58 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB (0x78220)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB (0x78220 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB (0x78320)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB (0x78320 + 4)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC (0x78420)
-#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC (0x78420 + 4)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC (0x78520)
-#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC (0x78520 + 4)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC)
-#define ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB, \
- _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC)
-#define ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB, \
- _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC)
-
-#define ICP_TC_HPD_LONG_DETECT(tc_port) (2 << (tc_port) * 4)
-#define ICP_TC_HPD_SHORT_DETECT(tc_port) (1 << (tc_port) * 4)
-
-#define ICP_DDI_HPD_ENABLE_MASK (SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_B) | \
- SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_A))
-#define ICP_TC_HPD_ENABLE_MASK (ICP_TC_HPD_ENABLE(PORT_TC4) | \
- ICP_TC_HPD_ENABLE(PORT_TC3) | \
- ICP_TC_HPD_ENABLE(PORT_TC2) | \
- ICP_TC_HPD_ENABLE(PORT_TC1))
-#define TGP_DDI_HPD_ENABLE_MASK (SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_C) | \
- SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_B) | \
- SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_A))
-#define TGP_TC_HPD_ENABLE_MASK (ICP_TC_HPD_ENABLE(PORT_TC6) | \
- ICP_TC_HPD_ENABLE(PORT_TC5) | \
- ICP_TC_HPD_ENABLE_MASK)
-
#define _PCH_DPLL_A 0xc6014
#define _PCH_DPLL_B 0xc6018
#define PCH_DPLL(pll) _MMIO((pll) == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
@@ -8686,6 +8707,10 @@ enum {
#define SOUTH_CHICKEN1 _MMIO(0xc2000)
#define FDIA_PHASE_SYNC_SHIFT_OVR 19
#define FDIA_PHASE_SYNC_SHIFT_EN 18
+#define INVERT_DDID_HPD (1 << 18)
+#define INVERT_DDIC_HPD (1 << 17)
+#define INVERT_DDIB_HPD (1 << 16)
+#define INVERT_DDIA_HPD (1 << 15)
#define FDI_PHASE_SYNC_OVR(pipe) (1 << (FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2)))
#define FDI_PHASE_SYNC_EN(pipe) (1 << (FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
#define FDI_BC_BIFURCATION_SELECT (1 << 12)
@@ -8956,12 +8981,12 @@ enum {
#define FORCEWAKE_MEDIA_VDBOX_GEN11(n) _MMIO(0xa540 + (n) * 4)
#define FORCEWAKE_MEDIA_VEBOX_GEN11(n) _MMIO(0xa560 + (n) * 4)
#define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278)
-#define FORCEWAKE_BLITTER_GEN9 _MMIO(0xa188)
+#define FORCEWAKE_GT_GEN9 _MMIO(0xa188)
#define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0x0D88)
#define FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(n) _MMIO(0x0D50 + (n) * 4)
#define FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(n) _MMIO(0x0D70 + (n) * 4)
#define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0x0D84)
-#define FORCEWAKE_ACK_BLITTER_GEN9 _MMIO(0x130044)
+#define FORCEWAKE_ACK_GT_GEN9 _MMIO(0x130044)
#define FORCEWAKE_KERNEL BIT(0)
#define FORCEWAKE_USER BIT(1)
#define FORCEWAKE_KERNEL_FALLBACK BIT(15)
@@ -9223,6 +9248,9 @@ enum {
#define GEN9_SAGV_DISABLE 0x0
#define GEN9_SAGV_IS_DISABLED 0x1
#define GEN9_SAGV_ENABLE 0x3
+#define DG1_PCODE_STATUS 0x7E
+#define DG1_UNCORE_GET_INIT_STATUS 0x0
+#define DG1_UNCORE_INIT_STATUS_COMPLETE 0x1
#define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23
#define GEN6_PCODE_DATA _MMIO(0x138128)
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
@@ -10257,6 +10285,7 @@ enum skl_power_gate {
#define DPLL_CFGCR2_PDIV_2 (1 << 2)
#define DPLL_CFGCR2_PDIV_3 (2 << 2)
#define DPLL_CFGCR2_PDIV_7 (4 << 2)
+#define DPLL_CFGCR2_PDIV_7_INVALID (5 << 2)
#define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3)
#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR1)
@@ -10273,12 +10302,13 @@ enum skl_power_gate {
#define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port))
#define DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port) ((pll) << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port))
+/* ICL Clocks */
#define ICL_DPCLKA_CFGCR0 _MMIO(0x164280)
#define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24))
#define RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT((phy) + 10)
-#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < PORT_TC4 ? \
+#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < TC_PORT_4 ? \
(tc_port) + 12 : \
- (tc_port) - PORT_TC4 + 21))
+ (tc_port) - TC_PORT_4 + 21))
#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) ((phy) * 2)
#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (3 << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
@@ -10288,6 +10318,27 @@ enum skl_power_gate {
#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) \
((pll) << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+/*
+ * DG1 Clocks
+ * First registers controls the first A and B, while the second register
+ * controls the phy C and D. The bits on these registers are the
+ * same, but refer to different phys
+ */
+#define _DG1_DPCLKA_CFGCR0 0x164280
+#define _DG1_DPCLKA1_CFGCR0 0x16C280
+#define _DG1_DPCLKA_PHY_IDX(phy) ((phy) % 2)
+#define _DG1_DPCLKA_PLL_IDX(pll) ((pll) % 2)
+#define _DG1_PHY_DPLL_MAP(phy) ((phy) >= PHY_C ? DPLL_ID_DG1_DPLL2 : DPLL_ID_DG1_DPLL0)
+#define DG1_DPCLKA_CFGCR0(phy) _MMIO_PHY((phy) / 2, \
+ _DG1_DPCLKA_CFGCR0, \
+ _DG1_DPCLKA1_CFGCR0)
+#define DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT(_DG1_DPCLKA_PHY_IDX(phy) + 10)
+#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) (_DG1_DPCLKA_PHY_IDX(phy) * 2)
+#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) (_DG1_DPCLKA_PLL_IDX(pll) << DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (0x3 << DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy) \
+ (((clk_sel) >> DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) + _DG1_PHY_DPLL_MAP(phy))
+
/* CNL PLL */
#define DPLL0_ENABLE 0x46010
#define DPLL1_ENABLE 0x46014
@@ -10307,6 +10358,10 @@ enum skl_power_gate {
#define MG_PLL_ENABLE(tc_port) _MMIO_PORT((tc_port), _MG_PLL1_ENABLE, \
_MG_PLL2_ENABLE)
+/* DG1 PLL */
+#define DG1_DPLL_ENABLE(pll) _MMIO_PLL3(pll, DPLL0_ENABLE, DPLL1_ENABLE, \
+ _MG_PLL1_ENABLE, _MG_PLL2_ENABLE)
+
#define _MG_REFCLKIN_CTL_PORT1 0x16892C
#define _MG_REFCLKIN_CTL_PORT2 0x16992C
#define _MG_REFCLKIN_CTL_PORT3 0x16A92C
@@ -10523,6 +10578,20 @@ enum skl_power_gate {
#define RKL_DPLL_CFGCR1(pll) _MMIO_PLL(pll, _TGL_DPLL0_CFGCR1, \
_TGL_DPLL1_CFGCR1)
+#define _DG1_DPLL2_CFGCR0 0x16C284
+#define _DG1_DPLL3_CFGCR0 0x16C28C
+#define DG1_DPLL_CFGCR0(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR0, \
+ _TGL_DPLL1_CFGCR0, \
+ _DG1_DPLL2_CFGCR0, \
+ _DG1_DPLL3_CFGCR0)
+
+#define _DG1_DPLL2_CFGCR1 0x16C288
+#define _DG1_DPLL3_CFGCR1 0x16C290
+#define DG1_DPLL_CFGCR1(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR1, \
+ _TGL_DPLL1_CFGCR1, \
+ _DG1_DPLL2_CFGCR1, \
+ _DG1_DPLL3_CFGCR1)
+
#define _DKL_PHY1_BASE 0x168000
#define _DKL_PHY2_BASE 0x169000
#define _DKL_PHY3_BASE 0x16A000
@@ -11003,14 +11072,17 @@ enum skl_power_gate {
#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C)
#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910)
#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000)
+#define CGM_PIPE_DEGAMMA_RED_MASK REG_GENMASK(13, 0)
+#define CGM_PIPE_DEGAMMA_GREEN_MASK REG_GENMASK(29, 16)
+#define CGM_PIPE_DEGAMMA_BLUE_MASK REG_GENMASK(13, 0)
#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000)
+#define CGM_PIPE_GAMMA_RED_MASK REG_GENMASK(9, 0)
+#define CGM_PIPE_GAMMA_GREEN_MASK REG_GENMASK(25, 16)
+#define CGM_PIPE_GAMMA_BLUE_MASK REG_GENMASK(9, 0)
#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00)
#define CGM_PIPE_MODE_GAMMA (1 << 2)
#define CGM_PIPE_MODE_CSC (1 << 1)
#define CGM_PIPE_MODE_DEGAMMA (1 << 0)
-#define CGM_PIPE_GAMMA_RED_MASK REG_GENMASK(9, 0)
-#define CGM_PIPE_GAMMA_GREEN_MASK REG_GENMASK(25, 16)
-#define CGM_PIPE_GAMMA_BLUE_MASK REG_GENMASK(9, 0)
#define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900)
#define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904)
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
index b7b59328cb76..9cb26a224034 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.h
+++ b/drivers/gpu/drm/i915/i915_scatterlist.h
@@ -27,13 +27,17 @@ static __always_inline struct sgt_iter {
} __sgt_iter(struct scatterlist *sgl, bool dma) {
struct sgt_iter s = { .sgp = sgl };
- if (s.sgp) {
+ if (dma && s.sgp && sg_dma_len(s.sgp) == 0) {
+ s.sgp = NULL;
+ } else if (s.sgp) {
s.max = s.curr = s.sgp->offset;
- s.max += s.sgp->length;
- if (dma)
+ if (dma) {
s.dma = sg_dma_address(s.sgp);
- else
+ s.max += sg_dma_len(s.sgp);
+ } else {
s.pfn = page_to_pfn(sg_page(s.sgp));
+ s.max += s.sgp->length;
+ }
}
return s;
@@ -44,6 +48,11 @@ static inline int __sg_page_count(const struct scatterlist *sg)
return sg->length >> PAGE_SHIFT;
}
+static inline int __sg_dma_page_count(const struct scatterlist *sg)
+{
+ return sg_dma_len(sg) >> PAGE_SHIFT;
+}
+
static inline struct scatterlist *____sg_next(struct scatterlist *sg)
{
++sg;
@@ -112,7 +121,7 @@ static inline unsigned int i915_sg_segment_size(void)
unsigned int size = swiotlb_max_segment();
if (size == 0)
- return SCATTERLIST_MAX_SEGMENT;
+ size = UINT_MAX;
size = rounddown(size, PAGE_SIZE);
/* swiotlb_max_segment_size can return 1 byte when it means one page. */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 7b64e7137270..db2111fc809e 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -32,45 +32,10 @@
#include "i915_reg.h"
#include "i915_suspend.h"
-static void i915_save_display(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
-
- /* Display arbitration control */
- if (INTEL_GEN(dev_priv) <= 4)
- dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
-
- if (IS_GEN(dev_priv, 4))
- pci_read_config_word(pdev, GCDGMBUS,
- &dev_priv->regfile.saveGCDGMBUS);
-}
-
-static void i915_restore_display(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
-
- if (IS_GEN(dev_priv, 4))
- pci_write_config_word(pdev, GCDGMBUS,
- dev_priv->regfile.saveGCDGMBUS);
-
- /* Display arbitration */
- if (INTEL_GEN(dev_priv) <= 4)
- I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
-
- /* only restore FBC info on the platform that supports FBC*/
- intel_fbc_global_disable(dev_priv);
-
- intel_vga_redisable(dev_priv);
-
- intel_gmbus_reset(dev_priv);
-}
-
-int i915_save_state(struct drm_i915_private *dev_priv)
+static void intel_save_swf(struct drm_i915_private *dev_priv)
{
int i;
- i915_save_display(dev_priv);
-
/* Scratch space */
if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) {
for (i = 0; i < 7; i++) {
@@ -90,16 +55,12 @@ int i915_save_state(struct drm_i915_private *dev_priv)
for (i = 0; i < 3; i++)
dev_priv->regfile.saveSWF3[i] = I915_READ(SWF3(i));
}
-
- return 0;
}
-int i915_restore_state(struct drm_i915_private *dev_priv)
+static void intel_restore_swf(struct drm_i915_private *dev_priv)
{
int i;
- i915_restore_display(dev_priv);
-
/* Scratch space */
if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) {
for (i = 0; i < 7; i++) {
@@ -119,6 +80,41 @@ int i915_restore_state(struct drm_i915_private *dev_priv)
for (i = 0; i < 3; i++)
I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]);
}
+}
+
+void i915_save_display(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+
+ /* Display arbitration control */
+ if (INTEL_GEN(dev_priv) <= 4)
+ dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
- return 0;
+ if (IS_GEN(dev_priv, 4))
+ pci_read_config_word(pdev, GCDGMBUS,
+ &dev_priv->regfile.saveGCDGMBUS);
+
+ intel_save_swf(dev_priv);
+}
+
+void i915_restore_display(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+
+ intel_restore_swf(dev_priv);
+
+ if (IS_GEN(dev_priv, 4))
+ pci_write_config_word(pdev, GCDGMBUS,
+ dev_priv->regfile.saveGCDGMBUS);
+
+ /* Display arbitration */
+ if (INTEL_GEN(dev_priv) <= 4)
+ I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
+
+ /* only restore FBC info on the platform that supports FBC*/
+ intel_fbc_global_disable(dev_priv);
+
+ intel_vga_redisable(dev_priv);
+
+ intel_gmbus_reset(dev_priv);
}
diff --git a/drivers/gpu/drm/i915/i915_suspend.h b/drivers/gpu/drm/i915/i915_suspend.h
index 3a36fb4ecc05..e5a611ee3d15 100644
--- a/drivers/gpu/drm/i915/i915_suspend.h
+++ b/drivers/gpu/drm/i915/i915_suspend.h
@@ -8,7 +8,7 @@
struct drm_i915_private;
-int i915_save_state(struct drm_i915_private *i915);
-int i915_restore_state(struct drm_i915_private *i915);
+void i915_save_display(struct drm_i915_private *i915);
+void i915_restore_display(struct drm_i915_private *i915);
#endif /* __I915_SUSPEND_H__ */
diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
index adc836f15fde..e67cec8fa2aa 100644
--- a/drivers/gpu/drm/i915/intel_device_info.c
+++ b/drivers/gpu/drm/i915/intel_device_info.c
@@ -62,6 +62,7 @@ static const char * const platform_names[] = {
PLATFORM_NAME(CANNONLAKE),
PLATFORM_NAME(ICELAKE),
PLATFORM_NAME(ELKHARTLAKE),
+ PLATFORM_NAME(JASPERLAKE),
PLATFORM_NAME(TIGERLAKE),
PLATFORM_NAME(ROCKETLAKE),
PLATFORM_NAME(DG1),
diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h
index 6a3d607218aa..d92fa041c700 100644
--- a/drivers/gpu/drm/i915/intel_device_info.h
+++ b/drivers/gpu/drm/i915/intel_device_info.h
@@ -79,6 +79,7 @@ enum intel_platform {
/* gen11 */
INTEL_ICELAKE,
INTEL_ELKHARTLAKE,
+ INTEL_JASPERLAKE,
/* gen12 */
INTEL_TIGERLAKE,
INTEL_ROCKETLAKE,
diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c
index 8aa12cad93ce..4754296a250e 100644
--- a/drivers/gpu/drm/i915/intel_dram.c
+++ b/drivers/gpu/drm/i915/intel_dram.c
@@ -7,7 +7,8 @@
#include "intel_dram.h"
struct dram_dimm_info {
- u8 size, width, ranks;
+ u16 size;
+ u8 width, ranks;
};
struct dram_channel_info {
@@ -41,10 +42,10 @@ static int intel_dimm_num_devices(const struct dram_dimm_info *dimm)
return dimm->ranks * 64 / (dimm->width ?: 1);
}
-/* Returns total GB for the whole DIMM */
+/* Returns total Gb for the whole DIMM */
static int skl_get_dimm_size(u16 val)
{
- return val & SKL_DRAM_SIZE_MASK;
+ return (val & SKL_DRAM_SIZE_MASK) * 8;
}
static int skl_get_dimm_width(u16 val)
@@ -74,10 +75,10 @@ static int skl_get_dimm_ranks(u16 val)
return val + 1;
}
-/* Returns total GB for the whole DIMM */
+/* Returns total Gb for the whole DIMM */
static int cnl_get_dimm_size(u16 val)
{
- return (val & CNL_DRAM_SIZE_MASK) / 2;
+ return (val & CNL_DRAM_SIZE_MASK) * 8 / 2;
}
static int cnl_get_dimm_width(u16 val)
@@ -110,8 +111,8 @@ static int cnl_get_dimm_ranks(u16 val)
static bool
skl_is_16gb_dimm(const struct dram_dimm_info *dimm)
{
- /* Convert total GB to Gb per DRAM device */
- return 8 * dimm->size / (intel_dimm_num_devices(dimm) ?: 1) == 16;
+ /* Convert total Gb to Gb per DRAM device */
+ return dimm->size / (intel_dimm_num_devices(dimm) ?: 1) == 16;
}
static void
@@ -130,7 +131,7 @@ skl_dram_get_dimm_info(struct drm_i915_private *i915,
}
drm_dbg_kms(&i915->drm,
- "CH%u DIMM %c size: %u GB, width: X%u, ranks: %u, 16Gb DIMMs: %s\n",
+ "CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb DIMMs: %s\n",
channel, dimm_name, dimm->size, dimm->width, dimm->ranks,
yesno(skl_is_16gb_dimm(dimm)));
}
@@ -354,9 +355,9 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val)
/*
* Size in register is Gb per DRAM device. Convert to total
- * GB to match the way we report this for non-LP platforms.
+ * Gb to match the way we report this for non-LP platforms.
*/
- dimm->size = bxt_get_dimm_size(val) * intel_dimm_num_devices(dimm) / 8;
+ dimm->size = bxt_get_dimm_size(val) * intel_dimm_num_devices(dimm);
}
static int bxt_get_dram_info(struct drm_i915_private *i915)
@@ -404,7 +405,7 @@ static int bxt_get_dram_info(struct drm_i915_private *i915)
dram_info->type != type);
drm_dbg_kms(&i915->drm,
- "CH%u DIMM size: %u GB, width: X%u, ranks: %u, type: %s\n",
+ "CH%u DIMM size: %u Gb, width: X%u, ranks: %u, type: %s\n",
i - BXT_D_CR_DRP0_DUNIT_START,
dimm.size, dimm.width, dimm.ranks,
intel_dram_type_str(type));
diff --git a/drivers/gpu/drm/i915/intel_gvt.c b/drivers/gpu/drm/i915/intel_gvt.c
index 99fe8aef1c67..4e70c1a9ef2e 100644
--- a/drivers/gpu/drm/i915/intel_gvt.c
+++ b/drivers/gpu/drm/i915/intel_gvt.c
@@ -24,6 +24,7 @@
#include "i915_drv.h"
#include "i915_vgpu.h"
#include "intel_gvt.h"
+#include "gvt/gvt.h"
/**
* DOC: Intel GVT-g host support
@@ -147,3 +148,17 @@ void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)
intel_gvt_clean_device(dev_priv);
}
+
+/**
+ * intel_gvt_resume - GVT resume routine wapper
+ *
+ * @dev_priv: drm i915 private *
+ *
+ * This function is called at the i915 driver resume stage to restore required
+ * HW status for GVT so that vGPU can continue running after resumed.
+ */
+void intel_gvt_resume(struct drm_i915_private *dev_priv)
+{
+ if (intel_gvt_active(dev_priv))
+ intel_gvt_pm_resume(dev_priv->gvt);
+}
diff --git a/drivers/gpu/drm/i915/intel_gvt.h b/drivers/gpu/drm/i915/intel_gvt.h
index 502fad8a8652..d7d3fb6186fd 100644
--- a/drivers/gpu/drm/i915/intel_gvt.h
+++ b/drivers/gpu/drm/i915/intel_gvt.h
@@ -33,6 +33,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv);
void intel_gvt_clean_device(struct drm_i915_private *dev_priv);
int intel_gvt_init_host(void);
void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv);
+void intel_gvt_resume(struct drm_i915_private *dev_priv);
#else
static inline int intel_gvt_init(struct drm_i915_private *dev_priv)
{
@@ -46,6 +47,10 @@ static inline void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)
static inline void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv)
{
}
+
+static inline void intel_gvt_resume(struct drm_i915_private *dev_priv)
+{
+}
#endif
#endif /* _INTEL_GVT_H_ */
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index 180e1078ef7c..b326993a1026 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -114,7 +114,7 @@ __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
n_pages -= BIT(order);
block->private = mem;
- list_add(&block->link, blocks);
+ list_add_tail(&block->link, blocks);
if (!n_pages)
break;
diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/intel_pch.c
index 6c97192e9ca8..f31c0dabd0cc 100644
--- a/drivers/gpu/drm/i915/intel_pch.c
+++ b/drivers/gpu/drm/i915/intel_pch.c
@@ -115,7 +115,7 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id)
return PCH_ICP;
case INTEL_PCH_MCC_DEVICE_ID_TYPE:
drm_dbg_kms(&dev_priv->drm, "Found Mule Creek Canyon PCH\n");
- drm_WARN_ON(&dev_priv->drm, !IS_ELKHARTLAKE(dev_priv));
+ drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv));
return PCH_MCC;
case INTEL_PCH_TGP_DEVICE_ID_TYPE:
case INTEL_PCH_TGP2_DEVICE_ID_TYPE:
@@ -126,7 +126,7 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id)
case INTEL_PCH_JSP_DEVICE_ID_TYPE:
case INTEL_PCH_JSP2_DEVICE_ID_TYPE:
drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n");
- drm_WARN_ON(&dev_priv->drm, !IS_ELKHARTLAKE(dev_priv));
+ drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv));
return PCH_JSP;
default:
return PCH_NONE;
@@ -157,7 +157,7 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv)
if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv))
id = INTEL_PCH_TGP_DEVICE_ID_TYPE;
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
id = INTEL_PCH_MCC_DEVICE_ID_TYPE;
else if (IS_ICELAKE(dev_priv))
id = INTEL_PCH_ICP_DEVICE_ID_TYPE;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index cfb806767fc5..a20b5051f18c 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -33,6 +33,7 @@
#include <drm/drm_plane_helper.h>
#include "display/intel_atomic.h"
+#include "display/intel_atomic_plane.h"
#include "display/intel_bw.h"
#include "display/intel_display_types.h"
#include "display/intel_fbc.h"
@@ -899,12 +900,12 @@ static void pnv_update_wm(struct intel_crtc *unused_crtc)
crtc = single_enabled_crtc(dev_priv);
if (crtc) {
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc->config->hw.pipe_mode;
const struct drm_framebuffer *fb =
crtc->base.primary->state->fb;
int cpp = fb->format->cpp[0];
- int clock = adjusted_mode->crtc_clock;
+ int clock = pipe_mode->crtc_clock;
/* Display SR */
wm = intel_calculate_wm(clock, &pnv_display_wm,
@@ -1135,8 +1136,8 @@ static u16 g4x_compute_wm(const struct intel_crtc_state *crtc_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_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
unsigned int latency = dev_priv->wm.pri_latency[level] * 10;
unsigned int clock, htotal, cpp, width, wm;
@@ -1163,8 +1164,8 @@ static u16 g4x_compute_wm(const struct intel_crtc_state *crtc_state,
level != G4X_WM_LEVEL_NORMAL)
cpp = max(cpp, 4u);
- clock = adjusted_mode->crtc_clock;
- htotal = adjusted_mode->crtc_htotal;
+ clock = pipe_mode->crtc_clock;
+ htotal = pipe_mode->crtc_htotal;
width = drm_rect_width(&plane_state->uapi.dst);
@@ -1660,8 +1661,8 @@ static u16 vlv_compute_wm_level(const struct intel_crtc_state *crtc_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_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
unsigned int clock, htotal, cpp, width, wm;
if (dev_priv->wm.pri_latency[level] == 0)
@@ -1671,8 +1672,8 @@ static u16 vlv_compute_wm_level(const struct intel_crtc_state *crtc_state,
return 0;
cpp = plane_state->hw.fb->format->cpp[0];
- clock = adjusted_mode->crtc_clock;
- htotal = adjusted_mode->crtc_htotal;
+ clock = pipe_mode->crtc_clock;
+ htotal = pipe_mode->crtc_htotal;
width = crtc_state->pipe_src_w;
if (plane->id == PLANE_CURSOR) {
@@ -2261,12 +2262,12 @@ static void i965_update_wm(struct intel_crtc *unused_crtc)
if (crtc) {
/* self-refresh has much higher latency */
static const int sr_latency_ns = 12000;
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc->config->hw.pipe_mode;
const struct drm_framebuffer *fb =
crtc->base.primary->state->fb;
- int clock = adjusted_mode->crtc_clock;
- int htotal = adjusted_mode->crtc_htotal;
+ int clock = pipe_mode->crtc_clock;
+ int htotal = pipe_mode->crtc_htotal;
int hdisplay = crtc->config->pipe_src_w;
int cpp = fb->format->cpp[0];
int entries;
@@ -2345,8 +2346,8 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_A);
crtc = intel_get_crtc_for_plane(dev_priv, PLANE_A);
if (intel_crtc_active(crtc)) {
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc->config->hw.pipe_mode;
const struct drm_framebuffer *fb =
crtc->base.primary->state->fb;
int cpp;
@@ -2356,7 +2357,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
else
cpp = fb->format->cpp[0];
- planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
+ planea_wm = intel_calculate_wm(pipe_mode->crtc_clock,
wm_info, fifo_size, cpp,
pessimal_latency_ns);
enabled = crtc;
@@ -2372,8 +2373,8 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B);
crtc = intel_get_crtc_for_plane(dev_priv, PLANE_B);
if (intel_crtc_active(crtc)) {
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc->config->hw.pipe_mode;
const struct drm_framebuffer *fb =
crtc->base.primary->state->fb;
int cpp;
@@ -2383,7 +2384,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
else
cpp = fb->format->cpp[0];
- planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
+ planeb_wm = intel_calculate_wm(pipe_mode->crtc_clock,
wm_info, fifo_size, cpp,
pessimal_latency_ns);
if (enabled == NULL)
@@ -2421,12 +2422,12 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
if (HAS_FW_BLC(dev_priv) && enabled) {
/* self-refresh has much higher latency */
static const int sr_latency_ns = 6000;
- const struct drm_display_mode *adjusted_mode =
- &enabled->config->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &enabled->config->hw.pipe_mode;
const struct drm_framebuffer *fb =
enabled->base.primary->state->fb;
- int clock = adjusted_mode->crtc_clock;
- int htotal = adjusted_mode->crtc_htotal;
+ int clock = pipe_mode->crtc_clock;
+ int htotal = pipe_mode->crtc_htotal;
int hdisplay = enabled->config->pipe_src_w;
int cpp;
int entries;
@@ -2474,7 +2475,7 @@ static void i845_update_wm(struct intel_crtc *unused_crtc)
{
struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
struct intel_crtc *crtc;
- const struct drm_display_mode *adjusted_mode;
+ const struct drm_display_mode *pipe_mode;
u32 fwater_lo;
int planea_wm;
@@ -2482,8 +2483,8 @@ static void i845_update_wm(struct intel_crtc *unused_crtc)
if (crtc == NULL)
return;
- adjusted_mode = &crtc->config->hw.adjusted_mode;
- planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
+ pipe_mode = &crtc->config->hw.pipe_mode;
+ planea_wm = intel_calculate_wm(pipe_mode->crtc_clock,
&i845_wm_info,
dev_priv->display.get_fifo_size(dev_priv, PLANE_A),
4, pessimal_latency_ns);
@@ -2573,7 +2574,7 @@ static u32 ilk_compute_pri_wm(const struct intel_crtc_state *crtc_state,
return method1;
method2 = ilk_wm_method2(crtc_state->pixel_rate,
- crtc_state->hw.adjusted_mode.crtc_htotal,
+ crtc_state->hw.pipe_mode.crtc_htotal,
drm_rect_width(&plane_state->uapi.dst),
cpp, mem_value);
@@ -2601,7 +2602,7 @@ static u32 ilk_compute_spr_wm(const struct intel_crtc_state *crtc_state,
method1 = ilk_wm_method1(crtc_state->pixel_rate, cpp, mem_value);
method2 = ilk_wm_method2(crtc_state->pixel_rate,
- crtc_state->hw.adjusted_mode.crtc_htotal,
+ crtc_state->hw.pipe_mode.crtc_htotal,
drm_rect_width(&plane_state->uapi.dst),
cpp, mem_value);
return min(method1, method2);
@@ -2626,7 +2627,7 @@ static u32 ilk_compute_cur_wm(const struct intel_crtc_state *crtc_state,
cpp = plane_state->hw.fb->format->cpp[0];
return ilk_wm_method2(crtc_state->pixel_rate,
- crtc_state->hw.adjusted_mode.crtc_htotal,
+ crtc_state->hw.pipe_mode.crtc_htotal,
drm_rect_width(&plane_state->uapi.dst),
cpp, mem_value);
}
@@ -3573,11 +3574,11 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
_ilk_disable_lp_wm(dev_priv, dirty);
if (dirty & WM_DIRTY_PIPE(PIPE_A))
- I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
+ I915_WRITE(WM0_PIPE_ILK(PIPE_A), results->wm_pipe[0]);
if (dirty & WM_DIRTY_PIPE(PIPE_B))
- I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]);
+ I915_WRITE(WM0_PIPE_ILK(PIPE_B), results->wm_pipe[1]);
if (dirty & WM_DIRTY_PIPE(PIPE_C))
- I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]);
+ I915_WRITE(WM0_PIPE_ILK(PIPE_C), results->wm_pipe[2]);
if (dirty & WM_DIRTY_DDB) {
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
@@ -3706,7 +3707,7 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv)
* - All planes can enable watermarks for latencies >= SAGV engine block time
* - We're not using an interlaced display configuration
*/
-int
+static int
intel_enable_sagv(struct drm_i915_private *dev_priv)
{
int ret;
@@ -3740,7 +3741,7 @@ intel_enable_sagv(struct drm_i915_private *dev_priv)
return 0;
}
-int
+static int
intel_disable_sagv(struct drm_i915_private *dev_priv)
{
int ret;
@@ -3873,9 +3874,7 @@ static bool skl_crtc_can_enable_sagv(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);
- struct intel_plane *plane;
- const struct intel_plane_state *plane_state;
- int level, latency;
+ enum plane_id plane_id;
if (!intel_has_sagv(dev_priv))
return false;
@@ -3883,12 +3882,13 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state)
if (!crtc_state->hw.active)
return true;
- if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+ if (crtc_state->hw.pipe_mode.flags & DRM_MODE_FLAG_INTERLACE)
return false;
- intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
+ for_each_plane_id_on_crtc(crtc, plane_id) {
const struct skl_plane_wm *wm =
- &crtc_state->wm.skl.optimal.planes[plane->id];
+ &crtc_state->wm.skl.optimal.planes[plane_id];
+ int level;
/* Skip this plane if it's not enabled */
if (!wm->wm[0].plane_en)
@@ -3899,19 +3899,12 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state)
!wm->wm[level].plane_en; --level)
{ }
- latency = dev_priv->wm.skl_latency[level];
-
- if (skl_needs_memory_bw_wa(dev_priv) &&
- plane_state->uapi.fb->modifier ==
- I915_FORMAT_MOD_X_TILED)
- latency += 15;
-
/*
* If any of the planes on this pipe don't enable wm levels that
* incur memory latencies higher than sagv_block_time_us we
* can't enable SAGV.
*/
- if (latency < dev_priv->sagv_block_time_us)
+ if (!wm->wm[level].can_sagv)
return false;
}
@@ -4174,8 +4167,8 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
*/
total_slice_mask = dbuf_slice_mask;
for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
enum pipe pipe = crtc->pipe;
int hdisplay, vdisplay;
u32 pipe_dbuf_slice_mask;
@@ -4205,7 +4198,7 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
if (dbuf_slice_mask != pipe_dbuf_slice_mask)
continue;
- drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay);
+ drm_mode_get_hv_timing(pipe_mode, &hdisplay, &vdisplay);
total_width_in_range += hdisplay;
@@ -4704,50 +4697,63 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *crtc_state,
}
static u64
-skl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
- u64 *plane_data_rate,
- u64 *uv_plane_data_rate)
+skl_get_total_relative_data_rate(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_plane *plane;
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_plane_state *plane_state;
+ struct intel_plane *plane;
u64 total_data_rate = 0;
+ enum plane_id plane_id;
+ int i;
/* Calculate and cache data rate for each plane */
- intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
- enum plane_id plane_id = plane->id;
- u64 rate;
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+ if (plane->pipe != crtc->pipe)
+ continue;
+
+ plane_id = plane->id;
/* packed/y */
- rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0);
- plane_data_rate[plane_id] = rate;
- total_data_rate += rate;
+ crtc_state->plane_data_rate[plane_id] =
+ skl_plane_relative_data_rate(crtc_state, plane_state, 0);
/* uv-plane */
- rate = skl_plane_relative_data_rate(crtc_state, plane_state, 1);
- uv_plane_data_rate[plane_id] = rate;
- total_data_rate += rate;
+ crtc_state->uv_plane_data_rate[plane_id] =
+ skl_plane_relative_data_rate(crtc_state, plane_state, 1);
+ }
+
+ for_each_plane_id_on_crtc(crtc, plane_id) {
+ total_data_rate += crtc_state->plane_data_rate[plane_id];
+ total_data_rate += crtc_state->uv_plane_data_rate[plane_id];
}
return total_data_rate;
}
static u64
-icl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
- u64 *plane_data_rate)
+icl_get_total_relative_data_rate(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_plane *plane;
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_plane_state *plane_state;
+ struct intel_plane *plane;
u64 total_data_rate = 0;
+ enum plane_id plane_id;
+ int i;
/* Calculate and cache data rate for each plane */
- intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
- enum plane_id plane_id = plane->id;
- u64 rate;
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+ if (plane->pipe != crtc->pipe)
+ continue;
+
+ plane_id = plane->id;
if (!plane_state->planar_linked_plane) {
- rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0);
- plane_data_rate[plane_id] = rate;
- total_data_rate += rate;
+ crtc_state->plane_data_rate[plane_id] =
+ skl_plane_relative_data_rate(crtc_state, plane_state, 0);
} else {
enum plane_id y_plane_id;
@@ -4762,17 +4768,18 @@ icl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
continue;
/* Y plane rate is calculated on the slave */
- rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0);
y_plane_id = plane_state->planar_linked_plane->id;
- plane_data_rate[y_plane_id] = rate;
- total_data_rate += rate;
+ crtc_state->plane_data_rate[y_plane_id] =
+ skl_plane_relative_data_rate(crtc_state, plane_state, 0);
- rate = skl_plane_relative_data_rate(crtc_state, plane_state, 1);
- plane_data_rate[plane_id] = rate;
- total_data_rate += rate;
+ crtc_state->plane_data_rate[plane_id] =
+ skl_plane_relative_data_rate(crtc_state, plane_state, 1);
}
}
+ for_each_plane_id_on_crtc(crtc, plane_id)
+ total_data_rate += crtc_state->plane_data_rate[plane_id];
+
return total_data_rate;
}
@@ -4791,9 +4798,11 @@ skl_plane_wm_level(const struct intel_crtc_state *crtc_state,
}
static int
-skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state)
+skl_allocate_pipe_ddb(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct skl_ddb_entry *alloc = &crtc_state->wm.skl.ddb;
u16 alloc_size, start = 0;
@@ -4802,8 +4811,6 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state)
u64 total_data_rate;
enum plane_id plane_id;
int num_active;
- u64 plane_data_rate[I915_MAX_PLANES] = {};
- u64 uv_plane_data_rate[I915_MAX_PLANES] = {};
u32 blocks;
int level;
int ret;
@@ -4843,13 +4850,10 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state)
if (INTEL_GEN(dev_priv) >= 11)
total_data_rate =
- icl_get_total_relative_data_rate(crtc_state,
- plane_data_rate);
+ icl_get_total_relative_data_rate(state, crtc);
else
total_data_rate =
- skl_get_total_relative_data_rate(crtc_state,
- plane_data_rate,
- uv_plane_data_rate);
+ skl_get_total_relative_data_rate(state, crtc);
ret = skl_ddb_get_pipe_allocation_limits(dev_priv, crtc_state,
total_data_rate,
@@ -4930,7 +4934,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state)
if (total_data_rate == 0)
break;
- rate = plane_data_rate[plane_id];
+ rate = crtc_state->plane_data_rate[plane_id];
extra = min_t(u16, alloc_size,
DIV64_U64_ROUND_UP(alloc_size * rate,
total_data_rate));
@@ -4941,7 +4945,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state)
if (total_data_rate == 0)
break;
- rate = uv_plane_data_rate[plane_id];
+ rate = crtc_state->uv_plane_data_rate[plane_id];
extra = min_t(u16, alloc_size,
DIV64_U64_ROUND_UP(alloc_size * rate,
total_data_rate));
@@ -5093,36 +5097,12 @@ intel_get_linetime_us(const struct intel_crtc_state *crtc_state)
if (drm_WARN_ON(&dev_priv->drm, pixel_rate == 0))
return u32_to_fixed16(0);
- crtc_htotal = crtc_state->hw.adjusted_mode.crtc_htotal;
+ crtc_htotal = crtc_state->hw.pipe_mode.crtc_htotal;
linetime_us = div_fixed16(crtc_htotal * 1000, pixel_rate);
return linetime_us;
}
-static u32
-skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
- const struct intel_plane_state *plane_state)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
- u64 adjusted_pixel_rate;
- uint_fixed_16_16_t downscale_amount;
-
- /* Shouldn't reach here on disabled planes... */
- if (drm_WARN_ON(&dev_priv->drm,
- !intel_wm_plane_visible(crtc_state, plane_state)))
- return 0;
-
- /*
- * Adjusted plane pixel rate is just the pipe's adjusted pixel rate
- * with additional adjustments for plane-specific scaling.
- */
- adjusted_pixel_rate = crtc_state->pixel_rate;
- downscale_amount = skl_plane_downscale_amount(crtc_state, plane_state);
-
- return mul_round_up_u32_fixed16(adjusted_pixel_rate,
- downscale_amount);
-}
-
static int
skl_compute_wm_params(const struct intel_crtc_state *crtc_state,
int width, const struct drm_format_info *format,
@@ -5235,7 +5215,7 @@ skl_compute_plane_wm_params(const struct intel_crtc_state *crtc_state,
return skl_compute_wm_params(crtc_state, width,
fb->format, fb->modifier,
plane_state->hw.rotation,
- skl_adjusted_plane_pixel_rate(crtc_state, plane_state),
+ intel_plane_pixel_rate(crtc_state, plane_state),
wp, color_plane);
}
@@ -5282,14 +5262,14 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
method1 = skl_wm_method1(dev_priv, wp->plane_pixel_rate,
wp->cpp, latency, wp->dbuf_block_size);
method2 = skl_wm_method2(wp->plane_pixel_rate,
- crtc_state->hw.adjusted_mode.crtc_htotal,
+ crtc_state->hw.pipe_mode.crtc_htotal,
latency,
wp->plane_blocks_per_line);
if (wp->y_tiled) {
selected_result = max_fixed16(method2, wp->y_tile_minimum);
} else {
- if ((wp->cpp * crtc_state->hw.adjusted_mode.crtc_htotal /
+ if ((wp->cpp * crtc_state->hw.pipe_mode.crtc_htotal /
wp->dbuf_block_size < 1) &&
(wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) {
selected_result = method2;
@@ -5373,6 +5353,9 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
/* Bspec says: value >= plane ddb allocation -> invalid, hence the +1 here */
result->min_ddb_alloc = max(min_ddb_alloc, res_blocks) + 1;
result->plane_en = true;
+
+ if (INTEL_GEN(dev_priv) < 12)
+ result->can_sagv = latency >= dev_priv->sagv_block_time_us;
}
static void
@@ -5478,7 +5461,7 @@ static int skl_build_plane_wm_single(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);
- struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+ struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id];
struct skl_wm_params wm_params;
int ret;
@@ -5501,7 +5484,7 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
enum plane_id plane_id)
{
- struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+ struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id];
struct skl_wm_params wm_params;
int ret;
@@ -5522,10 +5505,13 @@ static int skl_build_plane_wm(struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
- const struct drm_framebuffer *fb = plane_state->hw.fb;
enum plane_id plane_id = plane->id;
+ struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id];
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
int ret;
+ memset(wm, 0, sizeof(*wm));
+
if (!intel_wm_plane_visible(crtc_state, plane_state))
return 0;
@@ -5547,10 +5533,14 @@ static int skl_build_plane_wm(struct intel_crtc_state *crtc_state,
static int icl_build_plane_wm(struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
- enum plane_id plane_id = to_intel_plane(plane_state->uapi.plane)->id;
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ enum plane_id plane_id = plane->id;
+ struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id];
int ret;
+ memset(wm, 0, sizeof(*wm));
+
/* Watermarks calculated in master */
if (plane_state->planar_slave)
return 0;
@@ -5583,22 +5573,24 @@ static int icl_build_plane_wm(struct intel_crtc_state *crtc_state,
return 0;
}
-static int skl_build_pipe_wm(struct intel_crtc_state *crtc_state)
+static int skl_build_pipe_wm(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
- struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
- struct intel_plane *plane;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_plane_state *plane_state;
- int ret;
-
- /*
- * We'll only calculate watermarks for planes that are actually
- * enabled, so make sure all other planes are set as disabled.
- */
- memset(pipe_wm->planes, 0, sizeof(pipe_wm->planes));
+ struct intel_plane *plane;
+ int ret, i;
- intel_atomic_crtc_state_for_each_plane_state(plane, plane_state,
- crtc_state) {
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+ /*
+ * FIXME should perhaps check {old,new}_plane_crtc->hw.crtc
+ * instead but we don't populate that correctly for NV12 Y
+ * planes so for now hack this.
+ */
+ if (plane->pipe != crtc->pipe)
+ continue;
if (INTEL_GEN(dev_priv) >= 11)
ret = icl_build_plane_wm(crtc_state, plane_state);
@@ -5608,6 +5600,8 @@ static int skl_build_pipe_wm(struct intel_crtc_state *crtc_state)
return ret;
}
+ crtc_state->wm.skl.optimal = crtc_state->wm.skl.raw;
+
return 0;
}
@@ -5794,7 +5788,7 @@ skl_compute_ddb(struct intel_atomic_state *state)
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
- ret = skl_allocate_pipe_ddb(new_crtc_state);
+ ret = skl_allocate_pipe_ddb(state, crtc);
if (ret)
return ret;
@@ -6092,7 +6086,6 @@ skl_compute_wm(struct intel_atomic_state *state)
{
struct intel_crtc *crtc;
struct intel_crtc_state *new_crtc_state;
- struct intel_crtc_state *old_crtc_state;
int ret, i;
ret = skl_ddb_add_affected_pipes(state);
@@ -6104,9 +6097,8 @@ skl_compute_wm(struct intel_atomic_state *state)
* Note that skl_ddb_add_affected_pipes may have added more CRTC's that
* weren't otherwise being modified if pipe allocations had to change.
*/
- for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
- new_crtc_state, i) {
- ret = skl_build_pipe_wm(new_crtc_state);
+ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+ ret = skl_build_pipe_wm(state, crtc);
if (ret)
return ret;
}
@@ -6124,8 +6116,7 @@ skl_compute_wm(struct intel_atomic_state *state)
* based on how much ddb is available. Now we can actually
* check if the final watermarks changed.
*/
- for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
- new_crtc_state, i) {
+ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
ret = skl_wm_add_affected_planes(state, crtc);
if (ret)
return ret;
@@ -6271,6 +6262,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
crtc_state = to_intel_crtc_state(crtc->base.state);
skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
+ crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal;
}
if (dev_priv->active_pipes) {
@@ -6287,13 +6279,8 @@ static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
struct intel_pipe_wm *active = &crtc_state->wm.ilk.optimal;
enum pipe pipe = crtc->pipe;
- static const i915_reg_t wm0_pipe_reg[] = {
- [PIPE_A] = WM0_PIPEA_ILK,
- [PIPE_B] = WM0_PIPEB_ILK,
- [PIPE_C] = WM0_PIPEC_IVB,
- };
- hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]);
+ hw->wm_pipe[pipe] = I915_READ(WM0_PIPE_ILK(pipe));
memset(active, 0, sizeof(*active));
@@ -7132,6 +7119,14 @@ static void tgl_init_clock_gating(struct drm_i915_private *dev_priv)
0, DFR_DISABLE);
}
+static void dg1_init_clock_gating(struct drm_i915_private *dev_priv)
+{
+ /* Wa_1409836686:dg1[a0] */
+ if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0))
+ I915_WRITE(GEN9_CLKGATE_DIS_3, I915_READ(GEN9_CLKGATE_DIS_3) |
+ DPT_GATING_DIS);
+}
+
static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
{
if (!HAS_PCH_CNP(dev_priv))
@@ -7184,6 +7179,10 @@ static void cfl_init_clock_gating(struct drm_i915_private *dev_priv)
cnp_init_clock_gating(dev_priv);
gen9_init_clock_gating(dev_priv);
+ /* WAC6entrylatency:cfl */
+ I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) |
+ FBC_LLC_FULLY_OPEN);
+
/*
* WaFbcTurnOffFbcWatermark:cfl
* Display WA #0562: cfl
@@ -7203,6 +7202,10 @@ static void kbl_init_clock_gating(struct drm_i915_private *dev_priv)
{
gen9_init_clock_gating(dev_priv);
+ /* WAC6entrylatency:kbl */
+ I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) |
+ FBC_LLC_FULLY_OPEN);
+
/* WaDisableSDEUnitClockGating:kbl */
if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
@@ -7577,7 +7580,9 @@ static void nop_init_clock_gating(struct drm_i915_private *dev_priv)
*/
void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv)
{
- if (IS_GEN(dev_priv, 12))
+ if (IS_DG1(dev_priv))
+ dev_priv->display.init_clock_gating = dg1_init_clock_gating;
+ else if (IS_GEN(dev_priv, 12))
dev_priv->display.init_clock_gating = tgl_init_clock_gating;
else if (IS_GEN(dev_priv, 11))
dev_priv->display.init_clock_gating = icl_init_clock_gating;
diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h
index a2473594c2db..eab83e251dd5 100644
--- a/drivers/gpu/drm/i915/intel_pm.h
+++ b/drivers/gpu/drm/i915/intel_pm.h
@@ -49,8 +49,6 @@ void g4x_wm_sanitize(struct drm_i915_private *dev_priv);
void vlv_wm_sanitize(struct drm_i915_private *dev_priv);
bool intel_can_enable_sagv(struct drm_i915_private *dev_priv,
const struct intel_bw_state *bw_state);
-int intel_enable_sagv(struct drm_i915_private *dev_priv);
-int intel_disable_sagv(struct drm_i915_private *dev_priv);
void intel_sagv_pre_plane_update(struct intel_atomic_state *state);
void intel_sagv_post_plane_update(struct intel_atomic_state *state);
bool skl_wm_level_equals(const struct skl_wm_level *l1,
diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c
index 5b3279262123..02ebf5a04a9b 100644
--- a/drivers/gpu/drm/i915/intel_sideband.c
+++ b/drivers/gpu/drm/i915/intel_sideband.c
@@ -555,3 +555,18 @@ out:
return ret ? ret : status;
#undef COND
}
+
+void intel_pcode_init(struct drm_i915_private *i915)
+{
+ int ret;
+
+ if (!IS_DGFX(i915))
+ return;
+
+ ret = skl_pcode_request(i915, DG1_PCODE_STATUS,
+ DG1_UNCORE_GET_INIT_STATUS,
+ DG1_UNCORE_INIT_STATUS_COMPLETE,
+ DG1_UNCORE_INIT_STATUS_COMPLETE, 50);
+ if (ret)
+ drm_err(&i915->drm, "Pcode did not report uncore initialization completion!\n");
+}
diff --git a/drivers/gpu/drm/i915/intel_sideband.h b/drivers/gpu/drm/i915/intel_sideband.h
index 7fb95745a444..094c7b19c5d4 100644
--- a/drivers/gpu/drm/i915/intel_sideband.h
+++ b/drivers/gpu/drm/i915/intel_sideband.h
@@ -138,4 +138,6 @@ int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, u32 mbox,
int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request,
u32 reply_mask, u32 reply, int timeout_base_ms);
+void intel_pcode_init(struct drm_i915_private *i915);
+
#endif /* _INTEL_SIDEBAND_H */
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 97ded2a59cf4..1c14a07eba7d 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -1051,37 +1051,37 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = {
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
static const struct intel_forcewake_range __gen9_fw_ranges[] = {
- GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_GT),
GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */
GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8000, 0x812f, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8000, 0x812f, FORCEWAKE_GT),
GEN_FW_RANGE(0x8130, 0x813f, FORCEWAKE_MEDIA),
GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x8800, 0x89ff, FORCEWAKE_MEDIA),
- GEN_FW_RANGE(0x8a00, 0x8bff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8a00, 0x8bff, FORCEWAKE_GT),
GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
- GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_GT),
GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0xb480, 0xcfff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0xb480, 0xcfff, FORCEWAKE_GT),
GEN_FW_RANGE(0xd000, 0xd7ff, FORCEWAKE_MEDIA),
- GEN_FW_RANGE(0xd800, 0xdfff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0xd800, 0xdfff, FORCEWAKE_GT),
GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0xe900, 0x11fff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0xe900, 0x11fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x12000, 0x13fff, FORCEWAKE_MEDIA),
- GEN_FW_RANGE(0x14000, 0x19fff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x14000, 0x19fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x1a000, 0x1e9ff, FORCEWAKE_MEDIA),
- GEN_FW_RANGE(0x1ea00, 0x243ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x1ea00, 0x243ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x24800, 0x2ffff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x24800, 0x2ffff, FORCEWAKE_GT),
GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_MEDIA),
};
@@ -1089,33 +1089,33 @@ static const struct intel_forcewake_range __gen9_fw_ranges[] = {
static const struct intel_forcewake_range __gen11_fw_ranges[] = {
GEN_FW_RANGE(0x0, 0x1fff, 0), /* uncore range */
GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_GT),
GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x8800, 0x8bff, 0),
GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8d00, 0x94cf, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8d00, 0x94cf, FORCEWAKE_GT),
GEN_FW_RANGE(0x94d0, 0x955f, FORCEWAKE_RENDER),
GEN_FW_RANGE(0x9560, 0x95ff, 0),
- GEN_FW_RANGE(0x9600, 0xafff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x9600, 0xafff, FORCEWAKE_GT),
GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0xb480, 0xdeff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0xb480, 0xdeff, FORCEWAKE_GT),
GEN_FW_RANGE(0xdf00, 0xe8ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0xe900, 0x16dff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0xe900, 0x16dff, FORCEWAKE_GT),
GEN_FW_RANGE(0x16e00, 0x19fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x1a000, 0x23fff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x1a000, 0x23fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x24000, 0x2407f, 0),
- GEN_FW_RANGE(0x24080, 0x2417f, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x24080, 0x2417f, FORCEWAKE_GT),
GEN_FW_RANGE(0x24180, 0x242ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x24300, 0x243ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x24300, 0x243ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x24400, 0x24fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x25000, 0x3ffff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x25000, 0x3ffff, FORCEWAKE_GT),
GEN_FW_RANGE(0x40000, 0x1bffff, 0),
GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0),
GEN_FW_RANGE(0x1c4000, 0x1c7fff, 0),
@@ -1124,44 +1124,113 @@ static const struct intel_forcewake_range __gen11_fw_ranges[] = {
GEN_FW_RANGE(0x1d4000, 0x1dbfff, 0)
};
-/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
+/*
+ * *Must* be sorted by offset ranges! See intel_fw_table_check().
+ *
+ * Note that the spec lists several reserved/unused ranges that don't
+ * actually contain any registers. In the table below we'll combine those
+ * reserved ranges with either the preceding or following range to keep the
+ * table small and lookups fast.
+ */
static const struct intel_forcewake_range __gen12_fw_ranges[] = {
- GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */
+ GEN_FW_RANGE(0x0, 0x1fff, 0), /*
+ 0x0 - 0xaff: reserved
+ 0xb00 - 0x1fff: always on */
GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x2700, 0x27ff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x2800, 0x2aff, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0x2b00, 0x2fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT), /*
+ 0x4000 - 0x48ff: gt
+ 0x4900 - 0x51ff: reserved */
+ GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), /*
+ 0x5200 - 0x53ff: render
+ 0x5400 - 0x54ff: reserved
+ 0x5500 - 0x7fff: render */
+ GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_GT),
GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8160, 0x81ff, 0), /*
+ 0x8160 - 0x817f: reserved
+ 0x8180 - 0x81ff: always on */
+ GEN_FW_RANGE(0x8200, 0x82ff, FORCEWAKE_GT),
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8500, 0x8bff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_ALL),
- GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0xb480, 0xdfff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0xe900, 0x147ff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x14800, 0x148ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x14900, 0x19fff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x1a000, 0x1a7ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x1a800, 0x1afff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x1b000, 0x1bfff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x1c000, 0x243ff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER),
- GEN_FW_RANGE(0x24800, 0x3ffff, FORCEWAKE_BLITTER),
+ GEN_FW_RANGE(0x8500, 0x94cf, FORCEWAKE_GT), /*
+ 0x8500 - 0x87ff: gt
+ 0x8800 - 0x8fff: reserved
+ 0x9000 - 0x947f: gt
+ 0x9480 - 0x94cf: reserved */
+ GEN_FW_RANGE(0x94d0, 0x955f, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0x9560, 0x97ff, 0), /*
+ 0x9560 - 0x95ff: always on
+ 0x9600 - 0x97ff: reserved */
+ GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0xb000, 0xb3ff, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0xb400, 0xcfff, FORCEWAKE_GT), /*
+ 0xb400 - 0xbf7f: gt
+ 0xb480 - 0xbfff: reserved
+ 0xc000 - 0xcfff: gt */
+ GEN_FW_RANGE(0xd000, 0xd7ff, 0),
+ GEN_FW_RANGE(0xd800, 0xd8ff, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0xd900, 0xdbff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0xdc00, 0xefff, FORCEWAKE_RENDER), /*
+ 0xdc00 - 0xddff: render
+ 0xde00 - 0xde7f: reserved
+ 0xde80 - 0xe8ff: render
+ 0xe900 - 0xefff: reserved */
+ GEN_FW_RANGE(0xf000, 0x147ff, FORCEWAKE_GT), /*
+ 0xf000 - 0xffff: gt
+ 0x10000 - 0x147ff: reserved */
+ GEN_FW_RANGE(0x14800, 0x1ffff, FORCEWAKE_RENDER), /*
+ 0x14800 - 0x14fff: render
+ 0x15000 - 0x16dff: reserved
+ 0x16e00 - 0x1bfff: render
+ 0x1c000 - 0x1ffff: reserved */
+ GEN_FW_RANGE(0x20000, 0x20fff, FORCEWAKE_MEDIA_VDBOX0),
+ GEN_FW_RANGE(0x21000, 0x21fff, FORCEWAKE_MEDIA_VDBOX2),
+ GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x24000, 0x2417f, 0), /*
+ 0x24000 - 0x2407f: always on
+ 0x24080 - 0x2417f: reserved */
+ GEN_FW_RANGE(0x24180, 0x249ff, FORCEWAKE_GT), /*
+ 0x24180 - 0x241ff: gt
+ 0x24200 - 0x249ff: reserved */
+ GEN_FW_RANGE(0x24a00, 0x251ff, FORCEWAKE_RENDER), /*
+ 0x24a00 - 0x24a7f: render
+ 0x24a80 - 0x251ff: reserved */
+ GEN_FW_RANGE(0x25200, 0x255ff, FORCEWAKE_GT), /*
+ 0x25200 - 0x252ff: gt
+ 0x25300 - 0x255ff: reserved */
+ GEN_FW_RANGE(0x25600, 0x2567f, FORCEWAKE_MEDIA_VDBOX0),
+ GEN_FW_RANGE(0x25680, 0x259ff, FORCEWAKE_MEDIA_VDBOX2), /*
+ 0x25680 - 0x256ff: VD2
+ 0x25700 - 0x259ff: reserved */
+ GEN_FW_RANGE(0x25a00, 0x25a7f, FORCEWAKE_MEDIA_VDBOX0),
+ GEN_FW_RANGE(0x25a80, 0x2ffff, FORCEWAKE_MEDIA_VDBOX2), /*
+ 0x25a80 - 0x25aff: VD2
+ 0x25b00 - 0x2ffff: reserved */
+ GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT),
GEN_FW_RANGE(0x40000, 0x1bffff, 0),
- GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0),
- GEN_FW_RANGE(0x1c4000, 0x1c7fff, FORCEWAKE_MEDIA_VDBOX1),
- GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0),
- GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_BLITTER),
- GEN_FW_RANGE(0x1d0000, 0x1d3fff, FORCEWAKE_MEDIA_VDBOX2),
- GEN_FW_RANGE(0x1d4000, 0x1d7fff, FORCEWAKE_MEDIA_VDBOX3),
- GEN_FW_RANGE(0x1d8000, 0x1dbfff, FORCEWAKE_MEDIA_VEBOX1)
+ GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0), /*
+ 0x1c0000 - 0x1c2bff: VD0
+ 0x1c2c00 - 0x1c2cff: reserved
+ 0x1c2d00 - 0x1c2dff: VD0
+ 0x1c2e00 - 0x1c3eff: reserved
+ 0x1c3f00 - 0x1c3fff: VD0 */
+ GEN_FW_RANGE(0x1c4000, 0x1c7fff, 0),
+ GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0), /*
+ 0x1c8000 - 0x1ca0ff: VE0
+ 0x1ca100 - 0x1cbeff: reserved
+ 0x1cbf00 - 0x1cbfff: VE0 */
+ GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_MEDIA_VDBOX0), /*
+ 0x1cc000 - 0x1ccfff: VD0
+ 0x1cd000 - 0x1cffff: reserved */
+ GEN_FW_RANGE(0x1d0000, 0x1d3fff, FORCEWAKE_MEDIA_VDBOX2), /*
+ 0x1d0000 - 0x1d2bff: VD2
+ 0x1d2c00 - 0x1d2cff: reserved
+ 0x1d2d00 - 0x1d2dff: VD2
+ 0x1d2e00 - 0x1d3eff: reserved
+ 0x1d3f00 - 0x1d3fff: VD2 */
};
static void
@@ -1491,7 +1560,7 @@ static int __fw_domain_init(struct intel_uncore *uncore,
d->id = domain_id;
BUILD_BUG_ON(FORCEWAKE_RENDER != (1 << FW_DOMAIN_ID_RENDER));
- BUILD_BUG_ON(FORCEWAKE_BLITTER != (1 << FW_DOMAIN_ID_BLITTER));
+ BUILD_BUG_ON(FORCEWAKE_GT != (1 << FW_DOMAIN_ID_GT));
BUILD_BUG_ON(FORCEWAKE_MEDIA != (1 << FW_DOMAIN_ID_MEDIA));
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX0));
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX1));
@@ -1560,9 +1629,9 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore)
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
FORCEWAKE_RENDER_GEN9,
FORCEWAKE_ACK_RENDER_GEN9);
- fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
- FORCEWAKE_BLITTER_GEN9,
- FORCEWAKE_ACK_BLITTER_GEN9);
+ fw_domain_init(uncore, FW_DOMAIN_ID_GT,
+ FORCEWAKE_GT_GEN9,
+ FORCEWAKE_ACK_GT_GEN9);
for (i = 0; i < I915_MAX_VCS; i++) {
if (!__HAS_ENGINE(emask, _VCS(i)))
@@ -1586,9 +1655,9 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore)
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
FORCEWAKE_RENDER_GEN9,
FORCEWAKE_ACK_RENDER_GEN9);
- fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
- FORCEWAKE_BLITTER_GEN9,
- FORCEWAKE_ACK_BLITTER_GEN9);
+ fw_domain_init(uncore, FW_DOMAIN_ID_GT,
+ FORCEWAKE_GT_GEN9,
+ FORCEWAKE_ACK_GT_GEN9);
fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
} else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
@@ -1723,11 +1792,15 @@ static int uncore_mmio_setup(struct intel_uncore *uncore)
* clobbering the GTT which we want ioremap_wc instead. Fortunately,
* the register BAR remains the same size for all the earlier
* generations up to Ironlake.
+ * For dgfx chips register range is expanded to 4MB.
*/
if (INTEL_GEN(i915) < 5)
mmio_size = 512 * 1024;
+ else if (IS_DGFX(i915))
+ mmio_size = 4 * 1024 * 1024;
else
mmio_size = 2 * 1024 * 1024;
+
uncore->regs = pci_iomap(pdev, mmio_bar, mmio_size);
if (uncore->regs == NULL) {
drm_err(&i915->drm, "failed to map registers\n");
diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
index c4b22d9d0b45..bd2467284295 100644
--- a/drivers/gpu/drm/i915/intel_uncore.h
+++ b/drivers/gpu/drm/i915/intel_uncore.h
@@ -46,7 +46,7 @@ struct intel_uncore_mmio_debug {
enum forcewake_domain_id {
FW_DOMAIN_ID_RENDER = 0,
- FW_DOMAIN_ID_BLITTER,
+ FW_DOMAIN_ID_GT, /* also includes blitter engine */
FW_DOMAIN_ID_MEDIA,
FW_DOMAIN_ID_MEDIA_VDBOX0,
FW_DOMAIN_ID_MEDIA_VDBOX1,
@@ -60,7 +60,7 @@ enum forcewake_domain_id {
enum forcewake_domains {
FORCEWAKE_RENDER = BIT(FW_DOMAIN_ID_RENDER),
- FORCEWAKE_BLITTER = BIT(FW_DOMAIN_ID_BLITTER),
+ FORCEWAKE_GT = BIT(FW_DOMAIN_ID_GT),
FORCEWAKE_MEDIA = BIT(FW_DOMAIN_ID_MEDIA),
FORCEWAKE_MEDIA_VDBOX0 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX0),
FORCEWAKE_MEDIA_VDBOX1 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX1),
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index b6c42fd872ad..e946bd2087d8 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -81,13 +81,10 @@ out:
i915_params_free(&i915->params);
}
-static struct drm_driver mock_driver = {
+static const struct drm_driver mock_driver = {
.name = "mock",
.driver_features = DRIVER_GEM,
.release = mock_device_release,
-
- .gem_close_object = i915_gem_close_object,
- .gem_free_object_unlocked = i915_gem_free_object,
};
static void release_dev(struct device *dev)