Merge drm/drm-next into drm-intel-next-queued
authorRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 10 Jul 2019 13:51:35 +0000 (06:51 -0700)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 10 Jul 2019 13:51:35 +0000 (06:51 -0700)
Catch-up with 5.2. Specially to remove a drm-tip merge
fixup around intel_workarounds.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
195 files changed:
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/Makefile.header-test
drivers/gpu/drm/i915/display/Makefile
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_atomic_plane.c
drivers/gpu/drm/i915/display/intel_atomic_plane.h
drivers/gpu/drm/i915/display/intel_audio.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_bios.h
drivers/gpu/drm/i915/display/intel_bw.c
drivers/gpu/drm/i915/display/intel_cdclk.c
drivers/gpu/drm/i915/display/intel_combo_phy.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display.h
drivers/gpu/drm/i915/display/intel_display_power.c
drivers/gpu/drm/i915/display/intel_display_power.h
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
drivers/gpu/drm/i915/display/intel_dp_mst.h
drivers/gpu/drm/i915/display/intel_dpll_mgr.c
drivers/gpu/drm/i915/display/intel_dpll_mgr.h
drivers/gpu/drm/i915/display/intel_hdcp.c
drivers/gpu/drm/i915/display/intel_overlay.c
drivers/gpu/drm/i915/display/intel_pipe_crc.c
drivers/gpu/drm/i915/display/intel_sdvo.c
drivers/gpu/drm/i915/display/intel_sprite.c
drivers/gpu/drm/i915/display/intel_tc.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_tc.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/vlv_dsi.c
drivers/gpu/drm/i915/gem/Makefile
drivers/gpu/drm/i915/gem/i915_gem_client_blt.c
drivers/gpu/drm/i915/gem/i915_gem_context.c
drivers/gpu/drm/i915/gem/i915_gem_context.h
drivers/gpu/drm/i915/gem/i915_gem_context_types.h
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_object.c
drivers/gpu/drm/i915/gem/i915_gem_object.h
drivers/gpu/drm/i915/gem/i915_gem_object_types.h
drivers/gpu/drm/i915/gem/i915_gem_phys.c
drivers/gpu/drm/i915/gem/i915_gem_pm.c
drivers/gpu/drm/i915/gem/i915_gem_shmem.c
drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
drivers/gpu/drm/i915/gem/i915_gem_stolen.c
drivers/gpu/drm/i915/gem/i915_gem_userptr.c
drivers/gpu/drm/i915/gem/selftests/huge_pages.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_object_blt.c
drivers/gpu/drm/i915/gt/Makefile
drivers/gpu/drm/i915/gt/gen6_renderstate.c [moved from drivers/gpu/drm/i915/intel_renderstate_gen6.c with 100% similarity]
drivers/gpu/drm/i915/gt/gen7_renderstate.c [moved from drivers/gpu/drm/i915/intel_renderstate_gen7.c with 100% similarity]
drivers/gpu/drm/i915/gt/gen8_renderstate.c [moved from drivers/gpu/drm/i915/intel_renderstate_gen8.c with 100% similarity]
drivers/gpu/drm/i915/gt/gen9_renderstate.c [moved from drivers/gpu/drm/i915/intel_renderstate_gen9.c with 100% similarity]
drivers/gpu/drm/i915/gt/intel_context.c
drivers/gpu/drm/i915/gt/intel_context.h
drivers/gpu/drm/i915/gt/intel_context_types.h
drivers/gpu/drm/i915/gt/intel_engine.h
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/gt/intel_engine_pm.c
drivers/gpu/drm/i915/gt/intel_engine_pm.h
drivers/gpu/drm/i915/gt/intel_engine_types.h
drivers/gpu/drm/i915/gt/intel_gt.c [new file with mode: 0644]
drivers/gpu/drm/i915/gt/intel_gt.h [new file with mode: 0644]
drivers/gpu/drm/i915/gt/intel_gt_pm.c
drivers/gpu/drm/i915/gt/intel_gt_pm.h
drivers/gpu/drm/i915/gt/intel_gt_types.h [new file with mode: 0644]
drivers/gpu/drm/i915/gt/intel_hangcheck.c
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/gt/intel_mocs.c
drivers/gpu/drm/i915/gt/intel_mocs.h
drivers/gpu/drm/i915/gt/intel_renderstate.c [moved from drivers/gpu/drm/i915/i915_gem_render_state.c with 95% similarity]
drivers/gpu/drm/i915/gt/intel_renderstate.h [moved from drivers/gpu/drm/i915/intel_renderstate.h with 91% similarity]
drivers/gpu/drm/i915/gt/intel_reset.c
drivers/gpu/drm/i915/gt/intel_reset.h
drivers/gpu/drm/i915/gt/intel_ringbuffer.c
drivers/gpu/drm/i915/gt/intel_timeline.c [moved from drivers/gpu/drm/i915/i915_timeline.c with 69% similarity]
drivers/gpu/drm/i915/gt/intel_timeline.h [new file with mode: 0644]
drivers/gpu/drm/i915/gt/intel_timeline_types.h [moved from drivers/gpu/drm/i915/i915_timeline_types.h with 92% similarity]
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/gt/intel_workarounds.h
drivers/gpu/drm/i915/gt/mock_engine.c
drivers/gpu/drm/i915/gt/selftest_hangcheck.c
drivers/gpu/drm/i915/gt/selftest_lrc.c
drivers/gpu/drm/i915/gt/selftest_reset.c
drivers/gpu/drm/i915/gt/selftest_timeline.c [moved from drivers/gpu/drm/i915/selftests/i915_timeline.c with 86% similarity]
drivers/gpu/drm/i915/gt/selftest_workarounds.c
drivers/gpu/drm/i915/gt/selftests/mock_timeline.c [moved from drivers/gpu/drm/i915/selftests/mock_timeline.c with 68% similarity]
drivers/gpu/drm/i915/gt/selftests/mock_timeline.h [moved from drivers/gpu/drm/i915/selftests/mock_timeline.h with 53% similarity]
drivers/gpu/drm/i915/i915_active.c
drivers/gpu/drm/i915/i915_active.h
drivers/gpu/drm/i915/i915_active_types.h
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_fixed.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_batch_pool.c
drivers/gpu/drm/i915/i915_gem_fence_reg.c
drivers/gpu/drm/i915/i915_gem_fence_reg.h
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_render_state.h [deleted file]
drivers/gpu/drm/i915/i915_globals.h
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_irq.h
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_params.h
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/i915_priolist_types.h
drivers/gpu/drm/i915/i915_pvinfo.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_request.h
drivers/gpu/drm/i915/i915_scheduler.c
drivers/gpu/drm/i915/i915_scheduler_types.h
drivers/gpu/drm/i915/i915_selftest.h
drivers/gpu/drm/i915/i915_timeline.h [deleted file]
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/i915_utils.h
drivers/gpu/drm/i915/i915_vgpu.c
drivers/gpu/drm/i915/i915_vgpu.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_device_info.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_guc.h
drivers/gpu/drm/i915/intel_guc_ads.c
drivers/gpu/drm/i915/intel_guc_ct.c
drivers/gpu/drm/i915/intel_guc_ct.h
drivers/gpu/drm/i915/intel_guc_fw.c
drivers/gpu/drm/i915/intel_guc_fwif.h
drivers/gpu/drm/i915/intel_guc_log.c
drivers/gpu/drm/i915/intel_guc_reg.h
drivers/gpu/drm/i915/intel_guc_submission.c
drivers/gpu/drm/i915/intel_gvt.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_pm.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_uc.c
drivers/gpu/drm/i915/intel_uc_fw.h
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/i915/intel_uncore.h
drivers/gpu/drm/i915/intel_wakeref.c
drivers/gpu/drm/i915/intel_wakeref.h
drivers/gpu/drm/i915/intel_wopcm.c
drivers/gpu/drm/i915/intel_wopcm.h
drivers/gpu/drm/i915/oa/Makefile [new file with mode: 0644]
drivers/gpu/drm/i915/oa/i915_oa_bdw.c [moved from drivers/gpu/drm/i915/i915_oa_bdw.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_bdw.h [moved from drivers/gpu/drm/i915/i915_oa_bdw.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_bxt.c [moved from drivers/gpu/drm/i915/i915_oa_bxt.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_bxt.h [moved from drivers/gpu/drm/i915/i915_oa_bxt.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_cflgt2.c [moved from drivers/gpu/drm/i915/i915_oa_cflgt2.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_cflgt2.h [moved from drivers/gpu/drm/i915/i915_oa_cflgt2.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_cflgt3.c [moved from drivers/gpu/drm/i915/i915_oa_cflgt3.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_cflgt3.h [moved from drivers/gpu/drm/i915/i915_oa_cflgt3.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_chv.c [moved from drivers/gpu/drm/i915/i915_oa_chv.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_chv.h [moved from drivers/gpu/drm/i915/i915_oa_chv.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_cnl.c [moved from drivers/gpu/drm/i915/i915_oa_cnl.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_cnl.h [moved from drivers/gpu/drm/i915/i915_oa_cnl.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_glk.c [moved from drivers/gpu/drm/i915/i915_oa_glk.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_glk.h [moved from drivers/gpu/drm/i915/i915_oa_glk.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_hsw.c [moved from drivers/gpu/drm/i915/i915_oa_hsw.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_hsw.h [moved from drivers/gpu/drm/i915/i915_oa_hsw.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_icl.c [moved from drivers/gpu/drm/i915/i915_oa_icl.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_icl.h [moved from drivers/gpu/drm/i915/i915_oa_icl.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_kblgt2.c [moved from drivers/gpu/drm/i915/i915_oa_kblgt2.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_kblgt2.h [moved from drivers/gpu/drm/i915/i915_oa_kblgt2.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_kblgt3.c [moved from drivers/gpu/drm/i915/i915_oa_kblgt3.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_kblgt3.h [moved from drivers/gpu/drm/i915/i915_oa_kblgt3.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_sklgt2.c [moved from drivers/gpu/drm/i915/i915_oa_sklgt2.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_sklgt2.h [moved from drivers/gpu/drm/i915/i915_oa_sklgt2.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_sklgt3.c [moved from drivers/gpu/drm/i915/i915_oa_sklgt3.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_sklgt3.h [moved from drivers/gpu/drm/i915/i915_oa_sklgt3.h with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_sklgt4.c [moved from drivers/gpu/drm/i915/i915_oa_sklgt4.c with 100% similarity]
drivers/gpu/drm/i915/oa/i915_oa_sklgt4.h [moved from drivers/gpu/drm/i915/i915_oa_sklgt4.h with 100% similarity]
drivers/gpu/drm/i915/selftests/i915_active.c
drivers/gpu/drm/i915/selftests/i915_gem.c
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/i915/selftests/i915_live_selftests.h
drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
drivers/gpu/drm/i915/selftests/i915_request.c
drivers/gpu/drm/i915/selftests/i915_selftest.c
drivers/gpu/drm/i915/selftests/igt_spinner.c
drivers/gpu/drm/i915/selftests/igt_spinner.h
drivers/gpu/drm/i915/selftests/mock_gem_device.c
drivers/gpu/drm/i915/selftests/mock_gtt.c
drivers/gpu/drm/i915/selftests/mock_uncore.c
include/drm/i915_pciids.h
include/uapi/drm/i915_drm.h

index 91355c2ea8a509fb29e57859d4ed29d182dfd447..5266dbeab01fd79f40683371fea1d8bfd597ff5b 100644 (file)
@@ -35,7 +35,7 @@ subdir-ccflags-y += \
 # Extra header tests
 include $(src)/Makefile.header-test
 
-subdir-ccflags-y += -I$(src)
+subdir-ccflags-y += -I$(srctree)/$(src)
 
 # Please keep these build lists sorted!
 
@@ -74,14 +74,23 @@ gt-y += \
        gt/intel_context.o \
        gt/intel_engine_cs.o \
        gt/intel_engine_pm.o \
+       gt/intel_gt.o \
        gt/intel_gt_pm.o \
        gt/intel_hangcheck.o \
        gt/intel_lrc.o \
+       gt/intel_renderstate.o \
        gt/intel_reset.o \
        gt/intel_ringbuffer.o \
        gt/intel_mocs.o \
        gt/intel_sseu.o \
+       gt/intel_timeline.o \
        gt/intel_workarounds.o
+# autogenerated null render state
+gt-y += \
+       gt/gen6_renderstate.o \
+       gt/gen7_renderstate.o \
+       gt/gen8_renderstate.o \
+       gt/gen9_renderstate.o
 gt-$(CONFIG_DRM_I915_SELFTEST) += \
        gt/mock_engine.o
 i915-y += $(gt-y)
@@ -121,12 +130,10 @@ i915-y += \
          i915_gem_fence_reg.o \
          i915_gem_gtt.o \
          i915_gem.o \
-         i915_gem_render_state.o \
          i915_globals.o \
          i915_query.o \
          i915_request.o \
          i915_scheduler.o \
-         i915_timeline.o \
          i915_trace_points.o \
          i915_vma.o \
          intel_wopcm.o
@@ -143,12 +150,6 @@ i915-y += intel_uc.o \
          intel_huc.o \
          intel_huc_fw.o
 
-# autogenerated null render state
-i915-y += intel_renderstate_gen6.o \
-         intel_renderstate_gen7.o \
-         intel_renderstate_gen8.o \
-         intel_renderstate_gen9.o
-
 # modesetting core code
 obj-y += display/
 i915-y += \
@@ -174,7 +175,8 @@ i915-y += \
        display/intel_overlay.o \
        display/intel_psr.o \
        display/intel_quirks.o \
-       display/intel_sprite.o
+       display/intel_sprite.o \
+       display/intel_tc.o
 i915-$(CONFIG_ACPI) += \
        display/intel_acpi.o \
        display/intel_opregion.o
@@ -211,6 +213,25 @@ i915-y += \
        display/vlv_dsi.o \
        display/vlv_dsi_pll.o
 
+# perf code
+obj-y += oa/
+i915-y += \
+       oa/i915_oa_hsw.o \
+       oa/i915_oa_bdw.o \
+       oa/i915_oa_chv.o \
+       oa/i915_oa_sklgt2.o \
+       oa/i915_oa_sklgt3.o \
+       oa/i915_oa_sklgt4.o \
+       oa/i915_oa_bxt.o \
+       oa/i915_oa_kblgt2.o \
+       oa/i915_oa_kblgt3.o \
+       oa/i915_oa_glk.o \
+       oa/i915_oa_cflgt2.o \
+       oa/i915_oa_cflgt3.o \
+       oa/i915_oa_cnl.o \
+       oa/i915_oa_icl.o
+i915-y += i915_perf.o
+
 # Post-mortem debug and GPU hang state capture
 i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
 i915-$(CONFIG_DRM_I915_SELFTEST) += \
@@ -225,23 +246,6 @@ i915-$(CONFIG_DRM_I915_SELFTEST) += \
 # virtual gpu code
 i915-y += i915_vgpu.o
 
-# perf code
-i915-y += i915_perf.o \
-         i915_oa_hsw.o \
-         i915_oa_bdw.o \
-         i915_oa_chv.o \
-         i915_oa_sklgt2.o \
-         i915_oa_sklgt3.o \
-         i915_oa_sklgt4.o \
-         i915_oa_bxt.o \
-         i915_oa_kblgt2.o \
-         i915_oa_kblgt3.o \
-         i915_oa_glk.o \
-         i915_oa_cflgt2.o \
-         i915_oa_cflgt3.o \
-         i915_oa_cnl.o \
-         i915_oa_icl.o
-
 ifeq ($(CONFIG_DRM_I915_GVT),y)
 i915-y += intel_gvt.o
 include $(src)/gvt/Makefile
index e6ba66f787f99217adfe5d82ddbf57ecd7951af6..2fd61869bdaa28f9d6117cd0b15a87b97c608ad4 100644 (file)
@@ -6,18 +6,27 @@ header_test := \
        i915_active_types.h \
        i915_debugfs.h \
        i915_drv.h \
+       i915_fixed.h \
+       i915_gem_gtt.h \
+       i915_globals.h \
        i915_irq.h \
        i915_params.h \
        i915_priolist_types.h \
+       i915_pvinfo.h \
        i915_reg.h \
        i915_scheduler_types.h \
-       i915_timeline_types.h \
        i915_utils.h \
+       i915_vgpu.h \
        intel_csr.h \
        intel_drv.h \
+       intel_guc_ct.h \
+       intel_guc_fwif.h \
+       intel_guc_reg.h \
+       intel_gvt.h \
        intel_pm.h \
        intel_runtime_pm.h \
        intel_sideband.h \
+       intel_uc_fw.h \
        intel_uncore.h \
        intel_wakeref.h
 
index 1c75b5c9790c7ff56695f13f85ac79017afb5496..eec6961015a115decfd878c39390cd3dd8b1e1d1 100644 (file)
@@ -1,2 +1,5 @@
+# For building individual subdir files on the command line
+subdir-ccflags-y += -I$(srctree)/$(src)/..
+
 # Extra header tests
 include $(src)/Makefile.header-test
index 74448e6bf749c309774936d232808b86a010ad81..3cf95c34143cd4d6b2fd91567180ccf0bb339fa8 100644 (file)
@@ -403,6 +403,19 @@ static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
                tmp &= ~FRC_LATENCY_OPTIM_MASK;
                tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
                I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+
+               /* For EHL set latency optimization for PCS_DW1 lanes */
+               if (IS_ELKHARTLAKE(dev_priv)) {
+                       tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port));
+                       tmp &= ~LATENCY_OPTIM_MASK;
+                       tmp |= LATENCY_OPTIM_VAL(0);
+                       I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp);
+
+                       tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
+                       tmp &= ~LATENCY_OPTIM_MASK;
+                       tmp |= LATENCY_OPTIM_VAL(0x1);
+                       I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp);
+               }
        }
 
 }
@@ -531,6 +544,14 @@ static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder)
                        I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp);
                }
        }
+
+       if (IS_ELKHARTLAKE(dev_priv)) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       tmp = I915_READ(ICL_DPHY_CHKN(port));
+                       tmp |= ICL_DPHY_CHKN_AFE_OVER_PPI_STRAP;
+                       I915_WRITE(ICL_DPHY_CHKN(port), tmp);
+               }
+       }
 }
 
 static void gen11_dsi_gate_clocks(struct intel_encoder *encoder)
@@ -1487,6 +1508,26 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi)
        intel_dsi_log_params(intel_dsi);
 }
 
+static void icl_dsi_add_properties(struct intel_connector *connector)
+{
+       u32 allowed_scalers;
+
+       allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) |
+                          BIT(DRM_MODE_SCALE_FULLSCREEN) |
+                          BIT(DRM_MODE_SCALE_CENTER);
+
+       drm_connector_attach_scaling_mode_property(&connector->base,
+                                                  allowed_scalers);
+
+       connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+
+       connector->base.display_info.panel_orientation =
+                       intel_dsi_get_panel_orientation(connector);
+       drm_connector_init_panel_orientation_property(&connector->base,
+                               connector->panel.fixed_mode->hdisplay,
+                               connector->panel.fixed_mode->vdisplay);
+}
+
 void icl_dsi_init(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = &dev_priv->drm;
@@ -1580,6 +1621,8 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
        }
 
        icl_dphy_param_init(intel_dsi);
+
+       icl_dsi_add_properties(intel_connector);
        return;
 
 err:
index 30bd4e76fff910b43aad0d0bceda13cfb0656eff..ab411d5e093c74f7f75d9d2de1352575e260e8a5 100644 (file)
@@ -176,33 +176,49 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
        new_crtc_state->data_rate[plane->id] =
                intel_plane_data_rate(new_crtc_state, new_plane_state);
 
-       return intel_plane_atomic_calc_changes(old_crtc_state,
-                                              &new_crtc_state->base,
-                                              old_plane_state,
-                                              &new_plane_state->base);
+       return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
+                                              old_plane_state, new_plane_state);
 }
 
-static int intel_plane_atomic_check(struct drm_plane *plane,
-                                   struct drm_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)
 {
-       struct drm_atomic_state *state = new_plane_state->state;
-       const struct drm_plane_state *old_plane_state =
-               drm_atomic_get_old_plane_state(state, plane);
-       struct drm_crtc *crtc = new_plane_state->crtc ?: old_plane_state->crtc;
-       const struct drm_crtc_state *old_crtc_state;
-       struct drm_crtc_state *new_crtc_state;
-
-       new_plane_state->visible = false;
+       if (new_plane_state->base.crtc)
+               return to_intel_crtc(new_plane_state->base.crtc);
+
+       if (old_plane_state->base.crtc)
+               return to_intel_crtc(old_plane_state->base.crtc);
+
+       return NULL;
+}
+
+static int intel_plane_atomic_check(struct drm_plane *_plane,
+                                   struct drm_plane_state *_new_plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(_plane);
+       struct intel_atomic_state *state =
+               to_intel_atomic_state(_new_plane_state->state);
+       struct intel_plane_state *new_plane_state =
+               to_intel_plane_state(_new_plane_state);
+       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;
+
+       new_plane_state->base.visible = false;
        if (!crtc)
                return 0;
 
-       old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
-       new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       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(to_intel_crtc_state(old_crtc_state),
-                                                  to_intel_crtc_state(new_crtc_state),
-                                                  to_intel_plane_state(old_plane_state),
-                                                  to_intel_plane_state(new_plane_state));
+       return intel_plane_atomic_check_with_state(old_crtc_state,
+                                                  new_crtc_state,
+                                                  old_plane_state,
+                                                  new_plane_state);
 }
 
 static struct intel_plane *
index 1437a8797e1032bef7ad34db536ea5b68eca40ed..cb7ef4f9eafd475d6cd240274a3207d7c6d8b186 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 
-struct drm_crtc_state;
 struct drm_plane;
 struct drm_property;
 struct intel_atomic_state;
@@ -43,8 +42,8 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
                                        const struct intel_plane_state *old_plane_state,
                                        struct intel_plane_state *intel_state);
 int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
-                                   struct drm_crtc_state *crtc_state,
+                                   struct intel_crtc_state *crtc_state,
                                    const struct intel_plane_state *old_plane_state,
-                                   struct drm_plane_state *plane_state);
+                                   struct intel_plane_state *plane_state);
 
 #endif /* __INTEL_ATOMIC_PLANE_H__ */
index 840daff122464e3def177a81c99e62e043156e96..c8fd35a7ca4255715c7bbc2faf8c82957e809bb5 100644 (file)
@@ -72,6 +72,13 @@ struct dp_aud_n_m {
        u16 n;
 };
 
+struct hdmi_aud_ncts {
+       int sample_rate;
+       int clock;
+       int n;
+       int cts;
+};
+
 /* Values according to DP 1.4 Table 2-104 */
 static const struct dp_aud_n_m dp_aud_n_m[] = {
        { 32000, LC_162M, 1024, 10125 },
@@ -148,12 +155,7 @@ static const struct {
 #define TMDS_594M 594000
 #define TMDS_593M 593407
 
-static const struct {
-       int sample_rate;
-       int clock;
-       int n;
-       int cts;
-} hdmi_aud_ncts[] = {
+static const struct hdmi_aud_ncts hdmi_aud_ncts_24bpp[] = {
        { 32000, TMDS_296M, 5824, 421875 },
        { 32000, TMDS_297M, 3072, 222750 },
        { 32000, TMDS_593M, 5824, 843750 },
@@ -184,6 +186,49 @@ static const struct {
        { 192000, TMDS_594M, 24576, 594000 },
 };
 
+/* Appendix C - N & CTS values for deep color from HDMI 2.0 spec*/
+/* HDMI N/CTS table for 10 bit deep color(30 bpp)*/
+#define TMDS_371M 371250
+#define TMDS_370M 370878
+
+static const struct hdmi_aud_ncts hdmi_aud_ncts_30bpp[] = {
+       { 32000, TMDS_370M, 5824, 527344 },
+       { 32000, TMDS_371M, 6144, 556875 },
+       { 44100, TMDS_370M, 8918, 585938 },
+       { 44100, TMDS_371M, 4704, 309375 },
+       { 88200, TMDS_370M, 17836, 585938 },
+       { 88200, TMDS_371M, 9408, 309375 },
+       { 176400, TMDS_370M, 35672, 585938 },
+       { 176400, TMDS_371M, 18816, 309375 },
+       { 48000, TMDS_370M, 11648, 703125 },
+       { 48000, TMDS_371M, 5120, 309375 },
+       { 96000, TMDS_370M, 23296, 703125 },
+       { 96000, TMDS_371M, 10240, 309375 },
+       { 192000, TMDS_370M, 46592, 703125 },
+       { 192000, TMDS_371M, 20480, 309375 },
+};
+
+/* HDMI N/CTS table for 12 bit deep color(36 bpp)*/
+#define TMDS_445_5M 445500
+#define TMDS_445M 445054
+
+static const struct hdmi_aud_ncts hdmi_aud_ncts_36bpp[] = {
+       { 32000, TMDS_445M, 5824, 632813 },
+       { 32000, TMDS_445_5M, 4096, 445500 },
+       { 44100, TMDS_445M, 8918, 703125 },
+       { 44100, TMDS_445_5M, 4704, 371250 },
+       { 88200, TMDS_445M, 17836, 703125 },
+       { 88200, TMDS_445_5M, 9408, 371250 },
+       { 176400, TMDS_445M, 35672, 703125 },
+       { 176400, TMDS_445_5M, 18816, 371250 },
+       { 48000, TMDS_445M, 5824, 421875 },
+       { 48000, TMDS_445_5M, 5120, 371250 },
+       { 96000, TMDS_445M, 11648, 421875 },
+       { 96000, TMDS_445_5M, 10240, 371250 },
+       { 192000, TMDS_445M, 23296, 421875 },
+       { 192000, TMDS_445_5M, 20480, 371250 },
+};
+
 /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
 static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_state)
 {
@@ -212,14 +257,24 @@ static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_sta
 static int audio_config_hdmi_get_n(const struct intel_crtc_state *crtc_state,
                                   int rate)
 {
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       int i;
+       const struct hdmi_aud_ncts *hdmi_ncts_table;
+       int i, size;
+
+       if (crtc_state->pipe_bpp == 36) {
+               hdmi_ncts_table = hdmi_aud_ncts_36bpp;
+               size = ARRAY_SIZE(hdmi_aud_ncts_36bpp);
+       } else if (crtc_state->pipe_bpp == 30) {
+               hdmi_ncts_table = hdmi_aud_ncts_30bpp;
+               size = ARRAY_SIZE(hdmi_aud_ncts_30bpp);
+       } else {
+               hdmi_ncts_table = hdmi_aud_ncts_24bpp;
+               size = ARRAY_SIZE(hdmi_aud_ncts_24bpp);
+       }
 
-       for (i = 0; i < ARRAY_SIZE(hdmi_aud_ncts); i++) {
-               if (rate == hdmi_aud_ncts[i].sample_rate &&
-                   adjusted_mode->crtc_clock == hdmi_aud_ncts[i].clock) {
-                       return hdmi_aud_ncts[i].n;
+       for (i = 0; i < size; i++) {
+               if (rate == hdmi_ncts_table[i].sample_rate &&
+                   crtc_state->port_clock == hdmi_ncts_table[i].clock) {
+                       return hdmi_ncts_table[i].n;
                }
        }
        return 0;
index c4710889cb321aa7d4d7e58365519dbc06d09f56..0c9808132d67db6c21ca95a8bee0396e93231713 100644 (file)
@@ -1668,6 +1668,9 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                if (!child->device_type)
                        continue;
 
+               DRM_DEBUG_KMS("Found VBT child device with type 0x%x\n",
+                             child->device_type);
+
                /*
                 * Copy as much as we know (sizeof) and is available
                 * (child_dev_size) of the child device. Accessing the data must
index 4e42cfaf61a7e3903ba6d5b57b3cd96a731c4163..0b7be6389a07b1c9ca944c6ca756f44a263fe5cb 100644 (file)
@@ -42,6 +42,7 @@ enum intel_backlight_type {
        INTEL_BACKLIGHT_DISPLAY_DDI,
        INTEL_BACKLIGHT_DSI_DCS,
        INTEL_BACKLIGHT_PANEL_DRIVER_INTERFACE,
+       INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE,
 };
 
 struct edp_power_seq {
index 753ac3165061c606ca62d7372cc4825f16fd7dcd..7b908e10d32e65f6808dcffea5d19d8d50c295db 100644 (file)
@@ -178,6 +178,8 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv)
                clpchgroup = (sa->deburst * deinterleave / num_channels) << i;
                bi->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1;
 
+               bi->num_qgv_points = qi.num_points;
+
                for (j = 0; j < qi.num_points; j++) {
                        const struct intel_qgv_point *sp = &qi.points[j];
                        int ct, bw;
@@ -195,7 +197,7 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv)
                        bi->deratedbw[j] = min(maxdebw,
                                               bw * 9 / 10); /* 90% */
 
-                       DRM_DEBUG_KMS("BW%d / QGV %d: num_planes=%d deratedbw=%d\n",
+                       DRM_DEBUG_KMS("BW%d / QGV %d: num_planes=%d deratedbw=%u\n",
                                      i, j, bi->num_planes, bi->deratedbw[j]);
                }
 
@@ -211,14 +213,17 @@ static unsigned int icl_max_bw(struct drm_i915_private *dev_priv,
 {
        int i;
 
-       /* Did we initialize the bw limits successfully? */
-       if (dev_priv->max_bw[0].num_planes == 0)
-               return UINT_MAX;
-
        for (i = 0; i < ARRAY_SIZE(dev_priv->max_bw); i++) {
                const struct intel_bw_info *bi =
                        &dev_priv->max_bw[i];
 
+               /*
+                * Pcode will not expose all QGV points when
+                * SAGV is forced to off/min/med/max.
+                */
+               if (qgv_point >= bi->num_qgv_points)
+                       return UINT_MAX;
+
                if (num_planes >= bi->num_planes)
                        return bi->deratedbw[qgv_point];
        }
index 8993ab283562b2dc8fa65ec54ad5a0c05353c010..0b8b8ae3b7fca1fee1ee2e5d36af64e941219f38 100644 (file)
@@ -1756,9 +1756,10 @@ sanitize:
 
 static int icl_calc_cdclk(int min_cdclk, unsigned int ref)
 {
-       int ranges_24[] = { 312000, 552000, 648000 };
-       int ranges_19_38[] = { 307200, 556800, 652800 };
-       int *ranges;
+       static const int ranges_24[] = { 180000, 192000, 312000, 552000, 648000 };
+       static const int ranges_19_38[] = { 172800, 192000, 307200, 556800, 652800 };
+       const int *ranges;
+       int len, i;
 
        switch (ref) {
        default:
@@ -1766,19 +1767,22 @@ static int icl_calc_cdclk(int min_cdclk, unsigned int ref)
                /* fall through */
        case 24000:
                ranges = ranges_24;
+               len = ARRAY_SIZE(ranges_24);
                break;
        case 19200:
        case 38400:
                ranges = ranges_19_38;
+               len = ARRAY_SIZE(ranges_19_38);
                break;
        }
 
-       if (min_cdclk > ranges[1])
-               return ranges[2];
-       else if (min_cdclk > ranges[0])
-               return ranges[1];
-       else
-               return ranges[0];
+       for (i = 0; i < len; i++) {
+               if (min_cdclk <= ranges[i])
+                       return ranges[i];
+       }
+
+       WARN_ON(min_cdclk > ranges[len - 1]);
+       return ranges[len - 1];
 }
 
 static int icl_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
@@ -1792,16 +1796,24 @@ static int icl_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
        default:
                MISSING_CASE(cdclk);
                /* fall through */
+       case 172800:
        case 307200:
        case 556800:
        case 652800:
                WARN_ON(dev_priv->cdclk.hw.ref != 19200 &&
                        dev_priv->cdclk.hw.ref != 38400);
                break;
+       case 180000:
        case 312000:
        case 552000:
        case 648000:
                WARN_ON(dev_priv->cdclk.hw.ref != 24000);
+               break;
+       case 192000:
+               WARN_ON(dev_priv->cdclk.hw.ref != 19200 &&
+                       dev_priv->cdclk.hw.ref != 38400 &&
+                       dev_priv->cdclk.hw.ref != 24000);
+               break;
        }
 
        ratio = cdclk / (dev_priv->cdclk.hw.ref / 2);
@@ -1854,14 +1866,23 @@ static void icl_set_cdclk(struct drm_i915_private *dev_priv,
        dev_priv->cdclk.hw.voltage_level = cdclk_state->voltage_level;
 }
 
-static u8 icl_calc_voltage_level(int cdclk)
+static u8 icl_calc_voltage_level(struct drm_i915_private *dev_priv, int cdclk)
 {
-       if (cdclk > 556800)
-               return 2;
-       else if (cdclk > 312000)
-               return 1;
-       else
-               return 0;
+       if (IS_ELKHARTLAKE(dev_priv)) {
+               if (cdclk > 312000)
+                       return 2;
+               else if (cdclk > 180000)
+                       return 1;
+               else
+                       return 0;
+       } else {
+               if (cdclk > 556800)
+                       return 2;
+               else if (cdclk > 312000)
+                       return 1;
+               else
+                       return 0;
+       }
 }
 
 static void icl_get_cdclk(struct drm_i915_private *dev_priv,
@@ -1912,7 +1933,7 @@ out:
         * at least what the CDCLK frequency requires.
         */
        cdclk_state->voltage_level =
-               icl_calc_voltage_level(cdclk_state->cdclk);
+               icl_calc_voltage_level(dev_priv, cdclk_state->cdclk);
 }
 
 static void icl_init_cdclk(struct drm_i915_private *dev_priv)
@@ -1947,7 +1968,8 @@ sanitize:
        sanitized_state.vco = icl_calc_cdclk_pll_vco(dev_priv,
                                                     sanitized_state.cdclk);
        sanitized_state.voltage_level =
-                               icl_calc_voltage_level(sanitized_state.cdclk);
+                               icl_calc_voltage_level(dev_priv,
+                                                      sanitized_state.cdclk);
 
        icl_set_cdclk(dev_priv, &sanitized_state, INVALID_PIPE);
 }
@@ -1958,7 +1980,8 @@ static void icl_uninit_cdclk(struct drm_i915_private *dev_priv)
 
        cdclk_state.cdclk = cdclk_state.bypass;
        cdclk_state.vco = 0;
-       cdclk_state.voltage_level = icl_calc_voltage_level(cdclk_state.cdclk);
+       cdclk_state.voltage_level = icl_calc_voltage_level(dev_priv,
+                                                          cdclk_state.cdclk);
 
        icl_set_cdclk(dev_priv, &cdclk_state, INVALID_PIPE);
 }
@@ -2549,7 +2572,7 @@ static int icl_modeset_calc_cdclk(struct intel_atomic_state *state)
        state->cdclk.logical.vco = vco;
        state->cdclk.logical.cdclk = cdclk;
        state->cdclk.logical.voltage_level =
-               max(icl_calc_voltage_level(cdclk),
+               max(icl_calc_voltage_level(dev_priv, cdclk),
                    cnl_compute_min_voltage_level(state));
 
        if (!state->active_crtcs) {
@@ -2559,7 +2582,7 @@ static int icl_modeset_calc_cdclk(struct intel_atomic_state *state)
                state->cdclk.actual.vco = vco;
                state->cdclk.actual.cdclk = cdclk;
                state->cdclk.actual.voltage_level =
-                       icl_calc_voltage_level(cdclk);
+                       icl_calc_voltage_level(dev_priv, cdclk);
        } else {
                state->cdclk.actual = state->cdclk.logical;
        }
@@ -2594,7 +2617,12 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
  */
 void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
 {
-       if (INTEL_GEN(dev_priv) >= 11) {
+       if (IS_ELKHARTLAKE(dev_priv)) {
+               if (dev_priv->cdclk.hw.ref == 24000)
+                       dev_priv->max_cdclk_freq = 552000;
+               else
+                       dev_priv->max_cdclk_freq = 556800;
+       } else if (INTEL_GEN(dev_priv) >= 11) {
                if (dev_priv->cdclk.hw.ref == 24000)
                        dev_priv->max_cdclk_freq = 648000;
                else
index 841708da5a5693fd4de36c1ead7a6087e3a8586a..d3d5244765e634da5d634db75547e4c31a6e912f 100644 (file)
@@ -183,9 +183,13 @@ static void cnl_combo_phys_uninit(struct drm_i915_private *dev_priv)
 static bool icl_combo_phy_enabled(struct drm_i915_private *dev_priv,
                                  enum port port)
 {
-       return !(I915_READ(ICL_PHY_MISC(port)) &
-                ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN) &&
-               (I915_READ(ICL_PORT_COMP_DW0(port)) & COMP_INIT);
+       /* The PHY C added by EHL has no PHY_MISC register */
+       if (IS_ELKHARTLAKE(dev_priv) && port == PORT_C)
+               return I915_READ(ICL_PORT_COMP_DW0(port)) & COMP_INIT;
+       else
+               return !(I915_READ(ICL_PHY_MISC(port)) &
+                        ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN) &&
+                       (I915_READ(ICL_PORT_COMP_DW0(port)) & COMP_INIT);
 }
 
 static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
@@ -260,6 +264,32 @@ void intel_combo_phy_power_up_lanes(struct drm_i915_private *dev_priv,
        I915_WRITE(ICL_PORT_CL_DW10(port), val);
 }
 
+static u32 ehl_combo_phy_a_mux(struct drm_i915_private *i915, u32 val)
+{
+       bool ddi_a_present = i915->vbt.ddi_port_info[PORT_A].child != NULL;
+       bool ddi_d_present = i915->vbt.ddi_port_info[PORT_D].child != NULL;
+       bool dsi_present = intel_bios_is_dsi_present(i915, NULL);
+
+       /*
+        * VBT's 'dvo port' field for child devices references the DDI, not
+        * the PHY.  So if combo PHY A is wired up to drive an external
+        * display, we should see a child device present on PORT_D and
+        * nothing on PORT_A and no DSI.
+        */
+       if (ddi_d_present && !ddi_a_present && !dsi_present)
+               return val | ICL_PHY_MISC_MUX_DDID;
+
+       /*
+        * If we encounter a VBT that claims to have an external display on
+        * DDI-D _and_ an internal display on DDI-A/DSI leave an error message
+        * in the log and let the internal display win.
+        */
+       if (ddi_d_present)
+               DRM_ERROR("VBT claims to have both internal and external displays on PHY A.  Configuring for internal.\n");
+
+       return val & ~ICL_PHY_MISC_MUX_DDID;
+}
+
 static void icl_combo_phys_init(struct drm_i915_private *dev_priv)
 {
        enum port port;
@@ -273,10 +303,29 @@ static void icl_combo_phys_init(struct drm_i915_private *dev_priv)
                        continue;
                }
 
+               /*
+                * Although EHL adds a combo PHY C, there's no PHY_MISC
+                * register for it and no need to program the
+                * DE_IO_COMP_PWR_DOWN setting on PHY C.
+                */
+               if (IS_ELKHARTLAKE(dev_priv) && port == PORT_C)
+                       goto skip_phy_misc;
+
+               /*
+                * EHL's combo PHY A can be hooked up to either an external
+                * display (via DDI-D) or an internal display (via DDI-A or
+                * the DSI DPHY).  This is a motherboard design decision that
+                * can't be changed on the fly, so initialize the PHY's mux
+                * based on whether our VBT indicates the presence of any
+                * "internal" child devices.
+                */
                val = I915_READ(ICL_PHY_MISC(port));
+               if (IS_ELKHARTLAKE(dev_priv) && port == PORT_A)
+                       val = ehl_combo_phy_a_mux(dev_priv, val);
                val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
                I915_WRITE(ICL_PHY_MISC(port), val);
 
+skip_phy_misc:
                cnl_set_procmon_ref_values(dev_priv, port);
 
                if (port == PORT_A) {
@@ -307,10 +356,19 @@ static void icl_combo_phys_uninit(struct drm_i915_private *dev_priv)
                        DRM_WARN("Port %c combo PHY HW state changed unexpectedly\n",
                                 port_name(port));
 
+               /*
+                * Although EHL adds a combo PHY C, there's no PHY_MISC
+                * register for it and no need to program the
+                * DE_IO_COMP_PWR_DOWN setting on PHY C.
+                */
+               if (IS_ELKHARTLAKE(dev_priv) && port == PORT_C)
+                       goto skip_phy_misc;
+
                val = I915_READ(ICL_PHY_MISC(port));
                val |= ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
                I915_WRITE(ICL_PHY_MISC(port), val);
 
+skip_phy_misc:
                val = I915_READ(ICL_PORT_COMP_DW0(port));
                val &= ~COMP_INIT;
                I915_WRITE(ICL_PORT_COMP_DW0(port), val);
index 7925a176f90073763bf189cb0bee2482b8cf5c94..30e48609db1d13a19ef4302d4db08a05b8fd0d7f 100644 (file)
@@ -45,6 +45,7 @@
 #include "intel_lspcon.h"
 #include "intel_panel.h"
 #include "intel_psr.h"
+#include "intel_tc.h"
 #include "intel_vdsc.h"
 
 struct ddi_buf_trans {
@@ -846,8 +847,8 @@ cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 }
 
 static const struct cnl_ddi_buf_trans *
-icl_get_combo_buf_trans(struct drm_i915_private *dev_priv, enum port port,
-                       int type, int rate, int *n_entries)
+icl_get_combo_buf_trans(struct drm_i915_private *dev_priv, int type, int rate,
+                       int *n_entries)
 {
        if (type == INTEL_OUTPUT_HDMI) {
                *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
@@ -872,7 +873,7 @@ static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port por
 
        if (INTEL_GEN(dev_priv) >= 11) {
                if (intel_port_is_combophy(dev_priv, port))
-                       icl_get_combo_buf_trans(dev_priv, port, INTEL_OUTPUT_HDMI,
+                       icl_get_combo_buf_trans(dev_priv, INTEL_OUTPUT_HDMI,
                                                0, &n_entries);
                else
                        n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
@@ -2231,7 +2232,7 @@ u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder)
 
        if (INTEL_GEN(dev_priv) >= 11) {
                if (intel_port_is_combophy(dev_priv, port))
-                       icl_get_combo_buf_trans(dev_priv, port, encoder->type,
+                       icl_get_combo_buf_trans(dev_priv, encoder->type,
                                                intel_dp->link_rate, &n_entries);
                else
                        n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
@@ -2420,8 +2421,8 @@ static void icl_ddi_combo_vswing_program(struct drm_i915_private *dev_priv,
        u32 n_entries, val;
        int ln;
 
-       ddi_translations = icl_get_combo_buf_trans(dev_priv, port, type,
-                                                  rate, &n_entries);
+       ddi_translations = icl_get_combo_buf_trans(dev_priv, type, rate,
+                                                  &n_entries);
        if (!ddi_translations)
                return;
 
@@ -2995,25 +2996,22 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port)
 {
        struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
        enum port port = intel_dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       u32 ln0, ln1, lane_info;
+       u32 ln0, ln1, lane_mask;
 
-       if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT)
+       if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT)
                return;
 
        ln0 = I915_READ(MG_DP_MODE(0, port));
        ln1 = I915_READ(MG_DP_MODE(1, port));
 
-       switch (intel_dig_port->tc_type) {
-       case TC_PORT_TYPEC:
+       switch (intel_dig_port->tc_mode) {
+       case TC_PORT_DP_ALT:
                ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE);
                ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE);
 
-               lane_info = (I915_READ(PORT_TX_DFLEXDPSP) &
-                            DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
-                           DP_LANE_ASSIGNMENT_SHIFT(tc_port);
+               lane_mask = intel_tc_port_get_lane_mask(intel_dig_port);
 
-               switch (lane_info) {
+               switch (lane_mask) {
                case 0x1:
                case 0x4:
                        break;
@@ -3038,7 +3036,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port)
                               MG_DP_MODE_CFG_DP_X2_MODE;
                        break;
                default:
-                       MISSING_CASE(lane_info);
+                       MISSING_CASE(lane_mask);
                }
                break;
 
@@ -3048,7 +3046,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port)
                break;
 
        default:
-               MISSING_CASE(intel_dig_port->tc_type);
+               MISSING_CASE(intel_dig_port->tc_mode);
                return;
        }
 
@@ -3123,7 +3121,10 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 
        intel_ddi_clk_select(encoder, crtc_state);
 
-       intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
+       if (!intel_port_is_tc(dev_priv, port) ||
+           dig_port->tc_mode != TC_PORT_TBT_ALT)
+               intel_display_power_get(dev_priv,
+                                       dig_port->ddi_io_power_domain);
 
        icl_program_mg_dp_mode(dig_port);
        icl_disable_phy_clock_gating(dig_port);
@@ -3305,8 +3306,10 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
        intel_edp_panel_vdd_on(intel_dp);
        intel_edp_panel_off(intel_dp);
 
-       intel_display_power_put_unchecked(dev_priv,
-                                         dig_port->ddi_io_power_domain);
+       if (!intel_port_is_tc(dev_priv, encoder->port) ||
+           dig_port->tc_mode != TC_PORT_TBT_ALT)
+               intel_display_power_put_unchecked(dev_priv,
+                                                 dig_port->ddi_io_power_domain);
 
        intel_ddi_clk_disable(encoder);
 }
@@ -3601,6 +3604,8 @@ static void intel_ddi_set_fia_lane_count(struct intel_encoder *encoder,
        u32 val = I915_READ(PORT_TX_DFLEXDPMLE1);
        bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
 
+       WARN_ON(lane_reversal && dig_port->tc_mode != TC_PORT_LEGACY);
+
        val &= ~DFLEXDPMLE1_DPMLETC_MASK(tc_port);
        switch (pipe_config->lane_count) {
        case 1:
@@ -3620,6 +3625,30 @@ static void intel_ddi_set_fia_lane_count(struct intel_encoder *encoder,
        I915_WRITE(PORT_TX_DFLEXDPMLE1, val);
 }
 
+static void
+intel_ddi_update_prepare(struct intel_atomic_state *state,
+                        struct intel_encoder *encoder,
+                        struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *crtc_state =
+               crtc ? intel_atomic_get_new_crtc_state(state, crtc) : NULL;
+       int required_lanes = crtc_state ? crtc_state->lane_count : 1;
+
+       WARN_ON(crtc && crtc->active);
+
+       intel_tc_port_get_link(enc_to_dig_port(&encoder->base), required_lanes);
+       if (crtc_state && crtc_state->base.active)
+               intel_update_active_dpll(state, crtc, encoder);
+}
+
+static void
+intel_ddi_update_complete(struct intel_atomic_state *state,
+                         struct intel_encoder *encoder,
+                         struct intel_crtc *crtc)
+{
+       intel_tc_port_put_link(enc_to_dig_port(&encoder->base));
+}
+
 static void
 intel_ddi_pre_pll_enable(struct intel_encoder *encoder,
                         const struct intel_crtc_state *crtc_state,
@@ -3627,10 +3656,13 @@ intel_ddi_pre_pll_enable(struct intel_encoder *encoder,
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       bool is_tc_port = intel_port_is_tc(dev_priv, encoder->port);
        enum port port = encoder->port;
 
-       if (intel_crtc_has_dp_encoder(crtc_state) ||
-           intel_port_is_tc(dev_priv, encoder->port))
+       if (is_tc_port)
+               intel_tc_port_get_link(dig_port, crtc_state->lane_count);
+
+       if (intel_crtc_has_dp_encoder(crtc_state) || is_tc_port)
                intel_display_power_get(dev_priv,
                                        intel_ddi_main_link_aux_domain(dig_port));
 
@@ -3642,8 +3674,7 @@ intel_ddi_pre_pll_enable(struct intel_encoder *encoder,
         * Program the lane count for static/dynamic connections on Type-C ports.
         * Skip this step for TBT.
         */
-       if (dig_port->tc_type == TC_PORT_UNKNOWN ||
-           dig_port->tc_type == TC_PORT_TBT)
+       if (dig_port->tc_mode == TC_PORT_TBT_ALT)
                return;
 
        intel_ddi_set_fia_lane_count(encoder, crtc_state, port);
@@ -3656,11 +3687,14 @@ intel_ddi_post_pll_disable(struct intel_encoder *encoder,
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       bool is_tc_port = intel_port_is_tc(dev_priv, encoder->port);
 
-       if (intel_crtc_has_dp_encoder(crtc_state) ||
-           intel_port_is_tc(dev_priv, encoder->port))
+       if (intel_crtc_has_dp_encoder(crtc_state) || is_tc_port)
                intel_display_power_put_unchecked(dev_priv,
                                                  intel_ddi_main_link_aux_domain(dig_port));
+
+       if (is_tc_port)
+               intel_tc_port_put_link(dig_port);
 }
 
 static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
@@ -3737,7 +3771,6 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
-       struct intel_digital_port *intel_dig_port;
        u32 temp, flags = 0;
 
        /* XXX: DSI transcoder paranoia */
@@ -3776,7 +3809,6 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
        switch (temp & TRANS_DDI_MODE_SELECT_MASK) {
        case TRANS_DDI_MODE_SELECT_HDMI:
                pipe_config->has_hdmi_sink = true;
-               intel_dig_port = enc_to_dig_port(&encoder->base);
 
                pipe_config->infoframes.enable |=
                        intel_hdmi_infoframes_enabled(encoder, pipe_config);
@@ -3914,49 +3946,18 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder,
        return 0;
 }
 
-static void intel_ddi_encoder_suspend(struct intel_encoder *encoder)
-{
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       struct drm_i915_private *i915 = to_i915(encoder->base.dev);
-
-       intel_dp_encoder_suspend(encoder);
-
-       /*
-        * TODO: disconnect also from USB DP alternate mode once we have a
-        * way to handle the modeset restore in that mode during resume
-        * even if the sink has disappeared while being suspended.
-        */
-       if (dig_port->tc_legacy_port)
-               icl_tc_phy_disconnect(i915, dig_port);
-}
-
-static void intel_ddi_encoder_reset(struct drm_encoder *drm_encoder)
-{
-       struct intel_digital_port *dig_port = enc_to_dig_port(drm_encoder);
-       struct drm_i915_private *i915 = to_i915(drm_encoder->dev);
-
-       if (intel_port_is_tc(i915, dig_port->base.port))
-               intel_digital_port_connected(&dig_port->base);
-
-       intel_dp_encoder_reset(drm_encoder);
-}
-
 static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
-       struct drm_i915_private *i915 = to_i915(encoder->dev);
 
        intel_dp_encoder_flush_work(encoder);
 
-       if (intel_port_is_tc(i915, dig_port->base.port))
-               icl_tc_phy_disconnect(i915, dig_port);
-
        drm_encoder_cleanup(encoder);
        kfree(dig_port);
 }
 
 static const struct drm_encoder_funcs intel_ddi_funcs = {
-       .reset = intel_ddi_encoder_reset,
+       .reset = intel_dp_encoder_reset,
        .destroy = intel_ddi_encoder_destroy,
 };
 
@@ -4242,7 +4243,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        intel_encoder->update_pipe = intel_ddi_update_pipe;
        intel_encoder->get_hw_state = intel_ddi_get_hw_state;
        intel_encoder->get_config = intel_ddi_get_config;
-       intel_encoder->suspend = intel_ddi_encoder_suspend;
+       intel_encoder->suspend = intel_dp_encoder_suspend;
        intel_encoder->get_power_domains = intel_ddi_get_power_domains;
        intel_encoder->type = INTEL_OUTPUT_DDI;
        intel_encoder->power_domain = intel_port_to_power_domain(port);
@@ -4261,9 +4262,15 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port);
        intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
 
-       intel_dig_port->tc_legacy_port = intel_port_is_tc(dev_priv, port) &&
-                                        !port_info->supports_typec_usb &&
-                                        !port_info->supports_tbt;
+       if (intel_port_is_tc(dev_priv, port)) {
+               bool is_legacy = !port_info->supports_typec_usb &&
+                                !port_info->supports_tbt;
+
+               intel_tc_port_init(intel_dig_port, is_legacy);
+
+               intel_encoder->update_prepare = intel_ddi_update_prepare;
+               intel_encoder->update_complete = intel_ddi_update_complete;
+       }
 
        switch (port) {
        case PORT_A:
@@ -4324,9 +4331,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 
        intel_infoframe_init(intel_dig_port);
 
-       if (intel_port_is_tc(dev_priv, port))
-               intel_digital_port_connected(intel_encoder);
-
        return;
 
 err:
index 8592a7d422de9c147d5407cdbb225aa81fb314b9..f07081815b804f984a4defa1f7ed374829566cd4 100644 (file)
@@ -78,6 +78,7 @@
 #include "intel_quirks.h"
 #include "intel_sideband.h"
 #include "intel_sprite.h"
+#include "intel_tc.h"
 
 /* Primary plane formats for gen <= 3 */
 static const u32 i8xx_primary_formats[] = {
@@ -515,9 +516,9 @@ icl_wa_scalerclkgating(struct drm_i915_private *dev_priv, enum pipe pipe,
 }
 
 static bool
-needs_modeset(const struct drm_crtc_state *state)
+needs_modeset(const struct intel_crtc_state *state)
 {
-       return drm_atomic_crtc_needs_modeset(state);
+       return drm_atomic_crtc_needs_modeset(&state->base);
 }
 
 /*
@@ -1839,7 +1840,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
                /* FIXME: assert CPU port conditions for SNB+ */
        }
 
-       trace_intel_pipe_enable(dev_priv, pipe);
+       trace_intel_pipe_enable(crtc);
 
        reg = PIPECONF(cpu_transcoder);
        val = I915_READ(reg);
@@ -1880,7 +1881,7 @@ static void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state)
         */
        assert_planes_disabled(crtc);
 
-       trace_intel_pipe_disable(dev_priv, pipe);
+       trace_intel_pipe_disable(crtc);
 
        reg = PIPECONF(cpu_transcoder);
        val = I915_READ(reg);
@@ -3715,10 +3716,27 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
        return 0;
 }
 
+static bool i9xx_plane_has_windowing(struct intel_plane *plane)
+{
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+
+       if (IS_CHERRYVIEW(dev_priv))
+               return i9xx_plane == PLANE_B;
+       else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+               return false;
+       else if (IS_GEN(dev_priv, 4))
+               return i9xx_plane == PLANE_C;
+       else
+               return i9xx_plane == PLANE_B ||
+                       i9xx_plane == PLANE_C;
+}
+
 static int
 i9xx_plane_check(struct intel_crtc_state *crtc_state,
                 struct intel_plane_state *plane_state)
 {
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        int ret;
 
        ret = chv_plane_check_rotation(plane_state);
@@ -3729,7 +3747,8 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state,
                                                  &crtc_state->base,
                                                  DRM_PLANE_HELPER_NO_SCALING,
                                                  DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, true);
+                                                 i9xx_plane_has_windowing(plane),
+                                                 true);
        if (ret)
                return ret;
 
@@ -3758,6 +3777,10 @@ static void i9xx_update_plane(struct intel_plane *plane,
        u32 linear_offset;
        int x = plane_state->color_plane[0].x;
        int y = plane_state->color_plane[0].y;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       int crtc_w = drm_rect_width(&plane_state->base.dst);
+       int crtc_h = drm_rect_height(&plane_state->base.dst);
        unsigned long irqflags;
        u32 dspaddr_offset;
        u32 dspcntr;
@@ -3776,18 +3799,18 @@ static void i9xx_update_plane(struct intel_plane *plane,
        I915_WRITE_FW(DSPSTRIDE(i9xx_plane), plane_state->color_plane[0].stride);
 
        if (INTEL_GEN(dev_priv) < 4) {
-               /* pipesrc and dspsize control the size that is scaled from,
-                * which should always be the user's requested size.
+               /*
+                * PLANE_A doesn't actually have a full window
+                * generator but let's assume we still need to
+                * program whatever is there.
                 */
-               I915_WRITE_FW(DSPPOS(i9xx_plane), 0);
+               I915_WRITE_FW(DSPPOS(i9xx_plane), (crtc_y << 16) | crtc_x);
                I915_WRITE_FW(DSPSIZE(i9xx_plane),
-                             ((crtc_state->pipe_src_h - 1) << 16) |
-                             (crtc_state->pipe_src_w - 1));
+                             ((crtc_h - 1) << 16) | (crtc_w - 1));
        } else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
-               I915_WRITE_FW(PRIMPOS(i9xx_plane), 0);
+               I915_WRITE_FW(PRIMPOS(i9xx_plane), (crtc_y << 16) | crtc_x);
                I915_WRITE_FW(PRIMSIZE(i9xx_plane),
-                             ((crtc_state->pipe_src_h - 1) << 16) |
-                             (crtc_state->pipe_src_w - 1));
+                             ((crtc_h - 1) << 16) | (crtc_w - 1));
                I915_WRITE_FW(PRIMCNSTALPHA(i9xx_plane), 0);
        }
 
@@ -3950,10 +3973,10 @@ static u32 skl_plane_ctl_format(u32 pixel_format)
        case DRM_FORMAT_XRGB8888:
        case DRM_FORMAT_ARGB8888:
                return PLANE_CTL_FORMAT_XRGB_8888;
+       case DRM_FORMAT_XBGR2101010:
+               return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX;
        case DRM_FORMAT_XRGB2101010:
                return PLANE_CTL_FORMAT_XRGB_2101010;
-       case DRM_FORMAT_XBGR2101010:
-               return PLANE_CTL_ORDER_RGBX | PLANE_CTL_FORMAT_XRGB_2101010;
        case DRM_FORMAT_XBGR16161616F:
        case DRM_FORMAT_ABGR16161616F:
                return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX;
@@ -5796,7 +5819,7 @@ static bool hsw_pre_update_disable_ips(const struct intel_crtc_state *old_crtc_s
        if (!old_crtc_state->ips_enabled)
                return false;
 
-       if (needs_modeset(&new_crtc_state->base))
+       if (needs_modeset(new_crtc_state))
                return true;
 
        /*
@@ -5823,7 +5846,7 @@ static bool hsw_post_update_enable_ips(const struct intel_crtc_state *old_crtc_s
        if (!new_crtc_state->ips_enabled)
                return false;
 
-       if (needs_modeset(&new_crtc_state->base))
+       if (needs_modeset(new_crtc_state))
                return true;
 
        /*
@@ -5877,13 +5900,13 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
        struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_atomic_state *old_state = old_crtc_state->base.state;
+       struct drm_atomic_state *state = old_crtc_state->base.state;
        struct intel_crtc_state *pipe_config =
-               intel_atomic_get_new_crtc_state(to_intel_atomic_state(old_state),
+               intel_atomic_get_new_crtc_state(to_intel_atomic_state(state),
                                                crtc);
        struct drm_plane *primary = crtc->base.primary;
        struct drm_plane_state *old_primary_state =
-               drm_atomic_get_old_plane_state(old_state, primary);
+               drm_atomic_get_old_plane_state(state, primary);
 
        intel_frontbuffer_flip(to_i915(crtc->base.dev), pipe_config->fb_bits);
 
@@ -5895,12 +5918,12 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
 
        if (old_primary_state) {
                struct drm_plane_state *new_primary_state =
-                       drm_atomic_get_new_plane_state(old_state, primary);
+                       drm_atomic_get_new_plane_state(state, primary);
 
                intel_fbc_post_update(crtc);
 
                if (new_primary_state->visible &&
-                   (needs_modeset(&pipe_config->base) ||
+                   (needs_modeset(pipe_config) ||
                     !old_primary_state->visible))
                        intel_post_enable_primary(&crtc->base, pipe_config);
        }
@@ -5920,20 +5943,20 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
        struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_atomic_state *old_state = old_crtc_state->base.state;
+       struct drm_atomic_state *state = old_crtc_state->base.state;
        struct drm_plane *primary = crtc->base.primary;
        struct drm_plane_state *old_primary_state =
-               drm_atomic_get_old_plane_state(old_state, primary);
-       bool modeset = needs_modeset(&pipe_config->base);
-       struct intel_atomic_state *old_intel_state =
-               to_intel_atomic_state(old_state);
+               drm_atomic_get_old_plane_state(state, primary);
+       bool modeset = needs_modeset(pipe_config);
+       struct intel_atomic_state *intel_state =
+               to_intel_atomic_state(state);
 
        if (hsw_pre_update_disable_ips(old_crtc_state, pipe_config))
                hsw_disable_ips(old_crtc_state);
 
        if (old_primary_state) {
                struct intel_plane_state *new_primary_state =
-                       intel_atomic_get_new_plane_state(old_intel_state,
+                       intel_atomic_get_new_plane_state(intel_state,
                                                         to_intel_plane(primary));
 
                intel_fbc_pre_update(crtc, pipe_config, new_primary_state);
@@ -5984,7 +6007,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
         * If we're doing a modeset, we're done.  No need to do any pre-vblank
         * watermark programming here.
         */
-       if (needs_modeset(&pipe_config->base))
+       if (needs_modeset(pipe_config))
                return;
 
        /*
@@ -6002,7 +6025,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
         * us to.
         */
        if (dev_priv->display.initial_watermarks != NULL)
-               dev_priv->display.initial_watermarks(old_intel_state,
+               dev_priv->display.initial_watermarks(intel_state,
                                                     pipe_config);
        else if (pipe_config->update_wm_pre)
                intel_update_watermarks(crtc);
@@ -6036,19 +6059,111 @@ static void intel_crtc_disable_planes(struct intel_atomic_state *state,
        intel_frontbuffer_flip(dev_priv, fb_bits);
 }
 
-static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
+/*
+ * intel_connector_primary_encoder - get the primary encoder for a connector
+ * @connector: connector for which to return the encoder
+ *
+ * Returns the primary encoder for a connector. There is a 1:1 mapping from
+ * all connectors to their encoder, except for DP-MST connectors which have
+ * both a virtual and a primary encoder. These DP-MST primary encoders can be
+ * pointed to by as many DP-MST connectors as there are pipes.
+ */
+static struct intel_encoder *
+intel_connector_primary_encoder(struct intel_connector *connector)
+{
+       struct intel_encoder *encoder;
+
+       if (connector->mst_port)
+               return &dp_to_dig_port(connector->mst_port)->base;
+
+       encoder = intel_attached_encoder(&connector->base);
+       WARN_ON(!encoder);
+
+       return encoder;
+}
+
+static bool
+intel_connector_needs_modeset(struct intel_atomic_state *state,
+                             const struct drm_connector_state *old_conn_state,
+                             const struct drm_connector_state *new_conn_state)
+{
+       struct intel_crtc *old_crtc = old_conn_state->crtc ?
+                                     to_intel_crtc(old_conn_state->crtc) : NULL;
+       struct intel_crtc *new_crtc = new_conn_state->crtc ?
+                                     to_intel_crtc(new_conn_state->crtc) : NULL;
+
+       return new_crtc != old_crtc ||
+              (new_crtc &&
+               needs_modeset(intel_atomic_get_new_crtc_state(state, new_crtc)));
+}
+
+static void intel_encoders_update_prepare(struct intel_atomic_state *state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector_state *new_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_oldnew_connector_in_state(&state->base, conn,
+                                          old_conn_state, new_conn_state, i) {
+               struct intel_encoder *encoder;
+               struct intel_crtc *crtc;
+
+               if (!intel_connector_needs_modeset(state,
+                                                  old_conn_state,
+                                                  new_conn_state))
+                       continue;
+
+               encoder = intel_connector_primary_encoder(to_intel_connector(conn));
+               if (!encoder->update_prepare)
+                       continue;
+
+               crtc = new_conn_state->crtc ?
+                       to_intel_crtc(new_conn_state->crtc) : NULL;
+               encoder->update_prepare(state, encoder, crtc);
+       }
+}
+
+static void intel_encoders_update_complete(struct intel_atomic_state *state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector_state *new_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_oldnew_connector_in_state(&state->base, conn,
+                                          old_conn_state, new_conn_state, i) {
+               struct intel_encoder *encoder;
+               struct intel_crtc *crtc;
+
+               if (!intel_connector_needs_modeset(state,
+                                                  old_conn_state,
+                                                  new_conn_state))
+                       continue;
+
+               encoder = intel_connector_primary_encoder(to_intel_connector(conn));
+               if (!encoder->update_complete)
+                       continue;
+
+               crtc = new_conn_state->crtc ?
+                       to_intel_crtc(new_conn_state->crtc) : NULL;
+               encoder->update_complete(state, encoder, crtc);
+       }
+}
+
+static void intel_encoders_pre_pll_enable(struct intel_crtc *crtc,
                                          struct intel_crtc_state *crtc_state,
-                                         struct drm_atomic_state *old_state)
+                                         struct intel_atomic_state *state)
 {
        struct drm_connector_state *conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_new_connector_in_state(old_state, conn, conn_state, i) {
+       for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(conn_state->best_encoder);
 
-               if (conn_state->crtc != crtc)
+               if (conn_state->crtc != &crtc->base)
                        continue;
 
                if (encoder->pre_pll_enable)
@@ -6056,19 +6171,19 @@ static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
        }
 }
 
-static void intel_encoders_pre_enable(struct drm_crtc *crtc,
+static void intel_encoders_pre_enable(struct intel_crtc *crtc,
                                      struct intel_crtc_state *crtc_state,
-                                     struct drm_atomic_state *old_state)
+                                     struct intel_atomic_state *state)
 {
        struct drm_connector_state *conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_new_connector_in_state(old_state, conn, conn_state, i) {
+       for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(conn_state->best_encoder);
 
-               if (conn_state->crtc != crtc)
+               if (conn_state->crtc != &crtc->base)
                        continue;
 
                if (encoder->pre_enable)
@@ -6076,19 +6191,19 @@ static void intel_encoders_pre_enable(struct drm_crtc *crtc,
        }
 }
 
-static void intel_encoders_enable(struct drm_crtc *crtc,
+static void intel_encoders_enable(struct intel_crtc *crtc,
                                  struct intel_crtc_state *crtc_state,
-                                 struct drm_atomic_state *old_state)
+                                 struct intel_atomic_state *state)
 {
        struct drm_connector_state *conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_new_connector_in_state(old_state, conn, conn_state, i) {
+       for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(conn_state->best_encoder);
 
-               if (conn_state->crtc != crtc)
+               if (conn_state->crtc != &crtc->base)
                        continue;
 
                if (encoder->enable)
@@ -6097,19 +6212,19 @@ static void intel_encoders_enable(struct drm_crtc *crtc,
        }
 }
 
-static void intel_encoders_disable(struct drm_crtc *crtc,
+static void intel_encoders_disable(struct intel_crtc *crtc,
                                   struct intel_crtc_state *old_crtc_state,
-                                  struct drm_atomic_state *old_state)
+                                  struct intel_atomic_state *state)
 {
        struct drm_connector_state *old_conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
+       for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(old_conn_state->best_encoder);
 
-               if (old_conn_state->crtc != crtc)
+               if (old_conn_state->crtc != &crtc->base)
                        continue;
 
                intel_opregion_notify_encoder(encoder, false);
@@ -6118,19 +6233,19 @@ static void intel_encoders_disable(struct drm_crtc *crtc,
        }
 }
 
-static void intel_encoders_post_disable(struct drm_crtc *crtc,
+static void intel_encoders_post_disable(struct intel_crtc *crtc,
                                        struct intel_crtc_state *old_crtc_state,
-                                       struct drm_atomic_state *old_state)
+                                       struct intel_atomic_state *state)
 {
        struct drm_connector_state *old_conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
+       for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(old_conn_state->best_encoder);
 
-               if (old_conn_state->crtc != crtc)
+               if (old_conn_state->crtc != &crtc->base)
                        continue;
 
                if (encoder->post_disable)
@@ -6138,19 +6253,19 @@ static void intel_encoders_post_disable(struct drm_crtc *crtc,
        }
 }
 
-static void intel_encoders_post_pll_disable(struct drm_crtc *crtc,
+static void intel_encoders_post_pll_disable(struct intel_crtc *crtc,
                                            struct intel_crtc_state *old_crtc_state,
-                                           struct drm_atomic_state *old_state)
+                                           struct intel_atomic_state *state)
 {
        struct drm_connector_state *old_conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
+       for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(old_conn_state->best_encoder);
 
-               if (old_conn_state->crtc != crtc)
+               if (old_conn_state->crtc != &crtc->base)
                        continue;
 
                if (encoder->post_pll_disable)
@@ -6158,19 +6273,19 @@ static void intel_encoders_post_pll_disable(struct drm_crtc *crtc,
        }
 }
 
-static void intel_encoders_update_pipe(struct drm_crtc *crtc,
+static void intel_encoders_update_pipe(struct intel_crtc *crtc,
                                       struct intel_crtc_state *crtc_state,
-                                      struct drm_atomic_state *old_state)
+                                      struct intel_atomic_state *state)
 {
        struct drm_connector_state *conn_state;
        struct drm_connector *conn;
        int i;
 
-       for_each_new_connector_in_state(old_state, conn, conn_state, i) {
+       for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
                struct intel_encoder *encoder =
                        to_intel_encoder(conn_state->best_encoder);
 
-               if (conn_state->crtc != crtc)
+               if (conn_state->crtc != &crtc->base)
                        continue;
 
                if (encoder->update_pipe)
@@ -6187,15 +6302,13 @@ static void intel_disable_primary_plane(const struct intel_crtc_state *crtc_stat
 }
 
 static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
-                                struct drm_atomic_state *old_state)
+                                struct intel_atomic_state *state)
 {
        struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       struct intel_atomic_state *old_intel_state =
-               to_intel_atomic_state(old_state);
 
        if (WARN_ON(intel_crtc->active))
                return;
@@ -6231,7 +6344,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
 
        intel_crtc->active = true;
 
-       intel_encoders_pre_enable(crtc, pipe_config, old_state);
+       intel_encoders_pre_enable(intel_crtc, pipe_config, state);
 
        if (pipe_config->has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
@@ -6255,16 +6368,16 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_disable_primary_plane(pipe_config);
 
        if (dev_priv->display.initial_watermarks != NULL)
-               dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
+               dev_priv->display.initial_watermarks(state, pipe_config);
        intel_enable_pipe(pipe_config);
 
        if (pipe_config->has_pch_encoder)
-               ironlake_pch_enable(old_intel_state, pipe_config);
+               ironlake_pch_enable(state, pipe_config);
 
        assert_vblank_disabled(crtc);
        intel_crtc_vblank_on(pipe_config);
 
-       intel_encoders_enable(crtc, pipe_config, old_state);
+       intel_encoders_enable(intel_crtc, pipe_config, state);
 
        if (HAS_PCH_CPT(dev_priv))
                cpt_verify_modeset(dev, intel_crtc->pipe);
@@ -6317,26 +6430,24 @@ static void icl_pipe_mbus_enable(struct intel_crtc *crtc)
 }
 
 static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
-                               struct drm_atomic_state *old_state)
+                               struct intel_atomic_state *state)
 {
        struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe, hsw_workaround_pipe;
        enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
-       struct intel_atomic_state *old_intel_state =
-               to_intel_atomic_state(old_state);
        bool psl_clkgate_wa;
 
        if (WARN_ON(intel_crtc->active))
                return;
 
-       intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
+       intel_encoders_pre_pll_enable(intel_crtc, pipe_config, state);
 
        if (pipe_config->shared_dpll)
                intel_enable_shared_dpll(pipe_config);
 
-       intel_encoders_pre_enable(crtc, pipe_config, old_state);
+       intel_encoders_pre_enable(intel_crtc, pipe_config, state);
 
        if (intel_crtc_has_dp_encoder(pipe_config))
                intel_dp_set_m_n(pipe_config, M1_N1);
@@ -6394,7 +6505,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
                intel_ddi_enable_transcoder_func(pipe_config);
 
        if (dev_priv->display.initial_watermarks != NULL)
-               dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
+               dev_priv->display.initial_watermarks(state, pipe_config);
 
        if (INTEL_GEN(dev_priv) >= 11)
                icl_pipe_mbus_enable(intel_crtc);
@@ -6404,7 +6515,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
                intel_enable_pipe(pipe_config);
 
        if (pipe_config->has_pch_encoder)
-               lpt_pch_enable(old_intel_state, pipe_config);
+               lpt_pch_enable(state, pipe_config);
 
        if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST))
                intel_ddi_set_vc_payload_alloc(pipe_config, true);
@@ -6412,7 +6523,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        assert_vblank_disabled(crtc);
        intel_crtc_vblank_on(pipe_config);
 
-       intel_encoders_enable(crtc, pipe_config, old_state);
+       intel_encoders_enable(intel_crtc, pipe_config, state);
 
        if (psl_clkgate_wa) {
                intel_wait_for_vblank(dev_priv, pipe);
@@ -6444,7 +6555,7 @@ static void ironlake_pfit_disable(const struct intel_crtc_state *old_crtc_state)
 }
 
 static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
-                                 struct drm_atomic_state *old_state)
+                                 struct intel_atomic_state *state)
 {
        struct drm_crtc *crtc = old_crtc_state->base.crtc;
        struct drm_device *dev = crtc->dev;
@@ -6460,7 +6571,7 @@ static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 
-       intel_encoders_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_disable(intel_crtc, old_crtc_state, state);
 
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
@@ -6472,7 +6583,7 @@ static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
        if (old_crtc_state->has_pch_encoder)
                ironlake_fdi_disable(crtc);
 
-       intel_encoders_post_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_post_disable(intel_crtc, old_crtc_state, state);
 
        if (old_crtc_state->has_pch_encoder) {
                ironlake_disable_pch_transcoder(dev_priv, pipe);
@@ -6503,14 +6614,14 @@ static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
 }
 
 static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
-                                struct drm_atomic_state *old_state)
+                                struct intel_atomic_state *state)
 {
        struct drm_crtc *crtc = old_crtc_state->base.crtc;
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
 
-       intel_encoders_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_disable(intel_crtc, old_crtc_state, state);
 
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
@@ -6532,9 +6643,9 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
        else
                ironlake_pfit_disable(old_crtc_state);
 
-       intel_encoders_post_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_post_disable(intel_crtc, old_crtc_state, state);
 
-       intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_post_pll_disable(intel_crtc, old_crtc_state, state);
 }
 
 static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state)
@@ -6614,6 +6725,25 @@ enum intel_display_power_domain intel_port_to_power_domain(enum port port)
 enum intel_display_power_domain
 intel_aux_power_domain(struct intel_digital_port *dig_port)
 {
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+       if (intel_port_is_tc(dev_priv, dig_port->base.port) &&
+           dig_port->tc_mode == TC_PORT_TBT_ALT) {
+               switch (dig_port->aux_ch) {
+               case AUX_CH_C:
+                       return POWER_DOMAIN_AUX_TBT1;
+               case AUX_CH_D:
+                       return POWER_DOMAIN_AUX_TBT2;
+               case AUX_CH_E:
+                       return POWER_DOMAIN_AUX_TBT3;
+               case AUX_CH_F:
+                       return POWER_DOMAIN_AUX_TBT4;
+               default:
+                       MISSING_CASE(dig_port->aux_ch);
+                       return POWER_DOMAIN_AUX_TBT1;
+               }
+       }
+
        switch (dig_port->aux_ch) {
        case AUX_CH_A:
                return POWER_DOMAIN_AUX_A;
@@ -6633,14 +6763,13 @@ intel_aux_power_domain(struct intel_digital_port *dig_port)
        }
 }
 
-static u64 get_crtc_power_domains(struct drm_crtc *crtc,
+static u64 get_crtc_power_domains(struct intel_crtc *crtc,
                                  struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_encoder *encoder;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum pipe pipe = intel_crtc->pipe;
+       enum pipe pipe = crtc->pipe;
        u64 mask;
        enum transcoder transcoder = crtc_state->cpu_transcoder;
 
@@ -6669,16 +6798,15 @@ static u64 get_crtc_power_domains(struct drm_crtc *crtc,
 }
 
 static u64
-modeset_get_crtc_power_domains(struct drm_crtc *crtc,
+modeset_get_crtc_power_domains(struct intel_crtc *crtc,
                               struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum intel_display_power_domain domain;
        u64 domains, new_domains, old_domains;
 
-       old_domains = intel_crtc->enabled_power_domains;
-       intel_crtc->enabled_power_domains = new_domains =
+       old_domains = crtc->enabled_power_domains;
+       crtc->enabled_power_domains = new_domains =
                get_crtc_power_domains(crtc, crtc_state);
 
        domains = new_domains & ~old_domains;
@@ -6699,10 +6827,8 @@ static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
 }
 
 static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
-                                  struct drm_atomic_state *old_state)
+                                  struct intel_atomic_state *state)
 {
-       struct intel_atomic_state *old_intel_state =
-               to_intel_atomic_state(old_state);
        struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -6729,7 +6855,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
 
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-       intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
+       intel_encoders_pre_pll_enable(intel_crtc, pipe_config, state);
 
        if (IS_CHERRYVIEW(dev_priv)) {
                chv_prepare_pll(intel_crtc, pipe_config);
@@ -6739,7 +6865,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
                vlv_enable_pll(intel_crtc, pipe_config);
        }
 
-       intel_encoders_pre_enable(crtc, pipe_config, old_state);
+       intel_encoders_pre_enable(intel_crtc, pipe_config, state);
 
        i9xx_pfit_enable(pipe_config);
 
@@ -6748,14 +6874,13 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        /* update DSPCNTR to configure gamma for pipe bottom color */
        intel_disable_primary_plane(pipe_config);
 
-       dev_priv->display.initial_watermarks(old_intel_state,
-                                            pipe_config);
+       dev_priv->display.initial_watermarks(state, pipe_config);
        intel_enable_pipe(pipe_config);
 
        assert_vblank_disabled(crtc);
        intel_crtc_vblank_on(pipe_config);
 
-       intel_encoders_enable(crtc, pipe_config, old_state);
+       intel_encoders_enable(intel_crtc, pipe_config, state);
 }
 
 static void i9xx_set_pll_dividers(const struct intel_crtc_state *crtc_state)
@@ -6768,10 +6893,8 @@ static void i9xx_set_pll_dividers(const struct intel_crtc_state *crtc_state)
 }
 
 static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
-                            struct drm_atomic_state *old_state)
+                            struct intel_atomic_state *state)
 {
-       struct intel_atomic_state *old_intel_state =
-               to_intel_atomic_state(old_state);
        struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -6796,7 +6919,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        if (!IS_GEN(dev_priv, 2))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-       intel_encoders_pre_enable(crtc, pipe_config, old_state);
+       intel_encoders_pre_enable(intel_crtc, pipe_config, state);
 
        i9xx_enable_pll(intel_crtc, pipe_config);
 
@@ -6808,7 +6931,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_disable_primary_plane(pipe_config);
 
        if (dev_priv->display.initial_watermarks != NULL)
-               dev_priv->display.initial_watermarks(old_intel_state,
+               dev_priv->display.initial_watermarks(state,
                                                     pipe_config);
        else
                intel_update_watermarks(intel_crtc);
@@ -6817,7 +6940,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        assert_vblank_disabled(crtc);
        intel_crtc_vblank_on(pipe_config);
 
-       intel_encoders_enable(crtc, pipe_config, old_state);
+       intel_encoders_enable(intel_crtc, pipe_config, state);
 }
 
 static void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state)
@@ -6836,7 +6959,7 @@ static void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state)
 }
 
 static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
-                             struct drm_atomic_state *old_state)
+                             struct intel_atomic_state *state)
 {
        struct drm_crtc *crtc = old_crtc_state->base.crtc;
        struct drm_device *dev = crtc->dev;
@@ -6851,7 +6974,7 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
        if (IS_GEN(dev_priv, 2))
                intel_wait_for_vblank(dev_priv, pipe);
 
-       intel_encoders_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_disable(intel_crtc, old_crtc_state, state);
 
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
@@ -6860,7 +6983,7 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
 
        i9xx_pfit_disable(old_crtc_state);
 
-       intel_encoders_post_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_post_disable(intel_crtc, old_crtc_state, state);
 
        if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DSI)) {
                if (IS_CHERRYVIEW(dev_priv))
@@ -6871,7 +6994,7 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
                        i9xx_disable_pll(old_crtc_state);
        }
 
-       intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
+       intel_encoders_post_pll_disable(intel_crtc, old_crtc_state, state);
 
        if (!IS_GEN(dev_priv, 2))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
@@ -6925,7 +7048,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
 
        WARN_ON(IS_ERR(crtc_state) || ret);
 
-       dev_priv->display.crtc_disable(crtc_state, state);
+       dev_priv->display.crtc_disable(crtc_state, to_intel_atomic_state(state));
 
        drm_atomic_state_put(state);
 
@@ -6988,7 +7111,7 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
 
 /* Cross check the actual hw state with our own modeset state tracking (and it's
  * internal consistency). */
-static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
+static void intel_connector_verify_state(struct intel_crtc_state *crtc_state,
                                         struct drm_connector_state *conn_state)
 {
        struct intel_connector *connector = to_intel_connector(conn_state->connector);
@@ -7006,7 +7129,7 @@ static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
                if (!crtc_state)
                        return;
 
-               I915_STATE_WARN(!crtc_state->active,
+               I915_STATE_WARN(!crtc_state->base.active,
                      "connector is active, but attached crtc isn't\n");
 
                if (!encoder || encoder->type == INTEL_OUTPUT_DP_MST)
@@ -7018,7 +7141,7 @@ static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
                I915_STATE_WARN(conn_state->crtc != encoder->base.crtc,
                        "attached encoder crtc differs from connector crtc\n");
        } else {
-               I915_STATE_WARN(crtc_state && crtc_state->active,
+               I915_STATE_WARN(crtc_state && crtc_state->base.active,
                        "attached crtc is active, but connector isn't\n");
                I915_STATE_WARN(!crtc_state && conn_state->best_encoder,
                        "best encoder set without crtc!\n");
@@ -9484,6 +9607,8 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
                                       struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_atomic_state *state =
+               to_intel_atomic_state(crtc_state->base.state);
        const struct intel_limit *limit;
        int refclk = 120000;
 
@@ -9525,7 +9650,7 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
 
        ironlake_compute_dpll(crtc, crtc_state, NULL);
 
-       if (!intel_get_shared_dpll(crtc_state, NULL)) {
+       if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
                DRM_DEBUG_KMS("failed to find PLL for pipe %c\n",
                              pipe_name(crtc->pipe));
                return -EINVAL;
@@ -9906,7 +10031,7 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                struct intel_encoder *encoder =
                        intel_get_crtc_new_encoder(state, crtc_state);
 
-               if (!intel_get_shared_dpll(crtc_state, encoder)) {
+               if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
                        DRM_DEBUG_KMS("failed to find PLL for pipe %c\n",
                                      pipe_name(crtc->pipe));
                        return -EINVAL;
@@ -9936,22 +10061,36 @@ static void icelake_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;
        enum intel_dpll_id id;
        u32 temp;
 
-       /* TODO: TBT pll not implemented. */
        if (intel_port_is_combophy(dev_priv, port)) {
                temp = I915_READ(DPCLKA_CFGCR0_ICL) &
                       DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
                id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
+               port_dpll_id = ICL_PORT_DPLL_DEFAULT;
        } else if (intel_port_is_tc(dev_priv, port)) {
-               id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv, port));
+               u32 clk_sel = I915_READ(DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK;
+
+               if (clk_sel == DDI_CLK_SEL_MG) {
+                       id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv,
+                                                                   port));
+                       port_dpll_id = ICL_PORT_DPLL_MG_PHY;
+               } else {
+                       WARN_ON(clk_sel < DDI_CLK_SEL_TBT_162);
+                       id = DPLL_ID_ICL_TBTPLL;
+                       port_dpll_id = ICL_PORT_DPLL_DEFAULT;
+               }
        } else {
                WARN(1, "Invalid port %x\n", port);
                return;
        }
 
-       pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+       pipe_config->icl_port_dplls[port_dpll_id].pll =
+               intel_get_shared_dpll_by_id(dev_priv, id);
+
+       icl_set_active_port_dpll(pipe_config, port_dpll_id);
 }
 
 static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
@@ -11297,7 +11436,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
  *
  * Returns true or false.
  */
-static bool intel_wm_need_update(struct intel_plane_state *cur,
+static bool intel_wm_need_update(const struct intel_plane_state *cur,
                                 struct intel_plane_state *new)
 {
        /* Update watermarks on tiling or size changes. */
@@ -11329,33 +11468,28 @@ static bool needs_scaling(const struct intel_plane_state *state)
 }
 
 int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
-                                   struct drm_crtc_state *crtc_state,
+                                   struct intel_crtc_state *crtc_state,
                                    const struct intel_plane_state *old_plane_state,
-                                   struct drm_plane_state *plane_state)
+                                   struct intel_plane_state *plane_state)
 {
-       struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
-       struct drm_crtc *crtc = crtc_state->crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_plane *plane = to_intel_plane(plane_state->plane);
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        bool mode_changed = needs_modeset(crtc_state);
        bool was_crtc_enabled = old_crtc_state->base.active;
-       bool is_crtc_enabled = crtc_state->active;
+       bool is_crtc_enabled = crtc_state->base.active;
        bool turn_off, turn_on, visible, was_visible;
-       struct drm_framebuffer *fb = plane_state->fb;
+       struct drm_framebuffer *fb = plane_state->base.fb;
        int ret;
 
        if (INTEL_GEN(dev_priv) >= 9 && plane->id != PLANE_CURSOR) {
-               ret = skl_update_scaler_plane(
-                       to_intel_crtc_state(crtc_state),
-                       to_intel_plane_state(plane_state));
+               ret = skl_update_scaler_plane(crtc_state, plane_state);
                if (ret)
                        return ret;
        }
 
        was_visible = old_plane_state->base.visible;
-       visible = plane_state->visible;
+       visible = plane_state->base.visible;
 
        if (!was_crtc_enabled && WARN_ON(was_visible))
                was_visible = false;
@@ -11371,22 +11505,22 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
         * only combine the results from all planes in the current place?
         */
        if (!is_crtc_enabled) {
-               plane_state->visible = visible = false;
-               to_intel_crtc_state(crtc_state)->active_planes &= ~BIT(plane->id);
-               to_intel_crtc_state(crtc_state)->data_rate[plane->id] = 0;
+               plane_state->base.visible = visible = false;
+               crtc_state->active_planes &= ~BIT(plane->id);
+               crtc_state->data_rate[plane->id] = 0;
        }
 
        if (!was_visible && !visible)
                return 0;
 
        if (fb != old_plane_state->base.fb)
-               pipe_config->fb_changed = true;
+               crtc_state->fb_changed = true;
 
        turn_off = was_visible && (!visible || mode_changed);
        turn_on = visible && (!was_visible || mode_changed);
 
        DRM_DEBUG_ATOMIC("[CRTC:%d:%s] has [PLANE:%d:%s] with fb %i\n",
-                        intel_crtc->base.base.id, intel_crtc->base.name,
+                        crtc->base.base.id, crtc->base.name,
                         plane->base.base.id, plane->base.name,
                         fb ? fb->base.id : -1);
 
@@ -11397,29 +11531,28 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
 
        if (turn_on) {
                if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
-                       pipe_config->update_wm_pre = true;
+                       crtc_state->update_wm_pre = true;
 
                /* must disable cxsr around plane enable/disable */
                if (plane->id != PLANE_CURSOR)
-                       pipe_config->disable_cxsr = true;
+                       crtc_state->disable_cxsr = true;
        } else if (turn_off) {
                if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
-                       pipe_config->update_wm_post = true;
+                       crtc_state->update_wm_post = true;
 
                /* must disable cxsr around plane enable/disable */
                if (plane->id != PLANE_CURSOR)
-                       pipe_config->disable_cxsr = true;
-       } else if (intel_wm_need_update(to_intel_plane_state(plane->base.state),
-                                       to_intel_plane_state(plane_state))) {
+                       crtc_state->disable_cxsr = true;
+       } else if (intel_wm_need_update(old_plane_state, plane_state)) {
                if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) {
                        /* FIXME bollocks */
-                       pipe_config->update_wm_pre = true;
-                       pipe_config->update_wm_post = true;
+                       crtc_state->update_wm_pre = true;
+                       crtc_state->update_wm_post = true;
                }
        }
 
        if (visible || was_visible)
-               pipe_config->fb_bits |= plane->frontbuffer_bit;
+               crtc_state->fb_bits |= plane->frontbuffer_bit;
 
        /*
         * ILK/SNB DVSACNTR/Sprite Enable
@@ -11458,8 +11591,8 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
            (IS_GEN_RANGE(dev_priv, 5, 6) ||
             IS_IVYBRIDGE(dev_priv)) &&
            (turn_on || (!needs_scaling(old_plane_state) &&
-                        needs_scaling(to_intel_plane_state(plane_state)))))
-               pipe_config->disable_lp_wm = true;
+                        needs_scaling(plane_state))))
+               crtc_state->disable_lp_wm = true;
 
        return 0;
 }
@@ -11608,7 +11741,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc_state);
        int ret;
-       bool mode_changed = needs_modeset(crtc_state);
+       bool mode_changed = needs_modeset(pipe_config);
 
        if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv) &&
            mode_changed && !crtc_state->active)
@@ -12090,6 +12223,8 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        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;
+       memcpy(saved_state->icl_port_dplls, crtc_state->icl_port_dplls,
+              sizeof(saved_state->icl_port_dplls));
        saved_state->crc_enabled = crtc_state->crc_enabled;
        if (IS_G4X(dev_priv) ||
            IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
@@ -12706,10 +12841,10 @@ static void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv,
        }
 }
 
-static void verify_wm_state(struct drm_crtc *crtc,
-                           struct drm_crtc_state *new_state)
+static void verify_wm_state(struct intel_crtc *crtc,
+                           struct intel_crtc_state *new_crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct skl_hw_state {
                struct skl_ddb_entry ddb_y[I915_MAX_PLANES];
                struct skl_ddb_entry ddb_uv[I915_MAX_PLANES];
@@ -12719,21 +12854,20 @@ static void verify_wm_state(struct drm_crtc *crtc,
        struct skl_ddb_allocation *sw_ddb;
        struct skl_pipe_wm *sw_wm;
        struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       const enum pipe pipe = intel_crtc->pipe;
+       const enum pipe pipe = crtc->pipe;
        int plane, level, max_level = ilk_wm_max_level(dev_priv);
 
-       if (INTEL_GEN(dev_priv) < 9 || !new_state->active)
+       if (INTEL_GEN(dev_priv) < 9 || !new_crtc_state->base.active)
                return;
 
        hw = kzalloc(sizeof(*hw), GFP_KERNEL);
        if (!hw)
                return;
 
-       skl_pipe_wm_get_hw_state(intel_crtc, &hw->wm);
-       sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal;
+       skl_pipe_wm_get_hw_state(crtc, &hw->wm);
+       sw_wm = &new_crtc_state->wm.skl.optimal;
 
-       skl_pipe_ddb_get_hw_state(intel_crtc, hw->ddb_y, hw->ddb_uv);
+       skl_pipe_ddb_get_hw_state(crtc, hw->ddb_y, hw->ddb_uv);
 
        skl_ddb_get_hw_state(dev_priv, &hw->ddb);
        sw_ddb = &dev_priv->wm.skl_hw.ddb;
@@ -12781,7 +12915,7 @@ static void verify_wm_state(struct drm_crtc *crtc,
 
                /* DDB */
                hw_ddb_entry = &hw->ddb_y[plane];
-               sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[plane];
+               sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb_y[plane];
 
                if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
                        DRM_ERROR("mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n",
@@ -12833,7 +12967,7 @@ static void verify_wm_state(struct drm_crtc *crtc,
 
                /* DDB */
                hw_ddb_entry = &hw->ddb_y[PLANE_CURSOR];
-               sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[PLANE_CURSOR];
+               sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR];
 
                if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
                        DRM_ERROR("mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n",
@@ -12847,23 +12981,22 @@ static void verify_wm_state(struct drm_crtc *crtc,
 }
 
 static void
-verify_connector_state(struct drm_device *dev,
-                      struct drm_atomic_state *state,
-                      struct drm_crtc *crtc)
+verify_connector_state(struct intel_atomic_state *state,
+                      struct intel_crtc *crtc)
 {
        struct drm_connector *connector;
        struct drm_connector_state *new_conn_state;
        int i;
 
-       for_each_new_connector_in_state(state, connector, new_conn_state, i) {
+       for_each_new_connector_in_state(&state->base, connector, new_conn_state, i) {
                struct drm_encoder *encoder = connector->encoder;
-               struct drm_crtc_state *crtc_state = NULL;
+               struct intel_crtc_state *crtc_state = NULL;
 
-               if (new_conn_state->crtc != crtc)
+               if (new_conn_state->crtc != &crtc->base)
                        continue;
 
                if (crtc)
-                       crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
+                       crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
 
                intel_connector_verify_state(crtc_state, new_conn_state);
 
@@ -12873,14 +13006,14 @@ verify_connector_state(struct drm_device *dev,
 }
 
 static void
-verify_encoder_state(struct drm_device *dev, struct drm_atomic_state *state)
+verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_state *state)
 {
        struct intel_encoder *encoder;
        struct drm_connector *connector;
        struct drm_connector_state *old_conn_state, *new_conn_state;
        int i;
 
-       for_each_intel_encoder(dev, encoder) {
+       for_each_intel_encoder(&dev_priv->drm, encoder) {
                bool enabled = false, found = false;
                enum pipe pipe;
 
@@ -12888,7 +13021,7 @@ verify_encoder_state(struct drm_device *dev, struct drm_atomic_state *state)
                              encoder->base.base.id,
                              encoder->base.name);
 
-               for_each_oldnew_connector_in_state(state, connector, old_conn_state,
+               for_each_oldnew_connector_in_state(&state->base, connector, old_conn_state,
                                                   new_conn_state, i) {
                        if (old_conn_state->best_encoder == &encoder->base)
                                found = true;
@@ -12922,50 +13055,49 @@ verify_encoder_state(struct drm_device *dev, struct drm_atomic_state *state)
 }
 
 static void
-verify_crtc_state(struct drm_crtc *crtc,
-                 struct drm_crtc_state *old_crtc_state,
-                 struct drm_crtc_state *new_crtc_state)
+verify_crtc_state(struct intel_crtc *crtc,
+                 struct intel_crtc_state *old_crtc_state,
+                 struct intel_crtc_state *new_crtc_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_encoder *encoder;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_crtc_state *pipe_config, *sw_config;
-       struct drm_atomic_state *old_state;
+       struct intel_crtc_state *pipe_config;
+       struct drm_atomic_state *state;
        bool active;
 
-       old_state = old_crtc_state->state;
-       __drm_atomic_helper_crtc_destroy_state(old_crtc_state);
-       pipe_config = to_intel_crtc_state(old_crtc_state);
+       state = old_crtc_state->base.state;
+       __drm_atomic_helper_crtc_destroy_state(&old_crtc_state->base);
+       pipe_config = old_crtc_state;
        memset(pipe_config, 0, sizeof(*pipe_config));
-       pipe_config->base.crtc = crtc;
-       pipe_config->base.state = old_state;
+       pipe_config->base.crtc = &crtc->base;
+       pipe_config->base.state = state;
 
-       DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
+       DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.base.id, crtc->base.name);
 
-       active = dev_priv->display.get_pipe_config(intel_crtc, pipe_config);
+       active = dev_priv->display.get_pipe_config(crtc, pipe_config);
 
        /* we keep both pipes enabled on 830 */
        if (IS_I830(dev_priv))
-               active = new_crtc_state->active;
+               active = new_crtc_state->base.active;
 
-       I915_STATE_WARN(new_crtc_state->active != active,
+       I915_STATE_WARN(new_crtc_state->base.active != active,
             "crtc active state doesn't match with hw state "
-            "(expected %i, found %i)\n", new_crtc_state->active, active);
+            "(expected %i, found %i)\n", new_crtc_state->base.active, active);
 
-       I915_STATE_WARN(intel_crtc->active != new_crtc_state->active,
+       I915_STATE_WARN(crtc->active != new_crtc_state->base.active,
             "transitional active state does not match atomic hw state "
-            "(expected %i, found %i)\n", new_crtc_state->active, intel_crtc->active);
+            "(expected %i, found %i)\n", new_crtc_state->base.active, crtc->active);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder) {
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
                enum pipe pipe;
 
                active = encoder->get_hw_state(encoder, &pipe);
-               I915_STATE_WARN(active != new_crtc_state->active,
+               I915_STATE_WARN(active != new_crtc_state->base.active,
                        "[ENCODER:%i] active %i with crtc active %i\n",
-                       encoder->base.base.id, active, new_crtc_state->active);
+                       encoder->base.base.id, active, new_crtc_state->base.active);
 
-               I915_STATE_WARN(active && intel_crtc->pipe != pipe,
+               I915_STATE_WARN(active && crtc->pipe != pipe,
                                "Encoder connected to wrong pipe %c\n",
                                pipe_name(pipe));
 
@@ -12975,16 +13107,16 @@ verify_crtc_state(struct drm_crtc *crtc,
 
        intel_crtc_compute_pixel_rate(pipe_config);
 
-       if (!new_crtc_state->active)
+       if (!new_crtc_state->base.active)
                return;
 
        intel_pipe_config_sanity_check(dev_priv, pipe_config);
 
-       sw_config = to_intel_crtc_state(new_crtc_state);
-       if (!intel_pipe_config_compare(sw_config, pipe_config, false)) {
+       if (!intel_pipe_config_compare(new_crtc_state,
+                                      pipe_config, false)) {
                I915_STATE_WARN(1, "pipe state doesn't match!\n");
                intel_dump_pipe_config(pipe_config, NULL, "[hw state]");
-               intel_dump_pipe_config(sw_config, NULL, "[sw state]");
+               intel_dump_pipe_config(new_crtc_state, NULL, "[sw state]");
        }
 }
 
@@ -13004,8 +13136,8 @@ intel_verify_planes(struct intel_atomic_state *state)
 static void
 verify_single_dpll_state(struct drm_i915_private *dev_priv,
                         struct intel_shared_dpll *pll,
-                        struct drm_crtc *crtc,
-                        struct drm_crtc_state *new_state)
+                        struct intel_crtc *crtc,
+                        struct intel_crtc_state *new_crtc_state)
 {
        struct intel_dpll_hw_state dpll_hw_state;
        unsigned int crtc_mask;
@@ -13035,16 +13167,16 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv,
                return;
        }
 
-       crtc_mask = drm_crtc_mask(crtc);
+       crtc_mask = drm_crtc_mask(&crtc->base);
 
-       if (new_state->active)
+       if (new_crtc_state->base.active)
                I915_STATE_WARN(!(pll->active_mask & crtc_mask),
                                "pll active mismatch (expected pipe %c in active mask 0x%02x)\n",
-                               pipe_name(drm_crtc_index(crtc)), pll->active_mask);
+                               pipe_name(drm_crtc_index(&crtc->base)), pll->active_mask);
        else
                I915_STATE_WARN(pll->active_mask & crtc_mask,
                                "pll active mismatch (didn't expect pipe %c in active mask 0x%02x)\n",
-                               pipe_name(drm_crtc_index(crtc)), pll->active_mask);
+                               pipe_name(drm_crtc_index(&crtc->base)), pll->active_mask);
 
        I915_STATE_WARN(!(pll->state.crtc_mask & crtc_mask),
                        "pll enabled crtcs mismatch (expected 0x%x in 0x%02x)\n",
@@ -13057,51 +13189,47 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv,
 }
 
 static void
-verify_shared_dpll_state(struct drm_device *dev, struct drm_crtc *crtc,
-                        struct drm_crtc_state *old_crtc_state,
-                        struct drm_crtc_state *new_crtc_state)
+verify_shared_dpll_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(dev);
-       struct intel_crtc_state *old_state = to_intel_crtc_state(old_crtc_state);
-       struct intel_crtc_state *new_state = to_intel_crtc_state(new_crtc_state);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       if (new_state->shared_dpll)
-               verify_single_dpll_state(dev_priv, new_state->shared_dpll, crtc, new_crtc_state);
+       if (new_crtc_state->shared_dpll)
+               verify_single_dpll_state(dev_priv, new_crtc_state->shared_dpll, crtc, new_crtc_state);
 
-       if (old_state->shared_dpll &&
-           old_state->shared_dpll != new_state->shared_dpll) {
-               unsigned int crtc_mask = drm_crtc_mask(crtc);
-               struct intel_shared_dpll *pll = old_state->shared_dpll;
+       if (old_crtc_state->shared_dpll &&
+           old_crtc_state->shared_dpll != new_crtc_state->shared_dpll) {
+               unsigned int crtc_mask = drm_crtc_mask(&crtc->base);
+               struct intel_shared_dpll *pll = old_crtc_state->shared_dpll;
 
                I915_STATE_WARN(pll->active_mask & crtc_mask,
                                "pll active mismatch (didn't expect pipe %c in active mask)\n",
-                               pipe_name(drm_crtc_index(crtc)));
+                               pipe_name(drm_crtc_index(&crtc->base)));
                I915_STATE_WARN(pll->state.crtc_mask & crtc_mask,
                                "pll enabled crtcs mismatch (found %x in enabled mask)\n",
-                               pipe_name(drm_crtc_index(crtc)));
+                               pipe_name(drm_crtc_index(&crtc->base)));
        }
 }
 
 static void
-intel_modeset_verify_crtc(struct drm_crtc *crtc,
-                         struct drm_atomic_state *state,
-                         struct drm_crtc_state *old_state,
-                         struct drm_crtc_state *new_state)
+intel_modeset_verify_crtc(struct intel_crtc *crtc,
+                         struct intel_atomic_state *state,
+                         struct intel_crtc_state *old_crtc_state,
+                         struct intel_crtc_state *new_crtc_state)
 {
-       if (!needs_modeset(new_state) &&
-           !to_intel_crtc_state(new_state)->update_pipe)
+       if (!needs_modeset(new_crtc_state) && !new_crtc_state->update_pipe)
                return;
 
-       verify_wm_state(crtc, new_state);
-       verify_connector_state(crtc->dev, state, crtc);
-       verify_crtc_state(crtc, old_state, new_state);
-       verify_shared_dpll_state(crtc->dev, crtc, old_state, new_state);
+       verify_wm_state(crtc, new_crtc_state);
+       verify_connector_state(state, crtc);
+       verify_crtc_state(crtc, old_crtc_state, new_crtc_state);
+       verify_shared_dpll_state(crtc, old_crtc_state, new_crtc_state);
 }
 
 static void
-verify_disabled_dpll_state(struct drm_device *dev)
+verify_disabled_dpll_state(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        int i;
 
        for (i = 0; i < dev_priv->num_shared_dpll; i++)
@@ -13109,12 +13237,12 @@ verify_disabled_dpll_state(struct drm_device *dev)
 }
 
 static void
-intel_modeset_verify_disabled(struct drm_device *dev,
-                             struct drm_atomic_state *state)
+intel_modeset_verify_disabled(struct drm_i915_private *dev_priv,
+                             struct intel_atomic_state *state)
 {
-       verify_encoder_state(dev, state);
-       verify_connector_state(dev, state, NULL);
-       verify_disabled_dpll_state(dev);
+       verify_encoder_state(dev_priv, state);
+       verify_connector_state(state, NULL);
+       verify_disabled_dpll_state(dev_priv);
 }
 
 static void update_scanline_offset(const struct intel_crtc_state *crtc_state)
@@ -13168,27 +13296,18 @@ static void update_scanline_offset(const struct intel_crtc_state *crtc_state)
 static void intel_modeset_clear_plls(struct intel_atomic_state *state)
 {
        struct drm_i915_private *dev_priv = to_i915(state->base.dev);
-       struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc_state *new_crtc_state;
        struct intel_crtc *crtc;
        int i;
 
        if (!dev_priv->display.crtc_compute_clock)
                return;
 
-       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
-                                           new_crtc_state, i) {
-               struct intel_shared_dpll *old_dpll =
-                       old_crtc_state->shared_dpll;
-
-               if (!needs_modeset(&new_crtc_state->base))
-                       continue;
-
-               new_crtc_state->shared_dpll = NULL;
-
-               if (!old_dpll)
+       for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+               if (!needs_modeset(new_crtc_state))
                        continue;
 
-               intel_release_shared_dpll(old_dpll, crtc, &state->base);
+               intel_release_shared_dplls(state, crtc);
        }
 }
 
@@ -13210,7 +13329,7 @@ static int haswell_mode_set_planes_workaround(struct intel_atomic_state *state)
        /* look at all crtc's that are going to be enabled in during modeset */
        for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
                if (!crtc_state->base.active ||
-                   !needs_modeset(&crtc_state->base))
+                   !needs_modeset(crtc_state))
                        continue;
 
                if (first_crtc_state) {
@@ -13235,7 +13354,7 @@ static int haswell_mode_set_planes_workaround(struct intel_atomic_state *state)
                crtc_state->hsw_workaround_pipe = INVALID_PIPE;
 
                if (!crtc_state->base.active ||
-                   needs_modeset(&crtc_state->base))
+                   needs_modeset(crtc_state))
                        continue;
 
                /* 2 or more enabled crtcs means no need for w/a */
@@ -13285,7 +13404,7 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
                if (IS_ERR(crtc_state))
                        return PTR_ERR(crtc_state);
 
-               if (!crtc_state->active || needs_modeset(crtc_state))
+               if (!crtc_state->active || needs_modeset(to_intel_crtc_state(crtc_state)))
                        continue;
 
                crtc_state->mode_changed = true;
@@ -13362,12 +13481,12 @@ static int intel_modeset_checks(struct intel_atomic_state *state)
                }
 
                if (is_power_of_2(state->active_crtcs)) {
-                       struct drm_crtc *crtc;
-                       struct drm_crtc_state *crtc_state;
+                       struct intel_crtc *crtc;
+                       struct intel_crtc_state *crtc_state;
 
                        pipe = ilog2(state->active_crtcs);
-                       crtc = &intel_get_crtc_for_pipe(dev_priv, pipe)->base;
-                       crtc_state = drm_atomic_get_new_crtc_state(&state->base, crtc);
+                       crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+                       crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
                        if (crtc_state && needs_modeset(crtc_state))
                                pipe = INVALID_PIPE;
                } else {
@@ -13478,7 +13597,7 @@ 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 (!needs_modeset(&new_crtc_state->base))
+               if (!needs_modeset(new_crtc_state))
                        continue;
 
                if (!new_crtc_state->base.enable) {
@@ -13492,7 +13611,7 @@ static int intel_atomic_check(struct drm_device *dev,
 
                intel_crtc_check_fastset(old_crtc_state, new_crtc_state);
 
-               if (needs_modeset(&new_crtc_state->base))
+               if (needs_modeset(new_crtc_state))
                        any_ms = true;
        }
 
@@ -13527,12 +13646,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 (!needs_modeset(&new_crtc_state->base) &&
+               if (!needs_modeset(new_crtc_state) &&
                    !new_crtc_state->update_pipe)
                        continue;
 
                intel_dump_pipe_config(new_crtc_state, state,
-                                      needs_modeset(&new_crtc_state->base) ?
+                                      needs_modeset(new_crtc_state) ?
                                       "[modeset]" : "[fastset]");
        }
 
@@ -13567,60 +13686,57 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
        if (!vblank->max_vblank_count)
                return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
 
-       return dev->driver->get_vblank_counter(dev, crtc->pipe);
+       return crtc->base.funcs->get_vblank_counter(&crtc->base);
 }
 
-static void intel_update_crtc(struct drm_crtc *crtc,
-                             struct drm_atomic_state *state,
-                             struct drm_crtc_state *old_crtc_state,
-                             struct drm_crtc_state *new_crtc_state)
+static void intel_update_crtc(struct intel_crtc *crtc,
+                             struct intel_atomic_state *state,
+                             struct intel_crtc_state *old_crtc_state,
+                             struct intel_crtc_state *new_crtc_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = state->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_crtc_state *pipe_config = to_intel_crtc_state(new_crtc_state);
        bool modeset = needs_modeset(new_crtc_state);
        struct intel_plane_state *new_plane_state =
-               intel_atomic_get_new_plane_state(to_intel_atomic_state(state),
-                                                to_intel_plane(crtc->primary));
+               intel_atomic_get_new_plane_state(state,
+                                                to_intel_plane(crtc->base.primary));
 
        if (modeset) {
-               update_scanline_offset(pipe_config);
-               dev_priv->display.crtc_enable(pipe_config, state);
+               update_scanline_offset(new_crtc_state);
+               dev_priv->display.crtc_enable(new_crtc_state, state);
 
                /* vblanks work again, re-enable pipe CRC. */
-               intel_crtc_enable_pipe_crc(intel_crtc);
+               intel_crtc_enable_pipe_crc(crtc);
        } else {
-               intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
-                                      pipe_config);
+               intel_pre_plane_update(old_crtc_state, new_crtc_state);
 
-               if (pipe_config->update_pipe)
-                       intel_encoders_update_pipe(crtc, pipe_config, state);
+               if (new_crtc_state->update_pipe)
+                       intel_encoders_update_pipe(crtc, new_crtc_state, state);
        }
 
-       if (pipe_config->update_pipe && !pipe_config->enable_fbc)
-               intel_fbc_disable(intel_crtc);
+       if (new_crtc_state->update_pipe && !new_crtc_state->enable_fbc)
+               intel_fbc_disable(crtc);
        else if (new_plane_state)
-               intel_fbc_enable(intel_crtc, pipe_config, new_plane_state);
+               intel_fbc_enable(crtc, new_crtc_state, new_plane_state);
 
-       intel_begin_crtc_commit(to_intel_atomic_state(state), intel_crtc);
+       intel_begin_crtc_commit(state, crtc);
 
        if (INTEL_GEN(dev_priv) >= 9)
-               skl_update_planes_on_crtc(to_intel_atomic_state(state), intel_crtc);
+               skl_update_planes_on_crtc(state, crtc);
        else
-               i9xx_update_planes_on_crtc(to_intel_atomic_state(state), intel_crtc);
+               i9xx_update_planes_on_crtc(state, crtc);
 
-       intel_finish_crtc_commit(to_intel_atomic_state(state), intel_crtc);
+       intel_finish_crtc_commit(state, crtc);
 }
 
-static void intel_update_crtcs(struct drm_atomic_state *state)
+static void intel_update_crtcs(struct intel_atomic_state *state)
 {
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc *crtc;
+       struct intel_crtc_state *old_crtc_state, *new_crtc_state;
        int i;
 
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               if (!new_crtc_state->active)
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               if (!new_crtc_state->base.active)
                        continue;
 
                intel_update_crtc(crtc, state, old_crtc_state,
@@ -13628,26 +13744,23 @@ static void intel_update_crtcs(struct drm_atomic_state *state)
        }
 }
 
-static void skl_update_crtcs(struct drm_atomic_state *state)
+static void skl_update_crtcs(struct intel_atomic_state *state)
 {
-       struct drm_i915_private *dev_priv = to_i915(state->dev);
-       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-       struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
-       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
-       struct intel_crtc_state *cstate;
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct intel_crtc *crtc;
+       struct intel_crtc_state *old_crtc_state, *new_crtc_state;
        unsigned int updated = 0;
        bool progress;
        enum pipe pipe;
        int i;
        u8 hw_enabled_slices = dev_priv->wm.skl_hw.ddb.enabled_slices;
-       u8 required_slices = intel_state->wm_results.ddb.enabled_slices;
+       u8 required_slices = state->wm_results.ddb.enabled_slices;
        struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
 
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i)
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i)
                /* ignore allocations for crtc's that have been turned off. */
-               if (new_crtc_state->active)
-                       entries[i] = to_intel_crtc_state(old_crtc_state)->wm.skl.ddb;
+               if (new_crtc_state->base.active)
+                       entries[i] = old_crtc_state->wm.skl.ddb;
 
        /* If 2nd DBuf slice required, enable it here */
        if (INTEL_GEN(dev_priv) >= 11 && required_slices > hw_enabled_slices)
@@ -13662,24 +13775,22 @@ static void skl_update_crtcs(struct drm_atomic_state *state)
        do {
                progress = false;
 
-               for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                        bool vbl_wait = false;
-                       unsigned int cmask = drm_crtc_mask(crtc);
+                       unsigned int cmask = drm_crtc_mask(&crtc->base);
 
-                       intel_crtc = to_intel_crtc(crtc);
-                       cstate = to_intel_crtc_state(new_crtc_state);
-                       pipe = intel_crtc->pipe;
+                       pipe = crtc->pipe;
 
-                       if (updated & cmask || !cstate->base.active)
+                       if (updated & cmask || !new_crtc_state->base.active)
                                continue;
 
-                       if (skl_ddb_allocation_overlaps(&cstate->wm.skl.ddb,
+                       if (skl_ddb_allocation_overlaps(&new_crtc_state->wm.skl.ddb,
                                                        entries,
                                                        INTEL_INFO(dev_priv)->num_pipes, i))
                                continue;
 
                        updated |= cmask;
-                       entries[i] = cstate->wm.skl.ddb;
+                       entries[i] = new_crtc_state->wm.skl.ddb;
 
                        /*
                         * If this is an already active pipe, it's DDB changed,
@@ -13687,10 +13798,10 @@ static void skl_update_crtcs(struct drm_atomic_state *state)
                         * then we need to wait for a vblank to pass for the
                         * new ddb allocation to take effect.
                         */
-                       if (!skl_ddb_entry_equal(&cstate->wm.skl.ddb,
-                                                &to_intel_crtc_state(old_crtc_state)->wm.skl.ddb) &&
-                           !new_crtc_state->active_changed &&
-                           intel_state->wm_results.dirty_pipes != updated)
+                       if (!skl_ddb_entry_equal(&new_crtc_state->wm.skl.ddb,
+                                                &old_crtc_state->wm.skl.ddb) &&
+                           !new_crtc_state->base.active_changed &&
+                           state->wm_results.dirty_pipes != updated)
                                vbl_wait = true;
 
                        intel_update_crtc(crtc, state, old_crtc_state,
@@ -13763,57 +13874,50 @@ static void intel_atomic_cleanup_work(struct work_struct *work)
        intel_atomic_helper_free_state(i915);
 }
 
-static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+static void intel_atomic_commit_tail(struct intel_atomic_state *state)
 {
-       struct drm_device *dev = state->dev;
-       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+       struct drm_device *dev = state->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
-       struct intel_crtc_state *new_intel_crtc_state, *old_intel_crtc_state;
-       struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
+       struct intel_crtc_state *new_crtc_state, *old_crtc_state;
+       struct intel_crtc *crtc;
        u64 put_domains[I915_MAX_PIPES] = {};
        intel_wakeref_t wakeref = 0;
        int i;
 
-       intel_atomic_commit_fence_wait(intel_state);
+       intel_atomic_commit_fence_wait(state);
 
-       drm_atomic_helper_wait_for_dependencies(state);
+       drm_atomic_helper_wait_for_dependencies(&state->base);
 
-       if (intel_state->modeset)
+       if (state->modeset)
                wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               old_intel_crtc_state = to_intel_crtc_state(old_crtc_state);
-               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
-               intel_crtc = to_intel_crtc(crtc);
-
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                if (needs_modeset(new_crtc_state) ||
-                   to_intel_crtc_state(new_crtc_state)->update_pipe) {
+                   new_crtc_state->update_pipe) {
 
-                       put_domains[intel_crtc->pipe] =
+                       put_domains[crtc->pipe] =
                                modeset_get_crtc_power_domains(crtc,
-                                       new_intel_crtc_state);
+                                       new_crtc_state);
                }
 
                if (!needs_modeset(new_crtc_state))
                        continue;
 
-               intel_pre_plane_update(old_intel_crtc_state, new_intel_crtc_state);
+               intel_pre_plane_update(old_crtc_state, new_crtc_state);
 
-               if (old_crtc_state->active) {
-                       intel_crtc_disable_planes(intel_state, intel_crtc);
+               if (old_crtc_state->base.active) {
+                       intel_crtc_disable_planes(state, crtc);
 
                        /*
                         * We need to disable pipe CRC before disabling the pipe,
                         * or we race against vblank off.
                         */
-                       intel_crtc_disable_pipe_crc(intel_crtc);
+                       intel_crtc_disable_pipe_crc(crtc);
 
-                       dev_priv->display.crtc_disable(old_intel_crtc_state, state);
-                       intel_crtc->active = false;
-                       intel_fbc_disable(intel_crtc);
-                       intel_disable_shared_dpll(old_intel_crtc_state);
+                       dev_priv->display.crtc_disable(old_crtc_state, state);
+                       crtc->active = false;
+                       intel_fbc_disable(crtc);
+                       intel_disable_shared_dpll(old_crtc_state);
 
                        /*
                         * Underruns don't always raise
@@ -13823,25 +13927,25 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                        intel_check_pch_fifo_underruns(dev_priv);
 
                        /* FIXME unify this for all platforms */
-                       if (!new_crtc_state->active &&
+                       if (!new_crtc_state->base.active &&
                            !HAS_GMCH(dev_priv) &&
                            dev_priv->display.initial_watermarks)
-                               dev_priv->display.initial_watermarks(intel_state,
-                                                                    new_intel_crtc_state);
+                               dev_priv->display.initial_watermarks(state,
+                                                                    new_crtc_state);
                }
        }
 
-       /* FIXME: Eventually get rid of our intel_crtc->config pointer */
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
-               to_intel_crtc(crtc)->config = to_intel_crtc_state(new_crtc_state);
+       /* FIXME: Eventually get rid of our crtc->config pointer */
+       for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
+               crtc->config = new_crtc_state;
 
-       if (intel_state->modeset) {
-               drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
+       if (state->modeset) {
+               drm_atomic_helper_update_legacy_modeset_state(dev, &state->base);
 
                intel_set_cdclk_pre_plane_update(dev_priv,
-                                                &intel_state->cdclk.actual,
+                                                &state->cdclk.actual,
                                                 &dev_priv->cdclk.actual,
-                                                intel_state->cdclk.pipe);
+                                                state->cdclk.pipe);
 
                /*
                 * SKL workaround: bspec recommends we disable the SAGV when we
@@ -13850,31 +13954,37 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                if (!intel_can_enable_sagv(state))
                        intel_disable_sagv(dev_priv);
 
-               intel_modeset_verify_disabled(dev, state);
+               intel_modeset_verify_disabled(dev_priv, state);
        }
 
        /* Complete the events for pipes that have now been disabled */
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+       for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
                bool modeset = needs_modeset(new_crtc_state);
 
                /* Complete events for now disable pipes here. */
-               if (modeset && !new_crtc_state->active && new_crtc_state->event) {
+               if (modeset && !new_crtc_state->base.active && new_crtc_state->base.event) {
                        spin_lock_irq(&dev->event_lock);
-                       drm_crtc_send_vblank_event(crtc, new_crtc_state->event);
+                       drm_crtc_send_vblank_event(&crtc->base, new_crtc_state->base.event);
                        spin_unlock_irq(&dev->event_lock);
 
-                       new_crtc_state->event = NULL;
+                       new_crtc_state->base.event = NULL;
                }
        }
 
+       if (state->modeset)
+               intel_encoders_update_prepare(state);
+
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
        dev_priv->display.update_crtcs(state);
 
-       if (intel_state->modeset)
+       if (state->modeset) {
+               intel_encoders_update_complete(state);
+
                intel_set_cdclk_post_plane_update(dev_priv,
-                                                 &intel_state->cdclk.actual,
+                                                 &state->cdclk.actual,
                                                  &dev_priv->cdclk.actual,
-                                                 intel_state->cdclk.pipe);
+                                                 state->cdclk.pipe);
+       }
 
        /* FIXME: We should call drm_atomic_helper_commit_hw_done() here
         * already, but still need the state for the delayed optimization. To
@@ -13885,16 +13995,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         * - switch over to the vblank wait helper in the core after that since
         *   we don't need out special handling any more.
         */
-       drm_atomic_helper_wait_for_flip_done(dev, state);
-
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
+       drm_atomic_helper_wait_for_flip_done(dev, &state->base);
 
-               if (new_crtc_state->active &&
+       for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+               if (new_crtc_state->base.active &&
                    !needs_modeset(new_crtc_state) &&
-                   (new_intel_crtc_state->base.color_mgmt_changed ||
-                    new_intel_crtc_state->update_pipe))
-                       intel_color_load_luts(new_intel_crtc_state);
+                   (new_crtc_state->base.color_mgmt_changed ||
+                    new_crtc_state->update_pipe))
+                       intel_color_load_luts(new_crtc_state);
        }
 
        /*
@@ -13904,16 +14012,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         *
         * TODO: Move this (and other cleanup) to an async worker eventually.
         */
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
-
+       for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
                if (dev_priv->display.optimize_watermarks)
-                       dev_priv->display.optimize_watermarks(intel_state,
-                                                             new_intel_crtc_state);
+                       dev_priv->display.optimize_watermarks(state,
+                                                             new_crtc_state);
        }
 
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               intel_post_plane_update(to_intel_crtc_state(old_crtc_state));
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               intel_post_plane_update(old_crtc_state);
 
                if (put_domains[i])
                        modeset_put_power_domains(dev_priv, put_domains[i]);
@@ -13921,15 +14027,15 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
        }
 
-       if (intel_state->modeset)
-               intel_verify_planes(intel_state);
+       if (state->modeset)
+               intel_verify_planes(state);
 
-       if (intel_state->modeset && intel_can_enable_sagv(state))
+       if (state->modeset && intel_can_enable_sagv(state))
                intel_enable_sagv(dev_priv);
 
-       drm_atomic_helper_commit_hw_done(state);
+       drm_atomic_helper_commit_hw_done(&state->base);
 
-       if (intel_state->modeset) {
+       if (state->modeset) {
                /* As one of the primary mmio accessors, KMS has a high
                 * likelihood of triggering bugs in unclaimed access. After we
                 * finish modesetting, see if an error has been flagged, and if
@@ -13939,7 +14045,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore);
                intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET, wakeref);
        }
-       intel_runtime_pm_put(&dev_priv->runtime_pm, intel_state->wakeref);
+       intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);
 
        /*
         * Defer the cleanup of the old state to a separate worker to not
@@ -13949,14 +14055,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         * schedule point (cond_resched()) here anyway to keep latencies
         * down.
         */
-       INIT_WORK(&state->commit_work, intel_atomic_cleanup_work);
-       queue_work(system_highpri_wq, &state->commit_work);
+       INIT_WORK(&state->base.commit_work, intel_atomic_cleanup_work);
+       queue_work(system_highpri_wq, &state->base.commit_work);
 }
 
 static void intel_atomic_commit_work(struct work_struct *work)
 {
-       struct drm_atomic_state *state =
-               container_of(work, struct drm_atomic_state, commit_work);
+       struct intel_atomic_state *state =
+               container_of(work, struct intel_atomic_state, base.commit_work);
 
        intel_atomic_commit_tail(state);
 }
@@ -14099,24 +14205,12 @@ static int intel_atomic_commit(struct drm_device *dev,
        } else {
                if (intel_state->modeset)
                        flush_workqueue(dev_priv->modeset_wq);
-               intel_atomic_commit_tail(state);
+               intel_atomic_commit_tail(intel_state);
        }
 
        return 0;
 }
 
-static const struct drm_crtc_funcs intel_crtc_funcs = {
-       .gamma_set = drm_atomic_helper_legacy_gamma_set,
-       .set_config = drm_atomic_helper_set_config,
-       .destroy = intel_crtc_destroy,
-       .page_flip = drm_atomic_helper_page_flip,
-       .atomic_duplicate_state = intel_crtc_duplicate_state,
-       .atomic_destroy_state = intel_crtc_destroy_state,
-       .set_crc_source = intel_crtc_set_crc_source,
-       .verify_crc_source = intel_crtc_verify_crc_source,
-       .get_crc_sources = intel_crtc_get_crc_sources,
-};
-
 struct wait_rps_boost {
        struct wait_queue_entry wait;
 
@@ -14250,9 +14344,9 @@ intel_prepare_plane_fb(struct drm_plane *plane,
        int ret;
 
        if (old_obj) {
-               struct drm_crtc_state *crtc_state =
-                       drm_atomic_get_new_crtc_state(new_state->state,
-                                                     plane->state->crtc);
+               struct intel_crtc_state *crtc_state =
+                       intel_atomic_get_new_crtc_state(intel_state,
+                                                       to_intel_crtc(plane->state->crtc));
 
                /* Big Hammer, we also need to ensure that any pending
                 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
@@ -14413,7 +14507,7 @@ static void intel_begin_crtc_commit(struct intel_atomic_state *state,
                intel_atomic_get_old_crtc_state(state, crtc);
        struct intel_crtc_state *new_crtc_state =
                intel_atomic_get_new_crtc_state(state, crtc);
-       bool modeset = needs_modeset(&new_crtc_state->base);
+       bool modeset = needs_modeset(new_crtc_state);
 
        /* Perform vblank evasion around commit operation */
        intel_pipe_update_start(new_crtc_state);
@@ -14466,7 +14560,7 @@ static void intel_finish_crtc_commit(struct intel_atomic_state *state,
        intel_pipe_update_end(new_crtc_state);
 
        if (new_crtc_state->update_pipe &&
-           !needs_modeset(&new_crtc_state->base) &&
+           !needs_modeset(new_crtc_state) &&
            old_crtc_state->base.mode.private_flags & I915_MODE_FLAG_INHERITED)
                intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
 }
@@ -14580,7 +14674,7 @@ 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
         */
-       if (!crtc_state->base.active || needs_modeset(&crtc_state->base) ||
+       if (!crtc_state->base.active || needs_modeset(crtc_state) ||
            crtc_state->update_pipe)
                goto slow;
 
@@ -14910,8 +15004,76 @@ static void intel_crtc_init_scalers(struct intel_crtc *crtc,
        scaler_state->scaler_id = -1;
 }
 
+#define INTEL_CRTC_FUNCS \
+       .gamma_set = drm_atomic_helper_legacy_gamma_set, \
+       .set_config = drm_atomic_helper_set_config, \
+       .destroy = intel_crtc_destroy, \
+       .page_flip = drm_atomic_helper_page_flip, \
+       .atomic_duplicate_state = intel_crtc_duplicate_state, \
+       .atomic_destroy_state = intel_crtc_destroy_state, \
+       .set_crc_source = intel_crtc_set_crc_source, \
+       .verify_crc_source = intel_crtc_verify_crc_source, \
+       .get_crc_sources = intel_crtc_get_crc_sources
+
+static const struct drm_crtc_funcs bdw_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       .get_vblank_counter = g4x_get_vblank_counter,
+       .enable_vblank = bdw_enable_vblank,
+       .disable_vblank = bdw_disable_vblank,
+};
+
+static const struct drm_crtc_funcs ilk_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       .get_vblank_counter = g4x_get_vblank_counter,
+       .enable_vblank = ilk_enable_vblank,
+       .disable_vblank = ilk_disable_vblank,
+};
+
+static const struct drm_crtc_funcs g4x_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       .get_vblank_counter = g4x_get_vblank_counter,
+       .enable_vblank = i965_enable_vblank,
+       .disable_vblank = i965_disable_vblank,
+};
+
+static const struct drm_crtc_funcs i965_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       .get_vblank_counter = i915_get_vblank_counter,
+       .enable_vblank = i965_enable_vblank,
+       .disable_vblank = i965_disable_vblank,
+};
+
+static const struct drm_crtc_funcs i945gm_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       .get_vblank_counter = i915_get_vblank_counter,
+       .enable_vblank = i945gm_enable_vblank,
+       .disable_vblank = i945gm_disable_vblank,
+};
+
+static const struct drm_crtc_funcs i915_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       .get_vblank_counter = i915_get_vblank_counter,
+       .enable_vblank = i8xx_enable_vblank,
+       .disable_vblank = i8xx_disable_vblank,
+};
+
+static const struct drm_crtc_funcs i8xx_crtc_funcs = {
+       INTEL_CRTC_FUNCS,
+
+       /* no hw vblank counter */
+       .enable_vblank = i8xx_enable_vblank,
+       .disable_vblank = i8xx_disable_vblank,
+};
+
 static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
+       const struct drm_crtc_funcs *funcs;
        struct intel_crtc *intel_crtc;
        struct intel_crtc_state *crtc_state = NULL;
        struct intel_plane *primary = NULL;
@@ -14955,10 +15117,28 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
        }
        intel_crtc->plane_ids_mask |= BIT(cursor->id);
 
+       if (HAS_GMCH(dev_priv)) {
+               if (IS_CHERRYVIEW(dev_priv) ||
+                   IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
+                       funcs = &g4x_crtc_funcs;
+               else if (IS_GEN(dev_priv, 4))
+                       funcs = &i965_crtc_funcs;
+               else if (IS_I945GM(dev_priv))
+                       funcs = &i945gm_crtc_funcs;
+               else if (IS_GEN(dev_priv, 3))
+                       funcs = &i915_crtc_funcs;
+               else
+                       funcs = &i8xx_crtc_funcs;
+       } else {
+               if (INTEL_GEN(dev_priv) >= 8)
+                       funcs = &bdw_crtc_funcs;
+               else
+                       funcs = &ilk_crtc_funcs;
+       }
+
        ret = drm_crtc_init_with_planes(&dev_priv->drm, &intel_crtc->base,
                                        &primary->base, &cursor->base,
-                                       &intel_crtc_funcs,
-                                       "pipe %c", pipe_name(pipe));
+                                       funcs, "pipe %c", pipe_name(pipe));
        if (ret)
                goto fail;
 
@@ -15775,8 +15955,8 @@ static void sanitize_watermarks(struct drm_device *dev)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_atomic_state *state;
        struct intel_atomic_state *intel_state;
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *cstate;
+       struct intel_crtc *crtc;
+       struct intel_crtc_state *crtc_state;
        struct drm_modeset_acquire_ctx ctx;
        int ret;
        int i;
@@ -15831,13 +16011,11 @@ retry:
        }
 
        /* Write calculated watermark values back */
-       for_each_new_crtc_in_state(state, crtc, cstate, i) {
-               struct intel_crtc_state *cs = to_intel_crtc_state(cstate);
+       for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
+               crtc_state->wm.need_postvbl_update = true;
+               dev_priv->display.optimize_watermarks(intel_state, crtc_state);
 
-               cs->wm.need_postvbl_update = true;
-               dev_priv->display.optimize_watermarks(intel_state, cs);
-
-               to_intel_crtc_state(crtc->state)->wm = cs->wm;
+               to_intel_crtc_state(crtc->base.state)->wm = crtc_state->wm;
        }
 
 put_state:
@@ -16495,6 +16673,13 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
 
                pll->on = pll->info->funcs->get_hw_state(dev_priv, pll,
                                                        &pll->state.hw_state);
+
+               if (IS_ELKHARTLAKE(dev_priv) && pll->on &&
+                   pll->info->id == DPLL_ID_EHL_DPLL4) {
+                       pll->wakeref = intel_display_power_get(dev_priv,
+                                                              POWER_DOMAIN_DPLL_DC_OFF);
+               }
+
                pll->state.crtc_mask = 0;
                for_each_intel_crtc(dev, crtc) {
                        struct intel_crtc_state *crtc_state =
@@ -16744,6 +16929,15 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
        intel_modeset_readout_hw_state(dev);
 
        /* HW state is read out, now we need to sanitize this mess. */
+
+       /* Sanitize the TypeC port mode upfront, encoders depend on this */
+       for_each_intel_encoder(dev, encoder) {
+               /* We need to sanitize only the MST primary port. */
+               if (encoder->type != INTEL_OUTPUT_DP_MST &&
+                   intel_port_is_tc(dev_priv, encoder->port))
+                       intel_tc_port_sanitize(enc_to_dig_port(&encoder->base));
+       }
+
        get_encoder_power_domains(dev_priv);
 
        if (HAS_PCH_IBX(dev_priv))
@@ -16804,7 +16998,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
                u64 put_domains;
 
                crtc_state = to_intel_crtc_state(crtc->base.state);
-               put_domains = modeset_get_crtc_power_domains(&crtc->base, crtc_state);
+               put_domains = modeset_get_crtc_power_domains(crtc, crtc_state);
                if (WARN_ON(put_domains))
                        modeset_put_power_domains(dev_priv, put_domains);
        }
index ee6b8194a459102d4894cf3d27eb374ae47cb899..d296556ed82ee92f31ed7584401e03d954f76146 100644 (file)
@@ -189,10 +189,9 @@ enum tc_port {
        I915_MAX_TC_PORTS
 };
 
-enum tc_port_type {
-       TC_PORT_UNKNOWN = 0,
-       TC_PORT_TYPEC,
-       TC_PORT_TBT,
+enum tc_port_mode {
+       TC_PORT_TBT_ALT,
+       TC_PORT_DP_ALT,
        TC_PORT_LEGACY,
 };
 
index c93ad512014ce2cca2757e4c6e3c0735a135b7c4..7437fc71d2899a249f1c5d1b1261d7d0ef0032d7 100644 (file)
@@ -17,6 +17,7 @@
 #include "intel_drv.h"
 #include "intel_hotplug.h"
 #include "intel_sideband.h"
+#include "intel_tc.h"
 
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
                                         enum i915_power_well_id power_well_id);
@@ -117,6 +118,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
                return "MODESET";
        case POWER_DOMAIN_GT_IRQ:
                return "GT_IRQ";
+       case POWER_DOMAIN_DPLL_DC_OFF:
+               return "DPLL_DC_OFF";
        default:
                MISSING_CASE(domain);
                return "?";
@@ -269,11 +272,17 @@ static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv,
        int pw_idx = power_well->desc->hsw.idx;
 
        /* Timeout for PW1:10 us, AUX:not specified, other PWs:20 us. */
-       WARN_ON(intel_wait_for_register(&dev_priv->uncore,
-                                       regs->driver,
-                                       HSW_PWR_WELL_CTL_STATE(pw_idx),
-                                       HSW_PWR_WELL_CTL_STATE(pw_idx),
-                                       1));
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   regs->driver,
+                                   HSW_PWR_WELL_CTL_STATE(pw_idx),
+                                   HSW_PWR_WELL_CTL_STATE(pw_idx),
+                                   1)) {
+               DRM_DEBUG_KMS("%s power well enable timeout\n",
+                             power_well->desc->name);
+
+               /* An AUX timeout is expected if the TBT DP tunnel is down. */
+               WARN_ON(!power_well->desc->hsw.is_tc_tbt);
+       }
 }
 
 static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv,
@@ -438,13 +447,91 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
 #define ICL_AUX_PW_TO_CH(pw_idx)       \
        ((pw_idx) - ICL_PW_CTL_IDX_AUX_A + AUX_CH_A)
 
+#define ICL_TBT_AUX_PW_TO_CH(pw_idx)   \
+       ((pw_idx) - ICL_PW_CTL_IDX_AUX_TBT1 + AUX_CH_C)
+
+static enum aux_ch icl_tc_phy_aux_ch(struct drm_i915_private *dev_priv,
+                                    struct i915_power_well *power_well)
+{
+       int pw_idx = power_well->desc->hsw.idx;
+
+       return power_well->desc->hsw.is_tc_tbt ? ICL_TBT_AUX_PW_TO_CH(pw_idx) :
+                                                ICL_AUX_PW_TO_CH(pw_idx);
+}
+
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+
+static u64 async_put_domains_mask(struct i915_power_domains *power_domains);
+
+static int power_well_async_ref_count(struct drm_i915_private *dev_priv,
+                                     struct i915_power_well *power_well)
+{
+       int refs = hweight64(power_well->desc->domains &
+                            async_put_domains_mask(&dev_priv->power_domains));
+
+       WARN_ON(refs > power_well->count);
+
+       return refs;
+}
+
+static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv,
+                                       struct i915_power_well *power_well)
+{
+       enum aux_ch aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
+       struct intel_digital_port *dig_port = NULL;
+       struct intel_encoder *encoder;
+
+       /* Bypass the check if all references are released asynchronously */
+       if (power_well_async_ref_count(dev_priv, power_well) ==
+           power_well->count)
+               return;
+
+       aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
+
+       for_each_intel_encoder(&dev_priv->drm, encoder) {
+               if (!intel_port_is_tc(dev_priv, encoder->port))
+                       continue;
+
+               /* We'll check the MST primary port */
+               if (encoder->type == INTEL_OUTPUT_DP_MST)
+                       continue;
+
+               dig_port = enc_to_dig_port(&encoder->base);
+               if (WARN_ON(!dig_port))
+                       continue;
+
+               if (dig_port->aux_ch != aux_ch) {
+                       dig_port = NULL;
+                       continue;
+               }
+
+               break;
+       }
+
+       if (WARN_ON(!dig_port))
+               return;
+
+       WARN_ON(!intel_tc_port_ref_held(dig_port));
+}
+
+#else
+
+static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv,
+                                       struct i915_power_well *power_well)
+{
+}
+
+#endif
+
 static void
 icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
                                 struct i915_power_well *power_well)
 {
-       enum aux_ch aux_ch = ICL_AUX_PW_TO_CH(power_well->desc->hsw.idx);
+       enum aux_ch aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
        u32 val;
 
+       icl_tc_port_assert_ref_held(dev_priv, power_well);
+
        val = I915_READ(DP_AUX_CH_CTL(aux_ch));
        val &= ~DP_AUX_CH_CTL_TBT_IO;
        if (power_well->desc->hsw.is_tc_tbt)
@@ -454,6 +541,15 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
        hsw_power_well_enable(dev_priv, power_well);
 }
 
+static void
+icl_tc_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
+                                 struct i915_power_well *power_well)
+{
+       icl_tc_port_assert_ref_held(dev_priv, power_well);
+
+       hsw_power_well_disable(dev_priv, power_well);
+}
+
 /*
  * We should only use the power well if we explicitly asked the hardware to
  * enable it, so check if it's enabled and also check if we've requested it to
@@ -1064,7 +1160,7 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
        spin_unlock_irq(&dev_priv->irq_lock);
 
        /* make sure we're done processing display irqs */
-       synchronize_irq(dev_priv->drm.irq);
+       intel_synchronize_irq(dev_priv);
 
        intel_power_sequencer_reset(dev_priv);
 
@@ -2361,6 +2457,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        ICL_PW_2_POWER_DOMAINS |                        \
        BIT_ULL(POWER_DOMAIN_MODESET) |                 \
        BIT_ULL(POWER_DOMAIN_AUX_A) |                   \
+       BIT_ULL(POWER_DOMAIN_DPLL_DC_OFF) |                     \
        BIT_ULL(POWER_DOMAIN_INIT))
 
 #define ICL_DDI_IO_A_POWER_DOMAINS (                   \
@@ -3106,7 +3203,7 @@ static const struct i915_power_well_ops icl_combo_phy_aux_power_well_ops = {
 static const struct i915_power_well_ops icl_tc_phy_aux_power_well_ops = {
        .sync_hw = hsw_power_well_sync_hw,
        .enable = icl_tc_phy_aux_power_well_enable,
-       .disable = hsw_power_well_disable,
+       .disable = icl_tc_phy_aux_power_well_disable,
        .is_enabled = hsw_power_well_enabled,
 };
 
index ff57b0a7fe59bcdb31fd2a5cc4b08cf72889fd5a..8f43f7051a16601b2d21c6d1db85f94b772620fe 100644 (file)
@@ -59,6 +59,7 @@ enum intel_display_power_domain {
        POWER_DOMAIN_GMBUS,
        POWER_DOMAIN_MODESET,
        POWER_DOMAIN_GT_IRQ,
+       POWER_DOMAIN_DPLL_DC_OFF,
        POWER_DOMAIN_INIT,
 
        POWER_DOMAIN_NUM,
index 4336df46fe7826460815a9ee621724199e1a7271..0bdb7ecc5a819f70b075549dcd1d76bfaf341f1e 100644 (file)
@@ -62,6 +62,7 @@
 #include "intel_panel.h"
 #include "intel_psr.h"
 #include "intel_sideband.h"
+#include "intel_tc.h"
 #include "intel_vdsc.h"
 
 #define DP_DPRX_ESI_LEN 14
@@ -211,46 +212,13 @@ static int intel_dp_max_common_rate(struct intel_dp *intel_dp)
        return intel_dp->common_rates[intel_dp->num_common_rates - 1];
 }
 
-static int intel_dp_get_fia_supported_lane_count(struct intel_dp *intel_dp)
-{
-       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 tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port);
-       intel_wakeref_t wakeref;
-       u32 lane_info;
-
-       if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC)
-               return 4;
-
-       lane_info = 0;
-       with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref)
-               lane_info = (I915_READ(PORT_TX_DFLEXDPSP) &
-                            DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
-                               DP_LANE_ASSIGNMENT_SHIFT(tc_port);
-
-       switch (lane_info) {
-       default:
-               MISSING_CASE(lane_info);
-       case 1:
-       case 2:
-       case 4:
-       case 8:
-               return 1;
-       case 3:
-       case 12:
-               return 2;
-       case 15:
-               return 4;
-       }
-}
-
 /* Theoretical max between source and sink */
 static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        int source_max = intel_dig_port->max_lanes;
        int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
-       int fia_max = intel_dp_get_fia_supported_lane_count(intel_dp);
+       int fia_max = intel_tc_port_fia_max_lane_count(intel_dig_port);
 
        return min3(source_max, sink_max, fia_max);
 }
@@ -1208,7 +1176,7 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
              DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) |
              DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
 
-       if (intel_dig_port->tc_type == TC_PORT_TBT)
+       if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT)
                ret |= DP_AUX_CH_CTL_TBT_IO;
 
        return ret;
@@ -1224,6 +1192,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
        struct drm_i915_private *i915 =
                        to_i915(intel_dig_port->base.base.dev);
        struct intel_uncore *uncore = &i915->uncore;
+       bool is_tc_port = intel_port_is_tc(i915, intel_dig_port->base.port);
        i915_reg_t ch_ctl, ch_data[5];
        u32 aux_clock_divider;
        enum intel_display_power_domain aux_domain =
@@ -1239,6 +1208,9 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
        for (i = 0; i < ARRAY_SIZE(ch_data); i++)
                ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
 
+       if (is_tc_port)
+               intel_tc_port_lock(intel_dig_port);
+
        aux_wakeref = intel_display_power_get(i915, aux_domain);
        pps_wakeref = pps_lock(intel_dp);
 
@@ -1391,6 +1363,9 @@ out:
        pps_unlock(intel_dp, pps_wakeref);
        intel_display_power_put_async(i915, aux_domain, aux_wakeref);
 
+       if (is_tc_port)
+               intel_tc_port_unlock(intel_dig_port);
+
        return ret;
 }
 
@@ -5232,195 +5207,6 @@ static bool icl_combo_port_connected(struct drm_i915_private *dev_priv,
        return I915_READ(SDEISR) & SDE_DDI_HOTPLUG_ICP(port);
 }
 
-static const char *tc_type_name(enum tc_port_type type)
-{
-       static const char * const names[] = {
-               [TC_PORT_UNKNOWN] = "unknown",
-               [TC_PORT_LEGACY] = "legacy",
-               [TC_PORT_TYPEC] = "typec",
-               [TC_PORT_TBT] = "tbt",
-       };
-
-       if (WARN_ON(type >= ARRAY_SIZE(names)))
-               type = TC_PORT_UNKNOWN;
-
-       return names[type];
-}
-
-static void icl_update_tc_port_type(struct drm_i915_private *dev_priv,
-                                   struct intel_digital_port *intel_dig_port,
-                                   bool is_legacy, bool is_typec, bool is_tbt)
-{
-       enum port port = intel_dig_port->base.port;
-       enum tc_port_type old_type = intel_dig_port->tc_type;
-
-       WARN_ON(is_legacy + is_typec + is_tbt != 1);
-
-       if (is_legacy)
-               intel_dig_port->tc_type = TC_PORT_LEGACY;
-       else if (is_typec)
-               intel_dig_port->tc_type = TC_PORT_TYPEC;
-       else if (is_tbt)
-               intel_dig_port->tc_type = TC_PORT_TBT;
-       else
-               return;
-
-       /* Types are not supposed to be changed at runtime. */
-       WARN_ON(old_type != TC_PORT_UNKNOWN &&
-               old_type != intel_dig_port->tc_type);
-
-       if (old_type != intel_dig_port->tc_type)
-               DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port),
-                             tc_type_name(intel_dig_port->tc_type));
-}
-
-/*
- * This function implements the first part of the Connect Flow described by our
- * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading
- * lanes, EDID, etc) is done as needed in the typical places.
- *
- * Unlike the other ports, type-C ports are not available to use as soon as we
- * get a hotplug. The type-C PHYs can be shared between multiple controllers:
- * display, USB, etc. As a result, handshaking through FIA is required around
- * connect and disconnect to cleanly transfer ownership with the controller and
- * set the type-C power state.
- *
- * We could opt to only do the connect flow when we actually try to use the AUX
- * channels or do a modeset, then immediately run the disconnect flow after
- * usage, but there are some implications on this for a dynamic environment:
- * things may go away or change behind our backs. So for now our driver is
- * always trying to acquire ownership of the controller as soon as it gets an
- * interrupt (or polls state and sees a port is connected) and only gives it
- * back when it sees a disconnect. Implementation of a more fine-grained model
- * will require a lot of coordination with user space and thorough testing for
- * the extra possible cases.
- */
-static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv,
-                              struct intel_digital_port *dig_port)
-{
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port);
-       u32 val;
-
-       if (dig_port->tc_type != TC_PORT_LEGACY &&
-           dig_port->tc_type != TC_PORT_TYPEC)
-               return true;
-
-       val = I915_READ(PORT_TX_DFLEXDPPMS);
-       if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) {
-               DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port);
-               WARN_ON(dig_port->tc_legacy_port);
-               return false;
-       }
-
-       /*
-        * This function may be called many times in a row without an HPD event
-        * in between, so try to avoid the write when we can.
-        */
-       val = I915_READ(PORT_TX_DFLEXDPCSSS);
-       if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) {
-               val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port);
-               I915_WRITE(PORT_TX_DFLEXDPCSSS, val);
-       }
-
-       /*
-        * Now we have to re-check the live state, in case the port recently
-        * became disconnected. Not necessary for legacy mode.
-        */
-       if (dig_port->tc_type == TC_PORT_TYPEC &&
-           !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) {
-               DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port);
-               icl_tc_phy_disconnect(dev_priv, dig_port);
-               return false;
-       }
-
-       return true;
-}
-
-/*
- * See the comment at the connect function. This implements the Disconnect
- * Flow.
- */
-void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv,
-                          struct intel_digital_port *dig_port)
-{
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port);
-
-       if (dig_port->tc_type == TC_PORT_UNKNOWN)
-               return;
-
-       /*
-        * TBT disconnection flow is read the live status, what was done in
-        * caller.
-        */
-       if (dig_port->tc_type == TC_PORT_TYPEC ||
-           dig_port->tc_type == TC_PORT_LEGACY) {
-               u32 val;
-
-               val = I915_READ(PORT_TX_DFLEXDPCSSS);
-               val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port);
-               I915_WRITE(PORT_TX_DFLEXDPCSSS, val);
-       }
-
-       DRM_DEBUG_KMS("Port %c TC type %s disconnected\n",
-                     port_name(dig_port->base.port),
-                     tc_type_name(dig_port->tc_type));
-
-       dig_port->tc_type = TC_PORT_UNKNOWN;
-}
-
-/*
- * The type-C ports are different because even when they are connected, they may
- * not be available/usable by the graphics driver: see the comment on
- * icl_tc_phy_connect(). So in our driver instead of adding the additional
- * concept of "usable" and make everything check for "connected and usable" we
- * define a port as "connected" when it is not only connected, but also when it
- * is usable by the rest of the driver. That maintains the old assumption that
- * connected ports are usable, and avoids exposing to the users objects they
- * can't really use.
- */
-static bool icl_tc_port_connected(struct drm_i915_private *dev_priv,
-                                 struct intel_digital_port *intel_dig_port)
-{
-       enum port port = intel_dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       bool is_legacy, is_typec, is_tbt;
-       u32 dpsp;
-
-       /*
-        * Complain if we got a legacy port HPD, but VBT didn't mark the port as
-        * legacy. Treat the port as legacy from now on.
-        */
-       if (!intel_dig_port->tc_legacy_port &&
-           I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) {
-               DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n",
-                         port_name(port));
-               intel_dig_port->tc_legacy_port = true;
-       }
-       is_legacy = intel_dig_port->tc_legacy_port;
-
-       /*
-        * The spec says we shouldn't be using the ISR bits for detecting
-        * between TC and TBT. We should use DFLEXDPSP.
-        */
-       dpsp = I915_READ(PORT_TX_DFLEXDPSP);
-       is_typec = dpsp & TC_LIVE_STATE_TC(tc_port);
-       is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port);
-
-       if (!is_legacy && !is_typec && !is_tbt) {
-               icl_tc_phy_disconnect(dev_priv, intel_dig_port);
-
-               return false;
-       }
-
-       icl_update_tc_port_type(dev_priv, intel_dig_port, is_legacy, is_typec,
-                               is_tbt);
-
-       if (!icl_tc_phy_connect(dev_priv, intel_dig_port))
-               return false;
-
-       return true;
-}
-
 static bool icl_digital_port_connected(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -5429,7 +5215,7 @@ static bool icl_digital_port_connected(struct intel_encoder *encoder)
        if (intel_port_is_combophy(dev_priv, encoder->port))
                return icl_combo_port_connected(dev_priv, dig_port);
        else if (intel_port_is_tc(dev_priv, encoder->port))
-               return icl_tc_port_connected(dev_priv, dig_port);
+               return intel_tc_port_connected(dig_port);
        else
                MISSING_CASE(encoder->hpd_pin);
 
@@ -6834,8 +6620,6 @@ static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
                                    const struct intel_crtc_state *crtc_state,
                                    int refresh_rate)
 {
-       struct intel_encoder *encoder;
-       struct intel_digital_port *dig_port = NULL;
        struct intel_dp *intel_dp = dev_priv->drrs.dp;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
@@ -6850,9 +6634,6 @@ static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
                return;
        }
 
-       dig_port = dp_to_dig_port(intel_dp);
-       encoder = &dig_port->base;
-
        if (!intel_crtc) {
                DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
                return;
index da70b1a41c834c4472d932f317f17fd6bcc8aa25..657bbb1f5ed08f01fea73b3e93d86b2165dc8237 100644 (file)
@@ -112,8 +112,6 @@ 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_digital_port_connected(struct intel_encoder *encoder);
-void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv,
-                          struct intel_digital_port *dig_port);
 
 static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
 {
index 7ded95a334db5b89bba90def1e1098e98a79f8b2..6b0b73479fb8e652a0c555da289334ce3da674c7 100644 (file)
@@ -264,8 +264,11 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector)
 int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector)
 {
        struct intel_panel *panel = &intel_connector->panel;
+       struct drm_i915_private *dev_priv = to_i915(intel_connector->base.dev);
 
-       if (!i915_modparams.enable_dpcd_backlight)
+       if (i915_modparams.enable_dpcd_backlight == 0 ||
+           (i915_modparams.enable_dpcd_backlight == -1 &&
+           dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE))
                return -ENODEV;
 
        if (!intel_dp_aux_display_control_capable(intel_connector))
index 1470c6e0514b1fcdcadf15fb23bef935cd061a89..6754c211205aa23b0337c7be1b66a1d7ac5a56e4 100644 (file)
@@ -6,9 +6,15 @@
 #ifndef __INTEL_DP_MST_H__
 #define __INTEL_DP_MST_H__
 
-struct intel_digital_port;
+#include "intel_drv.h"
 
 int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
 void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
+static inline int
+intel_dp_mst_encoder_active_links(struct intel_digital_port *intel_dig_port)
+{
+       return intel_dig_port->dp.active_mst_links;
+}
+
 
 #endif /* __INTEL_DP_MST_H__ */
index 2d4e7b9a7b9df4d72bc4f0d44bba88885fab996a..30d7500eb66c4dae69dd2a851d6d548ee11f3bef 100644 (file)
  * This file provides an abstraction over display PLLs. The function
  * intel_shared_dpll_init() initializes the PLLs for the given platform.  The
  * users of a PLL are tracked and that tracking is integrated with the atomic
- * modest interface. During an atomic operation, a PLL can be requested for a
- * given CRTC and encoder configuration by calling intel_get_shared_dpll() and
- * a previously used PLL can be released with intel_release_shared_dpll().
+ * modset interface. During an atomic operation, required PLLs can be reserved
+ * for a given CRTC and encoder configuration by calling
+ * intel_reserve_shared_dplls() and previously reserved PLLs can be released
+ * with intel_release_shared_dplls().
  * Changes to the users are first staged in the atomic state, and then made
  * effective by calling intel_shared_dpll_swap_state() during the atomic
  * commit phase.
@@ -243,17 +244,18 @@ out:
 }
 
 static struct intel_shared_dpll *
-intel_find_shared_dpll(struct intel_crtc_state *crtc_state,
+intel_find_shared_dpll(struct intel_atomic_state *state,
+                      const struct intel_crtc *crtc,
+                      const struct intel_dpll_hw_state *pll_state,
                       enum intel_dpll_id range_min,
                       enum intel_dpll_id range_max)
 {
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_shared_dpll *pll, *unused_pll = NULL;
        struct intel_shared_dpll_state *shared_dpll;
        enum intel_dpll_id i;
 
-       shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
+       shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
 
        for (i = range_min; i <= range_max; i++) {
                pll = &dev_priv->shared_dplls[i];
@@ -265,9 +267,9 @@ intel_find_shared_dpll(struct intel_crtc_state *crtc_state,
                        continue;
                }
 
-               if (memcmp(&crtc_state->dpll_hw_state,
+               if (memcmp(pll_state,
                           &shared_dpll[i].hw_state,
-                          sizeof(crtc_state->dpll_hw_state)) == 0) {
+                          sizeof(*pll_state)) == 0) {
                        DRM_DEBUG_KMS("[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n",
                                      crtc->base.base.id, crtc->base.name,
                                      pll->info->name,
@@ -289,26 +291,51 @@ intel_find_shared_dpll(struct intel_crtc_state *crtc_state,
 }
 
 static void
-intel_reference_shared_dpll(struct intel_shared_dpll *pll,
-                           struct intel_crtc_state *crtc_state)
+intel_reference_shared_dpll(struct intel_atomic_state *state,
+                           const struct intel_crtc *crtc,
+                           const struct intel_shared_dpll *pll,
+                           const struct intel_dpll_hw_state *pll_state)
 {
        struct intel_shared_dpll_state *shared_dpll;
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        const enum intel_dpll_id id = pll->info->id;
 
-       shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
+       shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
 
        if (shared_dpll[id].crtc_mask == 0)
-               shared_dpll[id].hw_state =
-                       crtc_state->dpll_hw_state;
+               shared_dpll[id].hw_state = *pll_state;
 
-       crtc_state->shared_dpll = pll;
        DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->info->name,
                         pipe_name(crtc->pipe));
 
        shared_dpll[id].crtc_mask |= 1 << crtc->pipe;
 }
 
+static void intel_unreference_shared_dpll(struct intel_atomic_state *state,
+                                         const struct intel_crtc *crtc,
+                                         const struct intel_shared_dpll *pll)
+{
+       struct intel_shared_dpll_state *shared_dpll;
+
+       shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
+       shared_dpll[pll->info->id].crtc_mask &= ~(1 << crtc->pipe);
+}
+
+static void intel_put_dpll(struct intel_atomic_state *state,
+                          struct intel_crtc *crtc)
+{
+       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);
+
+       new_crtc_state->shared_dpll = NULL;
+
+       if (!old_crtc_state->shared_dpll)
+               return;
+
+       intel_unreference_shared_dpll(state, crtc, old_crtc_state->shared_dpll);
+}
+
 /**
  * intel_shared_dpll_swap_state - make atomic DPLL configuration effective
  * @state: atomic state
@@ -421,11 +448,12 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
        udelay(200);
 }
 
-static struct intel_shared_dpll *
-ibx_get_dpll(struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool ibx_get_dpll(struct intel_atomic_state *state,
+                        struct intel_crtc *crtc,
+                        struct intel_encoder *encoder)
 {
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.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 intel_shared_dpll *pll;
        enum intel_dpll_id i;
@@ -439,18 +467,22 @@ ibx_get_dpll(struct intel_crtc_state *crtc_state,
                              crtc->base.base.id, crtc->base.name,
                              pll->info->name);
        } else {
-               pll = intel_find_shared_dpll(crtc_state,
+               pll = intel_find_shared_dpll(state, crtc,
+                                            &crtc_state->dpll_hw_state,
                                             DPLL_ID_PCH_PLL_A,
                                             DPLL_ID_PCH_PLL_B);
        }
 
        if (!pll)
-               return NULL;
+               return false;
 
        /* reference the pll */
-       intel_reference_shared_dpll(pll, crtc_state);
+       intel_reference_shared_dpll(state, crtc,
+                                   pll, &crtc_state->dpll_hw_state);
 
-       return pll;
+       crtc_state->shared_dpll = pll;
+
+       return true;
 }
 
 static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
@@ -767,8 +799,12 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
        *r2_out = best.r2;
 }
 
-static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(struct intel_crtc_state *crtc_state)
+static struct intel_shared_dpll *
+hsw_ddi_hdmi_get_dpll(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_shared_dpll *pll;
        u32 val;
        unsigned int p, n2, r2;
@@ -781,7 +817,8 @@ static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(struct intel_crtc_state *
 
        crtc_state->dpll_hw_state.wrpll = val;
 
-       pll = intel_find_shared_dpll(crtc_state,
+       pll = intel_find_shared_dpll(state, crtc,
+                                    &crtc_state->dpll_hw_state,
                                     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
 
        if (!pll)
@@ -821,38 +858,44 @@ hsw_ddi_dp_get_dpll(struct intel_crtc_state *crtc_state)
        return pll;
 }
 
-static struct intel_shared_dpll *
-hsw_get_dpll(struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool hsw_get_dpll(struct intel_atomic_state *state,
+                        struct intel_crtc *crtc,
+                        struct intel_encoder *encoder)
 {
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
        struct intel_shared_dpll *pll;
 
        memset(&crtc_state->dpll_hw_state, 0,
               sizeof(crtc_state->dpll_hw_state));
 
        if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
-               pll = hsw_ddi_hdmi_get_dpll(crtc_state);
+               pll = hsw_ddi_hdmi_get_dpll(state, crtc);
        } else if (intel_crtc_has_dp_encoder(crtc_state)) {
                pll = hsw_ddi_dp_get_dpll(crtc_state);
        } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
                if (WARN_ON(crtc_state->port_clock / 2 != 135000))
-                       return NULL;
+                       return false;
 
                crtc_state->dpll_hw_state.spll =
                        SPLL_PLL_ENABLE | SPLL_FREQ_1350MHz | SPLL_REF_MUXED_SSC;
 
-               pll = intel_find_shared_dpll(crtc_state,
+               pll = intel_find_shared_dpll(state, crtc,
+                                            &crtc_state->dpll_hw_state,
                                             DPLL_ID_SPLL, DPLL_ID_SPLL);
        } else {
-               return NULL;
+               return false;
        }
 
        if (!pll)
-               return NULL;
+               return false;
 
-       intel_reference_shared_dpll(pll, crtc_state);
+       intel_reference_shared_dpll(state, crtc,
+                                   pll, &crtc_state->dpll_hw_state);
 
-       return pll;
+       crtc_state->shared_dpll = pll;
+
+       return true;
 }
 
 static void hsw_dump_hw_state(struct drm_i915_private *dev_priv,
@@ -1385,10 +1428,12 @@ skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
        return true;
 }
 
-static struct intel_shared_dpll *
-skl_get_dpll(struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool skl_get_dpll(struct intel_atomic_state *state,
+                        struct intel_crtc *crtc,
+                        struct intel_encoder *encoder)
 {
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
        struct intel_shared_dpll *pll;
        bool bret;
 
@@ -1396,32 +1441,37 @@ skl_get_dpll(struct intel_crtc_state *crtc_state,
                bret = skl_ddi_hdmi_pll_dividers(crtc_state);
                if (!bret) {
                        DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
-                       return NULL;
+                       return false;
                }
        } else if (intel_crtc_has_dp_encoder(crtc_state)) {
                bret = skl_ddi_dp_set_dpll_hw_state(crtc_state);
                if (!bret) {
                        DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
-                       return NULL;
+                       return false;
                }
        } else {
-               return NULL;
+               return false;
        }
 
        if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
-               pll = intel_find_shared_dpll(crtc_state,
+               pll = intel_find_shared_dpll(state, crtc,
+                                            &crtc_state->dpll_hw_state,
                                             DPLL_ID_SKL_DPLL0,
                                             DPLL_ID_SKL_DPLL0);
        else
-               pll = intel_find_shared_dpll(crtc_state,
+               pll = intel_find_shared_dpll(state, crtc,
+                                            &crtc_state->dpll_hw_state,
                                             DPLL_ID_SKL_DPLL1,
                                             DPLL_ID_SKL_DPLL3);
        if (!pll)
-               return NULL;
+               return false;
 
-       intel_reference_shared_dpll(pll, crtc_state);
+       intel_reference_shared_dpll(state, crtc,
+                                   pll, &crtc_state->dpll_hw_state);
 
-       return pll;
+       crtc_state->shared_dpll = pll;
+
+       return true;
 }
 
 static void skl_dump_hw_state(struct drm_i915_private *dev_priv,
@@ -1827,22 +1877,23 @@ bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
        return bxt_ddi_set_dpll_hw_state(crtc_state, &clk_div);
 }
 
-static struct intel_shared_dpll *
-bxt_get_dpll(struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool bxt_get_dpll(struct intel_atomic_state *state,
+                        struct intel_crtc *crtc,
+                        struct intel_encoder *encoder)
 {
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.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 intel_shared_dpll *pll;
        enum intel_dpll_id id;
 
        if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
            !bxt_ddi_hdmi_set_dpll_hw_state(crtc_state))
-               return NULL;
+               return false;
 
        if (intel_crtc_has_dp_encoder(crtc_state) &&
            !bxt_ddi_dp_set_dpll_hw_state(crtc_state))
-               return NULL;
+               return false;
 
        /* 1:1 mapping between ports and PLLs */
        id = (enum intel_dpll_id) encoder->port;
@@ -1851,9 +1902,12 @@ bxt_get_dpll(struct intel_crtc_state *crtc_state,
        DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
                      crtc->base.base.id, crtc->base.name, pll->info->name);
 
-       intel_reference_shared_dpll(pll, crtc_state);
+       intel_reference_shared_dpll(state, crtc,
+                                   pll, &crtc_state->dpll_hw_state);
 
-       return pll;
+       crtc_state->shared_dpll = pll;
+
+       return true;
 }
 
 static void bxt_dump_hw_state(struct drm_i915_private *dev_priv,
@@ -1884,9 +1938,14 @@ static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
 struct intel_dpll_mgr {
        const struct dpll_info *dpll_info;
 
-       struct intel_shared_dpll *(*get_dpll)(struct intel_crtc_state *crtc_state,
-                                             struct intel_encoder *encoder);
-
+       bool (*get_dplls)(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc,
+                         struct intel_encoder *encoder);
+       void (*put_dplls)(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc);
+       void (*update_active_dpll)(struct intel_atomic_state *state,
+                                  struct intel_crtc *crtc,
+                                  struct intel_encoder *encoder);
        void (*dump_hw_state)(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state);
 };
@@ -1899,7 +1958,8 @@ static const struct dpll_info pch_plls[] = {
 
 static const struct intel_dpll_mgr pch_pll_mgr = {
        .dpll_info = pch_plls,
-       .get_dpll = ibx_get_dpll,
+       .get_dplls = ibx_get_dpll,
+       .put_dplls = intel_put_dpll,
        .dump_hw_state = ibx_dump_hw_state,
 };
 
@@ -1915,7 +1975,8 @@ static const struct dpll_info hsw_plls[] = {
 
 static const struct intel_dpll_mgr hsw_pll_mgr = {
        .dpll_info = hsw_plls,
-       .get_dpll = hsw_get_dpll,
+       .get_dplls = hsw_get_dpll,
+       .put_dplls = intel_put_dpll,
        .dump_hw_state = hsw_dump_hw_state,
 };
 
@@ -1929,7 +1990,8 @@ static const struct dpll_info skl_plls[] = {
 
 static const struct intel_dpll_mgr skl_pll_mgr = {
        .dpll_info = skl_plls,
-       .get_dpll = skl_get_dpll,
+       .get_dplls = skl_get_dpll,
+       .put_dplls = intel_put_dpll,
        .dump_hw_state = skl_dump_hw_state,
 };
 
@@ -1942,7 +2004,8 @@ static const struct dpll_info bxt_plls[] = {
 
 static const struct intel_dpll_mgr bxt_pll_mgr = {
        .dpll_info = bxt_plls,
-       .get_dpll = bxt_get_dpll,
+       .get_dplls = bxt_get_dpll,
+       .put_dplls = intel_put_dpll,
        .dump_hw_state = bxt_dump_hw_state,
 };
 
@@ -2332,10 +2395,12 @@ cnl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
        return true;
 }
 
-static struct intel_shared_dpll *
-cnl_get_dpll(struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool cnl_get_dpll(struct intel_atomic_state *state,
+                        struct intel_crtc *crtc,
+                        struct intel_encoder *encoder)
 {
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
        struct intel_shared_dpll *pll;
        bool bret;
 
@@ -2343,31 +2408,35 @@ cnl_get_dpll(struct intel_crtc_state *crtc_state,
                bret = cnl_ddi_hdmi_pll_dividers(crtc_state);
                if (!bret) {
                        DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
-                       return NULL;
+                       return false;
                }
        } else if (intel_crtc_has_dp_encoder(crtc_state)) {
                bret = cnl_ddi_dp_set_dpll_hw_state(crtc_state);
                if (!bret) {
                        DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
-                       return NULL;
+                       return false;
                }
        } else {
                DRM_DEBUG_KMS("Skip DPLL setup for output_types 0x%x\n",
                              crtc_state->output_types);
-               return NULL;
+               return false;
        }
 
-       pll = intel_find_shared_dpll(crtc_state,
+       pll = intel_find_shared_dpll(state, crtc,
+                                    &crtc_state->dpll_hw_state,
                                     DPLL_ID_SKL_DPLL0,
                                     DPLL_ID_SKL_DPLL2);
        if (!pll) {
                DRM_DEBUG_KMS("No PLL selected\n");
-               return NULL;
+               return false;
        }
 
-       intel_reference_shared_dpll(pll, crtc_state);
+       intel_reference_shared_dpll(state, crtc,
+                                   pll, &crtc_state->dpll_hw_state);
 
-       return pll;
+       crtc_state->shared_dpll = pll;
+
+       return true;
 }
 
 static void cnl_dump_hw_state(struct drm_i915_private *dev_priv,
@@ -2394,7 +2463,8 @@ static const struct dpll_info cnl_plls[] = {
 
 static const struct intel_dpll_mgr cnl_pll_mgr = {
        .dpll_info = cnl_plls,
-       .get_dpll = cnl_get_dpll,
+       .get_dplls = cnl_get_dpll,
+       .put_dplls = intel_put_dpll,
        .dump_hw_state = cnl_dump_hw_state,
 };
 
@@ -2506,7 +2576,8 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
 }
 
 static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state,
-                               struct intel_encoder *encoder)
+                               struct intel_encoder *encoder,
+                               struct intel_dpll_hw_state *pll_state)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
        u32 cfgcr0, cfgcr1;
@@ -2533,11 +2604,10 @@ static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state,
                 DPLL_CFGCR1_PDIV(pll_params.pdiv) |
                 DPLL_CFGCR1_CENTRAL_FREQ_8400;
 
-       memset(&crtc_state->dpll_hw_state, 0,
-              sizeof(crtc_state->dpll_hw_state));
+       memset(pll_state, 0, sizeof(*pll_state));
 
-       crtc_state->dpll_hw_state.cfgcr0 = cfgcr0;
-       crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+       pll_state->cfgcr0 = cfgcr0;
+       pll_state->cfgcr1 = cfgcr1;
 
        return true;
 }
@@ -2627,10 +2697,10 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
  * The specification for this function uses real numbers, so the math had to be
  * adapted to integer-only calculation, that's why it looks so different.
  */
-static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state)
+static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
+                                 struct intel_dpll_hw_state *pll_state)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
-       struct intel_dpll_hw_state *pll_state = &crtc_state->dpll_hw_state;
        int refclk_khz = dev_priv->cdclk.hw.ref;
        int clock = crtc_state->port_clock;
        u32 dco_khz, m1div, m2div_int, m2div_rem, m2div_frac;
@@ -2792,63 +2862,184 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state)
        return true;
 }
 
-static struct intel_shared_dpll *
-icl_get_dpll(struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+/**
+ * icl_set_active_port_dpll - select the active port DPLL for a given CRTC
+ * @crtc_state: state for the CRTC to select the DPLL for
+ * @port_dpll_id: the active @port_dpll_id to select
+ *
+ * Select the given @port_dpll_id instance from the DPLLs reserved for the
+ * CRTC.
+ */
+void icl_set_active_port_dpll(struct intel_crtc_state *crtc_state,
+                             enum icl_port_dpll_id port_dpll_id)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
-       struct intel_digital_port *intel_dig_port;
-       struct intel_shared_dpll *pll;
+       struct icl_port_dpll *port_dpll =
+               &crtc_state->icl_port_dplls[port_dpll_id];
+
+       crtc_state->shared_dpll = port_dpll->pll;
+       crtc_state->dpll_hw_state = port_dpll->hw_state;
+}
+
+static void icl_update_active_dpll(struct intel_atomic_state *state,
+                                  struct intel_crtc *crtc,
+                                  struct intel_encoder *encoder)
+{
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       struct intel_digital_port *primary_port;
+       enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT;
+
+       primary_port = encoder->type == INTEL_OUTPUT_DP_MST ?
+               enc_to_mst(&encoder->base)->primary :
+               enc_to_dig_port(&encoder->base);
+
+       if (primary_port &&
+           (primary_port->tc_mode == TC_PORT_DP_ALT ||
+            primary_port->tc_mode == TC_PORT_LEGACY))
+               port_dpll_id = ICL_PORT_DPLL_MG_PHY;
+
+       icl_set_active_port_dpll(crtc_state, port_dpll_id);
+}
+
+static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
+                                  struct intel_crtc *crtc,
+                                  struct intel_encoder *encoder)
+{
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       struct icl_port_dpll *port_dpll =
+               &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum port port = encoder->port;
-       enum intel_dpll_id min, max;
-       bool ret;
+       bool has_dpll4 = false;
 
-       if (intel_port_is_combophy(dev_priv, port)) {
-               min = DPLL_ID_ICL_DPLL0;
-               max = DPLL_ID_ICL_DPLL1;
-               ret = icl_calc_dpll_state(crtc_state, encoder);
-       } else if (intel_port_is_tc(dev_priv, port)) {
-               if (encoder->type == INTEL_OUTPUT_DP_MST) {
-                       struct intel_dp_mst_encoder *mst_encoder;
-
-                       mst_encoder = enc_to_mst(&encoder->base);
-                       intel_dig_port = mst_encoder->primary;
-               } else {
-                       intel_dig_port = enc_to_dig_port(&encoder->base);
-               }
+       if (!icl_calc_dpll_state(crtc_state, encoder, &port_dpll->hw_state)) {
+               DRM_DEBUG_KMS("Could not calculate combo PHY PLL state.\n");
 
-               if (intel_dig_port->tc_type == TC_PORT_TBT) {
-                       min = DPLL_ID_ICL_TBTPLL;
-                       max = min;
-                       ret = icl_calc_dpll_state(crtc_state, encoder);
-               } else {
-                       enum tc_port tc_port;
-
-                       tc_port = intel_port_to_tc(dev_priv, port);
-                       min = icl_tc_port_to_pll_id(tc_port);
-                       max = min;
-                       ret = icl_calc_mg_pll_state(crtc_state);
-               }
-       } else {
-               MISSING_CASE(port);
-               return NULL;
+               return false;
        }
 
-       if (!ret) {
-               DRM_DEBUG_KMS("Could not calculate PLL state.\n");
-               return NULL;
+       if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A)
+               has_dpll4 = true;
+
+       port_dpll->pll = intel_find_shared_dpll(state, crtc,
+                                               &port_dpll->hw_state,
+                                               DPLL_ID_ICL_DPLL0,
+                                               has_dpll4 ? DPLL_ID_EHL_DPLL4
+                                                         : DPLL_ID_ICL_DPLL1);
+       if (!port_dpll->pll) {
+               DRM_DEBUG_KMS("No combo PHY PLL found for port %c\n",
+                             port_name(encoder->port));
+               return false;
        }
 
+       intel_reference_shared_dpll(state, crtc,
+                                   port_dpll->pll, &port_dpll->hw_state);
 
-       pll = intel_find_shared_dpll(crtc_state, min, max);
-       if (!pll) {
-               DRM_DEBUG_KMS("No PLL selected\n");
-               return NULL;
+       icl_update_active_dpll(state, crtc, encoder);
+
+       return true;
+}
+
+static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
+                                struct intel_crtc *crtc,
+                                struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       struct icl_port_dpll *port_dpll;
+       enum intel_dpll_id dpll_id;
+
+       port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+       if (!icl_calc_dpll_state(crtc_state, encoder, &port_dpll->hw_state)) {
+               DRM_DEBUG_KMS("Could not calculate TBT PLL state.\n");
+               return false;
        }
 
-       intel_reference_shared_dpll(pll, crtc_state);
+       port_dpll->pll = intel_find_shared_dpll(state, crtc,
+                                               &port_dpll->hw_state,
+                                               DPLL_ID_ICL_TBTPLL,
+                                               DPLL_ID_ICL_TBTPLL);
+       if (!port_dpll->pll) {
+               DRM_DEBUG_KMS("No TBT-ALT PLL found\n");
+               return false;
+       }
+       intel_reference_shared_dpll(state, crtc,
+                                   port_dpll->pll, &port_dpll->hw_state);
 
-       return pll;
+
+       port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY];
+       if (!icl_calc_mg_pll_state(crtc_state, &port_dpll->hw_state)) {
+               DRM_DEBUG_KMS("Could not calculate MG PHY PLL state.\n");
+               goto err_unreference_tbt_pll;
+       }
+
+       dpll_id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv,
+                                                        encoder->port));
+       port_dpll->pll = intel_find_shared_dpll(state, crtc,
+                                               &port_dpll->hw_state,
+                                               dpll_id,
+                                               dpll_id);
+       if (!port_dpll->pll) {
+               DRM_DEBUG_KMS("No MG PHY PLL found\n");
+               goto err_unreference_tbt_pll;
+       }
+       intel_reference_shared_dpll(state, crtc,
+                                   port_dpll->pll, &port_dpll->hw_state);
+
+       icl_update_active_dpll(state, crtc, encoder);
+
+       return true;
+
+err_unreference_tbt_pll:
+       port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+       intel_unreference_shared_dpll(state, crtc, port_dpll->pll);
+
+       return false;
+}
+
+static bool icl_get_dplls(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc,
+                         struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       enum port port = encoder->port;
+
+       if (intel_port_is_combophy(dev_priv, port))
+               return icl_get_combo_phy_dpll(state, crtc, encoder);
+       else if (intel_port_is_tc(dev_priv, port))
+               return icl_get_tc_phy_dplls(state, crtc, encoder);
+
+       MISSING_CASE(port);
+
+       return false;
+}
+
+static void icl_put_dplls(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc)
+{
+       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);
+       enum icl_port_dpll_id id;
+
+       new_crtc_state->shared_dpll = NULL;
+
+       for (id = ICL_PORT_DPLL_DEFAULT; id < ICL_PORT_DPLL_COUNT; id++) {
+               const struct icl_port_dpll *old_port_dpll =
+                       &old_crtc_state->icl_port_dplls[id];
+               struct icl_port_dpll *new_port_dpll =
+                       &new_crtc_state->icl_port_dplls[id];
+
+               new_port_dpll->pll = NULL;
+
+               if (!old_port_dpll->pll)
+                       continue;
+
+               intel_unreference_shared_dpll(state, crtc, old_port_dpll->pll);
+       }
 }
 
 static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -2945,8 +3136,14 @@ static bool combo_pll_get_hw_state(struct drm_i915_private *dev_priv,
                                   struct intel_shared_dpll *pll,
                                   struct intel_dpll_hw_state *hw_state)
 {
-       return icl_pll_get_hw_state(dev_priv, pll, hw_state,
-                                   CNL_DPLL_ENABLE(pll->info->id));
+       i915_reg_t enable_reg = CNL_DPLL_ENABLE(pll->info->id);
+
+       if (IS_ELKHARTLAKE(dev_priv) &&
+           pll->info->id == DPLL_ID_EHL_DPLL4) {
+               enable_reg = MG_PLL_ENABLE(0);
+       }
+
+       return icl_pll_get_hw_state(dev_priv, pll, hw_state, enable_reg);
 }
 
 static bool tbt_pll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -3057,6 +3254,19 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv,
 {
        i915_reg_t enable_reg = CNL_DPLL_ENABLE(pll->info->id);
 
+       if (IS_ELKHARTLAKE(dev_priv) &&
+           pll->info->id == DPLL_ID_EHL_DPLL4) {
+               enable_reg = MG_PLL_ENABLE(0);
+
+               /*
+                * We need to disable DC states when this DPLL is enabled.
+                * This can be done by taking a reference on DPLL4 power
+                * domain.
+                */
+               pll->wakeref = intel_display_power_get(dev_priv,
+                                                      POWER_DOMAIN_DPLL_DC_OFF);
+       }
+
        icl_pll_power_enable(dev_priv, pll, enable_reg);
 
        icl_dpll_write(dev_priv, pll);
@@ -3152,7 +3362,19 @@ static void icl_pll_disable(struct drm_i915_private *dev_priv,
 static void combo_pll_disable(struct drm_i915_private *dev_priv,
                              struct intel_shared_dpll *pll)
 {
-       icl_pll_disable(dev_priv, pll, CNL_DPLL_ENABLE(pll->info->id));
+       i915_reg_t enable_reg = CNL_DPLL_ENABLE(pll->info->id);
+
+       if (IS_ELKHARTLAKE(dev_priv) &&
+           pll->info->id == DPLL_ID_EHL_DPLL4) {
+               enable_reg = MG_PLL_ENABLE(0);
+               icl_pll_disable(dev_priv, pll, enable_reg);
+
+               intel_display_power_put(dev_priv, POWER_DOMAIN_DPLL_DC_OFF,
+                                       pll->wakeref);
+               return;
+       }
+
+       icl_pll_disable(dev_priv, pll, enable_reg);
 }
 
 static void tbt_pll_disable(struct drm_i915_private *dev_priv,
@@ -3223,19 +3445,23 @@ static const struct dpll_info icl_plls[] = {
 
 static const struct intel_dpll_mgr icl_pll_mgr = {
        .dpll_info = icl_plls,
-       .get_dpll = icl_get_dpll,
+       .get_dplls = icl_get_dplls,
+       .put_dplls = icl_put_dplls,
+       .update_active_dpll = icl_update_active_dpll,
        .dump_hw_state = icl_dump_hw_state,
 };
 
 static const struct dpll_info ehl_plls[] = {
        { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 },
        { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 },
+       { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 },
        { },
 };
 
 static const struct intel_dpll_mgr ehl_pll_mgr = {
        .dpll_info = ehl_plls,
-       .get_dpll = icl_get_dpll,
+       .get_dplls = icl_get_dplls,
+       .put_dplls = icl_put_dplls,
        .dump_hw_state = icl_dump_hw_state,
 };
 
@@ -3287,50 +3513,87 @@ void intel_shared_dpll_init(struct drm_device *dev)
 }
 
 /**
- * intel_get_shared_dpll - get a shared DPLL for CRTC and encoder combination
- * @crtc_state: atomic state for the crtc
+ * intel_reserve_shared_dplls - reserve DPLLs for CRTC and encoder combination
+ * @state: atomic state
+ * @crtc: CRTC to reserve DPLLs for
  * @encoder: encoder
  *
- * Find an appropriate DPLL for the given CRTC and encoder combination. A
- * reference from the @crtc_state to the returned pll is registered in the
- * atomic state. That configuration is made effective by calling
- * intel_shared_dpll_swap_state(). The reference should be released by calling
- * intel_release_shared_dpll().
+ * This function reserves all required DPLLs for the given CRTC and encoder
+ * combination in the current atomic commit @state and the new @crtc atomic
+ * state.
+ *
+ * The new configuration in the atomic commit @state is made effective by
+ * calling intel_shared_dpll_swap_state().
+ *
+ * The reserved DPLLs should be released by calling
+ * intel_release_shared_dplls().
  *
  * Returns:
- * A shared DPLL to be used by @crtc_state and @encoder.
+ * True if all required DPLLs were successfully reserved.
  */
-struct intel_shared_dpll *
-intel_get_shared_dpll(struct intel_crtc_state *crtc_state,
-                     struct intel_encoder *encoder)
+bool intel_reserve_shared_dplls(struct intel_atomic_state *state,
+                               struct intel_crtc *crtc,
+                               struct intel_encoder *encoder)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
        const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
 
        if (WARN_ON(!dpll_mgr))
-               return NULL;
+               return false;
+
+       return dpll_mgr->get_dplls(state, crtc, encoder);
+}
+
+/**
+ * intel_release_shared_dplls - end use of DPLLs by CRTC in atomic state
+ * @state: atomic state
+ * @crtc: crtc from which the DPLLs are to be released
+ *
+ * This function releases all DPLLs reserved by intel_reserve_shared_dplls()
+ * from the current atomic commit @state and the old @crtc atomic state.
+ *
+ * The new configuration in the atomic commit @state is made effective by
+ * calling intel_shared_dpll_swap_state().
+ */
+void intel_release_shared_dplls(struct intel_atomic_state *state,
+                               struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
 
-       return dpll_mgr->get_dpll(crtc_state, encoder);
+       /*
+        * FIXME: this function is called for every platform having a
+        * compute_clock hook, even though the platform doesn't yet support
+        * the shared DPLL framework and intel_reserve_shared_dplls() is not
+        * called on those.
+        */
+       if (!dpll_mgr)
+               return;
+
+       dpll_mgr->put_dplls(state, crtc);
 }
 
 /**
- * intel_release_shared_dpll - end use of DPLL by CRTC in atomic state
- * @dpll: dpll in use by @crtc
- * @crtc: crtc
+ * intel_update_active_dpll - update the active DPLL for a CRTC/encoder
  * @state: atomic state
+ * @crtc: the CRTC for which to update the active DPLL
+ * @encoder: encoder determining the type of port DPLL
  *
- * This function releases the reference from @crtc to @dpll from the
- * atomic @state. The new configuration is made effective by calling
- * intel_shared_dpll_swap_state().
+ * Update the active DPLL for the given @crtc/@encoder in @crtc's atomic state,
+ * from the port DPLLs reserved previously by intel_reserve_shared_dplls(). The
+ * DPLL selected will be based on the current mode of the encoder's port.
  */
-void intel_release_shared_dpll(struct intel_shared_dpll *dpll,
-                              struct intel_crtc *crtc,
-                              struct drm_atomic_state *state)
+void intel_update_active_dpll(struct intel_atomic_state *state,
+                             struct intel_crtc *crtc,
+                             struct intel_encoder *encoder)
 {
-       struct intel_shared_dpll_state *shared_dpll_state;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
+
+       if (WARN_ON(!dpll_mgr))
+               return;
 
-       shared_dpll_state = intel_atomic_get_shared_dpll_state(state);
-       shared_dpll_state[dpll->info->id].crtc_mask &= ~(1 << crtc->pipe);
+       dpll_mgr->update_active_dpll(state, crtc, encoder);
 }
 
 /**
index d0570414f3d1304123673ba08d04c4b471ef6fa8..4c2c5e93aff33afe36772d4947e544aae0346caa 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 
 #include "intel_display.h"
+#include "intel_wakeref.h"
 
 /*FIXME: Move this to a more appropriate place. */
 #define abs_diff(a, b) ({                      \
@@ -39,6 +40,7 @@
 struct drm_atomic_state;
 struct drm_device;
 struct drm_i915_private;
+struct intel_atomic_state;
 struct intel_crtc;
 struct intel_crtc_state;
 struct intel_encoder;
@@ -117,6 +119,10 @@ enum intel_dpll_id {
         * @DPLL_ID_ICL_DPLL1: ICL combo PHY DPLL1
         */
        DPLL_ID_ICL_DPLL1 = 1,
+       /**
+        * @DPLL_ID_EHL_DPLL4: EHL combo PHY DPLL4
+        */
+       DPLL_ID_EHL_DPLL4 = 2,
        /**
         * @DPLL_ID_ICL_TBTPLL: ICL TBT PLL
         */
@@ -140,6 +146,13 @@ enum intel_dpll_id {
 };
 #define I915_NUM_PLLS 7
 
+enum icl_port_dpll_id {
+       ICL_PORT_DPLL_DEFAULT,
+       ICL_PORT_DPLL_MG_PHY,
+
+       ICL_PORT_DPLL_COUNT,
+};
+
 struct intel_dpll_hw_state {
        /* i9xx, pch plls */
        u32 dpll;
@@ -195,7 +208,7 @@ struct intel_dpll_hw_state {
  * future state which would be applied by an atomic mode set (stored in
  * a struct &intel_atomic_state).
  *
- * See also intel_get_shared_dpll() and intel_release_shared_dpll().
+ * See also intel_reserve_shared_dplls() and intel_release_shared_dplls().
  */
 struct intel_shared_dpll_state {
        /**
@@ -312,6 +325,7 @@ struct intel_shared_dpll {
         * @info: platform specific info
         */
        const struct dpll_info *info;
+       intel_wakeref_t wakeref;
 };
 
 #define SKL_DPLL0 0
@@ -331,11 +345,16 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
                        bool state);
 #define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
 #define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc_state *state,
-                                               struct intel_encoder *encoder);
-void intel_release_shared_dpll(struct intel_shared_dpll *dpll,
-                              struct intel_crtc *crtc,
-                              struct drm_atomic_state *state);
+bool intel_reserve_shared_dplls(struct intel_atomic_state *state,
+                               struct intel_crtc *crtc,
+                               struct intel_encoder *encoder);
+void intel_release_shared_dplls(struct intel_atomic_state *state,
+                               struct intel_crtc *crtc);
+void icl_set_active_port_dpll(struct intel_crtc_state *crtc_state,
+                             enum icl_port_dpll_id port_dpll_id);
+void intel_update_active_dpll(struct intel_atomic_state *state,
+                             struct intel_crtc *crtc,
+                             struct intel_encoder *encoder);
 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);
index bc3a94d491c4d0992b24346d011840318ade13d2..a78139f9e847630f906e266067f9b5d3975459e3 100644 (file)
@@ -523,12 +523,16 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector)
         * authentication.
         */
        num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
-       if (num_downstream == 0)
+       if (num_downstream == 0) {
+               DRM_DEBUG_KMS("Repeater with zero downstream devices\n");
                return -EINVAL;
+       }
 
        ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
-       if (!ksv_fifo)
+       if (!ksv_fifo) {
+               DRM_DEBUG_KMS("Out of mem: ksv_fifo\n");
                return -ENOMEM;
+       }
 
        ret = shim->read_ksv_fifo(intel_dig_port, num_downstream, ksv_fifo);
        if (ret)
@@ -1206,8 +1210,10 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector)
        if (ret < 0)
                return ret;
 
-       if (msgs.send_cert.rx_caps[0] != HDCP_2_2_RX_CAPS_VERSION_VAL)
+       if (msgs.send_cert.rx_caps[0] != HDCP_2_2_RX_CAPS_VERSION_VAL) {
+               DRM_DEBUG_KMS("cert.rx_caps dont claim HDCP2.2\n");
                return -EINVAL;
+       }
 
        hdcp->is_repeater = HDCP_2_2_RX_REPEATER(msgs.send_cert.rx_caps[2]);
 
index 21339b7f6a3e9209813d464a8b724f059faaa4a6..07929726b780c98a53e79858dbc188dfb919cf1e 100644 (file)
@@ -175,6 +175,7 @@ struct overlay_registers {
 
 struct intel_overlay {
        struct drm_i915_private *i915;
+       struct intel_context *context;
        struct intel_crtc *crtc;
        struct i915_vma *vma;
        struct i915_vma *old_vma;
@@ -239,9 +240,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
 
 static struct i915_request *alloc_request(struct intel_overlay *overlay)
 {
-       struct intel_engine_cs *engine = overlay->i915->engine[RCS0];
-
-       return i915_request_create(engine->kernel_context);
+       return i915_request_create(overlay->context);
 }
 
 /* overlay needs to be disable in OCMD reg */
@@ -1359,11 +1358,16 @@ void intel_overlay_setup(struct drm_i915_private *dev_priv)
        if (!HAS_OVERLAY(dev_priv))
                return;
 
+       if (!HAS_ENGINE(dev_priv, RCS0))
+               return;
+
        overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
        if (!overlay)
                return;
 
        overlay->i915 = dev_priv;
+       overlay->context = dev_priv->engine[RCS0]->kernel_context;
+       GEM_BUG_ON(!overlay->context);
 
        overlay->color_key = 0x0101fe;
        overlay->color_key_enabled = true;
index 1e2c4307d05a392245f60b28e1592da5b1dc4860..9a48f7a01e7ee0126816f154280abd4d3015171d 100644 (file)
@@ -667,5 +667,5 @@ void intel_crtc_disable_pipe_crc(struct intel_crtc *intel_crtc)
 
        I915_WRITE(PIPE_CRC_CTL(crtc->index), 0);
        POSTING_READ(PIPE_CRC_CTL(crtc->index));
-       synchronize_irq(dev_priv->drm.irq);
+       intel_synchronize_irq(dev_priv);
 }
index ceda03e5a3d4e0e50de7850fa155f13c7b464d34..3fe8eaef6bd89ab8ef8253526ff32e92f3a799b5 100644 (file)
@@ -274,130 +274,145 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
        return false;
 }
 
-#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
+#define SDVO_CMD_NAME_ENTRY(cmd_) { .cmd = SDVO_CMD_ ## cmd_, .name = #cmd_ }
+
 /** Mapping of command numbers to names, for debug output */
-static const struct _sdvo_cmd_name {
+static const struct {
        u8 cmd;
        const char *name;
 } __attribute__ ((packed)) sdvo_cmd_names[] = {
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POWER_STATE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DISPLAY_POWER_STATE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),
+       SDVO_CMD_NAME_ENTRY(RESET),
+       SDVO_CMD_NAME_ENTRY(GET_DEVICE_CAPS),
+       SDVO_CMD_NAME_ENTRY(GET_FIRMWARE_REV),
+       SDVO_CMD_NAME_ENTRY(GET_TRAINED_INPUTS),
+       SDVO_CMD_NAME_ENTRY(GET_ACTIVE_OUTPUTS),
+       SDVO_CMD_NAME_ENTRY(SET_ACTIVE_OUTPUTS),
+       SDVO_CMD_NAME_ENTRY(GET_IN_OUT_MAP),
+       SDVO_CMD_NAME_ENTRY(SET_IN_OUT_MAP),
+       SDVO_CMD_NAME_ENTRY(GET_ATTACHED_DISPLAYS),
+       SDVO_CMD_NAME_ENTRY(GET_HOT_PLUG_SUPPORT),
+       SDVO_CMD_NAME_ENTRY(SET_ACTIVE_HOT_PLUG),
+       SDVO_CMD_NAME_ENTRY(GET_ACTIVE_HOT_PLUG),
+       SDVO_CMD_NAME_ENTRY(GET_INTERRUPT_EVENT_SOURCE),
+       SDVO_CMD_NAME_ENTRY(SET_TARGET_INPUT),
+       SDVO_CMD_NAME_ENTRY(SET_TARGET_OUTPUT),
+       SDVO_CMD_NAME_ENTRY(GET_INPUT_TIMINGS_PART1),
+       SDVO_CMD_NAME_ENTRY(GET_INPUT_TIMINGS_PART2),
+       SDVO_CMD_NAME_ENTRY(SET_INPUT_TIMINGS_PART1),
+       SDVO_CMD_NAME_ENTRY(SET_INPUT_TIMINGS_PART2),
+       SDVO_CMD_NAME_ENTRY(SET_OUTPUT_TIMINGS_PART1),
+       SDVO_CMD_NAME_ENTRY(SET_OUTPUT_TIMINGS_PART2),
+       SDVO_CMD_NAME_ENTRY(GET_OUTPUT_TIMINGS_PART1),
+       SDVO_CMD_NAME_ENTRY(GET_OUTPUT_TIMINGS_PART2),
+       SDVO_CMD_NAME_ENTRY(CREATE_PREFERRED_INPUT_TIMING),
+       SDVO_CMD_NAME_ENTRY(GET_PREFERRED_INPUT_TIMING_PART1),
+       SDVO_CMD_NAME_ENTRY(GET_PREFERRED_INPUT_TIMING_PART2),
+       SDVO_CMD_NAME_ENTRY(GET_INPUT_PIXEL_CLOCK_RANGE),
+       SDVO_CMD_NAME_ENTRY(GET_OUTPUT_PIXEL_CLOCK_RANGE),
+       SDVO_CMD_NAME_ENTRY(GET_SUPPORTED_CLOCK_RATE_MULTS),
+       SDVO_CMD_NAME_ENTRY(GET_CLOCK_RATE_MULT),
+       SDVO_CMD_NAME_ENTRY(SET_CLOCK_RATE_MULT),
+       SDVO_CMD_NAME_ENTRY(GET_SUPPORTED_TV_FORMATS),
+       SDVO_CMD_NAME_ENTRY(GET_TV_FORMAT),
+       SDVO_CMD_NAME_ENTRY(SET_TV_FORMAT),
+       SDVO_CMD_NAME_ENTRY(GET_SUPPORTED_POWER_STATES),
+       SDVO_CMD_NAME_ENTRY(GET_POWER_STATE),
+       SDVO_CMD_NAME_ENTRY(SET_ENCODER_POWER_STATE),
+       SDVO_CMD_NAME_ENTRY(SET_DISPLAY_POWER_STATE),
+       SDVO_CMD_NAME_ENTRY(SET_CONTROL_BUS_SWITCH),
+       SDVO_CMD_NAME_ENTRY(GET_SDTV_RESOLUTION_SUPPORT),
+       SDVO_CMD_NAME_ENTRY(GET_SCALED_HDTV_RESOLUTION_SUPPORT),
+       SDVO_CMD_NAME_ENTRY(GET_SUPPORTED_ENHANCEMENTS),
 
        /* Add the op code for SDVO enhancements */
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HUE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HUE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HUE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_CONTRAST),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CONTRAST),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTRAST),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_BRIGHTNESS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_BRIGHTNESS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_BRIGHTNESS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_H),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_H),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_H),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_HPOS),
+       SDVO_CMD_NAME_ENTRY(GET_HPOS),
+       SDVO_CMD_NAME_ENTRY(SET_HPOS),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_VPOS),
+       SDVO_CMD_NAME_ENTRY(GET_VPOS),
+       SDVO_CMD_NAME_ENTRY(SET_VPOS),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_SATURATION),
+       SDVO_CMD_NAME_ENTRY(GET_SATURATION),
+       SDVO_CMD_NAME_ENTRY(SET_SATURATION),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_HUE),
+       SDVO_CMD_NAME_ENTRY(GET_HUE),
+       SDVO_CMD_NAME_ENTRY(SET_HUE),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_CONTRAST),
+       SDVO_CMD_NAME_ENTRY(GET_CONTRAST),
+       SDVO_CMD_NAME_ENTRY(SET_CONTRAST),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_BRIGHTNESS),
+       SDVO_CMD_NAME_ENTRY(GET_BRIGHTNESS),
+       SDVO_CMD_NAME_ENTRY(SET_BRIGHTNESS),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_OVERSCAN_H),
+       SDVO_CMD_NAME_ENTRY(GET_OVERSCAN_H),
+       SDVO_CMD_NAME_ENTRY(SET_OVERSCAN_H),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_OVERSCAN_V),
+       SDVO_CMD_NAME_ENTRY(GET_OVERSCAN_V),
+       SDVO_CMD_NAME_ENTRY(SET_OVERSCAN_V),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_FLICKER_FILTER),
+       SDVO_CMD_NAME_ENTRY(GET_FLICKER_FILTER),
+       SDVO_CMD_NAME_ENTRY(SET_FLICKER_FILTER),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_FLICKER_FILTER_ADAPTIVE),
+       SDVO_CMD_NAME_ENTRY(GET_FLICKER_FILTER_ADAPTIVE),
+       SDVO_CMD_NAME_ENTRY(SET_FLICKER_FILTER_ADAPTIVE),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_FLICKER_FILTER_2D),
+       SDVO_CMD_NAME_ENTRY(GET_FLICKER_FILTER_2D),
+       SDVO_CMD_NAME_ENTRY(SET_FLICKER_FILTER_2D),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_SHARPNESS),
+       SDVO_CMD_NAME_ENTRY(GET_SHARPNESS),
+       SDVO_CMD_NAME_ENTRY(SET_SHARPNESS),
+       SDVO_CMD_NAME_ENTRY(GET_DOT_CRAWL),
+       SDVO_CMD_NAME_ENTRY(SET_DOT_CRAWL),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_TV_CHROMA_FILTER),
+       SDVO_CMD_NAME_ENTRY(GET_TV_CHROMA_FILTER),
+       SDVO_CMD_NAME_ENTRY(SET_TV_CHROMA_FILTER),
+       SDVO_CMD_NAME_ENTRY(GET_MAX_TV_LUMA_FILTER),
+       SDVO_CMD_NAME_ENTRY(GET_TV_LUMA_FILTER),
+       SDVO_CMD_NAME_ENTRY(SET_TV_LUMA_FILTER),
 
        /* HDMI op code */
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_PIXEL_REPLI),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_COLORIMETRY),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_AUDIO_STAT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_AV_SPLIT),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_TXRATE),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_DATA),
-       SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
+       SDVO_CMD_NAME_ENTRY(GET_SUPP_ENCODE),
+       SDVO_CMD_NAME_ENTRY(GET_ENCODE),
+       SDVO_CMD_NAME_ENTRY(SET_ENCODE),
+       SDVO_CMD_NAME_ENTRY(SET_PIXEL_REPLI),
+       SDVO_CMD_NAME_ENTRY(GET_PIXEL_REPLI),
+       SDVO_CMD_NAME_ENTRY(GET_COLORIMETRY_CAP),
+       SDVO_CMD_NAME_ENTRY(SET_COLORIMETRY),
+       SDVO_CMD_NAME_ENTRY(GET_COLORIMETRY),
+       SDVO_CMD_NAME_ENTRY(GET_AUDIO_ENCRYPT_PREFER),
+       SDVO_CMD_NAME_ENTRY(SET_AUDIO_STAT),
+       SDVO_CMD_NAME_ENTRY(GET_AUDIO_STAT),
+       SDVO_CMD_NAME_ENTRY(GET_HBUF_INDEX),
+       SDVO_CMD_NAME_ENTRY(SET_HBUF_INDEX),
+       SDVO_CMD_NAME_ENTRY(GET_HBUF_INFO),
+       SDVO_CMD_NAME_ENTRY(GET_HBUF_AV_SPLIT),
+       SDVO_CMD_NAME_ENTRY(SET_HBUF_AV_SPLIT),
+       SDVO_CMD_NAME_ENTRY(GET_HBUF_TXRATE),
+       SDVO_CMD_NAME_ENTRY(SET_HBUF_TXRATE),
+       SDVO_CMD_NAME_ENTRY(SET_HBUF_DATA),
+       SDVO_CMD_NAME_ENTRY(GET_HBUF_DATA),
 };
 
+#undef SDVO_CMD_NAME_ENTRY
+
+static const char *sdvo_cmd_name(u8 cmd)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {
+               if (cmd == sdvo_cmd_names[i].cmd)
+                       return sdvo_cmd_names[i].name;
+       }
+
+       return NULL;
+}
+
 #define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC")
 
 static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
                                   const void *args, int args_len)
 {
+       const char *cmd_name;
        int i, pos = 0;
 #define BUF_LEN 256
        char buffer[BUF_LEN];
@@ -412,15 +427,12 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
        for (; i < 8; i++) {
                BUF_PRINT("   ");
        }
-       for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {
-               if (cmd == sdvo_cmd_names[i].cmd) {
-                       BUF_PRINT("(%s)", sdvo_cmd_names[i].name);
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(sdvo_cmd_names)) {
+
+       cmd_name = sdvo_cmd_name(cmd);
+       if (cmd_name)
+               BUF_PRINT("(%s)", cmd_name);
+       else
                BUF_PRINT("(%02X)", cmd);
-       }
        BUG_ON(pos >= BUF_LEN - 1);
 #undef BUF_PRINT
 #undef BUF_LEN
@@ -429,15 +441,23 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
 }
 
 static const char * const cmd_status_names[] = {
-       "Power on",
-       "Success",
-       "Not supported",
-       "Invalid arg",
-       "Pending",
-       "Target not specified",
-       "Scaling not supported"
+       [SDVO_CMD_STATUS_POWER_ON] = "Power on",
+       [SDVO_CMD_STATUS_SUCCESS] = "Success",
+       [SDVO_CMD_STATUS_NOTSUPP] = "Not supported",
+       [SDVO_CMD_STATUS_INVALID_ARG] = "Invalid arg",
+       [SDVO_CMD_STATUS_PENDING] = "Pending",
+       [SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED] = "Target not specified",
+       [SDVO_CMD_STATUS_SCALING_NOT_SUPP] = "Scaling not supported",
 };
 
+static const char *sdvo_cmd_status(u8 status)
+{
+       if (status < ARRAY_SIZE(cmd_status_names))
+               return cmd_status_names[status];
+       else
+               return NULL;
+}
+
 static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
                                   const void *args, int args_len,
                                   bool unlocked)
@@ -516,6 +536,7 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
 static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
                                     void *response, int response_len)
 {
+       const char *cmd_status;
        u8 retry = 15; /* 5 quick checks, followed by 10 long checks */
        u8 status;
        int i, pos = 0;
@@ -562,8 +583,9 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
 #define BUF_PRINT(args...) \
        pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args)
 
-       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               BUF_PRINT("(%s)", cmd_status_names[status]);
+       cmd_status = sdvo_cmd_status(status);
+       if (cmd_status)
+               BUF_PRINT("(%s)", cmd_status);
        else
                BUF_PRINT("(??? %d)", status);
 
index 004b52027ae8997a140f7fce071e411bfb52b2d4..5e5ea867aae95231702fba2b886328ecaebf7652 100644 (file)
@@ -441,9 +441,21 @@ icl_program_input_csc(struct intel_plane *plane,
                 */
                [DRM_COLOR_YCBCR_BT709] = {
                        0x7C98, 0x7800, 0x0,
-                       0x9EF8, 0x7800, 0xABF8,
+                       0x9EF8, 0x7800, 0xAC00,
                        0x0, 0x7800,  0x7ED8,
                },
+               /*
+                * BT.2020 full range YCbCr -> full range RGB
+                * The matrix required is :
+                * [1.000, 0.000, 1.474,
+                *  1.000, -0.1645, -0.5713,
+                *  1.000, 1.8814, 0.0000]
+                */
+               [DRM_COLOR_YCBCR_BT2020] = {
+                       0x7BC8, 0x7800, 0x0,
+                       0x8928, 0x7800, 0xAA88,
+                       0x0, 0x7800, 0x7F10,
+               },
        };
 
        /* Matrix for Limited Range to Full Range Conversion */
@@ -451,26 +463,38 @@ icl_program_input_csc(struct intel_plane *plane,
                /*
                 * BT.601 Limted range YCbCr -> full range RGB
                 * The matrix required is :
-                * [1.164384, 0.000, 1.596370,
-                *  1.138393, -0.382500, -0.794598,
-                *  1.138393, 1.971696, 0.0000]
+                * [1.164384, 0.000, 1.596027,
+                *  1.164384, -0.39175, -0.812813,
+                *  1.164384, 2.017232, 0.0000]
                 */
                [DRM_COLOR_YCBCR_BT601] = {
                        0x7CC8, 0x7950, 0x0,
-                       0x8CB8, 0x7918, 0x9C40,
-                       0x0, 0x7918, 0x7FC8,
+                       0x8D00, 0x7950, 0x9C88,
+                       0x0, 0x7950, 0x6810,
                },
                /*
                 * BT.709 Limited range YCbCr -> full range RGB
                 * The matrix required is :
-                * [1.164, 0.000, 1.833671,
-                *  1.138393, -0.213249, -0.532909,
-                *  1.138393, 2.112402, 0.0000]
+                * [1.164384, 0.000, 1.792741,
+                *  1.164384, -0.213249, -0.532909,
+                *  1.164384, 2.112402, 0.0000]
                 */
                [DRM_COLOR_YCBCR_BT709] = {
-                       0x7EA8, 0x7950, 0x0,
-                       0x8888, 0x7918, 0xADA8,
-                       0x0, 0x7918,  0x6870,
+                       0x7E58, 0x7950, 0x0,
+                       0x8888, 0x7950, 0xADA8,
+                       0x0, 0x7950,  0x6870,
+               },
+               /*
+                * BT.2020 Limited range YCbCr -> full range RGB
+                * The matrix required is :
+                * [1.164, 0.000, 1.678,
+                *  1.164, -0.1873, -0.6504,
+                *  1.164, 2.1417, 0.0000]
+                */
+               [DRM_COLOR_YCBCR_BT2020] = {
+                       0x7D70, 0x7950, 0x0,
+                       0x8A68, 0x7950, 0xAC00,
+                       0x0, 0x7950, 0x6890,
                },
        };
        const u16 *csc;
@@ -492,8 +516,11 @@ icl_program_input_csc(struct intel_plane *plane,
 
        I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
                      PREOFF_YUV_TO_RGB_HI);
-       I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
-                     PREOFF_YUV_TO_RGB_ME);
+       if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
+               I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), 0);
+       else
+               I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
+                             PREOFF_YUV_TO_RGB_ME);
        I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
                      PREOFF_YUV_TO_RGB_LO);
        I915_WRITE_FW(PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0);
@@ -683,6 +710,16 @@ skl_plane_get_hw_state(struct intel_plane *plane,
        return ret;
 }
 
+static void i9xx_plane_linear_gamma(u16 gamma[8])
+{
+       /* The points are not evenly spaced. */
+       static const u8 in[8] = { 0, 1, 2, 4, 8, 16, 24, 32 };
+       int i;
+
+       for (i = 0; i < 8; i++)
+               gamma[i] = (in[i] << 8) / 32;
+}
+
 static void
 chv_update_csc(const struct intel_plane_state *plane_state)
 {
@@ -858,6 +895,31 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
        return sprctl;
 }
 
+static void vlv_update_gamma(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       enum pipe pipe = plane->pipe;
+       enum plane_id plane_id = plane->id;
+       u16 gamma[8];
+       int i;
+
+       /* Seems RGB data bypasses the gamma always */
+       if (!fb->format->is_yuv)
+               return;
+
+       i9xx_plane_linear_gamma(gamma);
+
+       /* FIXME these register are single buffered :( */
+       /* The two end points are implicit (0.0 and 1.0) */
+       for (i = 1; i < 8 - 1; i++)
+               I915_WRITE_FW(SPGAMC(pipe, plane_id, i - 1),
+                             gamma[i] << 16 |
+                             gamma[i] << 8 |
+                             gamma[i]);
+}
+
 static void
 vlv_update_plane(struct intel_plane *plane,
                 const struct intel_crtc_state *crtc_state,
@@ -916,6 +978,7 @@ vlv_update_plane(struct intel_plane *plane,
                      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
 
        vlv_update_clrc(plane_state);
+       vlv_update_gamma(plane_state);
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
@@ -1013,6 +1076,8 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
                return 0;
        }
 
+       sprctl |= SPRITE_INT_GAMMA_DISABLE;
+
        if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
                sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709;
 
@@ -1033,6 +1098,45 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
        return sprctl;
 }
 
+static void ivb_sprite_linear_gamma(u16 gamma[18])
+{
+       int i;
+
+       for (i = 0; i < 17; i++)
+               gamma[i] = (i << 10) / 16;
+
+       gamma[i] = 3 << 10;
+       i++;
+}
+
+static void ivb_update_gamma(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       enum pipe pipe = plane->pipe;
+       u16 gamma[18];
+       int i;
+
+       ivb_sprite_linear_gamma(gamma);
+
+       /* FIXME these register are single buffered :( */
+       for (i = 0; i < 16; i++)
+               I915_WRITE_FW(SPRGAMC(pipe, i),
+                             gamma[i] << 20 |
+                             gamma[i] << 10 |
+                             gamma[i]);
+
+       I915_WRITE_FW(SPRGAMC16(pipe, 0), gamma[i]);
+       I915_WRITE_FW(SPRGAMC16(pipe, 1), gamma[i]);
+       I915_WRITE_FW(SPRGAMC16(pipe, 2), gamma[i]);
+       i++;
+
+       I915_WRITE_FW(SPRGAMC17(pipe, 0), gamma[i]);
+       I915_WRITE_FW(SPRGAMC17(pipe, 1), gamma[i]);
+       I915_WRITE_FW(SPRGAMC17(pipe, 2), gamma[i]);
+       i++;
+}
+
 static void
 ivb_update_plane(struct intel_plane *plane,
                 const struct intel_crtc_state *crtc_state,
@@ -1099,6 +1203,8 @@ ivb_update_plane(struct intel_plane *plane,
        I915_WRITE_FW(SPRSURF(pipe),
                      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
 
+       ivb_update_gamma(plane_state);
+
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
@@ -1224,6 +1330,66 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
        return dvscntr;
 }
 
+static void g4x_update_gamma(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       enum pipe pipe = plane->pipe;
+       u16 gamma[8];
+       int i;
+
+       /* Seems RGB data bypasses the gamma always */
+       if (!fb->format->is_yuv)
+               return;
+
+       i9xx_plane_