drm/i915: move modesetting output/encoder code under display/
authorJani Nikula <jani.nikula@intel.com>
Thu, 13 Jun 2019 08:44:15 +0000 (11:44 +0300)
committerJani Nikula <jani.nikula@intel.com>
Mon, 17 Jun 2019 08:25:06 +0000 (11:25 +0300)
Add a new subdirectory for display code, and start off by moving
modesetting output/encoder code. Judging by the include changes, this is
a surprisingly clean operation.

v2:
- move intel_sdvo_regs.h too
- use tabs for Makefile file lists and sort them

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Acked-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190613084416.6794-2-jani.nikula@intel.com
107 files changed:
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/Makefile.header-test
drivers/gpu/drm/i915/display/Makefile [new file with mode: 0644]
drivers/gpu/drm/i915/display/Makefile.header-test [new file with mode: 0644]
drivers/gpu/drm/i915/display/dvo_ch7017.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/dvo_ch7xxx.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/dvo_ivch.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/dvo_ns2501.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/dvo_sil164.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/dvo_tfp410.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/icl_dsi.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_crt.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_crt.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_ddi.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_ddi.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp_aux_backlight.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp_link_training.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp_link_training.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp_mst.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dp_mst.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dsi.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dsi.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dsi_vbt.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dvo.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dvo.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dvo_dev.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_gmbus.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_gmbus.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_hdmi.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_hdmi.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_lspcon.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_lspcon.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_lvds.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_lvds.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_panel.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_panel.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_sdvo.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_sdvo.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_sdvo_regs.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_tv.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_tv.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_vdsc.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_vdsc.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/vlv_dsi.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/vlv_dsi_pll.c [new file with mode: 0644]
drivers/gpu/drm/i915/dvo_ch7017.c [deleted file]
drivers/gpu/drm/i915/dvo_ch7xxx.c [deleted file]
drivers/gpu/drm/i915/dvo_ivch.c [deleted file]
drivers/gpu/drm/i915/dvo_ns2501.c [deleted file]
drivers/gpu/drm/i915/dvo_sil164.c [deleted file]
drivers/gpu/drm/i915/dvo_tfp410.c [deleted file]
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/icl_dsi.c [deleted file]
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_connector.c
drivers/gpu/drm/i915/intel_crt.c [deleted file]
drivers/gpu/drm/i915/intel_crt.h [deleted file]
drivers/gpu/drm/i915/intel_ddi.c [deleted file]
drivers/gpu/drm/i915/intel_ddi.h [deleted file]
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_display_power.c
drivers/gpu/drm/i915/intel_dp.c [deleted file]
drivers/gpu/drm/i915/intel_dp.h [deleted file]
drivers/gpu/drm/i915/intel_dp_aux_backlight.c [deleted file]
drivers/gpu/drm/i915/intel_dp_aux_backlight.h [deleted file]
drivers/gpu/drm/i915/intel_dp_link_training.c [deleted file]
drivers/gpu/drm/i915/intel_dp_link_training.h [deleted file]
drivers/gpu/drm/i915/intel_dp_mst.c [deleted file]
drivers/gpu/drm/i915/intel_dp_mst.h [deleted file]
drivers/gpu/drm/i915/intel_dpio_phy.c
drivers/gpu/drm/i915/intel_dsi.c [deleted file]
drivers/gpu/drm/i915/intel_dsi.h [deleted file]
drivers/gpu/drm/i915/intel_dsi_dcs_backlight.c [deleted file]
drivers/gpu/drm/i915/intel_dsi_dcs_backlight.h [deleted file]
drivers/gpu/drm/i915/intel_dsi_vbt.c [deleted file]
drivers/gpu/drm/i915/intel_dvo.c [deleted file]
drivers/gpu/drm/i915/intel_dvo.h [deleted file]
drivers/gpu/drm/i915/intel_dvo_dev.h [deleted file]
drivers/gpu/drm/i915/intel_frontbuffer.c
drivers/gpu/drm/i915/intel_gmbus.c [deleted file]
drivers/gpu/drm/i915/intel_gmbus.h [deleted file]
drivers/gpu/drm/i915/intel_hdmi.c [deleted file]
drivers/gpu/drm/i915/intel_hdmi.h [deleted file]
drivers/gpu/drm/i915/intel_lspcon.c [deleted file]
drivers/gpu/drm/i915/intel_lspcon.h [deleted file]
drivers/gpu/drm/i915/intel_lvds.c [deleted file]
drivers/gpu/drm/i915/intel_lvds.h [deleted file]
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c [deleted file]
drivers/gpu/drm/i915/intel_panel.h [deleted file]
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_sdvo.c [deleted file]
drivers/gpu/drm/i915/intel_sdvo.h [deleted file]
drivers/gpu/drm/i915/intel_sdvo_regs.h [deleted file]
drivers/gpu/drm/i915/intel_tv.c [deleted file]
drivers/gpu/drm/i915/intel_tv.h [deleted file]
drivers/gpu/drm/i915/intel_vdsc.c [deleted file]
drivers/gpu/drm/i915/intel_vdsc.h [deleted file]
drivers/gpu/drm/i915/vlv_dsi.c [deleted file]
drivers/gpu/drm/i915/vlv_dsi_pll.c [deleted file]

index c0a7b2994077739774afedd3bbbad001112073d3..649f286887b7d8b3698057b1f900e08ea6e61e73 100644 (file)
@@ -176,33 +176,35 @@ i915-$(CONFIG_ACPI)               += intel_acpi.o intel_opregion.o
 i915-$(CONFIG_DRM_FBDEV_EMULATION)     += intel_fbdev.o
 
 # modesetting output/encoder code
-i915-y += dvo_ch7017.o \
-         dvo_ch7xxx.o \
-         dvo_ivch.o \
-         dvo_ns2501.o \
-         dvo_sil164.o \
-         dvo_tfp410.o \
-         icl_dsi.o \
-         intel_crt.o \
-         intel_ddi.o \
-         intel_dp_aux_backlight.o \
-         intel_dp_link_training.o \
-         intel_dp_mst.o \
-         intel_dp.o \
-         intel_dsi.o \
-         intel_dsi_dcs_backlight.o \
-         intel_dsi_vbt.o \
-         intel_dvo.o \
-         intel_gmbus.o \
-         intel_hdmi.o \
-         intel_lspcon.o \
-         intel_lvds.o \
-         intel_panel.o \
-         intel_sdvo.o \
-         intel_tv.o \
-         vlv_dsi.o \
-         vlv_dsi_pll.o \
-         intel_vdsc.o
+obj-y += display/
+i915-y += \
+       display/dvo_ch7017.o \
+       display/dvo_ch7xxx.o \
+       display/dvo_ivch.o \
+       display/dvo_ns2501.o \
+       display/dvo_sil164.o \
+       display/dvo_tfp410.o \
+       display/icl_dsi.o \
+       display/intel_crt.o \
+       display/intel_ddi.o \
+       display/intel_dp.o \
+       display/intel_dp_aux_backlight.o \
+       display/intel_dp_link_training.o \
+       display/intel_dp_mst.o \
+       display/intel_dsi.o \
+       display/intel_dsi_dcs_backlight.o \
+       display/intel_dsi_vbt.o \
+       display/intel_dvo.o \
+       display/intel_gmbus.o \
+       display/intel_hdmi.o \
+       display/intel_lspcon.o \
+       display/intel_lvds.o \
+       display/intel_panel.o \
+       display/intel_sdvo.o \
+       display/intel_tv.o \
+       display/intel_vdsc.o \
+       display/vlv_dsi.o \
+       display/vlv_dsi_pll.o
 
 # Post-mortem debug and GPU hang state capture
 i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
index c04297ce57b46758e0673532cb4aa4f41ef77803..5a04858c9b7bfeb693f78c62120ca040a0232486 100644 (file)
@@ -22,46 +22,27 @@ header_test := \
        intel_color.h \
        intel_combo_phy.h \
        intel_connector.h \
-       intel_crt.h \
        intel_csr.h \
-       intel_ddi.h \
        intel_display_power.h \
-       intel_dp.h \
-       intel_dp_aux_backlight.h \
-       intel_dp_link_training.h \
-       intel_dp_mst.h \
        intel_dpio_phy.h \
        intel_dpll_mgr.h \
        intel_drv.h \
-       intel_dsi.h \
-       intel_dsi_dcs_backlight.h \
-       intel_dvo.h \
-       intel_dvo_dev.h \
        intel_fbc.h \
        intel_fbdev.h \
        intel_fifo_underrun.h \
        intel_frontbuffer.h \
-       intel_gmbus.h \
        intel_hdcp.h \
-       intel_hdmi.h \
        intel_hotplug.h \
        intel_lpe_audio.h \
-       intel_lspcon.h \
-       intel_lvds.h \
        intel_overlay.h \
-       intel_panel.h \
        intel_pipe_crc.h \
        intel_pm.h \
        intel_psr.h \
        intel_quirks.h \
        intel_runtime_pm.h \
-       intel_sdvo.h \
-       intel_sdvo_regs.h \
        intel_sideband.h \
        intel_sprite.h \
-       intel_tv.h \
        intel_uncore.h \
-       intel_vdsc.h \
        intel_wakeref.h
 
 quiet_cmd_header_test = HDRTEST $@
diff --git a/drivers/gpu/drm/i915/display/Makefile b/drivers/gpu/drm/i915/display/Makefile
new file mode 100644 (file)
index 0000000..1c75b5c
--- /dev/null
@@ -0,0 +1,2 @@
+# Extra header tests
+include $(src)/Makefile.header-test
diff --git a/drivers/gpu/drm/i915/display/Makefile.header-test b/drivers/gpu/drm/i915/display/Makefile.header-test
new file mode 100644 (file)
index 0000000..61e06cb
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: MIT
+# Copyright © 2019 Intel Corporation
+
+# Test the headers are compilable as standalone units
+header_test := $(notdir $(wildcard $(src)/*.h))
+
+quiet_cmd_header_test = HDRTEST $@
+      cmd_header_test = echo "\#include \"$(<F)\"" > $@
+
+header_test_%.c: %.h
+       $(call cmd,header_test)
+
+extra-$(CONFIG_DRM_I915_WERROR) += \
+       $(foreach h,$(header_test),$(patsubst %.h,header_test_%.o,$(h)))
+
+clean-files += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.c,$(h)))
diff --git a/drivers/gpu/drm/i915/display/dvo_ch7017.c b/drivers/gpu/drm/i915/display/dvo_ch7017.c
new file mode 100644 (file)
index 0000000..602380f
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "intel_drv.h"
+#include "intel_dvo_dev.h"
+
+#define CH7017_TV_DISPLAY_MODE         0x00
+#define CH7017_FLICKER_FILTER          0x01
+#define CH7017_VIDEO_BANDWIDTH         0x02
+#define CH7017_TEXT_ENHANCEMENT                0x03
+#define CH7017_START_ACTIVE_VIDEO      0x04
+#define CH7017_HORIZONTAL_POSITION     0x05
+#define CH7017_VERTICAL_POSITION       0x06
+#define CH7017_BLACK_LEVEL             0x07
+#define CH7017_CONTRAST_ENHANCEMENT    0x08
+#define CH7017_TV_PLL                  0x09
+#define CH7017_TV_PLL_M                        0x0a
+#define CH7017_TV_PLL_N                        0x0b
+#define CH7017_SUB_CARRIER_0           0x0c
+#define CH7017_CIV_CONTROL             0x10
+#define CH7017_CIV_0                   0x11
+#define CH7017_CHROMA_BOOST            0x14
+#define CH7017_CLOCK_MODE              0x1c
+#define CH7017_INPUT_CLOCK             0x1d
+#define CH7017_GPIO_CONTROL            0x1e
+#define CH7017_INPUT_DATA_FORMAT       0x1f
+#define CH7017_CONNECTION_DETECT       0x20
+#define CH7017_DAC_CONTROL             0x21
+#define CH7017_BUFFERED_CLOCK_OUTPUT   0x22
+#define CH7017_DEFEAT_VSYNC            0x47
+#define CH7017_TEST_PATTERN            0x48
+
+#define CH7017_POWER_MANAGEMENT                0x49
+/** Enables the TV output path. */
+#define CH7017_TV_EN                   (1 << 0)
+#define CH7017_DAC0_POWER_DOWN         (1 << 1)
+#define CH7017_DAC1_POWER_DOWN         (1 << 2)
+#define CH7017_DAC2_POWER_DOWN         (1 << 3)
+#define CH7017_DAC3_POWER_DOWN         (1 << 4)
+/** Powers down the TV out block, and DAC0-3 */
+#define CH7017_TV_POWER_DOWN_EN                (1 << 5)
+
+#define CH7017_VERSION_ID              0x4a
+
+#define CH7017_DEVICE_ID               0x4b
+#define CH7017_DEVICE_ID_VALUE         0x1b
+#define CH7018_DEVICE_ID_VALUE         0x1a
+#define CH7019_DEVICE_ID_VALUE         0x19
+
+#define CH7017_XCLK_D2_ADJUST          0x53
+#define CH7017_UP_SCALER_COEFF_0       0x55
+#define CH7017_UP_SCALER_COEFF_1       0x56
+#define CH7017_UP_SCALER_COEFF_2       0x57
+#define CH7017_UP_SCALER_COEFF_3       0x58
+#define CH7017_UP_SCALER_COEFF_4       0x59
+#define CH7017_UP_SCALER_VERTICAL_INC_0        0x5a
+#define CH7017_UP_SCALER_VERTICAL_INC_1        0x5b
+#define CH7017_GPIO_INVERT             0x5c
+#define CH7017_UP_SCALER_HORIZONTAL_INC_0      0x5d
+#define CH7017_UP_SCALER_HORIZONTAL_INC_1      0x5e
+
+#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT   0x5f
+/**< Low bits of horizontal active pixel input */
+
+#define CH7017_ACTIVE_INPUT_LINE_OUTPUT        0x60
+/** High bits of horizontal active pixel input */
+#define CH7017_LVDS_HAP_INPUT_MASK     (0x7 << 0)
+/** High bits of vertical active line output */
+#define CH7017_LVDS_VAL_HIGH_MASK      (0x7 << 3)
+
+#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT     0x61
+/**< Low bits of vertical active line output */
+
+#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT  0x62
+/**< Low bits of horizontal active pixel output */
+
+#define CH7017_LVDS_POWER_DOWN         0x63
+/** High bits of horizontal active pixel output */
+#define CH7017_LVDS_HAP_HIGH_MASK      (0x7 << 0)
+/** Enables the LVDS power down state transition */
+#define CH7017_LVDS_POWER_DOWN_EN      (1 << 6)
+/** Enables the LVDS upscaler */
+#define CH7017_LVDS_UPSCALER_EN                (1 << 7)
+#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08
+
+#define CH7017_LVDS_ENCODING           0x64
+#define CH7017_LVDS_DITHER_2D          (1 << 2)
+#define CH7017_LVDS_DITHER_DIS         (1 << 3)
+#define CH7017_LVDS_DUAL_CHANNEL_EN    (1 << 4)
+#define CH7017_LVDS_24_BIT             (1 << 5)
+
+#define CH7017_LVDS_ENCODING_2         0x65
+
+#define CH7017_LVDS_PLL_CONTROL                0x66
+/** Enables the LVDS panel output path */
+#define CH7017_LVDS_PANEN              (1 << 0)
+/** Enables the LVDS panel backlight */
+#define CH7017_LVDS_BKLEN              (1 << 3)
+
+#define CH7017_POWER_SEQUENCING_T1     0x67
+#define CH7017_POWER_SEQUENCING_T2     0x68
+#define CH7017_POWER_SEQUENCING_T3     0x69
+#define CH7017_POWER_SEQUENCING_T4     0x6a
+#define CH7017_POWER_SEQUENCING_T5     0x6b
+#define CH7017_GPIO_DRIVER_TYPE                0x6c
+#define CH7017_GPIO_DATA               0x6d
+#define CH7017_GPIO_DIRECTION_CONTROL  0x6e
+
+#define CH7017_LVDS_PLL_FEEDBACK_DIV   0x71
+# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4
+# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0
+# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80
+
+#define CH7017_LVDS_PLL_VCO_CONTROL    0x72
+# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80
+# define CH7017_LVDS_PLL_VCO_SHIFT     4
+# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0
+
+#define CH7017_OUTPUTS_ENABLE          0x73
+# define CH7017_CHARGE_PUMP_LOW                0x0
+# define CH7017_CHARGE_PUMP_HIGH       0x3
+# define CH7017_LVDS_CHANNEL_A         (1 << 3)
+# define CH7017_LVDS_CHANNEL_B         (1 << 4)
+# define CH7017_TV_DAC_A               (1 << 5)
+# define CH7017_TV_DAC_B               (1 << 6)
+# define CH7017_DDC_SELECT_DC2         (1 << 7)
+
+#define CH7017_LVDS_OUTPUT_AMPLITUDE   0x74
+#define CH7017_LVDS_PLL_EMI_REDUCTION  0x75
+#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
+
+#define CH7017_LVDS_CONTROL_2          0x78
+# define CH7017_LOOP_FILTER_SHIFT      5
+# define CH7017_PHASE_DETECTOR_SHIFT   0
+
+#define CH7017_BANG_LIMIT_CONTROL      0x7f
+
+struct ch7017_priv {
+       u8 dummy;
+};
+
+static void ch7017_dump_regs(struct intel_dvo_device *dvo);
+static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable);
+
+static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
+{
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &addr,
+               },
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = val,
+               }
+       };
+       return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
+}
+
+static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
+{
+       u8 buf[2] = { addr, val };
+       struct i2c_msg msg = {
+               .addr = dvo->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = buf,
+       };
+       return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
+}
+
+/** Probes for a CH7017 on the given bus and slave address. */
+static bool ch7017_init(struct intel_dvo_device *dvo,
+                       struct i2c_adapter *adapter)
+{
+       struct ch7017_priv *priv;
+       const char *str;
+       u8 val;
+
+       priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return false;
+
+       dvo->i2c_bus = adapter;
+       dvo->dev_priv = priv;
+
+       if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
+               goto fail;
+
+       switch (val) {
+       case CH7017_DEVICE_ID_VALUE:
+               str = "ch7017";
+               break;
+       case CH7018_DEVICE_ID_VALUE:
+               str = "ch7018";
+               break;
+       case CH7019_DEVICE_ID_VALUE:
+               str = "ch7019";
+               break;
+       default:
+               DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
+                             "slave %d.\n",
+                             val, adapter->name, dvo->slave_addr);
+               goto fail;
+       }
+
+       DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
+                     str, adapter->name, dvo->slave_addr);
+       return true;
+
+fail:
+       kfree(priv);
+       return false;
+}
+
+static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
+{
+       return connector_status_connected;
+}
+
+static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       if (mode->clock > 160000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static void ch7017_mode_set(struct intel_dvo_device *dvo,
+                           const struct drm_display_mode *mode,
+                           const struct drm_display_mode *adjusted_mode)
+{
+       u8 lvds_pll_feedback_div, lvds_pll_vco_control;
+       u8 outputs_enable, lvds_control_2, lvds_power_down;
+       u8 horizontal_active_pixel_input;
+       u8 horizontal_active_pixel_output, vertical_active_line_output;
+       u8 active_input_line_output;
+
+       DRM_DEBUG_KMS("Registers before mode setting\n");
+       ch7017_dump_regs(dvo);
+
+       /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
+       if (mode->clock < 100000) {
+               outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW;
+               lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
+                       (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
+                       (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
+               lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
+                       (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
+                       (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
+               lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
+                       (0 << CH7017_PHASE_DETECTOR_SHIFT);
+       } else {
+               outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH;
+               lvds_pll_feedback_div =
+                       CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
+                       (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
+                       (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
+               lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
+                       (0 << CH7017_PHASE_DETECTOR_SHIFT);
+               if (1) { /* XXX: dual channel panel detection.  Assume yes for now. */
+                       outputs_enable |= CH7017_LVDS_CHANNEL_B;
+                       lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
+                               (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
+                               (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
+               } else {
+                       lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
+                               (1 << CH7017_LVDS_PLL_VCO_SHIFT) |
+                               (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
+               }
+       }
+
+       horizontal_active_pixel_input = mode->hdisplay & 0x00ff;
+
+       vertical_active_line_output = mode->vdisplay & 0x00ff;
+       horizontal_active_pixel_output = mode->hdisplay & 0x00ff;
+
+       active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) |
+                                  (((mode->vdisplay & 0x0700) >> 8) << 3);
+
+       lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
+                         (mode->hdisplay & 0x0700) >> 8;
+
+       ch7017_dpms(dvo, false);
+       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
+                       horizontal_active_pixel_input);
+       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
+                       horizontal_active_pixel_output);
+       ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
+                       vertical_active_line_output);
+       ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT,
+                       active_input_line_output);
+       ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
+       ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
+       ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2);
+       ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable);
+
+       /* Turn the LVDS back on with new settings. */
+       ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down);
+
+       DRM_DEBUG_KMS("Registers after mode setting\n");
+       ch7017_dump_regs(dvo);
+}
+
+/* set the CH7017 power state */
+static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
+{
+       u8 val;
+
+       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
+
+       /* Turn off TV/VGA, and never turn it on since we don't support it. */
+       ch7017_write(dvo, CH7017_POWER_MANAGEMENT,
+                       CH7017_DAC0_POWER_DOWN |
+                       CH7017_DAC1_POWER_DOWN |
+                       CH7017_DAC2_POWER_DOWN |
+                       CH7017_DAC3_POWER_DOWN |
+                       CH7017_TV_POWER_DOWN_EN);
+
+       if (enable) {
+               /* Turn on the LVDS */
+               ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
+                            val & ~CH7017_LVDS_POWER_DOWN_EN);
+       } else {
+               /* Turn off the LVDS */
+               ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
+                            val | CH7017_LVDS_POWER_DOWN_EN);
+       }
+
+       /* XXX: Should actually wait for update power status somehow */
+       msleep(20);
+}
+
+static bool ch7017_get_hw_state(struct intel_dvo_device *dvo)
+{
+       u8 val;
+
+       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
+
+       if (val & CH7017_LVDS_POWER_DOWN_EN)
+               return false;
+       else
+               return true;
+}
+
+static void ch7017_dump_regs(struct intel_dvo_device *dvo)
+{
+       u8 val;
+
+#define DUMP(reg)                                      \
+do {                                                   \
+       ch7017_read(dvo, reg, &val);                    \
+       DRM_DEBUG_KMS(#reg ": %02x\n", val);            \
+} while (0)
+
+       DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
+       DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
+       DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
+       DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT);
+       DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
+       DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
+       DUMP(CH7017_LVDS_CONTROL_2);
+       DUMP(CH7017_OUTPUTS_ENABLE);
+       DUMP(CH7017_LVDS_POWER_DOWN);
+}
+
+static void ch7017_destroy(struct intel_dvo_device *dvo)
+{
+       struct ch7017_priv *priv = dvo->dev_priv;
+
+       if (priv) {
+               kfree(priv);
+               dvo->dev_priv = NULL;
+       }
+}
+
+const struct intel_dvo_dev_ops ch7017_ops = {
+       .init = ch7017_init,
+       .detect = ch7017_detect,
+       .mode_valid = ch7017_mode_valid,
+       .mode_set = ch7017_mode_set,
+       .dpms = ch7017_dpms,
+       .get_hw_state = ch7017_get_hw_state,
+       .dump_regs = ch7017_dump_regs,
+       .destroy = ch7017_destroy,
+};
diff --git a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
new file mode 100644 (file)
index 0000000..e070beb
--- /dev/null
@@ -0,0 +1,367 @@
+/**************************************************************************
+
+Copyright © 2006 Dave Airlie
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include "intel_drv.h"
+#include "intel_dvo_dev.h"
+
+#define CH7xxx_REG_VID         0x4a
+#define CH7xxx_REG_DID         0x4b
+
+#define CH7011_VID             0x83 /* 7010 as well */
+#define CH7010B_VID            0x05
+#define CH7009A_VID            0x84
+#define CH7009B_VID            0x85
+#define CH7301_VID             0x95
+
+#define CH7xxx_VID             0x84
+#define CH7xxx_DID             0x17
+#define CH7010_DID             0x16
+
+#define CH7xxx_NUM_REGS                0x4c
+
+#define CH7xxx_CM              0x1c
+#define CH7xxx_CM_XCM          (1<<0)
+#define CH7xxx_CM_MCP          (1<<2)
+#define CH7xxx_INPUT_CLOCK     0x1d
+#define CH7xxx_GPIO            0x1e
+#define CH7xxx_GPIO_HPIR       (1<<3)
+#define CH7xxx_IDF             0x1f
+
+#define CH7xxx_IDF_HSP         (1<<3)
+#define CH7xxx_IDF_VSP         (1<<4)
+
+#define CH7xxx_CONNECTION_DETECT 0x20
+#define CH7xxx_CDET_DVI                (1<<5)
+
+#define CH7301_DAC_CNTL                0x21
+#define CH7301_HOTPLUG         0x23
+#define CH7xxx_TCTL            0x31
+#define CH7xxx_TVCO            0x32
+#define CH7xxx_TPCP            0x33
+#define CH7xxx_TPD             0x34
+#define CH7xxx_TPVT            0x35
+#define CH7xxx_TLPF            0x36
+#define CH7xxx_TCT             0x37
+#define CH7301_TEST_PATTERN    0x48
+
+#define CH7xxx_PM              0x49
+#define CH7xxx_PM_FPD          (1<<0)
+#define CH7301_PM_DACPD0       (1<<1)
+#define CH7301_PM_DACPD1       (1<<2)
+#define CH7301_PM_DACPD2       (1<<3)
+#define CH7xxx_PM_DVIL         (1<<6)
+#define CH7xxx_PM_DVIP         (1<<7)
+
+#define CH7301_SYNC_POLARITY   0x56
+#define CH7301_SYNC_RGB_YUV    (1<<0)
+#define CH7301_SYNC_POL_DVI    (1<<5)
+
+/** @file
+ * driver for the Chrontel 7xxx DVI chip over DVO.
+ */
+
+static struct ch7xxx_id_struct {
+       u8 vid;
+       char *name;
+} ch7xxx_ids[] = {
+       { CH7011_VID, "CH7011" },
+       { CH7010B_VID, "CH7010B" },
+       { CH7009A_VID, "CH7009A" },
+       { CH7009B_VID, "CH7009B" },
+       { CH7301_VID, "CH7301" },
+};
+
+static struct ch7xxx_did_struct {
+       u8 did;
+       char *name;
+} ch7xxx_dids[] = {
+       { CH7xxx_DID, "CH7XXX" },
+       { CH7010_DID, "CH7010B" },
+};
+
+struct ch7xxx_priv {
+       bool quiet;
+};
+
+static char *ch7xxx_get_id(u8 vid)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
+               if (ch7xxx_ids[i].vid == vid)
+                       return ch7xxx_ids[i].name;
+       }
+
+       return NULL;
+}
+
+static char *ch7xxx_get_did(u8 did)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
+               if (ch7xxx_dids[i].did == did)
+                       return ch7xxx_dids[i].name;
+       }
+
+       return NULL;
+}
+
+/** Reads an 8 bit register */
+static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       }
+
+       if (!ch7xxx->quiet) {
+               DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+       return false;
+}
+
+/** Writes an 8 bit register */
+static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       struct i2c_msg msg = {
+               .addr = dvo->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(adapter, &msg, 1) == 1)
+               return true;
+
+       if (!ch7xxx->quiet) {
+               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+
+       return false;
+}
+
+static bool ch7xxx_init(struct intel_dvo_device *dvo,
+                       struct i2c_adapter *adapter)
+{
+       /* this will detect the CH7xxx chip on the specified i2c bus */
+       struct ch7xxx_priv *ch7xxx;
+       u8 vendor, device;
+       char *name, *devid;
+
+       ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
+       if (ch7xxx == NULL)
+               return false;
+
+       dvo->i2c_bus = adapter;
+       dvo->dev_priv = ch7xxx;
+       ch7xxx->quiet = true;
+
+       if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
+               goto out;
+
+       name = ch7xxx_get_id(vendor);
+       if (!name) {
+               DRM_DEBUG_KMS("ch7xxx not detected; got VID 0x%02x from %s slave %d.\n",
+                             vendor, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+
+
+       if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
+               goto out;
+
+       devid = ch7xxx_get_did(device);
+       if (!devid) {
+               DRM_DEBUG_KMS("ch7xxx not detected; got DID 0x%02x from %s slave %d.\n",
+                             device, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+
+       ch7xxx->quiet = false;
+       DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
+                 name, vendor, device);
+       return true;
+out:
+       kfree(ch7xxx);
+       return false;
+}
+
+static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
+{
+       u8 cdet, orig_pm, pm;
+
+       ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
+
+       pm = orig_pm;
+       pm &= ~CH7xxx_PM_FPD;
+       pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
+
+       ch7xxx_writeb(dvo, CH7xxx_PM, pm);
+
+       ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
+
+       ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
+
+       if (cdet & CH7xxx_CDET_DVI)
+               return connector_status_connected;
+       return connector_status_disconnected;
+}
+
+static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       if (mode->clock > 165000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
+                           const struct drm_display_mode *mode,
+                           const struct drm_display_mode *adjusted_mode)
+{
+       u8 tvco, tpcp, tpd, tlpf, idf;
+
+       if (mode->clock <= 65000) {
+               tvco = 0x23;
+               tpcp = 0x08;
+               tpd = 0x16;
+               tlpf = 0x60;
+       } else {
+               tvco = 0x2d;
+               tpcp = 0x06;
+               tpd = 0x26;
+               tlpf = 0xa0;
+       }
+
+       ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
+       ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
+       ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
+       ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
+       ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
+       ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
+       ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
+
+       ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
+
+       idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               idf |= CH7xxx_IDF_HSP;
+
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               idf |= CH7xxx_IDF_VSP;
+
+       ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
+}
+
+/* set the CH7xxx power state */
+static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
+{
+       if (enable)
+               ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
+       else
+               ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
+}
+
+static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
+{
+       u8 val;
+
+       ch7xxx_readb(dvo, CH7xxx_PM, &val);
+
+       if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
+               return true;
+       else
+               return false;
+}
+
+static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
+{
+       int i;
+
+       for (i = 0; i < CH7xxx_NUM_REGS; i++) {
+               u8 val;
+               if ((i % 8) == 0)
+                       DRM_DEBUG_KMS("\n %02X: ", i);
+               ch7xxx_readb(dvo, i, &val);
+               DRM_DEBUG_KMS("%02X ", val);
+       }
+}
+
+static void ch7xxx_destroy(struct intel_dvo_device *dvo)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+
+       if (ch7xxx) {
+               kfree(ch7xxx);
+               dvo->dev_priv = NULL;
+       }
+}
+
+const struct intel_dvo_dev_ops ch7xxx_ops = {
+       .init = ch7xxx_init,
+       .detect = ch7xxx_detect,
+       .mode_valid = ch7xxx_mode_valid,
+       .mode_set = ch7xxx_mode_set,
+       .dpms = ch7xxx_dpms,
+       .get_hw_state = ch7xxx_get_hw_state,
+       .dump_regs = ch7xxx_dump_regs,
+       .destroy = ch7xxx_destroy,
+};
diff --git a/drivers/gpu/drm/i915/display/dvo_ivch.c b/drivers/gpu/drm/i915/display/dvo_ivch.c
new file mode 100644 (file)
index 0000000..09dba35
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Thomas Richter <thor@math.tu-berlin.de>
+ *
+ * Minor modifications (Dithering enable):
+ *    Thomas Richter <thor@math.tu-berlin.de>
+ *
+ */
+
+#include "intel_drv.h"
+#include "intel_dvo_dev.h"
+
+/*
+ * register definitions for the i82807aa.
+ *
+ * Documentation on this chipset can be found in datasheet #29069001 at
+ * intel.com.
+ */
+
+/*
+ * VCH Revision & GMBus Base Addr
+ */
+#define VR00           0x00
+# define VR00_BASE_ADDRESS_MASK                0x007f
+
+/*
+ * Functionality Enable
+ */
+#define VR01           0x01
+
+/*
+ * Enable the panel fitter
+ */
+# define VR01_PANEL_FIT_ENABLE         (1 << 3)
+/*
+ * Enables the LCD display.
+ *
+ * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
+ */
+# define VR01_LCD_ENABLE               (1 << 2)
+/* Enables the DVO repeater. */
+# define VR01_DVO_BYPASS_ENABLE                (1 << 1)
+/* Enables the DVO clock */
+# define VR01_DVO_ENABLE               (1 << 0)
+/* Enable dithering for 18bpp panels. Not documented. */
+# define VR01_DITHER_ENABLE             (1 << 4)
+
+/*
+ * LCD Interface Format
+ */
+#define VR10           0x10
+/* Enables LVDS output instead of CMOS */
+# define VR10_LVDS_ENABLE              (1 << 4)
+/* Enables 18-bit LVDS output. */
+# define VR10_INTERFACE_1X18           (0 << 2)
+/* Enables 24-bit LVDS or CMOS output */
+# define VR10_INTERFACE_1X24           (1 << 2)
+/* Enables 2x18-bit LVDS or CMOS output. */
+# define VR10_INTERFACE_2X18           (2 << 2)
+/* Enables 2x24-bit LVDS output */
+# define VR10_INTERFACE_2X24           (3 << 2)
+/* Mask that defines the depth of the pipeline */
+# define VR10_INTERFACE_DEPTH_MASK      (3 << 2)
+
+/*
+ * VR20 LCD Horizontal Display Size
+ */
+#define VR20   0x20
+
+/*
+ * LCD Vertical Display Size
+ */
+#define VR21   0x21
+
+/*
+ * Panel power down status
+ */
+#define VR30           0x30
+/* Read only bit indicating that the panel is not in a safe poweroff state. */
+# define VR30_PANEL_ON                 (1 << 15)
+
+#define VR40           0x40
+# define VR40_STALL_ENABLE             (1 << 13)
+# define VR40_VERTICAL_INTERP_ENABLE   (1 << 12)
+# define VR40_ENHANCED_PANEL_FITTING   (1 << 11)
+# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10)
+# define VR40_AUTO_RATIO_ENABLE                (1 << 9)
+# define VR40_CLOCK_GATING_ENABLE      (1 << 8)
+
+/*
+ * Panel Fitting Vertical Ratio
+ * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
+ */
+#define VR41           0x41
+
+/*
+ * Panel Fitting Horizontal Ratio
+ * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
+ */
+#define VR42           0x42
+
+/*
+ * Horizontal Image Size
+ */
+#define VR43           0x43
+
+/* VR80 GPIO 0
+ */
+#define VR80       0x80
+#define VR81       0x81
+#define VR82       0x82
+#define VR83       0x83
+#define VR84       0x84
+#define VR85       0x85
+#define VR86       0x86
+#define VR87       0x87
+
+/* VR88 GPIO 8
+ */
+#define VR88       0x88
+
+/* Graphics BIOS scratch 0
+ */
+#define VR8E       0x8E
+# define VR8E_PANEL_TYPE_MASK          (0xf << 0)
+# define VR8E_PANEL_INTERFACE_CMOS     (0 << 4)
+# define VR8E_PANEL_INTERFACE_LVDS     (1 << 4)
+# define VR8E_FORCE_DEFAULT_PANEL      (1 << 5)
+
+/* Graphics BIOS scratch 1
+ */
+#define VR8F       0x8F
+# define VR8F_VCH_PRESENT              (1 << 0)
+# define VR8F_DISPLAY_CONN             (1 << 1)
+# define VR8F_POWER_MASK               (0x3c)
+# define VR8F_POWER_POS                        (2)
+
+/* Some Bios implementations do not restore the DVO state upon
+ * resume from standby. Thus, this driver has to handle it
+ * instead. The following list contains all registers that
+ * require saving.
+ */
+static const u16 backup_addresses[] = {
+       0x11, 0x12,
+       0x18, 0x19, 0x1a, 0x1f,
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+       0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+       0x8e, 0x8f,
+       0x10            /* this must come last */
+};
+
+
+struct ivch_priv {
+       bool quiet;
+
+       u16 width, height;
+
+       /* Register backup */
+
+       u16 reg_backup[ARRAY_SIZE(backup_addresses)];
+};
+
+
+static void ivch_dump_regs(struct intel_dvo_device *dvo);
+/*
+ * Reads a register on the ivch.
+ *
+ * Each of the 256 registers are 16 bits long.
+ */
+static bool ivch_read(struct intel_dvo_device *dvo, int addr, u16 *data)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[1];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 0,
+               },
+               {
+                       .addr = 0,
+                       .flags = I2C_M_NOSTART,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = I2C_M_RD | I2C_M_NOSTART,
+                       .len = 2,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+
+       if (i2c_transfer(adapter, msgs, 3) == 3) {
+               *data = (in_buf[1] << 8) | in_buf[0];
+               return true;
+       }
+
+       if (!priv->quiet) {
+               DRM_DEBUG_KMS("Unable to read register 0x%02x from "
+                               "%s:%02x.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+       return false;
+}
+
+/* Writes a 16-bit register on the ivch */
+static bool ivch_write(struct intel_dvo_device *dvo, int addr, u16 data)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[3];
+       struct i2c_msg msg = {
+               .addr = dvo->slave_addr,
+               .flags = 0,
+               .len = 3,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = data & 0xff;
+       out_buf[2] = data >> 8;
+
+       if (i2c_transfer(adapter, &msg, 1) == 1)
+               return true;
+
+       if (!priv->quiet) {
+               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+
+       return false;
+}
+
+/* Probes the given bus and slave address for an ivch */
+static bool ivch_init(struct intel_dvo_device *dvo,
+                     struct i2c_adapter *adapter)
+{
+       struct ivch_priv *priv;
+       u16 temp;
+       int i;
+
+       priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return false;
+
+       dvo->i2c_bus = adapter;
+       dvo->dev_priv = priv;
+       priv->quiet = true;
+
+       if (!ivch_read(dvo, VR00, &temp))
+               goto out;
+       priv->quiet = false;
+
+       /* Since the identification bits are probably zeroes, which doesn't seem
+        * very unique, check that the value in the base address field matches
+        * the address it's responding on.
+        */
+       if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
+               DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
+                         "(%d vs %d)\n",
+                         (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
+               goto out;
+       }
+
+       ivch_read(dvo, VR20, &priv->width);
+       ivch_read(dvo, VR21, &priv->height);
+
+       /* Make a backup of the registers to be able to restore them
+        * upon suspend.
+        */
+       for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
+               ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
+
+       ivch_dump_regs(dvo);
+
+       return true;
+
+out:
+       kfree(priv);
+       return false;
+}
+
+static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
+{
+       return connector_status_connected;
+}
+
+static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
+                                           struct drm_display_mode *mode)
+{
+       if (mode->clock > 112000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+/* Restore the DVO registers after a resume
+ * from RAM. Registers have been saved during
+ * the initialization.
+ */
+static void ivch_reset(struct intel_dvo_device *dvo)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+       int i;
+
+       DRM_DEBUG_KMS("Resetting the IVCH registers\n");
+
+       ivch_write(dvo, VR10, 0x0000);
+
+       for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
+               ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
+}
+
+/* Sets the power state of the panel connected to the ivch */
+static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
+{
+       int i;
+       u16 vr01, vr30, backlight;
+
+       ivch_reset(dvo);
+
+       /* Set the new power state of the panel. */
+       if (!ivch_read(dvo, VR01, &vr01))
+               return;
+
+       if (enable)
+               backlight = 1;
+       else
+               backlight = 0;
+
+       ivch_write(dvo, VR80, backlight);
+
+       if (enable)
+               vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
+       else
+               vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
+
+       ivch_write(dvo, VR01, vr01);
+
+       /* Wait for the panel to make its state transition */
+       for (i = 0; i < 100; i++) {
+               if (!ivch_read(dvo, VR30, &vr30))
+                       break;
+
+               if (((vr30 & VR30_PANEL_ON) != 0) == enable)
+                       break;
+               udelay(1000);
+       }
+       /* wait some more; vch may fail to resync sometimes without this */
+       udelay(16 * 1000);
+}
+
+static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
+{
+       u16 vr01;
+
+       ivch_reset(dvo);
+
+       /* Set the new power state of the panel. */
+       if (!ivch_read(dvo, VR01, &vr01))
+               return false;
+
+       if (vr01 & VR01_LCD_ENABLE)
+               return true;
+       else
+               return false;
+}
+
+static void ivch_mode_set(struct intel_dvo_device *dvo,
+                         const struct drm_display_mode *mode,
+                         const struct drm_display_mode *adjusted_mode)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+       u16 vr40 = 0;
+       u16 vr01 = 0;
+       u16 vr10;
+
+       ivch_reset(dvo);
+
+       vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
+
+       /* Enable dithering for 18 bpp pipelines */
+       vr10 &= VR10_INTERFACE_DEPTH_MASK;
+       if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
+               vr01 = VR01_DITHER_ENABLE;
+
+       vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
+               VR40_HORIZONTAL_INTERP_ENABLE);
+
+       if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
+           mode->vdisplay != adjusted_mode->crtc_vdisplay) {
+               u16 x_ratio, y_ratio;
+
+               vr01 |= VR01_PANEL_FIT_ENABLE;
+               vr40 |= VR40_CLOCK_GATING_ENABLE;
+               x_ratio = (((mode->hdisplay - 1) << 16) /
+                          (adjusted_mode->crtc_hdisplay - 1)) >> 2;
+               y_ratio = (((mode->vdisplay - 1) << 16) /
+                          (adjusted_mode->crtc_vdisplay - 1)) >> 2;
+               ivch_write(dvo, VR42, x_ratio);
+               ivch_write(dvo, VR41, y_ratio);
+       } else {
+               vr01 &= ~VR01_PANEL_FIT_ENABLE;
+               vr40 &= ~VR40_CLOCK_GATING_ENABLE;
+       }
+       vr40 &= ~VR40_AUTO_RATIO_ENABLE;
+
+       ivch_write(dvo, VR01, vr01);
+       ivch_write(dvo, VR40, vr40);
+}
+
+static void ivch_dump_regs(struct intel_dvo_device *dvo)
+{
+       u16 val;
+
+       ivch_read(dvo, VR00, &val);
+       DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
+       ivch_read(dvo, VR01, &val);
+       DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
+       ivch_read(dvo, VR10, &val);
+       DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
+       ivch_read(dvo, VR30, &val);
+       DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
+       ivch_read(dvo, VR40, &val);
+       DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
+
+       /* GPIO registers */
+       ivch_read(dvo, VR80, &val);
+       DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
+       ivch_read(dvo, VR81, &val);
+       DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
+       ivch_read(dvo, VR82, &val);
+       DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
+       ivch_read(dvo, VR83, &val);
+       DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
+       ivch_read(dvo, VR84, &val);
+       DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
+       ivch_read(dvo, VR85, &val);
+       DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
+       ivch_read(dvo, VR86, &val);
+       DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
+       ivch_read(dvo, VR87, &val);
+       DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
+       ivch_read(dvo, VR88, &val);
+       DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
+
+       /* Scratch register 0 - AIM Panel type */
+       ivch_read(dvo, VR8E, &val);
+       DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
+
+       /* Scratch register 1 - Status register */
+       ivch_read(dvo, VR8F, &val);
+       DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
+}
+
+static void ivch_destroy(struct intel_dvo_device *dvo)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+
+       if (priv) {
+               kfree(priv);
+               dvo->dev_priv = NULL;
+       }
+}
+
+const struct intel_dvo_dev_ops ivch_ops = {
+       .init = ivch_init,
+       .dpms = ivch_dpms,
+       .get_hw_state = ivch_get_hw_state,
+       .mode_valid = ivch_mode_valid,
+       .mode_set = ivch_mode_set,
+       .detect = ivch_detect,
+       .dump_regs = ivch_dump_regs,
+       .destroy = ivch_destroy,
+};
diff --git a/drivers/gpu/drm/i915/display/dvo_ns2501.c b/drivers/gpu/drm/i915/display/dvo_ns2501.c
new file mode 100644 (file)
index 0000000..c83a5d8
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ *
+ * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "i915_drv.h"
+#include "i915_reg.h"
+#include "intel_drv.h"
+#include "intel_dvo_dev.h"
+
+#define NS2501_VID 0x1305
+#define NS2501_DID 0x6726
+
+#define NS2501_VID_LO 0x00
+#define NS2501_VID_HI 0x01
+#define NS2501_DID_LO 0x02
+#define NS2501_DID_HI 0x03
+#define NS2501_REV 0x04
+#define NS2501_RSVD 0x05
+#define NS2501_FREQ_LO 0x06
+#define NS2501_FREQ_HI 0x07
+
+#define NS2501_REG8 0x08
+#define NS2501_8_VEN (1<<5)
+#define NS2501_8_HEN (1<<4)
+#define NS2501_8_DSEL (1<<3)
+#define NS2501_8_BPAS (1<<2)
+#define NS2501_8_RSVD (1<<1)
+#define NS2501_8_PD (1<<0)
+
+#define NS2501_REG9 0x09
+#define NS2501_9_VLOW (1<<7)
+#define NS2501_9_MSEL_MASK (0x7<<4)
+#define NS2501_9_TSEL (1<<3)
+#define NS2501_9_RSEN (1<<2)
+#define NS2501_9_RSVD (1<<1)
+#define NS2501_9_MDI (1<<0)
+
+#define NS2501_REGC 0x0c
+
+/*
+ * The following registers are not part of the official datasheet
+ * and are the result of reverse engineering.
+ */
+
+/*
+ * Register c0 controls how the DVO synchronizes with
+ * its input.
+ */
+#define NS2501_REGC0 0xc0
+#define NS2501_C0_ENABLE (1<<0)        /* enable the DVO sync in general */
+#define NS2501_C0_HSYNC (1<<1) /* synchronize horizontal with input */
+#define NS2501_C0_VSYNC (1<<2) /* synchronize vertical with input */
+#define NS2501_C0_RESET (1<<7) /* reset the synchronization flip/flops */
+
+/*
+ * Register 41 is somehow related to the sync register and sync
+ * configuration. It should be 0x32 whenever regC0 is 0x05 (hsync off)
+ * and 0x00 otherwise.
+ */
+#define NS2501_REG41 0x41
+
+/*
+ * this register controls the dithering of the DVO
+ * One bit enables it, the other define the dithering depth.
+ * The higher the value, the lower the dithering depth.
+ */
+#define NS2501_F9_REG 0xf9
+#define NS2501_F9_ENABLE (1<<0)                /* if set, dithering is enabled */
+#define NS2501_F9_DITHER_MASK (0x7f<<1)        /* controls the dither depth */
+#define NS2501_F9_DITHER_SHIFT 1       /* shifts the dither mask */
+
+/*
+ * PLL configuration register. This is a pair of registers,
+ * one single byte register at 1B, and a pair at 1C,1D.
+ * These registers are counters/dividers.
+ */
+#define NS2501_REG1B 0x1b /* one byte PLL control register */
+#define NS2501_REG1C 0x1c /* low-part of the second register */
+#define NS2501_REG1D 0x1d /* high-part of the second register */
+
+/*
+ * Scaler control registers. Horizontal at b8,b9,
+ * vertical at 10,11. The scale factor is computed as
+ * 2^16/control-value. The low-byte comes first.
+ */
+#define NS2501_REG10 0x10 /* low-byte vertical scaler */
+#define NS2501_REG11 0x11 /* high-byte vertical scaler */
+#define NS2501_REGB8 0xb8 /* low-byte horizontal scaler */
+#define NS2501_REGB9 0xb9 /* high-byte horizontal scaler */
+
+/*
+ * Display window definition. This consists of four registers
+ * per dimension. One register pair defines the start of the
+ * display, one the end.
+ * As far as I understand, this defines the window within which
+ * the scaler samples the input.
+ */
+#define NS2501_REGC1 0xc1 /* low-byte horizontal display start */
+#define NS2501_REGC2 0xc2 /* high-byte horizontal display start */
+#define NS2501_REGC3 0xc3 /* low-byte horizontal display stop */
+#define NS2501_REGC4 0xc4 /* high-byte horizontal display stop */
+#define NS2501_REGC5 0xc5 /* low-byte vertical display start */
+#define NS2501_REGC6 0xc6 /* high-byte vertical display start */
+#define NS2501_REGC7 0xc7 /* low-byte vertical display stop */
+#define NS2501_REGC8 0xc8 /* high-byte vertical display stop */
+
+/*
+ * The following register pair seems to define the start of
+ * the vertical sync. If automatic syncing is enabled, and the
+ * register value defines a sync pulse that is later than the
+ * incoming sync, then the register value is ignored and the
+ * external hsync triggers the synchronization.
+ */
+#define NS2501_REG80 0x80 /* low-byte vsync-start */
+#define NS2501_REG81 0x81 /* high-byte vsync-start */
+
+/*
+ * The following register pair seems to define the total number
+ * of lines created at the output side of the scaler.
+ * This is again a low-high register pair.
+ */
+#define NS2501_REG82 0x82 /* output display height, low byte */
+#define NS2501_REG83 0x83 /* output display height, high byte */
+
+/*
+ * The following registers define the end of the front-porch
+ * in horizontal and vertical position and hence allow to shift
+ * the image left/right or up/down.
+ */
+#define NS2501_REG98 0x98 /* horizontal start of display + 256, low */
+#define NS2501_REG99 0x99 /* horizontal start of display + 256, high */
+#define NS2501_REG8E 0x8e /* vertical start of the display, low byte */
+#define NS2501_REG8F 0x8f /* vertical start of the display, high byte */
+
+/*
+ * The following register pair control the function of the
+ * backlight and the DVO output. To enable the corresponding
+ * function, the corresponding bit must be set in both registers.
+ */
+#define NS2501_REG34 0x34 /* DVO enable functions, first register */
+#define NS2501_REG35 0x35 /* DVO enable functions, second register */
+#define NS2501_34_ENABLE_OUTPUT (1<<0) /* enable DVO output */
+#define NS2501_34_ENABLE_BACKLIGHT (1<<1) /* enable backlight */
+
+/*
+ * Registers 9C and 9D define the vertical output offset
+ * of the visible region.
+ */
+#define NS2501_REG9C 0x9c
+#define NS2501_REG9D 0x9d
+
+/*
+ * The register 9F defines the dithering. This requires the
+ * scaler to be ON. Bit 0 enables dithering, the remaining
+ * bits control the depth of the dither. The higher the value,
+ * the LOWER the dithering amplitude. A good value seems to be
+ * 15 (total register value).
+ */
+#define NS2501_REGF9 0xf9
+#define NS2501_F9_ENABLE_DITHER (1<<0) /* enable dithering */
+#define NS2501_F9_DITHER_MASK (0x7f<<1) /* dither masking */
+#define NS2501_F9_DITHER_SHIFT 1       /* upshift of the dither mask */
+
+enum {
+       MODE_640x480,
+       MODE_800x600,
+       MODE_1024x768,
+};
+
+struct ns2501_reg {
+       u8 offset;
+       u8 value;
+};
+
+/*
+ * The following structure keeps the complete configuration of
+ * the DVO, given a specific output configuration.
+ * This is pretty much guess-work from reverse-engineering, so
+ * read all this with a grain of salt.
+ */
+struct ns2501_configuration {
+       u8 sync;                /* configuration of the C0 register */
+       u8 conf;                /* configuration register 8 */
+       u8 syncb;               /* configuration register 41 */
+       u8 dither;              /* configuration of the dithering */
+       u8 pll_a;               /* PLL configuration, register A, 1B */
+       u16 pll_b;              /* PLL configuration, register B, 1C/1D */
+       u16 hstart;             /* horizontal start, registers C1/C2 */
+       u16 hstop;              /* horizontal total, registers C3/C4 */
+       u16 vstart;             /* vertical start, registers C5/C6 */
+       u16 vstop;              /* vertical total, registers C7/C8 */
+       u16 vsync;              /* manual vertical sync start, 80/81 */
+       u16 vtotal;             /* number of lines generated, 82/83 */
+       u16 hpos;               /* horizontal position + 256, 98/99  */
+       u16 vpos;               /* vertical position, 8e/8f */
+       u16 voffs;              /* vertical output offset, 9c/9d */
+       u16 hscale;             /* horizontal scaling factor, b8/b9 */
+       u16 vscale;             /* vertical scaling factor, 10/11 */
+};
+
+/*
+ * DVO configuration values, partially based on what the BIOS
+ * of the Fujitsu Lifebook S6010 writes into registers,
+ * partially found by manual tweaking. These configurations assume
+ * a 1024x768 panel.
+ */
+static const struct ns2501_configuration ns2501_modes[] = {
+       [MODE_640x480] = {
+               .sync   = NS2501_C0_ENABLE | NS2501_C0_VSYNC,
+               .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
+               .syncb  = 0x32,
+               .dither = 0x0f,
+               .pll_a  = 17,
+               .pll_b  = 852,
+               .hstart = 144,
+               .hstop  = 783,
+               .vstart = 22,
+               .vstop  = 514,
+               .vsync  = 2047, /* actually, ignored with this config */
+               .vtotal = 1341,
+               .hpos   = 0,
+               .vpos   = 16,
+               .voffs  = 36,
+               .hscale = 40960,
+               .vscale = 40960
+       },
+       [MODE_800x600] = {
+               .sync   = NS2501_C0_ENABLE |
+                         NS2501_C0_HSYNC | NS2501_C0_VSYNC,
+               .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
+               .syncb  = 0x00,
+               .dither = 0x0f,
+               .pll_a  = 25,
+               .pll_b  = 612,
+               .hstart = 215,
+               .hstop  = 1016,
+               .vstart = 26,
+               .vstop  = 627,
+               .vsync  = 807,
+               .vtotal = 1341,
+               .hpos   = 0,
+               .vpos   = 4,
+               .voffs  = 35,
+               .hscale = 51248,
+               .vscale = 51232
+       },
+       [MODE_1024x768] = {
+               .sync   = NS2501_C0_ENABLE | NS2501_C0_VSYNC,
+               .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
+               .syncb  = 0x32,
+               .dither = 0x0f,
+               .pll_a  = 11,
+               .pll_b  = 1350,
+               .hstart = 276,
+               .hstop  = 1299,
+               .vstart = 15,
+               .vstop  = 1056,
+               .vsync  = 2047,
+               .vtotal = 1341,
+               .hpos   = 0,
+               .vpos   = 7,
+               .voffs  = 27,
+               .hscale = 65535,
+               .vscale = 65535
+       }
+};
+
+/*
+ * Other configuration values left by the BIOS of the
+ * Fujitsu S6010 in the DVO control registers. Their
+ * value does not depend on the BIOS and their meaning
+ * is unknown.
+ */
+
+static const struct ns2501_reg mode_agnostic_values[] = {
+       /* 08 is mode specific */
+       [0] = { .offset = 0x0a, .value = 0x81, },
+       /* 10,11 are part of the mode specific configuration */
+       [1] = { .offset = 0x12, .value = 0x02, },
+       [2] = { .offset = 0x18, .value = 0x07, },
+       [3] = { .offset = 0x19, .value = 0x00, },
+       [4] = { .offset = 0x1a, .value = 0x00, }, /* PLL?, ignored */
+       /* 1b,1c,1d are part of the mode specific configuration */
+       [5] = { .offset = 0x1e, .value = 0x02, },
+       [6] = { .offset = 0x1f, .value = 0x40, },
+       [7] = { .offset = 0x20, .value = 0x00, },
+       [8] = { .offset = 0x21, .value = 0x00, },
+       [9] = { .offset = 0x22, .value = 0x00, },
+       [10] = { .offset = 0x23, .value = 0x00, },
+       [11] = { .offset = 0x24, .value = 0x00, },
+       [12] = { .offset = 0x25, .value = 0x00, },
+       [13] = { .offset = 0x26, .value = 0x00, },
+       [14] = { .offset = 0x27, .value = 0x00, },
+       [15] = { .offset = 0x7e, .value = 0x18, },
+       /* 80-84 are part of the mode-specific configuration */
+       [16] = { .offset = 0x84, .value = 0x00, },
+       [17] = { .offset = 0x85, .value = 0x00, },
+       [18] = { .offset = 0x86, .value = 0x00, },
+       [19] = { .offset = 0x87, .value = 0x00, },
+       [20] = { .offset = 0x88, .value = 0x00, },
+       [21] = { .offset = 0x89, .value = 0x00, },
+       [22] = { .offset = 0x8a, .value = 0x00, },
+       [23] = { .offset = 0x8b, .value = 0x00, },
+       [24] = { .offset = 0x8c, .value = 0x10, },
+       [25] = { .offset = 0x8d, .value = 0x02, },
+       /* 8e,8f are part of the mode-specific configuration */
+       [26] = { .offset = 0x90, .value = 0xff, },
+       [27] = { .offset = 0x91, .value = 0x07, },
+       [28] = { .offset = 0x92, .value = 0xa0, },
+       [29] = { .offset = 0x93, .value = 0x02, },
+       [30] = { .offset = 0x94, .value = 0x00, },
+       [31] = { .offset = 0x95, .value = 0x00, },
+       [32] = { .offset = 0x96, .value = 0x05, },
+       [33] = { .offset = 0x97, .value = 0x00, },
+       /* 98,99 are part of the mode-specific configuration */
+       [34] = { .offset = 0x9a, .value = 0x88, },
+       [35] = { .offset = 0x9b, .value = 0x00, },
+       /* 9c,9d are part of the mode-specific configuration */
+       [36] = { .offset = 0x9e, .value = 0x25, },
+       [37] = { .offset = 0x9f, .value = 0x03, },
+       [38] = { .offset = 0xa0, .value = 0x28, },
+       [39] = { .offset = 0xa1, .value = 0x01, },
+       [40] = { .offset = 0xa2, .value = 0x28, },
+       [41] = { .offset = 0xa3, .value = 0x05, },
+       /* register 0xa4 is mode specific, but 0x80..0x84 works always */
+       [42] = { .offset = 0xa4, .value = 0x84, },
+       [43] = { .offset = 0xa5, .value = 0x00, },
+       [44] = { .offset = 0xa6, .value = 0x00, },
+       [45] = { .offset = 0xa7, .value = 0x00, },
+       [46] = { .offset = 0xa8, .value = 0x00, },
+       /* 0xa9 to 0xab are mode specific, but have no visible effect */
+       [47] = { .offset = 0xa9, .value = 0x04, },
+       [48] = { .offset = 0xaa, .value = 0x70, },
+       [49] = { .offset = 0xab, .value = 0x4f, },
+       [50] = { .offset = 0xac, .value = 0x00, },
+       [51] = { .offset = 0xad, .value = 0x00, },
+       [52] = { .offset = 0xb6, .value = 0x09, },
+       [53] = { .offset = 0xb7, .value = 0x03, },
+       /* b8,b9 are part of the mode-specific configuration */
+       [54] = { .offset = 0xba, .value = 0x00, },
+       [55] = { .offset = 0xbb, .value = 0x20, },
+       [56] = { .offset = 0xf3, .value = 0x90, },
+       [57] = { .offset = 0xf4, .value = 0x00, },
+       [58] = { .offset = 0xf7, .value = 0x88, },
+       /* f8 is mode specific, but the value does not matter */
+       [59] = { .offset = 0xf8, .value = 0x0a, },
+       [60] = { .offset = 0xf9, .value = 0x00, }
+};
+
+static const struct ns2501_reg regs_init[] = {
+       [0] = { .offset = 0x35, .value = 0xff, },
+       [1] = { .offset = 0x34, .value = 0x00, },
+       [2] = { .offset = 0x08, .value = 0x30, },
+};
+
+struct ns2501_priv {
+       bool quiet;
+       const struct ns2501_configuration *conf;
+};
+
+#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
+
+/*
+** Read a register from the ns2501.
+** Returns true if successful, false otherwise.
+** If it returns false, it might be wise to enable the
+** DVO with the above function.
+*/
+static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
+{
+       struct ns2501_priv *ns = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                .addr = dvo->slave_addr,
+                .flags = 0,
+                .len = 1,
+                .buf = out_buf,
+                },
+               {
+                .addr = dvo->slave_addr,
+                .flags = I2C_M_RD,
+                .len = 1,
+                .buf = in_buf,
+                }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       }
+
+       if (!ns->quiet) {
+               DRM_DEBUG_KMS
+                   ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
+                    adapter->name, dvo->slave_addr);
+       }
+
+       return false;
+}
+
+/*
+** Write a register to the ns2501.
+** Returns true if successful, false otherwise.
+** If it returns false, it might be wise to enable the
+** DVO with the above function.
+*/
+static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
+{
+       struct ns2501_priv *ns = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+
+       struct i2c_msg msg = {
+               .addr = dvo->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(adapter, &msg, 1) == 1) {
+               return true;
+       }
+
+       if (!ns->quiet) {
+               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
+                             addr, adapter->name, dvo->slave_addr);
+       }
+
+       return false;
+}
+
+/* National Semiconductor 2501 driver for chip on i2c bus
+ * scan for the chip on the bus.
+ * Hope the VBIOS initialized the PLL correctly so we can
+ * talk to it. If not, it will not be seen and not detected.
+ * Bummer!
+ */
+static bool ns2501_init(struct intel_dvo_device *dvo,
+                       struct i2c_adapter *adapter)
+{
+       /* this will detect the NS2501 chip on the specified i2c bus */
+       struct ns2501_priv *ns;
+       unsigned char ch;
+
+       ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
+       if (ns == NULL)
+               return false;
+
+       dvo->i2c_bus = adapter;
+       dvo->dev_priv = ns;
+       ns->quiet = true;
+
+       if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
+               goto out;
+
+       if (ch != (NS2501_VID & 0xff)) {
+               DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
+                             ch, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+
+       if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
+               goto out;
+
+       if (ch != (NS2501_DID & 0xff)) {
+               DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
+                             ch, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+       ns->quiet = false;
+
+       DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
+
+       return true;
+
+out:
+       kfree(ns);
+       return false;
+}
+
+static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
+{
+       /*
+        * This is a Laptop display, it doesn't have hotplugging.
+        * Even if not, the detection bit of the 2501 is unreliable as
+        * it only works for some display types.
+        * It is even more unreliable as the PLL must be active for
+        * allowing reading from the chiop.
+        */
+       return connector_status_connected;
+}
+
+static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       DRM_DEBUG_KMS
+           ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
+            mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
+
+       /*
+        * Currently, these are all the modes I have data from.
+        * More might exist. Unclear how to find the native resolution
+        * of the panel in here so we could always accept it
+        * by disabling the scaler.
+        */
+       if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
+           (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
+           (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
+               return MODE_OK;
+       } else {
+               return MODE_ONE_SIZE;   /* Is this a reasonable error? */
+       }
+}
+
+static void ns2501_mode_set(struct intel_dvo_device *dvo,
+                           const struct drm_display_mode *mode,
+                           const struct drm_display_mode *adjusted_mode)
+{
+       const struct ns2501_configuration *conf;
+       struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
+       int mode_idx, i;
+
+       DRM_DEBUG_KMS
+           ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
+            mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
+
+       DRM_DEBUG_KMS("Detailed requested mode settings are:\n"
+                       "clock          : %d kHz\n"
+                       "hdisplay       : %d\n"
+                       "hblank start   : %d\n"
+                       "hblank end     : %d\n"
+                       "hsync start    : %d\n"
+                       "hsync end      : %d\n"
+                       "htotal         : %d\n"
+                       "hskew          : %d\n"
+                       "vdisplay       : %d\n"
+                       "vblank start   : %d\n"
+                       "hblank end     : %d\n"
+                       "vsync start    : %d\n"
+                       "vsync end      : %d\n"
+                       "vtotal         : %d\n",
+                       adjusted_mode->crtc_clock,
+                       adjusted_mode->crtc_hdisplay,
+                       adjusted_mode->crtc_hblank_start,
+                       adjusted_mode->crtc_hblank_end,
+                       adjusted_mode->crtc_hsync_start,
+                       adjusted_mode->crtc_hsync_end,
+                       adjusted_mode->crtc_htotal,
+                       adjusted_mode->crtc_hskew,
+                       adjusted_mode->crtc_vdisplay,
+                       adjusted_mode->crtc_vblank_start,
+                       adjusted_mode->crtc_vblank_end,
+                       adjusted_mode->crtc_vsync_start,
+                       adjusted_mode->crtc_vsync_end,
+                       adjusted_mode->crtc_vtotal);
+
+       if (mode->hdisplay == 640 && mode->vdisplay == 480)
+               mode_idx = MODE_640x480;
+       else if (mode->hdisplay == 800 && mode->vdisplay == 600)
+               mode_idx = MODE_800x600;
+       else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
+               mode_idx = MODE_1024x768;
+       else
+               return;
+
+       /* Hopefully doing it every time won't hurt... */
+       for (i = 0; i < ARRAY_SIZE(regs_init); i++)
+               ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
+
+       /* Write the mode-agnostic values */
+       for (i = 0; i < ARRAY_SIZE(mode_agnostic_values); i++)
+               ns2501_writeb(dvo, mode_agnostic_values[i].offset,
+                               mode_agnostic_values[i].value);
+
+       /* Write now the mode-specific configuration */
+       conf = ns2501_modes + mode_idx;
+       ns->conf = conf;
+
+       ns2501_writeb(dvo, NS2501_REG8, conf->conf);
+       ns2501_writeb(dvo, NS2501_REG1B, conf->pll_a);
+       ns2501_writeb(dvo, NS2501_REG1C, conf->pll_b & 0xff);
+       ns2501_writeb(dvo, NS2501_REG1D, conf->pll_b >> 8);
+       ns2501_writeb(dvo, NS2501_REGC1, conf->hstart & 0xff);
+       ns2501_writeb(dvo, NS2501_REGC2, conf->hstart >> 8);
+       ns2501_writeb(dvo, NS2501_REGC3, conf->hstop & 0xff);
+       ns2501_writeb(dvo, NS2501_REGC4, conf->hstop >> 8);
+       ns2501_writeb(dvo, NS2501_REGC5, conf->vstart & 0xff);
+       ns2501_writeb(dvo, NS2501_REGC6, conf->vstart >> 8);
+       ns2501_writeb(dvo, NS2501_REGC7, conf->vstop & 0xff);
+       ns2501_writeb(dvo, NS2501_REGC8, conf->vstop >> 8);
+       ns2501_writeb(dvo, NS2501_REG80, conf->vsync & 0xff);
+       ns2501_writeb(dvo, NS2501_REG81, conf->vsync >> 8);
+       ns2501_writeb(dvo, NS2501_REG82, conf->vtotal & 0xff);
+       ns2501_writeb(dvo, NS2501_REG83, conf->vtotal >> 8);
+       ns2501_writeb(dvo, NS2501_REG98, conf->hpos & 0xff);
+       ns2501_writeb(dvo, NS2501_REG99, conf->hpos >> 8);
+       ns2501_writeb(dvo, NS2501_REG8E, conf->vpos & 0xff);
+       ns2501_writeb(dvo, NS2501_REG8F, conf->vpos >> 8);
+       ns2501_writeb(dvo, NS2501_REG9C, conf->voffs & 0xff);
+       ns2501_writeb(dvo, NS2501_REG9D, conf->voffs >> 8);
+       ns2501_writeb(dvo, NS2501_REGB8, conf->hscale & 0xff);
+       ns2501_writeb(dvo, NS2501_REGB9, conf->hscale >> 8);
+       ns2501_writeb(dvo, NS2501_REG10, conf->vscale & 0xff);
+       ns2501_writeb(dvo, NS2501_REG11, conf->vscale >> 8);
+       ns2501_writeb(dvo, NS2501_REGF9, conf->dither);
+       ns2501_writeb(dvo, NS2501_REG41, conf->syncb);
+       ns2501_writeb(dvo, NS2501_REGC0, conf->sync);
+}
+
+/* set the NS2501 power state */
+static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
+{
+       unsigned char ch;
+
+       if (!ns2501_readb(dvo, NS2501_REG8, &ch))
+               return false;
+
+       return ch & NS2501_8_PD;
+}
+
+/* set the NS2501 power state */
+static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
+{
+       struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
+
+       DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
+
+       if (enable) {
+               ns2501_writeb(dvo, NS2501_REGC0, ns->conf->sync | 0x08);
+
+               ns2501_writeb(dvo, NS2501_REG41, ns->conf->syncb);
+
+               ns2501_writeb(dvo, NS2501_REG34, NS2501_34_ENABLE_OUTPUT);
+               msleep(15);
+
+               ns2501_writeb(dvo, NS2501_REG8,
+                               ns->conf->conf | NS2501_8_BPAS);
+               if (!(ns->conf->conf & NS2501_8_BPAS))
+                       ns2501_writeb(dvo, NS2501_REG8, ns->conf->conf);
+               msleep(200);
+
+               ns2501_writeb(dvo, NS2501_REG34,
+                       NS2501_34_ENABLE_OUTPUT | NS2501_34_ENABLE_BACKLIGHT);
+
+               ns2501_writeb(dvo, NS2501_REGC0, ns->conf->sync);
+       } else {
+               ns2501_writeb(dvo, NS2501_REG34, NS2501_34_ENABLE_OUTPUT);
+               msleep(200);
+
+               ns2501_writeb(dvo, NS2501_REG8, NS2501_8_VEN | NS2501_8_HEN |
+                               NS2501_8_BPAS);
+               msleep(15);
+
+               ns2501_writeb(dvo, NS2501_REG34, 0x00);
+       }
+}
+
+static void ns2501_destroy(struct intel_dvo_device *dvo)
+{
+       struct ns2501_priv *ns = dvo->dev_priv;
+
+       if (ns) {
+               kfree(ns);
+               dvo->dev_priv = NULL;
+       }
+}
+
+const struct intel_dvo_dev_ops ns2501_ops = {
+       .init = ns2501_init,
+       .detect = ns2501_detect,
+       .mode_valid = ns2501_mode_valid,
+       .mode_set = ns2501_mode_set,
+       .dpms = ns2501_dpms,
+       .get_hw_state = ns2501_get_hw_state,
+       .destroy = ns2501_destroy,
+};
diff --git a/drivers/gpu/drm/i915/display/dvo_sil164.c b/drivers/gpu/drm/i915/display/dvo_sil164.c
new file mode 100644 (file)
index 0000000..04698ea
--- /dev/null
@@ -0,0 +1,280 @@
+/**************************************************************************
+
+Copyright © 2006 Dave Airlie
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include "intel_drv.h"
+#include "intel_dvo_dev.h"
+
+#define SIL164_VID 0x0001
+#define SIL164_DID 0x0006
+
+#define SIL164_VID_LO 0x00
+#define SIL164_VID_HI 0x01
+#define SIL164_DID_LO 0x02
+#define SIL164_DID_HI 0x03
+#define SIL164_REV    0x04
+#define SIL164_RSVD   0x05
+#define SIL164_FREQ_LO 0x06
+#define SIL164_FREQ_HI 0x07
+
+#define SIL164_REG8 0x08
+#define SIL164_8_VEN (1<<5)
+#define SIL164_8_HEN (1<<4)
+#define SIL164_8_DSEL (1<<3)
+#define SIL164_8_BSEL (1<<2)
+#define SIL164_8_EDGE (1<<1)
+#define SIL164_8_PD   (1<<0)
+
+#define SIL164_REG9 0x09
+#define SIL164_9_VLOW (1<<7)
+#define SIL164_9_MSEL_MASK (0x7<<4)
+#define SIL164_9_TSEL (1<<3)
+#define SIL164_9_RSEN (1<<2)
+#define SIL164_9_HTPLG (1<<1)
+#define SIL164_9_MDI (1<<0)
+
+#define SIL164_REGC 0x0c
+
+struct sil164_priv {
+       //I2CDevRec d;
+       bool quiet;
+};
+
+#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
+
+static bool sil164_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
+{
+       struct sil164_priv *sil = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       }
+
+       if (!sil->quiet) {
+               DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+       return false;
+}
+
+static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
+{
+       struct sil164_priv *sil = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       struct i2c_msg msg = {
+               .addr = dvo->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(adapter, &msg, 1) == 1)
+               return true;
+
+       if (!sil->quiet) {
+               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+
+       return false;
+}
+
+/* Silicon Image 164 driver for chip on i2c bus */
+static bool sil164_init(struct intel_dvo_device *dvo,
+                       struct i2c_adapter *adapter)
+{
+       /* this will detect the SIL164 chip on the specified i2c bus */
+       struct sil164_priv *sil;
+       unsigned char ch;
+
+       sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
+       if (sil == NULL)
+               return false;
+
+       dvo->i2c_bus = adapter;
+       dvo->dev_priv = sil;
+       sil->quiet = true;
+
+       if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
+               goto out;
+
+       if (ch != (SIL164_VID & 0xff)) {
+               DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
+                         ch, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+
+       if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
+               goto out;
+
+       if (ch != (SIL164_DID & 0xff)) {
+               DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
+                         ch, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+       sil->quiet = false;
+
+       DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
+       return true;
+
+out:
+       kfree(sil);
+       return false;
+}
+
+static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
+{
+       u8 reg9;
+
+       sil164_readb(dvo, SIL164_REG9, &reg9);
+
+       if (reg9 & SIL164_9_HTPLG)
+               return connector_status_connected;
+       else
+               return connector_status_disconnected;
+}
+
+static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static void sil164_mode_set(struct intel_dvo_device *dvo,
+                           const struct drm_display_mode *mode,
+                           const struct drm_display_mode *adjusted_mode)
+{
+       /* As long as the basics are set up, since we don't have clock
+        * dependencies in the mode setup, we can just leave the
+        * registers alone and everything will work fine.
+        */
+       /* recommended programming sequence from doc */
+       /*sil164_writeb(sil, 0x08, 0x30);
+         sil164_writeb(sil, 0x09, 0x00);
+         sil164_writeb(sil, 0x0a, 0x90);
+         sil164_writeb(sil, 0x0c, 0x89);
+         sil164_writeb(sil, 0x08, 0x31);*/
+       /* don't do much */
+       return;
+}
+
+/* set the SIL164 power state */
+static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
+{
+       int ret;
+       unsigned char ch;
+
+       ret = sil164_readb(dvo, SIL164_REG8, &ch);
+       if (ret == false)
+               return;
+
+       if (enable)
+               ch |= SIL164_8_PD;
+       else
+               ch &= ~SIL164_8_PD;
+
+       sil164_writeb(dvo, SIL164_REG8, ch);
+       return;
+}
+
+static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
+{
+       int ret;
+       unsigned char ch;
+
+       ret = sil164_readb(dvo, SIL164_REG8, &ch);
+       if (ret == false)
+               return false;
+
+       if (ch & SIL164_8_PD)
+               return true;
+       else
+               return false;
+}
+
+static void sil164_dump_regs(struct intel_dvo_device *dvo)
+{
+       u8 val;
+
+       sil164_readb(dvo, SIL164_FREQ_LO, &val);
+       DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_FREQ_HI, &val);
+       DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_REG8, &val);
+       DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_REG9, &val);
+       DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_REGC, &val);
+       DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val);
+}
+
+static void sil164_destroy(struct intel_dvo_device *dvo)
+{
+       struct sil164_priv *sil = dvo->dev_priv;
+
+       if (sil) {
+               kfree(sil);
+               dvo->dev_priv = NULL;
+       }
+}
+
+const struct intel_dvo_dev_ops sil164_ops = {
+       .init = sil164_init,
+       .detect = sil164_detect,
+       .mode_valid = sil164_mode_valid,
+       .mode_set = sil164_mode_set,
+       .dpms = sil164_dpms,
+       .get_hw_state = sil164_get_hw_state,
+       .dump_regs = sil164_dump_regs,
+       .destroy = sil164_destroy,
+};
diff --git a/drivers/gpu/drm/i915/display/dvo_tfp410.c b/drivers/gpu/drm/i915/display/dvo_tfp410.c
new file mode 100644 (file)
index 0000000..623114e
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright © 2007 Dave Mueller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Dave Mueller <dave.mueller@gmx.ch>
+ *
+ */
+
+#include "intel_drv.h"
+#include "intel_dvo_dev.h"
+
+/* register definitions according to the TFP410 data sheet */
+#define TFP410_VID             0x014C
+#define TFP410_DID             0x0410
+
+#define TFP410_VID_LO          0x00
+#define TFP410_VID_HI          0x01
+#define TFP410_DID_LO          0x02
+#define TFP410_DID_HI          0x03
+#define TFP410_REV             0x04
+
+#define TFP410_CTL_1           0x08
+#define TFP410_CTL_1_TDIS      (1<<6)
+#define TFP410_CTL_1_VEN       (1<<5)
+#define TFP410_CTL_1_HEN       (1<<4)
+#define TFP410_CTL_1_DSEL      (1<<3)
+#define TFP410_CTL_1_BSEL      (1<<2)
+#define TFP410_CTL_1_EDGE      (1<<1)
+#define TFP410_CTL_1_PD                (1<<0)
+
+#define TFP410_CTL_2           0x09
+#define TFP410_CTL_2_VLOW      (1<<7)
+#define TFP410_CTL_2_MSEL_MASK (0x7<<4)
+#define TFP410_CTL_2_MSEL      (1<<4)
+#define TFP410_CTL_2_TSEL      (1<<3)
+#define TFP410_CTL_2_RSEN      (1<<2)
+#define TFP410_CTL_2_HTPLG     (1<<1)
+#define TFP410_CTL_2_MDI       (1<<0)
+
+#define TFP410_CTL_3           0x0A
+#define TFP410_CTL_3_DK_MASK   (0x7<<5)
+#define TFP410_CTL_3_DK                (1<<5)
+#define TFP410_CTL_3_DKEN      (1<<4)
+#define TFP410_CTL_3_CTL_MASK  (0x7<<1)
+#define TFP410_CTL_3_CTL       (1<<1)
+
+#define TFP410_USERCFG         0x0B
+
+#define TFP410_DE_DLY          0x32
+
+#define TFP410_DE_CTL          0x33
+#define TFP410_DE_CTL_DEGEN    (1<<6)
+#define TFP410_DE_CTL_VSPOL    (1<<5)
+#define TFP410_DE_CTL_HSPOL    (1<<4)
+#define TFP410_DE_CTL_DEDLY8   (1<<0)
+
+#define TFP410_DE_TOP          0x34
+
+#define TFP410_DE_CNT_LO       0x36
+#define TFP410_DE_CNT_HI       0x37
+
+#define TFP410_DE_LIN_LO       0x38
+#define TFP410_DE_LIN_HI       0x39
+
+#define TFP410_H_RES_LO                0x3A
+#define TFP410_H_RES_HI                0x3B
+
+#define TFP410_V_RES_LO                0x3C
+#define TFP410_V_RES_HI                0x3D
+
+struct tfp410_priv {
+       bool quiet;
+};
+
+static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = dvo->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       }
+
+       if (!tfp->quiet) {
+               DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+       return false;
+}
+
+static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       u8 out_buf[2];
+       struct i2c_msg msg = {
+               .addr = dvo->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(adapter, &msg, 1) == 1)
+               return true;
+
+       if (!tfp->quiet) {
+               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, adapter->name, dvo->slave_addr);
+       }
+
+       return false;
+}
+
+static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
+{
+       u8 ch1, ch2;
+
+       if (tfp410_readb(dvo, addr+0, &ch1) &&
+           tfp410_readb(dvo, addr+1, &ch2))
+               return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
+
+       return -1;
+}
+
+/* Ti TFP410 driver for chip on i2c bus */
+static bool tfp410_init(struct intel_dvo_device *dvo,
+                       struct i2c_adapter *adapter)
+{
+       /* this will detect the tfp410 chip on the specified i2c bus */
+       struct tfp410_priv *tfp;
+       int id;
+
+       tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
+       if (tfp == NULL)
+               return false;
+
+       dvo->i2c_bus = adapter;
+       dvo->dev_priv = tfp;
+       tfp->quiet = true;
+
+       if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
+               DRM_DEBUG_KMS("tfp410 not detected got VID %X: from %s "
+                               "Slave %d.\n",
+                         id, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+
+       if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
+               DRM_DEBUG_KMS("tfp410 not detected got DID %X: from %s "
+                               "Slave %d.\n",
+                         id, adapter->name, dvo->slave_addr);
+               goto out;
+       }
+       tfp->quiet = false;
+       return true;
+out:
+       kfree(tfp);
+       return false;
+}
+
+static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
+{
+       enum drm_connector_status ret = connector_status_disconnected;
+       u8 ctl2;
+
+       if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
+               if (ctl2 & TFP410_CTL_2_RSEN)
+                       ret = connector_status_connected;
+               else
+                       ret = connector_status_disconnected;
+       }
+
+       return ret;
+}
+
+static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static void tfp410_mode_set(struct intel_dvo_device *dvo,
+                           const struct drm_display_mode *mode,
+                           const struct drm_display_mode *adjusted_mode)
+{
+       /* As long as the basics are set up, since we don't have clock dependencies
+       * in the mode setup, we can just leave the registers alone and everything
+       * will work fine.
+       */
+       /* don't do much */
+       return;
+}
+
+/* set the tfp410 power state */
+static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
+{
+       u8 ctl1;
+
+       if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
+               return;
+
+       if (enable)
+               ctl1 |= TFP410_CTL_1_PD;
+       else
+               ctl1 &= ~TFP410_CTL_1_PD;
+
+       tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
+}
+
+static bool tfp410_get_hw_state(struct intel_dvo_device *dvo)
+{
+       u8 ctl1;
+
+       if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
+               return false;
+
+       if (ctl1 & TFP410_CTL_1_PD)
+               return true;
+       else
+               return false;
+}
+
+static void tfp410_dump_regs(struct intel_dvo_device *dvo)
+{
+       u8 val, val2;
+
+       tfp410_readb(dvo, TFP410_REV, &val);
+       DRM_DEBUG_KMS("TFP410_REV: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_CTL_1, &val);
+       DRM_DEBUG_KMS("TFP410_CTL1: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_CTL_2, &val);
+       DRM_DEBUG_KMS("TFP410_CTL2: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_CTL_3, &val);
+       DRM_DEBUG_KMS("TFP410_CTL3: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_USERCFG, &val);
+       DRM_DEBUG_KMS("TFP410_USERCFG: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_DLY, &val);
+       DRM_DEBUG_KMS("TFP410_DE_DLY: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_CTL, &val);
+       DRM_DEBUG_KMS("TFP410_DE_CTL: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_TOP, &val);
+       DRM_DEBUG_KMS("TFP410_DE_TOP: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
+       tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
+       DRM_DEBUG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
+       tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
+       tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
+       DRM_DEBUG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
+       tfp410_readb(dvo, TFP410_H_RES_LO, &val);
+       tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
+       DRM_DEBUG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);
+       tfp410_readb(dvo, TFP410_V_RES_LO, &val);
+       tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
+       DRM_DEBUG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
+}
+
+static void tfp410_destroy(struct intel_dvo_device *dvo)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+
+       if (tfp) {
+               kfree(tfp);
+               dvo->dev_priv = NULL;
+       }
+}
+
+const struct intel_dvo_dev_ops tfp410_ops = {
+       .init = tfp410_init,
+       .detect = tfp410_detect,
+       .mode_valid = tfp410_mode_valid,
+       .mode_set = tfp410_mode_set,
+       .dpms = tfp410_dpms,
+       .get_hw_state = tfp410_get_hw_state,
+       .dump_regs = tfp410_dump_regs,
+       .destroy = tfp410_destroy,
+};
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
new file mode 100644 (file)
index 0000000..74448e6
--- /dev/null
@@ -0,0 +1,1589 @@
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Madhav Chauhan <madhav.chauhan@intel.com>
+ *   Jani Nikula <jani.nikula@intel.com>
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_mipi_dsi.h>
+
+#include "intel_atomic.h"
+#include "intel_combo_phy.h"
+#include "intel_connector.h"
+#include "intel_ddi.h"
+#include "intel_dsi.h"
+#include "intel_panel.h"
+
+static inline int header_credits_available(struct drm_i915_private *dev_priv,
+                                          enum transcoder dsi_trans)
+{
+       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK)
+               >> FREE_HEADER_CREDIT_SHIFT;
+}
+
+static inline int payload_credits_available(struct drm_i915_private *dev_priv,
+                                           enum transcoder dsi_trans)
+{
+       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK)
+               >> FREE_PLOAD_CREDIT_SHIFT;
+}
+
+static void wait_for_header_credits(struct drm_i915_private *dev_priv,
+                                   enum transcoder dsi_trans)
+{
+       if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
+                       MAX_HEADER_CREDIT, 100))
+               DRM_ERROR("DSI header credits not released\n");
+}
+
+static void wait_for_payload_credits(struct drm_i915_private *dev_priv,
+                                    enum transcoder dsi_trans)
+{
+       if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
+                       MAX_PLOAD_CREDIT, 100))
+               DRM_ERROR("DSI payload credits not released\n");
+}
+
+static enum transcoder dsi_port_to_transcoder(enum port port)
+{
+       if (port == PORT_A)
+               return TRANSCODER_DSI_0;
+       else
+               return TRANSCODER_DSI_1;
+}
+
+static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct mipi_dsi_device *dsi;
+       enum port port;
+       enum transcoder dsi_trans;
+       int ret;
+
+       /* wait for header/payload credits to be released */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               wait_for_header_credits(dev_priv, dsi_trans);
+               wait_for_payload_credits(dev_priv, dsi_trans);
+       }
+
+       /* send nop DCS command */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi = intel_dsi->dsi_hosts[port]->device;
+               dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+               dsi->channel = 0;
+               ret = mipi_dsi_dcs_nop(dsi);
+               if (ret < 0)
+                       DRM_ERROR("error sending DCS NOP command\n");
+       }
+
+       /* wait for header credits to be released */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               wait_for_header_credits(dev_priv, dsi_trans);
+       }
+
+       /* wait for LP TX in progress bit to be cleared */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               if (wait_for_us(!(I915_READ(DSI_LP_MSG(dsi_trans)) &
+                                 LPTX_IN_PROGRESS), 20))
+                       DRM_ERROR("LPTX bit not cleared\n");
+       }
+}
+
+static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data,
+                              u32 len)
+{
+       struct intel_dsi *intel_dsi = host->intel_dsi;
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
+       int free_credits;
+       int i, j;
+
+       for (i = 0; i < len; i += 4) {
+               u32 tmp = 0;
+
+               free_credits = payload_credits_available(dev_priv, dsi_trans);
+               if (free_credits < 1) {
+                       DRM_ERROR("Payload credit not available\n");
+                       return false;
+               }
+
+               for (j = 0; j < min_t(u32, len - i, 4); j++)
+                       tmp |= *data++ << 8 * j;
+
+               I915_WRITE(DSI_CMD_TXPYLD(dsi_trans), tmp);
+       }
+
+       return true;
+}
+
+static int dsi_send_pkt_hdr(struct intel_dsi_host *host,
+                           struct mipi_dsi_packet pkt, bool enable_lpdt)
+{
+       struct intel_dsi *intel_dsi = host->intel_dsi;
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
+       u32 tmp;
+       int free_credits;
+
+       /* check if header credit available */
+       free_credits = header_credits_available(dev_priv, dsi_trans);
+       if (free_credits < 1) {
+               DRM_ERROR("send pkt header failed, not enough hdr credits\n");
+               return -1;
+       }
+
+       tmp = I915_READ(DSI_CMD_TXHDR(dsi_trans));
+
+       if (pkt.payload)
+               tmp |= PAYLOAD_PRESENT;
+       else
+               tmp &= ~PAYLOAD_PRESENT;
+
+       tmp &= ~VBLANK_FENCE;
+
+       if (enable_lpdt)
+               tmp |= LP_DATA_TRANSFER;
+
+       tmp &= ~(PARAM_WC_MASK | VC_MASK | DT_MASK);
+       tmp |= ((pkt.header[0] & VC_MASK) << VC_SHIFT);
+       tmp |= ((pkt.header[0] & DT_MASK) << DT_SHIFT);
+       tmp |= (pkt.header[1] << PARAM_WC_LOWER_SHIFT);
+       tmp |= (pkt.header[2] << PARAM_WC_UPPER_SHIFT);
+       I915_WRITE(DSI_CMD_TXHDR(dsi_trans), tmp);
+
+       return 0;
+}
+
+static int dsi_send_pkt_payld(struct intel_dsi_host *host,
+                             struct mipi_dsi_packet pkt)
+{
+       /* payload queue can accept *256 bytes*, check limit */
+       if (pkt.payload_length > MAX_PLOAD_CREDIT * 4) {
+               DRM_ERROR("payload size exceeds max queue limit\n");
+               return -1;
+       }
+
+       /* load data into command payload queue */
+       if (!add_payld_to_queue(host, pkt.payload,
+                               pkt.payload_length)) {
+               DRM_ERROR("adding payload to queue failed\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       int lane;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+
+               /*
+                * Program voltage swing and pre-emphasis level values as per
+                * table in BSPEC under DDI buffer programing
+                */
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
+               tmp |= SCALING_MODE_SEL(0x2);
+               tmp |= TAP2_DISABLE | TAP3_DISABLE;
+               tmp |= RTERM_SELECT(0x6);
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
+               tmp |= SCALING_MODE_SEL(0x2);
+               tmp |= TAP2_DISABLE | TAP3_DISABLE;
+               tmp |= RTERM_SELECT(0x6);
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                        RCOMP_SCALAR_MASK);
+               tmp |= SWING_SEL_UPPER(0x2);
+               tmp |= SWING_SEL_LOWER(0x2);
+               tmp |= RCOMP_SCALAR(0x98);
+               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
+               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                        RCOMP_SCALAR_MASK);
+               tmp |= SWING_SEL_UPPER(0x2);
+               tmp |= SWING_SEL_LOWER(0x2);
+               tmp |= RCOMP_SCALAR(0x98);
+               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
+               tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                        CURSOR_COEFF_MASK);
+               tmp |= POST_CURSOR_1(0x0);
+               tmp |= POST_CURSOR_2(0x0);
+               tmp |= CURSOR_COEFF(0x3f);
+               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
+
+               for (lane = 0; lane <= 3; lane++) {
+                       /* Bspec: must not use GRP register for write */
+                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(lane, port));
+                       tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                                CURSOR_COEFF_MASK);
+                       tmp |= POST_CURSOR_1(0x0);
+                       tmp |= POST_CURSOR_2(0x0);
+                       tmp |= CURSOR_COEFF(0x3f);
+                       I915_WRITE(ICL_PORT_TX_DW4_LN(lane, port), tmp);
+               }
+       }
+}
+
+static void configure_dual_link_mode(struct intel_encoder *encoder,
+                                    const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 dss_ctl1;
+
+       dss_ctl1 = I915_READ(DSS_CTL1);
+       dss_ctl1 |= SPLITTER_ENABLE;
+       dss_ctl1 &= ~OVERLAP_PIXELS_MASK;
+       dss_ctl1 |= OVERLAP_PIXELS(intel_dsi->pixel_overlap);
+
+       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+               const struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+               u32 dss_ctl2;
+               u16 hactive = adjusted_mode->crtc_hdisplay;
+               u16 dl_buffer_depth;
+
+               dss_ctl1 &= ~DUAL_LINK_MODE_INTERLEAVE;
+               dl_buffer_depth = hactive / 2 + intel_dsi->pixel_overlap;
+
+               if (dl_buffer_depth > MAX_DL_BUFFER_TARGET_DEPTH)
+                       DRM_ERROR("DL buffer depth exceed max value\n");
+
+               dss_ctl1 &= ~LEFT_DL_BUF_TARGET_DEPTH_MASK;
+               dss_ctl1 |= LEFT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
+               dss_ctl2 = I915_READ(DSS_CTL2);
+               dss_ctl2 &= ~RIGHT_DL_BUF_TARGET_DEPTH_MASK;
+               dss_ctl2 |= RIGHT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
+               I915_WRITE(DSS_CTL2, dss_ctl2);
+       } else {
+               /* Interleave */
+               dss_ctl1 |= DUAL_LINK_MODE_INTERLEAVE;
+       }
+
+       I915_WRITE(DSS_CTL1, dss_ctl1);
+}
+
+static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+       u32 afe_clk_khz; /* 8X Clock */
+       u32 esc_clk_div_m;
+
+       afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp,
+                                       intel_dsi->lane_count);
+
+       esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(ICL_DSI_ESC_CLK_DIV(port),
+                          esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
+               POSTING_READ(ICL_DSI_ESC_CLK_DIV(port));
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port),
+                          esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
+               POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port));
+       }
+}
+
+static void get_dsi_io_power_domains(struct drm_i915_private *dev_priv,
+                                    struct intel_dsi *intel_dsi)
+{
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               WARN_ON(intel_dsi->io_wakeref[port]);
+               intel_dsi->io_wakeref[port] =
+                       intel_display_power_get(dev_priv,
+                                               port == PORT_A ?
+                                               POWER_DOMAIN_PORT_DDI_A_IO :
+                                               POWER_DOMAIN_PORT_DDI_B_IO);
+       }
+}
+
+static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
+               tmp |= COMBO_PHY_MODE_DSI;
+               I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
+       }
+
+       get_dsi_io_power_domains(dev_priv, intel_dsi);
+}
+
+static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports)
+               intel_combo_phy_power_up_lanes(dev_priv, port, true,
+                                              intel_dsi->lane_count, false);
+}
+
+static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       int lane;
+
+       /* Step 4b(i) set loadgen select for transmit and aux lanes */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
+               tmp &= ~LOADGEN_SELECT;
+               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
+               for (lane = 0; lane <= 3; lane++) {
+                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(lane, port));
+                       tmp &= ~LOADGEN_SELECT;
+                       if (lane != 2)
+                               tmp |= LOADGEN_SELECT;
+                       I915_WRITE(ICL_PORT_TX_DW4_LN(lane, port), tmp);
+               }
+       }
+
+       /* Step 4b(ii) set latency optimization for transmit and aux lanes */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
+               tmp &= ~FRC_LATENCY_OPTIM_MASK;
+               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
+               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+               tmp &= ~FRC_LATENCY_OPTIM_MASK;
+               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
+               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+       }
+
+}
+
+static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       /* clear common keeper enable bit */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
+               tmp &= ~COMMON_KEEPER_EN;
+               I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port));
+               tmp &= ~COMMON_KEEPER_EN;
+               I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp);
+       }
+
+       /*
+        * Set SUS Clock Config bitfield to 11b
+        * Note: loadgen select program is done
+        * as part of lane phy sequence configuration
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_CL_DW5(port));
+               tmp |= SUS_CLOCK_CONFIG;
+               I915_WRITE(ICL_PORT_CL_DW5(port), tmp);
+       }
+
+       /* Clear training enable to change swing values */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp &= ~TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp &= ~TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+       }
+
+       /* Program swing and de-emphasis */
+       dsi_program_swing_and_deemphasis(encoder);
+
+       /* Set training enable to trigger update */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp |= TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp |= TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+       }
+}
+
+static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(DDI_BUF_CTL(port));
+               tmp |= DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(port), tmp);
+
+               if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) &
+                                 DDI_BUF_IS_IDLE),
+                                 500))
+                       DRM_ERROR("DDI port:%c buffer idle\n", port_name(port));
+       }
+}
+
+static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       /* Program T-INIT master registers */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port));
+               tmp &= ~MASTER_INIT_TIMER_MASK;
+               tmp |= intel_dsi->init_count;
+               I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp);
+       }
+
+       /* Program DPHY clock lanes timings */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(DPHY_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg);
+
+               /* shadow register inside display core */
+               I915_WRITE(DSI_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg);
+       }
+
+       /* Program DPHY data lanes timings */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(DPHY_DATA_TIMING_PARAM(port),
+                          intel_dsi->dphy_data_lane_reg);
+
+               /* shadow register inside display core */
+               I915_WRITE(DSI_DATA_TIMING_PARAM(port),
+                          intel_dsi->dphy_data_lane_reg);
+       }
+
+       /*
+        * If DSI link operating at or below an 800 MHz,
+        * TA_SURE should be override and programmed to
+        * a value '0' inside TA_PARAM_REGISTERS otherwise
+        * leave all fields at HW default values.
+        */
+       if (intel_dsi_bitrate(intel_dsi) <= 800000) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       tmp = I915_READ(DPHY_TA_TIMING_PARAM(port));
+                       tmp &= ~TA_SURE_MASK;
+                       tmp |= TA_SURE_OVERRIDE | TA_SURE(0);
+                       I915_WRITE(DPHY_TA_TIMING_PARAM(port), tmp);
+
+                       /* shadow register inside display core */
+                       tmp = I915_READ(DSI_TA_TIMING_PARAM(port));
+                       tmp &= ~TA_SURE_MASK;
+                       tmp |= TA_SURE_OVERRIDE | TA_SURE(0);
+                       I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp);
+               }
+       }
+}
+
+static void gen11_dsi_gate_clocks(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       mutex_lock(&dev_priv->dpll_lock);
+       tmp = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp |= DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+       }
+
+       I915_WRITE(DPCLKA_CFGCR0_ICL, tmp);
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void gen11_dsi_ungate_clocks(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       mutex_lock(&dev_priv->dpll_lock);
+       tmp = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+       }
+
+       I915_WRITE(DPCLKA_CFGCR0_ICL, tmp);
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void gen11_dsi_map_pll(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+       enum port port;
+       u32 val;
+
+       mutex_lock(&dev_priv->dpll_lock);
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
+       }
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+       }
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+
+       POSTING_READ(DPCLKA_CFGCR0_ICL);
+
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void
+gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       enum pipe pipe = intel_crtc->pipe;
+       u32 tmp;
+       enum port port;
+       enum transcoder dsi_trans;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans));
+
+               if (intel_dsi->eotp_pkt)
+                       tmp &= ~EOTP_DISABLED;
+               else
+                       tmp |= EOTP_DISABLED;
+
+               /* enable link calibration if freq > 1.5Gbps */
+               if (intel_dsi_bitrate(intel_dsi) >= 1500 * 1000) {
+                       tmp &= ~LINK_CALIBRATION_MASK;
+                       tmp |= CALIBRATION_ENABLED_INITIAL_ONLY;
+               }
+
+               /* configure continuous clock */
+               tmp &= ~CONTINUOUS_CLK_MASK;
+               if (intel_dsi->clock_stop)
+                       tmp |= CLK_ENTER_LP_AFTER_DATA;
+               else
+                       tmp |= CLK_HS_CONTINUOUS;
+
+               /* configure buffer threshold limit to minimum */
+               tmp &= ~PIX_BUF_THRESHOLD_MASK;
+               tmp |= PIX_BUF_THRESHOLD_1_4;
+
+               /* set virtual channel to '0' */
+               tmp &= ~PIX_VIRT_CHAN_MASK;
+               tmp |= PIX_VIRT_CHAN(0);
+
+               /* program BGR transmission */
+               if (intel_dsi->bgr_enabled)
+                       tmp |= BGR_TRANSMISSION;
+
+               /* select pixel format */
+               tmp &= ~PIX_FMT_MASK;
+               switch (intel_dsi->pixel_format) {
+               default:
+                       MISSING_CASE(intel_dsi->pixel_format);
+                       /* fallthrough */
+               case MIPI_DSI_FMT_RGB565:
+                       tmp |= PIX_FMT_RGB565;
+                       break;
+               case MIPI_DSI_FMT_RGB666_PACKED:
+                       tmp |= PIX_FMT_RGB666_PACKED;
+                       break;
+               case MIPI_DSI_FMT_RGB666:
+                       tmp |= PIX_FMT_RGB666_LOOSE;
+                       break;
+               case MIPI_DSI_FMT_RGB888:
+                       tmp |= PIX_FMT_RGB888;
+                       break;
+               }
+
+               /* program DSI operation mode */
+               if (is_vid_mode(intel_dsi)) {
+                       tmp &= ~OP_MODE_MASK;
+                       switch (intel_dsi->video_mode_format) {
+                       default:
+                               MISSING_CASE(intel_dsi->video_mode_format);
+                               /* fallthrough */
+                       case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS:
+                               tmp |= VIDEO_MODE_SYNC_EVENT;
+                               break;
+                       case VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE:
+                               tmp |= VIDEO_MODE_SYNC_PULSE;
+                               break;
+                       }
+               }
+
+               I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp);
+       }
+
+       /* enable port sync mode if dual link */
+       if (intel_dsi->dual_link) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       dsi_trans = dsi_port_to_transcoder(port);
+                       tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans));
+                       tmp |= PORT_SYNC_MODE_ENABLE;
+                       I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp);
+               }
+
+               /* configure stream splitting */
+               configure_dual_link_mode(encoder, pipe_config);
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /* select data lane width */
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+               tmp &= ~DDI_PORT_WIDTH_MASK;
+               tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count);
+
+               /* select input pipe */
+               tmp &= ~TRANS_DDI_EDP_INPUT_MASK;
+               switch (pipe) {
+               default:
+                       MISSING_CASE(pipe);
+                       /* fallthrough */
+               case PIPE_A:
+                       tmp |= TRANS_DDI_EDP_INPUT_A_ON;
+                       break;
+               case PIPE_B:
+                       tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
+                       break;
+               case PIPE_C:
+                       tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
+                       break;
+               }
+
+               /* enable DDI buffer */
+               tmp |= TRANS_DDI_FUNC_ENABLE;
+               I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp);
+       }
+
+       /* wait for link ready */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               if (wait_for_us((I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)) &
+                               LINK_READY), 2500))
+                       DRM_ERROR("DSI link not ready\n");
+       }
+}
+
+static void
+gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       const struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+       enum port port;
+       enum transcoder dsi_trans;
+       /* horizontal timings */
+       u16 htotal, hactive, hsync_start, hsync_end, hsync_size;
+       u16 hfront_porch, hback_porch;
+       /* vertical timings */
+       u16 vtotal, vactive, vsync_start, vsync_end, vsync_shift;
+
+       hactive = adjusted_mode->crtc_hdisplay;
+       htotal = adjusted_mode->crtc_htotal;
+       hsync_start = adjusted_mode->crtc_hsync_start;
+       hsync_end = adjusted_mode->crtc_hsync_end;
+       hsync_size  = hsync_end - hsync_start;
+       hfront_porch = (adjusted_mode->crtc_hsync_start -
+                       adjusted_mode->crtc_hdisplay);
+       hback_porch = (adjusted_mode->crtc_htotal -
+                      adjusted_mode->crtc_hsync_end);
+       vactive = adjusted_mode->crtc_vdisplay;
+       vtotal = adjusted_mode->crtc_vtotal;
+       vsync_start = adjusted_mode->crtc_vsync_start;
+       vsync_end = adjusted_mode->crtc_vsync_end;
+       vsync_shift = hsync_start - htotal / 2;
+
+       if (intel_dsi->dual_link) {
+               hactive /= 2;
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+                       hactive += intel_dsi->pixel_overlap;
+               htotal /= 2;
+       }
+
+       /* minimum hactive as per bspec: 256 pixels */
+       if (adjusted_mode->crtc_hdisplay < 256)
+               DRM_ERROR("hactive is less then 256 pixels\n");
+
+       /* if RGB666 format, then hactive must be multiple of 4 pixels */
+       if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB666 && hactive % 4 != 0)
+               DRM_ERROR("hactive pixels are not multiple of 4\n");
+
+       /* program TRANS_HTOTAL register */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               I915_WRITE(HTOTAL(dsi_trans),
+                          (hactive - 1) | ((htotal - 1) << 16));
+       }
+
+       /* TRANS_HSYNC register to be programmed only for video mode */
+       if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) {
+               if (intel_dsi->video_mode_format ==
+                   VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE) {
+                       /* BSPEC: hsync size should be atleast 16 pixels */
+                       if (hsync_size < 16)
+                               DRM_ERROR("hsync size < 16 pixels\n");
+               }
+
+               if (hback_porch < 16)
+                       DRM_ERROR("hback porch < 16 pixels\n");
+
+               if (intel_dsi->dual_link) {
+                       hsync_start /= 2;
+                       hsync_end /= 2;
+               }
+
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       dsi_trans = dsi_port_to_transcoder(port);
+                       I915_WRITE(HSYNC(dsi_trans),
+                                  (hsync_start - 1) | ((hsync_end - 1) << 16));
+               }
+       }
+
+       /* program TRANS_VTOTAL register */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               /*
+                * FIXME: Programing this by assuming progressive mode, since
+                * non-interlaced info from VBT is not saved inside
+                * struct drm_display_mode.
+                * For interlace mode: program required pixel minus 2
+                */
+               I915_WRITE(VTOTAL(dsi_trans),
+                          (vactive - 1) | ((vtotal - 1) << 16));
+       }
+
+       if (vsync_end < vsync_start || vsync_end > vtotal)
+               DRM_ERROR("Invalid vsync_end value\n");
+
+       if (vsync_start < vactive)
+               DRM_ERROR("vsync_start less than vactive\n");
+
+       /* program TRANS_VSYNC register */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               I915_WRITE(VSYNC(dsi_trans),
+                          (vsync_start - 1) | ((vsync_end - 1) << 16));
+       }
+
+       /*
+        * FIXME: It has to be programmed only for interlaced
+        * modes. Put the check condition here once interlaced
+        * info available as described above.
+        * program TRANS_VSYNCSHIFT register
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               I915_WRITE(VSYNCSHIFT(dsi_trans), vsync_shift);
+       }
+}
+
+static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(PIPECONF(dsi_trans));
+               tmp |= PIPECONF_ENABLE;
+               I915_WRITE(PIPECONF(dsi_trans), tmp);
+
+               /* wait for transcoder to be enabled */
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           PIPECONF(dsi_trans),
+                                           I965_PIPECONF_ACTIVE,
+                                           I965_PIPECONF_ACTIVE, 10))
+                       DRM_ERROR("DSI transcoder not enabled\n");
+       }
+}
+
+static void gen11_dsi_setup_timeouts(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp, hs_tx_timeout, lp_rx_timeout, ta_timeout, divisor, mul;
+
+       /*
+        * escape clock count calculation:
+        * BYTE_CLK_COUNT = TIME_NS/(8 * UI)
+        * UI (nsec) = (10^6)/Bitrate
+        * TIME_NS = (BYTE_CLK_COUNT * 8 * 10^6)/ Bitrate
+        * ESCAPE_CLK_COUNT  = TIME_NS/ESC_CLK_NS
+        */
+       divisor = intel_dsi_tlpx_ns(intel_dsi) * intel_dsi_bitrate(intel_dsi) * 1000;
+       mul = 8 * 1000000;
+       hs_tx_timeout = DIV_ROUND_UP(intel_dsi->hs_tx_timeout * mul,
+                                    divisor);
+       lp_rx_timeout = DIV_ROUND_UP(intel_dsi->lp_rx_timeout * mul, divisor);
+       ta_timeout = DIV_ROUND_UP(intel_dsi->turn_arnd_val * mul, divisor);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /* program hst_tx_timeout */
+               tmp = I915_READ(DSI_HSTX_TO(dsi_trans));
+               tmp &= ~HSTX_TIMEOUT_VALUE_MASK;
+               tmp |= HSTX_TIMEOUT_VALUE(hs_tx_timeout);
+               I915_WRITE(DSI_HSTX_TO(dsi_trans), tmp);
+
+               /* FIXME: DSI_CALIB_TO */
+
+               /* program lp_rx_host timeout */
+               tmp = I915_READ(DSI_LPRX_HOST_TO(dsi_trans));
+               tmp &= ~LPRX_TIMEOUT_VALUE_MASK;
+               tmp |= LPRX_TIMEOUT_VALUE(lp_rx_timeout);
+               I915_WRITE(DSI_LPRX_HOST_TO(dsi_trans), tmp);
+
+               /* FIXME: DSI_PWAIT_TO */
+
+               /* program turn around timeout */
+               tmp = I915_READ(DSI_TA_TO(dsi_trans));
+               tmp &= ~TA_TIMEOUT_VALUE_MASK;
+               tmp |= TA_TIMEOUT_VALUE(ta_timeout);
+               I915_WRITE(DSI_TA_TO(dsi_trans), tmp);
+       }
+}
+
+static void
+gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config)
+{
+       /* step 4a: power up all lanes of the DDI used by DSI */
+       gen11_dsi_power_up_lanes(encoder);
+
+       /* step 4b: configure lane sequencing of the Combo-PHY transmitters */
+       gen11_dsi_config_phy_lanes_sequence(encoder);
+
+       /* step 4c: configure voltage swing and skew */
+       gen11_dsi_voltage_swing_program_seq(encoder);
+
+       /* enable DDI buffer */
+       gen11_dsi_enable_ddi_buffer(encoder);
+
+       /* setup D-PHY timings */
+       gen11_dsi_setup_dphy_timings(encoder);
+
+       /* step 4h: setup DSI protocol timeouts */
+       gen11_dsi_setup_timeouts(encoder);
+
+       /* Step (4h, 4i, 4j, 4k): Configure transcoder */
+       gen11_dsi_configure_transcoder(encoder, pipe_config);
+
+       /* Step 4l: Gate DDI clocks */
+       gen11_dsi_gate_clocks(encoder);
+}
+
+static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct mipi_dsi_device *dsi;
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+       int ret;
+
+       /* set maximum return packet size */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /*
+                * FIXME: This uses the number of DW's currently in the payload
+                * receive queue. This is probably not what we want here.
+                */
+               tmp = I915_READ(DSI_CMD_RXCTL(dsi_trans));
+               tmp &= NUMBER_RX_PLOAD_DW_MASK;
+               /* multiply "Number Rx Payload DW" by 4 to get max value */
+               tmp = tmp * 4;
+               dsi = intel_dsi->dsi_hosts[port]->device;
+               ret = mipi_dsi_set_maximum_return_packet_size(dsi, tmp);
+               if (ret < 0)
+                       DRM_ERROR("error setting max return pkt size%d\n", tmp);
+       }
+
+       /* panel power on related mipi dsi vbt sequences */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
+       intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
+
+       /* ensure all panel commands dispatched before enabling transcoder */
+       wait_for_cmds_dispatched_to_panel(encoder);
+}
+
+static void gen11_dsi_pre_pll_enable(struct intel_encoder *encoder,
+                                    const struct intel_crtc_state *pipe_config,
+                                    const struct drm_connector_state *conn_state)
+{
+       /* step2: enable IO power */
+       gen11_dsi_enable_io_power(encoder);
+
+       /* step3: enable DSI PLL */
+       gen11_dsi_program_esc_clk_div(encoder);
+}
+
+static void gen11_dsi_pre_enable(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *pipe_config,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       /* step3b */
+       gen11_dsi_map_pll(encoder, pipe_config);
+
+       /* step4: enable DSI port and DPHY */
+       gen11_dsi_enable_port_and_phy(encoder, pipe_config);
+
+       /* step5: program and powerup panel */
+       gen11_dsi_powerup_panel(encoder);
+
+       /* step6c: configure transcoder timings */
+       gen11_dsi_set_transcoder_timings(encoder, pipe_config);
+
+       /* step6d: enable dsi transcoder */
+       gen11_dsi_enable_transcoder(encoder);
+
+       /* step7: enable backlight */
+       intel_panel_enable_backlight(pipe_config, conn_state);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
+}
+
+static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /* disable transcoder */
+               tmp = I915_READ(PIPECONF(dsi_trans));
+               tmp &= ~PIPECONF_ENABLE;
+               I915_WRITE(PIPECONF(dsi_trans), tmp);
+
+               /* wait for transcoder to be disabled */
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           PIPECONF(dsi_trans),
+                                           I965_PIPECONF_ACTIVE, 0, 50))
+                       DRM_ERROR("DSI trancoder not disabled\n");
+       }
+}
+
+static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
+
+       /* ensure cmds dispatched to panel */
+       wait_for_cmds_dispatched_to_panel(encoder);
+}
+
+static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+
+       /* put dsi link in ULPS */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(DSI_LP_MSG(dsi_trans));
+               tmp |= LINK_ENTER_ULPS;
+               tmp &= ~LINK_ULPS_TYPE_LP11;
+               I915_WRITE(DSI_LP_MSG(dsi_trans), tmp);
+
+               if (wait_for_us((I915_READ(DSI_LP_MSG(dsi_trans)) &
+                               LINK_IN_ULPS),
+                               10))
+                       DRM_ERROR("DSI link not in ULPS\n");
+       }
+
+       /* disable ddi function */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+               tmp &= ~TRANS_DDI_FUNC_ENABLE;
+               I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp);
+       }
+
+       /* disable port sync mode if dual link */
+       if (intel_dsi->dual_link) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       dsi_trans = dsi_port_to_transcoder(port);
+                       tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans));
+                       tmp &= ~PORT_SYNC_MODE_ENABLE;
+                       I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp);
+               }
+       }
+}
+
+static void gen11_dsi_disable_port(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       gen11_dsi_ungate_clocks(encoder);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(DDI_BUF_CTL(port));
+               tmp &= ~DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(port), tmp);
+
+               if (wait_for_us((I915_READ(DDI_BUF_CTL(port)) &
+                                DDI_BUF_IS_IDLE),
+                                8))
+                       DRM_ERROR("DDI port:%c buffer not idle\n",
+                                 port_name(port));
+       }
+       gen11_dsi_gate_clocks(encoder);
+}
+
+static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               intel_wakeref_t wakeref;
+
+               wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
+               intel_display_power_put(dev_priv,
+                                       port == PORT_A ?
+                                       POWER_DOMAIN_PORT_DDI_A_IO :
+                                       POWER_DOMAIN_PORT_DDI_B_IO,
+                                       wakeref);
+       }
+
+       /* set mode to DDI */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
+               tmp &= ~COMBO_PHY_MODE_DSI;
+               I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
+       }
+}
+
+static void gen11_dsi_disable(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       /* step1: turn off backlight */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
+       intel_panel_disable_backlight(old_conn_state);
+
+       /* step2d,e: disable transcoder and wait */
+       gen11_dsi_disable_transcoder(encoder);
+
+       /* step2f,g: powerdown panel */
+       gen11_dsi_powerdown_panel(encoder);
+
+       /* step2h,i,j: deconfig trancoder */
+       gen11_dsi_deconfigure_trancoder(encoder);
+
+       /* step3: disable port */
+       gen11_dsi_disable_port(encoder);
+
+       /* step4: disable IO power */
+       gen11_dsi_disable_io_power(encoder);
+}
+
+static void gen11_dsi_get_timings(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+
+       if (intel_dsi->dual_link) {
+               adjusted_mode->crtc_hdisplay *= 2;
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+                       adjusted_mode->crtc_hdisplay -=
+                                               intel_dsi->pixel_overlap;
+               adjusted_mode->crtc_htotal *= 2;
+       }
+       adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hdisplay;
+       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal;
+
+       if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) {
+               if (intel_dsi->dual_link) {
+                       adjusted_mode->crtc_hsync_start *= 2;
+                       adjusted_mode->crtc_hsync_end *= 2;
+               }
+       }
+       adjusted_mode->crtc_vblank_start = adjusted_mode->crtc_vdisplay;
+       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal;
+}
+
+static void gen11_dsi_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       /* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */
+       pipe_config->port_clock =
+               cnl_calc_wrpll_link(dev_priv, &pipe_config->dpll_hw_state);
+
+       pipe_config->base.adjusted_mode.crtc_clock = intel_dsi->pclk;
+       if (intel_dsi->dual_link)
+               pipe_config->base.adjusted_mode.crtc_clock *= 2;
+
+       gen11_dsi_get_timings(encoder, pipe_config);
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
+       pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
+}
+
+static int gen11_dsi_compute_config(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
+                                                  base);
+       struct intel_connector *intel_connector = intel_dsi->attached_connector;
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *fixed_mode =
+                                       intel_connector->panel.fixed_mode;
+       struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+       intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+       intel_pch_panel_fitting(crtc, pipe_config, conn_state->scaling_mode);
+
+       adjusted_mode->flags = 0;
+
+       /* Dual link goes to trancoder DSI'0' */
+       if (intel_dsi->ports == BIT(PORT_B))
+               pipe_config->cpu_transcoder = TRANSCODER_DSI_1;
+       else
+               pipe_config->cpu_transcoder = TRANSCODER_DSI_0;
+
+       pipe_config->clock_set = true;
+       pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5;
+
+       return 0;
+}
+
+static void gen11_dsi_get_power_domains(struct intel_encoder *encoder,
+                                       struct intel_crtc_state *crtc_state)
+{
+       get_dsi_io_power_domains(to_i915(encoder->base.dev),
+                                enc_to_intel_dsi(&encoder->base));
+}
+
+static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum transcoder dsi_trans;
+       intel_wakeref_t wakeref;
+       enum port port;
+       bool ret = false;
+       u32 tmp;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+               case TRANS_DDI_EDP_INPUT_A_ON:
+                       *pipe = PIPE_A;
+                       break;
+               case TRANS_DDI_EDP_INPUT_B_ONOFF:
+                       *pipe = PIPE_B;
+                       break;
+               case TRANS_DDI_EDP_INPUT_C_ONOFF:
+                       *pipe = PIPE_C;
+                       break;
+               default:
+                       DRM_ERROR("Invalid PIPE input\n");
+                       goto out;
+               }
+
+               tmp = I915_READ(PIPECONF(dsi_trans));
+               ret = tmp & PIPECONF_ENABLE;
+       }
+out:
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+       return ret;
+}
+
+static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+       intel_encoder_destroy(encoder);
+}
+
+static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
+       .destroy = gen11_dsi_encoder_destroy,
+};
+
+static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs gen11_dsi_connector_helper_funcs = {
+       .get_modes = intel_dsi_get_modes,
+       .mode_valid = intel_dsi_mode_valid,
+       .atomic_check = intel_digital_connector_atomic_check,
+};
+
+static int gen11_dsi_host_attach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *dsi)
+{
+       return 0;
+}
+
+static int gen11_dsi_host_detach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *dsi)
+{
+       return 0;
+}
+
+static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host,
+                                      const struct mipi_dsi_msg *msg)
+{
+       struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
+       struct mipi_dsi_packet dsi_pkt;
+       ssize_t ret;
+       bool enable_lpdt = false;
+
+       ret = mipi_dsi_create_packet(&dsi_pkt, msg);
+       if (ret < 0)
+               return ret;
+
+       if (msg->flags & MIPI_DSI_MSG_USE_LPM)
+               enable_lpdt = true;
+
+       /* send packet header */
+       ret  = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt);
+       if (ret < 0)
+               return ret;
+
+       /* only long packet contains payload */
+       if (mipi_dsi_packet_format_is_long(msg->type)) {
+               ret = dsi_send_pkt_payld(intel_dsi_host, dsi_pkt);
+               if (ret < 0)
+                       return ret;
+       }
+
+       //TODO: add payload receive code if needed
+
+       ret = sizeof(dsi_pkt.header) + dsi_pkt.payload_length;
+
+       return ret;
+}
+
+static const struct mipi_dsi_host_ops gen11_dsi_host_ops = {
+       .attach = gen11_dsi_host_attach,
+       .detach = gen11_dsi_host_detach,
+       .transfer = gen11_dsi_host_transfer,
+};
+
+#define ICL_PREPARE_CNT_MAX    0x7
+#define ICL_CLK_ZERO_CNT_MAX   0xf
+#define ICL_TRAIL_CNT_MAX      0x7
+#define ICL_TCLK_PRE_CNT_MAX   0x3
+#define ICL_TCLK_POST_CNT_MAX  0x7
+#define ICL_HS_ZERO_CNT_MAX    0xf
+#define ICL_EXIT_ZERO_CNT_MAX  0x7
+
+static void icl_dphy_param_init(struct intel_dsi *intel_dsi)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
+       u32 tlpx_ns;
+       u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
+       u32 ths_prepare_ns, tclk_trail_ns;
+       u32 hs_zero_cnt;
+       u32 tclk_pre_cnt, tclk_post_cnt;
+
+       tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
+
+       tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail);
+       ths_prepare_ns = max(mipi_config->ths_prepare,
+                            mipi_config->tclk_prepare);
+
+       /*
+        * prepare cnt in escape clocks
+        * this field represents a hexadecimal value with a precision
+        * of 1.2 – i.e. the most significant bit is the integer
+        * and the least significant 2 bits are fraction bits.
+        * so, the field can represent a range of 0.25 to 1.75
+        */
+       prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * 4, tlpx_ns);
+       if (prepare_cnt > ICL_PREPARE_CNT_MAX) {
+               DRM_DEBUG_KMS("prepare_cnt out of range (%d)\n", prepare_cnt);
+               prepare_cnt = ICL_PREPARE_CNT_MAX;
+       }
+
+       /* clk zero count in escape clocks */
+       clk_zero_cnt = DIV_ROUND_UP(mipi_config->tclk_prepare_clkzero -
+                                   ths_prepare_ns, tlpx_ns);
+       if (clk_zero_cnt > ICL_CLK_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("clk_zero_cnt out of range (%d)\n", clk_zero_cnt);
+               clk_zero_cnt = ICL_CLK_ZERO_CNT_MAX;
+       }
+
+       /* trail cnt in escape clocks*/
+       trail_cnt = DIV_ROUND_UP(tclk_trail_ns, tlpx_ns);
+       if (trail_cnt > ICL_TRAIL_CNT_MAX) {
+               DRM_DEBUG_KMS("trail_cnt out of range (%d)\n", trail_cnt);
+               trail_cnt = ICL_TRAIL_CNT_MAX;
+       }
+
+       /* tclk pre count in escape clocks */
+       tclk_pre_cnt = DIV_ROUND_UP(mipi_config->tclk_pre, tlpx_ns);
+       if (tclk_pre_cnt > ICL_TCLK_PRE_CNT_MAX) {
+               DRM_DEBUG_KMS("tclk_pre_cnt out of range (%d)\n", tclk_pre_cnt);
+               tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX;
+       }
+
+       /* tclk post count in escape clocks */
+       tclk_post_cnt = DIV_ROUND_UP(mipi_config->tclk_post, tlpx_ns);
+       if (tclk_post_cnt > ICL_TCLK_POST_CNT_MAX) {
+               DRM_DEBUG_KMS("tclk_post_cnt out of range (%d)\n", tclk_post_cnt);
+               tclk_post_cnt = ICL_TCLK_POST_CNT_MAX;
+       }
+
+       /* hs zero cnt in escape clocks */
+       hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero -
+                                  ths_prepare_ns, tlpx_ns);
+       if (hs_zero_cnt > ICL_HS_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("hs_zero_cnt out of range (%d)\n", hs_zero_cnt);
+               hs_zero_cnt = ICL_HS_ZERO_CNT_MAX;
+       }
+
+       /* hs exit zero cnt in escape clocks */
+       exit_zero_cnt = DIV_ROUND_UP(mipi_config->ths_exit, tlpx_ns);
+       if (exit_zero_cnt > ICL_EXIT_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("exit_zero_cnt out of range (%d)\n", exit_zero_cnt);
+               exit_zero_cnt = ICL_EXIT_ZERO_CNT_MAX;
+       }
+
+       /* clock lane dphy timings */
+       intel_dsi->dphy_reg = (CLK_PREPARE_OVERRIDE |
+                              CLK_PREPARE(prepare_cnt) |
+                              CLK_ZERO_OVERRIDE |
+                              CLK_ZERO(clk_zero_cnt) |
+                              CLK_PRE_OVERRIDE |
+                              CLK_PRE(tclk_pre_cnt) |
+                              CLK_POST_OVERRIDE |
+                              CLK_POST(tclk_post_cnt) |
+                              CLK_TRAIL_OVERRIDE |
+                              CLK_TRAIL(trail_cnt));
+
+       /* data lanes dphy timings */
+       intel_dsi->dphy_data_lane_reg = (HS_PREPARE_OVERRIDE |
+                                        HS_PREPARE(prepare_cnt) |
+                                        HS_ZERO_OVERRIDE |
+                                        HS_ZERO(hs_zero_cnt) |
+                                        HS_TRAIL_OVERRIDE |
+                                        HS_TRAIL(trail_cnt) |
+                                        HS_EXIT_OVERRIDE |
+                                        HS_EXIT(exit_zero_cnt));
+
+       intel_dsi_log_params(intel_dsi);
+}
+
+void icl_dsi_init(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = &dev_priv->drm;
+       struct intel_dsi *intel_dsi;
+       struct intel_encoder *encoder;
+       struct intel_connector *intel_connector;
+       struct drm_connector *connector;
+       struct drm_display_mode *fixed_mode;
+       enum port port;
+
+       if (!intel_bios_is_dsi_present(dev_priv, &port))
+               return;
+
+       intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
+       if (!intel_dsi)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(intel_dsi);
+               return;
+       }
+
+       encoder = &intel_dsi->base;
+       intel_dsi->attached_connector = intel_connector;
+       connector = &intel_connector->base;
+
+       /* register DSI encoder with DRM subsystem */
+       drm_encoder_init(dev, &encoder->base, &gen11_dsi_encoder_funcs,
+                        DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
+
+       encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
+       encoder->pre_enable = gen11_dsi_pre_enable;
+       encoder->disable = gen11_dsi_disable;
+       encoder->port = port;
+       encoder->get_config = gen11_dsi_get_config;
+       encoder->update_pipe = intel_panel_update_backlight;
+       encoder->compute_config = gen11_dsi_compute_config;
+       encoder->get_hw_state = gen11_dsi_get_hw_state;
+       encoder->type = INTEL_OUTPUT_DSI;
+       encoder->cloneable = 0;
+       encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C);
+       encoder->power_domain = POWER_DOMAIN_PORT_DSI;
+       encoder->get_power_domains = gen11_dsi_get_power_domains;
+
+       /* register DSI connector with DRM subsystem */
+       drm_connector_init(dev, connector, &gen11_dsi_connector_funcs,
+                          DRM_MODE_CONNECTOR_DSI);
+       drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
+       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       /* attach connector to encoder */
+       intel_connector_attach_encoder(intel_connector, encoder);
+
+       mutex_lock(&dev->mode_config.mutex);
+       fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       if (!fixed_mode) {
+               DRM_ERROR("DSI fixed mode info missing\n");
+               goto err;
+       }
+
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
+       intel_panel_setup_backlight(connector, INVALID_PIPE);
+
+       if (dev_priv->vbt.dsi.config->dual_link)
+               intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B);
+       else
+               intel_dsi->ports = BIT(port);
+
+       intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports;
+       intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               struct intel_dsi_host *host;
+
+               host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port);
+               if (!host)
+                       goto err;
+
+               intel_dsi->dsi_hosts[port] = host;
+       }
+
+       if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
+               DRM_DEBUG_KMS("no device found\n");
+               goto err;
+       }
+
+       icl_dphy_param_init(intel_dsi);
+       return;
+
+err:
+       drm_encoder_cleanup(&encoder->base);
+       kfree(intel_dsi);
+       kfree(intel_connector);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
new file mode 100644 (file)
index 0000000..3fcf2f8
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_connector.h"
+#include "intel_crt.h"
+#include "intel_ddi.h"
+#include "intel_drv.h"
+#include "intel_fifo_underrun.h"
+#include "intel_gmbus.h"
+#include "intel_hotplug.h"
+
+/* Here's the desired hotplug mode */
+#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |               \
+                          ADPA_CRT_HOTPLUG_WARMUP_10MS |               \
+                          ADPA_CRT_HOTPLUG_SAMPLE_4S |                 \
+                          ADPA_CRT_HOTPLUG_VOLTAGE_50 |                \
+                          ADPA_CRT_HOTPLUG_VOLREF_325MV |              \
+                          ADPA_CRT_HOTPLUG_ENABLE)
+
+struct intel_crt {
+       struct intel_encoder base;
+       /* DPMS state is stored in the connector, which we need in the
+        * encoder's enable/disable callbacks */
+       struct intel_connector *connector;
+       bool force_hotplug_required;
+       i915_reg_t adpa_reg;
+};
+
+static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
+{
+       return container_of(encoder, struct intel_crt, base);
+}
+
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
+{
+       return intel_encoder_to_crt(intel_attached_encoder(connector));
+}
+
+bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
+                           i915_reg_t adpa_reg, enum pipe *pipe)
+{
+       u32 val;
+
+       val = I915_READ(adpa_reg);
+
+       /* asserts want to know the pipe even if the port is disabled */
+       if (HAS_PCH_CPT(dev_priv))
+               *pipe = (val & ADPA_PIPE_SEL_MASK_CPT) >> ADPA_PIPE_SEL_SHIFT_CPT;
+       else
+               *pipe = (val & ADPA_PIPE_SEL_MASK) >> ADPA_PIPE_SEL_SHIFT;
+
+       return val & ADPA_DAC_ENABLE;
+}
+
+static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       intel_wakeref_t wakeref;
+       bool ret;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       ret = intel_crt_port_enabled(dev_priv, crt->adpa_reg, pipe);
+
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+
+       return ret;
+}
+
+static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(crt->adpa_reg);
+
+       if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       return flags;
+}
+
+static void intel_crt_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config)
+{
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG);
+
+       pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
+
+       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
+}
+
+static void hsw_crt_get_config(struct intel_encoder *encoder,
+                              struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       intel_ddi_get_config(encoder, pipe_config);
+
+       pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
+                                             DRM_MODE_FLAG_NHSYNC |
+                                             DRM_MODE_FLAG_PVSYNC |
+                                             DRM_MODE_FLAG_NVSYNC);
+       pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
+
+       pipe_config->base.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv);
+}
+
+/* Note: The caller is required to filter out dpms modes not supported by the
+ * platform. */
+static void intel_crt_set_dpms(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              int mode)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
+       u32 adpa;
+
+       if (INTEL_GEN(dev_priv) >= 5)
+               adpa = ADPA_HOTPLUG_BITS;
+       else
+               adpa = 0;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               adpa |= ADPA_HSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               adpa |= ADPA_VSYNC_ACTIVE_HIGH;
+
+       /* For CPT allow 3 pipe config, for others just use A or B */
+       if (HAS_PCH_LPT(dev_priv))
+               ; /* Those bits don't exist here */
+       else if (HAS_PCH_CPT(dev_priv))
+               adpa |= ADPA_PIPE_SEL_CPT(crtc->pipe);
+       else
+               adpa |= ADPA_PIPE_SEL(crtc->pipe);
+
+       if (!HAS_PCH_SPLIT(dev_priv))
+               I915_WRITE(BCLRPAT(crtc->pipe), 0);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               adpa |= ADPA_DAC_ENABLE;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+               adpa |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
+               break;
+       case DRM_MODE_DPMS_SUSPEND:
+               adpa |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
+               break;
+       case DRM_MODE_DPMS_OFF:
+               adpa |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
+               break;
+       }
+
+       I915_WRITE(crt->adpa_reg, adpa);
+}
+
+static void intel_disable_crt(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+{
+       intel_crt_set_dpms(encoder, old_crtc_state, DRM_MODE_DPMS_OFF);
+}
+
+static void pch_disable_crt(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *old_crtc_state,
+                           const struct drm_connector_state *old_conn_state)
+{
+}
+
+static void pch_post_disable_crt(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *old_crtc_state,
+                                const struct drm_connector_state *old_conn_state)
+{
+       intel_disable_crt(encoder, old_crtc_state, old_conn_state);
+}
+
+static void hsw_disable_crt(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *old_crtc_state,
+                           const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       WARN_ON(!old_crtc_state->has_pch_encoder);
+
+       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+}
+
+static void hsw_post_disable_crt(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *old_crtc_state,
+                                const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       intel_ddi_disable_pipe_clock(old_crtc_state);
+
+       pch_post_disable_crt(encoder, old_crtc_state, old_conn_state);
+
+       lpt_disable_pch_transcoder(dev_priv);
+       lpt_disable_iclkip(dev_priv);
+
+       intel_ddi_fdi_post_disable(encoder, old_crtc_state, old_conn_state);
+
+       WARN_ON(!old_crtc_state->has_pch_encoder);
+
+       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+}
+
+static void hsw_pre_pll_enable_crt(struct intel_encoder *encoder,
+                                  const struct intel_crtc_state *crtc_state,
+                                  const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       WARN_ON(!crtc_state->has_pch_encoder);
+
+       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+}
+
+static void hsw_pre_enable_crt(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       enum pipe pipe = crtc->pipe;
+
+       WARN_ON(!crtc_state->has_pch_encoder);
+
+       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
+       dev_priv->display.fdi_link_train(crtc, crtc_state);
+
+       intel_ddi_enable_pipe_clock(crtc_state);
+}
+
+static void hsw_enable_crt(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       enum pipe pipe = crtc->pipe;
+
+       WARN_ON(!crtc_state->has_pch_encoder);
+
+       intel_crt_set_dpms(encoder, crtc_state, DRM_MODE_DPMS_ON);
+
+       intel_wait_for_vblank(dev_priv, pipe);
+       intel_wait_for_vblank(dev_priv, pipe);
+       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+}
+
+static void intel_enable_crt(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *crtc_state,
+                            const struct drm_connector_state *conn_state)
+{
+       intel_crt_set_dpms(encoder, crtc_state, DRM_MODE_DPMS_ON);
+}
+
+static enum drm_mode_status
+intel_crt_mode_valid(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       int max_dotclk = dev_priv->max_dotclk_freq;
+       int max_clock;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (mode->clock < 25000)
+               return MODE_CLOCK_LOW;
+
+       if (HAS_PCH_LPT(dev_priv))
+               max_clock = 180000;
+       else if (IS_VALLEYVIEW(dev_priv))
+               /*
+                * 270 MHz due to current DPLL limits,
+                * DAC limit supposedly 355 MHz.
+                */
+               max_clock = 270000;
+       else if (IS_GEN_RANGE(dev_priv, 3, 4))
+               max_clock = 400000;
+       else
+               max_clock = 350000;
+       if (mode->clock > max_clock)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       /* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */
+       if (HAS_PCH_LPT(dev_priv) &&
+           (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2))
+               return MODE_CLOCK_HIGH;
+
+       /* HSW/BDW FDI limited to 4k */
+       if (mode->hdisplay > 4096)
+               return MODE_H_ILLEGAL;
+
+       return MODE_OK;
+}
+
+static int intel_crt_compute_config(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
+{
+       struct drm_display_mode *adjusted_mode =
+               &pipe_config->base.adjusted_mode;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       return 0;
+}
+
+static int pch_crt_compute_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct drm_connector_state *conn_state)
+{
+       struct drm_display_mode *adjusted_mode =
+               &pipe_config->base.adjusted_mode;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       pipe_config->has_pch_encoder = true;
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       return 0;
+}
+
+static int hsw_crt_compute_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct drm_display_mode *adjusted_mode =
+               &pipe_config->base.adjusted_mode;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       /* HSW/BDW FDI limited to 4k */
+       if (adjusted_mode->crtc_hdisplay > 4096 ||
+           adjusted_mode->crtc_hblank_start > 4096)
+               return -EINVAL;
+
+       pipe_config->has_pch_encoder = true;
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       /* LPT FDI RX only supports 8bpc. */
+       if (HAS_PCH_LPT(dev_priv)) {
+               if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) {
+                       DRM_DEBUG_KMS("LPT only supports 24bpp\n");
+                       return -EINVAL;
+               }
+
+               pipe_config->pipe_bpp = 24;
+       }
+
+       /* FDI must always be 2.7 GHz */
+       pipe_config->port_clock = 135000 * 2;
+
+       return 0;
+}
+
+static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_crt *crt = intel_attached_crt(connector);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 adpa;
+       bool ret;
+
+       /* The first time through, trigger an explicit detection cycle */
+       if (crt->force_hotplug_required) {
+               bool turn_off_dac = HAS_PCH_SPLIT(dev_priv);
+               u32 save_adpa;
+
+               crt->force_hotplug_required = 0;
+
+               save_adpa = adpa = I915_READ(crt->adpa_reg);
+               DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
+
+               adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+               if (turn_off_dac)
+                       adpa &= ~ADPA_DAC_ENABLE;
+
+               I915_WRITE(crt->adpa_reg, adpa);
+
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           crt->adpa_reg,
+                                           ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 0,
+                                           1000))
+                       DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
+
+               if (turn_off_dac) {
+                       I915_WRITE(crt->adpa_reg, save_adpa);
+                       POSTING_READ(crt->adpa_reg);
+               }
+       }
+
+       /* Check the status to see if both blue and green are on now */
+       adpa = I915_READ(crt->adpa_reg);
+       if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
+               ret = true;
+       else
+               ret = false;
+       DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
+
+       return ret;
+}
+
+static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_crt *crt = intel_attached_crt(connector);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       bool reenable_hpd;
+       u32 adpa;
+       bool ret;
+       u32 save_adpa;
+
+       /*
+        * Doing a force trigger causes a hpd interrupt to get sent, which can
+        * get us stuck in a loop if we're polling:
+        *  - We enable power wells and reset the ADPA
+        *  - output_poll_exec does force probe on VGA, triggering a hpd
+        *  - HPD handler waits for poll to unlock dev->mode_config.mutex
+        *  - output_poll_exec shuts off the ADPA, unlocks
+        *    dev->mode_config.mutex
+        *  - HPD handler runs, resets ADPA and brings us back to the start
+        *
+        * Just disable HPD interrupts here to prevent this
+        */
+       reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin);
+
+       save_adpa = adpa = I915_READ(crt->adpa_reg);
+       DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
+
+       adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+
+       I915_WRITE(crt->adpa_reg, adpa);
+
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   crt->adpa_reg,
+                                   ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 0,
+                                   1000)) {
+               DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
+               I915_WRITE(crt->adpa_reg, save_adpa);
+       }
+
+       /* Check the status to see if both blue and green are on now */
+       adpa = I915_READ(crt->adpa_reg);
+       if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
+               ret = true;
+       else
+               ret = false;
+
+       DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
+
+       if (reenable_hpd)
+               intel_hpd_enable(dev_priv, crt->base.hpd_pin);
+
+       return ret;
+}
+
+static bool intel_crt_detect_hotplug(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 stat;
+       bool ret = false;
+       int i, tries = 0;
+
+       if (HAS_PCH_SPLIT(dev_priv))
+               return intel_ironlake_crt_detect_hotplug(connector);
+
+       if (IS_VALLEYVIEW(dev_priv))
+               return valleyview_crt_detect_hotplug(connector);
+
+       /*
+        * On 4 series desktop, CRT detect sequence need to be done twice
+        * to get a reliable result.
+        */
+
+       if (IS_G45(dev_priv))
+               tries = 2;
+       else
+               tries = 1;
+
+       for (i = 0; i < tries ; i++) {
+               /* turn on the FORCE_DETECT */
+               i915_hotplug_interrupt_update(dev_priv,
+                                             CRT_HOTPLUG_FORCE_DETECT,
+                                             CRT_HOTPLUG_FORCE_DETECT);
+               /* wait for FORCE_DETECT to go off */
+               if (intel_wait_for_register(&dev_priv->uncore, PORT_HOTPLUG_EN,
+                                           CRT_HOTPLUG_FORCE_DETECT, 0,
+                                           1000))
+                       DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
+       }
+
+       stat = I915_READ(PORT_HOTPLUG_STAT);
+       if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
+               ret = true;
+
+       /* clear the interrupt we just generated, if any */
+       I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
+
+       i915_hotplug_interrupt_update(dev_priv, CRT_HOTPLUG_FORCE_DETECT, 0);
+
+       return ret;
+}
+
+static struct edid *intel_crt_get_edid(struct drm_connector *connector,
+                               struct i2c_adapter *i2c)
+{
+       struct edid *edid;
+
+       edid = drm_get_edid(connector, i2c);
+
+       if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
+               DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n");
+               intel_gmbus_force_bit(i2c, true);
+               edid = drm_get_edid(connector, i2c);
+               intel_gmbus_force_bit(i2c, false);
+       }
+
+       return edid;
+}
+
+/* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */
+static int intel_crt_ddc_get_modes(struct drm_connector *connector,
+                               struct i2c_adapter *adapter)
+{
+       struct edid *edid;
+       int ret;
+
+       edid = intel_crt_get_edid(connector, adapter);
+       if (!edid)
+               return 0;
+
+       ret = intel_connector_update_modes(connector, edid);
+       kfree(edid);
+
+       return ret;
+}
+
+static bool intel_crt_detect_ddc(struct drm_connector *connector)
+{
+       struct intel_crt *crt = intel_attached_crt(connector);
+       struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev);
+       struct edid *edid;
+       struct i2c_adapter *i2c;
+       bool ret = false;
+
+       BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
+
+       i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
+       edid = intel_crt_get_edid(connector, i2c);
+
+       if (edid) {
+               bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
+
+               /*
+                * This may be a DVI-I connector with a shared DDC
+                * link between analog and digital outputs, so we
+                * have to check the EDID input spec of the attached device.
+                */
+               if (!is_digital) {
+                       DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+                       ret = true;
+               } else {
+                       DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
+               }
+       } else {
+               DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
+       }
+
+       kfree(edid);
+
+       return ret;
+}
+
+static enum drm_connector_status
+intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
+{
+       struct drm_device *dev = crt->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_uncore *uncore = &dev_priv->uncore;
+       u32 save_bclrpat;
+       u32 save_vtotal;
+       u32 vtotal, vactive;
+       u32 vsample;
+       u32 vblank, vblank_start, vblank_end;
+       u32 dsl;
+       i915_reg_t bclrpat_reg, vtotal_reg,
+               vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg;
+       u8 st00;
+       enum drm_connector_status status;
+
+       DRM_DEBUG_KMS("starting load-detect on CRT\n");
+
+       bclrpat_reg = BCLRPAT(pipe);
+       vtotal_reg = VTOTAL(pipe);
+       vblank_reg = VBLANK(pipe);
+       vsync_reg = VSYNC(pipe);
+       pipeconf_reg = PIPECONF(pipe);
+       pipe_dsl_reg = PIPEDSL(pipe);
+
+       save_bclrpat = intel_uncore_read(uncore, bclrpat_reg);
+       save_vtotal = intel_uncore_read(uncore, vtotal_reg);
+       vblank = intel_uncore_read(uncore, vblank_reg);
+
+       vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
+       vactive = (save_vtotal & 0x7ff) + 1;
+
+       vblank_start = (vblank & 0xfff) + 1;
+       vblank_end = ((vblank >> 16) & 0xfff) + 1;
+
+       /* Set the border color to purple. */
+       intel_uncore_write(uncore, bclrpat_reg, 0x500050);
+
+       if (!IS_GEN(dev_priv, 2)) {
+               u32 pipeconf = intel_uncore_read(uncore, pipeconf_reg);
+               intel_uncore_write(uncore,
+                                  pipeconf_reg,
+                                  pipeconf | PIPECONF_FORCE_BORDER);
+               intel_uncore_posting_read(uncore, pipeconf_reg);
+               /* Wait for next Vblank to substitue
+                * border color for Color info */
+               intel_wait_for_vblank(dev_priv, pipe);
+               st00 = intel_uncore_read8(uncore, _VGA_MSR_WRITE);
+               status = ((st00 & (1 << 4)) != 0) ?
+                       connector_status_connected :
+                       connector_status_disconnected;
+
+               intel_uncore_write(uncore, pipeconf_reg, pipeconf);
+       } else {
+               bool restore_vblank = false;
+               int count, detect;
+
+               /*
+               * If there isn't any border, add some.
+               * Yes, this will flicker
+               */
+               if (vblank_start <= vactive && vblank_end >= vtotal) {
+                       u32 vsync = I915_READ(vsync_reg);
+                       u32 vsync_start = (vsync & 0xffff) + 1;
+
+                       vblank_start = vsync_start;
+                       intel_uncore_write(uncore,
+                                          vblank_reg,
+                                          (vblank_start - 1) |
+                                          ((vblank_end - 1) << 16));
+                       restore_vblank = true;
+               }
+               /* sample in the vertical border, selecting the larger one */
+               if (vblank_start - vactive >= vtotal - vblank_end)
+                       vsample = (vblank_start + vactive) >> 1;
+               else
+                       vsample = (vtotal + vblank_end) >> 1;
+
+               /*
+                * Wait for the border to be displayed
+                */
+               while (intel_uncore_read(uncore, pipe_dsl_reg) >= vactive)
+                       ;
+               while ((dsl = intel_uncore_read(uncore, pipe_dsl_reg)) <=
+                      vsample)
+                       ;
+               /*
+                * Watch ST00 for an entire scanline
+                */
+               detect = 0;
+               count = 0;
+               do {
+                       count++;
+                       /* Read the ST00 VGA status register */
+                       st00 = intel_uncore_read8(uncore, _VGA_MSR_WRITE);
+                       if (st00 & (1 << 4))
+                               detect++;
+               } while ((intel_uncore_read(uncore, pipe_dsl_reg) == dsl));
+
+               /* restore vblank if necessary */
+               if (restore_vblank)
+                       intel_uncore_write(uncore, vblank_reg, vblank);
+               /*
+                * If more than 3/4 of the scanline detected a monitor,
+                * then it is assumed to be present. This works even on i830,
+                * where there isn't any way to force the border color across
+                * the screen
+                */
+               status = detect * 4 > count * 3 ?
+                        connector_status_connected :
+                        connector_status_disconnected;
+       }
+
+       /* Restore previous settings */
+       intel_uncore_write(uncore, bclrpat_reg, save_bclrpat);
+
+       return status;
+}
+
+static int intel_spurious_crt_detect_dmi_callback(const struct dmi_system_id *id)
+{
+       DRM_DEBUG_DRIVER("Skipping CRT detection for %s\n", id->ident);
+       return 1;
+}
+
+static const struct dmi_system_id intel_spurious_crt_detect[] = {
+       {
+               .callback = intel_spurious_crt_detect_dmi_callback,
+               .ident = "ACER ZGB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
+               },
+       },
+       {
+               .callback = intel_spurious_crt_detect_dmi_callback,
+               .ident = "Intel DZ77BH-55K",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "DZ77BH-55K"),
+               },
+       },
+       { }
+};
+
+static int
+intel_crt_detect(struct drm_connector *connector,
+                struct drm_modeset_acquire_ctx *ctx,
+                bool force)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_crt *crt = intel_attached_crt(connector);
+       struct intel_encoder *intel_encoder = &crt->base;
+       intel_wakeref_t wakeref;
+       int status, ret;
+       struct intel_load_detect_pipe tmp;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
+                     connector->base.id, connector->name,
+                     force);
+
+       if (i915_modparams.load_detect_test) {
+               wakeref = intel_display_power_get(dev_priv,
+                                                 intel_encoder->power_domain);
+               goto load_detect;
+       }
+
+       /* Skip machines without VGA that falsely report hotplug events */
+       if (dmi_check_system(intel_spurious_crt_detect))
+               return connector_status_disconnected;
+
+       wakeref = intel_display_power_get(dev_priv,
+                                         intel_encoder->power_domain);
+
+       if (I915_HAS_HOTPLUG(dev_priv)) {
+               /* We can not rely on the HPD pin always being correctly wired
+                * up, for example many KVM do not pass it through, and so
+                * only trust an assertion that the monitor is connected.
+                */
+               if (intel_crt_detect_hotplug(connector)) {
+                       DRM_DEBUG_KMS("CRT detected via hotplug\n");
+                       status = connector_status_connected;
+                       goto out;
+               } else
+                       DRM_DEBUG_KMS("CRT not detected via hotplug\n");
+       }
+
+       if (intel_crt_detect_ddc(connector)) {
+               status = connector_status_connected;
+               goto out;
+       }
+
+       /* Load detection is broken on HPD capable machines. Whoever wants a
+        * broken monitor (without edid) to work behind a broken kvm (that fails
+        * to have the right resistors for HP detection) needs to fix this up.
+        * For now just bail out. */
+       if (I915_HAS_HOTPLUG(dev_priv)) {
+               status = connector_status_disconnected;
+               goto out;
+       }
+
+load_detect:
+       if (!force) {
+               status = connector->status;
+               goto out;
+       }
+
+       /* for pre-945g platforms use load detect */
+       ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
+       if (ret > 0) {
+               if (intel_crt_detect_ddc(connector))
+                       status = connector_status_connected;
+               else if (INTEL_GEN(dev_priv) < 4)
+                       status = intel_crt_load_detect(crt,
+                               to_intel_crtc(connector->state->crtc)->pipe);
+               else if (i915_modparams.load_detect_test)
+                       status = connector_status_disconnected;
+               else
+                       status = connector_status_unknown;
+               intel_release_load_detect_pipe(connector, &tmp, ctx);
+       } else if (ret == 0) {
+               status = connector_status_unknown;
+       } else {
+               status = ret;
+       }
+
+out:
+       intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
+       return status;
+}
+
+static int intel_crt_get_modes(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crt *crt = intel_attached_crt(connector);
+       struct intel_encoder *intel_encoder = &crt->base;
+       intel_wakeref_t wakeref;
+       struct i2c_adapter *i2c;
+       int ret;
+
+       wakeref = intel_display_power_get(dev_priv,
+                                         intel_encoder->power_domain);
+
+       i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
+       ret = intel_crt_ddc_get_modes(connector, i2c);
+       if (ret || !IS_G4X(dev_priv))
+               goto out;
+
+       /* Try to probe digital port for output in DVI-I -> VGA mode. */
+       i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB);
+       ret = intel_crt_ddc_get_modes(connector, i2c);
+
+out:
+       intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
+
+       return ret;
+}
+
+void intel_crt_reset(struct drm_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct intel_crt *crt = intel_encoder_to_crt(to_intel_encoder(encoder));
+
+       if (INTEL_GEN(dev_priv) >= 5) {
+               u32 adpa;
+
+               adpa = I915_READ(crt->adpa_reg);
+               adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+               adpa |= ADPA_HOTPLUG_BITS;
+               I915_WRITE(crt->adpa_reg, adpa);
+               POSTING_READ(crt->adpa_reg);
+
+               DRM_DEBUG_KMS("crt adpa set to 0x%x\n", adpa);
+               crt->force_hotplug_required = 1;
+       }
+
+}
+
+/*
+ * Routines for controlling stuff on the analog port
+ */
+
+static const struct drm_connector_funcs intel_crt_connector_funcs = {
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
+       .detect_ctx = intel_crt_detect,
+       .mode_valid = intel_crt_mode_valid,
+       .get_modes = intel_crt_get_modes,
+};
+
+static const struct drm_encoder_funcs intel_crt_enc_funcs = {
+       .reset = intel_crt_reset,
+       .destroy = intel_encoder_destroy,
+};
+
+void intel_crt_init(struct drm_i915_private *dev_priv)
+{
+       struct drm_connector *connector;
+       struct intel_crt *crt;
+       struct intel_connector *intel_connector;
+       i915_reg_t adpa_reg;
+       u32 adpa;
+
+       if (HAS_PCH_SPLIT(dev_priv))
+               adpa_reg = PCH_ADPA;
+       else if (IS_VALLEYVIEW(dev_priv))
+               adpa_reg = VLV_ADPA;
+       else
+               adpa_reg = ADPA;
+
+       adpa = I915_READ(adpa_reg);
+       if ((adpa & ADPA_DAC_ENABLE) == 0) {
+               /*
+                * On some machines (some IVB at least) CRT can be
+                * fused off, but there's no known fuse bit to
+                * indicate that. On these machine the ADPA register
+                * works normally, except the DAC enable bit won't
+                * take. So the only way to tell is attempt to enable
+                * it and see what happens.
+                */
+               I915_WRITE(adpa_reg, adpa | ADPA_DAC_ENABLE |
+                          ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
+               if ((I915_READ(adpa_reg) & ADPA_DAC_ENABLE) == 0)
+                       return;
+               I915_WRITE(adpa_reg, adpa);
+       }
+
+       crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
+       if (!crt)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(crt);
+               return;
+       }
+
+       connector = &intel_connector->base;
+       crt->connector = intel_connector;
+       drm_connector_init(&dev_priv->drm, &intel_connector->base,
+                          &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+       drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs,
+                        DRM_MODE_ENCODER_DAC, "CRT");
+
+       intel_connector_attach_encoder(intel_connector, &crt->base);
+
+       crt->base.type = INTEL_OUTPUT_ANALOG;
+       crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI);
+       if (IS_I830(dev_priv))
+               crt->base.crtc_mask = (1 << 0);
+       else
+               crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+
+       if (IS_GEN(dev_priv, 2))
+               connector->interlace_allowed = 0;
+       else
+               connector->interlace_allowed = 1;
+       connector->doublescan_allowed = 0;
+
+       crt->adpa_reg = adpa_reg;
+
+       crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
+
+       if (I915_HAS_HOTPLUG(dev_priv) &&
+           !dmi_check_system(intel_spurious_crt_detect)) {
+               crt->base.hpd_pin = HPD_CRT;
+               crt->base.hotplug = intel_encoder_hotplug;
+       }
+
+       if (HAS_DDI(dev_priv)) {
+               crt->base.port = PORT_E;
+               crt->base.get_config = hsw_crt_get_config;
+               crt->base.get_hw_state = intel_ddi_get_hw_state;
+               crt->base.compute_config = hsw_crt_compute_config;
+               crt->base.pre_pll_enable = hsw_pre_pll_enable_crt;
+               crt->base.pre_enable = hsw_pre_enable_crt;
+               crt->base.enable = hsw_enable_crt;
+               crt->base.disable = hsw_disable_crt;
+               crt->base.post_disable = hsw_post_disable_crt;
+       } else {
+               if (HAS_PCH_SPLIT(dev_priv)) {
+                       crt->base.compute_config = pch_crt_compute_config;
+                       crt->base.disable = pch_disable_crt;
+                       crt->base.post_disable = pch_post_disable_crt;
+               } else {
+                       crt->base.compute_config = intel_crt_compute_config;
+                       crt->base.disable = intel_disable_crt;
+               }
+               crt->base.port = PORT_NONE;
+               crt->base.get_config = intel_crt_get_config;
+               crt->base.get_hw_state = intel_crt_get_hw_state;
+               crt->base.enable = intel_enable_crt;
+       }
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
+
+       if (!I915_HAS_HOTPLUG(dev_priv))
+               intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+
+       /*
+        * Configure the automatic hotplug detection stuff
+        */
+       crt->force_hotplug_required = 0;
+
+       /*
+        * TODO: find a proper way to discover whether we need to set the the
+        * polarity and link reversal bits or not, instead of relying on the
+        * BIOS.
+        */
+       if (HAS_PCH_LPT(dev_priv)) {
+               u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
+                                FDI_RX_LINK_REVERSAL_OVERRIDE;
+
+               dev_priv->fdi_rx_config = I915_READ(FDI_RX_CTL(PIPE_A)) & fdi_config;
+       }
+
+       intel_crt_reset(&crt->base.base);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_crt.h b/drivers/gpu/drm/i915/display/intel_crt.h
new file mode 100644 (file)
index 0000000..1b3fba3
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_CRT_H__
+#define __INTEL_CRT_H__
+
+#include "i915_reg.h"
+
+enum pipe;
+struct drm_encoder;
+struct drm_i915_private;
+struct drm_i915_private;
+
+bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
+                           i915_reg_t adpa_reg, enum pipe *pipe);
+void intel_crt_init(struct drm_i915_private *dev_priv);
+void intel_crt_reset(struct drm_encoder *encoder);
+
+#endif /* __INTEL_CRT_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
new file mode 100644 (file)
index 0000000..7925a17
--- /dev/null
@@ -0,0 +1,4335 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eugeni Dodonov <eugeni.dodonov@intel.com>
+ *
+ */
+
+#include <drm/drm_scdc_helper.h>
+
+#include "i915_drv.h"
+#include "intel_audio.h"
+#include "intel_combo_phy.h"
+#include "intel_connector.h"
+#include "intel_ddi.h"
+#include "intel_dp.h"
+#include "intel_dp_link_training.h"
+#include "intel_dpio_phy.h"
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "intel_fifo_underrun.h"
+#include "intel_gmbus.h"
+#include "intel_hdcp.h"
+#include "intel_hdmi.h"
+#include "intel_hotplug.h"
+#include "intel_lspcon.h"
+#include "intel_panel.h"
+#include "intel_psr.h"
+#include "intel_vdsc.h"
+
+struct ddi_buf_trans {
+       u32 trans1;     /* balance leg enable, de-emph level */
+       u32 trans2;     /* vref sel, vswing */
+       u8 i_boost;     /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */
+};
+
+static const u8 index_to_dp_signal_levels[] = {
+       [0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0,
+       [1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1,
+       [2] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2,
+       [3] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3,
+       [4] = DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0,
+       [5] = DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1,
+       [6] = DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2,
+       [7] = DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0,
+       [8] = DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1,
+       [9] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0,
+};
+
+/* HDMI/DVI modes ignore everything but the last 2 items. So we share
+ * them for both DP and FDI transports, allowing those ports to
+ * automatically adapt to HDMI connections as well
+ */
+static const struct ddi_buf_trans hsw_ddi_translations_dp[] = {
+       { 0x00FFFFFF, 0x0006000E, 0x0 },
+       { 0x00D75FFF, 0x0005000A, 0x0 },
+       { 0x00C30FFF, 0x00040006, 0x0 },
+       { 0x80AAAFFF, 0x000B0000, 0x0 },
+       { 0x00FFFFFF, 0x0005000A, 0x0 },
+       { 0x00D75FFF, 0x000C0004, 0x0 },
+       { 0x80C30FFF, 0x000B0000, 0x0 },
+       { 0x00FFFFFF, 0x00040006, 0x0 },
+       { 0x80D75FFF, 0x000B0000, 0x0 },
+};
+
+static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = {
+       { 0x00FFFFFF, 0x0007000E, 0x0 },
+       { 0x00D75FFF, 0x000F000A, 0x0 },
+       { 0x00C30FFF, 0x00060006, 0x0 },
+       { 0x00AAAFFF, 0x001E0000, 0x0 },
+       { 0x00FFFFFF, 0x000F000A, 0x0 },
+       { 0x00D75FFF, 0x00160004, 0x0 },
+       { 0x00C30FFF, 0x001E0000, 0x0 },
+       { 0x00FFFFFF, 0x00060006, 0x0 },
+       { 0x00D75FFF, 0x001E0000, 0x0 },
+};
+
+static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = {
+                                       /* Idx  NT mV d T mV d  db      */
+       { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0:   400     400     0       */
+       { 0x00E79FFF, 0x000E000C, 0x0 },/* 1:   400     500     2       */
+       { 0x00D75FFF, 0x0005000A, 0x0 },/* 2:   400     600     3.5     */
+       { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3:   600     600     0       */
+       { 0x00E79FFF, 0x001D0007, 0x0 },/* 4:   600     750     2       */
+       { 0x00D75FFF, 0x000C0004, 0x0 },/* 5:   600     900     3.5     */
+       { 0x00FFFFFF, 0x00040006, 0x0 },/* 6:   800     800     0       */
+       { 0x80E79FFF, 0x00030002, 0x0 },/* 7:   800     1000    2       */
+       { 0x00FFFFFF, 0x00140005, 0x0 },/* 8:   850     850     0       */
+       { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9:   900     900     0       */
+       { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10:  950     950     0       */
+       { 0x80FFFFFF, 0x00030002, 0x0 },/* 11:  1000    1000    0       */
+};
+
+static const struct ddi_buf_trans bdw_ddi_translations_edp[] = {
+       { 0x00FFFFFF, 0x00000012, 0x0 },
+       { 0x00EBAFFF, 0x00020011, 0x0 },
+       { 0x00C71FFF, 0x0006000F, 0x0 },
+       { 0x00AAAFFF, 0x000E000A, 0x0 },
+       { 0x00FFFFFF, 0x00020011, 0x0 },
+       { 0x00DB6FFF, 0x0005000F, 0x0 },
+       { 0x00BEEFFF, 0x000A000C, 0x0 },
+       { 0x00FFFFFF, 0x0005000F, 0x0 },
+       { 0x00DB6FFF, 0x000A000C, 0x0 },
+};
+
+static const struct ddi_buf_trans bdw_ddi_translations_dp[] = {
+       { 0x00FFFFFF, 0x0007000E, 0x0 },
+       { 0x00D75FFF, 0x000E000A, 0x0 },
+       { 0x00BEFFFF, 0x00140006, 0x0 },
+       { 0x80B2CFFF, 0x001B0002, 0x0 },
+       { 0x00FFFFFF, 0x000E000A, 0x0 },
+       { 0x00DB6FFF, 0x00160005, 0x0 },
+       { 0x80C71FFF, 0x001A0002, 0x0 },
+       { 0x00F7DFFF, 0x00180004, 0x0 },
+       { 0x80D75FFF, 0x001B0002, 0x0 },
+};
+
+static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = {
+       { 0x00FFFFFF, 0x0001000E, 0x0 },
+       { 0x00D75FFF, 0x0004000A, 0x0 },
+       { 0x00C30FFF, 0x00070006, 0x0 },
+       { 0x00AAAFFF, 0x000C0000, 0x0 },
+       { 0x00FFFFFF, 0x0004000A, 0x0 },
+       { 0x00D75FFF, 0x00090004, 0x0 },
+       { 0x00C30FFF, 0x000C0000, 0x0 },
+       { 0x00FFFFFF, 0x00070006, 0x0 },
+       { 0x00D75FFF, 0x000C0000, 0x0 },
+};
+
+static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
+                                       /* Idx  NT mV d T mV df db      */
+       { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0:   400     400     0       */
+       { 0x00D75FFF, 0x000E000A, 0x0 },/* 1:   400     600     3.5     */
+       { 0x00BEFFFF, 0x00140006, 0x0 },/* 2:   400     800     6       */
+       { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3:   450     450     0       */
+       { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4:   600     600     0       */
+       { 0x00D7FFFF, 0x00140006, 0x0 },/* 5:   600     800     2.5     */
+       { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6:   600     1000    4.5     */
+       { 0x00FFFFFF, 0x00140006, 0x0 },/* 7:   800     800     0       */
+       { 0x80E79FFF, 0x001B0002, 0x0 },/* 8:   800     1000    2       */
+       { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9:   1000    1000    0       */
+};
+
+/* Skylake H and S */
+static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
+       { 0x00002016, 0x000000A0, 0x0 },
+       { 0x00005012, 0x0000009B, 0x0 },
+       { 0x00007011, 0x00000088, 0x0 },
+       { 0x80009010, 0x000000C0, 0x1 },
+       { 0x00002016, 0x0000009B, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000C0, 0x1 },
+       { 0x00002016, 0x000000DF, 0x0 },
+       { 0x80005012, 0x000000C0, 0x1 },
+};
+
+/* Skylake U */
+static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = {
+       { 0x0000201B, 0x000000A2, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000CD, 0x1 },
+       { 0x80009010, 0x000000C0, 0x1 },
+       { 0x0000201B, 0x0000009D, 0x0 },
+       { 0x80005012, 0x000000C0, 0x1 },
+       { 0x80007011, 0x000000C0, 0x1 },
+       { 0x00002016, 0x00000088, 0x0 },
+       { 0x80005012, 0x000000C0, 0x1 },
+};
+
+/* Skylake Y */
+static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = {
+       { 0x00000018, 0x000000A2, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000CD, 0x3 },
+       { 0x80009010, 0x000000C0, 0x3 },
+       { 0x00000018, 0x0000009D, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+       { 0x80007011, 0x000000C0, 0x3 },
+       { 0x00000018, 0x00000088, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+};
+
+/* Kabylake H and S */
+static const struct ddi_buf_trans kbl_ddi_translations_dp[] = {
+       { 0x00002016, 0x000000A0, 0x0 },
+       { 0x00005012, 0x0000009B, 0x0 },
+       { 0x00007011, 0x00000088, 0x0 },
+       { 0x80009010, 0x000000C0, 0x1 },
+       { 0x00002016, 0x0000009B, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000C0, 0x1 },
+       { 0x00002016, 0x00000097, 0x0 },
+       { 0x80005012, 0x000000C0, 0x1 },
+};
+
+/* Kabylake U */
+static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = {
+       { 0x0000201B, 0x000000A1, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000CD, 0x3 },
+       { 0x80009010, 0x000000C0, 0x3 },
+       { 0x0000201B, 0x0000009D, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+       { 0x80007011, 0x000000C0, 0x3 },
+       { 0x00002016, 0x0000004F, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+};
+
+/* Kabylake Y */
+static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = {
+       { 0x00001017, 0x000000A1, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000CD, 0x3 },
+       { 0x8000800F, 0x000000C0, 0x3 },
+       { 0x00001017, 0x0000009D, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+       { 0x80007011, 0x000000C0, 0x3 },
+       { 0x00001017, 0x0000004C, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+};
+
+/*
+ * Skylake/Kabylake H and S
+ * eDP 1.4 low vswing translation parameters
+ */
+static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
+       { 0x00000018, 0x000000A8, 0x0 },
+       { 0x00004013, 0x000000A9, 0x0 },
+       { 0x00007011, 0x000000A2, 0x0 },
+       { 0x00009010, 0x0000009C, 0x0 },
+       { 0x00000018, 0x000000A9, 0x0 },
+       { 0x00006013, 0x000000A2, 0x0 },
+       { 0x00007011, 0x000000A6, 0x0 },
+       { 0x00000018, 0x000000AB, 0x0 },
+       { 0x00007013, 0x0000009F, 0x0 },
+       { 0x00000018, 0x000000DF, 0x0 },
+};
+
+/*
+ * Skylake/Kabylake U
+ * eDP 1.4 low vswing translation parameters
+ */
+static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = {
+       { 0x00000018, 0x000000A8, 0x0 },
+       { 0x00004013, 0x000000A9, 0x0 },
+       { 0x00007011, 0x000000A2, 0x0 },
+       { 0x00009010, 0x0000009C, 0x0 },
+       { 0x00000018, 0x000000A9, 0x0 },
+       { 0x00006013, 0x000000A2, 0x0 },
+       { 0x00007011, 0x000000A6, 0x0 },
+       { 0x00002016, 0x000000AB, 0x0 },
+       { 0x00005013, 0x0000009F, 0x0 },
+       { 0x00000018, 0x000000DF, 0x0 },
+};
+
+/*
+ * Skylake/Kabylake Y
+ * eDP 1.4 low vswing translation parameters
+ */
+static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = {
+       { 0x00000018, 0x000000A8, 0x0 },
+       { 0x00004013, 0x000000AB, 0x0 },
+       { 0x00007011, 0x000000A4, 0x0 },
+       { 0x00009010, 0x000000DF, 0x0 },
+       { 0x00000018, 0x000000AA, 0x0 },
+       { 0x00006013, 0x000000A4, 0x0 },
+       { 0x00007011, 0x0000009D, 0x0 },
+       { 0x00000018, 0x000000A0, 0x0 },
+       { 0x00006012, 0x000000DF, 0x0 },
+       { 0x00000018, 0x0000008A, 0x0 },
+};
+
+/* Skylake/Kabylake U, H and S */
+static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
+       { 0x00000018, 0x000000AC, 0x0 },
+       { 0x00005012, 0x0000009D, 0x0 },
+       { 0x00007011, 0x00000088, 0x0 },
+       { 0x00000018, 0x000000A1, 0x0 },
+       { 0x00000018, 0x00000098, 0x0 },
+       { 0x00004013, 0x00000088, 0x0 },
+       { 0x80006012, 0x000000CD, 0x1 },
+       { 0x00000018, 0x000000DF, 0x0 },
+       { 0x80003015, 0x000000CD, 0x1 },        /* Default */
+       { 0x80003015, 0x000000C0, 0x1 },
+       { 0x80000018, 0x000000C0, 0x1 },
+};
+
+/* Skylake/Kabylake Y */
+static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = {
+       { 0x00000018, 0x000000A1, 0x0 },
+       { 0x00005012, 0x000000DF, 0x0 },
+       { 0x80007011, 0x000000CB, 0x3 },
+       { 0x00000018, 0x000000A4, 0x0 },
+       { 0x00000018, 0x0000009D, 0x0 },
+       { 0x00004013, 0x00000080, 0x0 },
+       { 0x80006013, 0x000000C0, 0x3 },
+       { 0x00000018, 0x0000008A, 0x0 },
+       { 0x80003015, 0x000000C0, 0x3 },        /* Default */
+       { 0x80003015, 0x000000C0, 0x3 },
+       { 0x80000018, 0x000000C0, 0x3 },
+};
+
+struct bxt_ddi_buf_trans {
+       u8 margin;      /* swing value */
+       u8 scale;       /* scale value */
+       u8 enable;      /* scale enable */
+       u8 deemphasis;
+};
+
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
+                                       /* Idx  NT mV diff      db  */
+       { 52,  0x9A, 0, 128, }, /* 0:   400             0   */
+       { 78,  0x9A, 0, 85,  }, /* 1:   400             3.5 */
+       { 104, 0x9A, 0, 64,  }, /* 2:   400             6   */
+       { 154, 0x9A, 0, 43,  }, /* 3:   400             9.5 */
+       { 77,  0x9A, 0, 128, }, /* 4:   600             0   */
+       { 116, 0x9A, 0, 85,  }, /* 5:   600             3.5 */
+       { 154, 0x9A, 0, 64,  }, /* 6:   600             6   */
+       { 102, 0x9A, 0, 128, }, /* 7:   800             0   */
+       { 154, 0x9A, 0, 85,  }, /* 8:   800             3.5 */
+       { 154, 0x9A, 1, 128, }, /* 9:   1200            0   */
+};
+
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = {
+                                       /* Idx  NT mV diff      db  */
+       { 26, 0, 0, 128, },     /* 0:   200             0   */
+       { 38, 0, 0, 112, },     /* 1:   200             1.5 */
+       { 48, 0, 0, 96,  },     /* 2:   200             4   */
+       { 54, 0, 0, 69,  },     /* 3:   200             6   */
+       { 32, 0, 0, 128, },     /* 4:   250             0   */
+       { 48, 0, 0, 104, },     /* 5:   250             1.5 */
+       { 54, 0, 0, 85,  },     /* 6:   250             4   */
+       { 43, 0, 0, 128, },     /* 7:   300             0   */
+       { 54, 0, 0, 101, },     /* 8:   300             1.5 */
+       { 48, 0, 0, 128, },     /* 9:   300             0   */
+};
+
+/* BSpec has 2 recommended values - entries 0 and 8.
+ * Using the entry with higher vswing.
+ */
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
+                                       /* Idx  NT mV diff      db  */
+       { 52,  0x9A, 0, 128, }, /* 0:   400             0   */
+       { 52,  0x9A, 0, 85,  }, /* 1:   400             3.5 */
+       { 52,  0x9A, 0, 64,  }, /* 2:   400             6   */
+       { 42,  0x9A, 0, 43,  }, /* 3:   400             9.5 */
+       { 77,  0x9A, 0, 128, }, /* 4:   600             0   */
+       { 77,  0x9A, 0, 85,  }, /* 5:   600             3.5 */
+       { 77,  0x9A, 0, 64,  }, /* 6:   600             6   */
+       { 102, 0x9A, 0, 128, }, /* 7:   800             0   */
+       { 102, 0x9A, 0, 85,  }, /* 8:   800             3.5 */
+       { 154, 0x9A, 1, 128, }, /* 9:   1200            0   */
+};
+
+struct cnl_ddi_buf_trans {
+       u8 dw2_swing_sel;
+       u8 dw7_n_scalar;
+       u8 dw4_cursor_coeff;
+       u8 dw4_post_cursor_2;
+       u8 dw4_post_cursor_1;
+};
+
+/* Voltage Swing Programming for VccIO 0.85V for DP */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_85V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x5D, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
+       { 0xA, 0x6A, 0x38, 0x00, 0x07 },        /* 350   500      3.1   */
+       { 0xB, 0x7A, 0x32, 0x00, 0x0D },        /* 350   700      6.0   */
+       { 0x6, 0x7C, 0x2D, 0x00, 0x12 },        /* 350   900      8.2   */
+       { 0xA, 0x69, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
+       { 0xB, 0x7A, 0x36, 0x00, 0x09 },        /* 500   700      2.9   */
+       { 0x6, 0x7C, 0x30, 0x00, 0x0F },        /* 500   900      5.1   */
+       { 0xB, 0x7D, 0x3C, 0x00, 0x03 },        /* 650   725      0.9   */
+       { 0x6, 0x7C, 0x34, 0x00, 0x0B },        /* 600   900      3.5   */
+       { 0x6, 0x7B, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 0.85V for HDMI */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_85V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x60, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
+       { 0xB, 0x73, 0x36, 0x00, 0x09 },        /* 450   650      3.2   */
+       { 0x6, 0x7F, 0x31, 0x00, 0x0E },        /* 450   850      5.5   */
+       { 0xB, 0x73, 0x3F, 0x00, 0x00 },        /* 650   650      0.0   */
+       { 0x6, 0x7F, 0x37, 0x00, 0x08 },        /* 650   850      2.3   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 850   850      0.0   */
+       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
+};
+
+/* Voltage Swing Programming for VccIO 0.85V for eDP */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_85V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x66, 0x3A, 0x00, 0x05 },        /* 384   500      2.3   */
+       { 0x0, 0x7F, 0x38, 0x00, 0x07 },        /* 153   200      2.3   */
+       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 192   250      2.3   */
+       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 230   300      2.3   */
+       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 269   350      2.3   */
+       { 0xA, 0x66, 0x3C, 0x00, 0x03 },        /* 446   500      1.0   */
+       { 0xB, 0x70, 0x3C, 0x00, 0x03 },        /* 460   600      2.3   */
+       { 0xC, 0x75, 0x3C, 0x00, 0x03 },        /* 537   700      2.3   */
+       { 0x2, 0x7F, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 0.95V for DP */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_95V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x5D, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
+       { 0xA, 0x6A, 0x38, 0x00, 0x07 },        /* 350   500      3.1   */
+       { 0xB, 0x7A, 0x32, 0x00, 0x0D },        /* 350   700      6.0   */
+       { 0x6, 0x7C, 0x2D, 0x00, 0x12 },        /* 350   900      8.2   */
+       { 0xA, 0x69, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
+       { 0xB, 0x7A, 0x36, 0x00, 0x09 },        /* 500   700      2.9   */
+       { 0x6, 0x7C, 0x30, 0x00, 0x0F },        /* 500   900      5.1   */
+       { 0xB, 0x7D, 0x3C, 0x00, 0x03 },        /* 650   725      0.9   */
+       { 0x6, 0x7C, 0x34, 0x00, 0x0B },        /* 600   900      3.5   */
+       { 0x6, 0x7B, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 0.95V for HDMI */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_95V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x5C, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
+       { 0xB, 0x69, 0x37, 0x00, 0x08 },        /* 400   600      3.5   */
+       { 0x5, 0x76, 0x31, 0x00, 0x0E },        /* 400   800      6.0   */
+       { 0xA, 0x5E, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
+       { 0xB, 0x69, 0x3F, 0x00, 0x00 },        /* 600   600      0.0   */
+       { 0xB, 0x79, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
+       { 0x6, 0x7D, 0x32, 0x00, 0x0D },        /* 600   1000     4.4   */
+       { 0x5, 0x76, 0x3F, 0x00, 0x00 },        /* 800   800      0.0   */
+       { 0x6, 0x7D, 0x39, 0x00, 0x06 },        /* 800   1000     1.9   */
+       { 0x6, 0x7F, 0x39, 0x00, 0x06 },        /* 850   1050     1.8   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 1050  1050     0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 0.95V for eDP */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_95V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x61, 0x3A, 0x00, 0x05 },        /* 384   500      2.3   */
+       { 0x0, 0x7F, 0x38, 0x00, 0x07 },        /* 153   200      2.3   */
+       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 192   250      2.3   */
+       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 230   300      2.3   */
+       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 269   350      2.3   */
+       { 0xA, 0x61, 0x3C, 0x00, 0x03 },        /* 446   500      1.0   */
+       { 0xB, 0x68, 0x39, 0x00, 0x06 },        /* 460   600      2.3   */
+       { 0xC, 0x6E, 0x39, 0x00, 0x06 },        /* 537   700      2.3   */
+       { 0x4, 0x7F, 0x3A, 0x00, 0x05 },        /* 460   600      2.3   */
+       { 0x2, 0x7F, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 1.05V for DP */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_1_05V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x58, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
+       { 0xB, 0x64, 0x37, 0x00, 0x08 },        /* 400   600      3.5   */
+       { 0x5, 0x70, 0x31, 0x00, 0x0E },        /* 400   800      6.0   */
+       { 0x6, 0x7F, 0x2C, 0x00, 0x13 },        /* 400   1050     8.4   */
+       { 0xB, 0x64, 0x3F, 0x00, 0x00 },        /* 600   600      0.0   */
+       { 0x5, 0x73, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
+       { 0x6, 0x7F, 0x30, 0x00, 0x0F },        /* 550   1050     5.6   */
+       { 0x5, 0x76, 0x3E, 0x00, 0x01 },        /* 850   900      0.5   */
+       { 0x6, 0x7F, 0x36, 0x00, 0x09 },        /* 750   1050     2.9   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 1050  1050     0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 1.05V for HDMI */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_1_05V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x58, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
+       { 0xB, 0x64, 0x37, 0x00, 0x08 },        /* 400   600      3.5   */
+       { 0x5, 0x70, 0x31, 0x00, 0x0E },        /* 400   800      6.0   */
+       { 0xA, 0x5B, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
+       { 0xB, 0x64, 0x3F, 0x00, 0x00 },        /* 600   600      0.0   */
+       { 0x5, 0x73, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
+       { 0x6, 0x7C, 0x32, 0x00, 0x0D },        /* 600   1000     4.4   */
+       { 0x5, 0x70, 0x3F, 0x00, 0x00 },        /* 800   800      0.0   */
+       { 0x6, 0x7C, 0x39, 0x00, 0x06 },        /* 800   1000     1.9   */
+       { 0x6, 0x7F, 0x39, 0x00, 0x06 },        /* 850   1050     1.8   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 1050  1050     0.0   */
+};
+
+/* Voltage Swing Programming for VccIO 1.05V for eDP */
+static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x5E, 0x3A, 0x00, 0x05 },        /* 384   500      2.3   */
+       { 0x0, 0x7F, 0x38, 0x00, 0x07 },        /* 153   200      2.3   */
+       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 192   250      2.3   */
+       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 230   300      2.3   */
+       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 269   350      2.3   */
+       { 0xA, 0x5E, 0x3C, 0x00, 0x03 },        /* 446   500      1.0   */
+       { 0xB, 0x64, 0x39, 0x00, 0x06 },        /* 460   600      2.3   */
+       { 0xE, 0x6A, 0x39, 0x00, 0x06 },        /* 537   700      2.3   */
+       { 0x2, 0x7F, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
+};
+
+/* icl_combo_phy_ddi_translations */
+static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x35, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
+       { 0xA, 0x4F, 0x37, 0x00, 0x08 },        /* 350   500      3.1   */
+       { 0xC, 0x71, 0x2F, 0x00, 0x10 },        /* 350   700      6.0   */
+       { 0x6, 0x7F, 0x2B, 0x00, 0x14 },        /* 350   900      8.2   */
+       { 0xA, 0x4C, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
+       { 0xC, 0x73, 0x34, 0x00, 0x0B },        /* 500   700      2.9   */
+       { 0x6, 0x7F, 0x2F, 0x00, 0x10 },        /* 500   900      5.1   */
+       { 0xC, 0x6C, 0x3C, 0x00, 0x03 },        /* 650   700      0.6   */
+       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   900      3.5   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
+};
+
+static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = {
+                                               /* NT mV Trans mV db    */
+       { 0x0, 0x7F, 0x3F, 0x00, 0x00 },        /* 200   200      0.0   */
+       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 200   250      1.9   */
+       { 0x1, 0x7F, 0x33, 0x00, 0x0C },        /* 200   300      3.5   */
+       { 0x9, 0x7F, 0x31, 0x00, 0x0E },        /* 200   350      4.9   */
+       { 0x8, 0x7F, 0x3F, 0x00, 0x00 },        /* 250   250      0.0   */
+       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 250   300      1.6   */
+       { 0x9, 0x7F, 0x35, 0x00, 0x0A },        /* 250   350      2.9   */
+       { 0x1, 0x7F, 0x3F, 0x00, 0x00 },        /* 300   300      0.0   */
+       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 300   350      1.3   */
+       { 0x9, 0x7F, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
+};
+
+static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x35, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
+       { 0xA, 0x4F, 0x37, 0x00, 0x08 },        /* 350   500      3.1   */
+       { 0xC, 0x71, 0x2F, 0x00, 0x10 },        /* 350   700      6.0   */
+       { 0x6, 0x7F, 0x2B, 0x00, 0x14 },        /* 350   900      8.2   */
+       { 0xA, 0x4C, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
+       { 0xC, 0x73, 0x34, 0x00, 0x0B },        /* 500   700      2.9   */
+       { 0x6, 0x7F, 0x2F, 0x00, 0x10 },        /* 500   900      5.1   */
+       { 0xC, 0x6C, 0x3C, 0x00, 0x03 },        /* 650   700      0.6   */
+       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   900      3.5   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
+};
+
+static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = {
+                                               /* NT mV Trans mV db    */
+       { 0xA, 0x60, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
+       { 0xB, 0x73, 0x36, 0x00, 0x09 },        /* 450   650      3.2   */
+       { 0x6, 0x7F, 0x31, 0x00, 0x0E },        /* 450   850      5.5   */
+       { 0xB, 0x73, 0x3F, 0x00, 0x00 },        /* 650   650      0.0   ALS */
+       { 0x6, 0x7F, 0x37, 0x00, 0x08 },        /* 650   850      2.3   */
+       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 850   850      0.0   */
+       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
+};
+
+struct icl_mg_phy_ddi_buf_trans {
+       u32 cri_txdeemph_override_5_0;
+       u32 cri_txdeemph_override_11_6;
+       u32 cri_txdeemph_override_17_12;
+};
+
+static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations[] = {
+                               /* Voltage swing  pre-emphasis */
+       { 0x0, 0x1B, 0x00 },    /* 0              0   */
+       { 0x0, 0x23, 0x08 },    /* 0              1   */
+       { 0x0, 0x2D, 0x12 },    /* 0              2   */
+       { 0x0, 0x00, 0x00 },    /* 0              3   */
+       { 0x0, 0x23, 0x00 },    /* 1              0   */
+       { 0x0, 0x2B, 0x09 },    /* 1              1   */
+       { 0x0, 0x2E, 0x11 },    /* 1              2   */
+       { 0x0, 0x2F, 0x00 },    /* 2              0   */
+       { 0x0, 0x33, 0x0C },    /* 2              1   */
+       { 0x0, 0x00, 0x00 },    /* 3              0   */
+};
+
+static const struct ddi_buf_trans *
+bdw_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (dev_priv->vbt.edp.low_vswing) {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+               return bdw_ddi_translations_edp;
+       } else {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
+               return bdw_ddi_translations_dp;
+       }
+}
+
+static const struct ddi_buf_trans *
+skl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (IS_SKL_ULX(dev_priv)) {
+               *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
+               return skl_y_ddi_translations_dp;
+       } else if (IS_SKL_ULT(dev_priv)) {
+               *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp);
+               return skl_u_ddi_translations_dp;
+       } else {
+               *n_entries = ARRAY_SIZE(skl_ddi_translations_dp);
+               return skl_ddi_translations_dp;
+       }
+}
+
+static const struct ddi_buf_trans *
+kbl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (IS_KBL_ULX(dev_priv) || IS_CFL_ULX(dev_priv)) {
+               *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp);
+               return kbl_y_ddi_translations_dp;
+       } else if (IS_KBL_ULT(dev_priv) || IS_CFL_ULT(dev_priv)) {
+               *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp);
+               return kbl_u_ddi_translations_dp;
+       } else {
+               *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp);
+               return kbl_ddi_translations_dp;
+       }
+}
+
+static const struct ddi_buf_trans *
+skl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (dev_priv->vbt.edp.low_vswing) {
+               if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv) ||
+                   IS_CFL_ULX(dev_priv)) {
+                       *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp);
+                       return skl_y_ddi_translations_edp;
+               } else if (IS_SKL_ULT(dev_priv) || IS_KBL_ULT(dev_priv) ||
+                          IS_CFL_ULT(dev_priv)) {
+                       *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp);
+                       return skl_u_ddi_translations_edp;
+               } else {
+                       *n_entries = ARRAY_SIZE(skl_ddi_translations_edp);
+                       return skl_ddi_translations_edp;
+               }
+       }
+
+       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv))
+               return kbl_get_buf_trans_dp(dev_priv, n_entries);
+       else
+               return skl_get_buf_trans_dp(dev_priv, n_entries);
+}
+
+static const struct ddi_buf_trans *
+skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv) ||
+           IS_CFL_ULX(dev_priv)) {
+               *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi);
+               return skl_y_ddi_translations_hdmi;
+       } else {
+               *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
+               return skl_ddi_translations_hdmi;
+       }
+}
+
+static int skl_buf_trans_num_entries(enum port port, int n_entries)
+{
+       /* Only DDIA and DDIE can select the 10th register with DP */
+       if (port == PORT_A || port == PORT_E)
+               return min(n_entries, 10);
+       else
+               return min(n_entries, 9);
+}
+
+static const struct ddi_buf_trans *
+intel_ddi_get_buf_trans_dp(struct drm_i915_private *dev_priv,
+                          enum port port, int *n_entries)
+{
+       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) {
+               const struct ddi_buf_trans *ddi_translations =
+                       kbl_get_buf_trans_dp(dev_priv, n_entries);
+               *n_entries = skl_buf_trans_num_entries(port, *n_entries);
+               return ddi_translations;
+       } else if (IS_SKYLAKE(dev_priv)) {
+               const struct ddi_buf_trans *ddi_translations =
+                       skl_get_buf_trans_dp(dev_priv, n_entries);
+               *n_entries = skl_buf_trans_num_entries(port, *n_entries);
+               return ddi_translations;
+       } else if (IS_BROADWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
+               return  bdw_ddi_translations_dp;
+       } else if (IS_HASWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp);
+               return hsw_ddi_translations_dp;
+       }
+
+       *n_entries = 0;
+       return NULL;
+}
+
+static const struct ddi_buf_trans *
+intel_ddi_get_buf_trans_edp(struct drm_i915_private *dev_priv,
+                           enum port port, int *n_entries)
+{
+       if (IS_GEN9_BC(dev_priv)) {
+               const struct ddi_buf_trans *ddi_translations =
+                       skl_get_buf_trans_edp(dev_priv, n_entries);
+               *n_entries = skl_buf_trans_num_entries(port, *n_entries);
+               return ddi_translations;
+       } else if (IS_BROADWELL(dev_priv)) {
+               return bdw_get_buf_trans_edp(dev_priv, n_entries);
+       } else if (IS_HASWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp);
+               return hsw_ddi_translations_dp;
+       }
+
+       *n_entries = 0;
+       return NULL;
+}
+
+static const struct ddi_buf_trans *
+intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv,
+                           int *n_entries)
+{
+       if (IS_BROADWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi);
+               return bdw_ddi_translations_fdi;
+       } else if (IS_HASWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi);
+               return hsw_ddi_translations_fdi;
+       }
+
+       *n_entries = 0;
+       return NULL;
+}
+
+static const struct ddi_buf_trans *
+intel_ddi_get_buf_trans_hdmi(struct drm_i915_private *dev_priv,
+                            int *n_entries)
+{
+       if (IS_GEN9_BC(dev_priv)) {
+               return skl_get_buf_trans_hdmi(dev_priv, n_entries);
+       } else if (IS_BROADWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+               return bdw_ddi_translations_hdmi;
+       } else if (IS_HASWELL(dev_priv)) {
+               *n_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
+               return hsw_ddi_translations_hdmi;
+       }
+
+       *n_entries = 0;
+       return NULL;
+}
+
+static const struct bxt_ddi_buf_trans *
+bxt_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       *n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
+       return bxt_ddi_translations_dp;
+}
+
+static const struct bxt_ddi_buf_trans *
+bxt_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (dev_priv->vbt.edp.low_vswing) {
+               *n_entries = ARRAY_SIZE(bxt_ddi_translations_edp);
+               return bxt_ddi_translations_edp;
+       }
+
+       return bxt_get_buf_trans_dp(dev_priv, n_entries);
+}
+
+static const struct bxt_ddi_buf_trans *
+bxt_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       *n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi);
+       return bxt_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+cnl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
+
+       if (voltage == VOLTAGE_INFO_0_85V) {
+               *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V);
+               return cnl_ddi_translations_hdmi_0_85V;
+       } else if (voltage == VOLTAGE_INFO_0_95V) {
+               *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V);
+               return cnl_ddi_translations_hdmi_0_95V;
+       } else if (voltage == VOLTAGE_INFO_1_05V) {
+               *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V);
+               return cnl_ddi_translations_hdmi_1_05V;
+       } else {
+               *n_entries = 1; /* shut up gcc */
+               MISSING_CASE(voltage);
+       }
+       return NULL;
+}
+
+static const struct cnl_ddi_buf_trans *
+cnl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
+
+       if (voltage == VOLTAGE_INFO_0_85V) {
+               *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V);
+               return cnl_ddi_translations_dp_0_85V;
+       } else if (voltage == VOLTAGE_INFO_0_95V) {
+               *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V);
+               return cnl_ddi_translations_dp_0_95V;
+       } else if (voltage == VOLTAGE_INFO_1_05V) {
+               *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V);
+               return cnl_ddi_translations_dp_1_05V;
+       } else {
+               *n_entries = 1; /* shut up gcc */
+               MISSING_CASE(voltage);
+       }
+       return NULL;
+}
+
+static const struct cnl_ddi_buf_trans *
+cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
+
+       if (dev_priv->vbt.edp.low_vswing) {
+               if (voltage == VOLTAGE_INFO_0_85V) {
+                       *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V);
+                       return cnl_ddi_translations_edp_0_85V;
+               } else if (voltage == VOLTAGE_INFO_0_95V) {
+                       *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V);
+                       return cnl_ddi_translations_edp_0_95V;
+               } else if (voltage == VOLTAGE_INFO_1_05V) {
+                       *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V);
+                       return cnl_ddi_translations_edp_1_05V;
+               } else {
+                       *n_entries = 1; /* shut up gcc */
+                       MISSING_CASE(voltage);
+               }
+               return NULL;
+       } else {
+               return cnl_get_buf_trans_dp(dev_priv, 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)
+{
+       if (type == INTEL_OUTPUT_HDMI) {
+               *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+               return icl_combo_phy_ddi_translations_hdmi;
+       } else if (rate > 540000 && type == INTEL_OUTPUT_EDP) {
+               *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
+               return icl_combo_phy_ddi_translations_edp_hbr3;
+       } else if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) {
+               *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
+               return icl_combo_phy_ddi_translations_edp_hbr2;
+       }
+
+       *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
+       return icl_combo_phy_ddi_translations_dp_hbr2;
+}
+
+static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port port)
+{
+       int n_entries, level, default_entry;
+
+       level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
+
+       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,
+                                               0, &n_entries);
+               else
+                       n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
+               default_entry = n_entries - 1;
+       } else if (IS_CANNONLAKE(dev_priv)) {
+               cnl_get_buf_trans_hdmi(dev_priv, &n_entries);
+               default_entry = n_entries - 1;
+       } else if (IS_GEN9_LP(dev_priv)) {
+               bxt_get_buf_trans_hdmi(dev_priv, &n_entries);
+               default_entry = n_entries - 1;
+       } else if (IS_GEN9_BC(dev_priv)) {
+               intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
+               default_entry = 8;
+       } else if (IS_BROADWELL(dev_priv)) {
+               intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
+               default_entry = 7;
+       } else if (IS_HASWELL(dev_priv)) {
+               intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
+               default_entry = 6;
+       } else {
+               WARN(1, "ddi translation table missing\n");
+               return 0;
+       }
+
+       /* Choose a good default if VBT is badly populated */
+       if (level == HDMI_LEVEL_SHIFT_UNKNOWN || level >= n_entries)
+               level = default_entry;
+
+       if (WARN_ON_ONCE(n_entries == 0))
+               return 0;
+       if (WARN_ON_ONCE(level >= n_entries))
+               level = n_entries - 1;
+
+       return level;
+}
+
+/*
+ * Starting with Haswell, DDI port buffers must be programmed with correct
+ * values in advance. This function programs the correct values for
+ * DP/eDP/FDI use cases.
+ */
+static void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder,
+                                        const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 iboost_bit = 0;
+       int i, n_entries;
+       enum port port = encoder->port;
+       const struct ddi_buf_trans *ddi_translations;
+
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
+               ddi_translations = intel_ddi_get_buf_trans_fdi(dev_priv,
+                                                              &n_entries);
+       else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+               ddi_translations = intel_ddi_get_buf_trans_edp(dev_priv, port,
+                                                              &n_entries);
+       else
+               ddi_translations = intel_ddi_get_buf_trans_dp(dev_priv, port,
+                                                             &n_entries);
+
+       /* If we're boosting the current, set bit 31 of trans1 */
+       if (IS_GEN9_BC(dev_priv) &&
+           dev_priv->vbt.ddi_port_info[port].dp_boost_level)
+               iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
+
+       for (i = 0; i < n_entries; i++) {
+               I915_WRITE(DDI_BUF_TRANS_LO(port, i),
+                          ddi_translations[i].trans1 | iboost_bit);
+               I915_WRITE(DDI_BUF_TRANS_HI(port, i),
+                          ddi_translations[i].trans2);
+       }
+}
+
+/*
+ * Starting with Haswell, DDI port buffers must be programmed with correct
+ * values in advance. This function programs the correct values for
+ * HDMI/DVI use cases.
+ */
+static void intel_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder,
+                                          int level)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 iboost_bit = 0;
+       int n_entries;
+       enum port port = encoder->port;
+       const struct ddi_buf_trans *ddi_translations;
+
+       ddi_translations = intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
+
+       if (WARN_ON_ONCE(!ddi_translations))
+               return;
+       if (WARN_ON_ONCE(level >= n_entries))
+               level = n_entries - 1;
+
+       /* If we're boosting the current, set bit 31 of trans1 */
+       if (IS_GEN9_BC(dev_priv) &&
+           dev_priv->vbt.ddi_port_info[port].hdmi_boost_level)
+               iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
+
+       /* Entry 9 is for HDMI: */
+       I915_WRITE(DDI_BUF_TRANS_LO(port, 9),
+                  ddi_translations[level].trans1 | iboost_bit);
+       I915_WRITE(DDI_BUF_TRANS_HI(port, 9),
+                  ddi_translations[level].trans2);
+}
+
+static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
+                                   enum port port)
+{
+       i915_reg_t reg = DDI_BUF_CTL(port);
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               udelay(1);
+               if (I915_READ(reg) & DDI_BUF_IS_IDLE)
+                       return;
+       }
+       DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
+}
+
+static u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll)
+{
+       switch (pll->info->id) {
+       case DPLL_ID_WRPLL1:
+               return PORT_CLK_SEL_WRPLL1;
+       case DPLL_ID_WRPLL2:
+               return PORT_CLK_SEL_WRPLL2;
+       case DPLL_ID_SPLL:
+               return PORT_CLK_SEL_SPLL;
+       case DPLL_ID_LCPLL_810:
+               return PORT_CLK_SEL_LCPLL_810;
+       case DPLL_ID_LCPLL_1350:
+               return PORT_CLK_SEL_LCPLL_1350;
+       case DPLL_ID_LCPLL_2700:
+               return PORT_CLK_SEL_LCPLL_2700;
+       default:
+               MISSING_CASE(pll->info->id);
+               return PORT_CLK_SEL_NONE;
+       }
+}
+
+static u32 icl_pll_to_ddi_clk_sel(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
+{
+       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+       int clock = crtc_state->port_clock;
+       const enum intel_dpll_id id = pll->info->id;
+
+       switch (id) {
+       default:
+               /*
+                * DPLL_ID_ICL_DPLL0 and DPLL_ID_ICL_DPLL1 should not be used
+                * here, so do warn if this get passed in
+                */
+               MISSING_CASE(id);
+               return DDI_CLK_SEL_NONE;
+       case DPLL_ID_ICL_TBTPLL:
+               switch (clock) {
+               case 162000:
+                       return DDI_CLK_SEL_TBT_162;
+               case 270000:
+                       return DDI_CLK_SEL_TBT_270;
+               case 540000:
+                       return DDI_CLK_SEL_TBT_540;
+               case 810000:
+                       return DDI_CLK_SEL_TBT_810;
+               default:
+                       MISSING_CASE(clock);
+                       return DDI_CLK_SEL_NONE;
+               }
+       case DPLL_ID_ICL_MGPLL1:
+       case DPLL_ID_ICL_MGPLL2:
+       case DPLL_ID_ICL_MGPLL3:
+       case DPLL_ID_ICL_MGPLL4:
+               return DDI_CLK_SEL_MG;
+       }
+}
+
+/* Starting with Haswell, different DDI ports can work in FDI mode for
+ * connection to the PCH-located connectors. For this, it is necessary to train
+ * both the DDI port and PCH receiver for the desired DDI buffer settings.
+ *
+ * The recommended port to work in FDI mode is DDI E, which we use here. Also,
+ * please note that when FDI mode is active on DDI E, it shares 2 lines with
+ * DDI A (which is used for eDP)
+ */
+
+void hsw_fdi_link_train(struct intel_crtc *crtc,
+                       const struct intel_crtc_state *crtc_state)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_encoder *encoder;
+       u32 temp, i, rx_ctl_val, ddi_pll_sel;
+
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+               WARN_ON(encoder->type != INTEL_OUTPUT_ANALOG);
+               intel_prepare_dp_ddi_buffers(encoder, crtc_state);
+       }
+
+       /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the
+        * mode set "sequence for CRT port" document:
+        * - TP1 to TP2 time with the default value
+        * - FDI delay to 90h
+        *
+        * WaFDIAutoLinkSetTimingOverrride:hsw
+        */
+       I915_WRITE(FDI_RX_MISC(PIPE_A), FDI_RX_PWRDN_LANE1_VAL(2) |
+                                 FDI_RX_PWRDN_LANE0_VAL(2) |
+                                 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
+
+       /* Enable the PCH Receiver FDI PLL */
+       rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
+                    FDI_RX_PLL_ENABLE |
+                    FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
+       I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+       POSTING_READ(FDI_RX_CTL(PIPE_A));
+       udelay(220);
+
+       /* Switch from Rawclk to PCDclk */
+       rx_ctl_val |= FDI_PCDCLK;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+
+       /* Configure Port Clock Select */
+       ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll);
+       I915_WRITE(PORT_CLK_SEL(PORT_E), ddi_pll_sel);
+       WARN_ON(ddi_pll_sel != PORT_CLK_SEL_SPLL);
+
+       /* Start the training iterating through available voltages and emphasis,
+        * testing each value twice. */
+       for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) {
+               /* Configure DP_TP_CTL with auto-training */
+               I915_WRITE(DP_TP_CTL(PORT_E),
+                                       DP_TP_CTL_FDI_AUTOTRAIN |
+                                       DP_TP_CTL_ENHANCED_FRAME_ENABLE |
+                                       DP_TP_CTL_LINK_TRAIN_PAT1 |
+                                       DP_TP_CTL_ENABLE);
+
+               /* Configure and enable DDI_BUF_CTL for DDI E with next voltage.
+                * DDI E does not support port reversal, the functionality is
+                * achieved on the PCH side in FDI_RX_CTL, so no need to set the
+                * port reversal bit */
+               I915_WRITE(DDI_BUF_CTL(PORT_E),
+                          DDI_BUF_CTL_ENABLE |
+                          ((crtc_state->fdi_lanes - 1) << 1) |
+                          DDI_BUF_TRANS_SELECT(i / 2));
+               POSTING_READ(DDI_BUF_CTL(PORT_E));
+
+               udelay(600);
+
+               /* Program PCH FDI Receiver TU */
+               I915_WRITE(FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64));
+
+               /* Enable PCH FDI Receiver with auto-training */
+               rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO;
+               I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+               POSTING_READ(FDI_RX_CTL(PIPE_A));
+
+               /* Wait for FDI receiver lane calibration */
+               udelay(30);
+
+               /* Unset FDI_RX_MISC pwrdn lanes */
+               temp = I915_READ(FDI_RX_MISC(PIPE_A));
+               temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
+               I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
+               POSTING_READ(FDI_RX_MISC(PIPE_A));
+
+               /* Wait for FDI auto training time */
+               udelay(5);
+
+               temp = I915_READ(DP_TP_STATUS(PORT_E));
+               if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
+                       DRM_DEBUG_KMS("FDI link training done on step %d\n", i);
+                       break;
+               }
+
+               /*
+                * Leave things enabled even if we failed to train FDI.
+                * Results in less fireworks from the state checker.
+                */
+               if (i == ARRAY_SIZE(hsw_ddi_translations_fdi) * 2 - 1) {
+                       DRM_ERROR("FDI link training failed!\n");
+                       break;
+               }
+
+               rx_ctl_val &= ~FDI_RX_ENABLE;
+               I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+               POSTING_READ(FDI_RX_CTL(PIPE_A));
+
+               temp = I915_READ(DDI_BUF_CTL(PORT_E));
+               temp &= ~DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(PORT_E), temp);
+               POSTING_READ(DDI_BUF_CTL(PORT_E));
+
+               /* Disable DP_TP_CTL and FDI_RX_CTL and retry */
+               temp = I915_READ(DP_TP_CTL(PORT_E));
+               temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
+               temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
+               I915_WRITE(DP_TP_CTL(PORT_E), temp);
+               POSTING_READ(DP_TP_CTL(PORT_E));
+
+               intel_wait_ddi_buf_idle(dev_priv, PORT_E);
+
+               /* Reset FDI_RX_MISC pwrdn lanes */
+               temp = I915_READ(FDI_RX_MISC(PIPE_A));
+               temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
+               temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
+               I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
+               POSTING_READ(FDI_RX_MISC(PIPE_A));
+       }
+
+       /* Enable normal pixel sending for FDI */
+       I915_WRITE(DP_TP_CTL(PORT_E),
+                  DP_TP_CTL_FDI_AUTOTRAIN |
+                  DP_TP_CTL_LINK_TRAIN_NORMAL |
+                  DP_TP_CTL_ENHANCED_FRAME_ENABLE |
+                  DP_TP_CTL_ENABLE);
+}
+
+static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_digital_port *intel_dig_port =
+               enc_to_dig_port(&encoder->base);
+
+       intel_dp->DP = intel_dig_port->saved_port_bits |
+               DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
+       intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
+}
+
+static struct intel_encoder *
+intel_ddi_get_crtc_encoder(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_encoder *encoder, *ret = NULL;
+       int num_encoders = 0;
+
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+               ret = encoder;
+               num_encoders++;
+       }
+
+       if (num_encoders != 1)
+               WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders,
+                    pipe_name(crtc->pipe));
+
+       BUG_ON(ret == NULL);
+       return ret;
+}
+
+static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                                  i915_reg_t reg)
+{
+       int refclk;
+       int n, p, r;
+       u32 wrpll;
+
+       wrpll = I915_READ(reg);
+       switch (wrpll & WRPLL_REF_MASK) {
+       case WRPLL_REF_SPECIAL_HSW:
+               /*
+                * muxed-SSC for BDW.
+                * non-SSC for non-ULT HSW. Check FUSE_STRAP3
+                * for the non-SSC reference frequency.
+                */
+               if (IS_HASWELL(dev_priv) && !IS_HSW_ULT(dev_priv)) {
+                       if (I915_READ(FUSE_STRAP3) & HSW_REF_CLK_SELECT)
+                               refclk = 24;
+                       else
+                               refclk = 135;
+                       break;
+               }
+               /* fall through */
+       case WRPLL_REF_PCH_SSC:
+               /*
+                * We could calculate spread here, but our checking
+                * code only cares about 5% accuracy, and spread is a max of
+                * 0.5% downspread.
+                */
+               refclk = 135;
+               break;
+       case WRPLL_REF_LCPLL:
+               refclk = 2700;
+               break;
+       default:
+               MISSING_CASE(wrpll);
+               return 0;
+       }
+
+       r = wrpll & WRPLL_DIVIDER_REF_MASK;
+       p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
+       n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
+
+       /* Convert to KHz, p & r have a fixed point portion */
+       return (refclk * n * 100) / (p * r);
+}
+
+static int skl_calc_wrpll_link(const struct intel_dpll_hw_state *pll_state)
+{
+       u32 p0, p1, p2, dco_freq;
+
+       p0 = pll_state->cfgcr2 & DPLL_CFGCR2_PDIV_MASK;
+       p2 = pll_state->cfgcr2 & DPLL_CFGCR2_KDIV_MASK;
+
+       if (pll_state->cfgcr2 &  DPLL_CFGCR2_QDIV_MODE(1))
+               p1 = (pll_state->cfgcr2 & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8;
+       else
+               p1 = 1;
+
+
+       switch (p0) {
+       case DPLL_CFGCR2_PDIV_1:
+               p0 = 1;
+               break;
+       case DPLL_CFGCR2_PDIV_2:
+               p0 = 2;
+               break;
+       case DPLL_CFGCR2_PDIV_3:
+               p0 = 3;
+               break;
+       case DPLL_CFGCR2_PDIV_7:
+               p0 = 7;
+               break;
+       }
+
+       switch (p2) {
+       case DPLL_CFGCR2_KDIV_5:
+               p2 = 5;
+               break;
+       case DPLL_CFGCR2_KDIV_2:
+               p2 = 2;
+               break;
+       case DPLL_CFGCR2_KDIV_3:
+               p2 = 3;
+               break;
+       case DPLL_CFGCR2_KDIV_1:
+               p2 = 1;
+               break;
+       }
+
+       dco_freq = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK)
+               * 24 * 1000;
+
+       dco_freq += (((pll_state->cfgcr1 & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9)
+                    * 24 * 1000) / 0x8000;
+
+       if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
+               return 0;
+
+       return dco_freq / (p0 * p1 * p2 * 5);
+}
+
+int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                       struct intel_dpll_hw_state *pll_state)
+{
+       u32 p0, p1, p2, dco_freq, ref_clock;
+
+       p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
+       p2 = pll_state->cfgcr1 & DPLL_CFGCR1_KDIV_MASK;
+
+       if (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1))
+               p1 = (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >>
+                       DPLL_CFGCR1_QDIV_RATIO_SHIFT;
+       else
+               p1 = 1;
+
+
+       switch (p0) {
+       case DPLL_CFGCR1_PDIV_2:
+               p0 = 2;
+               break;
+       case DPLL_CFGCR1_PDIV_3:
+               p0 = 3;
+               break;
+       case DPLL_CFGCR1_PDIV_5:
+               p0 = 5;
+               break;
+       case DPLL_CFGCR1_PDIV_7:
+               p0 = 7;
+               break;
+       }
+
+       switch (p2) {
+       case DPLL_CFGCR1_KDIV_1:
+               p2 = 1;
+               break;
+       case DPLL_CFGCR1_KDIV_2:
+               p2 = 2;
+               break;
+       case DPLL_CFGCR1_KDIV_3:
+               p2 = 3;
+               break;
+       }
+
+       ref_clock = cnl_hdmi_pll_ref_clock(dev_priv);
+
+       dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK)
+               * ref_clock;
+
+       dco_freq += (((pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
+                     DPLL_CFGCR0_DCO_FRACTION_SHIFT) * ref_clock) / 0x8000;
+
+       if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
+               return 0;
+
+       return dco_freq / (p0 * p1 * p2 * 5);
+}
+
+static int icl_calc_tbt_pll_link(struct drm_i915_private *dev_priv,
+                                enum port port)
+{
+       u32 val = I915_READ(DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK;
+
+       switch (val) {
+       case DDI_CLK_SEL_NONE:
+               return 0;
+       case DDI_CLK_SEL_TBT_162:
+               return 162000;
+       case DDI_CLK_SEL_TBT_270:
+               return 270000;
+       case DDI_CLK_SEL_TBT_540:
+               return 540000;
+       case DDI_CLK_SEL_TBT_810:
+               return 810000;
+       default:
+               MISSING_CASE(val);
+               return 0;
+       }
+}
+
+static int icl_calc_mg_pll_link(struct drm_i915_private *dev_priv,
+                               const struct intel_dpll_hw_state *pll_state)
+{
+       u32 m1, m2_int, m2_frac, div1, div2, ref_clock;
+       u64 tmp;
+
+       ref_clock = dev_priv->cdclk.hw.ref;
+
+       m1 = pll_state->mg_pll_div1 & MG_PLL_DIV1_FBPREDIV_MASK;
+       m2_int = pll_state->mg_pll_div0 & MG_PLL_DIV0_FBDIV_INT_MASK;
+       m2_frac = (pll_state->mg_pll_div0 & MG_PLL_DIV0_FRACNEN_H) ?
+               (pll_state->mg_pll_div0 & MG_PLL_DIV0_FBDIV_FRAC_MASK) >>
+               MG_PLL_DIV0_FBDIV_FRAC_SHIFT : 0;
+
+       switch (pll_state->mg_clktop2_hsclkctl &
+               MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK) {
+       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2:
+               div1 = 2;
+               break;
+       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3:
+               div1 = 3;
+               break;
+       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5:
+               div1 = 5;
+               break;
+       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7:
+               div1 = 7;
+               break;
+       default:
+               MISSING_CASE(pll_state->mg_clktop2_hsclkctl);
+               return 0;
+       }
+
+       div2 = (pll_state->mg_clktop2_hsclkctl &
+               MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK) >>
+               MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT;
+
+       /* div2 value of 0 is same as 1 means no div */
+       if (div2 == 0)
+               div2 = 1;
+
+       /*
+        * Adjust the original formula to delay the division by 2^22 in order to
+        * minimize possible rounding errors.
+        */
+       tmp = (u64)m1 * m2_int * ref_clock +
+             (((u64)m1 * m2_frac * ref_clock) >> 22);
+       tmp = div_u64(tmp, 5 * div1 * div2);
+
+       return tmp;
+}
+
+static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
+{
+       int dotclock;
+
+       if (pipe_config->has_pch_encoder)
+               dotclock = intel_dotclock_calculate(pipe_config->port_clock,
+                                                   &pipe_config->fdi_m_n);
+       else if (intel_crtc_has_dp_encoder(pipe_config))
+               dotclock = intel_dotclock_calculate(pipe_config->port_clock,
+                                                   &pipe_config->dp_m_n);
+       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36)
+               dotclock = pipe_config->port_clock * 2 / 3;
+       else
+               dotclock = pipe_config->port_clock;
+
+       if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
+           !intel_crtc_has_dp_encoder(pipe_config))
+               dotclock *= 2;
+
+       if (pipe_config->pixel_multiplier)
+               dotclock /= pipe_config->pixel_multiplier;
+
+       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+}
+
+static void icl_ddi_clock_get(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dpll_hw_state *pll_state = &pipe_config->dpll_hw_state;
+       enum port port = encoder->port;
+       int link_clock;
+
+       if (intel_port_is_combophy(dev_priv, port)) {
+               link_clock = cnl_calc_wrpll_link(dev_priv, pll_state);
+       } else {
+               enum intel_dpll_id pll_id = intel_get_shared_dpll_id(dev_priv,
+                                               pipe_config->shared_dpll);
+
+               if (pll_id == DPLL_ID_ICL_TBTPLL)
+                       link_clock = icl_calc_tbt_pll_link(dev_priv, port);
+               else
+                       link_clock = icl_calc_mg_pll_link(dev_priv, pll_state);
+       }
+
+       pipe_config->port_clock = link_clock;
+
+       ddi_dotclock_get(pipe_config);
+}
+
+static void cnl_ddi_clock_get(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dpll_hw_state *pll_state = &pipe_config->dpll_hw_state;
+       int link_clock;
+
+       if (pll_state->cfgcr0 & DPLL_CFGCR0_HDMI_MODE) {
+               link_clock = cnl_calc_wrpll_link(dev_priv, pll_state);
+       } else {
+               link_clock = pll_state->cfgcr0 & DPLL_CFGCR0_LINK_RATE_MASK;
+
+               switch (link_clock) {
+               case DPLL_CFGCR0_LINK_RATE_810:
+                       link_clock = 81000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_1080:
+                       link_clock = 108000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_1350:
+                       link_clock = 135000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_1620:
+                       link_clock = 162000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_2160:
+                       link_clock = 216000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_2700:
+                       link_clock = 270000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_3240:
+                       link_clock = 324000;
+                       break;
+               case DPLL_CFGCR0_LINK_RATE_4050:
+                       link_clock = 405000;
+                       break;
+               default:
+                       WARN(1, "Unsupported link rate\n");
+                       break;
+               }
+               link_clock *= 2;
+       }
+
+       pipe_config->port_clock = link_clock;
+
+       ddi_dotclock_get(pipe_config);
+}
+
+static void skl_ddi_clock_get(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config)
+{
+       struct intel_dpll_hw_state *pll_state = &pipe_config->dpll_hw_state;
+       int link_clock;
+
+       /*
+        * ctrl1 register is already shifted for each pll, just use 0 to get
+        * the internal shift for each field
+        */
+       if (pll_state->ctrl1 & DPLL_CTRL1_HDMI_MODE(0)) {
+               link_clock = skl_calc_wrpll_link(pll_state);
+       } else {
+               link_clock = pll_state->ctrl1 & DPLL_CTRL1_LINK_RATE_MASK(0);
+               link_clock >>= DPLL_CTRL1_LINK_RATE_SHIFT(0);
+
+               switch (link_clock) {
+               case DPLL_CTRL1_LINK_RATE_810:
+                       link_clock = 81000;
+                       break;
+               case DPLL_CTRL1_LINK_RATE_1080:
+                       link_clock = 108000;
+                       break;
+               case DPLL_CTRL1_LINK_RATE_1350:
+                       link_clock = 135000;
+                       break;
+               case DPLL_CTRL1_LINK_RATE_1620:
+                       link_clock = 162000;
+                       break;
+               case DPLL_CTRL1_LINK_RATE_2160:
+                       link_clock = 216000;
+                       break;
+               case DPLL_CTRL1_LINK_RATE_2700:
+                       link_clock = 270000;
+                       break;
+               default:
+                       WARN(1, "Unsupported link rate\n");
+                       break;
+               }
+               link_clock *= 2;
+       }
+
+       pipe_config->port_clock = link_clock;
+
+       ddi_dotclock_get(pipe_config);
+}
+
+static void hsw_ddi_clock_get(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       int link_clock = 0;
+       u32 val, pll;
+
+       val = hsw_pll_to_ddi_pll_sel(pipe_config->shared_dpll);
+       switch (val & PORT_CLK_SEL_MASK) {
+       case PORT_CLK_SEL_LCPLL_810:
+               link_clock = 81000;
+               break;
+       case PORT_CLK_SEL_LCPLL_1350:
+               link_clock = 135000;
+               break;
+       case PORT_CLK_SEL_LCPLL_2700:
+               link_clock = 270000;
+               break;
+       case PORT_CLK_SEL_WRPLL1:
+               link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(0));
+               break;
+       case PORT_CLK_SEL_WRPLL2:
+               link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(1));
+               break;
+       case PORT_CLK_SEL_SPLL:
+               pll = I915_READ(SPLL_CTL) & SPLL_FREQ_MASK;
+               if (pll == SPLL_FREQ_810MHz)
+                       link_clock = 81000;
+               else if (pll == SPLL_FREQ_1350MHz)
+                       link_clock = 135000;
+               else if (pll == SPLL_FREQ_2700MHz)
+                       link_clock = 270000;
+               else {
+                       WARN(1, "bad spll freq\n");
+                       return;
+               }
+               break;
+       default:
+               WARN(1, "bad port clock sel\n");
+               return;
+       }
+
+       pipe_config->port_clock = link_clock * 2;
+
+       ddi_dotclock_get(pipe_config);
+}
+
+static int bxt_calc_pll_link(const struct intel_dpll_hw_state *pll_state)
+{
+       struct dpll clock;
+
+       clock.m1 = 2;
+       clock.m2 = (pll_state->pll0 & PORT_PLL_M2_MASK) << 22;
+       if (pll_state->pll3 & PORT_PLL_M2_FRAC_ENABLE)
+               clock.m2 |= pll_state->pll2 & PORT_PLL_M2_FRAC_MASK;
+       clock.n = (pll_state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT;
+       clock.p1 = (pll_state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT;
+       clock.p2 = (pll_state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT;
+
+       return chv_calc_dpll_params(100000, &clock);
+}
+
+static void bxt_ddi_clock_get(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config)
+{
+       pipe_config->port_clock =
+               bxt_calc_pll_link(&pipe_config->dpll_hw_state);
+
+       ddi_dotclock_get(pipe_config);
+}
+
+static void intel_ddi_clock_get(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_ddi_clock_get(encoder, pipe_config);
+       else if (IS_CANNONLAKE(dev_priv))
+               cnl_ddi_clock_get(encoder, pipe_config);
+       else if (IS_GEN9_LP(dev_priv))
+               bxt_ddi_clock_get(encoder, pipe_config);
+       else if (IS_GEN9_BC(dev_priv))
+               skl_ddi_clock_get(encoder, pipe_config);
+       else if (INTEL_GEN(dev_priv) <= 8)
+               hsw_ddi_clock_get(encoder, pipe_config);
+}
+
+void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 temp;
+
+       if (!intel_crtc_has_dp_encoder(crtc_state))
+               return;
+
+       WARN_ON(transcoder_is_dsi(cpu_transcoder));
+
+       temp = TRANS_MSA_SYNC_CLK;
+
+       if (crtc_state->limited_color_range)
+               temp |= TRANS_MSA_CEA_RANGE;
+
+       switch (crtc_state->pipe_bpp) {
+       case 18:
+               temp |= TRANS_MSA_6_BPC;
+               break;
+       case 24:
+               temp |= TRANS_MSA_8_BPC;
+               break;
+       case 30:
+               temp |= TRANS_MSA_10_BPC;
+               break;
+       case 36:
+               temp |= TRANS_MSA_12_BPC;
+               break;
+       default:
+               MISSING_CASE(crtc_state->pipe_bpp);
+               break;
+       }
+
+       /*
+        * As per DP 1.2 spec section 2.3.4.3 while sending
+        * YCBCR 444 signals we should program MSA MISC1/0 fields with
+        * colorspace information. The output colorspace encoding is BT601.
+        */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+               temp |= TRANS_MSA_SAMPLING_444 | TRANS_MSA_CLRSP_YCBCR;
+       /*
+        * As per DP 1.4a spec section 2.2.4.3 [MSA Field for Indication
+        * of Color Encoding Format and Content Color Gamut] while sending
+        * YCBCR 420 signals we should program MSA MISC1 fields which
+        * indicate VSC SDP for the Pixel Encoding/Colorimetry Format.
+        */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+               temp |= TRANS_MSA_USE_VSC_SDP;
+       I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp);
+}
+
+void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
+                                   bool state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 temp;
+
+       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+       if (state == true)
+               temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
+       else
+               temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
+       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
+}
+
+void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       enum port port = encoder->port;
+       u32 temp;
+
+       /* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */
+       temp = TRANS_DDI_FUNC_ENABLE;
+       temp |= TRANS_DDI_SELECT_PORT(port);
+
+       switch (crtc_state->pipe_bpp) {
+       case 18:
+               temp |= TRANS_DDI_BPC_6;
+               break;
+       case 24:
+               temp |= TRANS_DDI_BPC_8;
+               break;
+       case 30:
+               temp |= TRANS_DDI_BPC_10;
+               break;
+       case 36:
+               temp |= TRANS_DDI_BPC_12;
+               break;
+       default:
+               BUG();
+       }
+
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
+               temp |= TRANS_DDI_PVSYNC;
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
+               temp |= TRANS_DDI_PHSYNC;
+
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               switch (pipe) {
+               case PIPE_A:
+                       /* On Haswell, can only use the always-on power well for
+                        * eDP when not using the panel fitter, and when not
+                        * using motion blur mitigation (which we don't
+                        * support). */
+                       if (crtc_state->pch_pfit.force_thru)
+                               temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
+                       else
+                               temp |= TRANS_DDI_EDP_INPUT_A_ON;
+                       break;
+               case PIPE_B:
+                       temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
+                       break;
+               case PIPE_C:
+                       temp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
+                       break;
+               default:
+                       BUG();
+                       break;
+               }
+       }
+
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+               if (crtc_state->has_hdmi_sink)
+                       temp |= TRANS_DDI_MODE_SELECT_HDMI;
+               else
+                       temp |= TRANS_DDI_MODE_SELECT_DVI;
+
+               if (crtc_state->hdmi_scrambling)
+                       temp |= TRANS_DDI_HDMI_SCRAMBLING;
+               if (crtc_state->hdmi_high_tmds_clock_ratio)
+                       temp |= TRANS_DDI_HIGH_TMDS_CHAR_RATE;
+       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
+               temp |= TRANS_DDI_MODE_SELECT_FDI;
+               temp |= (crtc_state->fdi_lanes - 1) << 1;
+       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
+               temp |= TRANS_DDI_MODE_SELECT_DP_MST;
+               temp |= DDI_PORT_WIDTH(crtc_state->lane_count);
+       } else {
+               temp |= TRANS_DDI_MODE_SELECT_DP_SST;
+               temp |= DDI_PORT_WIDTH(crtc_state->lane_count);
+       }
+
+       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
+}
+
+void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
+       u32 val = I915_READ(reg);
+
+       val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
+       val |= TRANS_DDI_PORT_NONE;
+       I915_WRITE(reg, val);
+
+       if (dev_priv->quirks & QUIRK_INCREASE_DDI_DISABLED_TIME &&
+           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+               DRM_DEBUG_KMS("Quirk Increase DDI disabled time\n");
+               /* Quirk time at 100ms for reliable operation */
+               msleep(100);
+       }
+}
+
+int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
+                                    bool enable)
+{
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       intel_wakeref_t wakeref;
+       enum pipe pipe = 0;
+       int ret = 0;
+       u32 tmp;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    intel_encoder->power_domain);
+       if (WARN_ON(!wakeref))
+               return -ENXIO;
+
+       if (WARN_ON(!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
+               ret = -EIO;
+               goto out;
+       }
+
+       tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe));
+       if (enable)
+               tmp |= TRANS_DDI_HDCP_SIGNALLING;
+       else
+               tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
+       I915_WRITE(TRANS_DDI_FUNC_CTL(pipe), tmp);
+out:
+       intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
+       return ret;
+}
+
+bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
+{
+       struct drm_device *dev = intel_connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_encoder *encoder = intel_connector->encoder;
+       int type = intel_connector->base.connector_type;
+       enum port port = encoder->port;
+       enum transcoder cpu_transcoder;
+       intel_wakeref_t wakeref;
+       enum pipe pipe = 0;
+       u32 tmp;
+       bool ret;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       if (!encoder->get_hw_state(encoder, &pipe)) {
+               ret = false;
+               goto out;
+       }
+
+       if (HAS_TRANSCODER_EDP(dev_priv) && port == PORT_A)
+               cpu_transcoder = TRANSCODER_EDP;
+       else
+               cpu_transcoder = (enum transcoder) pipe;
+
+       tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+
+       switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
+       case TRANS_DDI_MODE_SELECT_HDMI:
+       case TRANS_DDI_MODE_SELECT_DVI:
+               ret = type == DRM_MODE_CONNECTOR_HDMIA;
+               break;
+
+       case TRANS_DDI_MODE_SELECT_DP_SST:
+               ret = type == DRM_MODE_CONNECTOR_eDP ||
+                     type == DRM_MODE_CONNECTOR_DisplayPort;
+               break;
+
+       case TRANS_DDI_MODE_SELECT_DP_MST:
+               /* if the transcoder is in MST state then
+                * connector isn't connected */
+               ret = false;
+               break;
+
+       case TRANS_DDI_MODE_SELECT_FDI:
+               ret = type == DRM_MODE_CONNECTOR_VGA;
+               break;
+
+       default:
+               ret = false;
+               break;
+       }
+
+out:
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+
+       return ret;
+}
+
+static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
+                                       u8 *pipe_mask, bool *is_dp_mst)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       enum port port = encoder->port;
+       intel_wakeref_t wakeref;
+       enum pipe p;
+       u32 tmp;
+       u8 mst_pipe_mask;
+
+       *pipe_mask = 0;
+       *is_dp_mst = false;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return;
+
+       tmp = I915_READ(DDI_BUF_CTL(port));
+       if (!(tmp & DDI_BUF_CTL_ENABLE))
+               goto out;
+
+       if (HAS_TRANSCODER_EDP(dev_priv) && port == PORT_A) {
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
+
+               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+               default:
+                       MISSING_CASE(tmp & TRANS_DDI_EDP_INPUT_MASK);
+                       /* fallthrough */
+               case TRANS_DDI_EDP_INPUT_A_ON:
+               case TRANS_DDI_EDP_INPUT_A_ONOFF:
+                       *pipe_mask = BIT(PIPE_A);
+                       break;
+               case TRANS_DDI_EDP_INPUT_B_ONOFF:
+                       *pipe_mask = BIT(PIPE_B);
+                       break;
+               case TRANS_DDI_EDP_INPUT_C_ONOFF:
+                       *pipe_mask = BIT(PIPE_C);
+                       break;
+               }
+
+               goto out;
+       }
+
+       mst_pipe_mask = 0;
+       for_each_pipe(dev_priv, p) {
+               enum transcoder cpu_transcoder = (enum transcoder)p;
+
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+
+               if ((tmp & TRANS_DDI_PORT_MASK) != TRANS_DDI_SELECT_PORT(port))
+                       continue;
+
+               if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
+                   TRANS_DDI_MODE_SELECT_DP_MST)
+                       mst_pipe_mask |= BIT(p);
+
+               *pipe_mask |= BIT(p);
+       }
+
+       if (!*pipe_mask)
+               DRM_DEBUG_KMS("No pipe for ddi port %c found\n",
+                             port_name(port));
+
+       if (!mst_pipe_mask && hweight8(*pipe_mask) > 1) {
+               DRM_DEBUG_KMS("Multiple pipes for non DP-MST port %c (pipe_mask %02x)\n",
+                             port_name(port), *pipe_mask);
+               *pipe_mask = BIT(ffs(*pipe_mask) - 1);
+       }
+
+       if (mst_pipe_mask && mst_pipe_mask != *pipe_mask)
+               DRM_DEBUG_KMS("Conflicting MST and non-MST encoders for port %c (pipe_mask %02x mst_pipe_mask %02x)\n",
+                             port_name(port), *pipe_mask, mst_pipe_mask);
+       else
+               *is_dp_mst = mst_pipe_mask;
+
+out:
+       if (*pipe_mask && IS_GEN9_LP(dev_priv)) {
+               tmp = I915_READ(BXT_PHY_CTL(port));
+               if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK |
+                           BXT_PHY_LANE_POWERDOWN_ACK |
+                           BXT_PHY_LANE_ENABLED)) != BXT_PHY_LANE_ENABLED)
+                       DRM_ERROR("Port %c enabled but PHY powered down? "
+                                 "(PHY_CTL %08x)\n", port_name(port), tmp);
+       }
+
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+}
+
+bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
+                           enum pipe *pipe)
+{
+       u8 pipe_mask;
+       bool is_mst;
+
+       intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);
+
+       if (is_mst || !pipe_mask)
+               return false;
+
+       *pipe = ffs(pipe_mask) - 1;
+
+       return true;
+}
+
+static inline enum intel_display_power_domain
+intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port)
+{
+       /* CNL+ HW requires corresponding AUX IOs to be powered up for PSR with
+        * DC states enabled at the same time, while for driver initiated AUX
+        * transfers we need the same AUX IOs to be powered but with DC states
+        * disabled. Accordingly use the AUX power domain here which leaves DC
+        * states enabled.
+        * However, for non-A AUX ports the corresponding non-EDP transcoders
+        * would have already enabled power well 2 and DC_OFF. This means we can
+        * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a
+        * specific AUX_IO reference without powering up any extra wells.
+        * Note that PSR is enabled only on Port A even though this function
+        * returns the correct domain for other ports too.
+        */
+       return dig_port->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
+                                             intel_aux_power_domain(dig_port);
+}
+
+static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
+                                       struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port;
+
+       /*
+        * TODO: Add support for MST encoders. Atm, the following should never
+        * happen since fake-MST encoders don't set their get_power_domains()
+        * hook.
+        */
+       if (WARN_ON(intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)))
+               return;
+
+       dig_port = enc_to_dig_port(&encoder->base);
+       intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
+
+       /*
+        * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
+        * ports.
+        */
+       if (intel_crtc_has_dp_encoder(crtc_state) ||
+           intel_port_is_tc(dev_priv, encoder->port))
+               intel_display_power_get(dev_priv,
+                                       intel_ddi_main_link_aux_domain(dig_port));
+
+       /*
+        * VDSC power is needed when DSC is enabled
+        */
+       if (crtc_state->dsc_params.compression_enable)
+               intel_display_power_get(dev_priv,
+                                       intel_dsc_power_domain(crtc_state));
+}
+
+void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
+       enum port port = encoder->port;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+       if (cpu_transcoder != TRANSCODER_EDP)
+               I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
+                          TRANS_CLK_SEL_PORT(port));
+}
+
+void intel_ddi_disable_pipe_clock(const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+       if (cpu_transcoder != TRANSCODER_EDP)
+               I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
+                          TRANS_CLK_SEL_DISABLED);
+}
+
+static void _skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
+                               enum port port, u8 iboost)
+{
+       u32 tmp;
+
+       tmp = I915_READ(DISPIO_CR_TX_BMU_CR0);
+       tmp &= ~(BALANCE_LEG_MASK(port) | BALANCE_LEG_DISABLE(port));
+       if (iboost)
+               tmp |= iboost << BALANCE_LEG_SHIFT(port);
+       else
+               tmp |= BALANCE_LEG_DISABLE(port);
+       I915_WRITE(DISPIO_CR_TX_BMU_CR0, tmp);
+}
+
+static void skl_ddi_set_iboost(struct intel_encoder *encoder,
+                              int level, enum intel_output_type type)
+{
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u8 iboost;
+
+       if (type == INTEL_OUTPUT_HDMI)
+               iboost = dev_priv->vbt.ddi_port_info[port].hdmi_boost_level;
+       else
+               iboost = dev_priv->vbt.ddi_port_info[port].dp_boost_level;
+
+       if (iboost == 0) {
+               const struct ddi_buf_trans *ddi_translations;
+               int n_entries;
+
+               if (type == INTEL_OUTPUT_HDMI)
+                       ddi_translations = intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
+               else if (type == INTEL_OUTPUT_EDP)
+                       ddi_translations = intel_ddi_get_buf_trans_edp(dev_priv, port, &n_entries);
+               else
+                       ddi_translations = intel_ddi_get_buf_trans_dp(dev_priv, port, &n_entries);
+
+               if (WARN_ON_ONCE(!ddi_translations))
+                       return;
+               if (WARN_ON_ONCE(level >= n_entries))
+                       level = n_entries - 1;
+
+               iboost = ddi_translations[level].i_boost;
+       }
+
+       /* Make sure that the requested I_boost is valid */
+       if (iboost && iboost != 0x1 && iboost != 0x3 && iboost != 0x7) {
+               DRM_ERROR("Invalid I_boost value %u\n", iboost);
+               return;
+       }
+
+       _skl_ddi_set_iboost(dev_priv, port, iboost);
+
+       if (port == PORT_A && intel_dig_port->max_lanes == 4)
+               _skl_ddi_set_iboost(dev_priv, PORT_E, iboost);
+}
+
+static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
+                                   int level, enum intel_output_type type)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct bxt_ddi_buf_trans *ddi_translations;
+       enum port port = encoder->port;
+       int n_entries;
+
+       if (type == INTEL_OUTPUT_HDMI)
+               ddi_translations = bxt_get_buf_trans_hdmi(dev_priv, &n_entries);
+       else if (type == INTEL_OUTPUT_EDP)
+               ddi_translations = bxt_get_buf_trans_edp(dev_priv, &n_entries);
+       else
+               ddi_translations = bxt_get_buf_trans_dp(dev_priv, &n_entries);
+
+       if (WARN_ON_ONCE(!ddi_translations))
+               return;
+       if (WARN_ON_ONCE(level >= n_entries))
+               level = n_entries - 1;
+
+       bxt_ddi_phy_set_signal_level(dev_priv, port,
+                                    ddi_translations[level].margin,
+                                    ddi_translations[level].scale,
+                                    ddi_translations[level].enable,
+                                    ddi_translations[level].deemphasis);
+}
+
+u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = encoder->port;
+       int n_entries;
+
+       if (INTEL_GEN(dev_priv) >= 11) {
+               if (intel_port_is_combophy(dev_priv, port))
+                       icl_get_combo_buf_trans(dev_priv, port, encoder->type,
+                                               intel_dp->link_rate, &n_entries);
+               else
+                       n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
+       } else if (IS_CANNONLAKE(dev_priv)) {
+               if (encoder->type == INTEL_OUTPUT_EDP)
+                       cnl_get_buf_trans_edp(dev_priv, &n_entries);
+               else
+                       cnl_get_buf_trans_dp(dev_priv, &n_entries);
+       } else if (IS_GEN9_LP(dev_priv)) {
+               if (encoder->type == INTEL_OUTPUT_EDP)
+                       bxt_get_buf_trans_edp(dev_priv, &n_entries);
+               else
+                       bxt_get_buf_trans_dp(dev_priv, &n_entries);
+       } else {
+               if (encoder->type == INTEL_OUTPUT_EDP)
+                       intel_ddi_get_buf_trans_edp(dev_priv, port, &n_entries);
+               else
+                       intel_ddi_get_buf_trans_dp(dev_priv, port, &n_entries);
+       }
+
+       if (WARN_ON(n_entries < 1))
+               n_entries = 1;
+       if (WARN_ON(n_entries > ARRAY_SIZE(index_to_dp_signal_levels)))
+               n_entries = ARRAY_SIZE(index_to_dp_signal_levels);
+
+       return index_to_dp_signal_levels[n_entries - 1] &
+               DP_TRAIN_VOLTAGE_SWING_MASK;
+}
+
+/*
+ * We assume that the full set of pre-emphasis values can be
+ * used on all DDI platforms. Should that change we need to
+ * rethink this code.
+ */
+u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder, u8 voltage_swing)
+{
+       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+               return DP_TRAIN_PRE_EMPH_LEVEL_3;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+               return DP_TRAIN_PRE_EMPH_LEVEL_2;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+               return DP_TRAIN_PRE_EMPH_LEVEL_1;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+       default:
+               return DP_TRAIN_PRE_EMPH_LEVEL_0;
+       }
+}
+
+static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
+                                  int level, enum intel_output_type type)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct cnl_ddi_buf_trans *ddi_translations;
+       enum port port = encoder->port;
+       int n_entries, ln;
+       u32 val;
+
+       if (type == INTEL_OUTPUT_HDMI)
+               ddi_translations = cnl_get_buf_trans_hdmi(dev_priv, &n_entries);
+       else if (type == INTEL_OUTPUT_EDP)
+               ddi_translations = cnl_get_buf_trans_edp(dev_priv, &n_entries);
+       else
+               ddi_translations = cnl_get_buf_trans_dp(dev_priv, &n_entries);
+
+       if (WARN_ON_ONCE(!ddi_translations))
+               return;
+       if (WARN_ON_ONCE(level >= n_entries))
+               level = n_entries - 1;
+
+       /* Set PORT_TX_DW5 Scaling Mode Sel to 010b. */
+       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
+       val &= ~SCALING_MODE_SEL_MASK;
+       val |= SCALING_MODE_SEL(2);
+       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
+
+       /* Program PORT_TX_DW2 */
+       val = I915_READ(CNL_PORT_TX_DW2_LN0(port));
+       val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                RCOMP_SCALAR_MASK);
+       val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_sel);
+       val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_sel);
+       /* Rcomp scalar is fixed as 0x98 for every table entry */
+       val |= RCOMP_SCALAR(0x98);
+       I915_WRITE(CNL_PORT_TX_DW2_GRP(port), val);
+
+       /* Program PORT_TX_DW4 */
+       /* We cannot write to GRP. It would overrite individual loadgen */
+       for (ln = 0; ln < 4; ln++) {
+               val = I915_READ(CNL_PORT_TX_DW4_LN(ln, port));
+               val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                        CURSOR_COEFF_MASK);
+               val |= POST_CURSOR_1(ddi_translations[level].dw4_post_cursor_1);
+               val |= POST_CURSOR_2(ddi_translations[level].dw4_post_cursor_2);
+               val |= CURSOR_COEFF(ddi_translations[level].dw4_cursor_coeff);
+               I915_WRITE(CNL_PORT_TX_DW4_LN(ln, port), val);
+       }
+
+       /* Program PORT_TX_DW5 */
+       /* All DW5 values are fixed for every table entry */
+       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
+       val &= ~RTERM_SELECT_MASK;
+       val |= RTERM_SELECT(6);
+       val |= TAP3_DISABLE;
+       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
+
+       /* Program PORT_TX_DW7 */
+       val = I915_READ(CNL_PORT_TX_DW7_LN0(port));
+       val &= ~N_SCALAR_MASK;
+       val |= N_SCALAR(ddi_translations[level].dw7_n_scalar);
+       I915_WRITE(CNL_PORT_TX_DW7_GRP(port), val);
+}
+
+static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
+                                   int level, enum intel_output_type type)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       int width, rate, ln;
+       u32 val;
+
+       if (type == INTEL_OUTPUT_HDMI) {
+               width = 4;
+               rate = 0; /* Rate is always < than 6GHz for HDMI */
+       } else {
+               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+               width = intel_dp->lane_count;
+               rate = intel_dp->link_rate;
+       }
+
+       /*
+        * 1. If port type is eDP or DP,
+        * set PORT_PCS_DW1 cmnkeeper_enable to 1b,
+        * else clear to 0b.
+        */
+       val = I915_READ(CNL_PORT_PCS_DW1_LN0(port));
+       if (type != INTEL_OUTPUT_HDMI)
+               val |= COMMON_KEEPER_EN;
+       else
+               val &= ~COMMON_KEEPER_EN;
+       I915_WRITE(CNL_PORT_PCS_DW1_GRP(port), val);
+
+       /* 2. Program loadgen select */
+       /*
+        * Program PORT_TX_DW4_LN depending on Bit rate and used lanes
+        * <= 6 GHz and 4 lanes (LN0=0, LN1=1, LN2=1, LN3=1)
+        * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0)
+        * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0)
+        */
+       for (ln = 0; ln <= 3; ln++) {
+               val = I915_READ(CNL_PORT_TX_DW4_LN(ln, port));
+               val &= ~LOADGEN_SELECT;
+
+               if ((rate <= 600000 && width == 4 && ln >= 1)  ||
+                   (rate <= 600000 && width < 4 && (ln == 1 || ln == 2))) {
+                       val |= LOADGEN_SELECT;
+               }
+               I915_WRITE(CNL_PORT_TX_DW4_LN(ln, port), val);
+       }
+
+       /* 3. Set PORT_CL_DW5 SUS Clock Config to 11b */
+       val = I915_READ(CNL_PORT_CL1CM_DW5);
+       val |= SUS_CLOCK_CONFIG;
+       I915_WRITE(CNL_PORT_CL1CM_DW5, val);
+
+       /* 4. Clear training enable to change swing values */
+       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
+       val &= ~TX_TRAINING_EN;
+       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
+
+       /* 5. Program swing and de-emphasis */
+       cnl_ddi_vswing_program(encoder, level, type);
+
+       /* 6. Set training enable to trigger update */
+       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
+       val |= TX_TRAINING_EN;
+       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
+}
+
+static void icl_ddi_combo_vswing_program(struct drm_i915_private *dev_priv,
+                                       u32 level, enum port port, int type,
+                                       int rate)
+{
+       const struct cnl_ddi_buf_trans *ddi_translations = NULL;
+       u32 n_entries, val;
+       int ln;
+
+       ddi_translations = icl_get_combo_buf_trans(dev_priv, port, type,
+                                                  rate, &n_entries);
+       if (!ddi_translations)
+               return;
+
+       if (level >= n_entries) {
+               DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.", level, n_entries - 1);
+               level = n_entries - 1;
+       }
+
+       /* Set PORT_TX_DW5 */
+       val = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+       val &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK |
+                 TAP2_DISABLE | TAP3_DISABLE);
+       val |= SCALING_MODE_SEL(0x2);
+       val |= RTERM_SELECT(0x6);
+       val |= TAP3_DISABLE;
+       I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
+
+       /* Program PORT_TX_DW2 */
+       val = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+       val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                RCOMP_SCALAR_MASK);
+       val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_sel);
+       val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_sel);
+       /* Program Rcomp scalar for every table entry */
+       val |= RCOMP_SCALAR(0x98);
+       I915_WRITE(ICL_PORT_TX_DW2_GRP(port), val);
+
+       /* Program PORT_TX_DW4 */
+       /* We cannot write to GRP. It would overwrite individual loadgen. */
+       for (ln = 0; ln <= 3; ln++) {
+               val = I915_READ(ICL_PORT_TX_DW4_LN(ln, port));
+               val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                        CURSOR_COEFF_MASK);
+               val |= POST_CURSOR_1(ddi_translations[level].dw4_post_cursor_1);
+               val |= POST_CURSOR_2(ddi_translations[level].dw4_post_cursor_2);
+               val |= CURSOR_COEFF(ddi_translations[level].dw4_cursor_coeff);
+               I915_WRITE(ICL_PORT_TX_DW4_LN(ln, port), val);
+       }
+
+       /* Program PORT_TX_DW7 */
+       val = I915_READ(ICL_PORT_TX_DW7_LN0(port));
+       val &= ~N_SCALAR_MASK;
+       val |= N_SCALAR(ddi_translations[level].dw7_n_scalar);
+       I915_WRITE(ICL_PORT_TX_DW7_GRP(port), val);
+}
+
+static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
+                                             u32 level,
+                                             enum intel_output_type type)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       int width = 0;
+       int rate = 0;
+       u32 val;
+       int ln = 0;
+
+       if (type == INTEL_OUTPUT_HDMI) {
+               width = 4;
+               /* Rate is always < than 6GHz for HDMI */
+       } else {
+               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+               width = intel_dp->lane_count;
+               rate = intel_dp->link_rate;
+       }
+
+       /*
+        * 1. If port type is eDP or DP,
+        * set PORT_PCS_DW1 cmnkeeper_enable to 1b,
+        * else clear to 0b.
+        */
+       val = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
+       if (type == INTEL_OUTPUT_HDMI)
+               val &= ~COMMON_KEEPER_EN;
+       else
+               val |= COMMON_KEEPER_EN;
+       I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), val);
+
+       /* 2. Program loadgen select */
+       /*
+        * Program PORT_TX_DW4_LN depending on Bit rate and used lanes
+        * <= 6 GHz and 4 lanes (LN0=0, LN1=1, LN2=1, LN3=1)
+        * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0)
+        * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0)
+        */
+       for (ln = 0; ln <= 3; ln++) {
+               val = I915_READ(ICL_PORT_TX_DW4_LN(ln, port));
+               val &= ~LOADGEN_SELECT;
+
+               if ((rate <= 600000 && width == 4 && ln >= 1) ||
+                   (rate <= 600000 && width < 4 && (ln == 1 || ln == 2))) {
+                       val |= LOADGEN_SELECT;
+               }
+               I915_WRITE(ICL_PORT_TX_DW4_LN(ln, port), val);
+       }
+
+       /* 3. Set PORT_CL_DW5 SUS Clock Config to 11b */
+       val = I915_READ(ICL_PORT_CL_DW5(port));
+       val |= SUS_CLOCK_CONFIG;
+       I915_WRITE(ICL_PORT_CL_DW5(port), val);
+
+       /* 4. Clear training enable to change swing values */
+       val = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+       val &= ~TX_TRAINING_EN;
+       I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
+
+       /* 5. Program swing and de-emphasis */
+       icl_ddi_combo_vswing_program(dev_priv, level, port, type, rate);
+
+       /* 6. Set training enable to trigger update */
+       val = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+       val |= TX_TRAINING_EN;
+       I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
+}
+
+static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
+                                          int link_clock,
+                                          u32 level)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       const struct icl_mg_phy_ddi_buf_trans *ddi_translations;
+       u32 n_entries, val;
+       int ln;
+
+       n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
+       ddi_translations = icl_mg_phy_ddi_translations;
+       /* The table does not have values for level 3 and level 9. */
+       if (level >= n_entries || level == 3 || level == 9) {
+               DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.",
+                             level, n_entries - 2);
+               level = n_entries - 2;
+       }
+
+       /* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_TX1_LINK_PARAMS(ln, port));
+               val &= ~CRI_USE_FS32;
+               I915_WRITE(MG_TX1_LINK_PARAMS(ln, port), val);
+
+               val = I915_READ(MG_TX2_LINK_PARAMS(ln, port));
+               val &= ~CRI_USE_FS32;
+               I915_WRITE(MG_TX2_LINK_PARAMS(ln, port), val);
+       }
+
+       /* Program MG_TX_SWINGCTRL with values from vswing table */
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_TX1_SWINGCTRL(ln, port));
+               val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
+               val |= CRI_TXDEEMPH_OVERRIDE_17_12(
+                       ddi_translations[level].cri_txdeemph_override_17_12);
+               I915_WRITE(MG_TX1_SWINGCTRL(ln, port), val);
+
+               val = I915_READ(MG_TX2_SWINGCTRL(ln, port));
+               val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
+               val |= CRI_TXDEEMPH_OVERRIDE_17_12(
+                       ddi_translations[level].cri_txdeemph_override_17_12);
+               I915_WRITE(MG_TX2_SWINGCTRL(ln, port), val);
+       }
+
+       /* Program MG_TX_DRVCTRL with values from vswing table */
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_TX1_DRVCTRL(ln, port));
+               val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
+                        CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
+               val |= CRI_TXDEEMPH_OVERRIDE_5_0(
+                       ddi_translations[level].cri_txdeemph_override_5_0) |
+                       CRI_TXDEEMPH_OVERRIDE_11_6(
+                               ddi_translations[level].cri_txdeemph_override_11_6) |
+                       CRI_TXDEEMPH_OVERRIDE_EN;
+               I915_WRITE(MG_TX1_DRVCTRL(ln, port), val);
+
+               val = I915_READ(MG_TX2_DRVCTRL(ln, port));
+               val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
+                        CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
+               val |= CRI_TXDEEMPH_OVERRIDE_5_0(
+                       ddi_translations[level].cri_txdeemph_override_5_0) |
+                       CRI_TXDEEMPH_OVERRIDE_11_6(
+                               ddi_translations[level].cri_txdeemph_override_11_6) |
+                       CRI_TXDEEMPH_OVERRIDE_EN;
+               I915_WRITE(MG_TX2_DRVCTRL(ln, port), val);
+
+               /* FIXME: Program CRI_LOADGEN_SEL after the spec is updated */
+       }
+
+       /*
+        * Program MG_CLKHUB<LN, port being used> with value from frequency table
+        * In case of Legacy mode on MG PHY, both TX1 and TX2 enabled so use the
+        * values from table for which TX1 and TX2 enabled.
+        */
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_CLKHUB(ln, port));
+               if (link_clock < 300000)
+                       val |= CFG_LOW_RATE_LKREN_EN;
+               else
+                       val &= ~CFG_LOW_RATE_LKREN_EN;
+               I915_WRITE(MG_CLKHUB(ln, port), val);
+       }
+
+       /* Program the MG_TX_DCC<LN, port being used> based on the link frequency */
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_TX1_DCC(ln, port));
+               val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
+               if (link_clock <= 500000) {
+                       val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
+               } else {
+                       val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
+                               CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
+               }
+               I915_WRITE(MG_TX1_DCC(ln, port), val);
+
+               val = I915_READ(MG_TX2_DCC(ln, port));
+               val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
+               if (link_clock <= 500000) {
+                       val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
+               } else {
+                       val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
+                               CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
+               }
+               I915_WRITE(MG_TX2_DCC(ln, port), val);
+       }
+
+       /* Program MG_TX_PISO_READLOAD with values from vswing table */
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_TX1_PISO_READLOAD(ln, port));
+               val |= CRI_CALCINIT;
+               I915_WRITE(MG_TX1_PISO_READLOAD(ln, port), val);
+
+               val = I915_READ(MG_TX2_PISO_READLOAD(ln, port));
+               val |= CRI_CALCINIT;
+               I915_WRITE(MG_TX2_PISO_READLOAD(ln, port), val);
+       }
+}
+
+static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
+                                   int link_clock,
+                                   u32 level,
+                                   enum intel_output_type type)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+
+       if (intel_port_is_combophy(dev_priv, port))
+               icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
+       else
+               icl_mg_phy_ddi_vswing_sequence(encoder, link_clock, level);
+}
+
+static u32 translate_signal_level(int signal_levels)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(index_to_dp_signal_levels); i++) {
+               if (index_to_dp_signal_levels[i] == signal_levels)
+                       return i;
+       }
+
+       WARN(1, "Unsupported voltage swing/pre-emphasis level: 0x%x\n",
+            signal_levels);
+
+       return 0;
+}
+
+static u32 intel_ddi_dp_level(struct intel_dp *intel_dp)
+{
+       u8 train_set = intel_dp->train_set[0];
+       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+                                        DP_TRAIN_PRE_EMPHASIS_MASK);
+
+       return translate_signal_level(signal_levels);
+}
+
+u32 bxt_signal_levels(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
+       struct intel_encoder *encoder = &dport->base;
+       int level = intel_ddi_dp_level(intel_dp);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
+                                       level, encoder->type);
+       else if (IS_CANNONLAKE(dev_priv))
+               cnl_ddi_vswing_sequence(encoder, level, encoder->type);
+       else
+               bxt_ddi_vswing_sequence(encoder, level, encoder->type);
+
+       return 0;
+}
+
+u32 ddi_signal_levels(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
+       struct intel_encoder *encoder = &dport->base;
+       int level = intel_ddi_dp_level(intel_dp);
+
+       if (IS_GEN9_BC(dev_priv))
+               skl_ddi_set_iboost(encoder, level, encoder->type);
+
+       return DDI_BUF_TRANS_SELECT(level);
+}
+
+static inline
+u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv,
+                             enum port port)
+{
+       if (intel_port_is_combophy(dev_priv, port)) {
+               return ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+       } else if (intel_port_is_tc(dev_priv, port)) {
+               enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+
+               return ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port);
+       }
+
+       return 0;
+}
+
+static void icl_map_plls_to_ports(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+       enum port port = encoder->port;
+       u32 val;
+
+       mutex_lock(&dev_priv->dpll_lock);
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0);
+
+       if (intel_port_is_combophy(dev_priv, port)) {
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
+               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+               POSTING_READ(DPCLKA_CFGCR0_ICL);
+       }
+
+       val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port);
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
+
+       mutex_lock(&dev_priv->dpll_lock);
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port);
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val;
+       enum port port;
+       u32 port_mask;
+       bool ddi_clk_needed;
+
+       /*
+        * In case of DP MST, we sanitize the primary encoder only, not the
+        * virtual ones.
+        */
+       if (encoder->type == INTEL_OUTPUT_DP_MST)
+               return;
+
+       if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) {
+               u8 pipe_mask;
+               bool is_mst;
+
+               intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);
+               /*
+                * In the unlikely case that BIOS enables DP in MST mode, just
+                * warn since our MST HW readout is incomplete.
+                */
+               if (WARN_ON(is_mst))
+                       return;
+       }
+
+       port_mask = BIT(encoder->port);
+       ddi_clk_needed = encoder->base.crtc;
+
+       if (encoder->type == INTEL_OUTPUT_DSI) {
+               struct intel_encoder *other_encoder;
+
+               port_mask = intel_dsi_encoder_ports(encoder);
+               /*
+                * Sanity check that we haven't incorrectly registered another
+                * encoder using any of the ports of this DSI encoder.
+                */
+               for_each_intel_encoder(&dev_priv->drm, other_encoder) {
+                       if (other_encoder == encoder)
+                               continue;
+
+                       if (WARN_ON(port_mask & BIT(other_encoder->port)))
+                               return;
+               }
+               /*
+                * For DSI we keep the ddi clocks gated
+                * except during enable/disable sequence.
+                */
+               ddi_clk_needed = false;
+       }
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_port_masked(port, port_mask) {
+               bool ddi_clk_ungated = !(val &
+                                        icl_dpclka_cfgcr0_clk_off(dev_priv,
+                                                                  port));
+
+               if (ddi_clk_needed == ddi_clk_ungated)
+                       continue;
+
+               /*
+                * Punt on the case now where clock is gated, but it would
+                * be needed by the port. Something else is really broken then.
+                */
+               if (WARN_ON(ddi_clk_needed))
+                       continue;
+
+               DRM_NOTE("Port %c is disabled/in DSI mode with an ungated DDI clock, gate it\n",
+                        port_name(port));
+               val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port);
+               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+       }
+}
+
+static void intel_ddi_clk_select(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
+       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+
+       if (WARN_ON(!pll))
+               return;
+
+       mutex_lock(&dev_priv->dpll_lock);
+
+       if (INTEL_GEN(dev_priv) >= 11) {
+               if (!intel_port_is_combophy(dev_priv, port))
+                       I915_WRITE(DDI_CLK_SEL(port),
+                                  icl_pll_to_ddi_clk_sel(encoder, crtc_state));
+       } else if (IS_CANNONLAKE(dev_priv)) {
+               /* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */
+               val = I915_READ(DPCLKA_CFGCR0);
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
+               I915_WRITE(DPCLKA_CFGCR0, val);
+
+               /*
+                * Configure DPCLKA_CFGCR0 to turn on the clock for the DDI.
+                * This step and the step before must be done with separate
+                * register writes.
+                */
+               val = I915_READ(DPCLKA_CFGCR0);
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+               I915_WRITE(DPCLKA_CFGCR0, val);
+       } else if (IS_GEN9_BC(dev_priv)) {
+               /* DDI -> PLL mapping  */
+               val = I915_READ(DPLL_CTRL2);
+
+               val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
+                        DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
+               val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) |
+                       DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
+
+               I915_WRITE(DPLL_CTRL2, val);
+
+       } else if (INTEL_GEN(dev_priv) < 9) {
+               I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
+       }
+
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void intel_ddi_clk_disable(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+
+       if (INTEL_GEN(dev_priv) >= 11) {
+               if (!intel_port_is_combophy(dev_priv, port))
+                       I915_WRITE(DDI_CLK_SEL(port), DDI_CLK_SEL_NONE);
+       } else if (IS_CANNONLAKE(dev_priv)) {
+               I915_WRITE(DPCLKA_CFGCR0, I915_READ(DPCLKA_CFGCR0) |
+                          DPCLKA_CFGCR0_DDI_CLK_OFF(port));
+       } else if (IS_GEN9_BC(dev_priv)) {
+               I915_WRITE(DPLL_CTRL2, I915_READ(DPLL_CTRL2) |
+                          DPLL_CTRL2_DDI_CLK_OFF(port));
+       } else if (INTEL_GEN(dev_priv) < 9) {
+               I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
+       }
+}
+
+static void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum port port = dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       u32 val;
+       int ln;
+
+       if (tc_port == PORT_TC_NONE)
+               return;
+
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_DP_MODE(ln, port));
+               val |= MG_DP_MODE_CFG_TR2PWR_GATING |
+                      MG_DP_MODE_CFG_TRPWR_GATING |
+                      MG_DP_MODE_CFG_CLNPWR_GATING |
+                      MG_DP_MODE_CFG_DIGPWR_GATING |
+                      MG_DP_MODE_CFG_GAONPWR_GATING;
+               I915_WRITE(MG_DP_MODE(ln, port), val);
+       }
+
+       val = I915_READ(MG_MISC_SUS0(tc_port));
+       val |= MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(3) |
+              MG_MISC_SUS0_CFG_TR2PWR_GATING |
+              MG_MISC_SUS0_CFG_CL2PWR_GATING |
+              MG_MISC_SUS0_CFG_GAONPWR_GATING |
+              MG_MISC_SUS0_CFG_TRPWR_GATING |
+              MG_MISC_SUS0_CFG_CL1PWR_GATING |
+              MG_MISC_SUS0_CFG_DGPWR_GATING;
+       I915_WRITE(MG_MISC_SUS0(tc_port), val);
+}
+
+static void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum port port = dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       u32 val;
+       int ln;
+
+       if (tc_port == PORT_TC_NONE)
+               return;
+
+       for (ln = 0; ln < 2; ln++) {
+               val = I915_READ(MG_DP_MODE(ln, port));
+               val &= ~(MG_DP_MODE_CFG_TR2PWR_GATING |
+                        MG_DP_MODE_CFG_TRPWR_GATING |
+                        MG_DP_MODE_CFG_CLNPWR_GATING |
+                        MG_DP_MODE_CFG_DIGPWR_GATING |
+                        MG_DP_MODE_CFG_GAONPWR_GATING);
+               I915_WRITE(MG_DP_MODE(ln, port), val);
+       }
+
+       val = I915_READ(MG_MISC_SUS0(tc_port));
+       val &= ~(MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK |
+                MG_MISC_SUS0_CFG_TR2PWR_GATING |
+                MG_MISC_SUS0_CFG_CL2PWR_GATING |
+                MG_MISC_SUS0_CFG_GAONPWR_GATING |
+                MG_MISC_SUS0_CFG_TRPWR_GATING |
+                MG_MISC_SUS0_CFG_CL1PWR_GATING |
+                MG_MISC_SUS0_CFG_DGPWR_GATING);
+       I915_WRITE(MG_MISC_SUS0(tc_port), val);
+}
+
+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;
+
+       if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT)
+               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:
+               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);
+
+               switch (lane_info) {
+               case 0x1:
+               case 0x4:
+                       break;
+               case 0x2:
+                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE;
+                       break;
+               case 0x3:
+                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE |
+                              MG_DP_MODE_CFG_DP_X2_MODE;
+                       break;
+               case 0x8:
+                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE;
+                       break;
+               case 0xC:
+                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE |
+                              MG_DP_MODE_CFG_DP_X2_MODE;
+                       break;
+               case 0xF:
+                       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;
+                       break;
+               default:
+                       MISSING_CASE(lane_info);
+               }
+               break;
+
+       case TC_PORT_LEGACY:
+               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;
+               break;
+
+       default:
+               MISSING_CASE(intel_dig_port->tc_type);
+               return;
+       }
+
+       I915_WRITE(MG_DP_MODE(0, port), ln0);
+       I915_WRITE(MG_DP_MODE(1, port), ln1);
+}
+
+static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
+                                       const struct intel_crtc_state *crtc_state)
+{
+       if (!crtc_state->fec_enable)
+               return;
+
+       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0)
+               DRM_DEBUG_KMS("Failed to set FEC_READY in the sink\n");
+}
+
+static void intel_ddi_enable_fec(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
+
+       if (!crtc_state->fec_enable)
+               return;
+
+       val = I915_READ(DP_TP_CTL(port));
+       val |= DP_TP_CTL_FEC_ENABLE;
+       I915_WRITE(DP_TP_CTL(port), val);
+
+       if (intel_wait_for_register(&dev_priv->uncore, DP_TP_STATUS(port),
+                                   DP_TP_STATUS_FEC_ENABLE_LIVE,
+                                   DP_TP_STATUS_FEC_ENABLE_LIVE,
+                                   1))
+               DRM_ERROR("Timed out waiting for FEC Enable Status\n");
+}
+
+static void intel_ddi_disable_fec_state(struct intel_encoder *encoder,
+                                       const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
+
+       if (!crtc_state->fec_enable)
+               return;
+
+       val = I915_READ(DP_TP_CTL(port));
+       val &= ~DP_TP_CTL_FEC_ENABLE;
+       I915_WRITE(DP_TP_CTL(port), val);
+       POSTING_READ(DP_TP_CTL(port));
+}
+
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+                                   const struct intel_crtc_state *crtc_state,
+                                   const struct drm_connector_state *conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
+       int level = intel_ddi_dp_level(intel_dp);
+
+       WARN_ON(is_mst && (port == PORT_A || port == PORT_E));
+
+       intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
+                                crtc_state->lane_count, is_mst);
+
+       intel_edp_panel_on(intel_dp);
+
+       intel_ddi_clk_select(encoder, crtc_state);
+
+       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);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
+                                       level, encoder->type);
+       else if (IS_CANNONLAKE(dev_priv))
+               cnl_ddi_vswing_sequence(encoder, level, encoder->type);
+       else if (IS_GEN9_LP(dev_priv))
+               bxt_ddi_vswing_sequence(encoder, level, encoder->type);
+       else
+               intel_prepare_dp_ddi_buffers(encoder, crtc_state);
+
+       if (intel_port_is_combophy(dev_priv, port)) {
+               bool lane_reversal =
+                       dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
+
+               intel_combo_phy_power_up_lanes(dev_priv, port, false,
+                                              crtc_state->lane_count,
+                                              lane_reversal);
+       }
+
+       intel_ddi_init_dp_buf_reg(encoder);
+       if (!is_mst)
+               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
+                                             true);
+       intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
+       intel_dp_start_link_train(intel_dp);
+       if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
+               intel_dp_stop_link_train(intel_dp);
+
+       intel_ddi_enable_fec(encoder, crtc_state);
+
+       icl_enable_phy_clock_gating(dig_port);
+
+       if (!is_mst)
+               intel_ddi_enable_pipe_clock(crtc_state);
+
+       intel_dsc_enable(encoder, crtc_state);
+}
+
+static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
+                                     const struct intel_crtc_state *crtc_state,
+                                     const struct drm_connector_state *conn_state)
+{
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       int level = intel_ddi_hdmi_level(dev_priv, port);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
+       intel_ddi_clk_select(encoder, crtc_state);
+
+       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);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
+                                       level, INTEL_OUTPUT_HDMI);
+       else if (IS_CANNONLAKE(dev_priv))
+               cnl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+       else if (IS_GEN9_LP(dev_priv))
+               bxt_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+       else
+               intel_prepare_hdmi_ddi_buffers(encoder, level);
+
+       icl_enable_phy_clock_gating(dig_port);
+
+       if (IS_GEN9_BC(dev_priv))
+               skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI);
+
+       intel_ddi_enable_pipe_clock(crtc_state);
+
+       intel_dig_port->set_infoframes(encoder,
+                                      crtc_state->has_infoframe,
+                                      crtc_state, conn_state);
+}
+
+static void intel_ddi_pre_enable(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+
+       /*
+        * When called from DP MST code:
+        * - conn_state will be NULL
+        * - encoder will be the main encoder (ie. mst->primary)
+        * - the main connector associated with this port
+        *   won't be active or linked to a crtc
+        * - crtc_state will be the state of the first stream to
+        *   be activated on this port, and it may not be the same
+        *   stream that will be deactivated last, but each stream
+        *   should have a state that is identical when it comes to
+        *   the DP link parameteres
+        */
+
+       WARN_ON(crtc_state->has_pch_encoder);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_map_plls_to_ports(encoder, crtc_state);
+
+       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+               intel_ddi_pre_enable_hdmi(encoder, crtc_state, conn_state);
+       } else {
+               struct intel_lspcon *lspcon =
+                               enc_to_intel_lspcon(&encoder->base);
+
+               intel_ddi_pre_enable_dp(encoder, crtc_state, conn_state);
+               if (lspcon->active) {
+                       struct intel_digital_port *dig_port =
+                                       enc_to_dig_port(&encoder->base);
+
+                       dig_port->set_infoframes(encoder,
+                                                crtc_state->has_infoframe,
+                                                crtc_state, conn_state);
+               }
+       }
+}
+
+static void intel_disable_ddi_buf(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       bool wait = false;
+       u32 val;
+
+       val = I915_READ(DDI_BUF_CTL(port));
+       if (val & DDI_BUF_CTL_ENABLE) {
+               val &= ~DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(port), val);
+               wait = true;
+       }
+
+       val = I915_READ(DP_TP_CTL(port));
+       val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
+       val |= DP_TP_CTL_LINK_TRAIN_PAT1;
+       I915_WRITE(DP_TP_CTL(port), val);
+
+       /* Disable FEC in DP Sink */
+       intel_ddi_disable_fec_state(encoder, crtc_state);
+
+       if (wait)
+               intel_wait_ddi_buf_idle(dev_priv, port);
+}
+
+static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
+                                     const struct intel_crtc_state *old_crtc_state,
+                                     const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_dp *intel_dp = &dig_port->dp;
+       bool is_mst = intel_crtc_has_type(old_crtc_state,
+                                         INTEL_OUTPUT_DP_MST);
+
+       if (!is_mst) {
+               intel_ddi_disable_pipe_clock(old_crtc_state);
+               /*
+                * Power down sink before disabling the port, otherwise we end
+                * up getting interrupts from the sink on detecting link loss.
+                */
+               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+       }
+
+       intel_disable_ddi_buf(encoder, old_crtc_state);
+
+       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);
+
+       intel_ddi_clk_disable(encoder);
+}
+
+static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
+                                       const struct intel_crtc_state *old_crtc_state,
+                                       const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
+
+       dig_port->set_infoframes(encoder, false,
+                                old_crtc_state, old_conn_state);
+
+       intel_ddi_disable_pipe_clock(old_crtc_state);
+
+       intel_disable_ddi_buf(encoder, old_crtc_state);
+
+       intel_display_power_put_unchecked(dev_priv,
+                                         dig_port->ddi_io_power_domain);
+
+       intel_ddi_clk_disable(encoder);
+
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
+}
+
+static void intel_ddi_post_disable(struct intel_encoder *encoder,
+                                  const struct intel_crtc_state *old_crtc_state,
+                                  const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       /*
+        * When called from DP MST code:
+        * - old_conn_state will be NULL
+        * - encoder will be the main encoder (ie. mst->primary)
+        * - the main connector associated with this port
+        *   won't be active or linked to a crtc
+        * - old_crtc_state will be the state of the last stream to
+        *   be deactivated on this port, and it may not be the same
+        *   stream that was activated last, but each stream
+        *   should have a state that is identical when it comes to
+        *   the DP link parameteres
+        */
+
+       if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
+               intel_ddi_post_disable_hdmi(encoder,
+                                           old_crtc_state, old_conn_state);
+       else
+               intel_ddi_post_disable_dp(encoder,
+                                         old_crtc_state, old_conn_state);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_unmap_plls_to_ports(encoder);
+}
+
+void intel_ddi_fdi_post_disable(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *old_crtc_state,
+                               const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val;
+
+       /*
+        * Bspec lists this as both step 13 (before DDI_BUF_CTL disable)
+        * and step 18 (after clearing PORT_CLK_SEL). Based on a BUN,
+        * step 13 is the correct place for it. Step 18 is where it was
+        * originally before the BUN.
+        */
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
+       val &= ~FDI_RX_ENABLE;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
+
+       intel_disable_ddi_buf(encoder, old_crtc_state);
+       intel_ddi_clk_disable(encoder);
+
+       val = I915_READ(FDI_RX_MISC(PIPE_A));
+       val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
+       val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
+       I915_WRITE(FDI_RX_MISC(PIPE_A), val);
+
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
+       val &= ~FDI_PCDCLK;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
+
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
+       val &= ~FDI_RX_PLL_ENABLE;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
+}
+
+static void intel_enable_ddi_dp(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *crtc_state,
+                               const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = encoder->port;
+
+       if (port == PORT_A && INTEL_GEN(dev_priv) < 9)
+               intel_dp_stop_link_train(intel_dp);
+
+       intel_edp_backlight_on(crtc_state, conn_state);
+       intel_psr_enable(intel_dp, crtc_state);
+       intel_dp_ycbcr_420_enable(intel_dp, crtc_state);
+       intel_edp_drrs_enable(intel_dp, crtc_state);
+
+       if (crtc_state->has_audio)
+               intel_audio_codec_enable(encoder, crtc_state, conn_state);
+}
+
+static i915_reg_t
+gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv,
+                              enum port port)
+{
+       static const i915_reg_t regs[] = {
+               [PORT_A] = CHICKEN_TRANS_EDP,
+               [PORT_B] = CHICKEN_TRANS_A,
+               [PORT_C] = CHICKEN_TRANS_B,
+               [PORT_D] = CHICKEN_TRANS_C,
+               [PORT_E] = CHICKEN_TRANS_A,
+       };
+
+       WARN_ON(INTEL_GEN(dev_priv) < 9);
+
+       if (WARN_ON(port < PORT_A || port > PORT_E))
+               port = PORT_A;
+
+       return regs[port];
+}
+
+static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       struct drm_connector *connector = conn_state->connector;
+       enum port port = encoder->port;
+
+       if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
+                                              crtc_state->hdmi_high_tmds_clock_ratio,
+                                              crtc_state->hdmi_scrambling))
+               DRM_ERROR("[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n",
+                         connector->base.id, connector->name);
+
+       /* Display WA #1143: skl,kbl,cfl */
+       if (IS_GEN9_BC(dev_priv)) {
+               /*
+                * For some reason these chicken bits have been
+                * stuffed into a transcoder register, event though
+                * the bits affect a specific DDI port rather than
+                * a specific transcoder.
+                */
+               i915_reg_t reg = gen9_chicken_trans_reg_by_port(dev_priv, port);
+               u32 val;
+
+               val = I915_READ(reg);
+
+               if (port == PORT_E)
+                       val |= DDIE_TRAINING_OVERRIDE_ENABLE |
+                               DDIE_TRAINING_OVERRIDE_VALUE;
+               else
+                       val |= DDI_TRAINING_OVERRIDE_ENABLE |
+                               DDI_TRAINING_OVERRIDE_VALUE;
+
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+
+               udelay(1);
+
+               if (port == PORT_E)
+                       val &= ~(DDIE_TRAINING_OVERRIDE_ENABLE |
+                                DDIE_TRAINING_OVERRIDE_VALUE);
+               else
+                       val &= ~(DDI_TRAINING_OVERRIDE_ENABLE |
+                                DDI_TRAINING_OVERRIDE_VALUE);
+
+               I915_WRITE(reg, val);
+       }
+
+       /* In HDMI/DVI mode, the port width, and swing/emphasis values
+        * are ignored so nothing special needs to be done besides
+        * enabling the port.
+        */
+       I915_WRITE(DDI_BUF_CTL(port),
+                  dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE);
+
+       if (crtc_state->has_audio)
+               intel_audio_codec_enable(encoder, crtc_state, conn_state);
+}
+
+static void intel_enable_ddi(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *crtc_state,
+                            const struct drm_connector_state *conn_state)
+{
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+               intel_enable_ddi_hdmi(encoder, crtc_state, conn_state);
+       else
+               intel_enable_ddi_dp(encoder, crtc_state, conn_state);
+
+       /* Enable hdcp if it's desired */
+       if (conn_state->content_protection ==
+           DRM_MODE_CONTENT_PROTECTION_DESIRED)
+               intel_hdcp_enable(to_intel_connector(conn_state->connector));
+}
+
+static void intel_disable_ddi_dp(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *old_crtc_state,
+                                const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+       intel_dp->link_trained = false;
+
+       if (old_crtc_state->has_audio)
+               intel_audio_codec_disable(encoder,
+                                         old_crtc_state, old_conn_state);
+
+       intel_edp_drrs_disable(intel_dp, old_crtc_state);
+       intel_psr_disable(intel_dp, old_crtc_state);
+       intel_edp_backlight_off(old_conn_state);
+       /* Disable the decompression in DP Sink */
+       intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state,
+                                             false);
+}
+
+static void intel_disable_ddi_hdmi(struct intel_encoder *encoder,
+                                  const struct intel_crtc_state *old_crtc_state,
+                                  const struct drm_connector_state *old_conn_state)
+{
+       struct drm_connector *connector = old_conn_state->connector;
+
+       if (old_crtc_state->has_audio)
+               intel_audio_codec_disable(encoder,
+                                         old_crtc_state, old_conn_state);
+
+       if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
+                                              false, false))
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Failed to reset sink scrambling/TMDS bit clock ratio\n",
+                             connector->base.id, connector->name);
+}
+
+static void intel_disable_ddi(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+{
+       intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
+
+       if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
+               intel_disable_ddi_hdmi(encoder, old_crtc_state, old_conn_state);
+       else
+               intel_disable_ddi_dp(encoder, old_crtc_state, old_conn_state);
+}
+
+static void intel_ddi_update_pipe_dp(struct intel_encoder *encoder,
+                                    const struct intel_crtc_state *crtc_state,
+                                    const struct drm_connector_state *conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+       intel_ddi_set_pipe_settings(crtc_state);
+
+       intel_psr_update(intel_dp, crtc_state);
+       intel_edp_drrs_enable(intel_dp, crtc_state);
+
+       intel_panel_update_backlight(encoder, crtc_state, conn_state);
+}
+
+static void intel_ddi_update_pipe(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+               intel_ddi_update_pipe_dp(encoder, crtc_state, conn_state);
+
+       if (conn_state->content_protection ==
+           DRM_MODE_CONTENT_PROTECTION_DESIRED)
+               intel_hdcp_enable(to_intel_connector(conn_state->connector));
+       else if (conn_state->content_protection ==
+                DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+               intel_hdcp_disable(to_intel_connector(conn_state->connector));
+}
+
+static void intel_ddi_set_fia_lane_count(struct intel_encoder *encoder,
+                                        const struct intel_crtc_state *pipe_config,
+                                        enum port port)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       u32 val = I915_READ(PORT_TX_DFLEXDPMLE1);
+       bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
+
+       val &= ~DFLEXDPMLE1_DPMLETC_MASK(tc_port);
+       switch (pipe_config->lane_count) {
+       case 1:
+               val |= (lane_reversal) ? DFLEXDPMLE1_DPMLETC_ML3(tc_port) :
+               DFLEXDPMLE1_DPMLETC_ML0(tc_port);
+               break;
+       case 2:
+               val |= (lane_reversal) ? DFLEXDPMLE1_DPMLETC_ML3_2(tc_port) :
+               DFLEXDPMLE1_DPMLETC_ML1_0(tc_port);
+               break;
+       case 4:
+               val |= DFLEXDPMLE1_DPMLETC_ML3_0(tc_port);
+               break;
+       default:
+               MISSING_CASE(pipe_config->lane_count);
+       }
+       I915_WRITE(PORT_TX_DFLEXDPMLE1, val);
+}
+
+static void
+intel_ddi_pre_pll_enable(struct intel_encoder *encoder,
+                        const struct intel_crtc_state *crtc_state,
+                        const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       enum port port = encoder->port;
+
+       if (intel_crtc_has_dp_encoder(crtc_state) ||
+           intel_port_is_tc(dev_priv, encoder->port))
+               intel_display_power_get(dev_priv,
+                                       intel_ddi_main_link_aux_domain(dig_port));
+
+       if (IS_GEN9_LP(dev_priv))
+               bxt_ddi_phy_set_lane_optim_mask(encoder,
+                                               crtc_state->lane_lat_optim_mask);
+
+       /*
+        * 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)
+               return;
+
+       intel_ddi_set_fia_lane_count(encoder, crtc_state, port);
+}
+
+static void
+intel_ddi_post_pll_disable(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+
+       if (intel_crtc_has_dp_encoder(crtc_state) ||
+           intel_port_is_tc(dev_priv, encoder->port))
+               intel_display_power_put_unchecked(dev_priv,
+                                                 intel_ddi_main_link_aux_domain(dig_port));
+}
+
+static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv =
+               to_i915(intel_dig_port->base.base.dev);
+       enum port port = intel_dig_port->base.port;
+       u32 val;
+       bool wait = false;
+
+       if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) {
+               val = I915_READ(DDI_BUF_CTL(port));
+               if (val & DDI_BUF_CTL_ENABLE) {
+                       val &= ~DDI_BUF_CTL_ENABLE;
+                       I915_WRITE(DDI_BUF_CTL(port), val);
+                       wait = true;
+               }
+
+               val = I915_READ(DP_TP_CTL(port));
+               val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
+               val |= DP_TP_CTL_LINK_TRAIN_PAT1;
+               I915_WRITE(DP_TP_CTL(port), val);
+               POSTING_READ(DP_TP_CTL(port));
+
+               if (wait)
+                       intel_wait_ddi_buf_idle(dev_priv, port);
+       }
+
+       val = DP_TP_CTL_ENABLE |
+             DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
+       if (intel_dp->link_mst)
+               val |= DP_TP_CTL_MODE_MST;
+       else {
+               val |= DP_TP_CTL_MODE_SST;
+               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+                       val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
+       }
+       I915_WRITE(DP_TP_CTL(port), val);
+       POSTING_READ(DP_TP_CTL(port));
+
+       intel_dp->DP |= DDI_BUF_CTL_ENABLE;
+       I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP);
+       POSTING_READ(DDI_BUF_CTL(port));
+
+       udelay(600);
+}
+
+static bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
+                                      enum transcoder cpu_transcoder)
+{
+       if (cpu_transcoder == TRANSCODER_EDP)
+               return false;
+
+       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO))
+               return false;
+
+       return I915_READ(HSW_AUD_PIN_ELD_CP_VLD) &
+               AUDIO_OUTPUT_ENABLE(cpu_transcoder);
+}
+
+void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
+                                        struct intel_crtc_state *crtc_state)
+{
+       if (INTEL_GEN(dev_priv) >= 11 && crtc_state->port_clock > 594000)
+               crtc_state->min_voltage_level = 1;
+       else if (IS_CANNONLAKE(dev_priv) && crtc_state->port_clock > 594000)
+               crtc_state->min_voltage_level = 2;
+}
+
+void intel_ddi_get_config(struct intel_encoder *encoder,
+                         struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       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 */
+       if (WARN_ON(transcoder_is_dsi(cpu_transcoder)))
+               return;
+
+       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+       if (temp & TRANS_DDI_PHSYNC)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (temp & TRANS_DDI_PVSYNC)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->base.adjusted_mode.flags |= flags;
+
+       switch (temp & TRANS_DDI_BPC_MASK) {
+       case TRANS_DDI_BPC_6:
+               pipe_config->pipe_bpp = 18;
+               break;
+       case TRANS_DDI_BPC_8:
+               pipe_config->pipe_bpp = 24;
+               break;
+       case TRANS_DDI_BPC_10:
+               pipe_config->pipe_bpp = 30;
+               break;
+       case TRANS_DDI_BPC_12:
+               pipe_config->pipe_bpp = 36;
+               break;
+       default:
+               break;
+       }
+
+       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);
+
+               if (pipe_config->infoframes.enable)
+                       pipe_config->has_infoframe = true;
+
+               if (temp & TRANS_DDI_HDMI_SCRAMBLING)
+                       pipe_config->hdmi_scrambling = true;
+               if (temp & TRANS_DDI_HIGH_TMDS_CHAR_RATE)
+                       pipe_config->hdmi_high_tmds_clock_ratio = true;
+               /* fall through */
+       case TRANS_DDI_MODE_SELECT_DVI:
+               pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI);
+               pipe_config->lane_count = 4;
+               break;
+       case TRANS_DDI_MODE_SELECT_FDI:
+               pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG);
+               break;
+       case TRANS_DDI_MODE_SELECT_DP_SST:
+               if (encoder->type == INTEL_OUTPUT_EDP)
+                       pipe_config->output_types |= BIT(INTEL_OUTPUT_EDP);
+               else
+                       pipe_config->output_types |= BIT(INTEL_OUTPUT_DP);
+               pipe_config->lane_count =
+                       ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
+               intel_dp_get_m_n(intel_crtc, pipe_config);
+               break;
+       case TRANS_DDI_MODE_SELECT_DP_MST:
+               pipe_config->output_types |= BIT(INTEL_OUTPUT_DP_MST);
+               pipe_config->lane_count =
+                       ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
+               intel_dp_get_m_n(intel_crtc, pipe_config);
+               break;
+       default:
+               break;
+       }
+
+       pipe_config->has_audio =
+               intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder);
+
+       if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.bpp &&
+           pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) {
+               /*
+                * This is a big fat ugly hack.
+                *
+                * Some machines in UEFI boot mode provide us a VBT that has 18
+                * bpp and 1.62 GHz link bandwidth for eDP, which for reasons
+                * unknown we fail to light up. Yet the same BIOS boots up with
+                * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as
+                * max, not what it tells us to use.
+                *
+                * Note: This will still be broken if the eDP panel is not lit
+                * up by the BIOS, and thus we can't get the mode at module
+                * load.
+                */
+               DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n",
+                             pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp);
+               dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
+       }
+
+       intel_ddi_clock_get(encoder, pipe_config);
+
+       if (IS_GEN9_LP(dev_priv))
+               pipe_config->lane_lat_optim_mask =
+                       bxt_ddi_phy_get_lane_lat_optim_mask(encoder);
+
+       intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
+
+       intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
+
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_AVI,
+                            &pipe_config->infoframes.avi);
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_SPD,
+                            &pipe_config->infoframes.spd);
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_VENDOR,
+                            &pipe_config->infoframes.hdmi);
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_DRM,
+                            &pipe_config->infoframes.drm);
+}
+
+static enum intel_output_type
+intel_ddi_compute_output_type(struct intel_encoder *encoder,
+                             struct intel_crtc_state *crtc_state,
+                             struct drm_connector_state *conn_state)
+{
+       switch (conn_state->connector->connector_type) {
+       case DRM_MODE_CONNECTOR_HDMIA:
+               return INTEL_OUTPUT_HDMI;
+       case DRM_MODE_CONNECTOR_eDP:
+               return INTEL_OUTPUT_EDP;
+       case DRM_MODE_CONNECTOR_DisplayPort:
+               return INTEL_OUTPUT_DP;
+       default:
+               MISSING_CASE(conn_state->connector->connector_type);
+               return INTEL_OUTPUT_UNUSED;
+       }
+}
+
+static int intel_ddi_compute_config(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       int ret;
+
+       if (HAS_TRANSCODER_EDP(dev_priv) && port == PORT_A)
+               pipe_config->cpu_transcoder = TRANSCODER_EDP;
+
+       if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
+               ret = intel_hdmi_compute_config(encoder, pipe_config, conn_state);
+       else
+               ret = intel_dp_compute_config(encoder, pipe_config, conn_state);
+       if (ret)
+               return ret;
+
+       if (IS_HASWELL(dev_priv) && crtc->pipe == PIPE_A &&
+           pipe_config->cpu_transcoder == TRANSCODER_EDP)
+               pipe_config->pch_pfit.force_thru =
+                       pipe_config->pch_pfit.enabled ||
+                       pipe_config->crc_enabled;
+
+       if (IS_GEN9_LP(dev_priv))
+               pipe_config->lane_lat_optim_mask =
+                       bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count);
+
+       intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
+
+       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,
+       .destroy = intel_ddi_encoder_destroy,
+};
+
+static struct intel_connector *
+intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
+{
+       struct intel_connector *connector;
+       enum port port = intel_dig_port->base.port;
+
+       connector = intel_connector_alloc();
+       if (!connector)
+               return NULL;
+
+       intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
+       intel_dig_port->dp.prepare_link_retrain =
+               intel_ddi_prepare_link_retrain;
+
+       if (!intel_dp_init_connector(intel_dig_port, connector)) {
+               kfree(connector);
+               return NULL;
+       }
+
+       return connector;
+}
+
+static int modeset_pipe(struct drm_crtc *crtc,
+                       struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_atomic_state *state;
+       struct drm_crtc_state *crtc_state;
+       int ret;
+
+       state = drm_atomic_state_alloc(crtc->dev);
+       if (!state)
+               return -ENOMEM;
+
+       state->acquire_ctx = ctx;
+
+       crtc_state = drm_atomic_get_crtc_state(state, crtc);
+       if (IS_ERR(crtc_state)) {
+               ret = PTR_ERR(crtc_state);
+               goto out;
+       }
+
+       crtc_state->connectors_changed = true;
+
+       ret = drm_atomic_commit(state);
+out:
+       drm_atomic_state_put(state);
+
+       return ret;
+}
+
+static int intel_hdmi_reset_link(struct intel_encoder *encoder,
+                                struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct intel_connector *connector = hdmi->attached_connector;
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+       struct drm_connector_state *conn_state;
+       struct intel_crtc_state *crtc_state;
+       struct intel_crtc *crtc;
+       u8 config;
+       int ret;
+
+       if (!connector || connector->base.status != connector_status_connected)
+               return 0;
+
+       ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
+                              ctx);
+       if (ret)
+               return ret;
+
+       conn_state = connector->base.state;
+
+       crtc = to_intel_crtc(conn_state->crtc);
+       if (!crtc)
+               return 0;
+
+       ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+       if (ret)
+               return ret;
+
+       crtc_state = to_intel_crtc_state(crtc->base.state);
+
+       WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
+
+       if (!crtc_state->base.active)
+               return 0;
+
+       if (!crtc_state->hdmi_high_tmds_clock_ratio &&
+           !crtc_state->hdmi_scrambling)
+               return 0;
+
+       if (conn_state->commit &&
+           !try_wait_for_completion(&conn_state->commit->hw_done))
+               return 0;
+
+       ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
+       if (ret < 0) {
+               DRM_ERROR("Failed to read TMDS config: %d\n", ret);
+               return 0;
+       }
+
+       if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
+           crtc_state->hdmi_high_tmds_clock_ratio &&
+           !!(config & SCDC_SCRAMBLING_ENABLE) ==
+           crtc_state->hdmi_scrambling)
+               return 0;
+
+       /*
+        * HDMI 2.0 says that one should not send scrambled data
+        * prior to configuring the sink scrambling, and that
+        * TMDS clock/data transmission should be suspended when
+        * changing the TMDS clock rate in the sink. So let's
+        * just do a full modeset here, even though some sinks
+        * would be perfectly happy if were to just reconfigure
+        * the SCDC settings on the fly.
+        */
+       return modeset_pipe(&crtc->base, ctx);
+}
+
+static bool intel_ddi_hotplug(struct intel_encoder *encoder,
+                             struct intel_connector *connector)
+{
+       struct drm_modeset_acquire_ctx ctx;
+       bool changed;
+       int ret;
+
+       changed = intel_encoder_hotplug(encoder, connector);
+
+       drm_modeset_acquire_init(&ctx, 0);
+
+       for (;;) {
+               if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
+                       ret = intel_hdmi_reset_link(encoder, &ctx);
+               else
+                       ret = intel_dp_retrain_link(encoder, &ctx);
+
+               if (ret == -EDEADLK) {
+                       drm_modeset_backoff(&ctx);
+                       continue;
+               }
+
+               break;
+       }
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+       WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
+
+       return changed;
+}
+
+static struct intel_connector *
+intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
+{
+       struct intel_connector *connector;
+       enum port port = intel_dig_port->base.port;
+
+       connector = intel_connector_alloc();
+       if (!connector)
+               return NULL;
+
+       intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
+       intel_hdmi_init_connector(intel_dig_port, connector);
+
+       return connector;
+}
+
+static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dport)
+{
+       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
+
+       if (dport->base.port != PORT_A)
+               return false;
+
+       if (dport->saved_port_bits & DDI_A_4_LANES)
+               return false;
+
+       /* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only
+        *                     supported configuration
+        */
+       if (IS_GEN9_LP(dev_priv))
+               return true;
+
+       /* Cannonlake: Most of SKUs don't support DDI_E, and the only
+        *             one who does also have a full A/E split called
+        *             DDI_F what makes DDI_E useless. However for this
+        *             case let's trust VBT info.
+        */
+       if (IS_CANNONLAKE(dev_priv) &&
+           !intel_bios_is_port_present(dev_priv, PORT_E))
+               return true;
+
+       return false;
+}
+
+static int
+intel_ddi_max_lanes(struct intel_digital_port *intel_dport)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dport->base.base.dev);
+       enum port port = intel_dport->base.port;
+       int max_lanes = 4;
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               return max_lanes;
+
+       if (port == PORT_A || port == PORT_E) {
+               if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)
+                       max_lanes = port == PORT_A ? 4 : 0;
+               else
+                       /* Both A and E share 2 lanes */
+                       max_lanes = 2;
+       }
+
+       /*
+        * Some BIOS might fail to set this bit on port A if eDP
+        * wasn't lit up at boot.  Force this bit set when needed
+        * so we use the proper lane count for our calculations.
+        */
+       if (intel_ddi_a_force_4_lanes(intel_dport)) {
+               DRM_DEBUG_KMS("Forcing DDI_A_4_LANES for port A\n");
+               intel_dport->saved_port_bits |= DDI_A_4_LANES;
+               max_lanes = 4;
+       }
+
+       return max_lanes;
+}
+
+void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
+{
+       struct ddi_vbt_port_info *port_info =
+               &dev_priv->vbt.ddi_port_info[port];
+       struct intel_digital_port *intel_dig_port;
+       struct intel_encoder *intel_encoder;
+       struct drm_encoder *encoder;
+       bool init_hdmi, init_dp, init_lspcon = false;
+       enum pipe pipe;
+
+       init_hdmi = port_info->supports_dvi || port_info->supports_hdmi;
+       init_dp = port_info->supports_dp;
+
+       if (intel_bios_is_lspcon_present(dev_priv, port)) {
+               /*
+                * Lspcon device needs to be driven with DP connector
+                * with special detection sequence. So make sure DP
+                * is initialized before lspcon.
+                */
+               init_dp = true;
+               init_lspcon = true;
+               init_hdmi = false;
+               DRM_DEBUG_KMS("VBT says port %c has lspcon\n", port_name(port));
+       }
+
+       if (!init_dp && !init_hdmi) {
+               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, respect it\n",
+                             port_name(port));
+               return;
+       }
+
+       intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
+       if (!intel_dig_port)
+               return;
+
+       intel_encoder = &intel_dig_port->base;
+       encoder = &intel_encoder->base;
+
+       drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
+                        DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
+
+       intel_encoder->hotplug = intel_ddi_hotplug;
+       intel_encoder->compute_output_type = intel_ddi_compute_output_type;
+       intel_encoder->compute_config = intel_ddi_compute_config;
+       intel_encoder->enable = intel_enable_ddi;
+       intel_encoder->pre_pll_enable = intel_ddi_pre_pll_enable;
+       intel_encoder->post_pll_disable = intel_ddi_post_pll_disable;
+       intel_encoder->pre_enable = intel_ddi_pre_enable;
+       intel_encoder->disable = intel_disable_ddi;
+       intel_encoder->post_disable = intel_ddi_post_disable;
+       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->get_power_domains = intel_ddi_get_power_domains;
+       intel_encoder->type = INTEL_OUTPUT_DDI;
+       intel_encoder->power_domain = intel_port_to_power_domain(port);
+       intel_encoder->port = port;
+       intel_encoder->cloneable = 0;
+       for_each_pipe(dev_priv, pipe)
+               intel_encoder->crtc_mask |= BIT(pipe);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
+                       DDI_BUF_PORT_REVERSAL;
+       else
+               intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
+                       (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES);
+       intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
+       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;
+
+       switch (port) {
+       case PORT_A:
+               intel_dig_port->ddi_io_power_domain =
+                       POWER_DOMAIN_PORT_DDI_A_IO;
+               break;
+       case PORT_B:
+               intel_dig_port->ddi_io_power_domain =
+                       POWER_DOMAIN_PORT_DDI_B_IO;
+               break;
+       case PORT_C:
+               intel_dig_port->ddi_io_power_domain =
+                       POWER_DOMAIN_PORT_DDI_C_IO;
+               break;
+       case PORT_D:
+               intel_dig_port->ddi_io_power_domain =
+                       POWER_DOMAIN_PORT_DDI_D_IO;
+               break;
+       case PORT_E:
+               intel_dig_port->ddi_io_power_domain =
+                       POWER_DOMAIN_PORT_DDI_E_IO;
+               break;
+       case PORT_F:
+               intel_dig_port->ddi_io_power_domain =
+                       POWER_DOMAIN_PORT_DDI_F_IO;
+               break;
+       default:
+               MISSING_CASE(port);
+       }
+
+       if (init_dp) {
+               if (!intel_ddi_init_dp_connector(intel_dig_port))
+                       goto err;
+
+               intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
+       }
+
+       /* In theory we don't need the encoder->type check, but leave it just in
+        * case we have some really bad VBTs... */
+       if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
+               if (!intel_ddi_init_hdmi_connector(intel_dig_port))
+                       goto err;
+       }
+
+       if (init_lspcon) {
+               if (lspcon_init(intel_dig_port))
+                       /* TODO: handle hdmi info frame part */
+                       DRM_DEBUG_KMS("LSPCON init success on port %c\n",
+                               port_name(port));
+               else
+                       /*
+                        * LSPCON init faied, but DP init was success, so
+                        * lets try to drive as DP++ port.
+                        */
+                       DRM_ERROR("LSPCON init failed on port %c\n",
+                               port_name(port));
+       }
+
+       intel_infoframe_init(intel_dig_port);
+
+       if (intel_port_is_tc(dev_priv, port))
+               intel_digital_port_connected(intel_encoder);
+
+       return;
+
+err:
+       drm_encoder_cleanup(encoder);
+       kfree(intel_dig_port);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h
new file mode 100644 (file)
index 0000000..a08365d
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DDI_H__
+#define __INTEL_DDI_H__
+
+#include <drm/i915_drm.h>
+
+#include "intel_display.h"
+
+struct drm_connector_state;
+struct drm_i915_private;
+struct intel_connector;
+struct intel_crtc;
+struct intel_crtc_state;
+struct intel_dp;
+struct intel_dpll_hw_state;
+struct intel_encoder;
+
+void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
+                               const struct intel_crtc_state *old_crtc_state,
+                               const struct drm_connector_state *old_conn_state);
+void hsw_fdi_link_train(struct intel_crtc *crtc,
+                       const struct intel_crtc_state *crtc_state);
+void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port);
+bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe);
+void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state);
+void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state);
+void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state);
+void intel_ddi_disable_pipe_clock(const  struct intel_crtc_state *crtc_state);
+void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state);
+bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
+void intel_ddi_get_config(struct intel_encoder *encoder,
+                         struct intel_crtc_state *pipe_config);
+void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
+                                   bool state);
+void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
+                                        struct intel_crtc_state *crtc_state);
+u32 bxt_signal_levels(struct intel_dp *intel_dp);
+u32 ddi_signal_levels(struct intel_dp *intel_dp);
+u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder);
+u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder,
+                                u8 voltage_swing);
+int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
+                                    bool enable);
+void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
+int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                       struct intel_dpll_hw_state *state);
+
+#endif /* __INTEL_DDI_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
new file mode 100644 (file)
index 0000000..4336df4
--- /dev/null
@@ -0,0 +1,7577 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_hdcp.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/i915_drm.h>
+
+#include "i915_debugfs.h"
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_audio.h"
+#include "intel_connector.h"
+#include "intel_ddi.h"
+#include "intel_dp.h"
+#include "intel_dp_link_training.h"
+#include "intel_dp_mst.h"
+#include "intel_dpio_phy.h"
+#include "intel_drv.h"
+#include "intel_fifo_underrun.h"
+#include "intel_hdcp.h"
+#include "intel_hdmi.h"
+#include "intel_hotplug.h"
+#include "intel_lspcon.h"
+#include "intel_lvds.h"
+#include "intel_panel.h"
+#include "intel_psr.h"
+#include "intel_sideband.h"
+#include "intel_vdsc.h"
+
+#define DP_DPRX_ESI_LEN 14
+
+/* DP DSC small joiner has 2 FIFOs each of 640 x 6 bytes */
+#define DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER     61440
+#define DP_DSC_MIN_SUPPORTED_BPC               8
+#define DP_DSC_MAX_SUPPORTED_BPC               10
+
+/* DP DSC throughput values used for slice count calculations KPixels/s */
+#define DP_DSC_PEAK_PIXEL_RATE                 2720000
+#define DP_DSC_MAX_ENC_THROUGHPUT_0            340000
+#define DP_DSC_MAX_ENC_THROUGHPUT_1            400000
+
+/* DP DSC FEC Overhead factor = (100 - 2.4)/100 */
+#define DP_DSC_FEC_OVERHEAD_FACTOR             976
+
+/* Compliance test status bits  */
+#define INTEL_DP_RESOLUTION_SHIFT_MASK 0
+#define INTEL_DP_RESOLUTION_PREFERRED  (1 << INTEL_DP_RESOLUTION_SHIFT_MASK)
+#define INTEL_DP_RESOLUTION_STANDARD   (2 << INTEL_DP_RESOLUTION_SHIFT_MASK)
+#define INTEL_DP_RESOLUTION_FAILSAFE   (3 << INTEL_DP_RESOLUTION_SHIFT_MASK)
+
+struct dp_link_dpll {
+       int clock;
+       struct dpll dpll;
+};
+
+static const struct dp_link_dpll g4x_dpll[] = {
+       { 162000,
+               { .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } },
+       { 270000,
+               { .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } }
+};
+
+static const struct dp_link_dpll pch_dpll[] = {
+       { 162000,
+               { .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } },
+       { 270000,
+               { .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } }
+};
+
+static const struct dp_link_dpll vlv_dpll[] = {
+       { 162000,
+               { .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } },
+       { 270000,
+               { .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } }
+};
+
+/*
+ * CHV supports eDP 1.4 that have  more link rates.
+ * Below only provides the fixed rate but exclude variable rate.
+ */
+static const struct dp_link_dpll chv_dpll[] = {
+       /*
+        * CHV requires to program fractional division for m2.
+        * m2 is stored in fixed point format using formula below
+        * (m2_int << 22) | m2_fraction
+        */
+       { 162000,       /* m2_int = 32, m2_fraction = 1677722 */
+               { .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } },
+       { 270000,       /* m2_int = 27, m2_fraction = 0 */
+               { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } },
+};
+
+/* Constants for DP DSC configurations */
+static const u8 valid_dsc_bpp[] = {6, 8, 10, 12, 15};
+
+/* With Single pipe configuration, HW is capable of supporting maximum
+ * of 4 slices per line.
+ */
+static const u8 valid_dsc_slicecount[] = {1, 2, 4};
+
+/**
+ * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU or PCH)
+ * @intel_dp: DP struct
+ *
+ * If a CPU or PCH DP output is attached to an eDP panel, this function
+ * will return true, and false otherwise.
+ */
+bool intel_dp_is_edp(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+
+       return intel_dig_port->base.type == INTEL_OUTPUT_EDP;
+}
+
+static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
+{
+       return enc_to_intel_dp(&intel_attached_encoder(connector)->base);
+}
+
+static void intel_dp_link_down(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *old_crtc_state);
+static bool edp_panel_vdd_on(struct intel_dp *intel_dp);
+static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
+static void vlv_init_panel_power_sequencer(struct intel_encoder *encoder,
+                                          const struct intel_crtc_state *crtc_state);
+static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
+                                     enum pipe pipe);
+static void intel_dp_unset_edid(struct intel_dp *intel_dp);
+
+/* update sink rates from dpcd */
+static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
+{
+       static const int dp_rates[] = {
+               162000, 270000, 540000, 810000
+       };
+       int i, max_rate;
+
+       max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+
+       for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
+               if (dp_rates[i] > max_rate)
+                       break;
+               intel_dp->sink_rates[i] = dp_rates[i];
+       }
+
+       intel_dp->num_sink_rates = i;
+}
+
+/* Get length of rates array potentially limited by max_rate. */
+static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate)
+{
+       int i;
+
+       /* Limit results by potentially reduced max rate */
+       for (i = 0; i < len; i++) {
+               if (rates[len - i - 1] <= max_rate)
+                       return len - i;
+       }
+
+       return 0;
+}
+
+/* Get length of common rates array potentially limited by max_rate. */
+static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
+                                         int max_rate)
+{
+       return intel_dp_rate_limit_len(intel_dp->common_rates,
+                                      intel_dp->num_common_rates, max_rate);
+}
+
+/* Theoretical max between source and sink */
+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);
+
+       return min3(source_max, sink_max, fia_max);
+}
+
+int intel_dp_max_lane_count(struct intel_dp *intel_dp)
+{
+       return intel_dp->max_link_lane_count;
+}
+
+int
+intel_dp_link_required(int pixel_clock, int bpp)
+{
+       /* pixel_clock is in kHz, divide bpp by 8 for bit to Byte conversion */
+       return DIV_ROUND_UP(pixel_clock * bpp, 8);
+}
+
+int
+intel_dp_max_data_rate(int max_link_clock, int max_lanes)
+{
+       /* max_link_clock is the link symbol clock (LS_Clk) in kHz and not the
+        * link rate that is generally expressed in Gbps. Since, 8 bits of data
+        * is transmitted every LS_Clk per lane, there is no need to account for
+        * the channel encoding that is done in the PHY layer here.
+        */
+
+       return max_link_clock * max_lanes;
+}
+
+static int
+intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       int max_dotclk = dev_priv->max_dotclk_freq;
+       int ds_max_dotclk;
+
+       int type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
+
+       if (type != DP_DS_PORT_TYPE_VGA)
+               return max_dotclk;
+
+       ds_max_dotclk = drm_dp_downstream_max_clock(intel_dp->dpcd,
+                                                   intel_dp->downstream_ports);
+
+       if (ds_max_dotclk != 0)
+               max_dotclk = min(max_dotclk, ds_max_dotclk);
+
+       return max_dotclk;
+}
+
+static int cnl_max_source_rate(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 port port = dig_port->base.port;
+
+       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
+
+       /* Low voltage SKUs are limited to max of 5.4G */
+       if (voltage == VOLTAGE_INFO_0_85V)
+               return 540000;
+
+       /* For this SKU 8.1G is supported in all ports */
+       if (IS_CNL_WITH_PORT_F(dev_priv))
+               return 810000;
+
+       /* For other SKUs, max rate on ports A and D is 5.4G */
+       if (port == PORT_A || port == PORT_D)
+               return 540000;
+
+       return 810000;
+}
+
+static int icl_max_source_rate(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 port port = dig_port->base.port;
+
+       if (intel_port_is_combophy(dev_priv, port) &&
+           !IS_ELKHARTLAKE(dev_priv) &&
+           !intel_dp_is_edp(intel_dp))
+               return 540000;
+
+       return 810000;
+}
+
+static void
+intel_dp_set_source_rates(struct intel_dp *intel_dp)
+{
+       /* The values must be in increasing order */
+       static const int cnl_rates[] = {
+               162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000
+       };
+       static const int bxt_rates[] = {
+               162000, 216000, 243000, 270000, 324000, 432000, 540000
+       };
+       static const int skl_rates[] = {
+               162000, 216000, 270000, 324000, 432000, 540000
+       };
+       static const int hsw_rates[] = {
+               162000, 270000, 540000
+       };
+       static const int g4x_rates[] = {
+               162000, 270000
+       };
+       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);
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[dig_port->base.port];
+       const int *source_rates;
+       int size, max_rate = 0, vbt_max_rate = info->dp_max_link_rate;
+
+       /* This should only be done once */
+       WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates);
+
+       if (INTEL_GEN(dev_priv) >= 10) {
+               source_rates = cnl_rates;
+               size = ARRAY_SIZE(cnl_rates);
+               if (IS_GEN(dev_priv, 10))
+                       max_rate = cnl_max_source_rate(intel_dp);
+               else
+                       max_rate = icl_max_source_rate(intel_dp);
+       } else if (IS_GEN9_LP(dev_priv)) {
+               source_rates = bxt_rates;
+               size = ARRAY_SIZE(bxt_rates);
+       } else if (IS_GEN9_BC(dev_priv)) {
+               source_rates = skl_rates;
+               size = ARRAY_SIZE(skl_rates);
+       } else if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+                  IS_BROADWELL(dev_priv)) {
+               source_rates = hsw_rates;
+               size = ARRAY_SIZE(hsw_rates);
+       } else {
+               source_rates = g4x_rates;
+               size = ARRAY_SIZE(g4x_rates);
+       }
+
+       if (max_rate && vbt_max_rate)
+               max_rate = min(max_rate, vbt_max_rate);
+       else if (vbt_max_rate)
+               max_rate = vbt_max_rate;
+
+       if (max_rate)
+               size = intel_dp_rate_limit_len(source_rates, size, max_rate);
+
+       intel_dp->source_rates = source_rates;
+       intel_dp->num_source_rates = size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+                          const int *sink_rates, int sink_len,
+                          int *common_rates)
+{
+       int i = 0, j = 0, k = 0;
+
+       while (i < source_len && j < sink_len) {
+               if (source_rates[i] == sink_rates[j]) {
+                       if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+                               return k;
+                       common_rates[k] = source_rates[i];
+                       ++k;
+                       ++i;
+                       ++j;
+               } else if (source_rates[i] < sink_rates[j]) {
+                       ++i;
+               } else {
+                       ++j;
+               }
+       }
+       return k;
+}
+
+/* return index of rate in rates array, or -1 if not found */
+static int intel_dp_rate_index(const int *rates, int len, int rate)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (rate == rates[i])
+                       return i;
+
+       return -1;
+}
+
+static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
+{
+       WARN_ON(!intel_dp->num_source_rates || !intel_dp->num_sink_rates);
+
+       intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates,
+                                                    intel_dp->num_source_rates,
+                                                    intel_dp->sink_rates,
+                                                    intel_dp->num_sink_rates,
+                                                    intel_dp->common_rates);
+
+       /* Paranoia, there should always be something in common. */
+       if (WARN_ON(intel_dp->num_common_rates == 0)) {
+               intel_dp->common_rates[0] = 162000;
+               intel_dp->num_common_rates = 1;
+       }
+}
+
+static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
+                                      u8 lane_count)
+{
+       /*
+        * FIXME: we need to synchronize the current link parameters with
+        * hardware readout. Currently fast link training doesn't work on
+        * boot-up.
+        */
+       if (link_rate == 0 ||
+           link_rate > intel_dp->max_link_rate)
+               return false;
+
+       if (lane_count == 0 ||
+           lane_count > intel_dp_max_lane_count(intel_dp))
+               return false;
+
+       return true;
+}
+
+static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
+                                                    int link_rate,
+                                                    u8 lane_count)
+{
+       const struct drm_display_mode *fixed_mode =
+               intel_dp->attached_connector->panel.fixed_mode;
+       int mode_rate, max_rate;
+
+       mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
+       max_rate = intel_dp_max_data_rate(link_rate, lane_count);
+       if (mode_rate > max_rate)
+               return false;
+
+       return true;
+}
+
+int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+                                           int link_rate, u8 lane_count)
+{
+       int index;
+
+       index = intel_dp_rate_index(intel_dp->common_rates,
+                                   intel_dp->num_common_rates,
+                                   link_rate);
+       if (index > 0) {
+               if (intel_dp_is_edp(intel_dp) &&
+                   !intel_dp_can_link_train_fallback_for_edp(intel_dp,
+                                                             intel_dp->common_rates[index - 1],
+                                                             lane_count)) {
+                       DRM_DEBUG_KMS("Retrying Link training for eDP with same parameters\n");
+                       return 0;
+               }
+               intel_dp->max_link_rate = intel_dp->common_rates[index - 1];
+               intel_dp->max_link_lane_count = lane_count;
+       } else if (lane_count > 1) {
+               if (intel_dp_is_edp(intel_dp) &&
+                   !intel_dp_can_link_train_fallback_for_edp(intel_dp,
+                                                             intel_dp_max_common_rate(intel_dp),
+                                                             lane_count >> 1)) {
+                       DRM_DEBUG_KMS("Retrying Link training for eDP with same parameters\n");
+                       return 0;
+               }
+               intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
+               intel_dp->max_link_lane_count = lane_count >> 1;
+       } else {
+               DRM_ERROR("Link Training Unsuccessful\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static enum drm_mode_status
+intel_dp_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       int target_clock = mode->clock;
+       int max_rate, mode_rate, max_lanes, max_link_clock;
+       int max_dotclk;
+       u16 dsc_max_output_bpp = 0;
+       u8 dsc_slice_count = 0;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
+
+       if (intel_dp_is_edp(intel_dp) && fixed_mode) {
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+
+               target_clock = fixed_mode->clock;
+       }
+
+       max_link_clock = intel_dp_max_link_rate(intel_dp);
+       max_lanes = intel_dp_max_lane_count(intel_dp);
+
+       max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
+       mode_rate = intel_dp_link_required(target_clock, 18);
+
+       /*
+        * Output bpp is stored in 6.4 format so right shift by 4 to get the
+        * integer value since we support only integer values of bpp.
+        */
+       if ((INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) &&
+           drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) {
+               if (intel_dp_is_edp(intel_dp)) {
+                       dsc_max_output_bpp =
+                               drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4;
+                       dsc_slice_count =
+                               drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                               true);
+               } else if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) {
+                       dsc_max_output_bpp =
+                               intel_dp_dsc_get_output_bpp(max_link_clock,
+                                                           max_lanes,
+                                                           target_clock,
+                                                           mode->hdisplay) >> 4;
+                       dsc_slice_count =
+                               intel_dp_dsc_get_slice_count(intel_dp,
+                                                            target_clock,
+                                                            mode->hdisplay);
+               }
+       }
+
+       if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) ||
+           target_clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               return MODE_H_ILLEGAL;
+
+       return MODE_OK;
+}
+
+u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
+{
+       int i;
+       u32 v = 0;
+
+       if (src_bytes > 4)
+               src_bytes = 4;
+       for (i = 0; i < src_bytes; i++)
+               v |= ((u32)src[i]) << ((3 - i) * 8);
+       return v;
+}
+
+static void intel_dp_unpack_aux(u32 src, u8 *dst, int dst_bytes)
+{
+       int i;
+       if (dst_bytes > 4)
+               dst_bytes = 4;
+       for (i = 0; i < dst_bytes; i++)
+               dst[i] = src >> ((3-i) * 8);
+}
+
+static void
+intel_dp_init_panel_power_sequencer(struct intel_dp *intel_dp);
+static void
+intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
+                                             bool force_disable_vdd);
+static void
+intel_dp_pps_init(struct intel_dp *intel_dp);
+
+static intel_wakeref_t
+pps_lock(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       intel_wakeref_t wakeref;
+
+       /*
+        * See intel_power_sequencer_reset() why we need
+        * a power domain reference here.
+        */
+       wakeref = intel_display_power_get(dev_priv,
+                                         intel_aux_power_domain(dp_to_dig_port(intel_dp)));
+
+       mutex_lock(&dev_priv->pps_mutex);
+
+       return wakeref;
+}
+
+static intel_wakeref_t
+pps_unlock(struct intel_dp *intel_dp, intel_wakeref_t wakeref)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       mutex_unlock(&dev_priv->pps_mutex);
+       intel_display_power_put(dev_priv,
+                               intel_aux_power_domain(dp_to_dig_port(intel_dp)),
+                               wakeref);
+       return 0;
+}
+
+#define with_pps_lock(dp, wf) \
+       for ((wf) = pps_lock(dp); (wf); (wf) = pps_unlock((dp), (wf)))
+
+static void
+vlv_power_sequencer_kick(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum pipe pipe = intel_dp->pps_pipe;
+       bool pll_enabled, release_cl_override = false;
+       enum dpio_phy phy = DPIO_PHY(pipe);
+       enum dpio_channel ch = vlv_pipe_to_channel(pipe);
+       u32 DP;
+
+       if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
+                "skipping pipe %c power sequencer kick due to port %c being active\n",
+                pipe_name(pipe), port_name(intel_dig_port->base.port)))
+               return;
+
+       DRM_DEBUG_KMS("kicking pipe %c power sequencer for port %c\n",
+                     pipe_name(pipe), port_name(intel_dig_port->base.port));
+
+       /* Preserve the BIOS-computed detected bit. This is
+        * supposed to be read-only.
+        */
+       DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
+       DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
+       DP |= DP_PORT_WIDTH(1);
+       DP |= DP_LINK_TRAIN_PAT_1;
+
+       if (IS_CHERRYVIEW(dev_priv))
+               DP |= DP_PIPE_SEL_CHV(pipe);
+       else
+               DP |= DP_PIPE_SEL(pipe);
+
+       pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE;
+
+       /*
+        * The DPLL for the pipe must be enabled for this to work.
+        * So enable temporarily it if it's not already enabled.
+        */
+       if (!pll_enabled) {
+               release_cl_override = IS_CHERRYVIEW(dev_priv) &&
+                       !chv_phy_powergate_ch(dev_priv, phy, ch, true);
+
+               if (vlv_force_pll_on(dev_priv, pipe, IS_CHERRYVIEW(dev_priv) ?
+                                    &chv_dpll[0].dpll : &vlv_dpll[0].dpll)) {
+                       DRM_ERROR("Failed to force on pll for pipe %c!\n",
+                                 pipe_name(pipe));
+                       return;
+               }
+       }
+
+       /*
+        * Similar magic as in intel_dp_enable_port().
+        * We _must_ do this port enable + disable trick
+        * to make this power sequencer lock onto the port.
+        * Otherwise even VDD force bit won't work.
+        */
+       I915_WRITE(intel_dp->output_reg, DP);
+       POSTING_READ(intel_dp->output_reg);
+
+       I915_WRITE(intel_dp->output_reg, DP | DP_PORT_EN);
+       POSTING_READ(intel_dp->output_reg);
+
+       I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
+       POSTING_READ(intel_dp->output_reg);
+
+       if (!pll_enabled) {
+               vlv_force_pll_off(dev_priv, pipe);
+
+               if (release_cl_override)
+                       chv_phy_powergate_ch(dev_priv, phy, ch, false);
+       }
+}
+
+static enum pipe vlv_find_free_pps(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder;
+       unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
+
+       /*
+        * We don't have power sequencer currently.
+        * Pick one that's not used by other ports.
+        */
+       for_each_intel_dp(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+               if (encoder->type == INTEL_OUTPUT_EDP) {
+                       WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
+                               intel_dp->active_pipe != intel_dp->pps_pipe);
+
+                       if (intel_dp->pps_pipe != INVALID_PIPE)
+                               pipes &= ~(1 << intel_dp->pps_pipe);
+               } else {
+                       WARN_ON(intel_dp->pps_pipe != INVALID_PIPE);
+
+                       if (intel_dp->active_pipe != INVALID_PIPE)
+                               pipes &= ~(1 << intel_dp->active_pipe);
+               }
+       }
+
+       if (pipes == 0)
+               return INVALID_PIPE;
+
+       return ffs(pipes) - 1;
+}
+
+static enum pipe
+vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum pipe pipe;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       /* We should never land here with regular DP ports */
+       WARN_ON(!intel_dp_is_edp(intel_dp));
+
+       WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
+               intel_dp->active_pipe != intel_dp->pps_pipe);
+
+       if (intel_dp->pps_pipe != INVALID_PIPE)
+               return intel_dp->pps_pipe;
+
+       pipe = vlv_find_free_pps(dev_priv);
+
+       /*
+        * Didn't find one. This should not happen since there
+        * are two power sequencers and up to two eDP ports.
+        */
+       if (WARN_ON(pipe == INVALID_PIPE))
+               pipe = PIPE_A;
+
+       vlv_steal_power_sequencer(dev_priv, pipe);
+       intel_dp->pps_pipe = pipe;
+
+       DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n",
+                     pipe_name(intel_dp->pps_pipe),
+                     port_name(intel_dig_port->base.port));
+
+       /* init power sequencer on this pipe and port */
+       intel_dp_init_panel_power_sequencer(intel_dp);
+       intel_dp_init_panel_power_sequencer_registers(intel_dp, true);
+
+       /*
+        * Even vdd force doesn't work until we've made
+        * the power sequencer lock in on the port.
+        */
+       vlv_power_sequencer_kick(intel_dp);
+
+       return intel_dp->pps_pipe;
+}
+
+static int
+bxt_power_sequencer_idx(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       int backlight_controller = dev_priv->vbt.backlight.controller;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       /* We should never land here with regular DP ports */
+       WARN_ON(!intel_dp_is_edp(intel_dp));
+
+       if (!intel_dp->pps_reset)
+               return backlight_controller;
+
+       intel_dp->pps_reset = false;
+
+       /*
+        * Only the HW needs to be reprogrammed, the SW state is fixed and
+        * has been setup during connector init.
+        */
+       intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
+
+       return backlight_controller;
+}
+
+typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
+                              enum pipe pipe);
+
+static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
+                              enum pipe pipe)
+{
+       return I915_READ(PP_STATUS(pipe)) & PP_ON;
+}
+
+static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
+                               enum pipe pipe)
+{
+       return I915_READ(PP_CONTROL(pipe)) & EDP_FORCE_VDD;
+}
+
+static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
+                        enum pipe pipe)
+{
+       return true;
+}
+
+static enum pipe
+vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
+                    enum port port,
+                    vlv_pipe_check pipe_check)
+{
+       enum pipe pipe;
+
+       for (pipe = PIPE_A; pipe <= PIPE_B; pipe++) {
+               u32 port_sel = I915_READ(PP_ON_DELAYS(pipe)) &
+                       PANEL_PORT_SELECT_MASK;
+
+               if (port_sel != PANEL_PORT_SELECT_VLV(port))
+                       continue;
+
+               if (!pipe_check(dev_priv, pipe))
+                       continue;
+
+               return pipe;
+       }
+
+       return INVALID_PIPE;
+}
+
+static void
+vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->base.port;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       /* try to find a pipe with this port selected */
+       /* first pick one where the panel is on */
+       intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                 vlv_pipe_has_pp_on);
+       /* didn't find one? pick one where vdd is on */
+       if (intel_dp->pps_pipe == INVALID_PIPE)
+               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                         vlv_pipe_has_vdd_on);
+       /* didn't find one? pick one with just the correct port */
+       if (intel_dp->pps_pipe == INVALID_PIPE)
+               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                         vlv_pipe_any);
+
+       /* didn't find one? just let vlv_power_sequencer_pipe() pick one when needed */
+       if (intel_dp->pps_pipe == INVALID_PIPE) {
+               DRM_DEBUG_KMS("no initial power sequencer for port %c\n",
+                             port_name(port));
+               return;
+       }
+
+       DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n",
+                     port_name(port), pipe_name(intel_dp->pps_pipe));
+
+       intel_dp_init_panel_power_sequencer(intel_dp);
+       intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
+}
+
+void intel_power_sequencer_reset(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder;
+
+       if (WARN_ON(!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
+                   !IS_GEN9_LP(dev_priv)))
+               return;
+
+       /*
+        * We can't grab pps_mutex here due to deadlock with power_domain
+        * mutex when power_domain functions are called while holding pps_mutex.
+        * That also means that in order to use pps_pipe the code needs to
+        * hold both a power domain reference and pps_mutex, and the power domain
+        * reference get/put must be done while _not_ holding pps_mutex.
+        * pps_{lock,unlock}() do these steps in the correct order, so one
+        * should use them always.
+        */
+
+       for_each_intel_dp(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+               WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               if (IS_GEN9_LP(dev_priv))
+                       intel_dp->pps_reset = true;
+               else
+                       intel_dp->pps_pipe = INVALID_PIPE;
+       }
+}
+
+struct pps_registers {
+       i915_reg_t pp_ctrl;
+       i915_reg_t pp_stat;
+       i915_reg_t pp_on;
+       i915_reg_t pp_off;
+       i915_reg_t pp_div;
+};
+
+static void intel_pps_get_registers(struct intel_dp *intel_dp,
+                                   struct pps_registers *regs)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       int pps_idx = 0;
+
+       memset(regs, 0, sizeof(*regs));
+
+       if (IS_GEN9_LP(dev_priv))
+               pps_idx = bxt_power_sequencer_idx(intel_dp);
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               pps_idx = vlv_power_sequencer_pipe(intel_dp);
+
+       regs->pp_ctrl = PP_CONTROL(pps_idx);
+       regs->pp_stat = PP_STATUS(pps_idx);
+       regs->pp_on = PP_ON_DELAYS(pps_idx);
+       regs->pp_off = PP_OFF_DELAYS(pps_idx);
+
+       /* Cycle delay moved from PP_DIVISOR to PP_CONTROL */
+       if (IS_GEN9_LP(dev_priv) || INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
+               regs->pp_div = INVALID_MMIO_REG;
+       else
+               regs->pp_div = PP_DIVISOR(pps_idx);
+}
+
+static i915_reg_t
+_pp_ctrl_reg(struct intel_dp *intel_dp)
+{
+       struct pps_registers regs;
+
+       intel_pps_get_registers(intel_dp, &regs);
+
+       return regs.pp_ctrl;
+}
+
+static i915_reg_t
+_pp_stat_reg(struct intel_dp *intel_dp)
+{
+       struct pps_registers regs;
+
+       intel_pps_get_registers(intel_dp, &regs);
+
+       return regs.pp_stat;
+}
+
+/* Reboot notifier handler to shutdown panel power to guarantee T12 timing
+   This function only applicable when panel PM state is not to be tracked */
+static int edp_notify_handler(struct notifier_block *this, unsigned long code,
+                             void *unused)
+{
+       struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp),
+                                                edp_notifier);
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       intel_wakeref_t wakeref;
+
+       if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART)
+               return 0;
+
+       with_pps_lock(intel_dp, wakeref) {
+               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+                       enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
+                       i915_reg_t pp_ctrl_reg, pp_div_reg;
+                       u32 pp_div;
+
+                       pp_ctrl_reg = PP_CONTROL(pipe);
+                       pp_div_reg  = PP_DIVISOR(pipe);
+                       pp_div = I915_READ(pp_div_reg);
+                       pp_div &= PP_REFERENCE_DIVIDER_MASK;
+
+                       /* 0x1F write to PP_DIV_REG sets max cycle delay */
+                       I915_WRITE(pp_div_reg, pp_div | 0x1F);
+                       I915_WRITE(pp_ctrl_reg, PANEL_UNLOCK_REGS);
+                       msleep(intel_dp->panel_power_cycle_delay);
+               }
+       }
+
+       return 0;
+}
+
+static bool edp_have_panel_power(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
+           intel_dp->pps_pipe == INVALID_PIPE)
+               return false;
+
+       return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
+}
+
+static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
+           intel_dp->pps_pipe == INVALID_PIPE)
+               return false;
+
+       return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD;
+}
+
+static void
+intel_dp_check_edp(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) {
+               WARN(1, "eDP powered off while attempting aux channel communication.\n");
+               DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
+                             I915_READ(_pp_stat_reg(intel_dp)),
+                             I915_READ(_pp_ctrl_reg(intel_dp)));
+       }
+}
+
+static u32
+intel_dp_aux_wait_done(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+       i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
+       u32 status;
+       bool done;
+
+#define C (((status = intel_uncore_read_notrace(&i915->uncore, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+       done = wait_event_timeout(i915->gmbus_wait_queue, C,
+                                 msecs_to_jiffies_timeout(10));
+
+       /* just trace the final value */
+       trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
+
+       if (!done)
+               DRM_ERROR("dp aux hw did not signal timeout!\n");
+#undef C
+
+       return status;
+}
+
+static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (index)
+               return 0;
+
+       /*
+        * The clock divider is based off the hrawclk, and would like to run at
+        * 2MHz.  So, take the hrawclk value and divide by 2000 and use that
+        */
+       return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
+}
+
+static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+
+       if (index)
+               return 0;
+
+       /*
+        * The clock divider is based off the cdclk or PCH rawclk, and would
+        * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
+        * divide by 2000 and use that
+        */
+       if (dig_port->aux_ch == AUX_CH_A)
+               return DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.cdclk, 2000);
+       else
+               return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
+}
+
+static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+
+       if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
+               /* Workaround for non-ULT HSW */
+               switch (index) {
+               case 0: return 63;
+               case 1: return 72;
+               default: return 0;
+               }
+       }
+
+       return ilk_get_aux_clock_divider(intel_dp, index);
+}
+
+static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+{
+       /*
+        * SKL doesn't need us to program the AUX clock divider (Hardware will
+        * derive the clock from CDCLK automatically). We still implement the
+        * get_aux_clock_divider vfunc to plug-in into the existing code.
+        */
+       return index ? 0 : 1;
+}
+
+static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
+                               int send_bytes,
+                               u32 aux_clock_divider)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv =
+                       to_i915(intel_dig_port->base.base.dev);
+       u32 precharge, timeout;
+
+       if (IS_GEN(dev_priv, 6))
+               precharge = 3;
+       else
+               precharge = 5;
+
+       if (IS_BROADWELL(dev_priv))
+               timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
+       else
+               timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
+
+       return DP_AUX_CH_CTL_SEND_BUSY |
+              DP_AUX_CH_CTL_DONE |
+              DP_AUX_CH_CTL_INTERRUPT |
+              DP_AUX_CH_CTL_TIME_OUT_ERROR |
+              timeout |
+              DP_AUX_CH_CTL_RECEIVE_ERROR |
+              (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+              (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+              (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
+}
+
+static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
+                               int send_bytes,
+                               u32 unused)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       u32 ret;
+
+       ret = DP_AUX_CH_CTL_SEND_BUSY |
+             DP_AUX_CH_CTL_DONE |
+             DP_AUX_CH_CTL_INTERRUPT |
+             DP_AUX_CH_CTL_TIME_OUT_ERROR |
+             DP_AUX_CH_CTL_TIME_OUT_MAX |
+             DP_AUX_CH_CTL_RECEIVE_ERROR |
+             (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+             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)
+               ret |= DP_AUX_CH_CTL_TBT_IO;
+
+       return ret;
+}
+
+static int
+intel_dp_aux_xfer(struct intel_dp *intel_dp,
+                 const u8 *send, int send_bytes,
+                 u8 *recv, int recv_size,
+                 u32 aux_send_ctl_flags)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *i915 =
+                       to_i915(intel_dig_port->base.base.dev);
+       struct intel_uncore *uncore = &i915->uncore;
+       i915_reg_t ch_ctl, ch_data[5];
+       u32 aux_clock_divider;
+       enum intel_display_power_domain aux_domain =
+               intel_aux_power_domain(intel_dig_port);
+       intel_wakeref_t aux_wakeref;
+       intel_wakeref_t pps_wakeref;
+       int i, ret, recv_bytes;
+       int try, clock = 0;
+       u32 status;
+       bool vdd;
+
+       ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
+       for (i = 0; i < ARRAY_SIZE(ch_data); i++)
+               ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
+
+       aux_wakeref = intel_display_power_get(i915, aux_domain);
+       pps_wakeref = pps_lock(intel_dp);
+
+       /*
+        * We will be called with VDD already enabled for dpcd/edid/oui reads.
+        * In such cases we want to leave VDD enabled and it's up to upper layers
+        * to turn it off. But for eg. i2c-dev access we need to turn it on/off
+        * ourselves.
+        */
+       vdd = edp_panel_vdd_on(intel_dp);
+
+       /* dp aux is extremely sensitive to irq latency, hence request the
+        * lowest possible wakeup latency and so prevent the cpu from going into
+        * deep sleep states.
+        */
+       pm_qos_update_request(&i915->pm_qos, 0);
+
+       intel_dp_check_edp(intel_dp);
+
+       /* Try to wait for any previous AUX channel activity */
+       for (try = 0; try < 3; try++) {
+               status = intel_uncore_read_notrace(uncore, ch_ctl);
+               if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+                       break;
+               msleep(1);
+       }
+       /* just trace the final value */
+       trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
+
+       if (try == 3) {
+               static u32 last_status = -1;
+               const u32 status = intel_uncore_read(uncore, ch_ctl);
+
+               if (status != last_status) {
+                       WARN(1, "dp_aux_ch not started status 0x%08x\n",
+                            status);
+                       last_status = status;
+               }
+
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* Only 5 data registers! */
+       if (WARN_ON(send_bytes > 20 || recv_size > 20)) {
+               ret = -E2BIG;
+               goto out;
+       }
+
+       while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
+               u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
+                                                         send_bytes,
+                                                         aux_clock_divider);
+
+               send_ctl |= aux_send_ctl_flags;
+
+               /* Must try at least 3 times according to DP spec */
+               for (try = 0; try < 5; try++) {
+                       /* Load the send data into the aux channel data registers */
+                       for (i = 0; i < send_bytes; i += 4)
+                               intel_uncore_write(uncore,
+                                                  ch_data[i >> 2],
+                                                  intel_dp_pack_aux(send + i,
+                                                                    send_bytes - i));
+
+                       /* Send the command and wait for it to complete */
+                       intel_uncore_write(uncore, ch_ctl, send_ctl);
+
+                       status = intel_dp_aux_wait_done(intel_dp);
+
+                       /* Clear done status and any errors */
+                       intel_uncore_write(uncore,
+                                          ch_ctl,
+                                          status |
+                                          DP_AUX_CH_CTL_DONE |
+                                          DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                                          DP_AUX_CH_CTL_RECEIVE_ERROR);
+
+                       /* DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
+                        *   400us delay required for errors and timeouts
+                        *   Timeout errors from the HW already meet this
+                        *   requirement so skip to next iteration
+                        */
+                       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
+                               continue;
+
+                       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
+                               usleep_range(400, 500);
+                               continue;
+                       }
+                       if (status & DP_AUX_CH_CTL_DONE)
+                               goto done;
+               }
+       }
+
+       if ((status & DP_AUX_CH_CTL_DONE) == 0) {
+               DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
+               ret = -EBUSY;
+               goto out;
+       }
+
+done:
+       /* Check for timeout or receive error.
+        * Timeouts occur when the sink is not connected
+        */
+       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
+               DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
+               ret = -EIO;
+               goto out;
+       }
+
+       /* Timeouts occur when the device isn't connected, so they're
+        * "normal" -- don't fill the kernel log with these */
+       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
+               DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status);
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       /* Unload any bytes sent back from the other side */
+       recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
+                     DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+
+       /*
+        * By BSpec: "Message sizes of 0 or >20 are not allowed."
+        * We have no idea of what happened so we return -EBUSY so
+        * drm layer takes care for the necessary retries.
+        */
+       if (recv_bytes == 0 || recv_bytes > 20) {
+               DRM_DEBUG_KMS("Forbidden recv_bytes = %d on aux transaction\n",
+                             recv_bytes);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       if (recv_bytes > recv_size)
+               recv_bytes = recv_size;
+
+       for (i = 0; i < recv_bytes; i += 4)
+               intel_dp_unpack_aux(intel_uncore_read(uncore, ch_data[i >> 2]),
+                                   recv + i, recv_bytes - i);
+
+       ret = recv_bytes;
+out:
+       pm_qos_update_request(&i915->pm_qos, PM_QOS_DEFAULT_VALUE);
+
+       if (vdd)
+               edp_panel_vdd_off(intel_dp, false);
+
+       pps_unlock(intel_dp, pps_wakeref);
+       intel_display_power_put_async(i915, aux_domain, aux_wakeref);
+
+       return ret;
+}
+
+#define BARE_ADDRESS_SIZE      3
+#define HEADER_SIZE            (BARE_ADDRESS_SIZE + 1)
+
+static void
+intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
+                   const struct drm_dp_aux_msg *msg)
+{
+       txbuf[0] = (msg->request << 4) | ((msg->address >> 16) & 0xf);
+       txbuf[1] = (msg->address >> 8) & 0xff;
+       txbuf[2] = msg->address & 0xff;
+       txbuf[3] = msg->size - 1;
+}
+
+static ssize_t
+intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+       struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
+       u8 txbuf[20], rxbuf[20];
+       size_t txsize, rxsize;
+       int ret;
+
+       intel_dp_aux_header(txbuf, msg);
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_NATIVE_WRITE:
+       case DP_AUX_I2C_WRITE:
+       case DP_AUX_I2C_WRITE_STATUS_UPDATE:
+               txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
+               rxsize = 2; /* 0 or 1 data bytes */
+
+               if (WARN_ON(txsize > 20))
+                       return -E2BIG;
+
+               WARN_ON(!msg->buffer != !msg->size);
+
+               if (msg->buffer)
+                       memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
+
+               ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
+                                       rxbuf, rxsize, 0);
+               if (ret > 0) {
+                       msg->reply = rxbuf[0] >> 4;
+
+                       if (ret > 1) {
+                               /* Number of bytes written in a short write. */
+                               ret = clamp_t(int, rxbuf[1], 0, msg->size);
+                       } else {
+                               /* Return payload size. */
+                               ret = msg->size;
+                       }
+               }
+               break;
+
+       case DP_AUX_NATIVE_READ:
+       case DP_AUX_I2C_READ:
+               txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
+               rxsize = msg->size + 1;
+
+               if (WARN_ON(rxsize > 20))
+                       return -E2BIG;
+
+               ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
+                                       rxbuf, rxsize, 0);
+               if (ret > 0) {
+                       msg->reply = rxbuf[0] >> 4;
+                       /*
+                        * Assume happy day, and copy the data. The caller is
+                        * expected to check msg->reply before touching it.
+                        *
+                        * Return payload size.
+                        */
+                       ret--;
+                       memcpy(msg->buffer, rxbuf + 1, ret);
+               }
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+
+static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
+
+       switch (aux_ch) {
+       case AUX_CH_B:
+       case AUX_CH_C:
+       case AUX_CH_D:
+               return DP_AUX_CH_CTL(aux_ch);
+       default:
+               MISSING_CASE(aux_ch);
+               return DP_AUX_CH_CTL(AUX_CH_B);
+       }
+}
+
+static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
+
+       switch (aux_ch) {
+       case AUX_CH_B:
+       case AUX_CH_C:
+       case AUX_CH_D:
+               return DP_AUX_CH_DATA(aux_ch, index);
+       default:
+               MISSING_CASE(aux_ch);
+               return DP_AUX_CH_DATA(AUX_CH_B, index);
+       }
+}
+
+static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
+
+       switch (aux_ch) {
+       case AUX_CH_A:
+               return DP_AUX_CH_CTL(aux_ch);
+       case AUX_CH_B:
+       case AUX_CH_C:
+       case AUX_CH_D:
+               return PCH_DP_AUX_CH_CTL(aux_ch);
+       default:
+               MISSING_CASE(aux_ch);
+               return DP_AUX_CH_CTL(AUX_CH_A);
+       }
+}
+
+static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
+
+       switch (aux_ch) {
+       case AUX_CH_A:
+               return DP_AUX_CH_DATA(aux_ch, index);
+       case AUX_CH_B:
+       case AUX_CH_C:
+       case AUX_CH_D:
+               return PCH_DP_AUX_CH_DATA(aux_ch, index);
+       default:
+               MISSING_CASE(aux_ch);
+               return DP_AUX_CH_DATA(AUX_CH_A, index);
+       }
+}
+
+static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
+
+       switch (aux_ch) {
+       case AUX_CH_A:
+       case AUX_CH_B:
+       case AUX_CH_C:
+       case AUX_CH_D:
+       case AUX_CH_E:
+       case AUX_CH_F:
+               return DP_AUX_CH_CTL(aux_ch);
+       default:
+               MISSING_CASE(aux_ch);
+               return DP_AUX_CH_CTL(AUX_CH_A);
+       }
+}
+
+static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
+
+       switch (aux_ch) {
+       case AUX_CH_A:
+       case AUX_CH_B:
+       case AUX_CH_C:
+       case AUX_CH_D:
+       case AUX_CH_E:
+       case AUX_CH_F:
+               return DP_AUX_CH_DATA(aux_ch, index);
+       default:
+               MISSING_CASE(aux_ch);
+               return DP_AUX_CH_DATA(AUX_CH_A, index);
+       }
+}
+
+static void
+intel_dp_aux_fini(struct intel_dp *intel_dp)
+{
+       kfree(intel_dp->aux.name);
+}
+
+static void
+intel_dp_aux_init(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &dig_port->base;
+
+       if (INTEL_GEN(dev_priv) >= 9) {
+               intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
+               intel_dp->aux_ch_data_reg = skl_aux_data_reg;
+       } else if (HAS_PCH_SPLIT(dev_priv)) {
+               intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg;
+               intel_dp->aux_ch_data_reg = ilk_aux_data_reg;
+       } else {
+               intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg;
+               intel_dp->aux_ch_data_reg = g4x_aux_data_reg;
+       }
+
+       if (INTEL_GEN(dev_priv) >= 9)
+               intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
+       else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+               intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
+       else if (HAS_PCH_SPLIT(dev_priv))
+               intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
+       else
+               intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
+
+       if (INTEL_GEN(dev_priv) >= 9)
+               intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
+       else
+               intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
+
+       drm_dp_aux_init(&intel_dp->aux);
+
+       /* Failure to allocate our preferred name is not critical */
+       intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c",
+                                      port_name(encoder->port));
+       intel_dp->aux.transfer = intel_dp_aux_transfer;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+       int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1];
+
+       return max_rate >= 540000;
+}
+
+bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp)
+{
+       int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1];
+
+       return max_rate >= 810000;
+}
+
+static void
+intel_dp_set_clock(struct intel_encoder *encoder,
+                  struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct dp_link_dpll *divisor = NULL;
+       int i, count = 0;
+
+       if (IS_G4X(dev_priv)) {
+               divisor = g4x_dpll;
+               count = ARRAY_SIZE(g4x_dpll);
+       } else if (HAS_PCH_SPLIT(dev_priv)) {
+               divisor = pch_dpll;
+               count = ARRAY_SIZE(pch_dpll);
+       } else if (IS_CHERRYVIEW(dev_priv)) {
+               divisor = chv_dpll;
+               count = ARRAY_SIZE(chv_dpll);
+       } else if (IS_VALLEYVIEW(dev_priv)) {
+               divisor = vlv_dpll;
+               count = ARRAY_SIZE(vlv_dpll);
+       }
+
+       if (divisor && count) {
+               for (i = 0; i < count; i++) {
+                       if (pipe_config->port_clock == divisor[i].clock) {
+                               pipe_config->dpll = divisor[i].dpll;
+                               pipe_config->clock_set = true;
+                               break;
+                       }
+               }
+       }
+}
+
+static void snprintf_int_array(char *str, size_t len,
+                              const int *array, int nelem)
+{
+       int i;
+
+       str[0] = '\0';
+
+       for (i = 0; i < nelem; i++) {
+               int r = snprintf(str, len, "%s%d", i ? ", " : "", array[i]);
+               if (r >= len)
+                       return;
+               str += r;
+               len -= r;
+       }
+}
+
+static void intel_dp_print_rates(struct intel_dp *intel_dp)
+{
+       char str[128]; /* FIXME: too big for stack? */
+
+       if ((drm_debug & DRM_UT_KMS) == 0)
+               return;
+
+       snprintf_int_array(str, sizeof(str),
+                          intel_dp->source_rates, intel_dp->num_source_rates);
+       DRM_DEBUG_KMS("source rates: %s\n", str);
+
+       snprintf_int_array(str, sizeof(str),
+                          intel_dp->sink_rates, intel_dp->num_sink_rates);
+       DRM_DEBUG_KMS("sink rates: %s\n", str);
+
+       snprintf_int_array(str, sizeof(str),
+                          intel_dp->common_rates, intel_dp->num_common_rates);
+       DRM_DEBUG_KMS("common rates: %s\n", str);
+}
+
+int
+intel_dp_max_link_rate(struct intel_dp *intel_dp)
+{
+       int len;
+
+       len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate);
+       if (WARN_ON(len <= 0))
+               return 162000;
+
+       return intel_dp->common_rates[len - 1];
+}
+
+int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
+{
+       int i = intel_dp_rate_index(intel_dp->sink_rates,
+                                   intel_dp->num_sink_rates, rate);
+
+       if (WARN_ON(i < 0))
+               i = 0;
+
+       return i;
+}
+
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+                          u8 *link_bw, u8 *rate_select)
+{
+       /* eDP 1.4 rate select method. */
+       if (intel_dp->use_rate_select) {
+               *link_bw = 0;
+               *rate_select =
+                       intel_dp_rate_select(intel_dp, port_clock);
+       } else {
+               *link_bw = drm_dp_link_rate_to_bw_code(port_clock);
+               *rate_select = 0;
+       }
+}
+
+static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp,
+                                        const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       return INTEL_GEN(dev_priv) >= 11 &&
+               pipe_config->cpu_transcoder != TRANSCODER_A;
+}
+
+static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       return intel_dp_source_supports_fec(intel_dp, pipe_config) &&
+               drm_dp_sink_supports_fec(intel_dp->fec_capable);
+}
+
+static bool intel_dp_source_supports_dsc(struct intel_dp *intel_dp,
+                                        const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       return INTEL_GEN(dev_priv) >= 10 &&
+               pipe_config->cpu_transcoder != TRANSCODER_A;
+}
+
+static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       if (!intel_dp_is_edp(intel_dp) && !pipe_config->fec_enable)
+               return false;
+
+       return intel_dp_source_supports_dsc(intel_dp, pipe_config) &&
+               drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
+}
+
+static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       int bpp, bpc;
+
+       bpp = pipe_config->pipe_bpp;
+       bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, intel_dp->downstream_ports);
+
+       if (bpc > 0)
+               bpp = min(bpp, 3*bpc);
+
+       if (intel_dp_is_edp(intel_dp)) {
+               /* Get bpp from vbt only for panels that dont have bpp in edid */
+               if (intel_connector->base.display_info.bpc == 0 &&
+                   dev_priv->vbt.edp.bpp && dev_priv->vbt.edp.bpp < bpp) {
+                       DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
+                                     dev_priv->vbt.edp.bpp);
+                       bpp = dev_priv->vbt.edp.bpp;
+               }
+       }
+
+       return bpp;
+}
+
+/* Adjust link config limits based on compliance test requests. */
+void
+intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct link_config_limits *limits)
+{
+       /* For DP Compliance we override the computed bpp for the pipe */
+       if (intel_dp->compliance.test_data.bpc != 0) {
+               int bpp = 3 * intel_dp->compliance.test_data.bpc;
+
+               limits->min_bpp = limits->max_bpp = bpp;
+               pipe_config->dither_force_disable = bpp == 6 * 3;
+
+               DRM_DEBUG_KMS("Setting pipe_bpp to %d\n", bpp);
+       }
+
+       /* Use values requested by Compliance Test Request */
+       if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
+               int index;
+
+               /* Validate the compliance test data since max values
+                * might have changed due to link train fallback.
+                */
+               if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate,
+                                              intel_dp->compliance.test_lane_count)) {
+                       index = intel_dp_rate_index(intel_dp->common_rates,
+                                                   intel_dp->num_common_rates,
+                                                   intel_dp->compliance.test_link_rate);
+                       if (index >= 0)
+                               limits->min_clock = limits->max_clock = index;
+                       limits->min_lane_count = limits->max_lane_count =
+                               intel_dp->compliance.test_lane_count;
+               }
+       }
+}
+
+static int intel_dp_output_bpp(const struct intel_crtc_state *crtc_state, int bpp)
+{
+       /*
+        * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
+        * format of the number of bytes per pixel will be half the number
+        * of bytes of RGB pixel.
+        */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+               bpp /= 2;
+
+       return bpp;
+}
+
+/* Optimize link config in order: max bpp, min clock, min lanes */
+static int
+intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
+                                 struct intel_crtc_state *pipe_config,
+                                 const struct link_config_limits *limits)
+{
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       int bpp, clock, lane_count;
+       int mode_rate, link_clock, link_avail;
+
+       for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
+               mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                  bpp);
+
+               for (clock = limits->min_clock; clock <= limits->max_clock; clock++) {
+                       for (lane_count = limits->min_lane_count;
+                            lane_count <= limits->max_lane_count;
+                            lane_count <<= 1) {
+                               link_clock = intel_dp->common_rates[clock];
+                               link_avail = intel_dp_max_data_rate(link_clock,
+                                                                   lane_count);
+
+                               if (mode_rate <= link_avail) {
+                                       pipe_config->lane_count = lane_count;
+                                       pipe_config->pipe_bpp = bpp;
+                                       pipe_config->port_clock = link_clock;
+
+                                       return 0;
+                               }
+                       }
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc)
+{
+       int i, num_bpc;
+       u8 dsc_bpc[3] = {0};
+
+       num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd,
+                                                      dsc_bpc);
+       for (i = 0; i < num_bpc; i++) {
+               if (dsc_max_bpc >= dsc_bpc[i])
+                       return dsc_bpc[i] * 3;
+       }
+
+       return 0;
+}
+
+static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
+                                      struct intel_crtc_state *pipe_config,
+                                      struct drm_connector_state *conn_state,
+                                      struct link_config_limits *limits)
+{
+       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);
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       u8 dsc_max_bpc;
+       int pipe_bpp;
+       int ret;
+
+       pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) &&
+               intel_dp_supports_fec(intel_dp, pipe_config);
+
+       if (!intel_dp_supports_dsc(intel_dp, pipe_config))
+               return -EINVAL;
+
+       dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC,
+                           conn_state->max_requested_bpc);
+
+       pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc);
+       if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) {
+               DRM_DEBUG_KMS("No DSC support for less than 8bpc\n");
+               return -EINVAL;
+       }
+
+       /*
+        * For now enable DSC for max bpp, max link rate, max lane count.
+        * Optimize this later for the minimum possible link rate/lane count
+        * with DSC enabled for the requested mode.
+        */
+       pipe_config->pipe_bpp = pipe_bpp;
+       pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
+       pipe_config->lane_count = limits->max_lane_count;
+
+       if (intel_dp_is_edp(intel_dp)) {
+               pipe_config->dsc_params.compressed_bpp =
+                       min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4,
+                             pipe_config->pipe_bpp);
+               pipe_config->dsc_params.slice_count =
+                       drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                       true);
+       } else {
+               u16 dsc_max_output_bpp;
+               u8 dsc_dp_slice_count;
+
+               dsc_max_output_bpp =
+                       intel_dp_dsc_get_output_bpp(pipe_config->port_clock,
+                                                   pipe_config->lane_count,
+                                                   adjusted_mode->crtc_clock,
+                                                   adjusted_mode->crtc_hdisplay);
+               dsc_dp_slice_count =
+                       intel_dp_dsc_get_slice_count(intel_dp,
+                                                    adjusted_mode->crtc_clock,
+                                                    adjusted_mode->crtc_hdisplay);
+               if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
+                       DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n");
+                       return -EINVAL;
+               }
+               pipe_config->dsc_params.compressed_bpp = min_t(u16,
+                                                              dsc_max_output_bpp >> 4,
+                                                              pipe_config->pipe_bpp);
+               pipe_config->dsc_params.slice_count = dsc_dp_slice_count;
+       }
+       /*
+        * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate
+        * is greater than the maximum Cdclock and if slice count is even
+        * then we need to use 2 VDSC instances.
+        */
+       if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
+               if (pipe_config->dsc_params.slice_count > 1) {
+                       pipe_config->dsc_params.dsc_split = true;
+               } else {
+                       DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n");
+                       return -EINVAL;
+               }
+       }
+
+       ret = intel_dp_compute_dsc_params(intel_dp, pipe_config);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d "
+                             "Compressed BPP = %d\n",
+                             pipe_config->pipe_bpp,
+                             pipe_config->dsc_params.compressed_bpp);
+               return ret;
+       }
+
+       pipe_config->dsc_params.compression_enable = true;
+       DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d "
+                     "Compressed Bpp = %d Slice Count = %d\n",
+                     pipe_config->pipe_bpp,
+                     pipe_config->dsc_params.compressed_bpp,
+                     pipe_config->dsc_params.slice_count);
+
+       return 0;
+}
+
+int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state)
+{
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
+               return 6 * 3;
+       else
+               return 8 * 3;
+}
+
+static int
+intel_dp_compute_link_config(struct intel_encoder *encoder,
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state)
+{
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct link_config_limits limits;
+       int common_len;
+       int ret;
+
+       common_len = intel_dp_common_len_rate_limit(intel_dp,
+                                                   intel_dp->max_link_rate);
+
+       /* No common link rates between source and sink */
+       WARN_ON(common_len <= 0);
+
+       limits.min_clock = 0;
+       limits.max_clock = common_len - 1;
+
+       limits.min_lane_count = 1;
+       limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
+
+       limits.min_bpp = intel_dp_min_bpp(pipe_config);
+       limits.max_bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
+
+       if (intel_dp_is_edp(intel_dp)) {
+               /*
+                * Use the maximum clock and number of lanes the eDP panel
+                * advertizes being capable of. The panels are generally
+                * designed to support only a single clock and lane
+                * configuration, and typically these values correspond to the
+                * native resolution of the panel.
+                */
+               limits.min_lane_count = limits.max_lane_count;
+               limits.min_clock = limits.max_clock;
+       }
+
+       intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
+
+       DRM_DEBUG_KMS("DP link computation with max lane count %i "
+                     "max rate %d max bpp %d pixel clock %iKHz\n",
+                     limits.max_lane_count,
+                     intel_dp->common_rates[limits.max_clock],
+                     limits.max_bpp, adjusted_mode->crtc_clock);
+
+       /*
+        * Optimize for slow and wide. This is the place to add alternative
+        * optimization policy.
+        */
+       ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits);
+
+       /* enable compression if the mode doesn't fit available BW */
+       DRM_DEBUG_KMS("Force DSC en = %d\n", intel_dp->force_dsc_en);
+       if (ret || intel_dp->force_dsc_en) {
+               ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
+                                                 conn_state, &limits);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (pipe_config->dsc_params.compression_enable) {
+               DRM_DEBUG_KMS("DP lane count %d clock %d Input bpp %d Compressed bpp %d\n",
+                             pipe_config->lane_count, pipe_config->port_clock,
+                             pipe_config->pipe_bpp,
+                             pipe_config->dsc_params.compressed_bpp);
+
+               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
+                             intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                    pipe_config->dsc_params.compressed_bpp),
+                             intel_dp_max_data_rate(pipe_config->port_clock,
+                                                    pipe_config->lane_count));
+       } else {
+               DRM_DEBUG_KMS("DP lane count %d clock %d bpp %d\n",
+                             pipe_config->lane_count, pipe_config->port_clock,
+                             pipe_config->pipe_bpp);
+
+               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
+                             intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                    pipe_config->pipe_bpp),
+                             intel_dp_max_data_rate(pipe_config->port_clock,
+                                                    pipe_config->lane_count));
+       }
+       return 0;
+}
+
+static int
+intel_dp_ycbcr420_config(struct intel_dp *intel_dp,
+                        struct drm_connector *connector,
+                        struct intel_crtc_state *crtc_state)
+{
+       const struct drm_display_info *info = &connector->display_info;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       int ret;
+
+       if (!drm_mode_is_420_only(info, adjusted_mode) ||
+           !intel_dp_get_colorimetry_status(intel_dp) ||
+           !connector->ycbcr_420_allowed)
+               return 0;
+
+       crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
+
+       /* YCBCR 420 output conversion needs a scaler */
+       ret = skl_update_scaler_crtc(crtc_state);
+       if (ret) {
+               DRM_DEBUG_KMS("Scaler allocation for output failed\n");
+               return ret;
+       }
+
+       intel_pch_panel_fitting(crtc, crtc_state, DRM_MODE_SCALE_FULLSCREEN);
+
+       return 0;
+}
+
+bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       const struct intel_digital_connector_state *intel_conn_state =
+               to_intel_digital_connector_state(conn_state);
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+
+       if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
+               /*
+                * See:
+                * CEA-861-E - 5.1 Default Encoding Parameters
+                * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
+                */
+               return crtc_state->pipe_bpp != 18 &&
+                       drm_default_rgb_quant_range(adjusted_mode) ==
+                       HDMI_QUANTIZATION_RANGE_LIMITED;
+       } else {
+               return intel_conn_state->broadcast_rgb ==
+                       INTEL_BROADCAST_RGB_LIMITED;
+       }
+}
+
+int
+intel_dp_compute_config(struct intel_encoder *encoder,
+                       struct intel_crtc_state *pipe_config,
+                       struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
+       enum port port = encoder->port;
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       struct intel_digital_connector_state *intel_conn_state =
+               to_intel_digital_connector_state(conn_state);
+       bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
+                                          DP_DPCD_QUIRK_CONSTANT_N);
+       int ret = 0, output_bpp;
+
+       if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
+               pipe_config->has_pch_encoder = true;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+       if (lspcon->active)
+               lspcon_ycbcr420_config(&intel_connector->base, pipe_config);
+       else
+               ret = intel_dp_ycbcr420_config(intel_dp, &intel_connector->base,
+                                              pipe_config);
+
+       if (ret)
+               return ret;
+
+       pipe_config->has_drrs = false;
+       if (IS_G4X(dev_priv) || port == PORT_A)
+               pipe_config->has_audio = false;
+       else if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
+               pipe_config->has_audio = intel_dp->has_audio;
+       else
+               pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
+
+       if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
+               intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
+                                      adjusted_mode);
+
+               if (INTEL_GEN(dev_priv) >= 9) {
+                       ret = skl_update_scaler_crtc(pipe_config);
+                       if (ret)
+                               return ret;
+               }
+
+               if (HAS_GMCH(dev_priv))
+                       intel_gmch_panel_fitting(intel_crtc, pipe_config,
+                                                conn_state->scaling_mode);
+               else
+                       intel_pch_panel_fitting(intel_crtc, pipe_config,
+                                               conn_state->scaling_mode);
+       }
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       if (HAS_GMCH(dev_priv) &&
+           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+               return -EINVAL;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
+               return -EINVAL;
+
+       ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state);
+       if (ret < 0)
+               return ret;
+
+       pipe_config->limited_color_range =
+               intel_dp_limited_color_range(pipe_config, conn_state);
+
+       if (pipe_config->dsc_params.compression_enable)
+               output_bpp = pipe_config->dsc_params.compressed_bpp;
+       else
+               output_bpp = intel_dp_output_bpp(pipe_config, pipe_config->pipe_bpp);
+
+       intel_link_compute_m_n(output_bpp,
+                              pipe_config->lane_count,
+                              adjusted_mode->crtc_clock,
+                              pipe_config->port_clock,
+                              &pipe_config->dp_m_n,
+                              constant_n);
+
+       if (intel_connector->panel.downclock_mode != NULL &&
+               dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
+                       pipe_config->has_drrs = true;
+                       intel_link_compute_m_n(output_bpp,
+                                              pipe_config->lane_count,
+                                              intel_connector->panel.downclock_mode->clock,
+                                              pipe_config->port_clock,
+                                              &pipe_config->dp_m2_n2,
+                                              constant_n);
+       }
+
+       if (!HAS_DDI(dev_priv))
+               intel_dp_set_clock(encoder, pipe_config);
+
+       intel_psr_compute_config(intel_dp, pipe_config);
+
+       return 0;
+}
+
+void intel_dp_set_link_params(struct intel_dp *intel_dp,
+                             int link_rate, u8 lane_count,
+                             bool link_mst)
+{
+       intel_dp->link_trained = false;
+       intel_dp->link_rate = link_rate;
+       intel_dp->lane_count = lane_count;
+       intel_dp->link_mst = link_mst;
+}
+
+static void intel_dp_prepare(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = encoder->port;
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+
+       intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
+                                pipe_config->lane_count,
+                                intel_crtc_has_type(pipe_config,
+                                                    INTEL_OUTPUT_DP_MST));
+
+       /*
+        * There are four kinds of DP registers:
+        *
+        *      IBX PCH
+        *      SNB CPU
+        *      IVB CPU
+        *      CPT PCH
+        *
+        * IBX PCH and CPU are the same for almost everything,
+        * except that the CPU DP PLL is configured in this
+        * register
+        *
+        * CPT PCH is quite different, having many bits moved
+        * to the TRANS_DP_CTL register instead. That
+        * configuration happens (oddly) in ironlake_pch_enable
+        */
+
+       /* Preserve the BIOS-computed detected bit. This is
+        * supposed to be read-only.
+        */
+       intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
+
+       /* Handle DP bits in common between all three register formats */
+       intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
+       intel_dp->DP |= DP_PORT_WIDTH(pipe_config->lane_count);
+
+       /* Split out the IBX/CPU vs CPT settings */
+
+       if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) {
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+                       intel_dp->DP |= DP_SYNC_HS_HIGH;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+                       intel_dp->DP |= DP_SYNC_VS_HIGH;
+               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
+
+               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+                       intel_dp->DP |= DP_ENHANCED_FRAMING;
+
+               intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe);
+       } else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
+               u32 trans_dp;
+
+               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
+
+               trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
+               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+                       trans_dp |= TRANS_DP_ENH_FRAMING;
+               else
+                       trans_dp &= ~TRANS_DP_ENH_FRAMING;
+               I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
+       } else {
+               if (IS_G4X(dev_priv) && pipe_config->limited_color_range)
+                       intel_dp->DP |= DP_COLOR_RANGE_16_235;
+
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+                       intel_dp->DP |= DP_SYNC_HS_HIGH;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+                       intel_dp->DP |= DP_SYNC_VS_HIGH;
+               intel_dp->DP |= DP_LINK_TRAIN_OFF;
+
+               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+                       intel_dp->DP |= DP_ENHANCED_FRAMING;
+
+               if (IS_CHERRYVIEW(dev_priv))
+                       intel_dp->DP |= DP_PIPE_SEL_CHV(crtc->pipe);
+               else
+                       intel_dp->DP |= DP_PIPE_SEL(crtc->pipe);
+       }
+}
+
+#define IDLE_ON_MASK           (PP_ON | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
+#define IDLE_ON_VALUE          (PP_ON | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
+
+#define IDLE_OFF_MASK          (PP_ON | PP_SEQUENCE_MASK | 0                     | 0)
+#define IDLE_OFF_VALUE         (0     | PP_SEQUENCE_NONE | 0                     | 0)
+
+#define IDLE_CYCLE_MASK                (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
+#define IDLE_CYCLE_VALUE       (0     | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
+
+static void intel_pps_verify_state(struct intel_dp *intel_dp);
+
+static void wait_panel_status(struct intel_dp *intel_dp,
+                                      u32 mask,
+                                      u32 value)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       i915_reg_t pp_stat_reg, pp_ctrl_reg;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       intel_pps_verify_state(intel_dp);
+
+       pp_stat_reg = _pp_stat_reg(intel_dp);
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+
+       DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n",
+                       mask, value,
+                       I915_READ(pp_stat_reg),
+                       I915_READ(pp_ctrl_reg));
+
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   pp_stat_reg, mask, value,
+                                   5000))
+               DRM_ERROR("Panel status timeout: status %08x control %08x\n",
+                               I915_READ(pp_stat_reg),
+                               I915_READ(pp_ctrl_reg));
+
+       DRM_DEBUG_KMS("Wait complete\n");
+}
+
+static void wait_panel_on(struct intel_dp *intel_dp)
+{
+       DRM_DEBUG_KMS("Wait for panel power on\n");
+       wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
+}
+
+static void wait_panel_off(struct intel_dp *intel_dp)
+{
+       DRM_DEBUG_KMS("Wait for panel power off time\n");
+       wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
+}
+
+static void wait_panel_power_cycle(struct intel_dp *intel_dp)
+{
+       ktime_t panel_power_on_time;
+       s64 panel_power_off_duration;
+
+       DRM_DEBUG_KMS("Wait for panel power cycle\n");
+
+       /* take the difference of currrent time and panel power off time
+        * and then make panel wait for t11_t12 if needed. */
+       panel_power_on_time = ktime_get_boottime();
+       panel_power_off_duration = ktime_ms_delta(panel_power_on_time, intel_dp->panel_power_off_time);
+
+       /* When we disable the VDD override bit last we have to do the manual
+        * wait. */
+       if (panel_power_off_duration < (s64)intel_dp->panel_power_cycle_delay)
+               wait_remaining_ms_from_jiffies(jiffies,
+                                      intel_dp->panel_power_cycle_delay - panel_power_off_duration);
+
+       wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
+}
+
+static void wait_backlight_on(struct intel_dp *intel_dp)
+{
+       wait_remaining_ms_from_jiffies(intel_dp->last_power_on,
+                                      intel_dp->backlight_on_delay);
+}
+
+static void edp_wait_backlight_off(struct intel_dp *intel_dp)
+{
+       wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off,
+                                      intel_dp->backlight_off_delay);
+}
+
+/* Read the current pp_control value, unlocking the register if it
+ * is locked
+ */
+
+static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       u32 control;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       control = I915_READ(_pp_ctrl_reg(intel_dp));
+       if (WARN_ON(!HAS_DDI(dev_priv) &&
+                   (control & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS)) {
+               control &= ~PANEL_UNLOCK_MASK;
+               control |= PANEL_UNLOCK_REGS;
+       }
+       return control;
+}
+
+/*
+ * Must be paired with edp_panel_vdd_off().
+ * Must hold pps_mutex around the whole on/off sequence.
+ * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
+ */
+static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       u32 pp;
+       i915_reg_t pp_stat_reg, pp_ctrl_reg;
+       bool need_to_disable = !intel_dp->want_panel_vdd;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return false;
+
+       cancel_delayed_work(&intel_dp->panel_vdd_work);
+       intel_dp->want_panel_vdd = true;
+
+       if (edp_have_panel_vdd(intel_dp))
+               return need_to_disable;
+
+       intel_display_power_get(dev_priv,
+                               intel_aux_power_domain(intel_dig_port));
+
+       DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
+                     port_name(intel_dig_port->base.port));
+
+       if (!edp_have_panel_power(intel_dp))
+               wait_panel_power_cycle(intel_dp);
+
+       pp = ironlake_get_pp_control(intel_dp);
+       pp |= EDP_FORCE_VDD;
+
+       pp_stat_reg = _pp_stat_reg(intel_dp);
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+
+       I915_WRITE(pp_ctrl_reg, pp);
+       POSTING_READ(pp_ctrl_reg);
+       DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+                       I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
+       /*
+        * If the panel wasn't on, delay before accessing aux channel
+        */
+       if (!edp_have_panel_power(intel_dp)) {
+               DRM_DEBUG_KMS("eDP port %c panel power wasn't enabled\n",
+                             port_name(intel_dig_port->base.port));
+               msleep(intel_dp->panel_power_up_delay);
+       }
+
+       return need_to_disable;
+}
+
+/*
+ * Must be paired with intel_edp_panel_vdd_off() or
+ * intel_edp_panel_off().
+ * Nested calls to these functions are not allowed since
+ * we drop the lock. Caller must use some higher level
+ * locking to prevent nested calls from other threads.
+ */
+void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
+{
+       intel_wakeref_t wakeref;
+       bool vdd;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       vdd = false;
+       with_pps_lock(intel_dp, wakeref)
+               vdd = edp_panel_vdd_on(intel_dp);
+       I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
+            port_name(dp_to_dig_port(intel_dp)->base.port));
+}
+
+static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port =
+               dp_to_dig_port(intel_dp);
+       u32 pp;
+       i915_reg_t pp_stat_reg, pp_ctrl_reg;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       WARN_ON(intel_dp->want_panel_vdd);
+
+       if (!edp_have_panel_vdd(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("Turning eDP port %c VDD off\n",
+                     port_name(intel_dig_port->base.port));
+
+       pp = ironlake_get_pp_control(intel_dp);
+       pp &= ~EDP_FORCE_VDD;
+
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+       pp_stat_reg = _pp_stat_reg(intel_dp);
+
+       I915_WRITE(pp_ctrl_reg, pp);
+       POSTING_READ(pp_ctrl_reg);
+
+       /* Make sure sequencer is idle before allowing subsequent activity */
+       DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+       I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
+
+       if ((pp & PANEL_POWER_ON) == 0)
+               intel_dp->panel_power_off_time = ktime_get_boottime();
+
+       intel_display_power_put_unchecked(dev_priv,
+                                         intel_aux_power_domain(intel_dig_port));
+}
+
+static void edp_panel_vdd_work(struct work_struct *__work)
+{
+       struct intel_dp *intel_dp =
+               container_of(to_delayed_work(__work),
+                            struct intel_dp, panel_vdd_work);
+       intel_wakeref_t wakeref;
+
+       with_pps_lock(intel_dp, wakeref) {
+               if (!intel_dp->want_panel_vdd)
+                       edp_panel_vdd_off_sync(intel_dp);
+       }
+}
+
+static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
+{
+       unsigned long delay;
+
+       /*
+        * Queue the timer to fire a long time from now (relative to the power
+        * down delay) to keep the panel power up across a sequence of
+        * operations.
+        */
+       delay = msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5);
+       schedule_delayed_work(&intel_dp->panel_vdd_work, delay);
+}
+
+/*
+ * Must be paired with edp_panel_vdd_on().
+ * Must hold pps_mutex around the whole on/off sequence.
+ * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
+ */
+static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
+            port_name(dp_to_dig_port(intel_dp)->base.port));
+
+       intel_dp->want_panel_vdd = false;
+
+       if (sync)
+               edp_panel_vdd_off_sync(intel_dp);
+       else
+               edp_panel_vdd_schedule_off(intel_dp);
+}
+
+static void edp_panel_on(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       u32 pp;
+       i915_reg_t pp_ctrl_reg;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("Turn eDP port %c panel power on\n",
+                     port_name(dp_to_dig_port(intel_dp)->base.port));
+
+       if (WARN(edp_have_panel_power(intel_dp),
+                "eDP port %c panel power already on\n",
+                port_name(dp_to_dig_port(intel_dp)->base.port)))
+               return;
+
+       wait_panel_power_cycle(intel_dp);
+
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+       pp = ironlake_get_pp_control(intel_dp);
+       if (IS_GEN(dev_priv, 5)) {
+               /* ILK workaround: disable reset around power sequence */
+               pp &= ~PANEL_POWER_RESET;
+               I915_WRITE(pp_ctrl_reg, pp);
+               POSTING_READ(pp_ctrl_reg);
+       }
+
+       pp |= PANEL_POWER_ON;
+       if (!IS_GEN(dev_priv, 5))
+               pp |= PANEL_POWER_RESET;
+
+       I915_WRITE(pp_ctrl_reg, pp);
+       POSTING_READ(pp_ctrl_reg);
+
+       wait_panel_on(intel_dp);
+       intel_dp->last_power_on = jiffies;
+
+       if (IS_GEN(dev_priv, 5)) {
+               pp |= PANEL_POWER_RESET; /* restore panel reset bit */
+               I915_WRITE(pp_ctrl_reg, pp);
+               POSTING_READ(pp_ctrl_reg);
+       }
+}
+
+void intel_edp_panel_on(struct intel_dp *intel_dp)
+{
+       intel_wakeref_t wakeref;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       with_pps_lock(intel_dp, wakeref)
+               edp_panel_on(intel_dp);
+}
+
+
+static void edp_panel_off(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       u32 pp;
+       i915_reg_t pp_ctrl_reg;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("Turn eDP port %c panel power off\n",
+                     port_name(dig_port->base.port));
+
+       WARN(!intel_dp->want_panel_vdd, "Need eDP port %c VDD to turn off panel\n",
+            port_name(dig_port->base.port));
+
+       pp = ironlake_get_pp_control(intel_dp);
+       /* We need to switch off panel power _and_ force vdd, for otherwise some
+        * panels get very unhappy and cease to work. */
+       pp &= ~(PANEL_POWER_ON | PANEL_POWER_RESET | EDP_FORCE_VDD |
+               EDP_BLC_ENABLE);
+
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+
+       intel_dp->want_panel_vdd = false;
+
+       I915_WRITE(pp_ctrl_reg, pp);
+       POSTING_READ(pp_ctrl_reg);
+
+       wait_panel_off(intel_dp);
+       intel_dp->panel_power_off_time = ktime_get_boottime();
+
+       /* We got a reference when we enabled the VDD. */
+       intel_display_power_put_unchecked(dev_priv, intel_aux_power_domain(dig_port));
+}
+
+void intel_edp_panel_off(struct intel_dp *intel_dp)
+{
+       intel_wakeref_t wakeref;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       with_pps_lock(intel_dp, wakeref)
+               edp_panel_off(intel_dp);
+}
+
+/* Enable backlight in the panel power control. */
+static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       intel_wakeref_t wakeref;
+
+       /*
+        * If we enable the backlight right away following a panel power
+        * on, we may see slight flicker as the panel syncs with the eDP
+        * link.  So delay a bit to make sure the image is solid before
+        * allowing it to appear.
+        */
+       wait_backlight_on(intel_dp);
+
+       with_pps_lock(intel_dp, wakeref) {
+               i915_reg_t pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+               u32 pp;
+
+               pp = ironlake_get_pp_control(intel_dp);
+               pp |= EDP_BLC_ENABLE;
+
+               I915_WRITE(pp_ctrl_reg, pp);
+               POSTING_READ(pp_ctrl_reg);
+       }
+}
+
+/* Enable backlight PWM and backlight PP control. */
+void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
+                           const struct drm_connector_state *conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(conn_state->best_encoder);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_panel_enable_backlight(crtc_state, conn_state);
+       _intel_edp_backlight_on(intel_dp);
+}
+
+/* Disable backlight in the panel power control. */
+static void _intel_edp_backlight_off(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       intel_wakeref_t wakeref;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       with_pps_lock(intel_dp, wakeref) {
+               i915_reg_t pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+               u32 pp;
+
+               pp = ironlake_get_pp_control(intel_dp);
+               pp &= ~EDP_BLC_ENABLE;
+
+               I915_WRITE(pp_ctrl_reg, pp);
+               POSTING_READ(pp_ctrl_reg);
+       }
+
+       intel_dp->last_backlight_off = jiffies;
+       edp_wait_backlight_off(intel_dp);
+}
+
+/* Disable backlight PP control and backlight PWM. */
+void intel_edp_backlight_off(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(old_conn_state->best_encoder);
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       _intel_edp_backlight_off(intel_dp);
+       intel_panel_disable_backlight(old_conn_state);
+}
+
+/*
+ * Hook for controlling the panel power control backlight through the bl_power
+ * sysfs attribute. Take care to handle multiple calls.
+ */
+static void intel_edp_backlight_power(struct intel_connector *connector,
+                                     bool enable)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(&connector->base);
+       intel_wakeref_t wakeref;
+       bool is_enabled;
+
+       is_enabled = false;
+       with_pps_lock(intel_dp, wakeref)
+               is_enabled = ironlake_get_pp_control(intel_dp) & EDP_BLC_ENABLE;
+       if (is_enabled == enable)
+               return;
+
+       DRM_DEBUG_KMS("panel power control backlight %s\n",
+                     enable ? "enable" : "disable");
+
+       if (enable)
+               _intel_edp_backlight_on(intel_dp);
+       else
+               _intel_edp_backlight_off(intel_dp);
+}
+
+static void assert_dp_port(struct intel_dp *intel_dp, bool state)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN;
+
+       I915_STATE_WARN(cur_state != state,
+                       "DP port %c state assertion failure (expected %s, current %s)\n",
+                       port_name(dig_port->base.port),
+                       onoff(state), onoff(cur_state));
+}
+#define assert_dp_port_disabled(d) assert_dp_port((d), false)
+
+static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
+{
+       bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE;
+
+       I915_STATE_WARN(cur_state != state,
+                       "eDP PLL state assertion failure (expected %s, current %s)\n",
+                       onoff(state), onoff(cur_state));
+}
+#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
+#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
+
+static void ironlake_edp_pll_on(struct intel_dp *intel_dp,
+                               const struct intel_crtc_state *pipe_config)
+{
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+       assert_dp_port_disabled(intel_dp);
+       assert_edp_pll_disabled(dev_priv);
+
+       DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
+                     pipe_config->port_clock);
+
+       intel_dp->DP &= ~DP_PLL_FREQ_MASK;
+
+       if (pipe_config->port_clock == 162000)
+               intel_dp->DP |= DP_PLL_FREQ_162MHZ;
+       else
+               intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+
+       I915_WRITE(DP_A, intel_dp->DP);
+       POSTING_READ(DP_A);
+       udelay(500);
+
+       /*
+        * [DevILK] Work around required when enabling DP PLL
+        * while a pipe is enabled going to FDI:
+        * 1. Wait for the start of vertical blank on the enabled pipe going to FDI
+        * 2. Program DP PLL enable
+        */
+       if (IS_GEN(dev_priv, 5))
+               intel_wait_for_vblank_if_active(dev_priv, !crtc->pipe);
+
+       intel_dp->DP |= DP_PLL_ENABLE;
+
+       I915_WRITE(DP_A, intel_dp->DP);
+       POSTING_READ(DP_A);
+       udelay(200);
+}
+
+static void ironlake_edp_pll_off(struct intel_dp *intel_dp,
+                                const struct intel_crtc_state *old_crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+       assert_dp_port_disabled(intel_dp);
+       assert_edp_pll_enabled(dev_priv);
+
+       DRM_DEBUG_KMS("disabling eDP PLL\n");
+
+       intel_dp->DP &= ~DP_PLL_ENABLE;
+
+       I915_WRITE(DP_A, intel_dp->DP);
+       POSTING_READ(DP_A);
+       udelay(200);
+}
+
+static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
+{
+       /*
+        * DPCD 1.2+ should support BRANCH_DEVICE_CTRL, and thus
+        * be capable of signalling downstream hpd with a long pulse.
+        * Whether or not that means D3 is safe to use is not clear,
+        * but let's assume so until proven otherwise.
+        *
+        * FIXME should really check all downstream ports...
+        */
+       return intel_dp->dpcd[DP_DPCD_REV] == 0x11 &&
+               intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
+               intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
+}
+
+void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state *crtc_state,
+                                          bool enable)
+{
+       int ret;
+
+       if (!crtc_state->dsc_params.compression_enable)
+               return;
+
+       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_DSC_ENABLE,
+                                enable ? DP_DECOMPRESSION_EN : 0);
+       if (ret < 0)
+               DRM_DEBUG_KMS("Failed to %s sink decompression state\n",
+                             enable ? "enable" : "disable");
+}
+
+/* If the sink supports it, try to set the power state appropriately */
+void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
+{
+       int ret, i;
+
+       /* Should have a valid DPCD by this point */
+       if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
+               return;
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               if (downstream_hpd_needs_d0(intel_dp))
+                       return;
+
+               ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+                                        DP_SET_POWER_D3);
+       } else {
+               struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+
+               /*
+                * When turning on, we need to retry for 1ms to give the sink
+                * time to wake up.
+                */
+               for (i = 0; i < 3; i++) {
+                       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+                                                DP_SET_POWER_D0);
+                       if (ret == 1)
+                               break;
+                       msleep(1);
+               }
+
+               if (ret == 1 && lspcon->active)
+                       lspcon_wait_pcon_mode(lspcon);
+       }
+
+       if (ret != 1)
+               DRM_DEBUG_KMS("failed to %s sink power state\n",
+                             mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
+}
+
+static bool cpt_dp_port_selected(struct drm_i915_private *dev_priv,
+                                enum port port, enum pipe *pipe)
+{
+       enum pipe p;
+
+       for_each_pipe(dev_priv, p) {
+               u32 val = I915_READ(TRANS_DP_CTL(p));
+
+               if ((val & TRANS_DP_PORT_SEL_MASK) == TRANS_DP_PORT_SEL(port)) {
+                       *pipe = p;
+                       return true;
+               }
+       }
+
+       DRM_DEBUG_KMS("No pipe for DP port %c found\n", port_name(port));
+
+       /* must initialize pipe to something for the asserts */
+       *pipe = PIPE_A;
+
+       return false;
+}
+
+bool intel_dp_port_enabled(struct drm_i915_private *dev_priv,
+                          i915_reg_t dp_reg, enum port port,
+                          enum pipe *pipe)
+{
+       bool ret;
+       u32 val;
+
+       val = I915_READ(dp_reg);
+
+       ret = val & DP_PORT_EN;
+
+       /* asserts want to know the pipe even if the port is disabled */
+       if (IS_IVYBRIDGE(dev_priv) && port == PORT_A)
+               *pipe = (val & DP_PIPE_SEL_MASK_IVB) >> DP_PIPE_SEL_SHIFT_IVB;
+       else if (HAS_PCH_CPT(dev_priv) && port != PORT_A)
+               ret &= cpt_dp_port_selected(dev_priv, port, pipe);
+       else if (IS_CHERRYVIEW(dev_priv))
+               *pipe = (val & DP_PIPE_SEL_MASK_CHV) >> DP_PIPE_SEL_SHIFT_CHV;
+       else
+               *pipe = (val & DP_PIPE_SEL_MASK) >> DP_PIPE_SEL_SHIFT;
+
+       return ret;
+}
+
+static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
+                                 enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       intel_wakeref_t wakeref;
+       bool ret;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       ret = intel_dp_port_enabled(dev_priv, intel_dp->output_reg,
+                                   encoder->port, pipe);
+
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+
+       return ret;
+}
+
+static void intel_dp_get_config(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       u32 tmp, flags = 0;
+       enum port port = encoder->port;
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+
+       if (encoder->type == INTEL_OUTPUT_EDP)
+               pipe_config->output_types |= BIT(INTEL_OUTPUT_EDP);
+       else
+               pipe_config->output_types |= BIT(INTEL_OUTPUT_DP);
+
+       tmp = I915_READ(intel_dp->output_reg);
+
+       pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A;
+
+       if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
+               u32 trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
+
+               if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH)
+                       flags |= DRM_MODE_FLAG_PHSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NHSYNC;
+
+               if (trans_dp & TRANS_DP_VSYNC_ACTIVE_HIGH)
+                       flags |= DRM_MODE_FLAG_PVSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NVSYNC;
+       } else {
+               if (tmp & DP_SYNC_HS_HIGH)
+                       flags |= DRM_MODE_FLAG_PHSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NHSYNC;
+
+               if (tmp & DP_SYNC_VS_HIGH)
+                       flags |= DRM_MODE_FLAG_PVSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NVSYNC;
+       }
+
+       pipe_config->base.adjusted_mode.flags |= flags;
+
+       if (IS_G4X(dev_priv) && tmp & DP_COLOR_RANGE_16_235)
+               pipe_config->limited_color_range = true;
+
+       pipe_config->lane_count =
+               ((tmp & DP_PORT_WIDTH_MASK) >> DP_PORT_WIDTH_SHIFT) + 1;
+
+       intel_dp_get_m_n(crtc, pipe_config);
+
+       if (port == PORT_A) {
+               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ)
+                       pipe_config->port_clock = 162000;
+               else
+                       pipe_config->port_clock = 270000;
+       }
+
+       pipe_config->base.adjusted_mode.crtc_clock =
+               intel_dotclock_calculate(pipe_config->port_clock,
+                                        &pipe_config->dp_m_n);
+
+       if (intel_dp_is_edp(intel_dp) && dev_priv->vbt.edp.bpp &&
+           pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) {
+               /*
+                * This is a big fat ugly hack.
+                *
+                * Some machines in UEFI boot mode provide us a VBT that has 18
+                * bpp and 1.62 GHz link bandwidth for eDP, which for reasons
+                * unknown we fail to light up. Yet the same BIOS boots up with
+                * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as
+                * max, not what it tells us to use.
+                *
+                * Note: This will still be broken if the eDP panel is not lit
+                * up by the BIOS, and thus we can't get the mode at module
+                * load.
+                */
+               DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n",
+                             pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp);
+               dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
+       }
+}
+
+static void intel_disable_dp(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *old_crtc_state,
+                            const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+       intel_dp->link_trained = false;
+
+       if (old_crtc_state->has_audio)
+               intel_audio_codec_disable(encoder,
+                                         old_crtc_state, old_conn_state);
+
+       /* Make sure the panel is off before trying to change the mode. But also
+        * ensure that we have vdd while we switch off the panel. */
+       intel_edp_panel_vdd_on(intel_dp);
+       intel_edp_backlight_off(old_conn_state);
+       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+       intel_edp_panel_off(intel_dp);
+}
+
+static void g4x_disable_dp(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *old_crtc_state,
+                          const struct drm_connector_state *old_conn_state)
+{
+       intel_disable_dp(encoder, old_crtc_state, old_conn_state);
+}
+
+static void vlv_disable_dp(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *old_crtc_state,
+                          const struct drm_connector_state *old_conn_state)
+{
+       intel_disable_dp(encoder, old_crtc_state, old_conn_state);
+}
+
+static void g4x_post_disable_dp(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *old_crtc_state,
+                               const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = encoder->port;
+
+       /*
+        * Bspec does not list a specific disable sequence for g4x DP.
+        * Follow the ilk+ sequence (disable pipe before the port) for
+        * g4x DP as it does not suffer from underruns like the normal
+        * g4x modeset sequence (disable pipe after the port).
+        */
+       intel_dp_link_down(encoder, old_crtc_state);
+
+       /* Only ilk+ has port A */
+       if (port == PORT_A)
+               ironlake_edp_pll_off(intel_dp, old_crtc_state);
+}
+
+static void vlv_post_disable_dp(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *old_crtc_state,
+                               const struct drm_connector_state *old_conn_state)
+{
+       intel_dp_link_down(encoder, old_crtc_state);
+}
+
+static void chv_post_disable_dp(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *old_crtc_state,
+                               const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       intel_dp_link_down(encoder, old_crtc_state);
+
+       vlv_dpio_get(dev_priv);
+
+       /* Assert data lane reset */
+       chv_data_lane_soft_reset(encoder, old_crtc_state, true);
+
+       vlv_dpio_put(dev_priv);
+}
+
+static void
+_intel_dp_set_link_train(struct intel_dp *intel_dp,
+                        u32 *DP,
+                        u8 dp_train_pat)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->base.port;
+       u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
+
+       if (dp_train_pat & train_pat_mask)
+               DRM_DEBUG_KMS("Using DP training pattern TPS%d\n",
+                             dp_train_pat & train_pat_mask);
+
+       if (HAS_DDI(dev_priv)) {
+               u32 temp = I915_READ(DP_TP_CTL(port));
+
+               if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
+                       temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
+               else
+                       temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
+
+               temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
+               switch (dp_train_pat & train_pat_mask) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
+
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
+                       break;
+               case DP_TRAINING_PATTERN_4:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT4;
+                       break;
+               }
+               I915_WRITE(DP_TP_CTL(port), temp);
+
+       } else if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) ||
+                  (HAS_PCH_CPT(dev_priv) && port != PORT_A)) {
+               *DP &= ~DP_LINK_TRAIN_MASK_CPT;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       *DP |= DP_LINK_TRAIN_OFF_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       *DP |= DP_LINK_TRAIN_PAT_1_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
+                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               }
+
+       } else {
+               *DP &= ~DP_LINK_TRAIN_MASK;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       *DP |= DP_LINK_TRAIN_OFF;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       *DP |= DP_LINK_TRAIN_PAT_1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       *DP |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
+                       *DP |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               }
+       }
+}
+
+static void intel_dp_enable_port(struct intel_dp *intel_dp,
+                                const struct intel_crtc_state *old_crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       /* enable with pattern 1 (as per spec) */
+
+       intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
+
+       /*
+        * Magic for VLV/CHV. We _must_ first set up the register
+        * without actually enabling the port, and then do another
+        * write to enable the port. Otherwise link training will
+        * fail when the power sequencer is freshly used for this port.
+        */
+       intel_dp->DP |= DP_PORT_EN;
+       if (old_crtc_state->has_audio)
+               intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
+
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
+}
+
+static void intel_enable_dp(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *pipe_config,
+                           const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       u32 dp_reg = I915_READ(intel_dp->output_reg);
+       enum pipe pipe = crtc->pipe;
+       intel_wakeref_t wakeref;
+
+       if (WARN_ON(dp_reg & DP_PORT_EN))
+               return;
+
+       with_pps_lock(intel_dp, wakeref) {
+               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                       vlv_init_panel_power_sequencer(encoder, pipe_config);
+
+               intel_dp_enable_port(intel_dp, pipe_config);
+
+               edp_panel_vdd_on(intel_dp);
+               edp_panel_on(intel_dp);
+               edp_panel_vdd_off(intel_dp, true);
+       }
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               unsigned int lane_mask = 0x0;
+
+               if (IS_CHERRYVIEW(dev_priv))
+                       lane_mask = intel_dp_unused_lane_mask(pipe_config->lane_count);
+
+               vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
+                                   lane_mask);
+       }
+
+       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       intel_dp_start_link_train(intel_dp);
+       intel_dp_stop_link_train(intel_dp);
+
+       if (pipe_config->has_audio) {
+               DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
+                                pipe_name(pipe));
+               intel_audio_codec_enable(encoder, pipe_config, conn_state);
+       }
+}
+
+static void g4x_enable_dp(struct intel_encoder *encoder,
+                         const struct intel_crtc_state *pipe_config,
+                         const struct drm_connector_state *conn_state)
+{
+       intel_enable_dp(encoder, pipe_config, conn_state);
+       intel_edp_backlight_on(pipe_config, conn_state);
+}
+
+static void vlv_enable_dp(struct intel_encoder *encoder,
+                         const struct intel_crtc_state *pipe_config,
+                         const struct drm_connector_state *conn_state)
+{
+       intel_edp_backlight_on(pipe_config, conn_state);
+}
+
+static void g4x_pre_enable_dp(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config,
+                             const struct drm_connector_state *conn_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = encoder->port;
+
+       intel_dp_prepare(encoder, pipe_config);
+
+       /* Only ilk+ has port A */
+       if (port == PORT_A)
+               ironlake_edp_pll_on(intel_dp, pipe_config);
+}
+
+static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
+       enum pipe pipe = intel_dp->pps_pipe;
+       i915_reg_t pp_on_reg = PP_ON_DELAYS(pipe);
+
+       WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
+
+       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
+               return;
+
+       edp_panel_vdd_off_sync(intel_dp);
+
+       /*
+        * VLV seems to get confused when multiple power sequencers
+        * have the same port selected (even if only one has power/vdd
+        * enabled). The failure manifests as vlv_wait_port_ready() failing
+        * CHV on the other hand doesn't seem to mind having the same port
+        * selected in multiple power sequencers, but let's clear the
+        * port select always when logically disconnecting a power sequencer
+        * from a port.
+        */
+       DRM_DEBUG_KMS("detaching pipe %c power sequencer from port %c\n",
+                     pipe_name(pipe), port_name(intel_dig_port->base.port));
+       I915_WRITE(pp_on_reg, 0);
+       POSTING_READ(pp_on_reg);
+
+       intel_dp->pps_pipe = INVALID_PIPE;
+}
+
+static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
+                                     enum pipe pipe)
+{
+       struct intel_encoder *encoder;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       for_each_intel_dp(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+               enum port port = encoder->port;
+
+               WARN(intel_dp->active_pipe == pipe,
+                    "stealing pipe %c power sequencer from active (e)DP port %c\n",
+                    pipe_name(pipe), port_name(port));
+
+               if (intel_dp->pps_pipe != pipe)
+                       continue;
+
+               DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
+                             pipe_name(pipe), port_name(port));
+
+               /* make sure vdd is off before we steal it */
+               vlv_detach_power_sequencer(intel_dp);
+       }
+}
+
+static void vlv_init_panel_power_sequencer(struct intel_encoder *encoder,
+                                          const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
+
+       if (intel_dp->pps_pipe != INVALID_PIPE &&
+           intel_dp->pps_pipe != crtc->pipe) {
+               /*
+                * If another power sequencer was being used on this
+                * port previously make sure to turn off vdd there while
+                * we still have control of it.
+                */
+               vlv_detach_power_sequencer(intel_dp);
+       }
+
+       /*
+        * We may be stealing the power
+        * sequencer from another port.
+        */
+       vlv_steal_power_sequencer(dev_priv, crtc->pipe);
+
+       intel_dp->active_pipe = crtc->pipe;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       /* now it's all ours */
+       intel_dp->pps_pipe = crtc->pipe;
+
+       DRM_DEBUG_KMS("initializing pipe %c power sequencer for port %c\n",
+                     pipe_name(intel_dp->pps_pipe), port_name(encoder->port));
+
+       /* init power sequencer on this pipe and port */
+       intel_dp_init_panel_power_sequencer(intel_dp);
+       intel_dp_init_panel_power_sequencer_registers(intel_dp, true);
+}
+
+static void vlv_pre_enable_dp(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config,
+                             const struct drm_connector_state *conn_state)
+{
+       vlv_phy_pre_encoder_enable(encoder, pipe_config);
+
+       intel_enable_dp(encoder, pipe_config, conn_state);
+}
+
+static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config,
+                                 const struct drm_connector_state *conn_state)
+{
+       intel_dp_prepare(encoder, pipe_config);
+
+       vlv_phy_pre_pll_enable(encoder, pipe_config);
+}
+
+static void chv_pre_enable_dp(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config,
+                             const struct drm_connector_state *conn_state)
+{
+       chv_phy_pre_encoder_enable(encoder, pipe_config);
+
+       intel_enable_dp(encoder, pipe_config, conn_state);
+
+       /* Second common lane will stay alive on its own now */
+       chv_phy_release_cl2_override(encoder);
+}
+
+static void chv_dp_pre_pll_enable(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config,
+                                 const struct drm_connector_state *conn_state)
+{
+       intel_dp_prepare(encoder, pipe_config);
+
+       chv_phy_pre_pll_enable(encoder, pipe_config);
+}
+
+static void chv_dp_post_pll_disable(struct intel_encoder *encoder,
+                                   const struct intel_crtc_state *old_crtc_state,
+                                   const struct drm_connector_state *old_conn_state)
+{
+       chv_phy_post_pll_disable(encoder, old_crtc_state);
+}
+
+/*
+ * Fetch AUX CH registers 0x202 - 0x207 which contain
+ * link status information
+ */
+bool
+intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
+{
+       return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
+                               DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
+}
+
+/* These are source-specific values. */
+u8
+intel_dp_voltage_max(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+       enum port port = encoder->port;
+
+       if (HAS_DDI(dev_priv))
+               return intel_ddi_dp_voltage_max(encoder);
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+       else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A)
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+       else if (HAS_PCH_CPT(dev_priv) && port != PORT_A)
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+       else
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+}
+
+u8
+intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, u8 voltage_swing)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+       enum port port = encoder->port;
+
+       if (HAS_DDI(dev_priv)) {
+               return intel_ddi_dp_pre_emphasis_max(encoder, voltage_swing);
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+               default:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
+               }
+       } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               default:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
+               }
+       } else {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+               default:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
+               }
+       }
+}
+
+static u32 vlv_signal_levels(struct intel_dp *intel_dp)
+{
+       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+       unsigned long demph_reg_value, preemph_reg_value,
+               uniqtranscale_reg_value;
+       u8 train_set = intel_dp->train_set[0];
+
+       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
+               preemph_reg_value = 0x0004000;
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       demph_reg_value = 0x2B405555;
+                       uniqtranscale_reg_value = 0x552AB83A;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       demph_reg_value = 0x2B404040;
+                       uniqtranscale_reg_value = 0x5548B83A;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       demph_reg_value = 0x2B245555;
+                       uniqtranscale_reg_value = 0x5560B83A;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+                       demph_reg_value = 0x2B405555;
+                       uniqtranscale_reg_value = 0x5598DA3A;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
+               preemph_reg_value = 0x0002000;
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       demph_reg_value = 0x2B404040;
+                       uniqtranscale_reg_value = 0x5552B83A;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       demph_reg_value = 0x2B404848;
+                       uniqtranscale_reg_value = 0x5580B83A;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       demph_reg_value = 0x2B404040;
+                       uniqtranscale_reg_value = 0x55ADDA3A;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
+               preemph_reg_value = 0x0000000;
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       demph_reg_value = 0x2B305555;
+                       uniqtranscale_reg_value = 0x5570B83A;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       demph_reg_value = 0x2B2B4040;
+                       uniqtranscale_reg_value = 0x55ADDA3A;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
+               preemph_reg_value = 0x0006000;
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       demph_reg_value = 0x1B405555;
+                       uniqtranscale_reg_value = 0x55ADDA3A;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       default:
+               return 0;
+       }
+
+       vlv_set_phy_signal_level(encoder, demph_reg_value, preemph_reg_value,
+                                uniqtranscale_reg_value, 0);
+
+       return 0;
+}
+
+static u32 chv_signal_levels(struct intel_dp *intel_dp)
+{
+       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+       u32 deemph_reg_value, margin_reg_value;
+       bool uniq_trans_scale = false;
+       u8 train_set = intel_dp->train_set[0];
+
+       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       deemph_reg_value = 128;
+                       margin_reg_value = 52;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       deemph_reg_value = 128;
+                       margin_reg_value = 77;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       deemph_reg_value = 128;
+                       margin_reg_value = 102;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+                       deemph_reg_value = 128;
+                       margin_reg_value = 154;
+                       uniq_trans_scale = true;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       deemph_reg_value = 85;
+                       margin_reg_value = 78;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       deemph_reg_value = 85;
+                       margin_reg_value = 116;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       deemph_reg_value = 85;
+                       margin_reg_value = 154;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       deemph_reg_value = 64;
+                       margin_reg_value = 104;
+                       break;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       deemph_reg_value = 64;
+                       margin_reg_value = 154;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
+               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       deemph_reg_value = 43;
+                       margin_reg_value = 154;
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       default:
+               return 0;
+       }
+
+       chv_set_phy_signal_level(encoder, deemph_reg_value,
+                                margin_reg_value, uniq_trans_scale);
+
+       return 0;
+}
+
+static u32
+g4x_signal_levels(u8 train_set)
+{
+       u32 signal_levels = 0;
+
+       switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+       default:
+               signal_levels |= DP_VOLTAGE_0_4;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+               signal_levels |= DP_VOLTAGE_0_6;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+               signal_levels |= DP_VOLTAGE_0_8;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+               signal_levels |= DP_VOLTAGE_1_2;
+               break;
+       }
+       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
+       default:
+               signal_levels |= DP_PRE_EMPHASIS_0;
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
+               signal_levels |= DP_PRE_EMPHASIS_3_5;
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
+               signal_levels |= DP_PRE_EMPHASIS_6;
+               break;
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
+               signal_levels |= DP_PRE_EMPHASIS_9_5;
+               break;
+       }
+       return signal_levels;
+}
+
+/* SNB CPU eDP voltage swing and pre-emphasis control */
+static u32
+snb_cpu_edp_signal_levels(u8 train_set)
+{
+       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+                                        DP_TRAIN_PRE_EMPHASIS_MASK);
+       switch (signal_levels) {
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B;
+       default:
+               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
+                             "0x%x\n", signal_levels);
+               return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
+       }
+}
+
+/* IVB CPU eDP voltage swing and pre-emphasis control */
+static u32
+ivb_cpu_edp_signal_levels(u8 train_set)
+{
+       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+                                        DP_TRAIN_PRE_EMPHASIS_MASK);
+       switch (signal_levels) {
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return EDP_LINK_TRAIN_400MV_0DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               return EDP_LINK_TRAIN_400MV_6DB_IVB;
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return EDP_LINK_TRAIN_600MV_0DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return EDP_LINK_TRAIN_600MV_3_5DB_IVB;
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return EDP_LINK_TRAIN_800MV_0DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return EDP_LINK_TRAIN_800MV_3_5DB_IVB;
+
+       default:
+               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
+                             "0x%x\n", signal_levels);
+               return EDP_LINK_TRAIN_500MV_0DB_IVB;
+       }
+}
+
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->base.port;
+       u32 signal_levels, mask = 0;
+       u8 train_set = intel_dp->train_set[0];
+
+       if (IS_GEN9_LP(dev_priv) || INTEL_GEN(dev_priv) >= 10) {
+               signal_levels = bxt_signal_levels(intel_dp);
+       } else if (HAS_DDI(dev_priv)) {
+               signal_levels = ddi_signal_levels(intel_dp);
+               mask = DDI_BUF_EMP_MASK;
+       } else if (IS_CHERRYVIEW(dev_priv)) {
+               signal_levels = chv_signal_levels(intel_dp);
+       } else if (IS_VALLEYVIEW(dev_priv)) {
+               signal_levels = vlv_signal_levels(intel_dp);
+       } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) {
+               signal_levels = ivb_cpu_edp_signal_levels(train_set);
+               mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
+       } else if (IS_GEN(dev_priv, 6) && port == PORT_A) {
+               signal_levels = snb_cpu_edp_signal_levels(train_set);
+               mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB;
+       } else {
+               signal_levels = g4x_signal_levels(train_set);
+               mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK;
+       }
+
+       if (mask)
+               DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels);
+
+       DRM_DEBUG_KMS("Using vswing level %d\n",
+               train_set & DP_TRAIN_VOLTAGE_SWING_MASK);
+       DRM_DEBUG_KMS("Using pre-emphasis level %d\n",
+               (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+                       DP_TRAIN_PRE_EMPHASIS_SHIFT);
+
+       intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels;
+
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
+}
+
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+                                      u8 dp_train_pat)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv =
+               to_i915(intel_dig_port->base.base.dev);
+
+       _intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat);
+
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
+}
+
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->base.port;
+       u32 val;
+
+       if (!HAS_DDI(dev_priv))
+               return;
+
+       val = I915_READ(DP_TP_CTL(port));
+       val &= ~DP_TP_CTL_LINK_TRAIN_MASK;
+       val |= DP_TP_CTL_LINK_TRAIN_IDLE;
+       I915_WRITE(DP_TP_CTL(port), val);
+
+       /*
+        * On PORT_A we can have only eDP in SST mode. There the only reason
+        * we need to set idle transmission mode is to work around a HW issue
+        * where we enable the pipe while not in idle link-training mode.
+        * In this case there is requirement to wait for a minimum number of
+        * idle patterns to be sent.
+        */
+       if (port == PORT_A)
+               return;
+
+       if (intel_wait_for_register(&dev_priv->uncore, DP_TP_STATUS(port),
+                                   DP_TP_STATUS_IDLE_DONE,
+                                   DP_TP_STATUS_IDLE_DONE,
+                                   1))
+               DRM_ERROR("Timed out waiting for DP idle patterns\n");
+}
+
+static void
+intel_dp_link_down(struct intel_encoder *encoder,
+                  const struct intel_crtc_state *old_crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       enum port port = encoder->port;
+       u32 DP = intel_dp->DP;
+
+       if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) ||
+           (HAS_PCH_CPT(dev_priv) && port != PORT_A)) {
+               DP &= ~DP_LINK_TRAIN_MASK_CPT;
+               DP |= DP_LINK_TRAIN_PAT_IDLE_CPT;
+       } else {
+               DP &= ~DP_LINK_TRAIN_MASK;
+               DP |= DP_LINK_TRAIN_PAT_IDLE;
+       }
+       I915_WRITE(intel_dp->output_reg, DP);
+       POSTING_READ(intel_dp->output_reg);
+
+       DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
+       I915_WRITE(intel_dp->output_reg, DP);
+       POSTING_READ(intel_dp->output_reg);
+
+       /*
+        * HW workaround for IBX, we need to move the port
+        * to transcoder A after disabling it to allow the
+        * matching HDMI port to be enabled on transcoder A.
+        */
+       if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B && port != PORT_A) {
+               /*
+                * We get CPU/PCH FIFO underruns on the other pipe when
+                * doing the workaround. Sweep them under the rug.
+                */
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
+               /* always enable with pattern 1 (as per spec) */
+               DP &= ~(DP_PIPE_SEL_MASK | DP_LINK_TRAIN_MASK);
+               DP |= DP_PORT_EN | DP_PIPE_SEL(PIPE_A) |
+                       DP_LINK_TRAIN_PAT_1;
+               I915_WRITE(intel_dp->output_reg, DP);
+               POSTING_READ(intel_dp->output_reg);
+
+               DP &= ~DP_PORT_EN;
+               I915_WRITE(intel_dp->output_reg, DP);
+               POSTING_READ(intel_dp->output_reg);
+
+               intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+       }
+
+       msleep(intel_dp->panel_power_down_delay);
+
+       intel_dp->DP = DP;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               intel_wakeref_t wakeref;
+
+               with_pps_lock(intel_dp, wakeref)
+                       intel_dp->active_pipe = INVALID_PIPE;
+       }
+}
+
+static void
+intel_dp_extended_receiver_capabilities(struct intel_dp *intel_dp)
+{
+       u8 dpcd_ext[6];
+
+       /*
+        * Prior to DP1.3 the bit represented by
+        * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
+        * if it is set DP_DPCD_REV at 0000h could be at a value less than
+        * the true capability of the panel. The only way to check is to
+        * then compare 0000h and 2200h.
+        */
+       if (!(intel_dp->dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
+             DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
+               return;
+
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_DP13_DPCD_REV,
+                            &dpcd_ext, sizeof(dpcd_ext)) != sizeof(dpcd_ext)) {
+               DRM_ERROR("DPCD failed read at extended capabilities\n");
+               return;
+       }
+
+       if (intel_dp->dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
+               DRM_DEBUG_KMS("DPCD extended DPCD rev less than base DPCD rev\n");
+               return;
+       }
+
+       if (!memcmp(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext)))
+               return;
+
+       DRM_DEBUG_KMS("Base DPCD: %*ph\n",
+                     (int)sizeof(intel_dp->dpcd), intel_dp->dpcd);
+
+       memcpy(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext));
+}
+
+bool
+intel_dp_read_dpcd(struct intel_dp *intel_dp)
+{
+       if (drm_dp_dpcd_read(&intel_dp->aux, 0x000, intel_dp->dpcd,
+                            sizeof(intel_dp->dpcd)) < 0)
+               return false; /* aux transfer failed */
+
+       intel_dp_extended_receiver_capabilities(intel_dp);
+
+       DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd);
+
+       return intel_dp->dpcd[DP_DPCD_REV] != 0;
+}
+
+bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
+{
+       u8 dprx = 0;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
+                             &dprx) != 1)
+               return false;
+       return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
+}
+
+static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp)
+{
+       /*
+        * Clear the cached register set to avoid using stale values
+        * for the sinks that do not support DSC.
+        */
+       memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
+
+       /* Clear fec_capable to avoid using stale values */
+       intel_dp->fec_capable = 0;
+
+       /* Cache the DSC DPCD if eDP or DP rev >= 1.4 */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x14 ||
+           intel_dp->edp_dpcd[0] >= DP_EDP_14) {
+               if (drm_dp_dpcd_read(&intel_dp->aux, DP_DSC_SUPPORT,
+                                    intel_dp->dsc_dpcd,
+                                    sizeof(intel_dp->dsc_dpcd)) < 0)
+                       DRM_ERROR("Failed to read DPCD register 0x%x\n",
+                                 DP_DSC_SUPPORT);
+
+               DRM_DEBUG_KMS("DSC DPCD: %*ph\n",
+                             (int)sizeof(intel_dp->dsc_dpcd),
+                             intel_dp->dsc_dpcd);
+
+               /* FEC is supported only on DP 1.4 */
+               if (!intel_dp_is_edp(intel_dp) &&
+                   drm_dp_dpcd_readb(&intel_dp->aux, DP_FEC_CAPABILITY,
+                                     &intel_dp->fec_capable) < 0)
+                       DRM_ERROR("Failed to read FEC DPCD register\n");
+
+               DRM_DEBUG_KMS("FEC CAPABILITY: %x\n", intel_dp->fec_capable);
+       }
+}
+
+static bool
+intel_edp_init_dpcd(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
+
+       /* this function is meant to be called only once */
+       WARN_ON(intel_dp->dpcd[DP_DPCD_REV] != 0);
+
+       if (!intel_dp_read_dpcd(intel_dp))
+               return false;
+
+       drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
+                        drm_dp_is_branch(intel_dp->dpcd));
+
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
+               dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
+                       DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+
+       /*
+        * Read the eDP display control registers.
+        *
+        * Do this independent of DP_DPCD_DISPLAY_CONTROL_CAPABLE bit in
+        * DP_EDP_CONFIGURATION_CAP, because some buggy displays do not have it
+        * set, but require eDP 1.4+ detection (e.g. for supported link rates
+        * method). The display control registers should read zero if they're
+        * not supported anyway.
+        */
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
+                            intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
+                            sizeof(intel_dp->edp_dpcd))
+               DRM_DEBUG_KMS("eDP DPCD: %*ph\n", (int) sizeof(intel_dp->edp_dpcd),
+                             intel_dp->edp_dpcd);
+
+       /*
+        * This has to be called after intel_dp->edp_dpcd is filled, PSR checks
+        * for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1]
+        */
+       intel_psr_init_dpcd(intel_dp);
+
+       /* Read the eDP 1.4+ supported link rates. */
+       if (intel_dp->edp_dpcd[0] >= DP_EDP_14) {
+               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
+               int i;
+
+               drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
+                               sink_rates, sizeof(sink_rates));
+
+               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
+                       int val = le16_to_cpu(sink_rates[i]);
+
+                       if (val == 0)
+                               break;
+
+                       /* Value read multiplied by 200kHz gives the per-lane
+                        * link rate in kHz. The source rates are, however,
+                        * stored in terms of LS_Clk kHz. The full conversion
+                        * back to symbols is
+                        * (val * 200kHz)*(8/10 ch. encoding)*(1/8 bit to Byte)
+                        */
+                       intel_dp->sink_rates[i] = (val * 200) / 10;
+               }
+               intel_dp->num_sink_rates = i;
+       }
+
+       /*
+        * Use DP_LINK_RATE_SET if DP_SUPPORTED_LINK_RATES are available,
+        * default to DP_MAX_LINK_RATE and DP_LINK_BW_SET otherwise.
+        */
+       if (intel_dp->num_sink_rates)
+               intel_dp->use_rate_select = true;
+       else
+               intel_dp_set_sink_rates(intel_dp);
+
+       intel_dp_set_common_rates(intel_dp);
+
+       /* Read the eDP DSC DPCD registers */
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               intel_dp_get_dsc_sink_cap(intel_dp);
+
+       return true;
+}
+
+
+static bool
+intel_dp_get_dpcd(struct intel_dp *intel_dp)
+{
+       if (!intel_dp_read_dpcd(intel_dp))
+               return false;
+
+       /* Don't clobber cached eDP rates. */
+       if (!intel_dp_is_edp(intel_dp)) {
+               intel_dp_set_sink_rates(intel_dp);
+               intel_dp_set_common_rates(intel_dp);
+       }
+
+       /*
+        * Some eDP panels do not set a valid value for sink count, that is why
+        * it don't care about read it here and in intel_edp_init_dpcd().
+        */
+       if (!intel_dp_is_edp(intel_dp)) {
+               u8 count;
+               ssize_t r;
+
+               r = drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, &count);
+               if (r < 1)
+                       return false;
+
+               /*
+                * Sink count can change between short pulse hpd hence
+                * a member variable in intel_dp will track any changes
+                * between short pulse interrupts.
+                */
+               intel_dp->sink_count = DP_GET_SINK_COUNT(count);
+
+               /*
+                * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
+                * a dongle is present but no display. Unless we require to know
+                * if a dongle is present or not, we don't need to update
+                * downstream port information. So, an early return here saves
+                * time from performing other operations which are not required.
+                */
+               if (!intel_dp->sink_count)
+                       return false;
+       }
+
+       if (!drm_dp_is_branch(intel_dp->dpcd))
+               return true; /* native DP sink */
+
+       if (intel_dp->dpcd[DP_DPCD_REV] == 0x10)
+               return true; /* no per-port downstream info */
+
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_DOWNSTREAM_PORT_0,
+                            intel_dp->downstream_ports,
+                            DP_MAX_DOWNSTREAM_PORTS) < 0)
+               return false; /* downstream port status fetch failed */
+
+       return true;
+}
+
+static bool
+intel_dp_sink_can_mst(struct intel_dp *intel_dp)
+{
+       u8 mstm_cap;
+
+       if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
+               return false;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_MSTM_CAP, &mstm_cap) != 1)
+               return false;
+
+       return mstm_cap & DP_MST_CAP;
+}
+
+static bool
+intel_dp_can_mst(struct intel_dp *intel_dp)
+{
+       return i915_modparams.enable_dp_mst &&
+               intel_dp->can_mst &&
+               intel_dp_sink_can_mst(intel_dp);
+}
+
+static void
+intel_dp_configure_mst(struct intel_dp *intel_dp)
+{
+       struct intel_encoder *encoder =
+               &dp_to_dig_port(intel_dp)->base;
+       bool sink_can_mst = intel_dp_sink_can_mst(intel_dp);
+
+       DRM_DEBUG_KMS("MST support? port %c: %s, sink: %s, modparam: %s\n",
+                     port_name(encoder->port), yesno(intel_dp->can_mst),
+                     yesno(sink_can_mst), yesno(i915_modparams.enable_dp_mst));
+
+       if (!intel_dp->can_mst)
+               return;
+
+       intel_dp->is_mst = sink_can_mst &&
+               i915_modparams.enable_dp_mst;
+
+       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                       intel_dp->is_mst);
+}
+
+static bool
+intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
+{
+       return drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT_ESI,
+                               sink_irq_vector, DP_DPRX_ESI_LEN) ==
+               DP_DPRX_ESI_LEN;
+}
+
+u16 intel_dp_dsc_get_output_bpp(int link_clock, u8 lane_count,
+                               int mode_clock, int mode_hdisplay)
+{
+       u16 bits_per_pixel, max_bpp_small_joiner_ram;
+       int i;
+
+       /*
+        * Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)*
+        * (LinkSymbolClock)* 8 * ((100-FECOverhead)/100)*(TimeSlotsPerMTP)
+        * FECOverhead = 2.4%, for SST -> TimeSlotsPerMTP is 1,
+        * for MST -> TimeSlotsPerMTP has to be calculated
+        */
+       bits_per_pixel = (link_clock * lane_count * 8 *
+                         DP_DSC_FEC_OVERHEAD_FACTOR) /
+               mode_clock;
+
+       /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */
+       max_bpp_small_joiner_ram = DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER /
+               mode_hdisplay;
+
+       /*
+        * Greatest allowed DSC BPP = MIN (output BPP from avaialble Link BW
+        * check, output bpp from small joiner RAM check)
+        */
+       bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram);
+
+       /* Error out if the max bpp is less than smallest allowed valid bpp */
+       if (bits_per_pixel < valid_dsc_bpp[0]) {
+               DRM_DEBUG_KMS("Unsupported BPP %d\n", bits_per_pixel);
+               return 0;
+       }
+
+       /* Find the nearest match in the array of known BPPs from VESA */
+       for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
+               if (bits_per_pixel < valid_dsc_bpp[i + 1])
+                       break;
+       }
+       bits_per_pixel = valid_dsc_bpp[i];
+
+       /*
+        * Compressed BPP in U6.4 format so multiply by 16, for Gen 11,
+        * fractional part is 0
+        */
+       return bits_per_pixel << 4;
+}
+
+u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
+                               int mode_clock,
+                               int mode_hdisplay)
+{
+       u8 min_slice_count, i;
+       int max_slice_width;
+
+       if (mode_clock <= DP_DSC_PEAK_PIXEL_RATE)
+               min_slice_count = DIV_ROUND_UP(mode_clock,
+                                              DP_DSC_MAX_ENC_THROUGHPUT_0);
+       else
+               min_slice_count = DIV_ROUND_UP(mode_clock,
+                                              DP_DSC_MAX_ENC_THROUGHPUT_1);
+
+       max_slice_width = drm_dp_dsc_sink_max_slice_width(intel_dp->dsc_dpcd);
+       if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) {
+               DRM_DEBUG_KMS("Unsupported slice width %d by DP DSC Sink device\n",
+                             max_slice_width);
+               return 0;
+       }
+       /* Also take into account max slice width */
+       min_slice_count = min_t(u8, min_slice_count,
+                               DIV_ROUND_UP(mode_hdisplay,
+                                            max_slice_width));
+
+       /* Find the closest match to the valid slice count values */
+       for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) {
+               if (valid_dsc_slicecount[i] >
+                   drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                   false))
+                       break;
+               if (min_slice_count  <= valid_dsc_slicecount[i])
+                       return valid_dsc_slicecount[i];
+       }
+
+       DRM_DEBUG_KMS("Unsupported Slice Count %d\n", min_slice_count);
+       return 0;
+}
+
+static void
+intel_pixel_encoding_setup_vsc(struct intel_dp *intel_dp,
+                              const struct intel_crtc_state *crtc_state)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct dp_sdp vsc_sdp = {};
+
+       /* Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119 */
+       vsc_sdp.sdp_header.HB0 = 0;
+       vsc_sdp.sdp_header.HB1 = 0x7;
+
+       /*
+        * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
+        * Colorimetry Format indication.
+        */
+       vsc_sdp.sdp_header.HB2 = 0x5;
+
+       /*
+        * VSC SDP supporting 3D stereo, + PSR2, + Pixel Encoding/
+        * Colorimetry Format indication (HB2 = 05h).
+        */
+       vsc_sdp.sdp_header.HB3 = 0x13;
+
+       /*
+        * YCbCr 420 = 3h DB16[7:4] ITU-R BT.601 = 0h, ITU-R BT.709 = 1h
+        * DB16[3:0] DP 1.4a spec, Table 2-120
+        */
+       vsc_sdp.db[16] = 0x3 << 4; /* 0x3 << 4 , YCbCr 420*/
+       /* RGB->YCBCR color conversion uses the BT.709 color space. */
+       vsc_sdp.db[16] |= 0x1; /* 0x1, ITU-R BT.709 */
+
+       /*
+        * For pixel encoding formats YCbCr444, YCbCr422, YCbCr420, and Y Only,
+        * the following Component Bit Depth values are defined:
+        * 001b = 8bpc.
+        * 010b = 10bpc.
+        * 011b = 12bpc.
+        * 100b = 16bpc.
+        */
+       switch (crtc_state->pipe_bpp) {
+       case 24: /* 8bpc */
+               vsc_sdp.db[17] = 0x1;
+               break;
+       case 30: /* 10bpc */
+               vsc_sdp.db[17] = 0x2;
+               break;
+       case 36: /* 12bpc */
+               vsc_sdp.db[17] = 0x3;
+               break;
+       case 48: /* 16bpc */
+               vsc_sdp.db[17] = 0x4;
+               break;
+       default:
+               MISSING_CASE(crtc_state->pipe_bpp);
+               break;
+       }
+
+       /*
+        * Dynamic Range (Bit 7)
+        * 0 = VESA range, 1 = CTA range.
+        * all YCbCr are always limited range
+        */
+       vsc_sdp.db[17] |= 0x80;
+
+       /*
+        * Content Type (Bits 2:0)
+        * 000b = Not defined.
+        * 001b = Graphics.
+        * 010b = Photo.
+        * 011b = Video.
+        * 100b = Game
+        * All other values are RESERVED.
+        * Note: See CTA-861-G for the definition and expected
+        * processing by a stream sink for the above contect types.
+        */
+       vsc_sdp.db[18] = 0;
+
+       intel_dig_port->write_infoframe(&intel_dig_port->base,
+                       crtc_state, DP_SDP_VSC, &vsc_sdp, sizeof(vsc_sdp));
+}
+
+void intel_dp_ycbcr_420_enable(struct intel_dp *intel_dp,
+                              const struct intel_crtc_state *crtc_state)
+{
+       if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
+               return;
+
+       intel_pixel_encoding_setup_vsc(intel_dp, crtc_state);
+}
+
+static u8 intel_dp_autotest_link_training(struct intel_dp *intel_dp)
+{
+       int status = 0;
+       int test_link_rate;
+       u8 test_lane_count, test_link_bw;
+       /* (DP CTS 1.2)
+        * 4.3.1.11
+        */
+       /* Read the TEST_LANE_COUNT and TEST_LINK_RTAE fields (DP CTS 3.1.4) */
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LANE_COUNT,
+                                  &test_lane_count);
+
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Lane count read failed\n");
+               return DP_TEST_NAK;
+       }
+       test_lane_count &= DP_MAX_LANE_COUNT_MASK;
+
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE,
+                                  &test_link_bw);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Link Rate read failed\n");
+               return DP_TEST_NAK;
+       }
+       test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw);
+
+       /* Validate the requested link rate and lane count */
+       if (!intel_dp_link_params_valid(intel_dp, test_link_rate,
+                                       test_lane_count))
+               return DP_TEST_NAK;
+
+       intel_dp->compliance.test_lane_count = test_lane_count;
+       intel_dp->compliance.test_link_rate = test_link_rate;
+
+       return DP_TEST_ACK;
+}
+
+static u8 intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
+{
+       u8 test_pattern;
+       u8 test_misc;
+       __be16 h_width, v_height;
+       int status = 0;
+
+       /* Read the TEST_PATTERN (DP CTS 3.1.5) */
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_PATTERN,
+                                  &test_pattern);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Test pattern read failed\n");
+               return DP_TEST_NAK;
+       }
+       if (test_pattern != DP_COLOR_RAMP)
+               return DP_TEST_NAK;
+
+       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_H_WIDTH_HI,
+                                 &h_width, 2);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("H Width read failed\n");
+               return DP_TEST_NAK;
+       }
+
+       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_V_HEIGHT_HI,
+                                 &v_height, 2);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("V Height read failed\n");
+               return DP_TEST_NAK;
+       }
+
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_MISC0,
+                                  &test_misc);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("TEST MISC read failed\n");
+               return DP_TEST_NAK;
+       }
+       if ((test_misc & DP_TEST_COLOR_FORMAT_MASK) != DP_COLOR_FORMAT_RGB)
+               return DP_TEST_NAK;
+       if (test_misc & DP_TEST_DYNAMIC_RANGE_CEA)
+               return DP_TEST_NAK;
+       switch (test_misc & DP_TEST_BIT_DEPTH_MASK) {
+       case DP_TEST_BIT_DEPTH_6:
+               intel_dp->compliance.test_data.bpc = 6;
+               break;
+       case DP_TEST_BIT_DEPTH_8:
+               intel_dp->compliance.test_data.bpc = 8;
+               break;
+       default:
+               return DP_TEST_NAK;
+       }
+
+       intel_dp->compliance.test_data.video_pattern = test_pattern;
+       intel_dp->compliance.test_data.hdisplay = be16_to_cpu(h_width);
+       intel_dp->compliance.test_data.vdisplay = be16_to_cpu(v_height);
+       /* Set test active flag here so userspace doesn't interrupt things */
+       intel_dp->compliance.test_active = 1;
+
+       return DP_TEST_ACK;
+}
+
+static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
+{
+       u8 test_result = DP_TEST_ACK;
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       struct drm_connector *connector = &intel_connector->base;
+
+       if (intel_connector->detect_edid == NULL ||
+           connector->edid_corrupt ||
+           intel_dp->aux.i2c_defer_count > 6) {
+               /* Check EDID read for NACKs, DEFERs and corruption
+                * (DP CTS 1.2 Core r1.1)
+                *    4.2.2.4 : Failed EDID read, I2C_NAK
+                *    4.2.2.5 : Failed EDID read, I2C_DEFER
+                *    4.2.2.6 : EDID corruption detected
+                * Use failsafe mode for all cases
+                */
+               if (intel_dp->aux.i2c_nack_count > 0 ||
+                       intel_dp->aux.i2c_defer_count > 0)
+                       DRM_DEBUG_KMS("EDID read had %d NACKs, %d DEFERs\n",
+                                     intel_dp->aux.i2c_nack_count,
+                                     intel_dp->aux.i2c_defer_count);
+               intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_FAILSAFE;
+       } else {
+               struct edid *block = intel_connector->detect_edid;
+
+               /* We have to write the checksum
+                * of the last block read
+                */
+               block += intel_connector->detect_edid->extensions;
+
+               if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
+                                      block->checksum) <= 0)
+                       DRM_DEBUG_KMS("Failed to write EDID checksum\n");
+
+               test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE;
+               intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_PREFERRED;
+       }
+
+       /* Set test active flag here so userspace doesn't interrupt things */
+       intel_dp->compliance.test_active = 1;
+
+       return test_result;
+}
+
+static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
+{
+       u8 test_result = DP_TEST_NAK;
+       return test_result;
+}
+
+static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
+{
+       u8 response = DP_TEST_NAK;
+       u8 request = 0;
+       int status;
+
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_REQUEST, &request);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Could not read test request from sink\n");
+               goto update_status;
+       }
+
+       switch (request) {
+       case DP_TEST_LINK_TRAINING:
+               DRM_DEBUG_KMS("LINK_TRAINING test requested\n");
+               response = intel_dp_autotest_link_training(intel_dp);
+               break;
+       case DP_TEST_LINK_VIDEO_PATTERN:
+               DRM_DEBUG_KMS("TEST_PATTERN test requested\n");
+               response = intel_dp_autotest_video_pattern(intel_dp);
+               break;
+       case DP_TEST_LINK_EDID_READ:
+               DRM_DEBUG_KMS("EDID test requested\n");
+               response = intel_dp_autotest_edid(intel_dp);
+               break;
+       case DP_TEST_LINK_PHY_TEST_PATTERN:
+               DRM_DEBUG_KMS("PHY_PATTERN test requested\n");
+               response = intel_dp_autotest_phy_pattern(intel_dp);
+               break;
+       default:
+               DRM_DEBUG_KMS("Invalid test request '%02x'\n", request);
+               break;
+       }
+
+       if (response & DP_TEST_ACK)
+               intel_dp->compliance.test_type = request;
+
+update_status:
+       status = drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, response);
+       if (status <= 0)
+               DRM_DEBUG_KMS("Could not write test response to sink\n");
+}
+
+static int
+intel_dp_check_mst_status(struct intel_dp *intel_dp)
+{
+       bool bret;
+
+       if (intel_dp->is_mst) {
+               u8 esi[DP_DPRX_ESI_LEN] = { 0 };
+               int ret = 0;
+               int retry;
+               bool handled;
+
+               WARN_ON_ONCE(intel_dp->active_mst_links < 0);
+               bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
+go_again:
+               if (bret == true) {
+
+                       /* check link status - esi[10] = 0x200c */
+                       if (intel_dp->active_mst_links > 0 &&
+                           !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
+                               DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
+                               intel_dp_start_link_train(intel_dp);
+                               intel_dp_stop_link_train(intel_dp);
+                       }
+
+                       DRM_DEBUG_KMS("got esi %3ph\n", esi);
+                       ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
+
+                       if (handled) {
+                               for (retry = 0; retry < 3; retry++) {
+                                       int wret;
+                                       wret = drm_dp_dpcd_write(&intel_dp->aux,
+                                                                DP_SINK_COUNT_ESI+1,
+                                                                &esi[1], 3);
+                                       if (wret == 3) {
+                                               break;
+                                       }
+                               }
+
+                               bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
+                               if (bret == true) {
+                                       DRM_DEBUG_KMS("got esi2 %3ph\n", esi);
+                                       goto go_again;
+                               }
+                       } else
+                               ret = 0;
+
+                       return ret;
+               } else {
+                       DRM_DEBUG_KMS("failed to get ESI - device may have failed\n");
+                       intel_dp->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                                       intel_dp->is_mst);
+               }
+       }
+       return -EINVAL;
+}
+
+static bool
+intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
+{
+       u8 link_status[DP_LINK_STATUS_SIZE];
+
+       if (!intel_dp->link_trained)
+               return false;
+
+       /*
+        * While PSR source HW is enabled, it will control main-link sending
+        * frames, enabling and disabling it so trying to do a retrain will fail
+        * as the link would or not be on or it could mix training patterns
+        * and frame data at the same time causing retrain to fail.
+        * Also when exiting PSR, HW will retrain the link anyways fixing
+        * any link status error.
+        */
+       if (intel_psr_enabled(intel_dp))
+               return false;
+
+       if (!intel_dp_get_link_status(intel_dp, link_status))
+               return false;
+
+       /*
+        * Validate the cached values of intel_dp->link_rate and
+        * intel_dp->lane_count before attempting to retrain.
+        */
+       if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
+                                       intel_dp->lane_count))
+               return false;
+
+       /* Retrain if Channel EQ or CR not ok */
+       return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
+}
+
+int intel_dp_retrain_link(struct intel_encoder *encoder,
+                         struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_connector *connector = intel_dp->attached_connector;
+       struct drm_connector_state *conn_state;
+       struct intel_crtc_state *crtc_state;
+       struct intel_crtc *crtc;
+       int ret;
+
+       /* FIXME handle the MST connectors as well */
+
+       if (!connector || connector->base.status != connector_status_connected)
+               return 0;
+
+       ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
+                              ctx);
+       if (ret)
+               return ret;
+
+       conn_state = connector->base.state;
+
+       crtc = to_intel_crtc(conn_state->crtc);
+       if (!crtc)
+               return 0;
+
+       ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+       if (ret)
+               return ret;
+
+       crtc_state = to_intel_crtc_state(crtc->base.state);
+
+       WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
+
+       if (!crtc_state->base.active)
+               return 0;
+
+       if (conn_state->commit &&
+           !try_wait_for_completion(&conn_state->commit->hw_done))
+               return 0;
+
+       if (!intel_dp_needs_link_retrain(intel_dp))
+               return 0;
+
+       /* Suppress underruns caused by re-training */
+       intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
+       if (crtc_state->has_pch_encoder)
+               intel_set_pch_fifo_underrun_reporting(dev_priv,
+                                                     intel_crtc_pch_transcoder(crtc), false);
+
+       intel_dp_start_link_train(intel_dp);
+       intel_dp_stop_link_train(intel_dp);
+
+       /* Keep underrun reporting disabled until things are stable */
+       intel_wait_for_vblank(dev_priv, crtc->pipe);
+
+       intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true);
+       if (crtc_state->has_pch_encoder)
+               intel_set_pch_fifo_underrun_reporting(dev_priv,
+                                                     intel_crtc_pch_transcoder(crtc), true);
+
+       return 0;
+}
+
+/*
+ * If display is now connected check links status,
+ * there has been known issues of link loss triggering
+ * long pulse.
+ *
+ * Some sinks (eg. ASUS PB287Q) seem to perform some
+ * weird HPD ping pong during modesets. So we can apparently
+ * end up with HPD going low during a modeset, and then
+ * going back up soon after. And once that happens we must
+ * retrain the link to get a picture. That's in case no
+ * userspace component reacted to intermittent HPD dip.
+ */
+static bool intel_dp_hotplug(struct intel_encoder *encoder,
+                            struct intel_connector *connector)
+{
+       struct drm_modeset_acquire_ctx ctx;
+       bool changed;
+       int ret;
+
+       changed = intel_encoder_hotplug(encoder, connector);
+
+       drm_modeset_acquire_init(&ctx, 0);
+
+       for (;;) {
+               ret = intel_dp_retrain_link(encoder, &ctx);
+
+               if (ret == -EDEADLK) {
+                       drm_modeset_backoff(&ctx);
+                       continue;
+               }
+
+               break;
+       }
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+       WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
+
+       return changed;
+}
+
+static void intel_dp_check_service_irq(struct intel_dp *intel_dp)
+{
+       u8 val;
+
+       if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
+               return;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux,
+                             DP_DEVICE_SERVICE_IRQ_VECTOR, &val) != 1 || !val)
+               return;
+
+       drm_dp_dpcd_writeb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, val);
+
+       if (val & DP_AUTOMATED_TEST_REQUEST)
+               intel_dp_handle_test_request(intel_dp);
+
+       if (val & DP_CP_IRQ)
+               intel_hdcp_handle_cp_irq(intel_dp->attached_connector);
+
+       if (val & DP_SINK_SPECIFIC_IRQ)
+               DRM_DEBUG_DRIVER("Sink specific irq unhandled\n");
+}
+
+/*
+ * According to DP spec
+ * 5.1.2:
+ *  1. Read DPCD
+ *  2. Configure link according to Receiver Capabilities
+ *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
+ *  4. Check link status on receipt of hot-plug interrupt
+ *
+ * intel_dp_short_pulse -  handles short pulse interrupts
+ * when full detection is not required.
+ * Returns %true if short pulse is handled and full detection
+ * is NOT required and %false otherwise.
+ */
+static bool
+intel_dp_short_pulse(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       u8 old_sink_count = intel_dp->sink_count;
+       bool ret;
+
+       /*
+        * Clearing compliance test variables to allow capturing
+        * of values for next automated test request.
+        */
+       memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
+
+       /*
+        * Now read the DPCD to see if it's actually running
+        * If the current value of sink count doesn't match with
+        * the value that was stored earlier or dpcd read failed
+        * we need to do full detection
+        */
+       ret = intel_dp_get_dpcd(intel_dp);
+
+       if ((old_sink_count != intel_dp->sink_count) || !ret) {
+               /* No need to proceed if we are going to do full detect */
+               return false;
+       }
+
+       intel_dp_check_service_irq(intel_dp);
+
+       /* Handle CEC interrupts, if any */
+       drm_dp_cec_irq(&intel_dp->aux);
+
+       /* defer to the hotplug work for link retraining if needed */
+       if (intel_dp_needs_link_retrain(intel_dp))
+               return false;
+
+       intel_psr_short_pulse(intel_dp);
+
+       if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
+               DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
+               /* Send a Hotplug Uevent to userspace to start modeset */
+               drm_kms_helper_hotplug_event(&dev_priv->drm);
+       }
+
+       return true;
+}
+
+/* XXX this is probably wrong for multiple downstream ports */
+static enum drm_connector_status
+intel_dp_detect_dpcd(struct intel_dp *intel_dp)
+{
+       struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+       u8 *dpcd = intel_dp->dpcd;
+       u8 type;
+
+       if (WARN_ON(intel_dp_is_edp(intel_dp)))
+               return connector_status_connected;
+
+       if (lspcon->active)
+               lspcon_resume(lspcon);
+
+       if (!intel_dp_get_dpcd(intel_dp))
+               return connector_status_disconnected;
+
+       /* if there's no downstream port, we're done */
+       if (!drm_dp_is_branch(dpcd))
+               return connector_status_connected;
+
+       /* If we're HPD-aware, SINK_COUNT changes dynamically */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
+           intel_dp->downstream_ports[0] & DP_DS_PORT_HPD) {
+
+               return intel_dp->sink_count ?
+               connector_status_connected : connector_status_disconnected;
+       }
+
+       if (intel_dp_can_mst(intel_dp))
+               return connector_status_connected;
+
+       /* If no HPD, poke DDC gently */
+       if (drm_probe_ddc(&intel_dp->aux.ddc))
+               return connector_status_connected;
+
+       /* Well we tried, say unknown for unreliable port types */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
+               type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
+               if (type == DP_DS_PORT_TYPE_VGA ||
+                   type == DP_DS_PORT_TYPE_NON_EDID)
+                       return connector_status_unknown;
+       } else {
+               type = intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+                       DP_DWN_STRM_PORT_TYPE_MASK;
+               if (type == DP_DWN_STRM_PORT_TYPE_ANALOG ||
+                   type == DP_DWN_STRM_PORT_TYPE_OTHER)
+                       return connector_status_unknown;
+       }
+
+       /* Anything else is out of spec, warn and ignore */
+       DRM_DEBUG_KMS("Broken DP branch device, ignoring\n");
+       return connector_status_disconnected;
+}
+
+static enum drm_connector_status
+edp_detect(struct intel_dp *intel_dp)
+{
+       return connector_status_connected;
+}
+
+static bool ibx_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 bit;
+
+       switch (encoder->hpd_pin) {
+       case HPD_PORT_B:
+               bit = SDE_PORTB_HOTPLUG;
+               break;
+       case HPD_PORT_C:
+               bit = SDE_PORTC_HOTPLUG;
+               break;
+       case HPD_PORT_D:
+               bit = SDE_PORTD_HOTPLUG;
+               break;
+       default:
+               MISSING_CASE(encoder->hpd_pin);
+               return false;
+       }
+
+       return I915_READ(SDEISR) & bit;
+}
+
+static bool cpt_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 bit;
+
+       switch (encoder->hpd_pin) {
+       case HPD_PORT_B:
+               bit = SDE_PORTB_HOTPLUG_CPT;
+               break;
+       case HPD_PORT_C:
+               bit = SDE_PORTC_HOTPLUG_CPT;
+               break;
+       case HPD_PORT_D:
+               bit = SDE_PORTD_HOTPLUG_CPT;
+               break;
+       default:
+               MISSING_CASE(encoder->hpd_pin);
+               return false;
+       }
+
+       return I915_READ(SDEISR) & bit;
+}
+
+static bool spt_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 bit;
+
+       switch (encoder->hpd_pin) {
+       case HPD_PORT_A:
+               bit = SDE_PORTA_HOTPLUG_SPT;
+               break;
+       case HPD_PORT_E:
+               bit = SDE_PORTE_HOTPLUG_SPT;
+               break;
+       default:
+               return cpt_digital_port_connected(encoder);
+       }
+
+       return I915_READ(SDEISR) & bit;
+}
+
+static bool g4x_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 bit;
+
+       switch (encoder->hpd_pin) {
+       case HPD_PORT_B:
+               bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
+               break;
+       case HPD_PORT_C:
+               bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
+               break;
+       case HPD_PORT_D:
+               bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
+               break;
+       default:
+               MISSING_CASE(encoder->hpd_pin);
+               return false;
+       }
+
+       return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
+static bool gm45_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 bit;
+
+       switch (encoder->hpd_pin) {
+       case HPD_PORT_B:
+               bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
+               break;
+       case HPD_PORT_C:
+               bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
+               break;
+       case HPD_PORT_D:
+               bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
+               break;
+       default:
+               MISSING_CASE(encoder->hpd_pin);
+               return false;
+       }
+
+       return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
+static bool ilk_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (encoder->hpd_pin == HPD_PORT_A)
+               return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
+       else
+               return ibx_digital_port_connected(encoder);
+}
+
+static bool snb_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (encoder->hpd_pin == HPD_PORT_A)
+               return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
+       else
+               return cpt_digital_port_connected(encoder);
+}
+
+static bool ivb_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (encoder->hpd_pin == HPD_PORT_A)
+               return I915_READ(DEISR) & DE_DP_A_HOTPLUG_IVB;
+       else
+               return cpt_digital_port_connected(encoder);
+}
+
+static bool bdw_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (encoder->hpd_pin == HPD_PORT_A)
+               return I915_READ(GEN8_DE_PORT_ISR) & GEN8_PORT_DP_A_HOTPLUG;
+       else
+               return cpt_digital_port_connected(encoder);
+}
+
+static bool bxt_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 bit;
+
+       switch (encoder->hpd_pin) {
+       case HPD_PORT_A:
+               bit = BXT_DE_PORT_HP_DDIA;
+               break;
+       case HPD_PORT_B:
+               bit = BXT_DE_PORT_HP_DDIB;
+               break;
+       case HPD_PORT_C:
+               bit = BXT_DE_PORT_HP_DDIC;
+               break;
+       default:
+               MISSING_CASE(encoder->hpd_pin);
+               return false;
+       }
+
+       return I915_READ(GEN8_DE_PORT_ISR) & bit;
+}
+
+static bool icl_combo_port_connected(struct drm_i915_private *dev_priv,
+                                    struct intel_digital_port *intel_dig_port)
+{
+       enum port port = intel_dig_port->base.port;
+
+       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);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+
+       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);
+       else
+               MISSING_CASE(encoder->hpd_pin);
+
+       return false;
+}
+
+/*
+ * intel_digital_port_connected - is the specified port connected?
+ * @encoder: intel_encoder
+ *
+ * In cases where there's a connector physically connected but it can't be used
+ * by our hardware we also return false, since the rest of the driver should
+ * pretty much treat the port as disconnected. This is relevant for type-C
+ * (starting on ICL) where there's ownership involved.
+ *
+ * Return %true if port is connected, %false otherwise.
+ */
+static bool __intel_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (HAS_GMCH(dev_priv)) {
+               if (IS_GM45(dev_priv))
+                       return gm45_digital_port_connected(encoder);
+               else
+                       return g4x_digital_port_connected(encoder);
+       }
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               return icl_digital_port_connected(encoder);
+       else if (IS_GEN(dev_priv, 10) || IS_GEN9_BC(dev_priv))
+               return spt_digital_port_connected(encoder);
+       else if (IS_GEN9_LP(dev_priv))
+               return bxt_digital_port_connected(encoder);
+       else if (IS_GEN(dev_priv, 8))
+               return bdw_digital_port_connected(encoder);
+       else if (IS_GEN(dev_priv, 7))
+               return ivb_digital_port_connected(encoder);
+       else if (IS_GEN(dev_priv, 6))
+               return snb_digital_port_connected(encoder);
+       else if (IS_GEN(dev_priv, 5))
+               return ilk_digital_port_connected(encoder);
+
+       MISSING_CASE(INTEL_GEN(dev_priv));
+       return false;
+}
+
+bool intel_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       bool is_connected = false;
+       intel_wakeref_t wakeref;
+
+       with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref)
+               is_connected = __intel_digital_port_connected(encoder);
+
+       return is_connected;
+}
+
+static struct edid *
+intel_dp_get_edid(struct intel_dp *intel_dp)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+
+       /* use cached edid if we have one */
+       if (intel_connector->edid) {
+               /* invalid edid */
+               if (IS_ERR(intel_connector->edid))
+                       return NULL;
+
+               return drm_edid_duplicate(intel_connector->edid);
+       } else
+               return drm_get_edid(&intel_connector->base,
+                                   &intel_dp->aux.ddc);
+}
+
+static void
+intel_dp_set_edid(struct intel_dp *intel_dp)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       struct edid *edid;
+
+       intel_dp_unset_edid(intel_dp);
+       edid = intel_dp_get_edid(intel_dp);
+       intel_connector->detect_edid = edid;
+
+       intel_dp->has_audio = drm_detect_monitor_audio(edid);
+       drm_dp_cec_set_edid(&intel_dp->aux, edid);
+}
+
+static void
+intel_dp_unset_edid(struct intel_dp *intel_dp)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+
+       drm_dp_cec_unset_edid(&intel_dp->aux);
+       kfree(intel_connector->detect_edid);
+       intel_connector->detect_edid = NULL;
+
+       intel_dp->has_audio = false;
+}
+
+static int
+intel_dp_detect(struct drm_connector *connector,
+               struct drm_modeset_acquire_ctx *ctx,
+               bool force)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &dig_port->base;
+       enum drm_connector_status status;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+       WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
+
+       /* Can't disconnect eDP */
+       if (intel_dp_is_edp(intel_dp))
+               status = edp_detect(intel_dp);
+       else if (intel_digital_port_connected(encoder))
+               status = intel_dp_detect_dpcd(intel_dp);
+       else
+               status = connector_status_disconnected;
+
+       if (status == connector_status_disconnected) {
+               memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
+               memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
+
+               if (intel_dp->is_mst) {
+                       DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
+                                     intel_dp->is_mst,
+                                     intel_dp->mst_mgr.mst_state);
+                       intel_dp->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                                       intel_dp->is_mst);
+               }
+
+               goto out;
+       }
+
+       if (intel_dp->reset_link_params) {
+               /* Initial max link lane count */
+               intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
+
+               /* Initial max link rate */
+               intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
+
+               intel_dp->reset_link_params = false;
+       }
+
+       intel_dp_print_rates(intel_dp);
+
+       /* Read DP Sink DSC Cap DPCD regs for DP v1.4 */
+       if (INTEL_GEN(dev_priv) >= 11)
+               intel_dp_get_dsc_sink_cap(intel_dp);
+
+       drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
+                        drm_dp_is_branch(intel_dp->dpcd));
+
+       intel_dp_configure_mst(intel_dp);
+
+       if (intel_dp->is_mst) {
+               /*
+                * If we are in MST mode then this connector
+                * won't appear connected or have anything
+                * with EDID on it
+                */
+               status = connector_status_disconnected;
+               goto out;
+       }
+
+       /*
+        * Some external monitors do not signal loss of link synchronization
+        * with an IRQ_HPD, so force a link status check.
+        */
+       if (!intel_dp_is_edp(intel_dp)) {
+               int ret;
+
+               ret = intel_dp_retrain_link(encoder, ctx);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Clearing NACK and defer counts to get their exact values
+        * while reading EDID which are required by Compliance tests
+        * 4.2.2.4 and 4.2.2.5
+        */
+       intel_dp->aux.i2c_nack_count = 0;
+       intel_dp->aux.i2c_defer_count = 0;
+
+       intel_dp_set_edid(intel_dp);
+       if (intel_dp_is_edp(intel_dp) ||
+           to_intel_connector(connector)->detect_edid)
+               status = connector_status_connected;
+
+       intel_dp_check_service_irq(intel_dp);
+
+out:
+       if (status != connector_status_connected && !intel_dp->is_mst)
+               intel_dp_unset_edid(intel_dp);
+
+       return status;
+}
+
+static void
+intel_dp_force(struct drm_connector *connector)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &dig_port->base;
+       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
+       enum intel_display_power_domain aux_domain =
+               intel_aux_power_domain(dig_port);
+       intel_wakeref_t wakeref;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+       intel_dp_unset_edid(intel_dp);
+
+       if (connector->status != connector_status_connected)
+               return;
+
+       wakeref = intel_display_power_get(dev_priv, aux_domain);
+
+       intel_dp_set_edid(intel_dp);
+
+       intel_display_power_put(dev_priv, aux_domain, wakeref);
+}
+
+static int intel_dp_get_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct edid *edid;
+
+       edid = intel_connector->detect_edid;
+       if (edid) {
+               int ret = intel_connector_update_modes(connector, edid);
+               if (ret)
+                       return ret;
+       }
+
+       /* if eDP has no EDID, fall back to fixed mode */
+       if (intel_dp_is_edp(intel_attached_dp(connector)) &&
+           intel_connector->panel.fixed_mode) {
+               struct drm_display_mode *mode;
+
+               mode = drm_mode_duplicate(connector->dev,
+                                         intel_connector->panel.fixed_mode);
+               if (mode) {
+                       drm_mode_probed_add(connector, mode);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int
+intel_dp_connector_register(struct drm_connector *connector)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct drm_device *dev = connector->dev;
+       int ret;
+
+       ret = intel_connector_register(connector);
+       if (ret)
+               return ret;
+
+       i915_debugfs_connector_add(connector);
+
+       DRM_DEBUG_KMS("registering %s bus for %s\n",
+                     intel_dp->aux.name, connector->kdev->kobj.name);
+
+       intel_dp->aux.dev = connector->kdev;
+       ret = drm_dp_aux_register(&intel_dp->aux);
+       if (!ret)
+               drm_dp_cec_register_connector(&intel_dp->aux,
+                                             connector->name, dev->dev);
+       return ret;
+}
+
+static void
+intel_dp_connector_unregister(struct drm_connector *connector)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+
+       drm_dp_cec_unregister_connector(&intel_dp->aux);
+       drm_dp_aux_unregister(&intel_dp->aux);
+       intel_connector_unregister(connector);
+}
+
+void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
+{
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       intel_dp_mst_encoder_cleanup(intel_dig_port);
+       if (intel_dp_is_edp(intel_dp)) {
+               intel_wakeref_t wakeref;
+
+               cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               /*
+                * vdd might still be enabled do to the delayed vdd off.
+                * Make sure vdd is actually turned off here.
+                */
+               with_pps_lock(intel_dp, wakeref)
+                       edp_panel_vdd_off_sync(intel_dp);
+
+               if (intel_dp->edp_notifier.notifier_call) {
+                       unregister_reboot_notifier(&intel_dp->edp_notifier);
+                       intel_dp->edp_notifier.notifier_call = NULL;
+               }
+       }
+
+       intel_dp_aux_fini(intel_dp);
+}
+
+static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+{
+       intel_dp_encoder_flush_work(encoder);
+
+       drm_encoder_cleanup(encoder);
+       kfree(enc_to_dig_port(encoder));
+}
+
+void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
+       intel_wakeref_t wakeref;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return;
+
+       /*
+        * vdd might still be enabled do to the delayed vdd off.
+        * Make sure vdd is actually turned off here.
+        */
+       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+       with_pps_lock(intel_dp, wakeref)
+               edp_panel_vdd_off_sync(intel_dp);
+}
+
+static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
+{
+       long ret;
+
+#define C (hdcp->cp_irq_count_cached != atomic_read(&hdcp->cp_irq_count))
+       ret = wait_event_interruptible_timeout(hdcp->cp_irq_queue, C,
+                                              msecs_to_jiffies(timeout));
+
+       if (!ret)
+               DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
+}
+
+static
+int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
+                               u8 *an)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_dig_port->base.base);
+       static const struct drm_dp_aux_msg msg = {
+               .request = DP_AUX_NATIVE_WRITE,
+               .address = DP_AUX_HDCP_AKSV,
+               .size = DRM_HDCP_KSV_LEN,
+       };
+       u8 txbuf[HEADER_SIZE + DRM_HDCP_KSV_LEN] = {}, rxbuf[2], reply = 0;
+       ssize_t dpcd_ret;
+       int ret;
+
+       /* Output An first, that's easy */
+       dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AN,
+                                    an, DRM_HDCP_AN_LEN);
+       if (dpcd_ret != DRM_HDCP_AN_LEN) {
+               DRM_DEBUG_KMS("Failed to write An over DP/AUX (%zd)\n",
+                             dpcd_ret);
+               return dpcd_ret >= 0 ? -EIO : dpcd_ret;
+       }
+
+       /*
+        * Since Aksv is Oh-So-Secret, we can't access it in software. So in
+        * order to get it on the wire, we need to create the AUX header as if
+        * we were writing the data, and then tickle the hardware to output the
+        * data once the header is sent out.
+        */
+       intel_dp_aux_header(txbuf, &msg);
+
+       ret = intel_dp_aux_xfer(intel_dp, txbuf, HEADER_SIZE + msg.size,
+                               rxbuf, sizeof(rxbuf),
+                               DP_AUX_CH_CTL_AUX_AKSV_SELECT);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("Write Aksv over DP/AUX failed (%d)\n", ret);
+               return ret;
+       } else if (ret == 0) {
+               DRM_DEBUG_KMS("Aksv write over DP/AUX was empty\n");
+               return -EIO;
+       }
+
+       reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK;
+       if (reply != DP_AUX_NATIVE_REPLY_ACK) {
+               DRM_DEBUG_KMS("Aksv write: no DP_AUX_NATIVE_REPLY_ACK %x\n",
+                             reply);
+               return -EIO;
+       }
+       return 0;
+}
+
+static int intel_dp_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
+                                  u8 *bksv)
+{
+       ssize_t ret;
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
+                              DRM_HDCP_KSV_LEN);
+       if (ret != DRM_HDCP_KSV_LEN) {
+               DRM_DEBUG_KMS("Read Bksv from DP/AUX failed (%zd)\n", ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+       return 0;
+}
+
+static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
+                                     u8 *bstatus)
+{
+       ssize_t ret;
+       /*
+        * For some reason the HDMI and DP HDCP specs call this register
+        * definition by different names. In the HDMI spec, it's called BSTATUS,
+        * but in DP it's called BINFO.
+        */
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BINFO,
+                              bstatus, DRM_HDCP_BSTATUS_LEN);
+       if (ret != DRM_HDCP_BSTATUS_LEN) {
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+       return 0;
+}
+
+static
+int intel_dp_hdcp_read_bcaps(struct intel_digital_port *intel_dig_port,
+                            u8 *bcaps)
+{
+       ssize_t ret;
+
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
+                              bcaps, 1);
+       if (ret != 1) {
+               DRM_DEBUG_KMS("Read bcaps from DP/AUX failed (%zd)\n", ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+
+       return 0;
+}
+
+static
+int intel_dp_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
+                                  bool *repeater_present)
+{
+       ssize_t ret;
+       u8 bcaps;
+
+       ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
+       if (ret)
+               return ret;
+
+       *repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
+       return 0;
+}
+
+static
+int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
+                               u8 *ri_prime)
+{
+       ssize_t ret;
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
+                              ri_prime, DRM_HDCP_RI_LEN);
+       if (ret != DRM_HDCP_RI_LEN) {
+               DRM_DEBUG_KMS("Read Ri' from DP/AUX failed (%zd)\n", ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+       return 0;
+}
+
+static
+int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
+                                bool *ksv_ready)
+{
+       ssize_t ret;
+       u8 bstatus;
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
+                              &bstatus, 1);
+       if (ret != 1) {
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+       *ksv_ready = bstatus & DP_BSTATUS_READY;
+       return 0;
+}
+
+static
+int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
+                               int num_downstream, u8 *ksv_fifo)
+{
+       ssize_t ret;
+       int i;
+
+       /* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
+       for (i = 0; i < num_downstream; i += 3) {
+               size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
+               ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+                                      DP_AUX_HDCP_KSV_FIFO,
+                                      ksv_fifo + i * DRM_HDCP_KSV_LEN,
+                                      len);
+               if (ret != len) {
+                       DRM_DEBUG_KMS("Read ksv[%d] from DP/AUX failed (%zd)\n",
+                                     i, ret);
+                       return ret >= 0 ? -EIO : ret;
+               }
+       }
+       return 0;
+}
+
+static
+int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
+                                   int i, u32 *part)
+{
+       ssize_t ret;
+
+       if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
+               return -EINVAL;
+
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+                              DP_AUX_HDCP_V_PRIME(i), part,
+                              DRM_HDCP_V_PRIME_PART_LEN);
+       if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
+               DRM_DEBUG_KMS("Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+       return 0;
+}
+
+static
+int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
+                                   bool enable)
+{
+       /* Not used for single stream DisplayPort setups */
+       return 0;
+}
+
+static
+bool intel_dp_hdcp_check_link(struct intel_digital_port *intel_dig_port)
+{
+       ssize_t ret;
+       u8 bstatus;
+
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
+                              &bstatus, 1);
+       if (ret != 1) {
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               return false;
+       }
+
+       return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
+}
+
+static
+int intel_dp_hdcp_capable(struct intel_digital_port *intel_dig_port,
+                         bool *hdcp_capable)
+{
+       ssize_t ret;
+       u8 bcaps;
+
+       ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
+       if (ret)
+               return ret;
+
+       *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
+       return 0;
+}
+
+struct hdcp2_dp_errata_stream_type {
+       u8      msg_id;
+       u8      stream_type;
+} __packed;
+
+static struct hdcp2_dp_msg_data {
+       u8 msg_id;
+       u32 offset;
+       bool msg_detectable;
+       u32 timeout;
+       u32 timeout2; /* Added for non_paired situation */
+       } hdcp2_msg_data[] = {
+               {HDCP_2_2_AKE_INIT, DP_HDCP_2_2_AKE_INIT_OFFSET, false, 0, 0},
+               {HDCP_2_2_AKE_SEND_CERT, DP_HDCP_2_2_AKE_SEND_CERT_OFFSET,
+                               false, HDCP_2_2_CERT_TIMEOUT_MS, 0},
+               {HDCP_2_2_AKE_NO_STORED_KM, DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET,
+                               false, 0, 0},
+               {HDCP_2_2_AKE_STORED_KM, DP_HDCP_2_2_AKE_STORED_KM_OFFSET,
+                               false, 0, 0},
+               {HDCP_2_2_AKE_SEND_HPRIME, DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET,
+                               true, HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS,
+                               HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS},
+               {HDCP_2_2_AKE_SEND_PAIRING_INFO,
+                               DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET, true,
+                               HDCP_2_2_PAIRING_TIMEOUT_MS, 0},
+               {HDCP_2_2_LC_INIT, DP_HDCP_2_2_LC_INIT_OFFSET, false, 0, 0},
+               {HDCP_2_2_LC_SEND_LPRIME, DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET,
+                               false, HDCP_2_2_DP_LPRIME_TIMEOUT_MS, 0},
+               {HDCP_2_2_SKE_SEND_EKS, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET, false,
+                               0, 0},
+               {HDCP_2_2_REP_SEND_RECVID_LIST,
+                               DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET, true,
+                               HDCP_2_2_RECVID_LIST_TIMEOUT_MS, 0},
+               {HDCP_2_2_REP_SEND_ACK, DP_HDCP_2_2_REP_SEND_ACK_OFFSET, false,
+                               0, 0},
+               {HDCP_2_2_REP_STREAM_MANAGE,
+                               DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET, false,
+                               0, 0},
+               {HDCP_2_2_REP_STREAM_READY, DP_HDCP_2_2_REP_STREAM_READY_OFFSET,
+                               false, HDCP_2_2_STREAM_READY_TIMEOUT_MS, 0},
+/* local define to shovel this through the write_2_2 interface */
+#define HDCP_2_2_ERRATA_DP_STREAM_TYPE 50
+               {HDCP_2_2_ERRATA_DP_STREAM_TYPE,
+                               DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET, false,
+                               0, 0},
+               };
+
+static inline
+int intel_dp_hdcp2_read_rx_status(struct intel_digital_port *intel_dig_port,
+                                 u8 *rx_status)
+{
+       ssize_t ret;
+
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+                              DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status,
+                              HDCP_2_2_DP_RXSTATUS_LEN);
+       if (ret != HDCP_2_2_DP_RXSTATUS_LEN) {
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               return ret >= 0 ? -EIO : ret;
+       }
+
+       return 0;
+}
+
+static
+int hdcp2_detect_msg_availability(struct intel_digital_port *intel_dig_port,
+                                 u8 msg_id, bool *msg_ready)
+{
+       u8 rx_status;
+       int ret;
+
+       *msg_ready = false;
+       ret = intel_dp_hdcp2_read_rx_status(intel_dig_port, &rx_status);
+       if (ret < 0)
+               return ret;
+
+       switch (msg_id) {
+       case HDCP_2_2_AKE_SEND_HPRIME:
+               if (HDCP_2_2_DP_RXSTATUS_H_PRIME(rx_status))
+                       *msg_ready = true;
+               break;
+       case HDCP_2_2_AKE_SEND_PAIRING_INFO:
+               if (HDCP_2_2_DP_RXSTATUS_PAIRING(rx_status))
+                       *msg_ready = true;
+               break;
+       case HDCP_2_2_REP_SEND_RECVID_LIST:
+               if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
+                       *msg_ready = true;
+               break;
+       default:
+               DRM_ERROR("Unidentified msg_id: %d\n", msg_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static ssize_t
+intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port,
+                           struct hdcp2_dp_msg_data *hdcp2_msg_data)
+{
+       struct intel_dp *dp = &intel_dig_port->dp;
+       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
+       u8 msg_id = hdcp2_msg_data->msg_id;
+       int ret, timeout;
+       bool msg_ready = false;
+
+       if (msg_id == HDCP_2_2_AKE_SEND_HPRIME && !hdcp->is_paired)
+               timeout = hdcp2_msg_data->timeout2;
+       else
+               timeout = hdcp2_msg_data->timeout;
+
+       /*
+        * There is no way to detect the CERT, LPRIME and STREAM_READY
+        * availability. So Wait for timeout and read the msg.
+        */
+       if (!hdcp2_msg_data->msg_detectable) {
+               mdelay(timeout);
+               ret = 0;
+       } else {
+               /*
+                * As we want to check the msg availability at timeout, Ignoring
+                * the timeout at wait for CP_IRQ.
+                */
+               intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout);
+               ret = hdcp2_detect_msg_availability(intel_dig_port,
+                                                   msg_id, &msg_ready);
+               if (!msg_ready)
+                       ret = -ETIMEDOUT;
+       }
+
+       if (ret)
+               DRM_DEBUG_KMS("msg_id %d, ret %d, timeout(mSec): %d\n",
+                             hdcp2_msg_data->msg_id, ret, timeout);
+
+       return ret;
+}
+
+static struct hdcp2_dp_msg_data *get_hdcp2_dp_msg_data(u8 msg_id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hdcp2_msg_data); i++)
+               if (hdcp2_msg_data[i].msg_id == msg_id)
+                       return &hdcp2_msg_data[i];
+
+       return NULL;
+}
+
+static
+int intel_dp_hdcp2_write_msg(struct intel_digital_port *intel_dig_port,
+                            void *buf, size_t size)
+{
+       struct intel_dp *dp = &intel_dig_port->dp;
+       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
+       unsigned int offset;
+       u8 *byte = buf;
+       ssize_t ret, bytes_to_write, len;
+       struct hdcp2_dp_msg_data *hdcp2_msg_data;
+
+       hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte);
+       if (!hdcp2_msg_data)
+               return -EINVAL;
+
+       offset = hdcp2_msg_data->offset;
+
+       /* No msg_id in DP HDCP2.2 msgs */
+       bytes_to_write = size - 1;
+       byte++;
+
+       hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count);
+
+       while (bytes_to_write) {
+               len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ?
+                               DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write;
+
+               ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux,
+                                       offset, (void *)byte, len);
+               if (ret < 0)
+                       return ret;
+
+               bytes_to_write -= ret;
+               byte += ret;
+               offset += ret;
+       }
+
+       return size;
+}
+
+static
+ssize_t get_receiver_id_list_size(struct intel_digital_port *intel_dig_port)
+{
+       u8 rx_info[HDCP_2_2_RXINFO_LEN];
+       u32 dev_cnt;
+       ssize_t ret;
+
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+                              DP_HDCP_2_2_REG_RXINFO_OFFSET,
+                              (void *)rx_info, HDCP_2_2_RXINFO_LEN);
+       if (ret != HDCP_2_2_RXINFO_LEN)
+               return ret >= 0 ? -EIO : ret;
+
+       dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
+                  HDCP_2_2_DEV_COUNT_LO(rx_info[1]));
+
+       if (dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
+               dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
+
+       ret = sizeof(struct hdcp2_rep_send_receiverid_list) -
+               HDCP_2_2_RECEIVER_IDS_MAX_LEN +
+               (dev_cnt * HDCP_2_2_RECEIVER_ID_LEN);
+
+       return ret;
+}
+
+static
+int intel_dp_hdcp2_read_msg(struct intel_digital_port *intel_dig_port,
+                           u8 msg_id, void *buf, size_t size)
+{
+       unsigned int offset;
+       u8 *byte = buf;
+       ssize_t ret, bytes_to_recv, len;
+       struct hdcp2_dp_msg_data *hdcp2_msg_data;
+
+       hdcp2_msg_data = get_hdcp2_dp_msg_data(msg_id);
+       if (!hdcp2_msg_data)
+               return -EINVAL;
+       offset = hdcp2_msg_data->offset;
+
+       ret = intel_dp_hdcp2_wait_for_msg(intel_dig_port, hdcp2_msg_data);
+       if (ret < 0)
+               return ret;
+
+       if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) {
+               ret = get_receiver_id_list_size(intel_dig_port);
+               if (ret < 0)
+                       return ret;
+
+               size = ret;
+       }
+       bytes_to_recv = size - 1;
+
+       /* DP adaptation msgs has no msg_id */
+       byte++;
+
+       while (bytes_to_recv) {
+               len = bytes_to_recv > DP_AUX_MAX_PAYLOAD_BYTES ?
+                     DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv;
+
+               ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, offset,
+                                      (void *)byte, len);
+               if (ret < 0) {
+                       DRM_DEBUG_KMS("msg_id %d, ret %zd\n", msg_id, ret);
+                       return ret;
+               }
+
+               bytes_to_recv -= ret;
+               byte += ret;
+               offset += ret;
+       }
+       byte = buf;
+       *byte = msg_id;
+
+       return size;
+}
+
+static
+int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *intel_dig_port,
+                                     bool is_repeater, u8 content_type)
+{
+       struct hdcp2_dp_errata_stream_type stream_type_msg;
+
+       if (is_repeater)
+               return 0;
+
+       /*
+        * Errata for DP: As Stream type is used for encryption, Receiver
+        * should be communicated with stream type for the decryption of the
+        * content.
+        * Repeater will be communicated with stream type as a part of it's
+        * auth later in time.
+        */
+       stream_type_msg.msg_id = HDCP_2_2_ERRATA_DP_STREAM_TYPE;
+       stream_type_msg.stream_type = content_type;
+
+       return intel_dp_hdcp2_write_msg(intel_dig_port, &stream_type_msg,
+                                       sizeof(stream_type_msg));
+}
+
+static
+int intel_dp_hdcp2_check_link(struct intel_digital_port *intel_dig_port)
+{
+       u8 rx_status;
+       int ret;
+
+       ret = intel_dp_hdcp2_read_rx_status(intel_dig_port, &rx_status);
+       if (ret)
+               return ret;
+
+       if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rx_status))
+               ret = HDCP_REAUTH_REQUEST;
+       else if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rx_status))
+               ret = HDCP_LINK_INTEGRITY_FAILURE;
+       else if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
+               ret = HDCP_TOPOLOGY_CHANGE;
+
+       return ret;
+}
+
+static
+int intel_dp_hdcp2_capable(struct intel_digital_port *intel_dig_port,
+                          bool *capable)
+{
+       u8 rx_caps[3];
+       int ret;
+
+       *capable = false;
+       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+                              DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
+                              rx_caps, HDCP_2_2_RXCAPS_LEN);
+       if (ret != HDCP_2_2_RXCAPS_LEN)
+               return ret >= 0 ? -EIO : ret;
+
+       if (rx_caps[0] == HDCP_2_2_RX_CAPS_VERSION_VAL &&
+           HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2]))
+               *capable = true;
+
+       return 0;
+}
+
+static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
+       .write_an_aksv = intel_dp_hdcp_write_an_aksv,
+       .read_bksv = intel_dp_hdcp_read_bksv,
+       .read_bstatus = intel_dp_hdcp_read_bstatus,
+       .repeater_present = intel_dp_hdcp_repeater_present,
+       .read_ri_prime = intel_dp_hdcp_read_ri_prime,
+       .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
+       .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
+       .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
+       .toggle_signalling = intel_dp_hdcp_toggle_signalling,
+       .check_link = intel_dp_hdcp_check_link,
+       .hdcp_capable = intel_dp_hdcp_capable,
+       .write_2_2_msg = intel_dp_hdcp2_write_msg,
+       .read_2_2_msg = intel_dp_hdcp2_read_msg,
+       .config_stream_type = intel_dp_hdcp2_config_stream_type,
+       .check_2_2_link = intel_dp_hdcp2_check_link,
+       .hdcp_2_2_capable = intel_dp_hdcp2_capable,
+       .protocol = HDCP_PROTOCOL_DP,
+};
+
+static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (!edp_have_panel_vdd(intel_dp))
+               return;
+
+       /*
+        * The VDD bit needs a power domain reference, so if the bit is
+        * already enabled when we boot or resume, grab this reference and
+        * schedule a vdd off, so we don't hold on to the reference
+        * indefinitely.
+        */
+       DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
+       intel_display_power_get(dev_priv, intel_aux_power_domain(dig_port));
+
+       edp_panel_vdd_schedule_off(intel_dp);
+}
+
+static enum pipe vlv_active_pipe(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+       enum pipe pipe;
+
+       if (intel_dp_port_enabled(dev_priv, intel_dp->output_reg,
+                                 encoder->port, &pipe))
+               return pipe;
+
+       return INVALID_PIPE;
+}
+
+void intel_dp_encoder_reset(struct drm_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+       intel_wakeref_t wakeref;
+
+       if (!HAS_DDI(dev_priv))
+               intel_dp->DP = I915_READ(intel_dp->output_reg);
+
+       if (lspcon->active)
+               lspcon_resume(lspcon);
+
+       intel_dp->reset_link_params = true;
+
+       if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
+           !intel_dp_is_edp(intel_dp))
+               return;
+
+       with_pps_lock(intel_dp, wakeref) {
+               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                       intel_dp->active_pipe = vlv_active_pipe(intel_dp);
+
+               if (intel_dp_is_edp(intel_dp)) {
+                       /*
+                        * Reinit the power sequencer, in case BIOS did
+                        * something nasty with it.
+                        */
+                       intel_dp_pps_init(intel_dp);
+                       intel_edp_panel_vdd_sanitize(intel_dp);
+               }
+       }
+}
+
+static const struct drm_connector_funcs intel_dp_connector_funcs = {
+       .force = intel_dp_force,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .late_register = intel_dp_connector_register,
+       .early_unregister = intel_dp_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
+       .detect_ctx = intel_dp_detect,
+       .get_modes = intel_dp_get_modes,
+       .mode_valid = intel_dp_mode_valid,
+       .atomic_check = intel_digital_connector_atomic_check,
+};
+
+static const struct drm_encoder_funcs intel_dp_enc_funcs = {
+       .reset = intel_dp_encoder_reset,
+       .destroy = intel_dp_encoder_destroy,
+};
+
+enum irqreturn
+intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
+{
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
+               /*
+                * vdd off can generate a long pulse on eDP which
+                * would require vdd on to handle it, and thus we
+                * would end up in an endless cycle of
+                * "vdd off -> long hpd -> vdd on -> detect -> vdd off -> ..."
+                */
+               DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
+                             port_name(intel_dig_port->base.port));
+               return IRQ_HANDLED;
+       }
+
+       DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
+                     port_name(intel_dig_port->base.port),
+                     long_hpd ? "long" : "short");
+
+       if (long_hpd) {
+               intel_dp->reset_link_params = true;
+               return IRQ_NONE;
+       }
+
+       if (intel_dp->is_mst) {
+               if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
+                       /*
+                        * If we were in MST mode, and device is not
+                        * there, get out of MST mode
+                        */
+                       DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
+                                     intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
+                       intel_dp->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                                       intel_dp->is_mst);
+
+                       return IRQ_NONE;
+               }
+       }
+
+       if (!intel_dp->is_mst) {
+               bool handled;
+
+               handled = intel_dp_short_pulse(intel_dp);
+
+               if (!handled)
+                       return IRQ_NONE;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* check the VBT to see whether the eDP is on another port */
+bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
+{
+       /*
+        * eDP not supported on g4x. so bail out early just
+        * for a bit extra safety in case the VBT is bonkers.
+        */
+       if (INTEL_GEN(dev_priv) < 5)
+               return false;
+
+       if (INTEL_GEN(dev_priv) < 9 && port == PORT_A)
+               return true;
+
+       return intel_bios_is_port_edp(dev_priv, port);
+}
+
+static void
+intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       enum port port = dp_to_dig_port(intel_dp)->base.port;
+
+       if (!IS_G4X(dev_priv) && port != PORT_A)
+               intel_attach_force_audio_property(connector);
+
+       intel_attach_broadcast_rgb_property(connector);
+       if (HAS_GMCH(dev_priv))
+               drm_connector_attach_max_bpc_property(connector, 6, 10);
+       else if (INTEL_GEN(dev_priv) >= 5)
+               drm_connector_attach_max_bpc_property(connector, 6, 12);
+
+       if (intel_dp_is_edp(intel_dp)) {
+               u32 allowed_scalers;
+
+               allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
+               if (!HAS_GMCH(dev_priv))
+                       allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
+
+               drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
+
+               connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+
+       }
+}
+
+static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp)
+{
+       intel_dp->panel_power_off_time = ktime_get_boottime();
+       intel_dp->last_power_on = jiffies;
+       intel_dp->last_backlight_off = jiffies;
+}
+
+static void
+intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       u32 pp_on, pp_off, pp_ctl;
+       struct pps_registers regs;
+
+       intel_pps_get_registers(intel_dp, &regs);
+
+       pp_ctl = ironlake_get_pp_control(intel_dp);
+
+       /* Ensure PPS is unlocked */
+       if (!HAS_DDI(dev_priv))
+               I915_WRITE(regs.pp_ctrl, pp_ctl);
+
+       pp_on = I915_READ(regs.pp_on);
+       pp_off = I915_READ(regs.pp_off);
+
+       /* Pull timing values out of registers */
+       seq->t1_t3 = REG_FIELD_GET(PANEL_POWER_UP_DELAY_MASK, pp_on);
+       seq->t8 = REG_FIELD_GET(PANEL_LIGHT_ON_DELAY_MASK, pp_on);
+       seq->t9 = REG_FIELD_GET(PANEL_LIGHT_OFF_DELAY_MASK, pp_off);
+       seq->t10 = REG_FIELD_GET(PANEL_POWER_DOWN_DELAY_MASK, pp_off);
+
+       if (i915_mmio_reg_valid(regs.pp_div)) {
+               u32 pp_div;
+
+               pp_div = I915_READ(regs.pp_div);
+
+               seq->t11_t12 = REG_FIELD_GET(PANEL_POWER_CYCLE_DELAY_MASK, pp_div) * 1000;
+       } else {
+               seq->t11_t12 = REG_FIELD_GET(BXT_POWER_CYCLE_DELAY_MASK, pp_ctl) * 1000;
+       }
+}
+
+static void
+intel_pps_dump_state(const char *state_name, const struct edp_power_seq *seq)
+{
+       DRM_DEBUG_KMS("%s t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
+                     state_name,
+                     seq->t1_t3, seq->t8, seq->t9, seq->t10, seq->t11_t12);
+}
+
+static void
+intel_pps_verify_state(struct intel_dp *intel_dp)
+{
+       struct edp_power_seq hw;
+       struct edp_power_seq *sw = &intel_dp->pps_delays;
+
+       intel_pps_readout_hw_state(intel_dp, &hw);
+
+       if (hw.t1_t3 != sw->t1_t3 || hw.t8 != sw->t8 || hw.t9 != sw->t9 ||
+           hw.t10 != sw->t10 || hw.t11_t12 != sw->t11_t12) {
+               DRM_ERROR("PPS state mismatch\n");
+               intel_pps_dump_state("sw", sw);
+               intel_pps_dump_state("hw", &hw);
+       }
+}
+
+static void
+intel_dp_init_panel_power_sequencer(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct edp_power_seq cur, vbt, spec,
+               *final = &intel_dp->pps_delays;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       /* already initialized? */
+       if (final->t11_t12 != 0)
+               return;
+
+       intel_pps_readout_hw_state(intel_dp, &cur);
+
+       intel_pps_dump_state("cur", &cur);
+
+       vbt = dev_priv->vbt.edp.pps;
+       /* On Toshiba Satellite P50-C-18C system the VBT T12 delay
+        * of 500ms appears to be too short. Ocassionally the panel
+        * just fails to power back on. Increasing the delay to 800ms
+        * seems sufficient to avoid this problem.
+        */
+       if (dev_priv->quirks & QUIRK_INCREASE_T12_DELAY) {
+               vbt.t11_t12 = max_t(u16, vbt.t11_t12, 1300 * 10);
+               DRM_DEBUG_KMS("Increasing T12 panel delay as per the quirk to %d\n",
+                             vbt.t11_t12);
+       }
+       /* T11_T12 delay is special and actually in units of 100ms, but zero
+        * based in the hw (so we need to add 100 ms). But the sw vbt
+        * table multiplies it with 1000 to make it in units of 100usec,
+        * too. */
+       vbt.t11_t12 += 100 * 10;
+
+       /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of
+        * our hw here, which are all in 100usec. */
+       spec.t1_t3 = 210 * 10;
+       spec.t8 = 50 * 10; /* no limit for t8, use t7 instead */
+       spec.t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */
+       spec.t10 = 500 * 10;
+       /* This one is special and actually in units of 100ms, but zero
+        * based in the hw (so we need to add 100 ms). But the sw vbt
+        * table multiplies it with 1000 to make it in units of 100usec,
+        * too. */
+       spec.t11_t12 = (510 + 100) * 10;
+
+       intel_pps_dump_state("vbt", &vbt);
+
+       /* Use the max of the register settings and vbt. If both are
+        * unset, fall back to the spec limits. */
+#define assign_final(field)    final->field = (max(cur.field, vbt.field) == 0 ? \
+                                      spec.field : \
+                                      max(cur.field, vbt.field))
+       assign_final(t1_t3);
+       assign_final(t8);
+       assign_final(t9);
+       assign_final(t10);
+       assign_final(t11_t12);
+#undef assign_final
+
+#define get_delay(field)       (DIV_ROUND_UP(final->field, 10))
+       intel_dp->panel_power_up_delay = get_delay(t1_t3);
+       intel_dp->backlight_on_delay = get_delay(t8);
+       intel_dp->backlight_off_delay = get_delay(t9);
+       intel_dp->panel_power_down_delay = get_delay(t10);
+       intel_dp->panel_power_cycle_delay = get_delay(t11_t12);
+#undef get_delay
+
+       DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
+                     intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
+                     intel_dp->panel_power_cycle_delay);
+
+       DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
+                     intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
+
+       /*
+        * We override the HW backlight delays to 1 because we do manual waits
+        * on them. For T8, even BSpec recommends doing it. For T9, if we
+        * don't do this, we'll end up waiting for the backlight off delay
+        * twice: once when we do the manual sleep, and once when we disable
+        * the panel and wait for the PP_STATUS bit to become zero.
+        */
+       final->t8 = 1;
+       final->t9 = 1;
+
+       /*
+        * HW has only a 100msec granularity for t11_t12 so round it up
+        * accordingly.
+        */
+       final->t11_t12 = roundup(final->t11_t12, 100 * 10);
+}
+
+static void
+intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
+                                             bool force_disable_vdd)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       u32 pp_on, pp_off, port_sel = 0;
+       int div = dev_priv->rawclk_freq / 1000;
+       struct pps_registers regs;
+       enum port port = dp_to_dig_port(intel_dp)->base.port;
+       const struct edp_power_seq *seq = &intel_dp->pps_delays;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       intel_pps_get_registers(intel_dp, &regs);
+
+       /*
+        * On some VLV machines the BIOS can leave the VDD
+        * enabled even on power sequencers which aren't
+        * hooked up to any port. This would mess up the
+        * power domain tracking the first time we pick
+        * one of these power sequencers for use since
+        * edp_panel_vdd_on() would notice that the VDD was
+        * already on and therefore wouldn't grab the power
+        * domain reference. Disable VDD first to avoid this.
+        * This also avoids spuriously turning the VDD on as
+        * soon as the new power sequencer gets initialized.
+        */
+       if (force_disable_vdd) {
+               u32 pp = ironlake_get_pp_control(intel_dp);
+
+               WARN(pp & PANEL_POWER_ON, "Panel power already on\n");
+
+               if (pp & EDP_FORCE_VDD)
+                       DRM_DEBUG_KMS("VDD already on, disabling first\n");
+
+               pp &= ~EDP_FORCE_VDD;
+
+               I915_WRITE(regs.pp_ctrl, pp);
+       }
+
+       pp_on = REG_FIELD_PREP(PANEL_POWER_UP_DELAY_MASK, seq->t1_t3) |
+               REG_FIELD_PREP(PANEL_LIGHT_ON_DELAY_MASK, seq->t8);
+       pp_off = REG_FIELD_PREP(PANEL_LIGHT_OFF_DELAY_MASK, seq->t9) |
+               REG_FIELD_PREP(PANEL_POWER_DOWN_DELAY_MASK, seq->t10);
+
+       /* Haswell doesn't have any port selection bits for the panel
+        * power sequencer any more. */
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               port_sel = PANEL_PORT_SELECT_VLV(port);
+       } else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) {
+               switch (port) {
+               case PORT_A:
+                       port_sel = PANEL_PORT_SELECT_DPA;
+                       break;
+               case PORT_C:
+                       port_sel = PANEL_PORT_SELECT_DPC;
+                       break;
+               case PORT_D:
+                       port_sel = PANEL_PORT_SELECT_DPD;
+                       break;
+               default:
+                       MISSING_CASE(port);
+                       break;
+               }
+       }
+
+       pp_on |= port_sel;
+
+       I915_WRITE(regs.pp_on, pp_on);
+       I915_WRITE(regs.pp_off, pp_off);
+
+       /*
+        * Compute the divisor for the pp clock, simply match the Bspec formula.
+        */
+       if (i915_mmio_reg_valid(regs.pp_div)) {
+               I915_WRITE(regs.pp_div,
+                          REG_FIELD_PREP(PP_REFERENCE_DIVIDER_MASK, (100 * div) / 2 - 1) |
+                          REG_FIELD_PREP(PANEL_POWER_CYCLE_DELAY_MASK, DIV_ROUND_UP(seq->t11_t12, 1000)));
+       } else {
+               u32 pp_ctl;
+
+               pp_ctl = I915_READ(regs.pp_ctrl);
+               pp_ctl &= ~BXT_POWER_CYCLE_DELAY_MASK;
+               pp_ctl |= REG_FIELD_PREP(BXT_POWER_CYCLE_DELAY_MASK, DIV_ROUND_UP(seq->t11_t12, 1000));
+               I915_WRITE(regs.pp_ctrl, pp_ctl);
+       }
+
+       DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
+                     I915_READ(regs.pp_on),
+                     I915_READ(regs.pp_off),
+                     i915_mmio_reg_valid(regs.pp_div) ?
+                     I915_READ(regs.pp_div) :
+                     (I915_READ(regs.pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK));
+}
+
+static void intel_dp_pps_init(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               vlv_initial_power_sequencer_setup(intel_dp);
+       } else {
+               intel_dp_init_panel_power_sequencer(intel_dp);
+               intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
+       }
+}
+
+/**
+ * intel_dp_set_drrs_state - program registers for RR switch to take effect
+ * @dev_priv: i915 device
+ * @crtc_state: a pointer to the active intel_crtc_state
+ * @refresh_rate: RR to be programmed
+ *
+ * This function gets called when refresh rate (RR) has to be changed from
+ * one frequency to another. Switches can be between high and low RR
+ * supported by the panel or to any other RR based on media playback (in
+ * this case, RR value needs to be passed from user space).
+ *
+ * The caller of this function needs to take a lock on dev_priv->drrs.
+ */
+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;
+
+       if (refresh_rate <= 0) {
+               DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
+               return;
+       }
+
+       if (intel_dp == NULL) {
+               DRM_DEBUG_KMS("DRRS not supported.\n");
+               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;
+       }
+
+       if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
+               DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
+               return;
+       }
+
+       if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
+                       refresh_rate)
+               index = DRRS_LOW_RR;
+
+       if (index == dev_priv->drrs.refresh_rate_type) {
+               DRM_DEBUG_KMS(
+                       "DRRS requested for previously set RR...ignoring\n");
+               return;
+       }
+
+       if (!crtc_state->base.active) {
+               DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
+               return;
+       }
+
+       if (INTEL_GEN(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
+               switch (index) {
+               case DRRS_HIGH_RR:
+                       intel_dp_set_m_n(crtc_state, M1_N1);
+                       break;
+               case DRRS_LOW_RR:
+                       intel_dp_set_m_n(crtc_state, M2_N2);
+                       break;
+               case DRRS_MAX_RR:
+               default:
+                       DRM_ERROR("Unsupported refreshrate type\n");
+               }
+       } else if (INTEL_GEN(dev_priv) > 6) {
+               i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
+               u32 val;
+
+               val = I915_READ(reg);
+               if (index > DRRS_HIGH_RR) {
+                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH;
+               } else {
+                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+               }
+               I915_WRITE(reg, val);
+       }
+
+       dev_priv->drrs.refresh_rate_type = index;
+
+       DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+}
+
+/**
+ * intel_edp_drrs_enable - init drrs struct if supported
+ * @intel_dp: DP struct
+ * @crtc_state: A pointer to the active crtc state.
+ *
+ * Initializes frontbuffer_bits and drrs.dp
+ */
+void intel_edp_drrs_enable(struct intel_dp *intel_dp,
+                          const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (!crtc_state->has_drrs) {
+               DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
+               return;
+       }
+
+       if (dev_priv->psr.enabled) {
+               DRM_DEBUG_KMS("PSR enabled. Not enabling DRRS.\n");
+               return;
+       }
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (dev_priv->drrs.dp) {
+               DRM_DEBUG_KMS("DRRS already enabled\n");
+               goto unlock;
+       }
+
+       dev_priv->drrs.busy_frontbuffer_bits = 0;
+
+       dev_priv->drrs.dp = intel_dp;
+
+unlock:
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_edp_drrs_disable - Disable DRRS
+ * @intel_dp: DP struct
+ * @old_crtc_state: Pointer to old crtc_state.
+ *
+ */
+void intel_edp_drrs_disable(struct intel_dp *intel_dp,
+                           const struct intel_crtc_state *old_crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (!old_crtc_state->has_drrs)
+               return;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (!dev_priv->drrs.dp) {
+               mutex_unlock(&dev_priv->drrs.mutex);
+               return;
+       }
+
+       if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+               intel_dp_set_drrs_state(dev_priv, old_crtc_state,
+                       intel_dp->attached_connector->panel.fixed_mode->vrefresh);
+
+       dev_priv->drrs.dp = NULL;
+       mutex_unlock(&dev_priv->drrs.mutex);
+
+       cancel_delayed_work_sync(&dev_priv->drrs.work);
+}
+
+static void intel_edp_drrs_downclock_work(struct work_struct *work)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(work, typeof(*dev_priv), drrs.work.work);
+       struct intel_dp *intel_dp;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+
+       intel_dp = dev_priv->drrs.dp;
+
+       if (!intel_dp)
+               goto unlock;
+
+       /*
+        * The delayed work can race with an invalidate hence we need to
+        * recheck.
+        */
+
+       if (dev_priv->drrs.busy_frontbuffer_bits)
+               goto unlock;
+
+       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) {
+               struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+
+               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
+                       intel_dp->attached_connector->panel.downclock_mode->vrefresh);
+       }
+
+unlock:
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_edp_drrs_invalidate - Disable Idleness DRRS
+ * @dev_priv: i915 device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * This function gets called everytime rendering on the given planes start.
+ * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
+                              unsigned int frontbuffer_bits)
+{
+       struct drm_crtc *crtc;
+       enum pipe pipe;
+
+       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
+               return;
+
+       cancel_delayed_work(&dev_priv->drrs.work);
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (!dev_priv->drrs.dp) {
+               mutex_unlock(&dev_priv->drrs.mutex);
+               return;
+       }
+
+       crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+       pipe = to_intel_crtc(crtc)->pipe;
+
+       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+       dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
+
+       /* invalidate means busy screen hence upclock */
+       if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
+                       dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
+
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_edp_drrs_flush - Restart Idleness DRRS
+ * @dev_priv: i915 device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * This function gets called every time rendering on the given planes has
+ * completed or flip on a crtc is completed. So DRRS should be upclocked
+ * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
+ * if no other planes are dirty.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
+                         unsigned int frontbuffer_bits)
+{
+       struct drm_crtc *crtc;
+       enum pipe pipe;
+
+       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
+               return;
+
+       cancel_delayed_work(&dev_priv->drrs.work);
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (!dev_priv->drrs.dp) {
+               mutex_unlock(&dev_priv->drrs.mutex);
+               return;
+       }
+
+       crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+       pipe = to_intel_crtc(crtc)->pipe;
+
+       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+       dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
+
+       /* flush means busy screen hence upclock */
+       if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
+                               dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
+
+       /*
+        * flush also means no more activity hence schedule downclock, if all
+        * other fbs are quiescent too
+        */
+       if (!dev_priv->drrs.busy_frontbuffer_bits)
+               schedule_delayed_work(&dev_priv->drrs.work,
+                               msecs_to_jiffies(1000));
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * DOC: Display Refresh Rate Switching (DRRS)
+ *
+ * Display Refresh Rate Switching (DRRS) is a power conservation feature
+ * which enables swtching between low and high refresh rates,
+ * dynamically, based on the usage scenario. This feature is applicable
+ * for internal panels.
+ *
+ * Indication that the panel supports DRRS is given by the panel EDID, which
+ * would list multiple refresh rates for one resolution.
+ *
+ * DRRS is of 2 types - static and seamless.
+ * Static DRRS involves changing refresh rate (RR) by doing a full modeset
+ * (may appear as a blink on screen) and is used in dock-undock scenario.
+ * Seamless DRRS involves changing RR without any visual effect to the user
+ * and can be used during normal system usage. This is done by programming
+ * certain registers.
+ *
+ * Support for static/seamless DRRS may be indicated in the VBT based on
+ * inputs from the panel spec.
+ *
+ * DRRS saves power by switching to low RR based on usage scenarios.
+ *
+ * The implementation is based on frontbuffer tracking implementation.  When
+ * there is a disturbance on the screen triggered by user activity or a periodic
+ * system activity, DRRS is disabled (RR is changed to high RR).  When there is
+ * no movement on screen, after a timeout of 1 second, a switch to low RR is
+ * made.
+ *
+ * For integration with frontbuffer tracking code, intel_edp_drrs_invalidate()
+ * and intel_edp_drrs_flush() are called.
+ *
+ * DRRS can be further extended to support other internal panels and also
+ * the scenario of video playback wherein RR is set based on the rate
+ * requested by userspace.
+ */
+
+/**
+ * intel_dp_drrs_init - Init basic DRRS work and mutex.
+ * @connector: eDP connector
+ * @fixed_mode: preferred mode of panel
+ *
+ * This function is  called only once at driver load to initialize basic
+ * DRRS stuff.
+ *
+ * Returns:
+ * Downclock mode if panel supports it, else return NULL.
+ * DRRS support is determined by the presence of downclock mode (apart
+ * from VBT setting).
+ */
+static struct drm_display_mode *
+intel_dp_drrs_init(struct intel_connector *connector,
+                  struct drm_display_mode *fixed_mode)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct drm_display_mode *downclock_mode = NULL;
+
+       INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
+       mutex_init(&dev_priv->drrs.mutex);
+
+       if (INTEL_GEN(dev_priv) <= 6) {
+               DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n");
+               return NULL;
+       }
+
+       if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
+               DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
+               return NULL;
+       }
+
+       downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode);
+       if (!downclock_mode) {
+               DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
+               return NULL;
+       }
+
+       dev_priv->drrs.type = dev_priv->vbt.drrs_type;
+
+       dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
+       DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
+       return downclock_mode;
+}
+
+static bool intel_edp_init_connector(struct intel_dp *intel_dp,
+                                    struct intel_connector *intel_connector)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct drm_device *dev = &dev_priv->drm;
+       struct drm_connector *connector = &intel_connector->base;
+       struct drm_display_mode *fixed_mode = NULL;
+       struct drm_display_mode *downclock_mode = NULL;
+       bool has_dpcd;
+       enum pipe pipe = INVALID_PIPE;
+       intel_wakeref_t wakeref;
+       struct edid *edid;
+
+       if (!intel_dp_is_edp(intel_dp))
+               return true;
+
+       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, edp_panel_vdd_work);
+
+       /*
+        * On IBX/CPT we may get here with LVDS already registered. Since the
+        * driver uses the only internal power sequencer available for both
+        * eDP and LVDS bail out early in this case to prevent interfering
+        * with an already powered-on LVDS power sequencer.
+        */
+       if (intel_get_lvds_encoder(dev_priv)) {
+               WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
+               DRM_INFO("LVDS was detected, not registering eDP\n");
+
+               return false;
+       }
+
+       with_pps_lock(intel_dp, wakeref) {
+               intel_dp_init_panel_power_timestamps(intel_dp);
+               intel_dp_pps_init(intel_dp);
+               intel_edp_panel_vdd_sanitize(intel_dp);
+       }
+
+       /* Cache DPCD and EDID for edp. */
+       has_dpcd = intel_edp_init_dpcd(intel_dp);
+
+       if (!has_dpcd) {
+               /* if this fails, presume the device is a ghost */
+               DRM_INFO("failed to retrieve link info, disabling eDP\n");
+               goto out_vdd_off;
+       }
+
+       mutex_lock(&dev->mode_config.mutex);
+       edid = drm_get_edid(connector, &intel_dp->aux.ddc);
+       if (edid) {
+               if (drm_add_edid_modes(connector, edid)) {
+                       drm_connector_update_edid_property(connector,
+                                                               edid);
+               } else {
+                       kfree(edid);
+                       edid = ERR_PTR(-EINVAL);
+               }
+       } else {
+               edid = ERR_PTR(-ENOENT);
+       }
+       intel_connector->edid = edid;
+
+       fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
+       if (fixed_mode)
+               downclock_mode = intel_dp_drrs_init(intel_connector, fixed_mode);
+
+       /* fallback to VBT if available for eDP */
+       if (!fixed_mode)
+               fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               intel_dp->edp_notifier.notifier_call = edp_notify_handler;
+               register_reboot_notifier(&intel_dp->edp_notifier);
+
+               /*
+                * Figure out the current pipe for the initial backlight setup.
+                * If the current pipe isn't valid, try the PPS pipe, and if that
+                * fails just assume pipe A.
+                */
+               pipe = vlv_active_pipe(intel_dp);
+
+               if (pipe != PIPE_A && pipe != PIPE_B)
+                       pipe = intel_dp->pps_pipe;
+
+               if (pipe != PIPE_A && pipe != PIPE_B)
+                       pipe = PIPE_A;
+
+               DRM_DEBUG_KMS("using pipe %c for initial backlight setup\n",
+                             pipe_name(pipe));
+       }
+
+       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_connector->panel.backlight.power = intel_edp_backlight_power;
+       intel_panel_setup_backlight(connector, pipe);
+
+       if (fixed_mode)
+               drm_connector_init_panel_orientation_property(
+                       connector, fixed_mode->hdisplay, fixed_mode->vdisplay);
+
+       return true;
+
+out_vdd_off:
+       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+       /*
+        * vdd might still be enabled do to the delayed vdd off.
+        * Make sure vdd is actually turned off here.
+        */
+       with_pps_lock(intel_dp, wakeref)
+               edp_panel_vdd_off_sync(intel_dp);
+
+       return false;
+}
+
+static void intel_dp_modeset_retry_work_fn(struct work_struct *work)
+{
+       struct intel_connector *intel_connector;
+       struct drm_connector *connector;
+
+       intel_connector = container_of(work, typeof(*intel_connector),
+                                      modeset_retry_work);
+       connector = &intel_connector->base;
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
+                     connector->name);
+
+       /* Grab the locks before changing connector property*/
+       mutex_lock(&connector->dev->mode_config.mutex);
+       /* Set connector link status to BAD and send a Uevent to notify
+        * userspace to do a modeset.
+        */
+       drm_connector_set_link_status_property(connector,
+                                              DRM_MODE_LINK_STATUS_BAD);
+       mutex_unlock(&connector->dev->mode_config.mutex);
+       /* Send Hotplug uevent so userspace can reprobe */
+       drm_kms_helper_hotplug_event(connector->dev);
+}
+
+bool
+intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
+                       struct intel_connector *intel_connector)
+{
+       struct drm_connector *connector = &intel_connector->base;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       enum port port = intel_encoder->port;
+       int type;
+
+       /* Initialize the work for modeset in case of link train failure */
+       INIT_WORK(&intel_connector->modeset_retry_work,
+                 intel_dp_modeset_retry_work_fn);
+
+       if (WARN(intel_dig_port->max_lanes < 1,
+                "Not enough lanes (%d) for DP on port %c\n",
+                intel_dig_port->max_lanes, port_name(port)))
+               return false;
+
+       intel_dp_set_source_rates(intel_dp);
+
+       intel_dp->reset_link_params = true;
+       intel_dp->pps_pipe = INVALID_PIPE;
+       intel_dp->active_pipe = INVALID_PIPE;
+
+       /* Preserve the current hw state. */
+       intel_dp->DP = I915_READ(intel_dp->output_reg);
+       intel_dp->attached_connector = intel_connector;
+
+       if (intel_dp_is_port_edp(dev_priv, port)) {
+               /*
+                * Currently we don't support eDP on TypeC ports, although in
+                * theory it could work on TypeC legacy ports.
+                */
+               WARN_ON(intel_port_is_tc(dev_priv, port));
+               type = DRM_MODE_CONNECTOR_eDP;
+       } else {
+               type = DRM_MODE_CONNECTOR_DisplayPort;
+       }
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               intel_dp->active_pipe = vlv_active_pipe(intel_dp);
+
+       /*
+        * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
+        * for DP the encoder type can be set by the caller to
+        * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
+        */
+       if (type == DRM_MODE_CONNECTOR_eDP)
+               intel_encoder->type = INTEL_OUTPUT_EDP;
+
+       /* eDP only on port B and/or C on vlv/chv */
+       if (WARN_ON((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
+                   intel_dp_is_edp(intel_dp) &&
+                   port != PORT_B && port != PORT_C))
+               return false;
+
+       DRM_DEBUG_KMS("Adding %s connector on port %c\n",
+                       type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
+                       port_name(port));
+
+       drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
+       drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
+
+       if (!HAS_GMCH(dev_priv))
+               connector->interlace_allowed = true;
+       connector->doublescan_allowed = 0;
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               connector->ycbcr_420_allowed = true;
+
+       intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
+
+       intel_dp_aux_init(intel_dp);
+
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
+
+       if (HAS_DDI(dev_priv))
+               intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
+       else
+               intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       /* init MST on ports that can support it */
+       if (HAS_DP_MST(dev_priv) && !intel_dp_is_edp(intel_dp) &&
+           (port == PORT_B || port == PORT_C ||
+            port == PORT_D || port == PORT_F))
+               intel_dp_mst_encoder_init(intel_dig_port,
+                                         intel_connector->base.base.id);
+
+       if (!intel_edp_init_connector(intel_dp, intel_connector)) {
+               intel_dp_aux_fini(intel_dp);
+               intel_dp_mst_encoder_cleanup(intel_dig_port);
+               goto fail;
+       }
+
+       intel_dp_add_properties(intel_dp, connector);
+
+       if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) {
+               int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim);
+               if (ret)
+                       DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
+       }
+
+       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
+        * 0xd.  Failure to do so will result in spurious interrupts being
+        * generated on the port when a cable is not attached.
+        */
+       if (IS_G45(dev_priv)) {
+               u32 temp = I915_READ(PEG_BAND_GAP_DATA);
+               I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
+       }
+
+       return true;
+
+fail:
+       drm_connector_cleanup(connector);
+
+       return false;
+}
+
+bool intel_dp_init(struct drm_i915_private *dev_priv,
+                  i915_reg_t output_reg,
+                  enum port port)
+{
+       struct intel_digital_port *intel_dig_port;
+       struct intel_encoder *intel_encoder;
+       struct drm_encoder *encoder;
+       struct intel_connector *intel_connector;
+
+       intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
+       if (!intel_dig_port)
+               return false;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector)
+               goto err_connector_alloc;
+
+       intel_encoder = &intel_dig_port->base;
+       encoder = &intel_encoder->base;
+
+       if (drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
+                            &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
+                            "DP %c", port_name(port)))
+               goto err_encoder_init;
+
+       intel_encoder->hotplug = intel_dp_hotplug;
+       intel_encoder->compute_config = intel_dp_compute_config;
+       intel_encoder->get_hw_state = intel_dp_get_hw_state;
+       intel_encoder->get_config = intel_dp_get_config;
+       intel_encoder->update_pipe = intel_panel_update_backlight;
+       intel_encoder->suspend = intel_dp_encoder_suspend;
+       if (IS_CHERRYVIEW(dev_priv)) {
+               intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
+               intel_encoder->pre_enable = chv_pre_enable_dp;
+               intel_encoder->enable = vlv_enable_dp;
+               intel_encoder->disable = vlv_disable_dp;
+               intel_encoder->post_disable = chv_post_disable_dp;
+               intel_encoder->post_pll_disable = chv_dp_post_pll_disable;
+       } else if (IS_VALLEYVIEW(dev_priv)) {
+               intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable;
+               intel_encoder->pre_enable = vlv_pre_enable_dp;
+               intel_encoder->enable = vlv_enable_dp;
+               intel_encoder->disable = vlv_disable_dp;
+               intel_encoder->post_disable = vlv_post_disable_dp;
+       } else {
+               intel_encoder->pre_enable = g4x_pre_enable_dp;
+               intel_encoder->enable = g4x_enable_dp;
+               intel_encoder->disable = g4x_disable_dp;
+               intel_encoder->post_disable = g4x_post_disable_dp;
+       }
+
+       intel_dig_port->dp.output_reg = output_reg;
+       intel_dig_port->max_lanes = 4;
+
+       intel_encoder->type = INTEL_OUTPUT_DP;
+       intel_encoder->power_domain = intel_port_to_power_domain(port);
+       if (IS_CHERRYVIEW(dev_priv)) {
+               if (port == PORT_D)
+                       intel_encoder->crtc_mask = 1 << 2;
+               else
+                       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+       } else {
+               intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+       }
+       intel_encoder->cloneable = 0;
+       intel_encoder->port = port;
+
+       intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
+
+       if (port != PORT_A)
+               intel_infoframe_init(intel_dig_port);
+
+       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
+       if (!intel_dp_init_connector(intel_dig_port, intel_connector))
+               goto err_init_connector;
+
+       return true;
+
+err_init_connector:
+       drm_encoder_cleanup(encoder);
+err_encoder_init:
+       kfree(intel_connector);
+err_connector_alloc:
+       kfree(intel_dig_port);
+       return false;
+}
+
+void intel_dp_mst_suspend(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder;
+
+       for_each_intel_encoder(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp;
+
+               if (encoder->type != INTEL_OUTPUT_DDI)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+
+               if (!intel_dp->can_mst)
+                       continue;
+
+               if (intel_dp->is_mst)
+                       drm_dp_mst_topology_mgr_suspend(&intel_dp->mst_mgr);
+       }
+}
+
+void intel_dp_mst_resume(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder;
+
+       for_each_intel_encoder(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp;
+               int ret;
+
+               if (encoder->type != INTEL_OUTPUT_DDI)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+
+               if (!intel_dp->can_mst)
+                       continue;
+
+               ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr);
+               if (ret) {
+                       intel_dp->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                                       false);
+               }
+       }
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
new file mode 100644 (file)
index 0000000..da70b1a
--- /dev/null
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DP_H__
+#define __INTEL_DP_H__
+
+#include <linux/types.h>
+
+#include <drm/i915_drm.h>
+
+#include "i915_reg.h"
+
+enum pipe;
+struct drm_connector_state;
+struct drm_encoder;
+struct drm_i915_private;
+struct drm_modeset_acquire_ctx;
+struct intel_connector;
+struct intel_crtc_state;
+struct intel_digital_port;
+struct intel_dp;
+struct intel_encoder;
+
+struct link_config_limits {
+       int min_clock, max_clock;
+       int min_lane_count, max_lane_count;
+       int min_bpp, max_bpp;
+};
+
+void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
+                                      struct intel_crtc_state *pipe_config,
+                                      struct link_config_limits *limits);
+bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state);
+int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state);
+bool intel_dp_port_enabled(struct drm_i915_private *dev_priv,
+                          i915_reg_t dp_reg, enum port port,
+                          enum pipe *pipe);
+bool intel_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg,
+                  enum port port);
+bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
+                            struct intel_connector *intel_connector);
+void intel_dp_set_link_params(struct intel_dp *intel_dp,
+                             int link_rate, u8 lane_count,
+                             bool link_mst);
+int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+                                           int link_rate, u8 lane_count);
+int intel_dp_retrain_link(struct intel_encoder *encoder,
+                         struct drm_modeset_acquire_ctx *ctx);
+void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
+void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state *crtc_state,
+                                          bool enable);
+void intel_dp_encoder_reset(struct drm_encoder *encoder);
+void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
+void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
+int intel_dp_compute_config(struct intel_encoder *encoder,
+                           struct intel_crtc_state *pipe_config,
+                           struct drm_connector_state *conn_state);
+bool intel_dp_is_edp(struct intel_dp *intel_dp);
+bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port);
+enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
+                                 bool long_hpd);
+void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
+                           const struct drm_connector_state *conn_state);
+void intel_edp_backlight_off(const struct drm_connector_state *conn_state);
+void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
+void intel_edp_panel_on(struct intel_dp *intel_dp);
+void intel_edp_panel_off(struct intel_dp *intel_dp);
+void intel_dp_mst_suspend(struct drm_i915_private *dev_priv);
+void intel_dp_mst_resume(struct drm_i915_private *dev_priv);
+int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_max_lane_count(struct intel_dp *intel_dp);
+int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
+void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
+u32 intel_dp_pack_aux(const u8 *src, int src_bytes);
+
+void intel_edp_drrs_enable(struct intel_dp *intel_dp,
+                          const struct intel_crtc_state *crtc_state);
+void intel_edp_drrs_disable(struct intel_dp *intel_dp,
+                           const struct intel_crtc_state *crtc_state);
+void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
+                              unsigned int frontbuffer_bits);
+void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
+                         unsigned int frontbuffer_bits);
+
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+                                      u8 dp_train_pat);
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp);
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
+u8
+intel_dp_voltage_max(struct intel_dp *intel_dp);
+u8
+intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, u8 voltage_swing);
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+                          u8 *link_bw, u8 *rate_select);
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
+bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
+bool
+intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
+u16 intel_dp_dsc_get_output_bpp(int link_clock, u8 lane_count,
+                               int mode_clock, int mode_hdisplay);
+u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, int mode_clock,
+                               int mode_hdisplay);
+
+bool intel_dp_read_dpcd(struct intel_dp *intel_dp);
+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)
+{
+       return ~((1 << lane_count) - 1) & 0xf;
+}
+
+#endif /* __INTEL_DP_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
new file mode 100644 (file)
index 0000000..7ded95a
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "intel_dp_aux_backlight.h"
+#include "intel_drv.h"
+
+static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable)
+{
+       u8 reg_val = 0;
+
+       /* Early return when display use other mechanism to enable backlight. */
+       if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP))
+               return;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER,
+                             &reg_val) < 0) {
+               DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
+                             DP_EDP_DISPLAY_CONTROL_REGISTER);
+               return;
+       }
+       if (enable)
+               reg_val |= DP_EDP_BACKLIGHT_ENABLE;
+       else
+               reg_val &= ~(DP_EDP_BACKLIGHT_ENABLE);
+
+       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER,
+                              reg_val) != 1) {
+               DRM_DEBUG_KMS("Failed to %s aux backlight\n",
+                             enable ? "enable" : "disable");
+       }
+}
+
+/*
+ * Read the current backlight value from DPCD register(s) based
+ * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
+ */
+static u32 intel_dp_aux_get_backlight(struct intel_connector *connector)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+       u8 read_val[2] = { 0x0 };
+       u16 level = 0;
+
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
+                            &read_val, sizeof(read_val)) < 0) {
+               DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
+                             DP_EDP_BACKLIGHT_BRIGHTNESS_MSB);
+               return 0;
+       }
+       level = read_val[0];
+       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
+               level = (read_val[0] << 8 | read_val[1]);
+
+       return level;
+}
+
+/*
+ * Sends the current backlight level over the aux channel, checking if its using
+ * 8-bit or 16 bit value (MSB and LSB)
+ */
+static void
+intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+       u8 vals[2] = { 0x0 };
+
+       vals[0] = level;
+
+       /* Write the MSB and/or LSB */
+       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) {
+               vals[0] = (level & 0xFF00) >> 8;
+               vals[1] = (level & 0xFF);
+       }
+       if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
+                             vals, sizeof(vals)) < 0) {
+               DRM_DEBUG_KMS("Failed to write aux backlight level\n");
+               return;
+       }
+}
+
+/*
+ * Set PWM Frequency divider to match desired frequency in vbt.
+ * The PWM Frequency is calculated as 27Mhz / (F x P).
+ * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the
+ *             EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h)
+ * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the
+ *             EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h)
+ */
+static bool intel_dp_aux_set_pwm_freq(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+       int freq, fxp, fxp_min, fxp_max, fxp_actual, f = 1;
+       u8 pn, pn_min, pn_max;
+
+       /* Find desired value of (F x P)
+        * Note that, if F x P is out of supported range, the maximum value or
+        * minimum value will applied automatically. So no need to check that.
+        */
+       freq = dev_priv->vbt.backlight.pwm_freq_hz;
+       DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq);
+       if (!freq) {
+               DRM_DEBUG_KMS("Use panel default backlight frequency\n");
+               return false;
+       }
+
+       fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq);
+
+       /* Use highest possible value of Pn for more granularity of brightness
+        * adjustment while satifying the conditions below.
+        * - Pn is in the range of Pn_min and Pn_max
+        * - F is in the range of 1 and 255
+        * - FxP is within 25% of desired value.
+        *   Note: 25% is arbitrary value and may need some tweak.
+        */
+       if (drm_dp_dpcd_readb(&intel_dp->aux,
+                              DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min) != 1) {
+               DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n");
+               return false;
+       }
+       if (drm_dp_dpcd_readb(&intel_dp->aux,
+                              DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max) != 1) {
+               DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n");
+               return false;
+       }
+       pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
+       pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
+
+       fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4);
+       fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4);
+       if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) {
+               DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n");
+               return false;
+       }
+
+       for (pn = pn_max; pn >= pn_min; pn--) {
+               f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255);
+               fxp_actual = f << pn;
+               if (fxp_min <= fxp_actual && fxp_actual <= fxp_max)
+                       break;
+       }
+
+       if (drm_dp_dpcd_writeb(&intel_dp->aux,
+                              DP_EDP_PWMGEN_BIT_COUNT, pn) < 0) {
+               DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
+               return false;
+       }
+       if (drm_dp_dpcd_writeb(&intel_dp->aux,
+                              DP_EDP_BACKLIGHT_FREQ_SET, (u8) f) < 0) {
+               DRM_DEBUG_KMS("Failed to write aux backlight freq\n");
+               return false;
+       }
+       return true;
+}
+
+static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                         const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+       u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux,
+                       DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) {
+               DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
+                             DP_EDP_BACKLIGHT_MODE_SET_REGISTER);
+               return;
+       }
+
+       new_dpcd_buf = dpcd_buf;
+       edp_backlight_mode = dpcd_buf & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK;
+
+       switch (edp_backlight_mode) {
+       case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM:
+       case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET:
+       case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT:
+               new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK;
+               new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD;
+               break;
+
+       /* Do nothing when it is already DPCD mode */
+       case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD:
+       default:
+               break;
+       }
+
+       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP)
+               if (intel_dp_aux_set_pwm_freq(connector))
+                       new_dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE;
+
+       if (new_dpcd_buf != dpcd_buf) {
+               if (drm_dp_dpcd_writeb(&intel_dp->aux,
+                       DP_EDP_BACKLIGHT_MODE_SET_REGISTER, new_dpcd_buf) < 0) {
+                       DRM_DEBUG_KMS("Failed to write aux backlight mode\n");
+               }
+       }
+
+       set_aux_backlight_enable(intel_dp, true);
+       intel_dp_aux_set_backlight(conn_state, connector->panel.backlight.level);
+}
+
+static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       set_aux_backlight_enable(enc_to_intel_dp(old_conn_state->best_encoder), false);
+}
+
+static int intel_dp_aux_setup_backlight(struct intel_connector *connector,
+                                       enum pipe pipe)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+       struct intel_panel *panel = &connector->panel;
+
+       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
+               panel->backlight.max = 0xFFFF;
+       else
+               panel->backlight.max = 0xFF;
+
+       panel->backlight.min = 0;
+       panel->backlight.level = intel_dp_aux_get_backlight(connector);
+
+       panel->backlight.enabled = panel->backlight.level != 0;
+
+       return 0;
+}
+
+static bool
+intel_dp_aux_display_control_capable(struct intel_connector *connector)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+
+       /* Check the eDP Display control capabilities registers to determine if
+        * the panel can support backlight control over the aux channel
+        */
+       if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
+           (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) &&
+           !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
+               DRM_DEBUG_KMS("AUX Backlight Control Supported!\n");
+               return true;
+       }
+       return false;
+}
+
+int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector)
+{
+       struct intel_panel *panel = &intel_connector->panel;
+
+       if (!i915_modparams.enable_dpcd_backlight)
+               return -ENODEV;
+
+       if (!intel_dp_aux_display_control_capable(intel_connector))
+               return -ENODEV;
+
+       panel->backlight.setup = intel_dp_aux_setup_backlight;
+       panel->backlight.enable = intel_dp_aux_enable_backlight;
+       panel->backlight.disable = intel_dp_aux_disable_backlight;
+       panel->backlight.set = intel_dp_aux_set_backlight;
+       panel->backlight.get = intel_dp_aux_get_backlight;
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.h b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.h
new file mode 100644 (file)
index 0000000..ed60c28
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DP_AUX_BACKLIGHT_H__
+#define __INTEL_DP_AUX_BACKLIGHT_H__
+
+struct intel_connector;
+
+int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector);
+
+#endif /* __INTEL_DP_AUX_BACKLIGHT_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
new file mode 100644 (file)
index 0000000..9b1fcce
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright © 2008-2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "intel_dp.h"
+#include "intel_dp_link_training.h"
+#include "intel_drv.h"
+
+static void
+intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
+{
+
+       DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x",
+                     link_status[0], link_status[1], link_status[2],
+                     link_status[3], link_status[4], link_status[5]);
+}
+
+static void
+intel_get_adjust_train(struct intel_dp *intel_dp,
+                      const u8 link_status[DP_LINK_STATUS_SIZE])
+{
+       u8 v = 0;
+       u8 p = 0;
+       int lane;
+       u8 voltage_max;
+       u8 preemph_max;
+
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
+               u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
+
+               if (this_v > v)
+                       v = this_v;
+               if (this_p > p)
+                       p = this_p;
+       }
+
+       voltage_max = intel_dp_voltage_max(intel_dp);
+       if (v >= voltage_max)
+               v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
+
+       preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
+       if (p >= preemph_max)
+               p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+       for (lane = 0; lane < 4; lane++)
+               intel_dp->train_set[lane] = v | p;
+}
+
+static bool
+intel_dp_set_link_train(struct intel_dp *intel_dp,
+                       u8 dp_train_pat)
+{
+       u8 buf[sizeof(intel_dp->train_set) + 1];
+       int ret, len;
+
+       intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
+
+       buf[0] = dp_train_pat;
+       if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
+           DP_TRAINING_PATTERN_DISABLE) {
+               /* don't write DP_TRAINING_LANEx_SET on disable */
+               len = 1;
+       } else {
+               /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
+               memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
+               len = intel_dp->lane_count + 1;
+       }
+
+       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
+                               buf, len);
+
+       return ret == len;
+}
+
+static bool
+intel_dp_reset_link_train(struct intel_dp *intel_dp,
+                       u8 dp_train_pat)
+{
+       memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
+       intel_dp_set_signal_levels(intel_dp);
+       return intel_dp_set_link_train(intel_dp, dp_train_pat);
+}
+
+static bool
+intel_dp_update_link_train(struct intel_dp *intel_dp)
+{
+       int ret;
+
+       intel_dp_set_signal_levels(intel_dp);
+
+       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
+                               intel_dp->train_set, intel_dp->lane_count);
+
+       return ret == intel_dp->lane_count;
+}
+
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+{
+       int lane;
+
+       for (lane = 0; lane < intel_dp->lane_count; lane++)
+               if ((intel_dp->train_set[lane] &
+                    DP_TRAIN_MAX_SWING_REACHED) == 0)
+                       return false;
+
+       return true;
+}
+
+/* Enable corresponding port and start training pattern 1 */
+static bool
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+{
+       u8 voltage;
+       int voltage_tries, cr_tries, max_cr_tries;
+       bool max_vswing_reached = false;
+       u8 link_config[2];
+       u8 link_bw, rate_select;
+
+       if (intel_dp->prepare_link_retrain)
+               intel_dp->prepare_link_retrain(intel_dp);
+
+       intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
+                             &link_bw, &rate_select);
+
+       if (link_bw)
+               DRM_DEBUG_KMS("Using LINK_BW_SET value %02x\n", link_bw);
+       else
+               DRM_DEBUG_KMS("Using LINK_RATE_SET value %02x\n", rate_select);
+
+       /* Write the link configuration data */
+       link_config[0] = link_bw;
+       link_config[1] = intel_dp->lane_count;
+       if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+               link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+       drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+
+       /* eDP 1.4 rate select method. */
+       if (!link_bw)
+               drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
+                                 &rate_select, 1);
+
+       link_config[0] = 0;
+       link_config[1] = DP_SET_ANSI_8B10B;
+       drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
+
+       intel_dp->DP |= DP_PORT_EN;
+
+       /* clock recovery */
+       if (!intel_dp_reset_link_train(intel_dp,
+                                      DP_TRAINING_PATTERN_1 |
+                                      DP_LINK_SCRAMBLING_DISABLE)) {
+               DRM_ERROR("failed to enable link training\n");
+               return false;
+       }
+
+       /*
+        * The DP 1.4 spec defines the max clock recovery retries value
+        * as 10 but for pre-DP 1.4 devices we set a very tolerant
+        * retry limit of 80 (4 voltage levels x 4 preemphasis levels x
+        * x 5 identical voltage retries). Since the previous specs didn't
+        * define a limit and created the possibility of an infinite loop
+        * we want to prevent any sync from triggering that corner case.
+        */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
+               max_cr_tries = 10;
+       else
+               max_cr_tries = 80;
+
+       voltage_tries = 1;
+       for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
+               u8 link_status[DP_LINK_STATUS_SIZE];
+
+               drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+
+               if (!intel_dp_get_link_status(intel_dp, link_status)) {
+                       DRM_ERROR("failed to get link status\n");
+                       return false;
+               }
+
+               if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+                       DRM_DEBUG_KMS("clock recovery OK\n");
+                       return true;
+               }
+
+               if (voltage_tries == 5) {
+                       DRM_DEBUG_KMS("Same voltage tried 5 times\n");
+                       return false;
+               }
+
+               if (max_vswing_reached) {
+                       DRM_DEBUG_KMS("Max Voltage Swing reached\n");
+                       return false;
+               }
+
+               voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+               /* Update training set as requested by target */
+               intel_get_adjust_train(intel_dp, link_status);
+               if (!intel_dp_update_link_train(intel_dp)) {
+                       DRM_ERROR("failed to update link training\n");
+                       return false;
+               }
+
+               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
+                   voltage)
+                       ++voltage_tries;
+               else
+                       voltage_tries = 1;
+
+               if (intel_dp_link_max_vswing_reached(intel_dp))
+                       max_vswing_reached = true;
+
+       }
+       DRM_ERROR("Failed clock recovery %d times, giving up!\n", max_cr_tries);
+       return false;
+}
+
+/*
+ * Pick training pattern for channel equalization. Training pattern 4 for HBR3
+ * or for 1.4 devices that support it, training Pattern 3 for HBR2
+ * or 1.2 devices that support it, Training Pattern 2 otherwise.
+ */
+static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
+{
+       bool source_tps3, sink_tps3, source_tps4, sink_tps4;
+
+       /*
+        * Intel platforms that support HBR3 also support TPS4. It is mandatory
+        * for all downstream devices that support HBR3. There are no known eDP
+        * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
+        * specification.
+        */
+       source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
+       sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
+       if (source_tps4 && sink_tps4) {
+               return DP_TRAINING_PATTERN_4;
+       } else if (intel_dp->link_rate == 810000) {
+               if (!source_tps4)
+                       DRM_DEBUG_KMS("8.1 Gbps link rate without source HBR3/TPS4 support\n");
+               if (!sink_tps4)
+                       DRM_DEBUG_KMS("8.1 Gbps link rate without sink TPS4 support\n");
+       }
+       /*
+        * Intel platforms that support HBR2 also support TPS3. TPS3 support is
+        * also mandatory for downstream devices that support HBR2. However, not
+        * all sinks follow the spec.
+        */
+       source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
+       sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
+       if (source_tps3 && sink_tps3) {
+               return  DP_TRAINING_PATTERN_3;
+       } else if (intel_dp->link_rate >= 540000) {
+               if (!source_tps3)
+                       DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n");
+               if (!sink_tps3)
+                       DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without sink TPS3 support\n");
+       }
+
+       return DP_TRAINING_PATTERN_2;
+}
+
+static bool
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+{
+       int tries;
+       u32 training_pattern;
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       bool channel_eq = false;
+
+       training_pattern = intel_dp_training_pattern(intel_dp);
+       /* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
+       if (training_pattern != DP_TRAINING_PATTERN_4)
+               training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
+
+       /* channel equalization */
+       if (!intel_dp_set_link_train(intel_dp,
+                                    training_pattern)) {
+               DRM_ERROR("failed to start channel equalization\n");
+               return false;
+       }
+
+       for (tries = 0; tries < 5; tries++) {
+
+               drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
+               if (!intel_dp_get_link_status(intel_dp, link_status)) {
+                       DRM_ERROR("failed to get link status\n");
+                       break;
+               }
+
+               /* Make sure clock is still ok */
+               if (!drm_dp_clock_recovery_ok(link_status,
+                                             intel_dp->lane_count)) {
+                       intel_dp_dump_link_status(link_status);
+                       DRM_DEBUG_KMS("Clock recovery check failed, cannot "
+                                     "continue channel equalization\n");
+                       break;
+               }
+
+               if (drm_dp_channel_eq_ok(link_status,
+                                        intel_dp->lane_count)) {
+                       channel_eq = true;
+                       DRM_DEBUG_KMS("Channel EQ done. DP Training "
+                                     "successful\n");
+                       break;
+               }
+
+               /* Update training set as requested by target */
+               intel_get_adjust_train(intel_dp, link_status);
+               if (!intel_dp_update_link_train(intel_dp)) {
+                       DRM_ERROR("failed to update link training\n");
+                       break;
+               }
+       }
+
+       /* Try 5 times, else fail and try at lower BW */
+       if (tries == 5) {
+               intel_dp_dump_link_status(link_status);
+               DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
+       }
+
+       intel_dp_set_idle_link_train(intel_dp);
+
+       return channel_eq;
+
+}
+
+void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+{
+       intel_dp->link_trained = true;
+
+       intel_dp_set_link_train(intel_dp,
+                               DP_TRAINING_PATTERN_DISABLE);
+}
+
+void
+intel_dp_start_link_train(struct intel_dp *intel_dp)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+
+       if (!intel_dp_link_training_clock_recovery(intel_dp))
+               goto failure_handling;
+       if (!intel_dp_link_training_channel_equalization(intel_dp))
+               goto failure_handling;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
+                     intel_connector->base.base.id,
+                     intel_connector->base.name,
+                     intel_dp->link_rate, intel_dp->lane_count);
+       return;
+
+ failure_handling:
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
+                     intel_connector->base.base.id,
+                     intel_connector->base.name,
+                     intel_dp->link_rate, intel_dp->lane_count);
+       if (!intel_dp_get_link_train_fallback_values(intel_dp,
+                                                    intel_dp->link_rate,
+                                                    intel_dp->lane_count))
+               /* Schedule a Hotplug Uevent to userspace to start modeset */
+               schedule_work(&intel_connector->modeset_retry_work);
+       return;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
new file mode 100644 (file)
index 0000000..174566a
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DP_LINK_TRAINING_H__
+#define __INTEL_DP_LINK_TRAINING_H__
+
+struct intel_dp;
+
+void intel_dp_start_link_train(struct intel_dp *intel_dp);
+void intel_dp_stop_link_train(struct intel_dp *intel_dp);
+
+#endif /* __INTEL_DP_LINK_TRAINING_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
new file mode 100644 (file)
index 0000000..0caf645
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *             2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
+
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_audio.h"
+#include "intel_connector.h"
+#include "intel_ddi.h"
+#include "intel_dp.h"
+#include "intel_dp_mst.h"
+#include "intel_dpio_phy.h"
+#include "intel_drv.h"
+
+static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
+                                           struct intel_crtc_state *crtc_state,
+                                           struct drm_connector_state *conn_state,
+                                           struct link_config_limits *limits)
+{
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_dp *intel_dp = &intel_mst->primary->dp;
+       struct intel_connector *connector =
+               to_intel_connector(conn_state->connector);
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       void *port = connector->port;
+       bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
+                                          DP_DPCD_QUIRK_CONSTANT_N);
+       int bpp, slots = -EINVAL;
+
+       crtc_state->lane_count = limits->max_lane_count;
+       crtc_state->port_clock = limits->max_clock;
+
+       for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
+               crtc_state->pipe_bpp = bpp;
+
+               crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock,
+                                                      crtc_state->pipe_bpp);
+
+               slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
+                                                     port, crtc_state->pbn);
+               if (slots == -EDEADLK)
+                       return slots;
+               if (slots >= 0)
+                       break;
+       }
+
+       if (slots < 0) {
+               DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots);
+               return slots;
+       }
+
+       intel_link_compute_m_n(crtc_state->pipe_bpp,
+                              crtc_state->lane_count,
+                              adjusted_mode->crtc_clock,
+                              crtc_state->port_clock,
+                              &crtc_state->dp_m_n,
+                              constant_n);
+       crtc_state->dp_m_n.tu = slots;
+
+       return 0;
+}
+
+static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
+                                      struct intel_crtc_state *pipe_config,
+                                      struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_dp *intel_dp = &intel_mst->primary->dp;
+       struct intel_connector *connector =
+               to_intel_connector(conn_state->connector);
+       struct intel_digital_connector_state *intel_conn_state =
+               to_intel_digital_connector_state(conn_state);
+       const struct drm_display_mode *adjusted_mode =
+               &pipe_config->base.adjusted_mode;
+       void *port = connector->port;
+       struct link_config_limits limits;
+       int ret;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+       pipe_config->has_pch_encoder = false;
+
+       if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
+               pipe_config->has_audio =
+                       drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, port);
+       else
+               pipe_config->has_audio =
+                       intel_conn_state->force_audio == HDMI_AUDIO_ON;
+
+       /*
+        * for MST we always configure max link bw - the spec doesn't
+        * seem to suggest we should do otherwise.
+        */
+       limits.min_clock =
+       limits.max_clock = intel_dp_max_link_rate(intel_dp);
+
+       limits.min_lane_count =
+       limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
+
+       limits.min_bpp = intel_dp_min_bpp(pipe_config);
+       limits.max_bpp = pipe_config->pipe_bpp;
+
+       intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
+
+       ret = intel_dp_mst_compute_link_config(encoder, pipe_config,
+                                              conn_state, &limits);
+       if (ret)
+               return ret;
+
+       pipe_config->limited_color_range =
+               intel_dp_limited_color_range(pipe_config, conn_state);
+
+       if (IS_GEN9_LP(dev_priv))
+               pipe_config->lane_lat_optim_mask =
+                       bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count);
+
+       intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
+
+       return 0;
+}
+
+static int
+intel_dp_mst_atomic_check(struct drm_connector *connector,
+                         struct drm_connector_state *new_conn_state)
+{
+       struct drm_atomic_state *state = new_conn_state->state;
+       struct drm_connector_state *old_conn_state =
+               drm_atomic_get_old_connector_state(state, connector);
+       struct intel_connector *intel_connector =
+               to_intel_connector(connector);
+       struct drm_crtc *new_crtc = new_conn_state->crtc;
+       struct drm_crtc_state *crtc_state;
+       struct drm_dp_mst_topology_mgr *mgr;
+       int ret;
+
+       ret = intel_digital_connector_atomic_check(connector, new_conn_state);
+       if (ret)
+               return ret;
+
+       if (!old_conn_state->crtc)
+               return 0;
+
+       /* We only want to free VCPI if this state disables the CRTC on this
+        * connector
+        */
+       if (new_crtc) {
+               crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
+
+               if (!crtc_state ||
+                   !drm_atomic_crtc_needs_modeset(crtc_state) ||
+                   crtc_state->enable)
+                       return 0;
+       }
+
+       mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr;
+       ret = drm_dp_atomic_release_vcpi_slots(state, mgr,
+                                              intel_connector->port);
+
+       return ret;
+}
+
+static void intel_mst_disable_dp(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *old_crtc_state,
+                                const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct intel_connector *connector =
+               to_intel_connector(old_conn_state->connector);
+       int ret;
+
+       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
+
+       drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
+
+       ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
+       if (ret) {
+               DRM_ERROR("failed to update payload %d\n", ret);
+       }
+       if (old_crtc_state->has_audio)
+               intel_audio_codec_disable(encoder,
+                                         old_crtc_state, old_conn_state);
+}
+
+static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
+                                     const struct intel_crtc_state *old_crtc_state,
+                                     const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct intel_connector *connector =
+               to_intel_connector(old_conn_state->connector);
+
+       intel_ddi_disable_pipe_clock(old_crtc_state);
+
+       /* this can fail */
+       drm_dp_check_act_status(&intel_dp->mst_mgr);
+       /* and this can also fail */
+       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
+
+       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
+
+       /*
+        * Power down mst path before disabling the port, otherwise we end
+        * up getting interrupts from the sink upon detecting link loss.
+        */
+       drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port,
+                                    false);
+
+       intel_dp->active_mst_links--;
+
+       intel_mst->connector = NULL;
+       if (intel_dp->active_mst_links == 0) {
+               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+               intel_dig_port->base.post_disable(&intel_dig_port->base,
+                                                 old_crtc_state, NULL);
+       }
+
+       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
+}
+
+static void intel_mst_pre_pll_enable_dp(struct intel_encoder *encoder,
+                                       const struct intel_crtc_state *pipe_config,
+                                       const struct drm_connector_state *conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       if (intel_dp->active_mst_links == 0)
+               intel_dig_port->base.pre_pll_enable(&intel_dig_port->base,
+                                                   pipe_config, NULL);
+}
+
+static void intel_mst_post_pll_disable_dp(struct intel_encoder *encoder,
+                                         const struct intel_crtc_state *old_crtc_state,
+                                         const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       if (intel_dp->active_mst_links == 0)
+               intel_dig_port->base.post_pll_disable(&intel_dig_port->base,
+                                                     old_crtc_state,
+                                                     old_conn_state);
+}
+
+static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
+                                   const struct intel_crtc_state *pipe_config,
+                                   const struct drm_connector_state *conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = intel_dig_port->base.port;
+       struct intel_connector *connector =
+               to_intel_connector(conn_state->connector);
+       int ret;
+       u32 temp;
+
+       /* MST encoders are bound to a crtc, not to a connector,
+        * force the mapping here for get_hw_state.
+        */
+       connector->encoder = encoder;
+       intel_mst->connector = connector;
+
+       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
+
+       if (intel_dp->active_mst_links == 0)
+               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+
+       drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true);
+
+       if (intel_dp->active_mst_links == 0)
+               intel_dig_port->base.pre_enable(&intel_dig_port->base,
+                                               pipe_config, NULL);
+
+       ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
+                                      connector->port,
+                                      pipe_config->pbn,
+                                      pipe_config->dp_m_n.tu);
+       if (!ret)
+               DRM_ERROR("failed to allocate vcpi\n");
+
+       intel_dp->active_mst_links++;
+       temp = I915_READ(DP_TP_STATUS(port));
+       I915_WRITE(DP_TP_STATUS(port), temp);
+
+       ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
+
+       intel_ddi_enable_pipe_clock(pipe_config);
+}
+
+static void intel_mst_enable_dp(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *pipe_config,
+                               const struct drm_connector_state *conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = intel_dig_port->base.port;
+
+       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
+
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   DP_TP_STATUS(port),
+                                   DP_TP_STATUS_ACT_SENT,
+                                   DP_TP_STATUS_ACT_SENT,
+                                   1))
+               DRM_ERROR("Timed out waiting for ACT sent\n");
+
+       drm_dp_check_act_status(&intel_dp->mst_mgr);
+
+       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
+       if (pipe_config->has_audio)
+               intel_audio_codec_enable(encoder, pipe_config, conn_state);
+}
+
+static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
+                                     enum pipe *pipe)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       *pipe = intel_mst->pipe;
+       if (intel_mst->connector)
+               return true;
+       return false;
+}
+
+static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
+                                       struct intel_crtc_state *pipe_config)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+
+       intel_ddi_get_config(&intel_dig_port->base, pipe_config);
+}
+
+static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+       struct edid *edid;
+       int ret;
+
+       if (drm_connector_is_unregistered(connector))
+               return intel_connector_update_modes(connector, NULL);
+
+       edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
+       ret = intel_connector_update_modes(connector, edid);
+       kfree(edid);
+
+       return ret;
+}
+
+static enum drm_connector_status
+intel_dp_mst_detect(struct drm_connector *connector, bool force)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+
+       if (drm_connector_is_unregistered(connector))
+               return connector_status_disconnected;
+       return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr,
+                                     intel_connector->port);
+}
+
+static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
+       .detect = intel_dp_mst_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static int intel_dp_mst_get_modes(struct drm_connector *connector)
+{
+       return intel_dp_mst_get_ddc_modes(connector);
+}
+
+static enum drm_mode_status
+intel_dp_mst_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+       int max_rate, mode_rate, max_lanes, max_link_clock;
+
+       if (drm_connector_is_unregistered(connector))
+               return MODE_ERROR;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       max_link_clock = intel_dp_max_link_rate(intel_dp);
+       max_lanes = intel_dp_max_lane_count(intel_dp);
+
+       max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
+       mode_rate = intel_dp_link_required(mode->clock, 18);
+
+       /* TODO - validate mode against available PBN for link */
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               return MODE_H_ILLEGAL;
+
+       if (mode_rate > max_rate || mode->clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
+                                                        struct drm_connector_state *state)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+       struct intel_crtc *crtc = to_intel_crtc(state->crtc);
+
+       return &intel_dp->mst_encoders[crtc->pipe]->base.base;
+}
+
+static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
+       .get_modes = intel_dp_mst_get_modes,
+       .mode_valid = intel_dp_mst_mode_valid,
+       .atomic_best_encoder = intel_mst_atomic_best_encoder,
+       .atomic_check = intel_dp_mst_atomic_check,
+};
+
+static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+
+       drm_encoder_cleanup(encoder);
+       kfree(intel_mst);
+}
+
+static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {
+       .destroy = intel_dp_mst_encoder_destroy,
+};
+
+static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
+{
+       if (connector->encoder && connector->base.state->crtc) {
+               enum pipe pipe;
+               if (!connector->encoder->get_hw_state(connector->encoder, &pipe))
+                       return false;
+               return true;
+       }
+       return false;
+}
+
+static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop)
+{
+       struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_connector *intel_connector;
+       struct drm_connector *connector;
+       enum pipe pipe;
+       int ret;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector)
+               return NULL;
+
+       intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
+       intel_connector->mst_port = intel_dp;
+       intel_connector->port = port;
+       drm_dp_mst_get_port_malloc(port);
+
+       connector = &intel_connector->base;
+       ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
+                                DRM_MODE_CONNECTOR_DisplayPort);
+       if (ret) {
+               intel_connector_free(intel_connector);
+               return NULL;
+       }
+
+       drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
+
+       for_each_pipe(dev_priv, pipe) {
+               struct drm_encoder *enc =
+                       &intel_dp->mst_encoders[pipe]->base.base;
+
+               ret = drm_connector_attach_encoder(&intel_connector->base, enc);
+               if (ret)
+                       goto err;
+       }
+
+       drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
+       drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
+
+       ret = drm_connector_set_path_property(connector, pathprop);
+       if (ret)
+               goto err;
+
+       intel_attach_force_audio_property(connector);
+       intel_attach_broadcast_rgb_property(connector);
+       drm_connector_attach_max_bpc_property(connector, 6, 12);
+
+       return connector;
+
+err:
+       drm_connector_cleanup(connector);
+       return NULL;
+}
+
+static void intel_dp_register_mst_connector(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+
+       if (dev_priv->fbdev)
+               drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper,
+                                               connector);
+
+       drm_connector_register(connector);
+}
+
+static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                          struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name);
+       drm_connector_unregister(connector);
+
+       if (dev_priv->fbdev)
+               drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper,
+                                                  connector);
+
+       drm_connector_put(connector);
+}
+
+static const struct drm_dp_mst_topology_cbs mst_cbs = {
+       .add_connector = intel_dp_add_mst_connector,
+       .register_connector = intel_dp_register_mst_connector,
+       .destroy_connector = intel_dp_destroy_mst_connector,
+};
+
+static struct intel_dp_mst_encoder *
+intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe)
+{
+       struct intel_dp_mst_encoder *intel_mst;
+       struct intel_encoder *intel_encoder;
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+
+       intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
+
+       if (!intel_mst)
+               return NULL;
+
+       intel_mst->pipe = pipe;
+       intel_encoder = &intel_mst->base;
+       intel_mst->primary = intel_dig_port;
+
+       drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
+                        DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
+
+       intel_encoder->type = INTEL_OUTPUT_DP_MST;
+       intel_encoder->power_domain = intel_dig_port->base.power_domain;
+       intel_encoder->port = intel_dig_port->base.port;
+       intel_encoder->crtc_mask = 0x7;
+       intel_encoder->cloneable = 0;
+
+       intel_encoder->compute_config = intel_dp_mst_compute_config;
+       intel_encoder->disable = intel_mst_disable_dp;
+       intel_encoder->post_disable = intel_mst_post_disable_dp;
+       intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp;
+       intel_encoder->post_pll_disable = intel_mst_post_pll_disable_dp;
+       intel_encoder->pre_enable = intel_mst_pre_enable_dp;
+       intel_encoder->enable = intel_mst_enable_dp;
+       intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
+       intel_encoder->get_config = intel_dp_mst_enc_get_config;
+
+       return intel_mst;
+
+}
+
+static bool
+intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
+{
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
+       enum pipe pipe;
+
+       for_each_pipe(dev_priv, pipe)
+               intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
+       return true;
+}
+
+int
+intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
+{
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       int ret;
+
+       intel_dp->can_mst = true;
+       intel_dp->mst_mgr.cbs = &mst_cbs;
+
+       /* create encoders */
+       intel_dp_create_fake_mst_encoders(intel_dig_port);
+       ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
+                                          &intel_dp->aux, 16, 3, conn_base_id);
+       if (ret) {
+               intel_dp->can_mst = false;
+               return ret;
+       }
+       return 0;
+}
+
+void
+intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port)
+{
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       if (!intel_dp->can_mst)
+               return;
+
+       drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr);
+       /* encoders will get killed by normal cleanup */
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h
new file mode 100644 (file)
index 0000000..1470c6e
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DP_MST_H__
+#define __INTEL_DP_MST_H__
+
+struct intel_digital_port;
+
+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);
+
+#endif /* __INTEL_DP_MST_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c
new file mode 100644 (file)
index 0000000..5fec02a
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include <drm/drm_mipi_dsi.h>
+#include "intel_dsi.h"
+
+int intel_dsi_bitrate(const struct intel_dsi *intel_dsi)
+{
+       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+
+       if (WARN_ON(bpp < 0))
+               bpp = 16;
+
+       return intel_dsi->pclk * bpp / intel_dsi->lane_count;
+}
+
+int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi)
+{
+       switch (intel_dsi->escape_clk_div) {
+       default:
+       case 0:
+               return 50;
+       case 1:
+               return 100;
+       case 2:
+               return 200;
+       }
+}
+
+int intel_dsi_get_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct drm_display_mode *mode;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (!intel_connector->panel.fixed_mode) {
+               DRM_DEBUG_KMS("no fixed mode\n");
+               return 0;
+       }
+
+       mode = drm_mode_duplicate(connector->dev,
+                                 intel_connector->panel.fixed_mode);
+       if (!mode) {
+               DRM_DEBUG_KMS("drm_mode_duplicate failed\n");
+               return 0;
+       }
+
+       drm_mode_probed_add(connector, mode);
+       return 1;
+}
+
+enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
+                                         struct drm_display_mode *mode)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (fixed_mode) {
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+               if (fixed_mode->clock > max_dotclk)
+                       return MODE_CLOCK_HIGH;
+       }
+
+       return MODE_OK;
+}
+
+struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
+                                          const struct mipi_dsi_host_ops *funcs,
+                                          enum port port)
+{
+       struct intel_dsi_host *host;
+       struct mipi_dsi_device *device;
+
+       host = kzalloc(sizeof(*host), GFP_KERNEL);
+       if (!host)
+               return NULL;
+
+       host->base.ops = funcs;
+       host->intel_dsi = intel_dsi;
+       host->port = port;
+
+       /*
+        * We should call mipi_dsi_host_register(&host->base) here, but we don't
+        * have a host->dev, and we don't have OF stuff either. So just use the
+        * dsi framework as a library and hope for the best. Create the dsi
+        * devices by ourselves here too. Need to be careful though, because we
+        * don't initialize any of the driver model devices here.
+        */
+       device = kzalloc(sizeof(*device), GFP_KERNEL);
+       if (!device) {
+               kfree(host);
+               return NULL;
+       }
+
+       device->host = &host->base;
+       host->device = device;
+
+       return host;
+}
+
+enum drm_panel_orientation
+intel_dsi_get_panel_orientation(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum drm_panel_orientation orientation;
+
+       orientation = dev_priv->vbt.dsi.orientation;
+       if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+               return orientation;
+
+       orientation = dev_priv->vbt.orientation;
+       if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+               return orientation;
+
+       return DRM_MODE_PANEL_ORIENTATION_NORMAL;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h
new file mode 100644 (file)
index 0000000..6d20434
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _INTEL_DSI_H
+#define _INTEL_DSI_H
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include "intel_drv.h"
+
+#define INTEL_DSI_VIDEO_MODE   0
+#define INTEL_DSI_COMMAND_MODE 1
+
+/* Dual Link support */
+#define DSI_DUAL_LINK_NONE             0
+#define DSI_DUAL_LINK_FRONT_BACK       1
+#define DSI_DUAL_LINK_PIXEL_ALT                2
+
+struct intel_dsi_host;
+
+struct intel_dsi {
+       struct intel_encoder base;
+
+       struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
+       intel_wakeref_t io_wakeref[I915_MAX_PORTS];
+
+       /* GPIO Desc for CRC based Panel control */
+       struct gpio_desc *gpio_panel;
+
+       struct intel_connector *attached_connector;
+
+       /* bit mask of ports being driven */
+       u16 ports;
+
+       /* if true, use HS mode, otherwise LP */
+       bool hs;
+
+       /* virtual channel */
+       int channel;
+
+       /* Video mode or command mode */
+       u16 operation_mode;
+
+       /* number of DSI lanes */
+       unsigned int lane_count;
+
+       /*
+        * video mode pixel format
+        *
+        * XXX: consolidate on .format in struct mipi_dsi_device.
+        */
+       enum mipi_dsi_pixel_format pixel_format;
+
+       /* video mode format for MIPI_VIDEO_MODE_FORMAT register */
+       u32 video_mode_format;
+
+       /* eot for MIPI_EOT_DISABLE register */
+       u8 eotp_pkt;
+       u8 clock_stop;
+
+       u8 escape_clk_div;
+       u8 dual_link;
+
+       u16 dcs_backlight_ports;
+       u16 dcs_cabc_ports;
+
+       /* RGB or BGR */
+       bool bgr_enabled;
+
+       u8 pixel_overlap;
+       u32 port_bits;
+       u32 bw_timer;
+       u32 dphy_reg;
+
+       /* data lanes dphy timing */
+       u32 dphy_data_lane_reg;
+       u32 video_frmt_cfg_bits;
+       u16 lp_byte_clk;
+
+       /* timeouts in byte clocks */
+       u16 hs_tx_timeout;
+       u16 lp_rx_timeout;
+       u16 turn_arnd_val;
+       u16 rst_timer_val;
+       u16 hs_to_lp_count;
+       u16 clk_lp_to_hs_count;
+       u16 clk_hs_to_lp_count;
+
+       u16 init_count;
+       u32 pclk;
+       u16 burst_mode_ratio;
+
+       /* all delays in ms */
+       u16 backlight_off_delay;
+       u16 backlight_on_delay;
+       u16 panel_on_delay;
+       u16 panel_off_delay;
+       u16 panel_pwr_cycle_delay;
+};
+
+struct intel_dsi_host {
+       struct mipi_dsi_host base;
+       struct intel_dsi *intel_dsi;
+       enum port port;
+
+       /* our little hack */
+       struct mipi_dsi_device *device;
+};
+
+static inline struct intel_dsi_host *to_intel_dsi_host(struct mipi_dsi_host *h)
+{
+       return container_of(h, struct intel_dsi_host, base);
+}
+
+#define for_each_dsi_port(__port, __ports_mask) for_each_port_masked(__port, __ports_mask)
+
+static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
+{
+       return container_of(encoder, struct intel_dsi, base.base);
+}
+
+static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
+{
+       return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
+}
+
+static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
+{
+       return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE;
+}
+
+static inline u16 intel_dsi_encoder_ports(struct intel_encoder *encoder)
+{
+       return enc_to_intel_dsi(&encoder->base)->ports;
+}
+
+/* icl_dsi.c */
+void icl_dsi_init(struct drm_i915_private *dev_priv);
+
+/* intel_dsi.c */
+int intel_dsi_bitrate(const struct intel_dsi *intel_dsi);
+int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi);
+enum drm_panel_orientation
+intel_dsi_get_panel_orientation(struct intel_connector *connector);
+
+/* vlv_dsi.c */
+void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
+enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt);
+int intel_dsi_get_modes(struct drm_connector *connector);
+enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
+                                         struct drm_display_mode *mode);
+struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
+                                          const struct mipi_dsi_host_ops *funcs,
+                                          enum port port);
+void vlv_dsi_init(struct drm_i915_private *dev_priv);
+
+/* vlv_dsi_pll.c */
+int vlv_dsi_pll_compute(struct intel_encoder *encoder,
+                       struct intel_crtc_state *config);
+void vlv_dsi_pll_enable(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *config);
+void vlv_dsi_pll_disable(struct intel_encoder *encoder);
+u32 vlv_dsi_get_pclk(struct intel_encoder *encoder,
+                    struct intel_crtc_state *config);
+void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port);
+
+bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
+int bxt_dsi_pll_compute(struct intel_encoder *encoder,
+                       struct intel_crtc_state *config);
+void bxt_dsi_pll_enable(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *config);
+void bxt_dsi_pll_disable(struct intel_encoder *encoder);
+u32 bxt_dsi_get_pclk(struct intel_encoder *encoder,
+                    struct intel_crtc_state *config);
+void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port);
+
+/* intel_dsi_vbt.c */
+bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id);
+void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
+                                enum mipi_seq seq_id);
+void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec);
+void intel_dsi_log_params(struct intel_dsi *intel_dsi);
+
+#endif /* _INTEL_DSI_H */
diff --git a/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c b/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c
new file mode 100644 (file)
index 0000000..8c33262
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Deepak M <m.deepak at intel.com>
+ */
+
+#include <drm/drm_mipi_dsi.h>
+#include <video/mipi_display.h>
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "intel_dsi_dcs_backlight.h"
+
+#define CONTROL_DISPLAY_BCTRL          (1 << 5)
+#define CONTROL_DISPLAY_DD             (1 << 3)
+#define CONTROL_DISPLAY_BL             (1 << 2)
+
+#define POWER_SAVE_OFF                 (0 << 0)
+#define POWER_SAVE_LOW                 (1 << 0)
+#define POWER_SAVE_MEDIUM              (2 << 0)
+#define POWER_SAVE_HIGH                        (3 << 0)
+#define POWER_SAVE_OUTDOOR_MODE                (4 << 0)
+
+#define PANEL_PWM_MAX_VALUE            0xFF
+
+static u32 dcs_get_backlight(struct intel_connector *connector)
+{
+       struct intel_encoder *encoder = connector->encoder;
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct mipi_dsi_device *dsi_device;
+       u8 data = 0;
+       enum port port;
+
+       /* FIXME: Need to take care of 16 bit brightness level */
+       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
+               dsi_device = intel_dsi->dsi_hosts[port]->device;
+               mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+                                 &data, sizeof(data));
+               break;
+       }
+
+       return data;
+}
+
+static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder);
+       struct mipi_dsi_device *dsi_device;
+       u8 data = level;
+       enum port port;
+
+       /* FIXME: Need to take care of 16 bit brightness level */
+       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
+               dsi_device = intel_dsi->dsi_hosts[port]->device;
+               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
+                                  &data, sizeof(data));
+       }
+}
+
+static void dcs_disable_backlight(const struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder);
+       struct mipi_dsi_device *dsi_device;
+       enum port port;
+
+       dcs_set_backlight(conn_state, 0);
+
+       for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) {
+               u8 cabc = POWER_SAVE_OFF;
+
+               dsi_device = intel_dsi->dsi_hosts[port]->device;
+               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,
+                                  &cabc, sizeof(cabc));
+       }
+
+       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
+               u8 ctrl = 0;
+
+               dsi_device = intel_dsi->dsi_hosts[port]->device;
+
+               mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,
+                                 &ctrl, sizeof(ctrl));
+
+               ctrl &= ~CONTROL_DISPLAY_BL;
+               ctrl &= ~CONTROL_DISPLAY_DD;
+               ctrl &= ~CONTROL_DISPLAY_BCTRL;
+
+               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,
+                                  &ctrl, sizeof(ctrl));
+       }
+}
+
+static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder);
+       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
+       struct mipi_dsi_device *dsi_device;
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
+               u8 ctrl = 0;
+
+               dsi_device = intel_dsi->dsi_hosts[port]->device;
+
+               mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,
+                                 &ctrl, sizeof(ctrl));
+
+               ctrl |= CONTROL_DISPLAY_BL;
+               ctrl |= CONTROL_DISPLAY_DD;
+               ctrl |= CONTROL_DISPLAY_BCTRL;
+
+               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,
+                                  &ctrl, sizeof(ctrl));
+       }
+
+       for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) {
+               u8 cabc = POWER_SAVE_MEDIUM;
+
+               dsi_device = intel_dsi->dsi_hosts[port]->device;
+               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,
+                                  &cabc, sizeof(cabc));
+       }
+
+       dcs_set_backlight(conn_state, panel->backlight.level);
+}
+
+static int dcs_setup_backlight(struct intel_connector *connector,
+                              enum pipe unused)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       panel->backlight.max = PANEL_PWM_MAX_VALUE;
+       panel->backlight.level = PANEL_PWM_MAX_VALUE;
+
+       return 0;
+}
+
+int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector)
+{
+       struct drm_device *dev = intel_connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_encoder *encoder = intel_connector->encoder;
+       struct intel_panel *panel = &intel_connector->panel;
+
+       if (dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS)
+               return -ENODEV;
+
+       if (WARN_ON(encoder->type != INTEL_OUTPUT_DSI))
+               return -EINVAL;
+
+       panel->backlight.setup = dcs_setup_backlight;
+       panel->backlight.enable = dcs_enable_backlight;
+       panel->backlight.disable = dcs_disable_backlight;
+       panel->backlight.set = dcs_set_backlight;
+       panel->backlight.get = dcs_get_backlight;
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.h b/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.h
new file mode 100644 (file)
index 0000000..eb01947
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DSI_DCS_BACKLIGHT_H__
+#define __INTEL_DSI_DCS_BACKLIGHT_H__
+
+struct intel_connector;
+
+int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
+
+#endif /* __INTEL_DSI_DCS_BACKLIGHT_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
new file mode 100644 (file)
index 0000000..e5b1786
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Shobhit Kumar <shobhit.kumar@intel.com>
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/slab.h>
+
+#include <asm/intel-mid.h>
+#include <asm/unaligned.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/i915_drm.h>
+
+#include <video/mipi_display.h>
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "intel_sideband.h"
+
+#define MIPI_TRANSFER_MODE_SHIFT       0
+#define MIPI_VIRTUAL_CHANNEL_SHIFT     1
+#define MIPI_PORT_SHIFT                        3
+
+/* base offsets for gpio pads */
+#define VLV_GPIO_NC_0_HV_DDI0_HPD      0x4130
+#define VLV_GPIO_NC_1_HV_DDI0_DDC_SDA  0x4120
+#define VLV_GPIO_NC_2_HV_DDI0_DDC_SCL  0x4110
+#define VLV_GPIO_NC_3_PANEL0_VDDEN     0x4140
+#define VLV_GPIO_NC_4_PANEL0_BKLTEN    0x4150
+#define VLV_GPIO_NC_5_PANEL0_BKLTCTL   0x4160
+#define VLV_GPIO_NC_6_HV_DDI1_HPD      0x4180
+#define VLV_GPIO_NC_7_HV_DDI1_DDC_SDA  0x4190
+#define VLV_GPIO_NC_8_HV_DDI1_DDC_SCL  0x4170
+#define VLV_GPIO_NC_9_PANEL1_VDDEN     0x4100
+#define VLV_GPIO_NC_10_PANEL1_BKLTEN   0x40E0
+#define VLV_GPIO_NC_11_PANEL1_BKLTCTL  0x40F0
+
+#define VLV_GPIO_PCONF0(base_offset)   (base_offset)
+#define VLV_GPIO_PAD_VAL(base_offset)  ((base_offset) + 8)
+
+struct gpio_map {
+       u16 base_offset;
+       bool init;
+};
+
+static struct gpio_map vlv_gpio_table[] = {
+       { VLV_GPIO_NC_0_HV_DDI0_HPD },
+       { VLV_GPIO_NC_1_HV_DDI0_DDC_SDA },
+       { VLV_GPIO_NC_2_HV_DDI0_DDC_SCL },
+       { VLV_GPIO_NC_3_PANEL0_VDDEN },
+       { VLV_GPIO_NC_4_PANEL0_BKLTEN },
+       { VLV_GPIO_NC_5_PANEL0_BKLTCTL },
+       { VLV_GPIO_NC_6_HV_DDI1_HPD },
+       { VLV_GPIO_NC_7_HV_DDI1_DDC_SDA },
+       { VLV_GPIO_NC_8_HV_DDI1_DDC_SCL },
+       { VLV_GPIO_NC_9_PANEL1_VDDEN },
+       { VLV_GPIO_NC_10_PANEL1_BKLTEN },
+       { VLV_GPIO_NC_11_PANEL1_BKLTCTL },
+};
+
+#define CHV_GPIO_IDX_START_N           0
+#define CHV_GPIO_IDX_START_E           73
+#define CHV_GPIO_IDX_START_SW          100
+#define CHV_GPIO_IDX_START_SE          198
+
+#define CHV_VBT_MAX_PINS_PER_FMLY      15
+
+#define CHV_GPIO_PAD_CFG0(f, i)                (0x4400 + (f) * 0x400 + (i) * 8)
+#define  CHV_GPIO_GPIOEN               (1 << 15)
+#define  CHV_GPIO_GPIOCFG_GPIO         (0 << 8)
+#define  CHV_GPIO_GPIOCFG_GPO          (1 << 8)
+#define  CHV_GPIO_GPIOCFG_GPI          (2 << 8)
+#define  CHV_GPIO_GPIOCFG_HIZ          (3 << 8)
+#define  CHV_GPIO_GPIOTXSTATE(state)   ((!!(state)) << 1)
+
+#define CHV_GPIO_PAD_CFG1(f, i)                (0x4400 + (f) * 0x400 + (i) * 8 + 4)
+#define  CHV_GPIO_CFGLOCK              (1 << 31)
+
+/* ICL DSI Display GPIO Pins */
+#define  ICL_GPIO_DDSP_HPD_A           0
+#define  ICL_GPIO_L_VDDEN_1            1
+#define  ICL_GPIO_L_BKLTEN_1           2
+#define  ICL_GPIO_DDPA_CTRLCLK_1       3
+#define  ICL_GPIO_DDPA_CTRLDATA_1      4
+#define  ICL_GPIO_DDSP_HPD_B           5
+#define  ICL_GPIO_L_VDDEN_2            6
+#define  ICL_GPIO_L_BKLTEN_2           7
+#define  ICL_GPIO_DDPA_CTRLCLK_2       8
+#define  ICL_GPIO_DDPA_CTRLDATA_2      9
+
+static inline enum port intel_dsi_seq_port_to_port(u8 port)
+{
+       return port ? PORT_C : PORT_A;
+}
+
+static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
+                                      const u8 *data)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       struct mipi_dsi_device *dsi_device;
+       u8 type, flags, seq_port;
+       u16 len;
+       enum port port;
+
+       DRM_DEBUG_KMS("\n");
+
+       flags = *data++;
+       type = *data++;
+
+       len = *((u16 *) data);
+       data += 2;
+
+       seq_port = (flags >> MIPI_PORT_SHIFT) & 3;
+
+       /* For DSI single link on Port A & C, the seq_port value which is
+        * parsed from Sequence Block#53 of VBT has been set to 0
+        * Now, read/write of packets for the DSI single link on Port A and
+        * Port C will based on the DVO port from VBT block 2.
+        */
+       if (intel_dsi->ports == (1 << PORT_C))
+               port = PORT_C;
+       else
+               port = intel_dsi_seq_port_to_port(seq_port);
+
+       dsi_device = intel_dsi->dsi_hosts[port]->device;
+       if (!dsi_device) {
+               DRM_DEBUG_KMS("no dsi device for port %c\n", port_name(port));
+               goto out;
+       }
+
+       if ((flags >> MIPI_TRANSFER_MODE_SHIFT) & 1)
+               dsi_device->mode_flags &= ~MIPI_DSI_MODE_LPM;
+       else
+               dsi_device->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       dsi_device->channel = (flags >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 3;
+
+       switch (type) {
+       case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+               mipi_dsi_generic_write(dsi_device, NULL, 0);
+               break;
+       case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+               mipi_dsi_generic_write(dsi_device, data, 1);
+               break;
+       case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+               mipi_dsi_generic_write(dsi_device, data, 2);
+               break;
+       case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+               DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n");
+               break;
+       case MIPI_DSI_GENERIC_LONG_WRITE:
+               mipi_dsi_generic_write(dsi_device, data, len);
+               break;
+       case MIPI_DSI_DCS_SHORT_WRITE:
+               mipi_dsi_dcs_write_buffer(dsi_device, data, 1);
+               break;
+       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+               mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
+               break;
+       case MIPI_DSI_DCS_READ:
+               DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n");
+               break;
+       case MIPI_DSI_DCS_LONG_WRITE:
+               mipi_dsi_dcs_write_buffer(dsi_device, data, len);
+               break;
+       }
+
+       if (INTEL_GEN(dev_priv) < 11)
+               vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
+
+out:
+       data += len;
+
+       return data;
+}
+
+static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data)
+{
+       u32 delay = *((const u32 *) data);
+
+       DRM_DEBUG_KMS("\n");
+
+       usleep_range(delay, delay + 10);
+       data += 4;
+
+       return data;
+}
+
+static void vlv_exec_gpio(struct drm_i915_private *dev_priv,
+                         u8 gpio_source, u8 gpio_index, bool value)
+{
+       struct gpio_map *map;
+       u16 pconf0, padval;
+       u32 tmp;
+       u8 port;
+
+       if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) {
+               DRM_DEBUG_KMS("unknown gpio index %u\n", gpio_index);
+               return;
+       }
+
+       map = &vlv_gpio_table[gpio_index];
+
+       if (dev_priv->vbt.dsi.seq_version >= 3) {
+               /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */
+               port = IOSF_PORT_GPIO_NC;
+       } else {
+               if (gpio_source == 0) {
+                       port = IOSF_PORT_GPIO_NC;
+               } else if (gpio_source == 1) {
+                       DRM_DEBUG_KMS("SC gpio not supported\n");
+                       return;
+               } else {
+                       DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source);
+                       return;
+               }
+       }
+
+       pconf0 = VLV_GPIO_PCONF0(map->base_offset);
+       padval = VLV_GPIO_PAD_VAL(map->base_offset);
+
+       vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO));
+       if (!map->init) {
+               /* FIXME: remove constant below */
+               vlv_iosf_sb_write(dev_priv, port, pconf0, 0x2000CC00);
+               map->init = true;
+       }
+
+       tmp = 0x4 | value;
+       vlv_iosf_sb_write(dev_priv, port, padval, tmp);
+       vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO));
+}
+
+static void chv_exec_gpio(struct drm_i915_private *dev_priv,
+                         u8 gpio_source, u8 gpio_index, bool value)
+{
+       u16 cfg0, cfg1;
+       u16 family_num;
+       u8 port;
+
+       if (dev_priv->vbt.dsi.seq_version >= 3) {
+               if (gpio_index >= CHV_GPIO_IDX_START_SE) {
+                       /* XXX: it's unclear whether 255->57 is part of SE. */
+                       gpio_index -= CHV_GPIO_IDX_START_SE;
+                       port = CHV_IOSF_PORT_GPIO_SE;
+               } else if (gpio_index >= CHV_GPIO_IDX_START_SW) {
+                       gpio_index -= CHV_GPIO_IDX_START_SW;
+                       port = CHV_IOSF_PORT_GPIO_SW;
+               } else if (gpio_index >= CHV_GPIO_IDX_START_E) {
+                       gpio_index -= CHV_GPIO_IDX_START_E;
+                       port = CHV_IOSF_PORT_GPIO_E;
+               } else {
+                       port = CHV_IOSF_PORT_GPIO_N;
+               }
+       } else {
+               /* XXX: The spec is unclear about CHV GPIO on seq v2 */
+               if (gpio_source != 0) {
+                       DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source);
+                       return;
+               }
+
+               if (gpio_index >= CHV_GPIO_IDX_START_E) {
+                       DRM_DEBUG_KMS("invalid gpio index %u for GPIO N\n",
+                                     gpio_index);
+                       return;
+               }
+
+               port = CHV_IOSF_PORT_GPIO_N;
+       }
+
+       family_num = gpio_index / CHV_VBT_MAX_PINS_PER_FMLY;
+       gpio_index = gpio_index % CHV_VBT_MAX_PINS_PER_FMLY;
+
+       cfg0 = CHV_GPIO_PAD_CFG0(family_num, gpio_index);
+       cfg1 = CHV_GPIO_PAD_CFG1(family_num, gpio_index);
+
+       vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO));
+       vlv_iosf_sb_write(dev_priv, port, cfg1, 0);
+       vlv_iosf_sb_write(dev_priv, port, cfg0,
+                         CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO |
+                         CHV_GPIO_GPIOTXSTATE(value));
+       vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO));
+}
+
+static void bxt_exec_gpio(struct drm_i915_private *dev_priv,
+                         u8 gpio_source, u8 gpio_index, bool value)
+{
+       /* XXX: this table is a quick ugly hack. */
+       static struct gpio_desc *bxt_gpio_table[U8_MAX + 1];
+       struct gpio_desc *gpio_desc = bxt_gpio_table[gpio_index];
+
+       if (!gpio_desc) {
+               gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev,
+                                                NULL, gpio_index,
+                                                value ? GPIOD_OUT_LOW :
+                                                GPIOD_OUT_HIGH);
+
+               if (IS_ERR_OR_NULL(gpio_desc)) {
+                       DRM_ERROR("GPIO index %u request failed (%ld)\n",
+                                 gpio_index, PTR_ERR(gpio_desc));
+                       return;
+               }
+
+               bxt_gpio_table[gpio_index] = gpio_desc;
+       }
+
+       gpiod_set_value(gpio_desc, value);
+}
+
+static void icl_exec_gpio(struct drm_i915_private *dev_priv,
+                         u8 gpio_source, u8 gpio_index, bool value)
+{
+       DRM_DEBUG_KMS("Skipping ICL GPIO element execution\n");
+}
+
+static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u8 gpio_source, gpio_index = 0, gpio_number;
+       bool value;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (dev_priv->vbt.dsi.seq_version >= 3)
+               gpio_index = *data++;
+
+       gpio_number = *data++;
+
+       /* gpio source in sequence v2 only */
+       if (dev_priv->vbt.dsi.seq_version == 2)
+               gpio_source = (*data >> 1) & 3;
+       else
+               gpio_source = 0;
+
+       /* pull up/down */
+       value = *data++ & 1;
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_exec_gpio(dev_priv, gpio_source, gpio_index, value);
+       else if (IS_VALLEYVIEW(dev_priv))
+               vlv_exec_gpio(dev_priv, gpio_source, gpio_number, value);
+       else if (IS_CHERRYVIEW(dev_priv))
+               chv_exec_gpio(dev_priv, gpio_source, gpio_number, value);
+       else
+               bxt_exec_gpio(dev_priv, gpio_source, gpio_index, value);
+
+       return data;
+}
+
+static const u8 *mipi_exec_i2c(struct intel_dsi *intel_dsi, const u8 *data)
+{
+       DRM_DEBUG_KMS("Skipping I2C element execution\n");
+
+       return data + *(data + 6) + 7;
+}
+
+static const u8 *mipi_exec_spi(struct intel_dsi *intel_dsi, const u8 *data)
+{
+       DRM_DEBUG_KMS("Skipping SPI element execution\n");
+
+       return data + *(data + 5) + 6;
+}
+
+static const u8 *mipi_exec_pmic(struct intel_dsi *intel_dsi, const u8 *data)
+{
+#ifdef CONFIG_PMIC_OPREGION
+       u32 value, mask, reg_address;
+       u16 i2c_address;
+       int ret;
+
+       /* byte 0 aka PMIC Flag is reserved */
+       i2c_address     = get_unaligned_le16(data + 1);
+       reg_address     = get_unaligned_le32(data + 3);
+       value           = get_unaligned_le32(data + 7);
+       mask            = get_unaligned_le32(data + 11);
+
+       ret = intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address,
+                                                       reg_address,
+                                                       value, mask);
+       if (ret)
+               DRM_ERROR("%s failed, error: %d\n", __func__, ret);
+#else
+       DRM_ERROR("Your hardware requires CONFIG_PMIC_OPREGION and it is not set\n");
+#endif
+
+       return data + 15;
+}
+
+typedef const u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi,
+                                       const u8 *data);
+static const fn_mipi_elem_exec exec_elem[] = {
+       [MIPI_SEQ_ELEM_SEND_PKT] = mipi_exec_send_packet,
+       [MIPI_SEQ_ELEM_DELAY] = mipi_exec_delay,
+       [MIPI_SEQ_ELEM_GPIO] = mipi_exec_gpio,
+       [MIPI_SEQ_ELEM_I2C] = mipi_exec_i2c,
+       [MIPI_SEQ_ELEM_SPI] = mipi_exec_spi,
+       [MIPI_SEQ_ELEM_PMIC] = mipi_exec_pmic,
+};
+
+/*
+ * MIPI Sequence from VBT #53 parsing logic
+ * We have already separated each seqence during bios parsing
+ * Following is generic execution function for any sequence
+ */
+
+static const char * const seq_name[] = {
+       [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
+       [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
+       [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
+       [MIPI_SEQ_DISPLAY_OFF]  = "MIPI_SEQ_DISPLAY_OFF",
+       [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
+       [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
+       [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
+       [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
+       [MIPI_SEQ_TEAR_OFF] = "MIPI_SEQ_TEAR_OFF",
+       [MIPI_SEQ_POWER_ON] = "MIPI_SEQ_POWER_ON",
+       [MIPI_SEQ_POWER_OFF] = "MIPI_SEQ_POWER_OFF",
+};
+
+static const char *sequence_name(enum mipi_seq seq_id)
+{
+       if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id])
+               return seq_name[seq_id];
+       else
+               return "(unknown)";
+}
+
+void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
+                                enum mipi_seq seq_id)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       const u8 *data;
+       fn_mipi_elem_exec mipi_elem_exec;
+
+       if (WARN_ON(seq_id >= ARRAY_SIZE(dev_priv->vbt.dsi.sequence)))
+               return;
+
+       data = dev_priv->vbt.dsi.sequence[seq_id];
+       if (!data)
+               return;
+
+       WARN_ON(*data != seq_id);
+
+       DRM_DEBUG_KMS("Starting MIPI sequence %d - %s\n",
+                     seq_id, sequence_name(seq_id));
+
+       /* Skip Sequence Byte. */
+       data++;
+
+       /* Skip Size of Sequence. */
+       if (dev_priv->vbt.dsi.seq_version >= 3)
+               data += 4;
+
+       while (1) {
+               u8 operation_byte = *data++;
+               u8 operation_size = 0;
+
+               if (operation_byte == MIPI_SEQ_ELEM_END)
+                       break;
+
+               if (operation_byte < ARRAY_SIZE(exec_elem))
+                       mipi_elem_exec = exec_elem[operation_byte];
+               else
+                       mipi_elem_exec = NULL;
+
+               /* Size of Operation. */
+               if (dev_priv->vbt.dsi.seq_version >= 3)
+                       operation_size = *data++;
+
+               if (mipi_elem_exec) {
+                       const u8 *next = data + operation_size;
+
+                       data = mipi_elem_exec(intel_dsi, data);
+
+                       /* Consistency check if we have size. */
+                       if (operation_size && data != next) {
+                               DRM_ERROR("Inconsistent operation size\n");
+                               return;
+                       }
+               } else if (operation_size) {
+                       /* We have size, skip. */
+                       DRM_DEBUG_KMS("Unsupported MIPI operation byte %u\n",
+                                     operation_byte);
+                       data += operation_size;
+               } else {
+                       /* No size, can't skip without parsing. */
+                       DRM_ERROR("Unsupported MIPI operation byte %u\n",
+                                 operation_byte);
+                       return;
+               }
+       }
+}
+
+void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+
+       /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */
+       if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3)
+               return;
+
+       msleep(msec);
+}
+
+void intel_dsi_log_params(struct intel_dsi *intel_dsi)
+{
+       DRM_DEBUG_KMS("Pclk %d\n", intel_dsi->pclk);
+       DRM_DEBUG_KMS("Pixel overlap %d\n", intel_dsi->pixel_overlap);
+       DRM_DEBUG_KMS("Lane count %d\n", intel_dsi->lane_count);
+       DRM_DEBUG_KMS("DPHY param reg 0x%x\n", intel_dsi->dphy_reg);
+       DRM_DEBUG_KMS("Video mode format %s\n",
+                     intel_dsi->video_mode_format == VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE ?
+                     "non-burst with sync pulse" :
+                     intel_dsi->video_mode_format == VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS ?
+                     "non-burst with sync events" :
+                     intel_dsi->video_mode_format == VIDEO_MODE_BURST ?
+                     "burst" : "<unknown>");
+       DRM_DEBUG_KMS("Burst mode ratio %d\n", intel_dsi->burst_mode_ratio);
+       DRM_DEBUG_KMS("Reset timer %d\n", intel_dsi->rst_timer_val);
+       DRM_DEBUG_KMS("Eot %s\n", enableddisabled(intel_dsi->eotp_pkt));
+       DRM_DEBUG_KMS("Clockstop %s\n", enableddisabled(!intel_dsi->clock_stop));
+       DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video");
+       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+               DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n");
+       else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT)
+               DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n");
+       else
+               DRM_DEBUG_KMS("Dual link: NONE\n");
+       DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format);
+       DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div);
+       DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout);
+       DRM_DEBUG_KMS("Turnaround Timeout 0x%x\n", intel_dsi->turn_arnd_val);
+       DRM_DEBUG_KMS("Init Count 0x%x\n", intel_dsi->init_count);
+       DRM_DEBUG_KMS("HS to LP Count 0x%x\n", intel_dsi->hs_to_lp_count);
+       DRM_DEBUG_KMS("LP Byte Clock %d\n", intel_dsi->lp_byte_clk);
+       DRM_DEBUG_KMS("DBI BW Timer 0x%x\n", intel_dsi->bw_timer);
+       DRM_DEBUG_KMS("LP to HS Clock Count 0x%x\n", intel_dsi->clk_lp_to_hs_count);
+       DRM_DEBUG_KMS("HS to LP Clock Count 0x%x\n", intel_dsi->clk_hs_to_lp_count);
+       DRM_DEBUG_KMS("BTA %s\n",
+                       enableddisabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA)));
+}
+
+bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
+       struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
+       struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
+       u16 burst_mode_ratio;
+       enum port port;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1;
+       intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
+       intel_dsi->lane_count = mipi_config->lane_cnt + 1;
+       intel_dsi->pixel_format =
+                       pixel_format_from_register_bits(
+                               mipi_config->videomode_color_format << 7);
+
+       intel_dsi->dual_link = mipi_config->dual_link;
+       intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
+       intel_dsi->operation_mode = mipi_config->is_cmd_mode;
+       intel_dsi->video_mode_format = mipi_config->video_transfer_mode;
+       intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
+       intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout;
+       intel_dsi->hs_tx_timeout = mipi_config->hs_tx_timeout;
+       intel_dsi->turn_arnd_val = mipi_config->turn_around_timeout;
+       intel_dsi->rst_timer_val = mipi_config->device_reset_timer;
+       intel_dsi->init_count = mipi_config->master_init_timer;
+       intel_dsi->bw_timer = mipi_config->dbi_bw_timer;
+       intel_dsi->video_frmt_cfg_bits =
+               mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0;
+       intel_dsi->bgr_enabled = mipi_config->rgb_flip;
+
+       /* Starting point, adjusted depending on dual link and burst mode */
+       intel_dsi->pclk = mode->clock;
+
+       /* In dual link mode each port needs half of pixel clock */
+       if (intel_dsi->dual_link) {
+               intel_dsi->pclk /= 2;
+
+               /* we can enable pixel_overlap if needed by panel. In this
+                * case we need to increase the pixelclock for extra pixels
+                */
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+                       intel_dsi->pclk += DIV_ROUND_UP(mode->vtotal * intel_dsi->pixel_overlap * 60, 1000);
+               }
+       }
+
+       /* Burst Mode Ratio
+        * Target ddr frequency from VBT / non burst ddr freq
+        * multiply by 100 to preserve remainder
+        */
+       if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
+               if (mipi_config->target_burst_mode_freq) {
+                       u32 bitrate = intel_dsi_bitrate(intel_dsi);
+
+                       /*
+                        * Sometimes the VBT contains a slightly lower clock,
+                        * then the bitrate we have calculated, in this case
+                        * just replace it with the calculated bitrate.
+                        */
+                       if (mipi_config->target_burst_mode_freq < bitrate &&
+                           intel_fuzzy_clock_check(
+                                       mipi_config->target_burst_mode_freq,
+                                       bitrate))
+                               mipi_config->target_burst_mode_freq = bitrate;
+
+                       if (mipi_config->target_burst_mode_freq < bitrate) {
+                               DRM_ERROR("Burst mode freq is less than computed\n");
+                               return false;
+                       }
+
+                       burst_mode_ratio = DIV_ROUND_UP(
+                               mipi_config->target_burst_mode_freq * 100,
+                               bitrate);
+
+                       intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100);
+               } else {
+                       DRM_ERROR("Burst mode target is not set\n");
+                       return false;
+               }
+       } else
+               burst_mode_ratio = 100;
+
+       intel_dsi->burst_mode_ratio = burst_mode_ratio;
+
+       /* delays in VBT are in unit of 100us, so need to convert
+        * here in ms
+        * Delay (100us) * 100 /1000 = Delay / 10 (ms) */
+       intel_dsi->backlight_off_delay = pps->bl_disable_delay / 10;
+       intel_dsi->backlight_on_delay = pps->bl_enable_delay / 10;
+       intel_dsi->panel_on_delay = pps->panel_on_delay / 10;
+       intel_dsi->panel_off_delay = pps->panel_off_delay / 10;
+       intel_dsi->panel_pwr_cycle_delay = pps->panel_power_cycle_delay / 10;
+
+       /* a regular driver would get the device in probe */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               mipi_dsi_attach(intel_dsi->dsi_hosts[port]->device);
+       }
+
+       return true;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
new file mode 100644 (file)
index 0000000..22666d2
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_connector.h"
+#include "intel_drv.h"
+#include "intel_dvo.h"
+#include "intel_dvo_dev.h"
+#include "intel_gmbus.h"
+#include "intel_panel.h"
+
+#define INTEL_DVO_CHIP_NONE    0
+#define INTEL_DVO_CHIP_LVDS    1
+#define INTEL_DVO_CHIP_TMDS    2
+#define INTEL_DVO_CHIP_TVOUT   4
+
+#define SIL164_ADDR    0x38
+#define CH7xxx_ADDR    0x76
+#define TFP410_ADDR    0x38
+#define NS2501_ADDR     0x38
+
+static const struct intel_dvo_device intel_dvo_devices[] = {
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "sil164",
+               .dvo_reg = DVOC,
+               .dvo_srcdim_reg = DVOC_SRCDIM,
+               .slave_addr = SIL164_ADDR,
+               .dev_ops = &sil164_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "ch7xxx",
+               .dvo_reg = DVOC,
+               .dvo_srcdim_reg = DVOC_SRCDIM,
+               .slave_addr = CH7xxx_ADDR,
+               .dev_ops = &ch7xxx_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "ch7xxx",
+               .dvo_reg = DVOC,
+               .dvo_srcdim_reg = DVOC_SRCDIM,
+               .slave_addr = 0x75, /* For some ch7010 */
+               .dev_ops = &ch7xxx_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_LVDS,
+               .name = "ivch",
+               .dvo_reg = DVOA,
+               .dvo_srcdim_reg = DVOA_SRCDIM,
+               .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
+               .dev_ops = &ivch_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "tfp410",
+               .dvo_reg = DVOC,
+               .dvo_srcdim_reg = DVOC_SRCDIM,
+               .slave_addr = TFP410_ADDR,
+               .dev_ops = &tfp410_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_LVDS,
+               .name = "ch7017",
+               .dvo_reg = DVOC,
+               .dvo_srcdim_reg = DVOC_SRCDIM,
+               .slave_addr = 0x75,
+               .gpio = GMBUS_PIN_DPB,
+               .dev_ops = &ch7017_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "ns2501",
+               .dvo_reg = DVOB,
+               .dvo_srcdim_reg = DVOB_SRCDIM,
+               .slave_addr = NS2501_ADDR,
+               .dev_ops = &ns2501_ops,
+       }
+};
+
+struct intel_dvo {
+       struct intel_encoder base;
+
+       struct intel_dvo_device dev;
+
+       struct intel_connector *attached_connector;
+
+       bool panel_wants_dither;
+};
+
+static struct intel_dvo *enc_to_dvo(struct intel_encoder *encoder)
+{
+       return container_of(encoder, struct intel_dvo, base);
+}
+
+static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
+{
+       return enc_to_dvo(intel_attached_encoder(connector));
+}
+
+static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
+       u32 tmp;
+
+       tmp = I915_READ(intel_dvo->dev.dvo_reg);
+
+       if (!(tmp & DVO_ENABLE))
+               return false;
+
+       return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
+}
+
+static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       u32 tmp;
+
+       tmp = I915_READ(intel_dvo->dev.dvo_reg);
+
+       *pipe = (tmp & DVO_PIPE_SEL_MASK) >> DVO_PIPE_SEL_SHIFT;
+
+       return tmp & DVO_ENABLE;
+}
+
+static void intel_dvo_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       u32 tmp, flags = 0;
+
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_DVO);
+
+       tmp = I915_READ(intel_dvo->dev.dvo_reg);
+       if (tmp & DVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (tmp & DVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->base.adjusted_mode.flags |= flags;
+
+       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
+}
+
+static void intel_disable_dvo(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
+       u32 temp = I915_READ(dvo_reg);
+
+       intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
+       I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
+       I915_READ(dvo_reg);
+}
+
+static void intel_enable_dvo(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *pipe_config,
+                            const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
+       u32 temp = I915_READ(dvo_reg);
+
+       intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
+                                        &pipe_config->base.mode,
+                                        &pipe_config->base.adjusted_mode);
+
+       I915_WRITE(dvo_reg, temp | DVO_ENABLE);
+       I915_READ(dvo_reg);
+
+       intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
+}
+
+static enum drm_mode_status
+intel_dvo_mode_valid(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
+{
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+       const struct drm_display_mode *fixed_mode =
+               to_intel_connector(connector)->panel.fixed_mode;
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+       int target_clock = mode->clock;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       /* XXX: Validate clock range */
+
+       if (fixed_mode) {
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+
+               target_clock = fixed_mode->clock;
+       }
+
+       if (target_clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
+}
+
+static int intel_dvo_compute_config(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
+{
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       const struct drm_display_mode *fixed_mode =
+               intel_dvo->attached_connector->panel.fixed_mode;
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+
+       /*
+        * If we have timings from the BIOS for the panel, put them in
+        * to the adjusted mode.  The CRTC will be set up for this mode,
+        * with the panel scaling set up to source from the H/VDisplay
+        * of the original mode.
+        */
+       if (fixed_mode)
+               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       return 0;
+}
+
+static void intel_dvo_pre_enable(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *pipe_config,
+                                const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       int pipe = crtc->pipe;
+       u32 dvo_val;
+       i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
+       i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg;
+
+       /* Save the data order, since I don't know what it should be set to. */
+       dvo_val = I915_READ(dvo_reg) &
+                 (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
+       dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |
+                  DVO_BLANK_ACTIVE_HIGH;
+
+       dvo_val |= DVO_PIPE_SEL(pipe);
+       dvo_val |= DVO_PIPE_STALL;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               dvo_val |= DVO_HSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
+
+       /*I915_WRITE(DVOB_SRCDIM,
+         (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+         (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
+       I915_WRITE(dvo_srcdim_reg,
+                  (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+                  (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
+       /*I915_WRITE(DVOB, dvo_val);*/
+       I915_WRITE(dvo_reg, dvo_val);
+}
+
+static enum drm_connector_status
+intel_dvo_detect(struct drm_connector *connector, bool force)
+{
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+       return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
+}
+
+static int intel_dvo_get_modes(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       const struct drm_display_mode *fixed_mode =
+               to_intel_connector(connector)->panel.fixed_mode;
+
+       /*
+        * We should probably have an i2c driver get_modes function for those
+        * devices which will have a fixed set of modes determined by the chip
+        * (TV-out, for example), but for now with just TMDS and LVDS,
+        * that's not the case.
+        */
+       intel_ddc_get_modes(connector,
+                           intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPC));
+       if (!list_empty(&connector->probed_modes))
+               return 1;
+
+       if (fixed_mode) {
+               struct drm_display_mode *mode;
+               mode = drm_mode_duplicate(connector->dev, fixed_mode);
+               if (mode) {
+                       drm_mode_probed_add(connector, mode);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static const struct drm_connector_funcs intel_dvo_connector_funcs = {
+       .detect = intel_dvo_detect,
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
+       .mode_valid = intel_dvo_mode_valid,
+       .get_modes = intel_dvo_get_modes,
+};
+
+static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
+{
+       struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder));
+
+       if (intel_dvo->dev.dev_ops->destroy)
+               intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
+
+       intel_encoder_destroy(encoder);
+}
+
+static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
+       .destroy = intel_dvo_enc_destroy,
+};
+
+/*
+ * Attempts to get a fixed panel timing for LVDS (currently only the i830).
+ *
+ * Other chips with DVO LVDS will need to extend this to deal with the LVDS
+ * chip being on DVOB/C and having multiple pipes.
+ */
+static struct drm_display_mode *
+intel_dvo_get_current_mode(struct intel_encoder *encoder)
+{
+       struct drm_display_mode *mode;
+
+       mode = intel_encoder_current_mode(encoder);
+       if (mode) {
+               DRM_DEBUG_KMS("using current (BIOS) mode: ");
+               drm_mode_debug_printmodeline(mode);
+               mode->type |= DRM_MODE_TYPE_PREFERRED;
+       }
+
+       return mode;
+}
+
+static enum port intel_dvo_port(i915_reg_t dvo_reg)
+{
+       if (i915_mmio_reg_equal(dvo_reg, DVOA))
+               return PORT_A;
+       else if (i915_mmio_reg_equal(dvo_reg, DVOB))
+               return PORT_B;
+       else
+               return PORT_C;
+}
+
+void intel_dvo_init(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *intel_encoder;
+       struct intel_dvo *intel_dvo;
+       struct intel_connector *intel_connector;
+       int i;
+       int encoder_type = DRM_MODE_ENCODER_NONE;
+
+       intel_dvo = kzalloc(sizeof(*intel_dvo), GFP_KERNEL);
+       if (!intel_dvo)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(intel_dvo);
+               return;
+       }
+
+       intel_dvo->attached_connector = intel_connector;
+
+       intel_encoder = &intel_dvo->base;
+
+       intel_encoder->disable = intel_disable_dvo;
+       intel_encoder->enable = intel_enable_dvo;
+       intel_encoder->get_hw_state = intel_dvo_get_hw_state;
+       intel_encoder->get_config = intel_dvo_get_config;
+       intel_encoder->compute_config = intel_dvo_compute_config;
+       intel_encoder->pre_enable = intel_dvo_pre_enable;
+       intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
+
+       /* Now, try to find a controller */
+       for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
+               struct drm_connector *connector = &intel_connector->base;
+               const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
+               struct i2c_adapter *i2c;
+               int gpio;
+               bool dvoinit;
+               enum pipe pipe;
+               u32 dpll[I915_MAX_PIPES];
+               enum port port;
+
+               /*
+                * Allow the I2C driver info to specify the GPIO to be used in
+                * special cases, but otherwise default to what's defined
+                * in the spec.
+                */
+               if (intel_gmbus_is_valid_pin(dev_priv, dvo->gpio))
+                       gpio = dvo->gpio;
+               else if (dvo->type == INTEL_DVO_CHIP_LVDS)
+                       gpio = GMBUS_PIN_SSC;
+               else
+                       gpio = GMBUS_PIN_DPB;
+
+               /*
+                * Set up the I2C bus necessary for the chip we're probing.
+                * It appears that everything is on GPIOE except for panels
+                * on i830 laptops, which are on GPIOB (DVOA).
+                */
+               i2c = intel_gmbus_get_adapter(dev_priv, gpio);
+
+               intel_dvo->dev = *dvo;
+
+               /*
+                * GMBUS NAK handling seems to be unstable, hence let the
+                * transmitter detection run in bit banging mode for now.
+                */
+               intel_gmbus_force_bit(i2c, true);
+
+               /*
+                * ns2501 requires the DVO 2x clock before it will
+                * respond to i2c accesses, so make sure we have
+                * have the clock enabled before we attempt to
+                * initialize the device.
+                */
+               for_each_pipe(dev_priv, pipe) {
+                       dpll[pipe] = I915_READ(DPLL(pipe));
+                       I915_WRITE(DPLL(pipe), dpll[pipe] | DPLL_DVO_2X_MODE);
+               }
+
+               dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c);
+
+               /* restore the DVO 2x clock state to original */
+               for_each_pipe(dev_priv, pipe) {
+                       I915_WRITE(DPLL(pipe), dpll[pipe]);
+               }
+
+               intel_gmbus_force_bit(i2c, false);
+
+               if (!dvoinit)
+                       continue;
+
+               port = intel_dvo_port(dvo->dvo_reg);
+               drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
+                                &intel_dvo_enc_funcs, encoder_type,
+                                "DVO %c", port_name(port));
+
+               intel_encoder->type = INTEL_OUTPUT_DVO;
+               intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
+               intel_encoder->port = port;
+               intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+
+               switch (dvo->type) {
+               case INTEL_DVO_CHIP_TMDS:
+                       intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
+                               (1 << INTEL_OUTPUT_DVO);
+                       drm_connector_init(&dev_priv->drm, connector,
+                                          &intel_dvo_connector_funcs,
+                                          DRM_MODE_CONNECTOR_DVII);
+                       encoder_type = DRM_MODE_ENCODER_TMDS;
+                       break;
+               case INTEL_DVO_CHIP_LVDS:
+                       intel_encoder->cloneable = 0;
+                       drm_connector_init(&dev_priv->drm, connector,
+                                          &intel_dvo_connector_funcs,
+                                          DRM_MODE_CONNECTOR_LVDS);
+                       encoder_type = DRM_MODE_ENCODER_LVDS;
+                       break;
+               }
+
+               drm_connector_helper_add(connector,
+                                        &intel_dvo_connector_helper_funcs);
+               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+               connector->interlace_allowed = false;
+               connector->doublescan_allowed = false;
+
+               intel_connector_attach_encoder(intel_connector, intel_encoder);
+               if (dvo->type == INTEL_DVO_CHIP_LVDS) {
+                       /*
+                        * For our LVDS chipsets, we should hopefully be able
+                        * to dig the fixed panel mode out of the BIOS data.
+                        * However, it's in a different format from the BIOS
+                        * data on chipsets with integrated LVDS (stored in AIM
+                        * headers, likely), so for now, just get the current
+                        * mode being output through DVO.
+                        */
+                       intel_panel_init(&intel_connector->panel,
+                                        intel_dvo_get_current_mode(intel_encoder),
+                                        NULL);
+                       intel_dvo->panel_wants_dither = true;
+               }
+
+               return;
+       }
+
+       kfree(intel_dvo);
+       kfree(intel_connector);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.h b/drivers/gpu/drm/i915/display/intel_dvo.h
new file mode 100644 (file)
index 0000000..3ed0fdf
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_DVO_H__
+#define __INTEL_DVO_H__
+
+struct drm_i915_private;
+
+void intel_dvo_init(struct drm_i915_private *dev_priv);
+
+#endif /* __INTEL_DVO_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dvo_dev.h b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
new file mode 100644 (file)
index 0000000..94a6ae1
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright © 2006 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __INTEL_DVO_DEV_H__
+#define __INTEL_DVO_DEV_H__
+
+#include <linux/i2c.h>
+
+#include <drm/drm_crtc.h>
+
+#include "i915_reg.h"
+
+struct intel_dvo_device {
+       const char *name;
+       int type;
+       /* DVOA/B/C output register */
+       i915_reg_t dvo_reg;
+       i915_reg_t dvo_srcdim_reg;
+       /* GPIO register used for i2c bus to control this device */
+       u32 gpio;
+       int slave_addr;
+
+       const struct intel_dvo_dev_ops *dev_ops;
+       void *dev_priv;
+       struct i2c_adapter *i2c_bus;
+};
+
+struct intel_dvo_dev_ops {
+       /*
+        * Initialize the device at startup time.
+        * Returns NULL if the device does not exist.
+        */
+       bool (*init)(struct intel_dvo_device *dvo,
+                    struct i2c_adapter *i2cbus);
+
+       /*
+        * Called to allow the output a chance to create properties after the
+        * RandR objects have been created.
+        */
+       void (*create_resources)(struct intel_dvo_device *dvo);
+
+       /*
+        * Turn on/off output.
+        *
+        * Because none of our dvo drivers support an intermediate power levels,
+        * we don't expose this in the interfac.
+        */
+       void (*dpms)(struct intel_dvo_device *dvo, bool enable);
+
+       /*
+        * Callback for testing a video mode for a given output.
+        *
+        * This function should only check for cases where a mode can't
+        * be supported on the output specifically, and not represent
+        * generic CRTC limitations.
+        *
+        * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
+        */
+       int (*mode_valid)(struct intel_dvo_device *dvo,
+                         struct drm_display_mode *mode);
+
+       /*
+        * Callback for preparing mode changes on an output
+        */
+       void (*prepare)(struct intel_dvo_device *dvo);
+
+       /*
+        * Callback for committing mode changes on an output
+        */
+       void (*commit)(struct intel_dvo_device *dvo);
+
+       /*
+        * Callback for setting up a video mode after fixups have been made.
+        *
+        * This is only called while the output is disabled.  The dpms callback
+        * must be all that's necessary for the output, to turn the output on
+        * after this function is called.
+        */
+       void (*mode_set)(struct intel_dvo_device *dvo,
+                        const struct drm_display_mode *mode,
+                        const struct drm_display_mode *adjusted_mode);
+
+       /*
+        * Probe for a connected output, and return detect_status.
+        */
+       enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
+
+       /*
+        * Probe the current hw status, returning true if the connected output
+        * is active.
+        */
+       bool (*get_hw_state)(struct intel_dvo_device *dev);
+
+       /**
+        * Query the device for the modes it provides.
+        *
+        * This function may also update MonInfo, mm_width, and mm_height.
+        *
+        * \return singly-linked list of modes or NULL if no modes found.
+        */
+       struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
+
+       /**
+        * Clean up driver-specific bits of the output
+        */
+       void (*destroy) (struct intel_dvo_device *dvo);
+
+       /**
+        * Debugging hook to dump device registers to log file
+        */
+       void (*dump_regs)(struct intel_dvo_device *dvo);
+};
+
+extern const struct intel_dvo_dev_ops sil164_ops;
+extern const struct intel_dvo_dev_ops ch7xxx_ops;
+extern const struct intel_dvo_dev_ops ivch_ops;
+extern const struct intel_dvo_dev_ops tfp410_ops;
+extern const struct intel_dvo_dev_ops ch7017_ops;
+extern const struct intel_dvo_dev_ops ns2501_ops;
+
+#endif /* __INTEL_DVO_DEV_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
new file mode 100644 (file)
index 0000000..aa88e6e
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright © 2006-2008,2010 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *     Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include <linux/export.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c.h>
+
+#include <drm/drm_hdcp.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include "intel_gmbus.h"
+
+struct gmbus_pin {
+       const char *name;
+       enum i915_gpio gpio;
+};
+
+/* Map gmbus pin pairs to names and registers. */
+static const struct gmbus_pin gmbus_pins[] = {
+       [GMBUS_PIN_SSC] = { "ssc", GPIOB },
+       [GMBUS_PIN_VGADDC] = { "vga", GPIOA },
+       [GMBUS_PIN_PANEL] = { "panel", GPIOC },
+       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
+       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
+       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
+};
+
+static const struct gmbus_pin gmbus_pins_bdw[] = {
+       [GMBUS_PIN_VGADDC] = { "vga", GPIOA },
+       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
+       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
+       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
+};
+
+static const struct gmbus_pin gmbus_pins_skl[] = {
+       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
+       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
+       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
+};
+
+static const struct gmbus_pin gmbus_pins_bxt[] = {
+       [GMBUS_PIN_1_BXT] = { "dpb", GPIOB },
+       [GMBUS_PIN_2_BXT] = { "dpc", GPIOC },
+       [GMBUS_PIN_3_BXT] = { "misc", GPIOD },
+};
+
+static const struct gmbus_pin gmbus_pins_cnp[] = {
+       [GMBUS_PIN_1_BXT] = { "dpb", GPIOB },
+       [GMBUS_PIN_2_BXT] = { "dpc", GPIOC },
+       [GMBUS_PIN_3_BXT] = { "misc", GPIOD },
+       [GMBUS_PIN_4_CNP] = { "dpd", GPIOE },
+};
+
+static const struct gmbus_pin gmbus_pins_icp[] = {
+       [GMBUS_PIN_1_BXT] = { "dpa", GPIOB },
+       [GMBUS_PIN_2_BXT] = { "dpb", GPIOC },
+       [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ },
+       [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOK },
+       [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOL },
+       [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOM },
+};
+
+/* pin is expected to be valid */
+static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
+                                            unsigned int pin)
+{
+       if (HAS_PCH_ICP(dev_priv))
+               return &gmbus_pins_icp[pin];
+       else if (HAS_PCH_CNP(dev_priv))
+               return &gmbus_pins_cnp[pin];
+       else if (IS_GEN9_LP(dev_priv))
+               return &gmbus_pins_bxt[pin];
+       else if (IS_GEN9_BC(dev_priv))
+               return &gmbus_pins_skl[pin];
+       else if (IS_BROADWELL(dev_priv))
+               return &gmbus_pins_bdw[pin];
+       else
+               return &gmbus_pins[pin];
+}
+
+bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
+                             unsigned int pin)
+{
+       unsigned int size;
+
+       if (HAS_PCH_ICP(dev_priv))
+               size = ARRAY_SIZE(gmbus_pins_icp);
+       else if (HAS_PCH_CNP(dev_priv))
+               size = ARRAY_SIZE(gmbus_pins_cnp);
+       else if (IS_GEN9_LP(dev_priv))
+               size = ARRAY_SIZE(gmbus_pins_bxt);
+       else if (IS_GEN9_BC(dev_priv))
+               size = ARRAY_SIZE(gmbus_pins_skl);
+       else if (IS_BROADWELL(dev_priv))
+               size = ARRAY_SIZE(gmbus_pins_bdw);
+       else
+               size = ARRAY_SIZE(gmbus_pins);
+
+       return pin < size && get_gmbus_pin(dev_priv, pin)->name;
+}
+
+/* Intel GPIO access functions */
+
+#define I2C_RISEFALL_TIME 10
+
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
+{
+       return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+void
+intel_gmbus_reset(struct drm_i915_private *dev_priv)
+{
+       I915_WRITE(GMBUS0, 0);
+       I915_WRITE(GMBUS4, 0);
+}
+
+static void pnv_gmbus_clock_gating(struct drm_i915_private *dev_priv,
+                                  bool enable)
+{
+       u32 val;
+
+       /* When using bit bashing for I2C, this bit needs to be set to 1 */
+       val = I915_READ(DSPCLK_GATE_D);
+       if (!enable)
+               val |= PNV_GMBUSUNIT_CLOCK_GATE_DISABLE;
+       else
+               val &= ~PNV_GMBUSUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, val);
+}
+
+static void pch_gmbus_clock_gating(struct drm_i915_private *dev_priv,
+                                  bool enable)
+{
+       u32 val;
+
+       val = I915_READ(SOUTH_DSPCLK_GATE_D);
+       if (!enable)
+               val |= PCH_GMBUSUNIT_CLOCK_GATE_DISABLE;
+       else
+               val &= ~PCH_GMBUSUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
+}
+
+static void bxt_gmbus_clock_gating(struct drm_i915_private *dev_priv,
+                                  bool enable)
+{
+       u32 val;
+
+       val = I915_READ(GEN9_CLKGATE_DIS_4);
+       if (!enable)
+               val |= BXT_GMBUS_GATING_DIS;
+       else
+               val &= ~BXT_GMBUS_GATING_DIS;
+       I915_WRITE(GEN9_CLKGATE_DIS_4, val);
+}
+
+static u32 get_reserved(struct intel_gmbus *bus)
+{
+       struct drm_i915_private *i915 = bus->dev_priv;
+       struct intel_uncore *uncore = &i915->uncore;
+       u32 reserved = 0;
+
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(i915) && !IS_I845G(i915))
+               reserved = intel_uncore_read_notrace(uncore, bus->gpio_reg) &
+                          (GPIO_DATA_PULLUP_DISABLE |
+                           GPIO_CLOCK_PULLUP_DISABLE);
+
+       return reserved;
+}
+
+static int get_clock(void *data)
+{
+       struct intel_gmbus *bus = data;
+       struct intel_uncore *uncore = &bus->dev_priv->uncore;
+       u32 reserved = get_reserved(bus);
+
+       intel_uncore_write_notrace(uncore,
+                                  bus->gpio_reg,
+                                  reserved | GPIO_CLOCK_DIR_MASK);
+       intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved);
+
+       return (intel_uncore_read_notrace(uncore, bus->gpio_reg) &
+               GPIO_CLOCK_VAL_IN) != 0;
+}
+
+static int get_data(void *data)
+{
+       struct intel_gmbus *bus = data;
+       struct intel_uncore *uncore = &bus->dev_priv->uncore;
+       u32 reserved = get_reserved(bus);
+
+       intel_uncore_write_notrace(uncore,
+                                  bus->gpio_reg,
+                                  reserved | GPIO_DATA_DIR_MASK);
+       intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved);
+
+       return (intel_uncore_read_notrace(uncore, bus->gpio_reg) &
+               GPIO_DATA_VAL_IN) != 0;
+}
+
+static void set_clock(void *data, int state_high)
+{
+       struct intel_gmbus *bus = data;
+       struct intel_uncore *uncore = &bus->dev_priv->uncore;
+       u32 reserved = get_reserved(bus);
+       u32 clock_bits;
+
+       if (state_high)
+               clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
+       else
+               clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
+                            GPIO_CLOCK_VAL_MASK;
+
+       intel_uncore_write_notrace(uncore,
+                                  bus->gpio_reg,
+                                  reserved | clock_bits);
+       intel_uncore_posting_read(uncore, bus->gpio_reg);
+}
+
+static void set_data(void *data, int state_high)
+{
+       struct intel_gmbus *bus = data;
+       struct intel_uncore *uncore = &bus->dev_priv->uncore;
+       u32 reserved = get_reserved(bus);
+       u32 data_bits;
+
+       if (state_high)
+               data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
+       else
+               data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
+                       GPIO_DATA_VAL_MASK;
+
+       intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved | data_bits);
+       intel_uncore_posting_read(uncore, bus->gpio_reg);
+}
+
+static int
+intel_gpio_pre_xfer(struct i2c_adapter *adapter)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+
+       intel_gmbus_reset(dev_priv);
+
+       if (IS_PINEVIEW(dev_priv))
+               pnv_gmbus_clock_gating(dev_priv, false);
+
+       set_data(bus, 1);
+       set_clock(bus, 1);
+       udelay(I2C_RISEFALL_TIME);
+       return 0;
+}
+
+static void
+intel_gpio_post_xfer(struct i2c_adapter *adapter)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+
+       set_data(bus, 1);
+       set_clock(bus, 1);
+
+       if (IS_PINEVIEW(dev_priv))
+               pnv_gmbus_clock_gating(dev_priv, true);
+}
+
+static void
+intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
+{
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+       struct i2c_algo_bit_data *algo;
+
+       algo = &bus->bit_algo;
+
+       bus->gpio_reg = GPIO(get_gmbus_pin(dev_priv, pin)->gpio);
+       bus->adapter.algo_data = algo;
+       algo->setsda = set_data;
+       algo->setscl = set_clock;
+       algo->getsda = get_data;
+       algo->getscl = get_clock;
+       algo->pre_xfer = intel_gpio_pre_xfer;
+       algo->post_xfer = intel_gpio_post_xfer;
+       algo->udelay = I2C_RISEFALL_TIME;
+       algo->timeout = usecs_to_jiffies(2200);
+       algo->data = bus;
+}
+
+static int gmbus_wait(struct drm_i915_private *dev_priv, u32 status, u32 irq_en)
+{
+       DEFINE_WAIT(wait);
+       u32 gmbus2;
+       int ret;
+
+       /* Important: The hw handles only the first bit, so set only one! Since
+        * we also need to check for NAKs besides the hw ready/idle signal, we
+        * need to wake up periodically and check that ourselves.
+        */
+       if (!HAS_GMBUS_IRQ(dev_priv))
+               irq_en = 0;
+
+       add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+       I915_WRITE_FW(GMBUS4, irq_en);
+
+       status |= GMBUS_SATOER;
+       ret = wait_for_us((gmbus2 = I915_READ_FW(GMBUS2)) & status, 2);
+       if (ret)
+               ret = wait_for((gmbus2 = I915_READ_FW(GMBUS2)) & status, 50);
+
+       I915_WRITE_FW(GMBUS4, 0);
+       remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+
+       if (gmbus2 & GMBUS_SATOER)
+               return -ENXIO;
+
+       return ret;
+}
+
+static int
+gmbus_wait_idle(struct drm_i915_private *dev_priv)
+{
+       DEFINE_WAIT(wait);
+       u32 irq_enable;
+       int ret;
+
+       /* Important: The hw handles only the first bit, so set only one! */
+       irq_enable = 0;
+       if (HAS_GMBUS_IRQ(dev_priv))
+               irq_enable = GMBUS_IDLE_EN;
+
+       add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+       I915_WRITE_FW(GMBUS4, irq_enable);
+
+       ret = intel_wait_for_register_fw(&dev_priv->uncore,
+                                        GMBUS2, GMBUS_ACTIVE, 0,
+                                        10);
+
+       I915_WRITE_FW(GMBUS4, 0);
+       remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+
+       return ret;
+}
+
+static inline
+unsigned int gmbus_max_xfer_size(struct drm_i915_private *dev_priv)
+{
+       return INTEL_GEN(dev_priv) >= 9 ? GEN9_GMBUS_BYTE_COUNT_MAX :
+              GMBUS_BYTE_COUNT_MAX;
+}
+
+static int
+gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
+                     unsigned short addr, u8 *buf, unsigned int len,
+                     u32 gmbus0_reg, u32 gmbus1_index)
+{
+       unsigned int size = len;
+       bool burst_read = len > gmbus_max_xfer_size(dev_priv);
+       bool extra_byte_added = false;
+
+       if (burst_read) {
+               /*
+                * As per HW Spec, for 512Bytes need to read extra Byte and
+                * Ignore the extra byte read.
+                */
+               if (len == 512) {
+                       extra_byte_added = true;
+                       len++;
+               }
+               size = len % 256 + 256;
+               I915_WRITE_FW(GMBUS0, gmbus0_reg | GMBUS_BYTE_CNT_OVERRIDE);
+       }
+
+       I915_WRITE_FW(GMBUS1,
+                     gmbus1_index |
+                     GMBUS_CYCLE_WAIT |
+                     (size << GMBUS_BYTE_COUNT_SHIFT) |
+                     (addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                     GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+       while (len) {
+               int ret;
+               u32 val, loop = 0;
+
+               ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
+               if (ret)
+                       return ret;
+
+               val = I915_READ_FW(GMBUS3);
+               do {
+                       if (extra_byte_added && len == 1)
+                               break;
+
+                       *buf++ = val & 0xff;
+                       val >>= 8;
+               } while (--len && ++loop < 4);
+
+               if (burst_read && len == size - 4)
+                       /* Reset the override bit */
+                       I915_WRITE_FW(GMBUS0, gmbus0_reg);
+       }
+
+       return 0;
+}
+
+/*
+ * HW spec says that 512Bytes in Burst read need special treatment.
+ * But it doesn't talk about other multiple of 256Bytes. And couldn't locate
+ * an I2C slave, which supports such a lengthy burst read too for experiments.
+ *
+ * So until things get clarified on HW support, to avoid the burst read length
+ * in fold of 256Bytes except 512, max burst read length is fixed at 767Bytes.
+ */
+#define INTEL_GMBUS_BURST_READ_MAX_LEN         767U
+
+static int
+gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
+               u32 gmbus0_reg, u32 gmbus1_index)
+{
+       u8 *buf = msg->buf;
+       unsigned int rx_size = msg->len;
+       unsigned int len;
+       int ret;
+
+       do {
+               if (HAS_GMBUS_BURST_READ(dev_priv))
+                       len = min(rx_size, INTEL_GMBUS_BURST_READ_MAX_LEN);
+               else
+                       len = min(rx_size, gmbus_max_xfer_size(dev_priv));
+
+               ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, buf, len,
+                                           gmbus0_reg, gmbus1_index);
+               if (ret)
+                       return ret;
+
+               rx_size -= len;
+               buf += len;
+       } while (rx_size != 0);
+
+       return 0;
+}
+
+static int
+gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
+                      unsigned short addr, u8 *buf, unsigned int len,
+                      u32 gmbus1_index)
+{
+       unsigned int chunk_size = len;
+       u32 val, loop;
+
+       val = loop = 0;
+       while (len && loop < 4) {
+               val |= *buf++ << (8 * loop++);
+               len -= 1;
+       }
+
+       I915_WRITE_FW(GMBUS3, val);
+       I915_WRITE_FW(GMBUS1,
+                     gmbus1_index | GMBUS_CYCLE_WAIT |
+                     (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
+                     (addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                     GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+       while (len) {
+               int ret;
+
+               val = loop = 0;
+               do {
+                       val |= *buf++ << (8 * loop);
+               } while (--len && ++loop < 4);
+
+               I915_WRITE_FW(GMBUS3, val);
+
+               ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int
+gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
+                u32 gmbus1_index)
+{
+       u8 *buf = msg->buf;
+       unsigned int tx_size = msg->len;
+       unsigned int len;
+       int ret;
+
+       do {
+               len = min(tx_size, gmbus_max_xfer_size(dev_priv));
+
+               ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len,
+                                            gmbus1_index);
+               if (ret)
+                       return ret;
+
+               buf += len;
+               tx_size -= len;
+       } while (tx_size != 0);
+
+       return 0;
+}
+
+/*
+ * The gmbus controller can combine a 1 or 2 byte write with another read/write
+ * that immediately follows it by using an "INDEX" cycle.
+ */
+static bool
+gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num)
+{
+       return (i + 1 < num &&
+               msgs[i].addr == msgs[i + 1].addr &&
+               !(msgs[i].flags & I2C_M_RD) &&
+               (msgs[i].len == 1 || msgs[i].len == 2) &&
+               msgs[i + 1].len > 0);
+}
+
+static int
+gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs,
+                u32 gmbus0_reg)
+{
+       u32 gmbus1_index = 0;
+       u32 gmbus5 = 0;
+       int ret;
+
+       if (msgs[0].len == 2)
+               gmbus5 = GMBUS_2BYTE_INDEX_EN |
+                        msgs[0].buf[1] | (msgs[0].buf[0] << 8);
+       if (msgs[0].len == 1)
+               gmbus1_index = GMBUS_CYCLE_INDEX |
+                              (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT);
+
+       /* GMBUS5 holds 16-bit index */
+       if (gmbus5)
+               I915_WRITE_FW(GMBUS5, gmbus5);
+
+       if (msgs[1].flags & I2C_M_RD)
+               ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus0_reg,
+                                     gmbus1_index);
+       else
+               ret = gmbus_xfer_write(dev_priv, &msgs[1], gmbus1_index);
+
+       /* Clear GMBUS5 after each index transfer */
+       if (gmbus5)
+               I915_WRITE_FW(GMBUS5, 0);
+
+       return ret;
+}
+
+static int
+do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
+             u32 gmbus0_source)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+       int i = 0, inc, try = 0;
+       int ret = 0;
+
+       /* Display WA #0868: skl,bxt,kbl,cfl,glk,cnl */
+       if (IS_GEN9_LP(dev_priv))
+               bxt_gmbus_clock_gating(dev_priv, false);
+       else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_CNP(dev_priv))
+               pch_gmbus_clock_gating(dev_priv, false);
+
+retry:
+       I915_WRITE_FW(GMBUS0, gmbus0_source | bus->reg0);
+
+       for (; i < num; i += inc) {
+               inc = 1;
+               if (gmbus_is_index_xfer(msgs, i, num)) {
+                       ret = gmbus_index_xfer(dev_priv, &msgs[i],
+                                              gmbus0_source | bus->reg0);
+                       inc = 2; /* an index transmission is two msgs */
+               } else if (msgs[i].flags & I2C_M_RD) {
+                       ret = gmbus_xfer_read(dev_priv, &msgs[i],
+                                             gmbus0_source | bus->reg0, 0);
+               } else {
+                       ret = gmbus_xfer_write(dev_priv, &msgs[i], 0);
+               }
+
+               if (!ret)
+                       ret = gmbus_wait(dev_priv,
+                                        GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
+               if (ret == -ETIMEDOUT)
+                       goto timeout;
+               else if (ret)
+                       goto clear_err;
+       }
+
+       /* Generate a STOP condition on the bus. Note that gmbus can't generata
+        * a STOP on the very first cycle. To simplify the code we
+        * unconditionally generate the STOP condition with an additional gmbus
+        * cycle. */
+       I915_WRITE_FW(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+
+       /* Mark the GMBUS interface as disabled after waiting for idle.
+        * We will re-enable it at the start of the next xfer,
+        * till then let it sleep.
+        */
+       if (gmbus_wait_idle(dev_priv)) {
+               DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
+                        adapter->name);
+               ret = -ETIMEDOUT;
+       }
+       I915_WRITE_FW(GMBUS0, 0);
+       ret = ret ?: i;
+       goto out;
+
+clear_err:
+       /*
+        * Wait for bus to IDLE before clearing NAK.
+        * If we clear the NAK while bus is still active, then it will stay
+        * active and the next transaction may fail.
+        *
+        * If no ACK is received during the address phase of a transaction, the
+        * adapter must report -ENXIO. It is not clear what to return if no ACK
+        * is received at other times. But we have to be careful to not return
+        * spurious -ENXIO because that will prevent i2c and drm edid functions
+        * from retrying. So return -ENXIO only when gmbus properly quiescents -
+        * timing out seems to happen when there _is_ a ddc chip present, but
+        * it's slow responding and only answers on the 2nd retry.
+        */
+       ret = -ENXIO;
+       if (gmbus_wait_idle(dev_priv)) {
+               DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
+                             adapter->name);
+               ret = -ETIMEDOUT;
+       }
+
+       /* Toggle the Software Clear Interrupt bit. This has the effect
+        * of resetting the GMBUS controller and so clearing the
+        * BUS_ERROR raised by the slave's NAK.
+        */
+       I915_WRITE_FW(GMBUS1, GMBUS_SW_CLR_INT);
+       I915_WRITE_FW(GMBUS1, 0);
+       I915_WRITE_FW(GMBUS0, 0);
+
+       DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
+                        adapter->name, msgs[i].addr,
+                        (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
+
+       /*
+        * Passive adapters sometimes NAK the first probe. Retry the first
+        * message once on -ENXIO for GMBUS transfers; the bit banging algorithm
+        * has retries internally. See also the retry loop in
+        * drm_do_probe_ddc_edid, which bails out on the first -ENXIO.
+        */
+       if (ret == -ENXIO && i == 0 && try++ == 0) {
+               DRM_DEBUG_KMS("GMBUS [%s] NAK on first message, retry\n",
+                             adapter->name);
+               goto retry;
+       }
+
+       goto out;
+
+timeout:
+       DRM_DEBUG_KMS("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
+                     bus->adapter.name, bus->reg0 & 0xff);
+       I915_WRITE_FW(GMBUS0, 0);
+
+       /*
+        * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
+        * instead. Use EAGAIN to have i2c core retry.
+        */
+       ret = -EAGAIN;
+
+out:
+       /* Display WA #0868: skl,bxt,kbl,cfl,glk,cnl */
+       if (IS_GEN9_LP(dev_priv))
+               bxt_gmbus_clock_gating(dev_priv, true);
+       else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_CNP(dev_priv))
+               pch_gmbus_clock_gating(dev_priv, true);
+
+       return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+       struct intel_gmbus *bus =
+               container_of(adapter, struct intel_gmbus, adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+       intel_wakeref_t wakeref;
+       int ret;
+
+       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+
+       if (bus->force_bit) {
+               ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
+               if (ret < 0)
+                       bus->force_bit &= ~GMBUS_FORCE_BIT_RETRY;
+       } else {
+               ret = do_gmbus_xfer(adapter, msgs, num, 0);
+               if (ret == -EAGAIN)
+                       bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
+       }
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
+
+       return ret;
+}
+
+int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
+{
+       struct intel_gmbus *bus =
+               container_of(adapter, struct intel_gmbus, adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+       u8 cmd = DRM_HDCP_DDC_AKSV;
+       u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = DRM_HDCP_DDC_ADDR,
+                       .flags = 0,
+                       .len = sizeof(cmd),
+                       .buf = &cmd,
+               },
+               {
+                       .addr = DRM_HDCP_DDC_ADDR,
+                       .flags = 0,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+       intel_wakeref_t wakeref;
+       int ret;
+
+       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+       mutex_lock(&dev_priv->gmbus_mutex);
+
+       /*
+        * In order to output Aksv to the receiver, use an indexed write to
+        * pass the i2c command, and tell GMBUS to use the HW-provided value
+        * instead of sourcing GMBUS3 for the data.
+        */
+       ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
+
+       mutex_unlock(&dev_priv->gmbus_mutex);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
+
+       return ret;
+}
+
+static u32 gmbus_func(struct i2c_adapter *adapter)
+{
+       return i2c_bit_algo.functionality(adapter) &
+               (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+               /* I2C_FUNC_10BIT_ADDR | */
+               I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+               I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
+}
+
+static const struct i2c_algorithm gmbus_algorithm = {
+       .master_xfer    = gmbus_xfer,
+       .functionality  = gmbus_func
+};
+
+static void gmbus_lock_bus(struct i2c_adapter *adapter,
+                          unsigned int flags)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+
+       mutex_lock(&dev_priv->gmbus_mutex);
+}
+
+static int gmbus_trylock_bus(struct i2c_adapter *adapter,
+                            unsigned int flags)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+
+       return mutex_trylock(&dev_priv->gmbus_mutex);
+}
+
+static void gmbus_unlock_bus(struct i2c_adapter *adapter,
+                            unsigned int flags)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+
+       mutex_unlock(&dev_priv->gmbus_mutex);
+}
+
+static const struct i2c_lock_operations gmbus_lock_ops = {
+       .lock_bus =    gmbus_lock_bus,
+       .trylock_bus = gmbus_trylock_bus,
+       .unlock_bus =  gmbus_unlock_bus,
+};
+
+/**
+ * intel_gmbus_setup - instantiate all Intel i2c GMBuses
+ * @dev_priv: i915 device private
+ */
+int intel_gmbus_setup(struct drm_i915_private *dev_priv)
+{
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       struct intel_gmbus *bus;
+       unsigned int pin;
+       int ret;
+
+       if (!HAS_DISPLAY(dev_priv))
+               return 0;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
+       else if (!HAS_GMCH(dev_priv))
+               /*
+                * Broxton uses the same PCH offsets for South Display Engine,
+                * even though it doesn't have a PCH.
+                */
+               dev_priv->gpio_mmio_base = PCH_DISPLAY_BASE;
+
+       mutex_init(&dev_priv->gmbus_mutex);
+       init_waitqueue_head(&dev_priv->gmbus_wait_queue);
+
+       for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
+               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
+                       continue;
+
+               bus = &dev_priv->gmbus[pin];
+
+               bus->adapter.owner = THIS_MODULE;
+               bus->adapter.class = I2C_CLASS_DDC;
+               snprintf(bus->adapter.name,
+                        sizeof(bus->adapter.name),
+                        "i915 gmbus %s",
+                        get_gmbus_pin(dev_priv, pin)->name);
+
+               bus->adapter.dev.parent = &pdev->dev;
+               bus->dev_priv = dev_priv;
+
+               bus->adapter.algo = &gmbus_algorithm;
+               bus->adapter.lock_ops = &gmbus_lock_ops;
+
+               /*
+                * We wish to retry with bit banging
+                * after a timed out GMBUS attempt.
+                */
+               bus->adapter.retries = 1;
+
+               /* By default use a conservative clock rate */
+               bus->reg0 = pin | GMBUS_RATE_100KHZ;
+
+               /* gmbus seems to be broken on i830 */
+               if (IS_I830(dev_priv))
+                       bus->force_bit = 1;
+
+               intel_gpio_setup(bus, pin);
+
+               ret = i2c_add_adapter(&bus->adapter);
+               if (ret)
+                       goto err;
+       }
+
+       intel_gmbus_reset(dev_priv);
+
+       return 0;
+
+err:
+       while (pin--) {
+               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
+                       continue;
+
+               bus = &dev_priv->gmbus[pin];
+               i2c_del_adapter(&bus->adapter);
+       }
+       return ret;
+}
+
+struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
+                                           unsigned int pin)
+{
+       if (WARN_ON(!intel_gmbus_is_valid_pin(dev_priv, pin)))
+               return NULL;
+
+       return &dev_priv->gmbus[pin].adapter;
+}
+
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+       bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | speed;
+}
+
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+
+       mutex_lock(&dev_priv->gmbus_mutex);
+
+       bus->force_bit += force_bit ? 1 : -1;
+       DRM_DEBUG_KMS("%sabling bit-banging on %s. force bit now %d\n",
+                     force_bit ? "en" : "dis", adapter->name,
+                     bus->force_bit);
+
+       mutex_unlock(&dev_priv->gmbus_mutex);
+}
+
+bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+       return bus->force_bit;
+}
+
+void intel_gmbus_teardown(struct drm_i915_private *dev_priv)
+{
+       struct intel_gmbus *bus;
+       unsigned int pin;
+
+       for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
+               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
+                       continue;
+
+               bus = &dev_priv->gmbus[pin];
+               i2c_del_adapter(&bus->adapter);
+       }
+}
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.h b/drivers/gpu/drm/i915/display/intel_gmbus.h
new file mode 100644 (file)
index 0000000..d989085
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_GMBUS_H__
+#define __INTEL_GMBUS_H__
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+struct i2c_adapter;
+
+int intel_gmbus_setup(struct drm_i915_private *dev_priv);
+void intel_gmbus_teardown(struct drm_i915_private *dev_priv);
+bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
+                             unsigned int pin);
+int intel_gmbus_output_aksv(struct i2c_adapter *adapter);
+
+struct i2c_adapter *
+intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
+bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter);
+void intel_gmbus_reset(struct drm_i915_private *dev_priv);
+
+#endif /* __INTEL_GMBUS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
new file mode 100644 (file)
index 0000000..187a2b8
--- /dev/null
@@ -0,0 +1,3204 @@
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright © 2006-2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *     Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_hdcp.h>
+#include <drm/drm_scdc_helper.h>
+#include <drm/i915_drm.h>
+#include <drm/intel_lpe_audio.h>
+
+#include "i915_debugfs.h"
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_audio.h"
+#include "intel_connector.h"
+#include "intel_ddi.h"
+#include "intel_dp.h"
+#include "intel_dpio_phy.h"
+#include "intel_drv.h"
+#include "intel_fifo_underrun.h"
+#include "intel_gmbus.h"
+#include "intel_hdcp.h"
+#include "intel_hdmi.h"
+#include "intel_hotplug.h"
+#include "intel_lspcon.h"
+#include "intel_sdvo.h"
+#include "intel_panel.h"
+#include "intel_sideband.h"
+
+static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
+{
+       return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
+}
+
+static void
+assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
+{
+       struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 enabled_bits;
+
+       enabled_bits = HAS_DDI(dev_priv) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
+
+       WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
+            "HDMI port enabled, expecting disabled\n");
+}
+
+static void
+assert_hdmi_transcoder_func_disabled(struct drm_i915_private *dev_priv,
+                                    enum transcoder cpu_transcoder)
+{
+       WARN(I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)) &
+            TRANS_DDI_FUNC_ENABLE,
+            "HDMI transcoder function enabled, expecting disabled\n");
+}
+
+struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
+{
+       struct intel_digital_port *intel_dig_port =
+               container_of(encoder, struct intel_digital_port, base.base);
+       return &intel_dig_port->hdmi;
+}
+
+static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
+{
+       return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base);
+}
+
+static u32 g4x_infoframe_index(unsigned int type)
+{
+       switch (type) {
+       case HDMI_PACKET_TYPE_GAMUT_METADATA:
+               return VIDEO_DIP_SELECT_GAMUT;
+       case HDMI_INFOFRAME_TYPE_AVI:
+               return VIDEO_DIP_SELECT_AVI;
+       case HDMI_INFOFRAME_TYPE_SPD:
+               return VIDEO_DIP_SELECT_SPD;
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               return VIDEO_DIP_SELECT_VENDOR;
+       default:
+               MISSING_CASE(type);
+               return 0;
+       }
+}
+
+static u32 g4x_infoframe_enable(unsigned int type)
+{
+       switch (type) {
+       case HDMI_PACKET_TYPE_GENERAL_CONTROL:
+               return VIDEO_DIP_ENABLE_GCP;
+       case HDMI_PACKET_TYPE_GAMUT_METADATA:
+               return VIDEO_DIP_ENABLE_GAMUT;
+       case DP_SDP_VSC:
+               return 0;
+       case HDMI_INFOFRAME_TYPE_AVI:
+               return VIDEO_DIP_ENABLE_AVI;
+       case HDMI_INFOFRAME_TYPE_SPD:
+               return VIDEO_DIP_ENABLE_SPD;
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               return VIDEO_DIP_ENABLE_VENDOR;
+       case HDMI_INFOFRAME_TYPE_DRM:
+               return 0;
+       default:
+               MISSING_CASE(type);
+               return 0;
+       }
+}
+
+static u32 hsw_infoframe_enable(unsigned int type)
+{
+       switch (type) {
+       case HDMI_PACKET_TYPE_GENERAL_CONTROL:
+               return VIDEO_DIP_ENABLE_GCP_HSW;
+       case HDMI_PACKET_TYPE_GAMUT_METADATA:
+               return VIDEO_DIP_ENABLE_GMP_HSW;
+       case DP_SDP_VSC:
+               return VIDEO_DIP_ENABLE_VSC_HSW;
+       case DP_SDP_PPS:
+               return VDIP_ENABLE_PPS;
+       case HDMI_INFOFRAME_TYPE_AVI:
+               return VIDEO_DIP_ENABLE_AVI_HSW;
+       case HDMI_INFOFRAME_TYPE_SPD:
+               return VIDEO_DIP_ENABLE_SPD_HSW;
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               return VIDEO_DIP_ENABLE_VS_HSW;
+       case HDMI_INFOFRAME_TYPE_DRM:
+               return VIDEO_DIP_ENABLE_DRM_GLK;
+       default:
+               MISSING_CASE(type);
+               return 0;
+       }
+}
+
+static i915_reg_t
+hsw_dip_data_reg(struct drm_i915_private *dev_priv,
+                enum transcoder cpu_transcoder,
+                unsigned int type,
+                int i)
+{
+       switch (type) {
+       case HDMI_PACKET_TYPE_GAMUT_METADATA:
+               return HSW_TVIDEO_DIP_GMP_DATA(cpu_transcoder, i);
+       case DP_SDP_VSC:
+               return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i);
+       case DP_SDP_PPS:
+               return ICL_VIDEO_DIP_PPS_DATA(cpu_transcoder, i);
+       case HDMI_INFOFRAME_TYPE_AVI:
+               return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder, i);
+       case HDMI_INFOFRAME_TYPE_SPD:
+               return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder, i);
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
+       case HDMI_INFOFRAME_TYPE_DRM:
+               return GLK_TVIDEO_DIP_DRM_DATA(cpu_transcoder, i);
+       default:
+               MISSING_CASE(type);
+               return INVALID_MMIO_REG;
+       }
+}
+
+static int hsw_dip_data_size(unsigned int type)
+{
+       switch (type) {
+       case DP_SDP_VSC:
+               return VIDEO_DIP_VSC_DATA_SIZE;
+       case DP_SDP_PPS:
+               return VIDEO_DIP_PPS_DATA_SIZE;
+       default:
+               return VIDEO_DIP_DATA_SIZE;
+       }
+}
+
+static void g4x_write_infoframe(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *crtc_state,
+                               unsigned int type,
+                               const void *frame, ssize_t len)
+{
+       const u32 *data = frame;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val = I915_READ(VIDEO_DIP_CTL);
+       int i;
+
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       val &= ~g4x_infoframe_enable(type);
+
+       I915_WRITE(VIDEO_DIP_CTL, val);
+
+       for (i = 0; i < len; i += 4) {
+               I915_WRITE(VIDEO_DIP_DATA, *data);
+               data++;
+       }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(VIDEO_DIP_DATA, 0);
+
+       val |= g4x_infoframe_enable(type);
+       val &= ~VIDEO_DIP_FREQ_MASK;
+       val |= VIDEO_DIP_FREQ_VSYNC;
+
+       I915_WRITE(VIDEO_DIP_CTL, val);
+       POSTING_READ(VIDEO_DIP_CTL);
+}
+
+static void g4x_read_infoframe(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              unsigned int type,
+                              void *frame, ssize_t len)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val, *data = frame;
+       int i;
+
+       val = I915_READ(VIDEO_DIP_CTL);
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       I915_WRITE(VIDEO_DIP_CTL, val);
+
+       for (i = 0; i < len; i += 4)
+               *data++ = I915_READ(VIDEO_DIP_DATA);
+}
+
+static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val = I915_READ(VIDEO_DIP_CTL);
+
+       if ((val & VIDEO_DIP_ENABLE) == 0)
+               return 0;
+
+       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
+               return 0;
+
+       return val & (VIDEO_DIP_ENABLE_AVI |
+                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
+}
+
+static void ibx_write_infoframe(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *crtc_state,
+                               unsigned int type,
+                               const void *frame, ssize_t len)
+{
+       const u32 *data = frame;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+       int i;
+
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       val &= ~g4x_infoframe_enable(type);
+
+       I915_WRITE(reg, val);
+
+       for (i = 0; i < len; i += 4) {
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
+               data++;
+       }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
+
+       val |= g4x_infoframe_enable(type);
+       val &= ~VIDEO_DIP_FREQ_MASK;
+       val |= VIDEO_DIP_FREQ_VSYNC;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+}
+
+static void ibx_read_infoframe(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              unsigned int type,
+                              void *frame, ssize_t len)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       u32 val, *data = frame;
+       int i;
+
+       val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
+
+       for (i = 0; i < len; i += 4)
+               *data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
+}
+
+static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
+       i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
+       u32 val = I915_READ(reg);
+
+       if ((val & VIDEO_DIP_ENABLE) == 0)
+               return 0;
+
+       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
+               return 0;
+
+       return val & (VIDEO_DIP_ENABLE_AVI |
+                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                     VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+}
+
+static void cpt_write_infoframe(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *crtc_state,
+                               unsigned int type,
+                               const void *frame, ssize_t len)
+{
+       const u32 *data = frame;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+       int i;
+
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       /* The DIP control register spec says that we need to update the AVI
+        * infoframe without clearing its enable bit */
+       if (type != HDMI_INFOFRAME_TYPE_AVI)
+               val &= ~g4x_infoframe_enable(type);
+
+       I915_WRITE(reg, val);
+
+       for (i = 0; i < len; i += 4) {
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
+               data++;
+       }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
+
+       val |= g4x_infoframe_enable(type);
+       val &= ~VIDEO_DIP_FREQ_MASK;
+       val |= VIDEO_DIP_FREQ_VSYNC;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+}
+
+static void cpt_read_infoframe(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              unsigned int type,
+                              void *frame, ssize_t len)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       u32 val, *data = frame;
+       int i;
+
+       val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
+
+       for (i = 0; i < len; i += 4)
+               *data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
+}
+
+static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
+       u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
+
+       if ((val & VIDEO_DIP_ENABLE) == 0)
+               return 0;
+
+       return val & (VIDEO_DIP_ENABLE_AVI |
+                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                     VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+}
+
+static void vlv_write_infoframe(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *crtc_state,
+                               unsigned int type,
+                               const void *frame, ssize_t len)
+{
+       const u32 *data = frame;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+       int i;
+
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       val &= ~g4x_infoframe_enable(type);
+
+       I915_WRITE(reg, val);
+
+       for (i = 0; i < len; i += 4) {
+               I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
+               data++;
+       }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
+
+       val |= g4x_infoframe_enable(type);
+       val &= ~VIDEO_DIP_FREQ_MASK;
+       val |= VIDEO_DIP_FREQ_VSYNC;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+}
+
+static void vlv_read_infoframe(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              unsigned int type,
+                              void *frame, ssize_t len)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       u32 val, *data = frame;
+       int i;
+
+       val = I915_READ(VLV_TVIDEO_DIP_CTL(crtc->pipe));
+
+       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+       val |= g4x_infoframe_index(type);
+
+       I915_WRITE(VLV_TVIDEO_DIP_CTL(crtc->pipe), val);
+
+       for (i = 0; i < len; i += 4)
+               *data++ = I915_READ(VLV_TVIDEO_DIP_DATA(crtc->pipe));
+}
+
+static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
+       u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
+
+       if ((val & VIDEO_DIP_ENABLE) == 0)
+               return 0;
+
+       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
+               return 0;
+
+       return val & (VIDEO_DIP_ENABLE_AVI |
+                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                     VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+}
+
+static void hsw_write_infoframe(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *crtc_state,
+                               unsigned int type,
+                               const void *frame, ssize_t len)
+{
+       const u32 *data = frame;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
+       int data_size;
+       int i;
+       u32 val = I915_READ(ctl_reg);
+
+       data_size = hsw_dip_data_size(type);
+
+       val &= ~hsw_infoframe_enable(type);
+       I915_WRITE(ctl_reg, val);
+
+       for (i = 0; i < len; i += 4) {
+               I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
+                                           type, i >> 2), *data);
+               data++;
+       }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < data_size; i += 4)
+               I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
+                                           type, i >> 2), 0);
+
+       val |= hsw_infoframe_enable(type);
+       I915_WRITE(ctl_reg, val);
+       POSTING_READ(ctl_reg);
+}
+
+static void hsw_read_infoframe(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state,
+                              unsigned int type,
+                              void *frame, ssize_t len)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 val, *data = frame;
+       int i;
+
+       val = I915_READ(HSW_TVIDEO_DIP_CTL(cpu_transcoder));
+
+       for (i = 0; i < len; i += 4)
+               *data++ = I915_READ(hsw_dip_data_reg(dev_priv, cpu_transcoder,
+                                                    type, i >> 2));
+}
+
+static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
+       u32 mask;
+
+       mask = (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
+               VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
+               VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
+
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               mask |= VIDEO_DIP_ENABLE_DRM_GLK;
+
+       return val & mask;
+}
+
+static const u8 infoframe_type_to_idx[] = {
+       HDMI_PACKET_TYPE_GENERAL_CONTROL,
+       HDMI_PACKET_TYPE_GAMUT_METADATA,
+       DP_SDP_VSC,
+       HDMI_INFOFRAME_TYPE_AVI,
+       HDMI_INFOFRAME_TYPE_SPD,
+       HDMI_INFOFRAME_TYPE_VENDOR,
+       HDMI_INFOFRAME_TYPE_DRM,
+};
+
+u32 intel_hdmi_infoframe_enable(unsigned int type)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
+               if (infoframe_type_to_idx[i] == type)
+                       return BIT(i);
+       }
+
+       return 0;
+}
+
+u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       u32 val, ret = 0;
+       int i;
+
+       val = dig_port->infoframes_enabled(encoder, crtc_state);
+
+       /* map from hardware bits to dip idx */
+       for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
+               unsigned int type = infoframe_type_to_idx[i];
+
+               if (HAS_DDI(dev_priv)) {
+                       if (val & hsw_infoframe_enable(type))
+                               ret |= BIT(i);
+               } else {
+                       if (val & g4x_infoframe_enable(type))
+                               ret |= BIT(i);
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * The data we write to the DIP data buffer registers is 1 byte bigger than the
+ * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
+ * at 0). It's also a byte used by DisplayPort so the same DIP registers can be
+ * used for both technologies.
+ *
+ * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0
+ * DW1:       DB3       | DB2 | DB1 | DB0
+ * DW2:       DB7       | DB6 | DB5 | DB4
+ * DW3: ...
+ *
+ * (HB is Header Byte, DB is Data Byte)
+ *
+ * The hdmi pack() functions don't know about that hardware specific hole so we
+ * trick them by giving an offset into the buffer and moving back the header
+ * bytes by one.
+ */
+static void intel_write_infoframe(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state,
+                                 enum hdmi_infoframe_type type,
+                                 const union hdmi_infoframe *frame)
+{
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+       u8 buffer[VIDEO_DIP_DATA_SIZE];
+       ssize_t len;
+
+       if ((crtc_state->infoframes.enable &
+            intel_hdmi_infoframe_enable(type)) == 0)
+               return;
+
+       if (WARN_ON(frame->any.type != type))
+               return;
+
+       /* see comment above for the reason for this offset */
+       len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1);
+       if (WARN_ON(len < 0))
+               return;
+
+       /* Insert the 'hole' (see big comment above) at position 3 */
+       memmove(&buffer[0], &buffer[1], 3);
+       buffer[3] = 0;
+       len++;
+
+       intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
+}
+
+void intel_read_infoframe(struct intel_encoder *encoder,
+                         const struct intel_crtc_state *crtc_state,
+                         enum hdmi_infoframe_type type,
+                         union hdmi_infoframe *frame)
+{
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+       u8 buffer[VIDEO_DIP_DATA_SIZE];
+       int ret;
+
+       if ((crtc_state->infoframes.enable &
+            intel_hdmi_infoframe_enable(type)) == 0)
+               return;
+
+       intel_dig_port->read_infoframe(encoder, crtc_state,
+                                      type, buffer, sizeof(buffer));
+
+       /* Fill the 'hole' (see big comment above) at position 3 */
+       memmove(&buffer[1], &buffer[0], 3);
+
+       /* see comment above for the reason for this offset */
+       ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1);
+       if (ret) {
+               DRM_DEBUG_KMS("Failed to unpack infoframe type 0x%02x\n", type);
+               return;
+       }
+
+       if (frame->any.type != type)
+               DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
+                             frame->any.type, type);
+}
+
+static bool
+intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
+                                struct intel_crtc_state *crtc_state,
+                                struct drm_connector_state *conn_state)
+{
+       struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       struct drm_connector *connector = conn_state->connector;
+       int ret;
+
+       if (!crtc_state->has_infoframe)
+               return true;
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector,
+                                                      adjusted_mode);
+       if (ret)
+               return false;
+
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+               frame->colorspace = HDMI_COLORSPACE_YUV420;
+       else if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+               frame->colorspace = HDMI_COLORSPACE_YUV444;
+       else
+               frame->colorspace = HDMI_COLORSPACE_RGB;
+
+       drm_hdmi_avi_infoframe_colorspace(frame, conn_state);
+
+       drm_hdmi_avi_infoframe_quant_range(frame, connector,
+                                          adjusted_mode,
+                                          crtc_state->limited_color_range ?
+                                          HDMI_QUANTIZATION_RANGE_LIMITED :
+                                          HDMI_QUANTIZATION_RANGE_FULL);
+
+       drm_hdmi_avi_infoframe_content_type(frame, conn_state);
+
+       /* TODO: handle pixel repetition for YCBCR420 outputs */
+
+       ret = hdmi_avi_infoframe_check(frame);
+       if (WARN_ON(ret))
+               return false;
+
+       return true;
+}
+
+static bool
+intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
+                                struct intel_crtc_state *crtc_state,
+                                struct drm_connector_state *conn_state)
+{
+       struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd;
+       int ret;
+
+       if (!crtc_state->has_infoframe)
+               return true;
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD);
+
+       ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
+       if (WARN_ON(ret))
+               return false;
+
+       frame->sdi = HDMI_SPD_SDI_PC;
+
+       ret = hdmi_spd_infoframe_check(frame);
+       if (WARN_ON(ret))
+               return false;
+
+       return true;
+}
+
+static bool
+intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *crtc_state,
+                                 struct drm_connector_state *conn_state)
+{
+       struct hdmi_vendor_infoframe *frame =
+               &crtc_state->infoframes.hdmi.vendor.hdmi;
+       const struct drm_display_info *info =
+               &conn_state->connector->display_info;
+       int ret;
+
+       if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe)
+               return true;
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR);
+
+       ret = drm_hdmi_vendor_infoframe_from_display_mode(frame,
+                                                         conn_state->connector,
+                                                         &crtc_state->base.adjusted_mode);
+       if (WARN_ON(ret))
+               return false;
+
+       ret = hdmi_vendor_infoframe_check(frame);
+       if (WARN_ON(ret))
+               return false;
+
+       return true;
+}
+
+static bool
+intel_hdmi_compute_drm_infoframe(struct intel_encoder *encoder,
+                                struct intel_crtc_state *crtc_state,
+                                struct drm_connector_state *conn_state)
+{
+       struct hdmi_drm_infoframe *frame = &crtc_state->infoframes.drm.drm;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       int ret;
+
+       if (!(INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)))
+               return true;
+
+       if (!crtc_state->has_infoframe)
+               return true;
+
+       if (!conn_state->hdr_output_metadata)
+               return true;
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_DRM);
+
+       ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("couldn't set HDR metadata in infoframe\n");
+               return false;
+       }
+
+       ret = hdmi_drm_infoframe_check(frame);
+       if (WARN_ON(ret))
+               return false;
+
+       return true;
+}
+
+static void g4x_set_infoframes(struct intel_encoder *encoder,
+                              bool enable,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
+       i915_reg_t reg = VIDEO_DIP_CTL;
+       u32 val = I915_READ(reg);
+       u32 port = VIDEO_DIP_PORT(encoder->port);
+
+       assert_hdmi_port_disabled(intel_hdmi);
+
+       /* If the registers were not initialized yet, they might be zeroes,
+        * which means we're selecting the AVI DIP and we're setting its
+        * frequency to once. This seems to really confuse the HW and make
+        * things stop working (the register spec says the AVI always needs to
+        * be sent every VSync). So here we avoid writing to the register more
+        * than we need and also explicitly select the AVI DIP and explicitly
+        * set its frequency to every VSync. Avoiding to write it twice seems to
+        * be enough to solve the problem, but being defensive shouldn't hurt us
+        * either. */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!enable) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               if (port != (val & VIDEO_DIP_PORT_MASK)) {
+                       DRM_DEBUG_KMS("video DIP still enabled on port %c\n",
+                                     (val & VIDEO_DIP_PORT_MASK) >> 29);
+                       return;
+               }
+               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
+                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       if (port != (val & VIDEO_DIP_PORT_MASK)) {
+               if (val & VIDEO_DIP_ENABLE) {
+                       DRM_DEBUG_KMS("video DIP already enabled on port %c\n",
+                                     (val & VIDEO_DIP_PORT_MASK) >> 29);
+                       return;
+               }
+               val &= ~VIDEO_DIP_PORT_MASK;
+               val |= port;
+       }
+
+       val |= VIDEO_DIP_ENABLE;
+       val &= ~(VIDEO_DIP_ENABLE_AVI |
+                VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_AVI,
+                             &crtc_state->infoframes.avi);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_SPD,
+                             &crtc_state->infoframes.spd);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_VENDOR,
+                             &crtc_state->infoframes.hdmi);
+}
+
+/*
+ * Determine if default_phase=1 can be indicated in the GCP infoframe.
+ *
+ * From HDMI specification 1.4a:
+ * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0
+ * - The first pixel following each Video Data Period shall have a pixel packing phase of 0
+ * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase
+ * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing
+ *   phase of 0
+ */
+static bool gcp_default_phase_possible(int pipe_bpp,
+                                      const struct drm_display_mode *mode)
+{
+       unsigned int pixels_per_group;
+
+       switch (pipe_bpp) {
+       case 30:
+               /* 4 pixels in 5 clocks */
+               pixels_per_group = 4;
+               break;
+       case 36:
+               /* 2 pixels in 3 clocks */
+               pixels_per_group = 2;
+               break;
+       case 48:
+               /* 1 pixel in 2 clocks */
+               pixels_per_group = 1;
+               break;
+       default:
+               /* phase information not relevant for 8bpc */
+               return false;
+       }
+
+       return mode->crtc_hdisplay % pixels_per_group == 0 &&
+               mode->crtc_htotal % pixels_per_group == 0 &&
+               mode->crtc_hblank_start % pixels_per_group == 0 &&
+               mode->crtc_hblank_end % pixels_per_group == 0 &&
+               mode->crtc_hsync_start % pixels_per_group == 0 &&
+               mode->crtc_hsync_end % pixels_per_group == 0 &&
+               ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 ||
+                mode->crtc_htotal/2 % pixels_per_group == 0);
+}
+
+static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
+                                        const struct intel_crtc_state *crtc_state,
+                                        const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       i915_reg_t reg;
+
+       if ((crtc_state->infoframes.enable &
+            intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
+               return false;
+
+       if (HAS_DDI(dev_priv))
+               reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
+       else if (HAS_PCH_SPLIT(dev_priv))
+               reg = TVIDEO_DIP_GCP(crtc->pipe);
+       else
+               return false;
+
+       I915_WRITE(reg, crtc_state->infoframes.gcp);
+
+       return true;
+}
+
+void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
+                                  struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       i915_reg_t reg;
+
+       if ((crtc_state->infoframes.enable &
+            intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
+               return;
+
+       if (HAS_DDI(dev_priv))
+               reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
+       else if (HAS_PCH_SPLIT(dev_priv))
+               reg = TVIDEO_DIP_GCP(crtc->pipe);
+       else
+               return;
+
+       crtc_state->infoframes.gcp = I915_READ(reg);
+}
+
+static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
+                                            struct intel_crtc_state *crtc_state,
+                                            struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (IS_G4X(dev_priv) || !crtc_state->has_infoframe)
+               return;
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL);
+
+       /* Indicate color indication for deep color mode */
+       if (crtc_state->pipe_bpp > 24)
+               crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION;
+
+       /* Enable default_phase whenever the display mode is suitably aligned */
+       if (gcp_default_phase_possible(crtc_state->pipe_bpp,
+                                      &crtc_state->base.adjusted_mode))
+               crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE;
+}
+
+static void ibx_set_infoframes(struct intel_encoder *encoder,
+                              bool enable,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
+       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+       u32 port = VIDEO_DIP_PORT(encoder->port);
+
+       assert_hdmi_port_disabled(intel_hdmi);
+
+       /* See the big comment in g4x_set_infoframes() */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!enable) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
+                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                        VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       if (port != (val & VIDEO_DIP_PORT_MASK)) {
+               WARN(val & VIDEO_DIP_ENABLE,
+                    "DIP already enabled on port %c\n",
+                    (val & VIDEO_DIP_PORT_MASK) >> 29);
+               val &= ~VIDEO_DIP_PORT_MASK;
+               val |= port;
+       }
+
+       val |= VIDEO_DIP_ENABLE;
+       val &= ~(VIDEO_DIP_ENABLE_AVI |
+                VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+
+       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
+               val |= VIDEO_DIP_ENABLE_GCP;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_AVI,
+                             &crtc_state->infoframes.avi);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_SPD,
+                             &crtc_state->infoframes.spd);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_VENDOR,
+                             &crtc_state->infoframes.hdmi);
+}
+
+static void cpt_set_infoframes(struct intel_encoder *encoder,
+                              bool enable,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+
+       assert_hdmi_port_disabled(intel_hdmi);
+
+       /* See the big comment in g4x_set_infoframes() */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!enable) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
+                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                        VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       /* Set both together, unset both together: see the spec. */
+       val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
+       val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+
+       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
+               val |= VIDEO_DIP_ENABLE_GCP;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_AVI,
+                             &crtc_state->infoframes.avi);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_SPD,
+                             &crtc_state->infoframes.spd);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_VENDOR,
+                             &crtc_state->infoframes.hdmi);
+}
+
+static void vlv_set_infoframes(struct intel_encoder *encoder,
+                              bool enable,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+       u32 port = VIDEO_DIP_PORT(encoder->port);
+
+       assert_hdmi_port_disabled(intel_hdmi);
+
+       /* See the big comment in g4x_set_infoframes() */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!enable) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
+                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                        VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       if (port != (val & VIDEO_DIP_PORT_MASK)) {
+               WARN(val & VIDEO_DIP_ENABLE,
+                    "DIP already enabled on port %c\n",
+                    (val & VIDEO_DIP_PORT_MASK) >> 29);
+               val &= ~VIDEO_DIP_PORT_MASK;
+               val |= port;
+       }
+
+       val |= VIDEO_DIP_ENABLE;
+       val &= ~(VIDEO_DIP_ENABLE_AVI |
+                VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
+
+       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
+               val |= VIDEO_DIP_ENABLE_GCP;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_AVI,
+                             &crtc_state->infoframes.avi);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_SPD,
+                             &crtc_state->infoframes.spd);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_VENDOR,
+                             &crtc_state->infoframes.hdmi);
+}
+
+static void hsw_set_infoframes(struct intel_encoder *encoder,
+                              bool enable,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
+       u32 val = I915_READ(reg);
+
+       assert_hdmi_transcoder_func_disabled(dev_priv,
+                                            crtc_state->cpu_transcoder);
+
+       val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
+                VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
+                VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW |
+                VIDEO_DIP_ENABLE_DRM_GLK);
+
+       if (!enable) {
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
+               val |= VIDEO_DIP_ENABLE_GCP_HSW;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_AVI,
+                             &crtc_state->infoframes.avi);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_SPD,
+                             &crtc_state->infoframes.spd);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_VENDOR,
+                             &crtc_state->infoframes.hdmi);
+       intel_write_infoframe(encoder, crtc_state,
+                             HDMI_INFOFRAME_TYPE_DRM,
+                             &crtc_state->infoframes.drm);
+}
+
+void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+
+       if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
+               return;
+
+       DRM_DEBUG_KMS("%s DP dual mode adaptor TMDS output\n",
+                     enable ? "Enabling" : "Disabling");
+
+       drm_dp_dual_mode_set_tmds_output(hdmi->dp_dual_mode.type,
+                                        adapter, enable);
+}
+
+static int intel_hdmi_hdcp_read(struct intel_digital_port *intel_dig_port,
+                               unsigned int offset, void *buffer, size_t size)
+{
+       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+       struct drm_i915_private *dev_priv =
+               intel_dig_port->base.base.dev->dev_private;
+       struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
+                                                             hdmi->ddc_bus);
+       int ret;
+       u8 start = offset & 0xff;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = DRM_HDCP_DDC_ADDR,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &start,
+               },
+               {
+                       .addr = DRM_HDCP_DDC_ADDR,
+                       .flags = I2C_M_RD,
+                       .len = size,
+                       .buf = buffer
+               }
+       };
+       ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret == ARRAY_SIZE(msgs))
+               return 0;
+       return ret >= 0 ? -EIO : ret;
+}
+
+static int intel_hdmi_hdcp_write(struct intel_digital_port *intel_dig_port,
+                                unsigned int offset, void *buffer, size_t size)
+{
+       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+       struct drm_i915_private *dev_priv =
+               intel_dig_port->base.base.dev->dev_private;
+       struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
+                                                             hdmi->ddc_bus);
+       int ret;
+       u8 *write_buf;
+       struct i2c_msg msg;
+
+       write_buf = kzalloc(size + 1, GFP_KERNEL);
+       if (!write_buf)
+               return -ENOMEM;
+
+       write_buf[0] = offset & 0xff;
+       memcpy(&write_buf[1], buffer, size);
+
+       msg.addr = DRM_HDCP_DDC_ADDR;
+       msg.flags = 0,
+       msg.len = size + 1,
+       msg.buf = write_buf;
+
+       ret = i2c_transfer(adapter, &msg, 1);
+       if (ret == 1)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+
+       kfree(write_buf);
+       return ret;
+}
+
+static
+int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
+                                 u8 *an)
+{
+       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+       struct drm_i915_private *dev_priv =
+               intel_dig_port->base.base.dev->dev_private;
+       struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
+                                                             hdmi->ddc_bus);
+       int ret;
+
+       ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an,
+                                   DRM_HDCP_AN_LEN);
+       if (ret) {
+               DRM_DEBUG_KMS("Write An over DDC failed (%d)\n", ret);
+               return ret;
+       }
+
+       ret = intel_gmbus_output_aksv(adapter);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("Failed to output aksv (%d)\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
+                                    u8 *bksv)
+{
+       int ret;
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv,
+                                  DRM_HDCP_KSV_LEN);
+       if (ret)
+               DRM_DEBUG_KMS("Read Bksv over DDC failed (%d)\n", ret);
+       return ret;
+}
+
+static
+int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
+                                u8 *bstatus)
+{
+       int ret;
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS,
+                                  bstatus, DRM_HDCP_BSTATUS_LEN);
+       if (ret)
+               DRM_DEBUG_KMS("Read bstatus over DDC failed (%d)\n", ret);
+       return ret;
+}
+
+static
+int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
+                                    bool *repeater_present)
+{
+       int ret;
+       u8 val;
+
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
+       if (ret) {
+               DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
+               return ret;
+       }
+       *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
+       return 0;
+}
+
+static
+int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
+                                 u8 *ri_prime)
+{
+       int ret;
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME,
+                                  ri_prime, DRM_HDCP_RI_LEN);
+       if (ret)
+               DRM_DEBUG_KMS("Read Ri' over DDC failed (%d)\n", ret);
+       return ret;
+}
+
+static
+int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
+                                  bool *ksv_ready)
+{
+       int ret;
+       u8 val;
+
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
+       if (ret) {
+               DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
+               return ret;
+       }
+       *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
+       return 0;
+}
+
+static
+int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
+                                 int num_downstream, u8 *ksv_fifo)
+{
+       int ret;
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO,
+                                  ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
+       if (ret) {
+               DRM_DEBUG_KMS("Read ksv fifo over DDC failed (%d)\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static
+int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
+                                     int i, u32 *part)
+{
+       int ret;
+
+       if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
+               return -EINVAL;
+
+       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i),
+                                  part, DRM_HDCP_V_PRIME_PART_LEN);
+       if (ret)
+               DRM_DEBUG_KMS("Read V'[%d] over DDC failed (%d)\n", i, ret);
+       return ret;
+}
+
+static int kbl_repositioning_enc_en_signal(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
+       struct drm_crtc *crtc = connector->base.state->crtc;
+       struct intel_crtc *intel_crtc = container_of(crtc,
+                                                    struct intel_crtc, base);
+       u32 scanline;
+       int ret;
+
+       for (;;) {
+               scanline = I915_READ(PIPEDSL(intel_crtc->pipe));
+               if (scanline > 100 && scanline < 200)
+                       break;
+               usleep_range(25, 50);
+       }
+
+       ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, false);
+       if (ret) {
+               DRM_ERROR("Disable HDCP signalling failed (%d)\n", ret);
+               return ret;
+       }
+       ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, true);
+       if (ret) {
+               DRM_ERROR("Enable HDCP signalling failed (%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static
+int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
+                                     bool enable)
+{
+       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+       struct intel_connector *connector = hdmi->attached_connector;
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int ret;
+
+       if (!enable)
+               usleep_range(6, 60); /* Bspec says >= 6us */
+
+       ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, enable);
+       if (ret) {
+               DRM_ERROR("%s HDCP signalling failed (%d)\n",
+                         enable ? "Enable" : "Disable", ret);
+               return ret;
+       }
+
+       /*
+        * WA: To fix incorrect positioning of the window of
+        * opportunity and enc_en signalling in KABYLAKE.
+        */
+       if (IS_KABYLAKE(dev_priv) && enable)
+               return kbl_repositioning_enc_en_signal(connector);
+
+       return 0;
+}
+
+static
+bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port)
+{
+       struct drm_i915_private *dev_priv =
+               intel_dig_port->base.base.dev->dev_private;
+       enum port port = intel_dig_port->base.port;
+       int ret;
+       union {
+               u32 reg;
+               u8 shim[DRM_HDCP_RI_LEN];
+       } ri;
+
+       ret = intel_hdmi_hdcp_read_ri_prime(intel_dig_port, ri.shim);
+       if (ret)
+               return false;
+
+       I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg);
+
+       /* Wait for Ri prime match */
+       if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) &
+                    (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
+               DRM_ERROR("Ri' mismatch detected, link check failed (%x)\n",
+                         I915_READ(PORT_HDCP_STATUS(port)));
+               return false;
+       }
+       return true;
+}
+
+static struct hdcp2_hdmi_msg_data {
+       u8 msg_id;
+       u32 timeout;
+       u32 timeout2;
+       } hdcp2_msg_data[] = {
+               {HDCP_2_2_AKE_INIT, 0, 0},
+               {HDCP_2_2_AKE_SEND_CERT, HDCP_2_2_CERT_TIMEOUT_MS, 0},
+               {HDCP_2_2_AKE_NO_STORED_KM, 0, 0},
+               {HDCP_2_2_AKE_STORED_KM, 0, 0},
+               {HDCP_2_2_AKE_SEND_HPRIME, HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS,
+                               HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS},
+               {HDCP_2_2_AKE_SEND_PAIRING_INFO, HDCP_2_2_PAIRING_TIMEOUT_MS,
+                               0},
+               {HDCP_2_2_LC_INIT, 0, 0},
+               {HDCP_2_2_LC_SEND_LPRIME, HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS, 0},
+               {HDCP_2_2_SKE_SEND_EKS, 0, 0},
+               {HDCP_2_2_REP_SEND_RECVID_LIST,
+                               HDCP_2_2_RECVID_LIST_TIMEOUT_MS, 0},
+               {HDCP_2_2_REP_SEND_ACK, 0, 0},
+               {HDCP_2_2_REP_STREAM_MANAGE, 0, 0},
+               {HDCP_2_2_REP_STREAM_READY, HDCP_2_2_STREAM_READY_TIMEOUT_MS,
+                               0},
+       };
+
+static
+int intel_hdmi_hdcp2_read_rx_status(struct intel_digital_port *intel_dig_port,
+                                   u8 *rx_status)
+{
+       return intel_hdmi_hdcp_read(intel_dig_port,
+                                   HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET,
+                                   rx_status,
+                                   HDCP_2_2_HDMI_RXSTATUS_LEN);
+}
+
+static int get_hdcp2_msg_timeout(u8 msg_id, bool is_paired)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hdcp2_msg_data); i++)
+               if (hdcp2_msg_data[i].msg_id == msg_id &&
+                   (msg_id != HDCP_2_2_AKE_SEND_HPRIME || is_paired))
+                       return hdcp2_msg_data[i].timeout;
+               else if (hdcp2_msg_data[i].msg_id == msg_id)
+                       return hdcp2_msg_data[i].timeout2;
+
+       return -EINVAL;
+}
+
+static inline
+int hdcp2_detect_msg_availability(struct intel_digital_port *intel_digital_port,
+                                 u8 msg_id, bool *msg_ready,
+                                 ssize_t *msg_sz)
+{
+       u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
+       int ret;
+
+       ret = intel_hdmi_hdcp2_read_rx_status(intel_digital_port, rx_status);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("rx_status read failed. Err %d\n", ret);
+               return ret;
+       }
+
+       *msg_sz = ((HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(rx_status[1]) << 8) |
+                 rx_status[0]);
+
+       if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST)
+               *msg_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]) &&
+                            *msg_sz);
+       else
+               *msg_ready = *msg_sz;
+
+       return 0;
+}
+
+static ssize_t
+intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port,
+                             u8 msg_id, bool paired)
+{
+       bool msg_ready = false;
+       int timeout, ret;
+       ssize_t msg_sz = 0;
+
+       timeout = get_hdcp2_msg_timeout(msg_id, paired);
+       if (timeout < 0)
+               return timeout;
+
+       ret = __wait_for(ret = hdcp2_detect_msg_availability(intel_dig_port,
+                                                            msg_id, &msg_ready,
+                                                            &msg_sz),
+                        !ret && msg_ready && msg_sz, timeout * 1000,
+                        1000, 5 * 1000);
+       if (ret)
+               DRM_DEBUG_KMS("msg_id: %d, ret: %d, timeout: %d\n",
+                             msg_id, ret, timeout);
+
+       return ret ? ret : msg_sz;
+}
+
+static
+int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *intel_dig_port,
+                              void *buf, size_t size)
+{
+       unsigned int offset;
+
+       offset = HDCP_2_2_HDMI_REG_WR_MSG_OFFSET;
+       return intel_hdmi_hdcp_write(intel_dig_port, offset, buf, size);
+}
+
+static
+int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *intel_dig_port,
+                             u8 msg_id, void *buf, size_t size)
+{
+       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+       struct intel_hdcp *hdcp = &hdmi->attached_connector->hdcp;
+       unsigned int offset;
+       ssize_t ret;
+
+       ret = intel_hdmi_hdcp2_wait_for_msg(intel_dig_port, msg_id,
+                                           hdcp->is_paired);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Available msg size should be equal to or lesser than the
+        * available buffer.
+        */
+       if (ret > size) {
+               DRM_DEBUG_KMS("msg_sz(%zd) is more than exp size(%zu)\n",
+                             ret, size);
+               return -1;
+       }
+
+       offset = HDCP_2_2_HDMI_REG_RD_MSG_OFFSET;
+       ret = intel_hdmi_hdcp_read(intel_dig_port, offset, buf, ret);
+       if (ret)
+               DRM_DEBUG_KMS("Failed to read msg_id: %d(%zd)\n", msg_id, ret);
+
+       return ret;
+}
+
+static
+int intel_hdmi_hdcp2_check_link(struct intel_digital_port *intel_dig_port)
+{
+       u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
+       int ret;
+
+       ret = intel_hdmi_hdcp2_read_rx_status(intel_dig_port, rx_status);
+       if (ret)
+               return ret;
+
+       /*
+        * Re-auth request and Link Integrity Failures are represented by
+        * same bit. i.e reauth_req.
+        */
+       if (HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(rx_status[1]))
+               ret = HDCP_REAUTH_REQUEST;
+       else if (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]))
+               ret = HDCP_TOPOLOGY_CHANGE;
+
+       return ret;
+}
+
+static
+int intel_hdmi_hdcp2_capable(struct intel_digital_port *intel_dig_port,
+                            bool *capable)
+{
+       u8 hdcp2_version;
+       int ret;
+
+       *capable = false;
+       ret = intel_hdmi_hdcp_read(intel_dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
+                                  &hdcp2_version, sizeof(hdcp2_version));
+       if (!ret && hdcp2_version & HDCP_2_2_HDMI_SUPPORT_MASK)
+               *capable = true;
+
+       return ret;
+}
+
+static inline
+enum hdcp_wired_protocol intel_hdmi_hdcp2_protocol(void)
+{
+       return HDCP_PROTOCOL_HDMI;
+}
+
+static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
+       .write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
+       .read_bksv = intel_hdmi_hdcp_read_bksv,
+       .read_bstatus = intel_hdmi_hdcp_read_bstatus,
+       .repeater_present = intel_hdmi_hdcp_repeater_present,
+       .read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
+       .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
+       .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
+       .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
+       .toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
+       .check_link = intel_hdmi_hdcp_check_link,
+       .write_2_2_msg = intel_hdmi_hdcp2_write_msg,
+       .read_2_2_msg = intel_hdmi_hdcp2_read_msg,
+       .check_2_2_link = intel_hdmi_hdcp2_check_link,
+       .hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
+       .protocol = HDCP_PROTOCOL_HDMI,
+};
+
+static void intel_hdmi_prepare(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *crtc_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
+       u32 hdmi_val;
+
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
+
+       hdmi_val = SDVO_ENCODING_HDMI;
+       if (!HAS_PCH_SPLIT(dev_priv) && crtc_state->limited_color_range)
+               hdmi_val |= HDMI_COLOR_RANGE_16_235;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
+
+       if (crtc_state->pipe_bpp > 24)
+               hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
+       else
+               hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
+
+       if (crtc_state->has_hdmi_sink)
+               hdmi_val |= HDMI_MODE_SELECT_HDMI;
+
+       if (HAS_PCH_CPT(dev_priv))
+               hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe);
+       else if (IS_CHERRYVIEW(dev_priv))
+               hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe);
+       else
+               hdmi_val |= SDVO_PIPE_SEL(crtc->pipe);
+
+       I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
+       POSTING_READ(intel_hdmi->hdmi_reg);
+}
+
+static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
+                                   enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       intel_wakeref_t wakeref;
+       bool ret;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       ret = intel_sdvo_port_enabled(dev_priv, intel_hdmi->hdmi_reg, pipe);
+
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+
+       return ret;
+}
+
+static void intel_hdmi_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 tmp, flags = 0;
+       int dotclock;
+
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI);
+
+       tmp = I915_READ(intel_hdmi->hdmi_reg);
+
+       if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       if (tmp & HDMI_MODE_SELECT_HDMI)
+               pipe_config->has_hdmi_sink = true;
+
+       pipe_config->infoframes.enable |=
+               intel_hdmi_infoframes_enabled(encoder, pipe_config);
+
+       if (pipe_config->infoframes.enable)
+               pipe_config->has_infoframe = true;
+
+       if (tmp & HDMI_AUDIO_ENABLE)
+               pipe_config->has_audio = true;
+
+       if (!HAS_PCH_SPLIT(dev_priv) &&
+           tmp & HDMI_COLOR_RANGE_16_235)
+               pipe_config->limited_color_range = true;
+
+       pipe_config->base.adjusted_mode.flags |= flags;
+
+       if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
+               dotclock = pipe_config->port_clock * 2 / 3;
+       else
+               dotclock = pipe_config->port_clock;
+
+       if (pipe_config->pixel_multiplier)
+               dotclock /= pipe_config->pixel_multiplier;
+
+       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+
+       pipe_config->lane_count = 4;
+
+       intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
+
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_AVI,
+                            &pipe_config->infoframes.avi);
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_SPD,
+                            &pipe_config->infoframes.spd);
+       intel_read_infoframe(encoder, pipe_config,
+                            HDMI_INFOFRAME_TYPE_VENDOR,
+                            &pipe_config->infoframes.hdmi);
+}
+
+static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
+                                   const struct intel_crtc_state *pipe_config,
+                                   const struct drm_connector_state *conn_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+
+       WARN_ON(!pipe_config->has_hdmi_sink);
+       DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
+                        pipe_name(crtc->pipe));
+       intel_audio_codec_enable(encoder, pipe_config, conn_state);
+}
+
+static void g4x_enable_hdmi(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *pipe_config,
+                           const struct drm_connector_state *conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       u32 temp;
+
+       temp = I915_READ(intel_hdmi->hdmi_reg);
+
+       temp |= SDVO_ENABLE;
+       if (pipe_config->has_audio)
+               temp |= HDMI_AUDIO_ENABLE;
+
+       I915_WRITE(intel_hdmi->hdmi_reg, temp);
+       POSTING_READ(intel_hdmi->hdmi_reg);
+
+       if (pipe_config->has_audio)
+               intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
+}
+
+static void ibx_enable_hdmi(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *pipe_config,
+                           const struct drm_connector_state *conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       u32 temp;
+
+       temp = I915_READ(intel_hdmi->hdmi_reg);
+
+       temp |= SDVO_ENABLE;
+       if (pipe_config->has_audio)
+               temp |= HDMI_AUDIO_ENABLE;
+
+       /*
+        * HW workaround, need to write this twice for issue
+        * that may result in first write getting masked.
+        */
+       I915_WRITE(intel_hdmi->hdmi_reg, temp);
+       POSTING_READ(intel_hdmi->hdmi_reg);
+       I915_WRITE(intel_hdmi->hdmi_reg, temp);
+       POSTING_READ(intel_hdmi->hdmi_reg);
+
+       /*
+        * HW workaround, need to toggle enable bit off and on
+        * for 12bpc with pixel repeat.
+        *
+        * FIXME: BSpec says this should be done at the end of
+        * of the modeset sequence, so not sure if this isn't too soon.
+        */
+       if (pipe_config->pipe_bpp > 24 &&
+           pipe_config->pixel_multiplier > 1) {
+               I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+
+               /*
+                * HW workaround, need to write this twice for issue
+                * that may result in first write getting masked.
+                */
+               I915_WRITE(intel_hdmi->hdmi_reg, temp);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+               I915_WRITE(intel_hdmi->hdmi_reg, temp);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+       }
+
+       if (pipe_config->has_audio)
+               intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
+}
+
+static void cpt_enable_hdmi(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *pipe_config,
+                           const struct drm_connector_state *conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       enum pipe pipe = crtc->pipe;
+       u32 temp;
+
+       temp = I915_READ(intel_hdmi->hdmi_reg);
+
+       temp |= SDVO_ENABLE;
+       if (pipe_config->has_audio)
+               temp |= HDMI_AUDIO_ENABLE;
+
+       /*
+        * WaEnableHDMI8bpcBefore12bpc:snb,ivb
+        *
+        * The procedure for 12bpc is as follows:
+        * 1. disable HDMI clock gating
+        * 2. enable HDMI with 8bpc
+        * 3. enable HDMI with 12bpc
+        * 4. enable HDMI clock gating
+        */
+
+       if (pipe_config->pipe_bpp > 24) {
+               I915_WRITE(TRANS_CHICKEN1(pipe),
+                          I915_READ(TRANS_CHICKEN1(pipe)) |
+                          TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
+
+               temp &= ~SDVO_COLOR_FORMAT_MASK;
+               temp |= SDVO_COLOR_FORMAT_8bpc;
+       }
+
+       I915_WRITE(intel_hdmi->hdmi_reg, temp);
+       POSTING_READ(intel_hdmi->hdmi_reg);
+
+       if (pipe_config->pipe_bpp > 24) {
+               temp &= ~SDVO_COLOR_FORMAT_MASK;
+               temp |= HDMI_COLOR_FORMAT_12bpc;
+
+               I915_WRITE(intel_hdmi->hdmi_reg, temp);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+
+               I915_WRITE(TRANS_CHICKEN1(pipe),
+                          I915_READ(TRANS_CHICKEN1(pipe)) &
+                          ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
+       }
+
+       if (pipe_config->has_audio)
+               intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
+}
+
+static void vlv_enable_hdmi(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *pipe_config,
+                           const struct drm_connector_state *conn_state)
+{
+}
+
+static void intel_disable_hdmi(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *old_crtc_state,
+                              const struct drm_connector_state *old_conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct intel_digital_port *intel_dig_port =
+               hdmi_to_dig_port(intel_hdmi);
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       u32 temp;
+
+       temp = I915_READ(intel_hdmi->hdmi_reg);
+
+       temp &= ~(SDVO_ENABLE | HDMI_AUDIO_ENABLE);
+       I915_WRITE(intel_hdmi->hdmi_reg, temp);
+       POSTING_READ(intel_hdmi->hdmi_reg);
+
+       /*
+        * HW workaround for IBX, we need to move the port
+        * to transcoder A after disabling it to allow the
+        * matching DP port to be enabled on transcoder A.
+        */
+       if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
+               /*
+                * We get CPU/PCH FIFO underruns on the other pipe when
+                * doing the workaround. Sweep them under the rug.
+                */
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
+               temp &= ~SDVO_PIPE_SEL_MASK;
+               temp |= SDVO_ENABLE | SDVO_PIPE_SEL(PIPE_A);
+               /*
+                * HW workaround, need to write this twice for issue
+                * that may result in first write getting masked.
+                */
+               I915_WRITE(intel_hdmi->hdmi_reg, temp);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+               I915_WRITE(intel_hdmi->hdmi_reg, temp);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+
+               temp &= ~SDVO_ENABLE;
+               I915_WRITE(intel_hdmi->hdmi_reg, temp);
+               POSTING_READ(intel_hdmi->hdmi_reg);
+
+               intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+       }
+
+       intel_dig_port->set_infoframes(encoder,
+                                      false,
+                                      old_crtc_state, old_conn_state);
+
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
+}
+
+static void g4x_disable_hdmi(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *old_crtc_state,
+                            const struct drm_connector_state *old_conn_state)
+{
+       if (old_crtc_state->has_audio)
+               intel_audio_codec_disable(encoder,
+                                         old_crtc_state, old_conn_state);
+
+       intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
+}
+
+static void pch_disable_hdmi(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *old_crtc_state,
+                            const struct drm_connector_state *old_conn_state)
+{
+       if (old_crtc_state->has_audio)
+               intel_audio_codec_disable(encoder,
+                                         old_crtc_state, old_conn_state);
+}
+
+static void pch_post_disable_hdmi(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *old_crtc_state,
+                                 const struct drm_connector_state *old_conn_state)
+{
+       intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
+}
+
+static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[encoder->port];
+       int max_tmds_clock;
+
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               max_tmds_clock = 594000;
+       else if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv))
+               max_tmds_clock = 300000;
+       else if (INTEL_GEN(dev_priv) >= 5)
+               max_tmds_clock = 225000;
+       else
+               max_tmds_clock = 165000;
+
+       if (info->max_tmds_clock)
+               max_tmds_clock = min(max_tmds_clock, info->max_tmds_clock);
+
+       return max_tmds_clock;
+}
+
+static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
+                                bool respect_downstream_limits,
+                                bool force_dvi)
+{
+       struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base;
+       int max_tmds_clock = intel_hdmi_source_max_tmds_clock(encoder);
+
+       if (respect_downstream_limits) {
+               struct intel_connector *connector = hdmi->attached_connector;
+               const struct drm_display_info *info = &connector->base.display_info;
+
+               if (hdmi->dp_dual_mode.max_tmds_clock)
+                       max_tmds_clock = min(max_tmds_clock,
+                                            hdmi->dp_dual_mode.max_tmds_clock);
+
+               if (info->max_tmds_clock)
+                       max_tmds_clock = min(max_tmds_clock,
+                                            info->max_tmds_clock);
+               else if (!hdmi->has_hdmi_sink || force_dvi)
+                       max_tmds_clock = min(max_tmds_clock, 165000);
+       }
+
+       return max_tmds_clock;
+}
+
+static enum drm_mode_status
+hdmi_port_clock_valid(struct intel_hdmi *hdmi,
+                     int clock, bool respect_downstream_limits,
+                     bool force_dvi)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
+
+       if (clock < 25000)
+               return MODE_CLOCK_LOW;
+       if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits, force_dvi))
+               return MODE_CLOCK_HIGH;
+
+       /* BXT DPLL can't generate 223-240 MHz */
+       if (IS_GEN9_LP(dev_priv) && clock > 223333 && clock < 240000)
+               return MODE_CLOCK_RANGE;
+
+       /* CHV DPLL can't generate 216-240 MHz */
+       if (IS_CHERRYVIEW(dev_priv) && clock > 216000 && clock < 240000)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static enum drm_mode_status
+intel_hdmi_mode_valid(struct drm_connector *connector,
+                     struct drm_display_mode *mode)
+{
+       struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
+       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       enum drm_mode_status status;
+       int clock;
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+       bool force_dvi =
+               READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       clock = mode->clock;
+
+       if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
+               clock *= 2;
+
+       if (clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               clock *= 2;
+
+       if (drm_mode_is_420_only(&connector->display_info, mode))
+               clock /= 2;
+
+       /* check if we can do 8bpc */
+       status = hdmi_port_clock_valid(hdmi, clock, true, force_dvi);
+
+       if (hdmi->has_hdmi_sink && !force_dvi) {
+               /* if we can't do 8bpc we may still be able to do 12bpc */
+               if (status != MODE_OK && !HAS_GMCH(dev_priv))
+                       status = hdmi_port_clock_valid(hdmi, clock * 3 / 2,
+                                                      true, force_dvi);
+
+               /* if we can't do 8,12bpc we may still be able to do 10bpc */
+               if (status != MODE_OK && INTEL_GEN(dev_priv) >= 11)
+                       status = hdmi_port_clock_valid(hdmi, clock * 5 / 4,
+                                                      true, force_dvi);
+       }
+
+       return status;
+}
+
+static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
+                                    int bpc)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(crtc_state->base.crtc->dev);
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
+       struct drm_connector *connector;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       int i;
+
+       if (HAS_GMCH(dev_priv))
+               return false;
+
+       if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
+               return false;
+
+       if (crtc_state->pipe_bpp < bpc * 3)
+               return false;
+
+       if (!crtc_state->has_hdmi_sink)
+               return false;
+
+       /*
+        * HDMI deep color affects the clocks, so it's only possible
+        * when not cloning with other encoder types.
+        */
+       if (crtc_state->output_types != 1 << INTEL_OUTPUT_HDMI)
+               return false;
+
+       for_each_new_connector_in_state(state, connector, connector_state, i) {
+               const struct drm_display_info *info = &connector->display_info;
+
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
+
+               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
+                       const struct drm_hdmi_info *hdmi = &info->hdmi;
+
+                       if (bpc == 12 && !(hdmi->y420_dc_modes &
+                                          DRM_EDID_YCBCR420_DC_36))
+                               return false;
+                       else if (bpc == 10 && !(hdmi->y420_dc_modes &
+                                               DRM_EDID_YCBCR420_DC_30))
+                               return false;
+               } else {
+                       if (bpc == 12 && !(info->edid_hdmi_dc_modes &
+                                          DRM_EDID_HDMI_DC_36))
+                               return false;
+                       else if (bpc == 10 && !(info->edid_hdmi_dc_modes &
+                                               DRM_EDID_HDMI_DC_30))
+                               return false;
+               }
+       }
+
+       /* Display WA #1139: glk */
+       if (bpc == 12 && IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) &&
+           adjusted_mode->htotal > 5460)
+               return false;
+
+       /* Display Wa_1405510057:icl */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
+           bpc == 10 && INTEL_GEN(dev_priv) >= 11 &&
+           (adjusted_mode->crtc_hblank_end -
+            adjusted_mode->crtc_hblank_start) % 8 == 2)
+               return false;
+
+       return true;
+}
+
+static bool
+intel_hdmi_ycbcr420_config(struct drm_connector *connector,
+                          struct intel_crtc_state *config,
+                          int *clock_12bpc, int *clock_10bpc,
+                          int *clock_8bpc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(config->base.crtc);
+
+       if (!connector->ycbcr_420_allowed) {
+               DRM_ERROR("Platform doesn't support YCBCR420 output\n");
+               return false;
+       }
+
+       /* YCBCR420 TMDS rate requirement is half the pixel clock */
+       config->port_clock /= 2;
+       *clock_12bpc /= 2;
+       *clock_10bpc /= 2;
+       *clock_8bpc /= 2;
+       config->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
+
+       /* YCBCR 420 output conversion needs a scaler */
+       if (skl_update_scaler_crtc(config)) {
+               DRM_DEBUG_KMS("Scaler allocation for output failed\n");
+               return false;
+       }
+
+       intel_pch_panel_fitting(intel_crtc, config,
+                               DRM_MODE_SCALE_FULLSCREEN);
+
+       return true;
+}
+
+int intel_hdmi_compute_config(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       struct drm_connector *connector = conn_state->connector;
+       struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
+       struct intel_digital_connector_state *intel_conn_state =
+               to_intel_digital_connector_state(conn_state);
+       int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
+       int clock_10bpc = clock_8bpc * 5 / 4;
+       int clock_12bpc = clock_8bpc * 3 / 2;
+       int desired_bpp;
+       bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+       pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
+
+       if (pipe_config->has_hdmi_sink)
+               pipe_config->has_infoframe = true;
+
+       if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
+               /* See CEA-861-E - 5.1 Default Encoding Parameters */
+               pipe_config->limited_color_range =
+                       pipe_config->has_hdmi_sink &&
+                       drm_default_rgb_quant_range(adjusted_mode) ==
+                       HDMI_QUANTIZATION_RANGE_LIMITED;
+       } else {
+               pipe_config->limited_color_range =
+                       intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED;
+       }
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
+               pipe_config->pixel_multiplier = 2;
+               clock_8bpc *= 2;
+               clock_10bpc *= 2;
+               clock_12bpc *= 2;
+       }
+
+       if (drm_mode_is_420_only(&connector->display_info, adjusted_mode)) {
+               if (!intel_hdmi_ycbcr420_config(connector, pipe_config,
+                                               &clock_12bpc, &clock_10bpc,
+                                               &clock_8bpc)) {
+                       DRM_ERROR("Can't support YCBCR420 output\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv))
+               pipe_config->has_pch_encoder = true;
+
+       if (pipe_config->has_hdmi_sink) {
+               if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
+                       pipe_config->has_audio = intel_hdmi->has_audio;
+               else
+                       pipe_config->has_audio =
+                               intel_conn_state->force_audio == HDMI_AUDIO_ON;
+       }
+
+       /*
+        * Note that g4x/vlv don't support 12bpc hdmi outputs. We also need
+        * to check that the higher clock still fits within limits.
+        */
+       if (hdmi_deep_color_possible(pipe_config, 12) &&
+           hdmi_port_clock_valid(intel_hdmi, clock_12bpc,
+                                 true, force_dvi) == MODE_OK) {
+               DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
+               desired_bpp = 12*3;
+
+               /* Need to adjust the port link by 1.5x for 12bpc. */
+               pipe_config->port_clock = clock_12bpc;
+       } else if (hdmi_deep_color_possible(pipe_config, 10) &&
+                  hdmi_port_clock_valid(intel_hdmi, clock_10bpc,
+                                        true, force_dvi) == MODE_OK) {
+               DRM_DEBUG_KMS("picking bpc to 10 for HDMI output\n");
+               desired_bpp = 10 * 3;
+
+               /* Need to adjust the port link by 1.25x for 10bpc. */
+               pipe_config->port_clock = clock_10bpc;
+       } else {
+               DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
+               desired_bpp = 8*3;
+
+               pipe_config->port_clock = clock_8bpc;
+       }
+
+       if (!pipe_config->bw_constrained) {
+               DRM_DEBUG_KMS("forcing pipe bpp to %i for HDMI\n", desired_bpp);
+               pipe_config->pipe_bpp = desired_bpp;
+       }
+
+       if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
+                                 false, force_dvi) != MODE_OK) {
+               DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
+               return -EINVAL;
+       }
+
+       /* Set user selected PAR to incoming mode's member */
+       adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
+
+       pipe_config->lane_count = 4;
+
+       if (scdc->scrambling.supported && (INTEL_GEN(dev_priv) >= 10 ||
+                                          IS_GEMINILAKE(dev_priv))) {
+               if (scdc->scrambling.low_rates)
+                       pipe_config->hdmi_scrambling = true;
+
+               if (pipe_config->port_clock > 340000) {
+                       pipe_config->hdmi_scrambling = true;
+                       pipe_config->hdmi_high_tmds_clock_ratio = true;
+               }
+       }
+
+       intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, conn_state);
+
+       if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) {
+               DRM_DEBUG_KMS("bad AVI infoframe\n");
+               return -EINVAL;
+       }
+
+       if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) {
+               DRM_DEBUG_KMS("bad SPD infoframe\n");
+               return -EINVAL;
+       }
+
+       if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) {
+               DRM_DEBUG_KMS("bad HDMI infoframe\n");
+               return -EINVAL;
+       }
+
+       if (!intel_hdmi_compute_drm_infoframe(encoder, pipe_config, conn_state)) {
+               DRM_DEBUG_KMS("bad DRM infoframe\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void
+intel_hdmi_unset_edid(struct drm_connector *connector)
+{
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+
+       intel_hdmi->has_hdmi_sink = false;
+       intel_hdmi->has_audio = false;
+
+       intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
+       intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
+
+       kfree(to_intel_connector(connector)->detect_edid);
+       to_intel_connector(connector)->detect_edid = NULL;
+}
+
+static void
+intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
+       enum port port = hdmi_to_dig_port(hdmi)->base.port;
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+       enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(adapter);
+
+       /*
+        * Type 1 DVI adaptors are not required to implement any
+        * registers, so we can't always detect their presence.
+        * Ideally we should be able to check the state of the
+        * CONFIG1 pin, but no such luck on our hardware.
+        *
+        * The only method left to us is to check the VBT to see
+        * if the port is a dual mode capable DP port. But let's
+        * only do that when we sucesfully read the EDID, to avoid
+        * confusing log messages about DP dual mode adaptors when
+        * there's nothing connected to the port.
+        */
+       if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
+               /* An overridden EDID imply that we want this port for testing.
+                * Make sure not to set limits for that port.
+                */
+               if (has_edid && !connector->override_edid &&
+                   intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
+                       DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n");
+                       type = DRM_DP_DUAL_MODE_TYPE1_DVI;
+               } else {
+                       type = DRM_DP_DUAL_MODE_NONE;
+               }
+       }
+
+       if (type == DRM_DP_DUAL_MODE_NONE)
+               return;
+
+       hdmi->dp_dual_mode.type = type;
+       hdmi->dp_dual_mode.max_tmds_clock =
+               drm_dp_dual_mode_max_tmds_clock(type, adapter);
+
+       DRM_DEBUG_KMS("DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n",
+                     drm_dp_get_dual_mode_type_name(type),
+                     hdmi->dp_dual_mode.max_tmds_clock);
+}
+
+static bool
+intel_hdmi_set_edid(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       intel_wakeref_t wakeref;
+       struct edid *edid;
+       bool connected = false;
+       struct i2c_adapter *i2c;
+
+       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+
+       i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
+
+       edid = drm_get_edid(connector, i2c);
+
+       if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
+               DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
+               intel_gmbus_force_bit(i2c, true);
+               edid = drm_get_edid(connector, i2c);
+               intel_gmbus_force_bit(i2c, false);
+       }
+
+       intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
+
+       to_intel_connector(connector)->detect_edid = edid;
+       if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+               intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
+               intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+
+               connected = true;
+       }
+
+       cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid);
+
+       return connected;
+}
+
+static enum drm_connector_status
+intel_hdmi_detect(struct drm_connector *connector, bool force)
+{
+       enum drm_connector_status status = connector_status_disconnected;
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base;
+       intel_wakeref_t wakeref;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+
+       if (INTEL_GEN(dev_priv) >= 11 &&
+           !intel_digital_port_connected(encoder))
+               goto out;
+
+       intel_hdmi_unset_edid(connector);
+
+       if (intel_hdmi_set_edid(connector))
+               status = connector_status_connected;
+
+out:
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
+
+       if (status != connector_status_connected)
+               cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier);
+
+       return status;
+}
+
+static void
+intel_hdmi_force(struct drm_connector *connector)
+{
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       intel_hdmi_unset_edid(connector);
+
+       if (connector->status != connector_status_connected)
+               return;
+
+       intel_hdmi_set_edid(connector);
+}
+
+static int intel_hdmi_get_modes(struct drm_connector *connector)
+{
+       struct edid *edid;
+
+       edid = to_intel_connector(connector)->detect_edid;
+       if (edid == NULL)
+               return 0;
+
+       return intel_connector_update_modes(connector, edid);
+}
+
+static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct intel_digital_port *intel_dig_port =
+               enc_to_dig_port(&encoder->base);
+
+       intel_hdmi_prepare(encoder, pipe_config);
+
+       intel_dig_port->set_infoframes(encoder,
+                                      pipe_config->has_infoframe,
+                                      pipe_config, conn_state);
+}
+
+static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *pipe_config,
+                               const struct drm_connector_state *conn_state)
+{
+       struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       vlv_phy_pre_encoder_enable(encoder, pipe_config);
+
+       /* HDMI 1.0V-2dB */
+       vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
+                                0x2b247878);
+
+       dport->set_infoframes(encoder,
+                             pipe_config->has_infoframe,
+                             pipe_config, conn_state);
+
+       g4x_enable_hdmi(encoder, pipe_config, conn_state);
+
+       vlv_wait_port_ready(dev_priv, dport, 0x0);
+}
+
+static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
+                                   const struct intel_crtc_state *pipe_config,
+                                   const struct drm_connector_state *conn_state)
+{
+       intel_hdmi_prepare(encoder, pipe_config);
+
+       vlv_phy_pre_pll_enable(encoder, pipe_config);
+}
+
+static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
+                                   const struct intel_crtc_state *pipe_config,
+                                   const struct drm_connector_state *conn_state)
+{
+       intel_hdmi_prepare(encoder, pipe_config);
+
+       chv_phy_pre_pll_enable(encoder, pipe_config);
+}
+
+static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder,
+                                     const struct intel_crtc_state *old_crtc_state,
+                                     const struct drm_connector_state *old_conn_state)
+{
+       chv_phy_post_pll_disable(encoder, old_crtc_state);
+}
+
+static void vlv_hdmi_post_disable(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *old_crtc_state,
+                                 const struct drm_connector_state *old_conn_state)
+{
+       /* Reset lanes to avoid HDMI flicker (VLV w/a) */
+       vlv_phy_reset_lanes(encoder, old_crtc_state);
+}
+
+static void chv_hdmi_post_disable(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *old_crtc_state,
+                                 const struct drm_connector_state *old_conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       vlv_dpio_get(dev_priv);
+
+       /* Assert data lane reset */
+       chv_data_lane_soft_reset(encoder, old_crtc_state, true);
+
+       vlv_dpio_put(dev_priv);
+}
+
+static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *pipe_config,
+                               const struct drm_connector_state *conn_state)
+{
+       struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       chv_phy_pre_encoder_enable(encoder, pipe_config);
+
+       /* FIXME: Program the support xxx V-dB */
+       /* Use 800mV-0dB */
+       chv_set_phy_signal_level(encoder, 128, 102, false);
+
+       dport->set_infoframes(encoder,
+                             pipe_config->has_infoframe,
+                             pipe_config, conn_state);
+
+       g4x_enable_hdmi(encoder, pipe_config, conn_state);
+
+       vlv_wait_port_ready(dev_priv, dport, 0x0);
+
+       /* Second common lane will stay alive on its own now */
+       chv_phy_release_cl2_override(encoder);
+}
+
+static struct i2c_adapter *
+intel_hdmi_get_i2c_adapter(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+
+       return intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
+}
+
+static void intel_hdmi_create_i2c_symlink(struct drm_connector *connector)
+{
+       struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector);
+       struct kobject *i2c_kobj = &adapter->dev.kobj;
+       struct kobject *connector_kobj = &connector->kdev->kobj;
+       int ret;
+
+       ret = sysfs_create_link(connector_kobj, i2c_kobj, i2c_kobj->name);
+       if (ret)
+               DRM_ERROR("Failed to create i2c symlink (%d)\n", ret);
+}
+
+static void intel_hdmi_remove_i2c_symlink(struct drm_connector *connector)
+{
+       struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector);
+       struct kobject *i2c_kobj = &adapter->dev.kobj;
+       struct kobject *connector_kobj = &connector->kdev->kobj;
+
+       sysfs_remove_link(connector_kobj, i2c_kobj->name);
+}
+
+static int
+intel_hdmi_connector_register(struct drm_connector *connector)
+{
+       int ret;
+
+       ret = intel_connector_register(connector);
+       if (ret)
+               return ret;
+
+       i915_debugfs_connector_add(connector);
+
+       intel_hdmi_create_i2c_symlink(connector);
+
+       return ret;
+}
+
+static void intel_hdmi_destroy(struct drm_connector *connector)
+{
+       if (intel_attached_hdmi(connector)->cec_notifier)
+               cec_notifier_put(intel_attached_hdmi(connector)->cec_notifier);
+
+       intel_connector_destroy(connector);
+}
+
+static void intel_hdmi_connector_unregister(struct drm_connector *connector)
+{
+       intel_hdmi_remove_i2c_symlink(connector);
+
+       intel_connector_unregister(connector);
+}
+
+static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
+       .detect = intel_hdmi_detect,
+       .force = intel_hdmi_force,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .late_register = intel_hdmi_connector_register,
+       .early_unregister = intel_hdmi_connector_unregister,
+       .destroy = intel_hdmi_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
+       .get_modes = intel_hdmi_get_modes,
+       .mode_valid = intel_hdmi_mode_valid,
+       .atomic_check = intel_digital_connector_atomic_check,
+};
+
+static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
+       .destroy = intel_encoder_destroy,
+};
+
+static void
+intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_digital_port *intel_dig_port =
+                               hdmi_to_dig_port(intel_hdmi);
+
+       intel_attach_force_audio_property(connector);
+       intel_attach_broadcast_rgb_property(connector);
+       intel_attach_aspect_ratio_property(connector);
+
+       /*
+        * Attach Colorspace property for Non LSPCON based device
+        * ToDo: This needs to be extended for LSPCON implementation
+        * as well. Will be implemented separately.
+        */
+       if (!intel_dig_port->lspcon.active)
+               intel_attach_colorspace_property(connector);
+
+       drm_connector_attach_content_type_property(connector);
+       connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
+
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               drm_object_attach_property(&connector->base,
+                       connector->dev->mode_config.hdr_output_metadata_property, 0);
+
+       if (!HAS_GMCH(dev_priv))
+               drm_connector_attach_max_bpc_property(connector, 8, 12);
+}
+
+/*
+ * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup
+ * @encoder: intel_encoder
+ * @connector: drm_connector
+ * @high_tmds_clock_ratio = bool to indicate if the function needs to set
+ *  or reset the high tmds clock ratio for scrambling
+ * @scrambling: bool to Indicate if the function needs to set or reset
+ *  sink scrambling
+ *
+ * This function handles scrambling on HDMI 2.0 capable sinks.
+ * If required clock rate is > 340 Mhz && scrambling is supported by sink
+ * it enables scrambling. This should be called before enabling the HDMI
+ * 2.0 port, as the sink can choose to disable the scrambling if it doesn't
+ * detect a scrambled clock within 100 ms.
+ *
+ * Returns:
+ * True on success, false on failure.
+ */
+bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
+                                      struct drm_connector *connector,
+                                      bool high_tmds_clock_ratio,
+                                      bool scrambling)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_scrambling *sink_scrambling =
+               &connector->display_info.hdmi.scdc.scrambling;
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
+
+       if (!sink_scrambling->supported)
+               return true;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n",
+                     connector->base.id, connector->name,
+                     yesno(scrambling), high_tmds_clock_ratio ? 40 : 10);
+
+       /* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */
+       return drm_scdc_set_high_tmds_clock_ratio(adapter,
+                                                 high_tmds_clock_ratio) &&
+               drm_scdc_set_scrambling(adapter, scrambling);
+}
+
+static u8 chv_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
+{
+       u8 ddc_pin;
+
+       switch (port) {
+       case PORT_B:
+               ddc_pin = GMBUS_PIN_DPB;
+               break;
+       case PORT_C:
+               ddc_pin = GMBUS_PIN_DPC;
+               break;
+       case PORT_D:
+               ddc_pin = GMBUS_PIN_DPD_CHV;
+               break;
+       default:
+               MISSING_CASE(port);
+               ddc_pin = GMBUS_PIN_DPB;
+               break;
+       }
+       return ddc_pin;
+}
+
+static u8 bxt_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
+{
+       u8 ddc_pin;
+
+       switch (port) {
+       case PORT_B:
+               ddc_pin = GMBUS_PIN_1_BXT;
+               break;
+       case PORT_C:
+               ddc_pin = GMBUS_PIN_2_BXT;
+               break;
+       default:
+               MISSING_CASE(port);
+               ddc_pin = GMBUS_PIN_1_BXT;
+               break;
+       }
+       return ddc_pin;
+}
+
+static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv,
+                             enum port port)
+{
+       u8 ddc_pin;
+
+       switch (port) {
+       case PORT_B:
+               ddc_pin = GMBUS_PIN_1_BXT;
+               break;
+       case PORT_C:
+               ddc_pin = GMBUS_PIN_2_BXT;
+               break;
+       case PORT_D:
+               ddc_pin = GMBUS_PIN_4_CNP;
+               break;
+       case PORT_F:
+               ddc_pin = GMBUS_PIN_3_BXT;
+               break;
+       default:
+               MISSING_CASE(port);
+               ddc_pin = GMBUS_PIN_1_BXT;
+               break;
+       }
+       return ddc_pin;
+}
+
+static u8 icl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
+{
+       u8 ddc_pin;
+
+       switch (port) {
+       case PORT_A:
+               ddc_pin = GMBUS_PIN_1_BXT;
+               break;
+       case PORT_B:
+               ddc_pin = GMBUS_PIN_2_BXT;
+               break;
+       case PORT_C:
+               ddc_pin = GMBUS_PIN_9_TC1_ICP;
+               break;
+       case PORT_D:
+               ddc_pin = GMBUS_PIN_10_TC2_ICP;
+               break;
+       case PORT_E:
+               ddc_pin = GMBUS_PIN_11_TC3_ICP;
+               break;
+       case PORT_F:
+               ddc_pin = GMBUS_PIN_12_TC4_ICP;
+               break;
+       default:
+               MISSING_CASE(port);
+               ddc_pin = GMBUS_PIN_2_BXT;
+               break;
+       }
+       return ddc_pin;
+}
+
+static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv,
+                             enum port port)
+{
+       u8 ddc_pin;
+
+       switch (port) {
+       case PORT_B:
+               ddc_pin = GMBUS_PIN_DPB;
+               break;
+       case PORT_C:
+               ddc_pin = GMBUS_PIN_DPC;
+               break;
+       case PORT_D:
+               ddc_pin = GMBUS_PIN_DPD;
+               break;
+       default:
+               MISSING_CASE(port);
+               ddc_pin = GMBUS_PIN_DPB;
+               break;
+       }
+       return ddc_pin;
+}
+
+static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
+                            enum port port)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[port];
+       u8 ddc_pin;
+
+       if (info->alternate_ddc_pin) {
+               DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (VBT)\n",
+                             info->alternate_ddc_pin, port_name(port));
+               return info->alternate_ddc_pin;
+       }
+
+       if (HAS_PCH_ICP(dev_priv))
+               ddc_pin = icl_port_to_ddc_pin(dev_priv, port);
+       else if (HAS_PCH_CNP(dev_priv))
+               ddc_pin = cnp_port_to_ddc_pin(dev_priv, port);
+       else if (IS_GEN9_LP(dev_priv))
+               ddc_pin = bxt_port_to_ddc_pin(dev_priv, port);
+       else if (IS_CHERRYVIEW(dev_priv))
+               ddc_pin = chv_port_to_ddc_pin(dev_priv, port);
+       else
+               ddc_pin = g4x_port_to_ddc_pin(dev_priv, port);
+
+       DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (platform default)\n",
+                     ddc_pin, port_name(port));
+
+       return ddc_pin;
+}
+
+void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(intel_dig_port->base.base.dev);
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               intel_dig_port->write_infoframe = vlv_write_infoframe;
+               intel_dig_port->read_infoframe = vlv_read_infoframe;
+               intel_dig_port->set_infoframes = vlv_set_infoframes;
+               intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
+       } else if (IS_G4X(dev_priv)) {
+               intel_dig_port->write_infoframe = g4x_write_infoframe;
+               intel_dig_port->read_infoframe = g4x_read_infoframe;
+               intel_dig_port->set_infoframes = g4x_set_infoframes;
+               intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
+       } else if (HAS_DDI(dev_priv)) {
+               if (intel_dig_port->lspcon.active) {
+                       intel_dig_port->write_infoframe = lspcon_write_infoframe;
+                       intel_dig_port->read_infoframe = lspcon_read_infoframe;
+                       intel_dig_port->set_infoframes = lspcon_set_infoframes;
+                       intel_dig_port->infoframes_enabled = lspcon_infoframes_enabled;
+               } else {
+                       intel_dig_port->write_infoframe = hsw_write_infoframe;
+                       intel_dig_port->read_infoframe = hsw_read_infoframe;
+                       intel_dig_port->set_infoframes = hsw_set_infoframes;
+                       intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
+               }
+       } else if (HAS_PCH_IBX(dev_priv)) {
+               intel_dig_port->write_infoframe = ibx_write_infoframe;
+               intel_dig_port->read_infoframe = ibx_read_infoframe;
+               intel_dig_port->set_infoframes = ibx_set_infoframes;
+               intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
+       } else {
+               intel_dig_port->write_infoframe = cpt_write_infoframe;
+               intel_dig_port->read_infoframe = cpt_read_infoframe;
+               intel_dig_port->set_infoframes = cpt_set_infoframes;
+               intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
+       }
+}
+
+void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
+                              struct intel_connector *intel_connector)
+{
+       struct drm_connector *connector = &intel_connector->base;
+       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       enum port port = intel_encoder->port;
+
+       DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
+                     port_name(port));
+
+       if (WARN(intel_dig_port->max_lanes < 4,
+                "Not enough lanes (%d) for HDMI on port %c\n",
+                intel_dig_port->max_lanes, port_name(port)))
+               return;
+
+       drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
+                          DRM_MODE_CONNECTOR_HDMIA);
+       drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
+
+       connector->interlace_allowed = 1;
+       connector->doublescan_allowed = 0;
+       connector->stereo_allowed = 1;
+
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               connector->ycbcr_420_allowed = true;
+
+       intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(dev_priv, port);
+
+       if (WARN_ON(port == PORT_A))
+               return;
+       intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
+
+       if (HAS_DDI(dev_priv))
+               intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
+       else
+               intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       intel_hdmi_add_properties(intel_hdmi, connector);
+
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
+       intel_hdmi->attached_connector = intel_connector;
+
+       if (is_hdcp_supported(dev_priv, port)) {
+               int ret = intel_hdcp_init(intel_connector,
+                                         &intel_hdmi_hdcp_shim);
+               if (ret)
+                       DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
+       }
+
+       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
+        * 0xd.  Failure to do so will result in spurious interrupts being
+        * generated on the port when a cable is not attached.
+        */
+       if (IS_G45(dev_priv)) {
+               u32 temp = I915_READ(PEG_BAND_GAP_DATA);
+               I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
+       }
+
+       intel_hdmi->cec_notifier = cec_notifier_get_conn(dev->dev,
+                                                        port_identifier(port));
+       if (!intel_hdmi->cec_notifier)
+               DRM_DEBUG_KMS("CEC notifier get failed\n");
+}
+
+void intel_hdmi_init(struct drm_i915_private *dev_priv,
+                    i915_reg_t hdmi_reg, enum port port)
+{
+       struct intel_digital_port *intel_dig_port;
+       struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
+
+       intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
+       if (!intel_dig_port)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(intel_dig_port);
+               return;
+       }
+
+       intel_encoder = &intel_dig_port->base;
+
+       drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
+                        &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
+                        "HDMI %c", port_name(port));
+
+       intel_encoder->hotplug = intel_encoder_hotplug;
+       intel_encoder->compute_config = intel_hdmi_compute_config;
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               intel_encoder->disable = pch_disable_hdmi;
+               intel_encoder->post_disable = pch_post_disable_hdmi;
+       } else {
+               intel_encoder->disable = g4x_disable_hdmi;
+       }
+       intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
+       intel_encoder->get_config = intel_hdmi_get_config;
+       if (IS_CHERRYVIEW(dev_priv)) {
+               intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable;
+               intel_encoder->pre_enable = chv_hdmi_pre_enable;
+               intel_encoder->enable = vlv_enable_hdmi;
+               intel_encoder->post_disable = chv_hdmi_post_disable;
+               intel_encoder->post_pll_disable = chv_hdmi_post_pll_disable;
+       } else if (IS_VALLEYVIEW(dev_priv)) {
+               intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable;
+               intel_encoder->pre_enable = vlv_hdmi_pre_enable;
+               intel_encoder->enable = vlv_enable_hdmi;
+               intel_encoder->post_disable = vlv_hdmi_post_disable;
+       } else {
+               intel_encoder->pre_enable = intel_hdmi_pre_enable;
+               if (HAS_PCH_CPT(dev_priv))
+                       intel_encoder->enable = cpt_enable_hdmi;
+               else if (HAS_PCH_IBX(dev_priv))
+                       intel_encoder->enable = ibx_enable_hdmi;
+               else
+                       intel_encoder->enable = g4x_enable_hdmi;
+       }
+
+       intel_encoder->type = INTEL_OUTPUT_HDMI;
+       intel_encoder->power_domain = intel_port_to_power_domain(port);
+       intel_encoder->port = port;
+       if (IS_CHERRYVIEW(dev_priv)) {
+               if (port == PORT_D)
+                       intel_encoder->crtc_mask = 1 << 2;
+               else
+                       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+       } else {
+               intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+       }
+       intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
+       /*
+        * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
+        * to work on real hardware. And since g4x can send infoframes to
+        * only one port anyway, nothing is lost by allowing it.
+        */
+       if (IS_G4X(dev_priv))
+               intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
+
+       intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
+       intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
+       intel_dig_port->max_lanes = 4;
+
+       intel_infoframe_init(intel_dig_port);
+
+       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
+       intel_hdmi_init_connector(intel_dig_port, intel_connector);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
new file mode 100644 (file)
index 0000000..106c2e0
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_HDMI_H__
+#define __INTEL_HDMI_H__
+
+#include <linux/hdmi.h>
+#include <linux/types.h>
+
+#include <drm/i915_drm.h>
+
+#include "i915_reg.h"
+
+struct drm_connector;
+struct drm_encoder;
+struct drm_i915_private;
+struct intel_connector;
+struct intel_digital_port;
+struct intel_encoder;
+struct intel_crtc_state;
+struct intel_hdmi;
+struct drm_connector_state;
+union hdmi_infoframe;
+
+void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg,
+                    enum port port);
+void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
+                              struct intel_connector *intel_connector);
+struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
+int intel_hdmi_compute_config(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state);
+bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
+                                      struct drm_connector *connector,
+                                      bool high_tmds_clock_ratio,
+                                      bool scrambling);
+void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
+void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
+u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state);
+u32 intel_hdmi_infoframe_enable(unsigned int type);
+void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
+                                  struct intel_crtc_state *crtc_state);
+void intel_read_infoframe(struct intel_encoder *encoder,
+                         const struct intel_crtc_state *crtc_state,
+                         enum hdmi_infoframe_type type,
+                         union hdmi_infoframe *frame);
+
+#endif /* __INTEL_HDMI_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c
new file mode 100644 (file)
index 0000000..7028d0c
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_dp_dual_mode_helper.h>
+#include <drm/drm_edid.h>
+
+#include "intel_dp.h"
+#include "intel_drv.h"
+#include "intel_lspcon.h"
+
+/* LSPCON OUI Vendor ID(signatures) */
+#define LSPCON_VENDOR_PARADE_OUI 0x001CF8
+#define LSPCON_VENDOR_MCA_OUI 0x0060AD
+
+/* AUX addresses to write MCA AVI IF */
+#define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
+#define LSPCON_MCA_AVI_IF_CTRL 0x5DF
+#define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
+#define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
+
+/* AUX addresses to write Parade AVI IF */
+#define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
+#define LSPCON_PARADE_AVI_IF_CTRL 0x51E
+#define  LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
+#define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
+
+static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
+{
+       struct intel_digital_port *dig_port =
+               container_of(lspcon, struct intel_digital_port, lspcon);
+
+       return &dig_port->dp;
+}
+
+static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
+{
+       switch (mode) {
+       case DRM_LSPCON_MODE_PCON:
+               return "PCON";
+       case DRM_LSPCON_MODE_LS:
+               return "LS";
+       case DRM_LSPCON_MODE_INVALID:
+               return "INVALID";
+       default:
+               MISSING_CASE(mode);
+               return "INVALID";
+       }
+}
+
+static bool lspcon_detect_vendor(struct intel_lspcon *lspcon)
+{
+       struct intel_dp *dp = lspcon_to_intel_dp(lspcon);
+       struct drm_dp_dpcd_ident *ident;
+       u32 vendor_oui;
+
+       if (drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd))) {
+               DRM_ERROR("Can't read description\n");
+               return false;
+       }
+
+       ident = &dp->desc.ident;
+       vendor_oui = (ident->oui[0] << 16) | (ident->oui[1] << 8) |
+                     ident->oui[2];
+
+       switch (vendor_oui) {
+       case LSPCON_VENDOR_MCA_OUI:
+               lspcon->vendor = LSPCON_VENDOR_MCA;
+               DRM_DEBUG_KMS("Vendor: Mega Chips\n");
+               break;
+
+       case LSPCON_VENDOR_PARADE_OUI:
+               lspcon->vendor = LSPCON_VENDOR_PARADE;
+               DRM_DEBUG_KMS("Vendor: Parade Tech\n");
+               break;
+
+       default:
+               DRM_ERROR("Invalid/Unknown vendor OUI\n");
+               return false;
+       }
+
+       return true;
+}
+
+static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
+{
+       enum drm_lspcon_mode current_mode;
+       struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
+
+       if (drm_lspcon_get_mode(adapter, &current_mode)) {
+               DRM_DEBUG_KMS("Error reading LSPCON mode\n");
+               return DRM_LSPCON_MODE_INVALID;
+       }
+       return current_mode;
+}
+
+static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
+                                            enum drm_lspcon_mode mode)
+{
+       enum drm_lspcon_mode current_mode;
+
+       current_mode = lspcon_get_current_mode(lspcon);
+       if (current_mode == mode)
+               goto out;
+
+       DRM_DEBUG_KMS("Waiting for LSPCON mode %s to settle\n",
+                     lspcon_mode_name(mode));
+
+       wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, 400);
+       if (current_mode != mode)
+               DRM_ERROR("LSPCON mode hasn't settled\n");
+
+out:
+       DRM_DEBUG_KMS("Current LSPCON mode %s\n",
+                     lspcon_mode_name(current_mode));
+
+       return current_mode;
+}
+
+static int lspcon_change_mode(struct intel_lspcon *lspcon,
+                             enum drm_lspcon_mode mode)
+{
+       int err;
+       enum drm_lspcon_mode current_mode;
+       struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
+
+       err = drm_lspcon_get_mode(adapter, &current_mode);
+       if (err) {
+               DRM_ERROR("Error reading LSPCON mode\n");
+               return err;
+       }
+
+       if (current_mode == mode) {
+               DRM_DEBUG_KMS("Current mode = desired LSPCON mode\n");
+               return 0;
+       }
+
+       err = drm_lspcon_set_mode(adapter, mode);
+       if (err < 0) {
+               DRM_ERROR("LSPCON mode change failed\n");
+               return err;
+       }
+
+       lspcon->mode = mode;
+       DRM_DEBUG_KMS("LSPCON mode changed done\n");
+       return 0;
+}
+
+static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
+{
+       u8 rev;
+
+       if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV,
+                             &rev) != 1) {
+               DRM_DEBUG_KMS("Native AUX CH down\n");
+               return false;
+       }
+
+       DRM_DEBUG_KMS("Native AUX CH up, DPCD version: %d.%d\n",
+                     rev >> 4, rev & 0xf);
+
+       return true;
+}
+
+void lspcon_ycbcr420_config(struct drm_connector *connector,
+                           struct intel_crtc_state *crtc_state)
+{
+       const struct drm_display_info *info = &connector->display_info;
+       const struct drm_display_mode *adjusted_mode =
+                                       &crtc_state->base.adjusted_mode;
+
+       if (drm_mode_is_420_only(info, adjusted_mode) &&
+           connector->ycbcr_420_allowed) {
+               crtc_state->port_clock /= 2;
+               crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
+               crtc_state->lspcon_downsampling = true;
+       }
+}
+
+static bool lspcon_probe(struct intel_lspcon *lspcon)
+{
+       int retry;
+       enum drm_dp_dual_mode_type adaptor_type;
+       struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
+       enum drm_lspcon_mode expected_mode;
+
+       expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
+                       DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
+
+       /* Lets probe the adaptor and check its type */
+       for (retry = 0; retry < 6; retry++) {
+               if (retry)
+                       usleep_range(500, 1000);
+
+               adaptor_type = drm_dp_dual_mode_detect(adapter);
+               if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON)
+                       break;
+       }
+
+       if (adaptor_type != DRM_DP_DUAL_MODE_LSPCON) {
+               DRM_DEBUG_KMS("No LSPCON detected, found %s\n",
+                              drm_dp_get_dual_mode_type_name(adaptor_type));
+               return false;
+       }
+
+       /* Yay ... got a LSPCON device */
+       DRM_DEBUG_KMS("LSPCON detected\n");
+       lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
+
+       /*
+        * In the SW state machine, lets Put LSPCON in PCON mode only.
+        * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
+        * 2.0 sinks.
+        */
+       if (lspcon->mode != DRM_LSPCON_MODE_PCON) {
+               if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
+                       DRM_ERROR("LSPCON mode change to PCON failed\n");
+                       return false;
+               }
+       }
+       return true;
+}
+
+static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
+{
+       struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       unsigned long start = jiffies;
+
+       while (1) {
+               if (intel_digital_port_connected(&dig_port->base)) {
+                       DRM_DEBUG_KMS("LSPCON recovering in PCON mode after %u ms\n",
+                                     jiffies_to_msecs(jiffies - start));
+                       return;
+               }
+
+               if (time_after(jiffies, start + msecs_to_jiffies(1000)))
+                       break;
+
+               usleep_range(10000, 15000);
+       }
+
+       DRM_DEBUG_KMS("LSPCON DP descriptor mismatch after resume\n");
+}
+
+static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
+{
+       u8 avi_if_ctrl;
+       u8 retry;
+       ssize_t ret;
+
+       /* Check if LSPCON FW is ready for data */
+       for (retry = 0; retry < 5; retry++) {
+               if (retry)
+                       usleep_range(200, 300);
+
+               ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
+                                      &avi_if_ctrl, 1);
+               if (ret < 0) {
+                       DRM_ERROR("Failed to read AVI IF control\n");
+                       return false;
+               }
+
+               if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0)
+                       return true;
+       }
+
+       DRM_ERROR("Parade FW not ready to accept AVI IF\n");
+       return false;
+}
+
+static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
+                                                 u8 *avi_buf)
+{
+       u8 avi_if_ctrl;
+       u8 block_count = 0;
+       u8 *data;
+       u16 reg;
+       ssize_t ret;
+
+       while (block_count < 4) {
+               if (!lspcon_parade_fw_ready(aux)) {
+                       DRM_DEBUG_KMS("LSPCON FW not ready, block %d\n",
+                                     block_count);
+                       return false;
+               }
+
+               reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
+               data = avi_buf + block_count * 8;
+               ret = drm_dp_dpcd_write(aux, reg, data, 8);
+               if (ret < 0) {
+                       DRM_ERROR("Failed to write AVI IF block %d\n",
+                                 block_count);
+                       return false;
+               }
+
+               /*
+                * Once a block of data is written, we have to inform the FW
+                * about this by writing into avi infoframe control register:
+                * - set the kickoff bit[7] to 1
+                * - write the block no. to bits[1:0]
+                */
+               reg = LSPCON_PARADE_AVI_IF_CTRL;
+               avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
+               ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
+               if (ret < 0) {
+                       DRM_ERROR("Failed to update (0x%x), block %d\n",
+                                 reg, block_count);
+                       return false;
+               }
+
+               block_count++;
+       }
+
+       DRM_DEBUG_KMS("Wrote AVI IF blocks successfully\n");
+       return true;
+}
+
+static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
+                                              const u8 *frame,
+                                              ssize_t len)
+{
+       u8 avi_if[LSPCON_PARADE_AVI_IF_DATA_SIZE] = {1, };
+
+       /*
+        * Parade's frames contains 32 bytes of data, divided
+        * into 4 frames:
+        *      Token byte (first byte of first frame, must be non-zero)
+        *      HB0 to HB2       from AVI IF (3 bytes header)
+        *      PB0 to PB27 from AVI IF (28 bytes data)
+        * So it should look like this
+        *      first block: | <token> <HB0-HB2> <DB0-DB3> |
+        *      next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
+        */
+
+       if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
+               DRM_ERROR("Invalid length of infoframes\n");
+               return false;
+       }
+
+       memcpy(&avi_if[1], frame, len);
+
+       if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
+               DRM_DEBUG_KMS("Failed to write infoframe blocks\n");
+               return false;
+       }
+
+       return true;
+}
+
+static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
+                                           const u8 *buffer, ssize_t len)
+{
+       int ret;
+       u32 val = 0;
+       u32 retry;
+       u16 reg;
+       const u8 *data = buffer;
+
+       reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
+       while (val < len) {
+               /* DPCD write for AVI IF can fail on a slow FW day, so retry */
+               for (retry = 0; retry < 5; retry++) {
+                       ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
+                       if (ret == 1) {
+                               break;
+                       } else if (retry < 4) {
+                               mdelay(50);
+                               continue;
+                       } else {
+                               DRM_ERROR("DPCD write failed at:0x%x\n", reg);
+                               return false;
+                       }
+               }
+               val++; reg++; data++;
+       }
+
+       val = 0;
+       reg = LSPCON_MCA_AVI_IF_CTRL;
+       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       /* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
+       val &= ~LSPCON_MCA_AVI_IF_HANDLED;
+       val |= LSPCON_MCA_AVI_IF_KICKOFF;
+
+       ret = drm_dp_dpcd_write(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       val = 0;
+       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       if (val == LSPCON_MCA_AVI_IF_HANDLED)
+               DRM_DEBUG_KMS("AVI IF handled by FW\n");
+
+       return true;
+}
+
+void lspcon_write_infoframe(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           unsigned int type,
+                           const void *frame, ssize_t len)
+{
+       bool ret;
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
+
+       /* LSPCON only needs AVI IF */
+       if (type != HDMI_INFOFRAME_TYPE_AVI)
+               return;
+
+       if (lspcon->vendor == LSPCON_VENDOR_MCA)
+               ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
+                                                     frame, len);
+       else
+               ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
+                                                        frame, len);
+
+       if (!ret) {
+               DRM_ERROR("Failed to write AVI infoframes\n");
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("AVI infoframes updated successfully\n");
+}
+
+void lspcon_read_infoframe(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *crtc_state,
+                          unsigned int type,
+                          void *frame, ssize_t len)
+{
+       /* FIXME implement this */
+}
+
+void lspcon_set_infoframes(struct intel_encoder *encoder,
+                          bool enable,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state)
+{
+       ssize_t ret;
+       union hdmi_infoframe frame;
+       u8 buf[VIDEO_DIP_DATA_SIZE];
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_lspcon *lspcon = &dig_port->lspcon;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+
+       if (!lspcon->active) {
+               DRM_ERROR("Writing infoframes while LSPCON disabled ?\n");
+               return;
+       }
+
+       /* FIXME precompute infoframes */
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
+                                                      conn_state->connector,
+                                                      adjusted_mode);
+       if (ret < 0) {
+               DRM_ERROR("couldn't fill AVI infoframe\n");
+               return;
+       }
+
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
+               if (crtc_state->lspcon_downsampling)
+                       frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
+               else
+                       frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
+       } else {
+               frame.avi.colorspace = HDMI_COLORSPACE_RGB;
+       }
+
+       drm_hdmi_avi_infoframe_quant_range(&frame.avi,
+                                          conn_state->connector,
+                                          adjusted_mode,
+                                          crtc_state->limited_color_range ?
+                                          HDMI_QUANTIZATION_RANGE_LIMITED :
+                                          HDMI_QUANTIZATION_RANGE_FULL);
+
+       ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
+       if (ret < 0) {
+               DRM_ERROR("Failed to pack AVI IF\n");
+               return;
+       }
+
+       dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI,
+                                 buf, ret);
+}
+
+u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config)
+{
+       /* FIXME actually read this from the hw */
+       return enc_to_intel_lspcon(&encoder->base)->active;
+}
+
+void lspcon_resume(struct intel_lspcon *lspcon)
+{
+       enum drm_lspcon_mode expected_mode;
+
+       if (lspcon_wake_native_aux_ch(lspcon)) {
+               expected_mode = DRM_LSPCON_MODE_PCON;
+               lspcon_resume_in_pcon_wa(lspcon);
+       } else {
+               expected_mode = DRM_LSPCON_MODE_LS;
+       }
+
+       if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
+               return;
+
+       if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
+               DRM_ERROR("LSPCON resume failed\n");
+       else
+               DRM_DEBUG_KMS("LSPCON resume success\n");
+}
+
+void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
+{
+       lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
+}
+
+bool lspcon_init(struct intel_digital_port *intel_dig_port)
+{
+       struct intel_dp *dp = &intel_dig_port->dp;
+       struct intel_lspcon *lspcon = &intel_dig_port->lspcon;
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_connector *connector = &dp->attached_connector->base;
+
+       if (!HAS_LSPCON(dev_priv)) {
+               DRM_ERROR("LSPCON is not supported on this platform\n");
+               return false;
+       }
+
+       lspcon->active = false;
+       lspcon->mode = DRM_LSPCON_MODE_INVALID;
+
+       if (!lspcon_probe(lspcon)) {
+               DRM_ERROR("Failed to probe lspcon\n");
+               return false;
+       }
+
+       if (!intel_dp_read_dpcd(dp)) {
+               DRM_ERROR("LSPCON DPCD read failed\n");
+               return false;
+       }
+
+       if (!lspcon_detect_vendor(lspcon)) {
+               DRM_ERROR("LSPCON vendor detection failed\n");
+               return false;
+       }
+
+       connector->ycbcr_420_allowed = true;
+       lspcon->active = true;
+       DRM_DEBUG_KMS("Success: LSPCON init\n");
+       return true;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.h b/drivers/gpu/drm/i915/display/intel_lspcon.h
new file mode 100644 (file)
index 0000000..37cfddf
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_LSPCON_H__
+#define __INTEL_LSPCON_H__
+
+#include <linux/types.h>
+
+struct drm_connector;
+struct drm_connector_state;
+struct intel_crtc_state;
+struct intel_digital_port;
+struct intel_encoder;
+struct intel_lspcon;
+
+bool lspcon_init(struct intel_digital_port *intel_dig_port);
+void lspcon_resume(struct intel_lspcon *lspcon);
+void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
+void lspcon_write_infoframe(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           unsigned int type,
+                           const void *buf, ssize_t len);
+void lspcon_read_infoframe(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *crtc_state,
+                          unsigned int type,
+                          void *frame, ssize_t len);
+void lspcon_set_infoframes(struct intel_encoder *encoder,
+                          bool enable,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state);
+u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config);
+void lspcon_ycbcr420_config(struct drm_connector *connector,
+                           struct intel_crtc_state *crtc_state);
+
+#endif /* __INTEL_LSPCON_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
new file mode 100644 (file)
index 0000000..efefed6
--- /dev/null
@@ -0,0 +1,1008 @@
+/*
+ * Copyright © 2006-2007 Intel Corporation
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <acpi/button.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/vga_switcheroo.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_connector.h"
+#include "intel_drv.h"
+#include "intel_gmbus.h"
+#include "intel_lvds.h"
+#include "intel_panel.h"
+
+/* Private structure for the integrated LVDS support */
+struct intel_lvds_pps {
+       /* 100us units */
+       int t1_t2;
+       int t3;
+       int t4;
+       int t5;
+       int tx;
+
+       int divider;
+
+       int port;
+       bool powerdown_on_reset;
+};
+
+struct intel_lvds_encoder {
+       struct intel_encoder base;
+
+       bool is_dual_link;
+       i915_reg_t reg;
+       u32 a3_power;
+
+       struct intel_lvds_pps init_pps;
+       u32 init_lvds_val;
+
+       struct intel_connector *attached_connector;
+};
+
+static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
+{
+       return container_of(encoder, struct intel_lvds_encoder, base.base);
+}
+
+bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
+                            i915_reg_t lvds_reg, enum pipe *pipe)
+{
+       u32 val;
+
+       val = I915_READ(lvds_reg);
+
+       /* asserts want to know the pipe even if the port is disabled */
+       if (HAS_PCH_CPT(dev_priv))
+               *pipe = (val & LVDS_PIPE_SEL_MASK_CPT) >> LVDS_PIPE_SEL_SHIFT_CPT;
+       else
+               *pipe = (val & LVDS_PIPE_SEL_MASK) >> LVDS_PIPE_SEL_SHIFT;
+
+       return val & LVDS_PORT_EN;
+}
+
+static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
+                                   enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+       intel_wakeref_t wakeref;
+       bool ret;
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       ret = intel_lvds_port_enabled(dev_priv, lvds_encoder->reg, pipe);
+
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+
+       return ret;
+}
+
+static void intel_lvds_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+       u32 tmp, flags = 0;
+
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_LVDS);
+
+       tmp = I915_READ(lvds_encoder->reg);
+       if (tmp & LVDS_HSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       if (tmp & LVDS_VSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_PVSYNC;
+
+       pipe_config->base.adjusted_mode.flags |= flags;
+
+       if (INTEL_GEN(dev_priv) < 5)
+               pipe_config->gmch_pfit.lvds_border_bits =
+                       tmp & LVDS_BORDER_ENABLE;
+
+       /* gen2/3 store dither state in pfit control, needs to match */
+       if (INTEL_GEN(dev_priv) < 4) {
+               tmp = I915_READ(PFIT_CONTROL);
+
+               pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
+       }
+
+       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
+}
+
+static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv,
+                                       struct intel_lvds_pps *pps)
+{
+       u32 val;
+
+       pps->powerdown_on_reset = I915_READ(PP_CONTROL(0)) & PANEL_POWER_RESET;
+
+       val = I915_READ(PP_ON_DELAYS(0));
+       pps->port = REG_FIELD_GET(PANEL_PORT_SELECT_MASK, val);
+       pps->t1_t2 = REG_FIELD_GET(PANEL_POWER_UP_DELAY_MASK, val);
+       pps->t5 = REG_FIELD_GET(PANEL_LIGHT_ON_DELAY_MASK, val);
+
+       val = I915_READ(PP_OFF_DELAYS(0));
+       pps->t3 = REG_FIELD_GET(PANEL_POWER_DOWN_DELAY_MASK, val);
+       pps->tx = REG_FIELD_GET(PANEL_LIGHT_OFF_DELAY_MASK, val);
+
+       val = I915_READ(PP_DIVISOR(0));
+       pps->divider = REG_FIELD_GET(PP_REFERENCE_DIVIDER_MASK, val);
+       val = REG_FIELD_GET(PANEL_POWER_CYCLE_DELAY_MASK, val);
+       /*
+        * Remove the BSpec specified +1 (100ms) offset that accounts for a
+        * too short power-cycle delay due to the asynchronous programming of
+        * the register.
+        */
+       if (val)
+               val--;
+       /* Convert from 100ms to 100us units */
+       pps->t4 = val * 1000;
+
+       if (INTEL_GEN(dev_priv) <= 4 &&
+           pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) {
+               DRM_DEBUG_KMS("Panel power timings uninitialized, "
+                             "setting defaults\n");
+               /* Set T2 to 40ms and T5 to 200ms in 100 usec units */
+               pps->t1_t2 = 40 * 10;
+               pps->t5 = 200 * 10;
+               /* Set T3 to 35ms and Tx to 200ms in 100 usec units */
+               pps->t3 = 35 * 10;
+               pps->tx = 200 * 10;
+       }
+
+       DRM_DEBUG_DRIVER("LVDS PPS:t1+t2 %d t3 %d t4 %d t5 %d tx %d "
+                        "divider %d port %d powerdown_on_reset %d\n",
+                        pps->t1_t2, pps->t3, pps->t4, pps->t5, pps->tx,
+                        pps->divider, pps->port, pps->powerdown_on_reset);
+}
+
+static void intel_lvds_pps_init_hw(struct drm_i915_private *dev_priv,
+                                  struct intel_lvds_pps *pps)
+{
+       u32 val;
+
+       val = I915_READ(PP_CONTROL(0));
+       WARN_ON((val & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS);
+       if (pps->powerdown_on_reset)
+               val |= PANEL_POWER_RESET;
+       I915_WRITE(PP_CONTROL(0), val);
+
+       I915_WRITE(PP_ON_DELAYS(0),
+                  REG_FIELD_PREP(PANEL_PORT_SELECT_MASK, pps->port) |
+                  REG_FIELD_PREP(PANEL_POWER_UP_DELAY_MASK, pps->t1_t2) |
+                  REG_FIELD_PREP(PANEL_LIGHT_ON_DELAY_MASK, pps->t5));
+
+       I915_WRITE(PP_OFF_DELAYS(0),
+                  REG_FIELD_PREP(PANEL_POWER_DOWN_DELAY_MASK, pps->t3) |
+                  REG_FIELD_PREP(PANEL_LIGHT_OFF_DELAY_MASK, pps->tx));
+
+       I915_WRITE(PP_DIVISOR(0),
+                  REG_FIELD_PREP(PP_REFERENCE_DIVIDER_MASK, pps->divider) |
+                  REG_FIELD_PREP(PANEL_POWER_CYCLE_DELAY_MASK,
+                                 DIV_ROUND_UP(pps->t4, 1000) + 1));
+}
+
+static void intel_pre_enable_lvds(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *pipe_config,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       int pipe = crtc->pipe;
+       u32 temp;
+
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               assert_fdi_rx_pll_disabled(dev_priv, pipe);
+               assert_shared_dpll_disabled(dev_priv,
+                                           pipe_config->shared_dpll);
+       } else {
+               assert_pll_disabled(dev_priv, pipe);
+       }
+
+       intel_lvds_pps_init_hw(dev_priv, &lvds_encoder->init_pps);
+
+       temp = lvds_encoder->init_lvds_val;
+       temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+
+       if (HAS_PCH_CPT(dev_priv)) {
+               temp &= ~LVDS_PIPE_SEL_MASK_CPT;
+               temp |= LVDS_PIPE_SEL_CPT(pipe);
+       } else {
+               temp &= ~LVDS_PIPE_SEL_MASK;
+               temp |= LVDS_PIPE_SEL(pipe);
+       }
+
+       /* set the corresponsding LVDS_BORDER bit */
+       temp &= ~LVDS_BORDER_ENABLE;
+       temp |= pipe_config->gmch_pfit.lvds_border_bits;
+
+       /*
+        * Set the B0-B3 data pairs corresponding to whether we're going to
+        * set the DPLLs for dual-channel mode or not.
+        */
+       if (lvds_encoder->is_dual_link)
+               temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+       else
+               temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+
+       /*
+        * It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+        * appropriately here, but we need to look more thoroughly into how
+        * panels behave in the two modes. For now, let's just maintain the
+        * value we got from the BIOS.
+        */
+       temp &= ~LVDS_A3_POWER_MASK;
+       temp |= lvds_encoder->a3_power;
+
+       /*
+        * Set the dithering flag on LVDS as needed, note that there is no
+        * special lvds dither control bit on pch-split platforms, dithering is
+        * only controlled through the PIPECONF reg.
+        */
+       if (IS_GEN(dev_priv, 4)) {
+               /*
+                * Bspec wording suggests that LVDS port dithering only exists
+                * for 18bpp panels.
+                */
+               if (pipe_config->dither && pipe_config->pipe_bpp == 18)
+                       temp |= LVDS_ENABLE_DITHER;
+               else
+                       temp &= ~LVDS_ENABLE_DITHER;
+       }
+       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+               temp |= LVDS_HSYNC_POLARITY;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+               temp |= LVDS_VSYNC_POLARITY;
+
+       I915_WRITE(lvds_encoder->reg, temp);
+}
+
+/*
+ * Sets the power state for the panel.
+ */
+static void intel_enable_lvds(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config,
+                             const struct drm_connector_state *conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN);
+
+       I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) | PANEL_POWER_ON);
+       POSTING_READ(lvds_encoder->reg);
+
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   PP_STATUS(0), PP_ON, PP_ON, 5000))
+               DRM_ERROR("timed out waiting for panel to power on\n");
+
+       intel_panel_enable_backlight(pipe_config, conn_state);
+}
+
+static void intel_disable_lvds(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *old_crtc_state,
+                              const struct drm_connector_state *old_conn_state)
+{
+       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) & ~PANEL_POWER_ON);
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   PP_STATUS(0), PP_ON, 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power off\n");
+
+       I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN);
+       POSTING_READ(lvds_encoder->reg);
+}
+
+static void gmch_disable_lvds(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+
+{
+       intel_panel_disable_backlight(old_conn_state);
+
+       intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
+}
+
+static void pch_disable_lvds(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *old_crtc_state,
+                            const struct drm_connector_state *old_conn_state)
+{
+       intel_panel_disable_backlight(old_conn_state);
+}
+
+static void pch_post_disable_lvds(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *old_crtc_state,
+                                 const struct drm_connector_state *old_conn_state)
+{
+       intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
+}
+
+static enum drm_mode_status
+intel_lvds_mode_valid(struct drm_connector *connector,
+                     struct drm_display_mode *mode)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+       int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+       if (mode->hdisplay > fixed_mode->hdisplay)
+               return MODE_PANEL;
+       if (mode->vdisplay > fixed_mode->vdisplay)
+               return MODE_PANEL;
+       if (fixed_mode->clock > max_pixclk)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
+       struct intel_lvds_encoder *lvds_encoder =
+               to_lvds_encoder(&intel_encoder->base);
+       struct intel_connector *intel_connector =
+               lvds_encoder->attached_connector;
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       unsigned int lvds_bpp;
+
+       /* Should never happen!! */
+       if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) {
+               DRM_ERROR("Can't support LVDS on pipe A\n");
+               return -EINVAL;
+       }
+
+       if (lvds_encoder->a3_power == LVDS_A3_POWER_UP)
+               lvds_bpp = 8*3;
+       else
+               lvds_bpp = 6*3;
+
+       if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) {
+               DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n",
+                             pipe_config->pipe_bpp, lvds_bpp);
+               pipe_config->pipe_bpp = lvds_bpp;
+       }
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       /*
+        * We have timings from the BIOS for the panel, put them in
+        * to the adjusted mode.  The CRTC will be set up for this mode,
+        * with the panel scaling set up to source from the H/VDisplay
+        * of the original mode.
+        */
+       intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
+                              adjusted_mode);
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               pipe_config->has_pch_encoder = true;
+
+               intel_pch_panel_fitting(intel_crtc, pipe_config,
+                                       conn_state->scaling_mode);
+       } else {
+               intel_gmch_panel_fitting(intel_crtc, pipe_config,
+                                        conn_state->scaling_mode);
+
+       }
+
+       /*
+        * XXX: It would be nice to support lower refresh rates on the
+        * panels to reduce power consumption, and perhaps match the
+        * user's requested refresh rate.
+        */
+
+       return 0;
+}
+
+static enum drm_connector_status
+intel_lvds_detect(struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+/*
+ * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
+ */
+static int intel_lvds_get_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode;
+
+       /* use cached edid if we have one */
+       if (!IS_ERR_OR_NULL(intel_connector->edid))
+               return drm_add_edid_modes(connector, intel_connector->edid);
+
+       mode = drm_mode_duplicate(dev, intel_connector->panel.fixed_mode);
+       if (mode == NULL)
+               return 0;
+
+       drm_mode_probed_add(connector, mode);
+       return 1;
+}
+
+static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
+       .get_modes = intel_lvds_get_modes,
+       .mode_valid = intel_lvds_mode_valid,
+       .atomic_check = intel_digital_connector_atomic_check,
+};
+
+static const struct drm_connector_funcs intel_lvds_connector_funcs = {
+       .detect = intel_lvds_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
+       .destroy = intel_encoder_destroy,
+};
+
+static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
+{
+       DRM_INFO("Skipping LVDS initialization for %s\n", id->ident);
+       return 1;
+}
+
+/* These systems claim to have LVDS, but really don't */
+static const struct dmi_system_id intel_no_lvds[] = {
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Apple Mac Mini (Core series)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Apple Mac Mini (Core 2 series)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "MSI IM-945GSE-A",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A9830IMS"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Dell Studio Hybrid",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Dell OptiPlex FX170",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex FX170"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "AOpen Mini PC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "AOpen"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "AOpen Mini PC MP915",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+                       DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "AOpen i915GMm-HFS",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+                       DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+                .ident = "AOpen i45GMx-I",
+                .matches = {
+                        DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+                        DMI_MATCH(DMI_BOARD_NAME, "i45GMx-I"),
+                },
+        },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Aopen i945GTt-VFA",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Clientron U800",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "U800"),
+               },
+       },
+       {
+                .callback = intel_no_lvds_dmi_callback,
+                .ident = "Clientron E830",
+                .matches = {
+                        DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
+                        DMI_MATCH(DMI_PRODUCT_NAME, "E830"),
+                },
+        },
+        {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Asus EeeBox PC EB1007",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EB1007"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Asus AT5NM10T-I",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Hewlett-Packard HP t5740",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, " t5740"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Hewlett-Packard t5745",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "hp t5745"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Hewlett-Packard st5747",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "hp st5747"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "MSI Wind Box DC500",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+                       DMI_MATCH(DMI_BOARD_NAME, "MS-7469"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Gigabyte GA-D525TUD",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
+                       DMI_MATCH(DMI_BOARD_NAME, "D525TUD"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Supermicro X7SPA-H",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Fujitsu Esprimo Q900",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D410PT",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_MATCH(DMI_BOARD_NAME, "D410PT"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D425KT",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D425KT"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D510MO",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D510MO"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D525MW",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Radiant P845",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "P845"),
+               },
+       },
+
+       { }     /* terminating entry */
+};
+
+static int intel_dual_link_lvds_callback(const struct dmi_system_id *id)
+{
+       DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident);
+       return 1;
+}
+
+static const struct dmi_system_id intel_dual_link_lvds[] = {
+       {
+               .callback = intel_dual_link_lvds_callback,
+               .ident = "Apple MacBook Pro 15\" (2010)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"),
+               },
+       },
+       {
+               .callback = intel_dual_link_lvds_callback,
+               .ident = "Apple MacBook Pro 15\" (2011)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
+               },
+       },
+       {
+               .callback = intel_dual_link_lvds_callback,
+               .ident = "Apple MacBook Pro 15\" (2012)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"),
+               },
+       },
+       { }     /* terminating entry */
+};
+
+struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder;
+
+       for_each_intel_encoder(&dev_priv->drm, encoder) {
+               if (encoder->type == INTEL_OUTPUT_LVDS)
+                       return encoder;
+       }
+
+       return NULL;
+}
+
+bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder = intel_get_lvds_encoder(dev_priv);
+
+       return encoder && to_lvds_encoder(&encoder->base)->is_dual_link;
+}
+
+static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
+{
+       struct drm_device *dev = lvds_encoder->base.base.dev;
+       unsigned int val;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       /* use the module option value if specified */
+       if (i915_modparams.lvds_channel_mode > 0)
+               return i915_modparams.lvds_channel_mode == 2;
+
+       /* single channel LVDS is limited to 112 MHz */
+       if (lvds_encoder->attached_connector->panel.fixed_mode->clock > 112999)
+               return true;
+
+       if (dmi_check_system(intel_dual_link_lvds))
+               return true;
+
+       /*
+        * BIOS should set the proper LVDS register value at boot, but
+        * in reality, it doesn't set the value when the lid is closed;
+        * we need to check "the value to be set" in VBT when LVDS
+        * register is uninitialized.
+        */
+       val = I915_READ(lvds_encoder->reg);
+       if (HAS_PCH_CPT(dev_priv))
+               val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK_CPT);
+       else
+               val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK);
+       if (val == 0)
+               val = dev_priv->vbt.bios_lvds_val;
+
+       return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
+}
+
+/**
+ * intel_lvds_init - setup LVDS connectors on this device
+ * @dev_priv: i915 device
+ *
+ * Create the connector, register the LVDS DDC bus, and try to figure out what
+ * modes we can display on the LVDS panel (if present).
+ */
+void intel_lvds_init(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = &dev_priv->drm;
+       struct intel_lvds_encoder *lvds_encoder;
+       struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct drm_display_mode *fixed_mode = NULL;
+       struct drm_display_mode *downclock_mode = NULL;
+       struct edid *edid;
+       i915_reg_t lvds_reg;
+       u32 lvds;
+       u8 pin;
+       u32 allowed_scalers;
+
+       /* Skip init on machines we know falsely report LVDS */
+       if (dmi_check_system(intel_no_lvds)) {
+               WARN(!dev_priv->vbt.int_lvds_support,
+                    "Useless DMI match. Internal LVDS support disabled by VBT\n");
+               return;
+       }
+
+       if (!dev_priv->vbt.int_lvds_support) {
+               DRM_DEBUG_KMS("Internal LVDS support disabled by VBT\n");
+               return;
+       }
+
+       if (HAS_PCH_SPLIT(dev_priv))
+               lvds_reg = PCH_LVDS;
+       else
+               lvds_reg = LVDS;
+
+       lvds = I915_READ(lvds_reg);
+
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               if ((lvds & LVDS_DETECTED) == 0)
+                       return;
+       }
+
+       pin = GMBUS_PIN_PANEL;
+       if (!intel_bios_is_lvds_present(dev_priv, &pin)) {
+               if ((lvds & LVDS_PORT_EN) == 0) {
+                       DRM_DEBUG_KMS("LVDS is not present in VBT\n");
+                       return;
+               }
+               DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled anyway\n");
+       }
+
+       lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL);
+       if (!lvds_encoder)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(lvds_encoder);
+               return;
+       }
+
+       lvds_encoder->attached_connector = intel_connector;
+
+       intel_encoder = &lvds_encoder->base;
+       encoder = &intel_encoder->base;
+       connector = &intel_connector->base;
+       drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
+                          DRM_MODE_CONNECTOR_LVDS);
+
+       drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
+                        DRM_MODE_ENCODER_LVDS, "LVDS");
+
+       intel_encoder->enable = intel_enable_lvds;
+       intel_encoder->pre_enable = intel_pre_enable_lvds;
+       intel_encoder->compute_config = intel_lvds_compute_config;
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               intel_encoder->disable = pch_disable_lvds;
+               intel_encoder->post_disable = pch_post_disable_lvds;
+       } else {
+               intel_encoder->disable = gmch_disable_lvds;
+       }
+       intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+       intel_encoder->get_config = intel_lvds_get_config;
+       intel_encoder->update_pipe = intel_panel_update_backlight;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
+
+       intel_encoder->type = INTEL_OUTPUT_LVDS;
+       intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
+       intel_encoder->port = PORT_NONE;
+       intel_encoder->cloneable = 0;
+       if (HAS_PCH_SPLIT(dev_priv))
+               intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+       else if (IS_GEN(dev_priv, 4))
+               intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+       else
+               intel_encoder->crtc_mask = (1 << 1);
+
+       drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
+       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+
+       lvds_encoder->reg = lvds_reg;
+
+       /* create the scaling mode property */
+       allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT);
+       allowed_scalers |= BIT(DRM_MODE_SCALE_FULLSCREEN);
+       allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
+       drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
+       connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+
+       intel_lvds_pps_get_hw_state(dev_priv, &lvds_encoder->init_pps);
+       lvds_encoder->init_lvds_val = lvds;
+
+       /*
+        * LVDS discovery:
+        * 1) check for EDID on DDC
+        * 2) check for VBT data
+        * 3) check to see if LVDS is already on
+        *    if none of the above, no panel
+        */
+
+       /*
+        * Attempt to get the fixed panel mode from DDC.  Assume that the
+        * preferred mode is the right one.
+        */
+       mutex_lock(&dev->mode_config.mutex);
+       if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
+               edid = drm_get_edid_switcheroo(connector,
+                                   intel_gmbus_get_adapter(dev_priv, pin));
+       else
+               edid = drm_get_edid(connector,
+                                   intel_gmbus_get_adapter(dev_priv, pin));
+       if (edid) {
+               if (drm_add_edid_modes(connector, edid)) {
+                       drm_connector_update_edid_property(connector,
+                                                               edid);
+               } else {
+                       kfree(edid);
+                       edid = ERR_PTR(-EINVAL);
+               }
+       } else {
+               edid = ERR_PTR(-ENOENT);
+       }
+       intel_connector->edid = edid;
+
+       fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
+       if (fixed_mode)
+               goto out;
+
+       /* Failed to get EDID, what about VBT? */
+       fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
+       if (fixed_mode)
+               goto out;
+
+       /*
+        * If we didn't get EDID, try checking if the panel is already turned
+        * on.  If so, assume that whatever is currently programmed is the
+        * correct mode.
+        */
+       fixed_mode = intel_encoder_current_mode(intel_encoder);
+       if (fixed_mode) {
+               DRM_DEBUG_KMS("using current (BIOS) mode: ");
+               drm_mode_debug_printmodeline(fixed_mode);
+               fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+       }
+
+       /* If we still don't have a mode after all that, give up. */
+       if (!fixed_mode)
+               goto failed;
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_panel_setup_backlight(connector, INVALID_PIPE);
+
+       lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
+       DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
+                     lvds_encoder->is_dual_link ? "dual" : "single");
+
+       lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK;
+
+       return;
+
+failed:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
+       drm_connector_cleanup(connector);
+       drm_encoder_cleanup(encoder);
+       kfree(lvds_encoder);
+       intel_connector_free(intel_connector);
+       return;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.h b/drivers/gpu/drm/i915/display/intel_lvds.h
new file mode 100644 (file)
index 0000000..bc9c8b8
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_LVDS_H__
+#define __INTEL_LVDS_H__
+
+#include <linux/types.h>
+
+#include "i915_reg.h"
+
+enum pipe;
+struct drm_i915_private;
+
+bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
+                            i915_reg_t lvds_reg, enum pipe *pipe);
+void intel_lvds_init(struct drm_i915_private *dev_priv);
+struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv);
+bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv);
+
+#endif /* __INTEL_LVDS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
new file mode 100644 (file)
index 0000000..39d7420
--- /dev/null
@@ -0,0 +1,2051 @@
+/*
+ * Copyright © 2006-2010 Intel Corporation
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ *      Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/pwm.h>
+
+#include "intel_connector.h"
+#include "intel_dp_aux_backlight.h"
+#include "intel_drv.h"
+#include "intel_dsi_dcs_backlight.h"
+#include "intel_panel.h"
+
+#define CRC_PMIC_PWM_PERIOD_NS 21333
+
+void
+intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
+                      struct drm_display_mode *adjusted_mode)
+{
+       drm_mode_copy(adjusted_mode, fixed_mode);
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+}
+
+static bool is_downclock_mode(const struct drm_display_mode *downclock_mode,
+                             const struct drm_display_mode *fixed_mode)
+{
+       return drm_mode_match(downclock_mode, fixed_mode,
+                             DRM_MODE_MATCH_TIMINGS |
+                             DRM_MODE_MATCH_FLAGS |
+                             DRM_MODE_MATCH_3D_FLAGS) &&
+               downclock_mode->clock < fixed_mode->clock;
+}
+
+struct drm_display_mode *
+intel_panel_edid_downclock_mode(struct intel_connector *connector,
+                               const struct drm_display_mode *fixed_mode)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       const struct drm_display_mode *scan, *best_mode = NULL;
+       struct drm_display_mode *downclock_mode;
+       int best_clock = fixed_mode->clock;
+
+       list_for_each_entry(scan, &connector->base.probed_modes, head) {
+               /*
+                * If one mode has the same resolution with the fixed_panel
+                * mode while they have the different refresh rate, it means
+                * that the reduced downclock is found. In such
+                * case we can set the different FPx0/1 to dynamically select
+                * between low and high frequency.
+                */
+               if (is_downclock_mode(scan, fixed_mode) &&
+                   scan->clock < best_clock) {
+                       /*
+                        * The downclock is already found. But we
+                        * expect to find the lower downclock.
+                        */
+                       best_clock = scan->clock;
+                       best_mode = scan;
+               }
+       }
+
+       if (!best_mode)
+               return NULL;
+
+       downclock_mode = drm_mode_duplicate(&dev_priv->drm, best_mode);
+       if (!downclock_mode)
+               return NULL;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using downclock mode from EDID: ",
+                     connector->base.base.id, connector->base.name);
+       drm_mode_debug_printmodeline(downclock_mode);
+
+       return downclock_mode;
+}
+
+struct drm_display_mode *
+intel_panel_edid_fixed_mode(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       const struct drm_display_mode *scan;
+       struct drm_display_mode *fixed_mode;
+
+       if (list_empty(&connector->base.probed_modes))
+               return NULL;
+
+       /* prefer fixed mode from EDID if available */
+       list_for_each_entry(scan, &connector->base.probed_modes, head) {
+               if ((scan->type & DRM_MODE_TYPE_PREFERRED) == 0)
+                       continue;
+
+               fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan);
+               if (!fixed_mode)
+                       return NULL;
+
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using preferred mode from EDID: ",
+                             connector->base.base.id, connector->base.name);
+               drm_mode_debug_printmodeline(fixed_mode);
+
+               return fixed_mode;
+       }
+
+       scan = list_first_entry(&connector->base.probed_modes,
+                               typeof(*scan), head);
+
+       fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan);
+       if (!fixed_mode)
+               return NULL;
+
+       fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using first mode from EDID: ",
+                     connector->base.base.id, connector->base.name);
+       drm_mode_debug_printmodeline(fixed_mode);
+
+       return fixed_mode;
+}
+
+struct drm_display_mode *
+intel_panel_vbt_fixed_mode(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct drm_display_info *info = &connector->base.display_info;
+       struct drm_display_mode *fixed_mode;
+
+       if (!dev_priv->vbt.lfp_lvds_vbt_mode)
+               return NULL;
+
+       fixed_mode = drm_mode_duplicate(&dev_priv->drm,
+                                       dev_priv->vbt.lfp_lvds_vbt_mode);
+       if (!fixed_mode)
+               return NULL;
+
+       fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using mode from VBT: ",
+                     connector->base.base.id, connector->base.name);
+       drm_mode_debug_printmodeline(fixed_mode);
+
+       info->width_mm = fixed_mode->width_mm;
+       info->height_mm = fixed_mode->height_mm;
+
+       return fixed_mode;
+}
+
+/* adjusted_mode has been preset to be the panel's fixed mode */
+void
+intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
+                       struct intel_crtc_state *pipe_config,
+                       int fitting_mode)
+{
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       int x = 0, y = 0, width = 0, height = 0;
+
+       /* Native modes don't need fitting */
+       if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
+           adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h &&
+           pipe_config->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
+               goto done;
+
+       switch (fitting_mode) {
+       case DRM_MODE_SCALE_CENTER:
+               width = pipe_config->pipe_src_w;
+               height = pipe_config->pipe_src_h;
+               x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
+               y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
+               break;
+
+       case DRM_MODE_SCALE_ASPECT:
+               /* Scale but preserve the aspect ratio */
+               {
+                       u32 scaled_width = adjusted_mode->crtc_hdisplay
+                               * pipe_config->pipe_src_h;
+                       u32 scaled_height = pipe_config->pipe_src_w
+                               * adjusted_mode->crtc_vdisplay;
+                       if (scaled_width > scaled_height) { /* pillar */
+                               width = scaled_height / pipe_config->pipe_src_h;
+                               if (width & 1)
+                                       width++;
+                               x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
+                               y = 0;
+                               height = adjusted_mode->crtc_vdisplay;
+                       } else if (scaled_width < scaled_height) { /* letter */
+                               height = scaled_width / pipe_config->pipe_src_w;
+                               if (height & 1)
+                                   height++;
+                               y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
+                               x = 0;
+                               width = adjusted_mode->crtc_hdisplay;
+                       } else {
+                               x = y = 0;
+                               width = adjusted_mode->crtc_hdisplay;
+                               height = adjusted_mode->crtc_vdisplay;
+                       }
+               }
+               break;
+
+       case DRM_MODE_SCALE_FULLSCREEN:
+               x = y = 0;
+               width = adjusted_mode->crtc_hdisplay;
+               height = adjusted_mode->crtc_vdisplay;
+               break;
+
+       default:
+               WARN(1, "bad panel fit mode: %d\n", fitting_mode);
+               return;
+       }
+
+done:
+       pipe_config->pch_pfit.pos = (x << 16) | y;
+       pipe_config->pch_pfit.size = (width << 16) | height;
+       pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
+}
+
+static void
+centre_horizontally(struct drm_display_mode *adjusted_mode,
+                   int width)
+{
+       u32 border, sync_pos, blank_width, sync_width;
+
+       /* keep the hsync and hblank widths constant */
+       sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+       blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
+       sync_pos = (blank_width - sync_width + 1) / 2;
+
+       border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
+       border += border & 1; /* make the border even */
+
+       adjusted_mode->crtc_hdisplay = width;
+       adjusted_mode->crtc_hblank_start = width + border;
+       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
+
+       adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
+       adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
+}
+
+static void
+centre_vertically(struct drm_display_mode *adjusted_mode,
+                 int height)
+{
+       u32 border, sync_pos, blank_width, sync_width;
+
+       /* keep the vsync and vblank widths constant */
+       sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
+       blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
+       sync_pos = (blank_width - sync_width + 1) / 2;
+
+       border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
+
+       adjusted_mode->crtc_vdisplay = height;
+       adjusted_mode->crtc_vblank_start = height + border;
+       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
+
+       adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
+       adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
+}
+
+static inline u32 panel_fitter_scaling(u32 source, u32 target)
+{
+       /*
+        * Floating point operation is not supported. So the FACTOR
+        * is defined, which can avoid the floating point computation
+        * when calculating the panel ratio.
+        */
+#define ACCURACY 12
+#define FACTOR (1 << ACCURACY)
+       u32 ratio = source * FACTOR / target;
+       return (FACTOR * ratio + FACTOR/2) / FACTOR;
+}
+
+static void i965_scale_aspect(struct intel_crtc_state *pipe_config,
+                             u32 *pfit_control)
+{
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       u32 scaled_width = adjusted_mode->crtc_hdisplay *
+               pipe_config->pipe_src_h;
+       u32 scaled_height = pipe_config->pipe_src_w *
+               adjusted_mode->crtc_vdisplay;
+
+       /* 965+ is easy, it does everything in hw */
+       if (scaled_width > scaled_height)
+               *pfit_control |= PFIT_ENABLE |
+                       PFIT_SCALING_PILLAR;
+       else if (scaled_width < scaled_height)
+               *pfit_control |= PFIT_ENABLE |
+                       PFIT_SCALING_LETTER;
+       else if (adjusted_mode->crtc_hdisplay != pipe_config->pipe_src_w)
+               *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
+}
+
+static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
+                             u32 *pfit_control, u32 *pfit_pgm_ratios,
+                             u32 *border)
+{
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       u32 scaled_width = adjusted_mode->crtc_hdisplay *
+               pipe_config->pipe_src_h;
+       u32 scaled_height = pipe_config->pipe_src_w *
+               adjusted_mode->crtc_vdisplay;
+       u32 bits;
+
+       /*
+        * For earlier chips we have to calculate the scaling
+        * ratio by hand and program it into the
+        * PFIT_PGM_RATIO register
+        */
+       if (scaled_width > scaled_height) { /* pillar */
+               centre_horizontally(adjusted_mode,
+                                   scaled_height /
+                                   pipe_config->pipe_src_h);
+
+               *border = LVDS_BORDER_ENABLE;
+               if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay) {
+                       bits = panel_fitter_scaling(pipe_config->pipe_src_h,
+                                                   adjusted_mode->crtc_vdisplay);
+
+                       *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
+                                            bits << PFIT_VERT_SCALE_SHIFT);
+                       *pfit_control |= (PFIT_ENABLE |
+                                         VERT_INTERP_BILINEAR |
+                                         HORIZ_INTERP_BILINEAR);
+               }
+       } else if (scaled_width < scaled_height) { /* letter */
+               centre_vertically(adjusted_mode,
+                                 scaled_width /
+                                 pipe_config->pipe_src_w);
+
+               *border = LVDS_BORDER_ENABLE;
+               if (pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) {
+                       bits = panel_fitter_scaling(pipe_config->pipe_src_w,
+                                                   adjusted_mode->crtc_hdisplay);
+
+                       *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
+                                            bits << PFIT_VERT_SCALE_SHIFT);
+                       *pfit_control |= (PFIT_ENABLE |
+                                         VERT_INTERP_BILINEAR |
+                                         HORIZ_INTERP_BILINEAR);
+               }
+       } else {
+               /* Aspects match, Let hw scale both directions */
+               *pfit_control |= (PFIT_ENABLE |
+                                 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+                                 VERT_INTERP_BILINEAR |
+                                 HORIZ_INTERP_BILINEAR);
+       }
+}
+
+void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
+                             struct intel_crtc_state *pipe_config,
+                             int fitting_mode)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+
+       /* Native modes don't need fitting */
+       if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
+           adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h)
+               goto out;
+
+       switch (fitting_mode) {
+       case DRM_MODE_SCALE_CENTER:
+               /*
+                * For centered modes, we have to calculate border widths &
+                * heights and modify the values programmed into the CRTC.
+                */
+               centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
+               centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
+               border = LVDS_BORDER_ENABLE;
+               break;
+       case DRM_MODE_SCALE_ASPECT:
+               /* Scale but preserve the aspect ratio */
+               if (INTEL_GEN(dev_priv) >= 4)
+                       i965_scale_aspect(pipe_config, &pfit_control);
+               else
+                       i9xx_scale_aspect(pipe_config, &pfit_control,
+                                         &pfit_pgm_ratios, &border);
+               break;
+       case DRM_MODE_SCALE_FULLSCREEN:
+               /*
+                * Full scaling, even if it changes the aspect ratio.
+                * Fortunately this is all done for us in hw.
+                */
+               if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay ||
+                   pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) {
+                       pfit_control |= PFIT_ENABLE;
+                       if (INTEL_GEN(dev_priv) >= 4)
+                               pfit_control |= PFIT_SCALING_AUTO;
+                       else
+                               pfit_control |= (VERT_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_AUTO_SCALE |
+                                                HORIZ_INTERP_BILINEAR);
+               }
+               break;
+       default:
+               WARN(1, "bad panel fit mode: %d\n", fitting_mode);
+               return;
+       }
+
+       /* 965+ wants fuzzy fitting */
+       /* FIXME: handle multiple panels by failing gracefully */
+       if (INTEL_GEN(dev_priv) >= 4)
+               pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
+                                PFIT_FILTER_FUZZY);
+
+out:
+       if ((pfit_control & PFIT_ENABLE) == 0) {
+               pfit_control = 0;
+               pfit_pgm_ratios = 0;
+       }
+
+       /* Make sure pre-965 set dither correctly for 18bpp panels. */
+       if (INTEL_GEN(dev_priv) < 4 && pipe_config->pipe_bpp == 18)
+               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+
+       pipe_config->gmch_pfit.control = pfit_control;
+       pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
+       pipe_config->gmch_pfit.lvds_border_bits = border;
+}
+
+/**
+ * scale - scale values from one range to another
+ * @source_val: value in range [@source_min..@source_max]
+ * @source_min: minimum legal value for @source_val
+ * @source_max: maximum legal value for @source_val
+ * @target_min: corresponding target value for @source_min
+ * @target_max: corresponding target value for @source_max
+ *
+ * Return @source_val in range [@source_min..@source_max] scaled to range
+ * [@target_min..@target_max].
+ */
+static u32 scale(u32 source_val,
+                u32 source_min, u32 source_max,
+                u32 target_min, u32 target_max)
+{
+       u64 target_val;
+
+       WARN_ON(source_min > source_max);
+       WARN_ON(target_min > target_max);
+
+       /* defensive */
+       source_val = clamp(source_val, source_min, source_max);
+
+       /* avoid overflows */
+       target_val = mul_u32_u32(source_val - source_min,
+                                target_max - target_min);
+       target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min);
+       target_val += target_min;
+
+       return target_val;
+}
+
+/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
+static inline u32 scale_user_to_hw(struct intel_connector *connector,
+                                  u32 user_level, u32 user_max)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       return scale(user_level, 0, user_max,
+                    panel->backlight.min, panel->backlight.max);
+}
+
+/* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
+ * to [hw_min..hw_max]. */
+static inline u32 clamp_user_to_hw(struct intel_connector *connector,
+                                  u32 user_level, u32 user_max)
+{
+       struct intel_panel *panel = &connector->panel;
+       u32 hw_level;
+
+       hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
+       hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
+
+       return hw_level;
+}
+
+/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
+static inline u32 scale_hw_to_user(struct intel_connector *connector,
+                                  u32 hw_level, u32 user_max)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       return scale(hw_level, panel->backlight.min, panel->backlight.max,
+                    0, user_max);
+}
+
+static u32 intel_panel_compute_brightness(struct intel_connector *connector,
+                                         u32 val)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       if (i915_modparams.invert_brightness < 0)
+               return val;
+
+       if (i915_modparams.invert_brightness > 0 ||
+           dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
+               return panel->backlight.max - val + panel->backlight.min;
+       }
+
+       return val;
+}
+
+static u32 lpt_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
+
+static u32 pch_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
+
+static u32 i9xx_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 val;
+
+       val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+       if (INTEL_GEN(dev_priv) < 4)
+               val >>= 1;
+
+       if (panel->backlight.combination_mode) {
+               u8 lbpc;
+
+               pci_read_config_byte(dev_priv->drm.pdev, LBPC, &lbpc);
+               val *= lbpc;
+       }
+
+       return val;
+}
+
+static u32 _vlv_get_backlight(struct drm_i915_private *dev_priv, enum pipe pipe)
+{
+       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
+               return 0;
+
+       return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
+
+static u32 vlv_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum pipe pipe = intel_connector_get_pipe(connector);
+
+       return _vlv_get_backlight(dev_priv, pipe);
+}
+
+static u32 bxt_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       return I915_READ(BXT_BLC_PWM_DUTY(panel->backlight.controller));
+}
+
+static u32 pwm_get_backlight(struct intel_connector *connector)
+{
+       struct intel_panel *panel = &connector->panel;
+       int duty_ns;
+
+       duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
+       return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
+}
+
+static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
+}
+
+static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       u32 tmp;
+
+       tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
+}
+
+static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp, mask;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       if (panel->backlight.combination_mode) {
+               u8 lbpc;
+
+               lbpc = level * 0xfe / panel->backlight.max + 1;
+               level /= lbpc;
+               pci_write_config_byte(dev_priv->drm.pdev, LBPC, lbpc);
+       }
+
+       if (IS_GEN(dev_priv, 4)) {
+               mask = BACKLIGHT_DUTY_CYCLE_MASK;
+       } else {
+               level <<= 1;
+               mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
+       }
+
+       tmp = I915_READ(BLC_PWM_CTL) & ~mask;
+       I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
+
+static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
+       u32 tmp;
+
+       tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
+}
+
+static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       I915_WRITE(BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
+}
+
+static void pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
+       int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+
+       pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
+}
+
+static void
+intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+       level = intel_panel_compute_brightness(connector, level);
+       panel->backlight.set(conn_state, level);
+}
+
+/* set backlight brightness to level in range [0..max], assuming hw min is
+ * respected.
+ */
+void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
+                                   u32 user_level, u32 user_max)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 hw_level;
+
+       /*
+        * Lack of crtc may occur during driver init because
+        * connection_mutex isn't held across the entire backlight
+        * setup + modeset readout, and the BIOS can issue the
+        * requests at any time.
+        */
+       if (!panel->backlight.present || !conn_state->crtc)
+               return;
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       WARN_ON(panel->backlight.max == 0);
+
+       hw_level = clamp_user_to_hw(connector, user_level, user_max);
+       panel->backlight.level = hw_level;
+
+       if (panel->backlight.device)
+               panel->backlight.device->props.brightness =
+                       scale_hw_to_user(connector,
+                                        panel->backlight.level,
+                                        panel->backlight.device->props.max_brightness);
+
+       if (panel->backlight.enabled)
+               intel_panel_actually_set_backlight(conn_state, hw_level);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+
+       /*
+        * Although we don't support or enable CPU PWM with LPT/SPT based
+        * systems, it may have been enabled prior to loading the
+        * driver. Disable to avoid warnings on LCPLL disable.
+        *
+        * This needs rework if we need to add support for CPU PWM on PCH split
+        * platforms.
+        */
+       tmp = I915_READ(BLC_PWM_CPU_CTL2);
+       if (tmp & BLM_PWM_ENABLE) {
+               DRM_DEBUG_KMS("cpu backlight was enabled, disabling\n");
+               I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+       }
+
+       tmp = I915_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+}
+
+static void pch_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+
+       tmp = I915_READ(BLC_PWM_CPU_CTL2);
+       I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+
+       tmp = I915_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+}
+
+static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+}
+
+static void i965_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+
+       tmp = I915_READ(BLC_PWM_CTL2);
+       I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
+}
+
+static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+
+       tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe));
+       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
+}
+
+static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp, val;
+
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+
+       tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+                       tmp & ~BXT_BLC_PWM_ENABLE);
+
+       if (panel->backlight.controller == 1) {
+               val = I915_READ(UTIL_PIN_CTL);
+               val &= ~UTIL_PIN_ENABLE;
+               I915_WRITE(UTIL_PIN_CTL, val);
+       }
+}
+
+static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+
+       tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+                  tmp & ~BXT_BLC_PWM_ENABLE);
+}
+
+static void pwm_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       /* Disable the backlight */
+       intel_panel_actually_set_backlight(old_conn_state, 0);
+       usleep_range(2000, 3000);
+       pwm_disable(panel->backlight.pwm);
+}
+
+void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       if (!panel->backlight.present)
+               return;
+
+       /*
+        * Do not disable backlight on the vga_switcheroo path. When switching
+        * away from i915, the other client may depend on i915 to handle the
+        * backlight. This will leave the backlight on unnecessarily when
+        * another client is not activated.
+        */
+       if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
+               DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
+               return;
+       }
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       if (panel->backlight.device)
+               panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
+       panel->backlight.enabled = false;
+       panel->backlight.disable(old_conn_state);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pch_ctl1, pch_ctl2, schicken;
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
+               DRM_DEBUG_KMS("pch backlight already enabled\n");
+               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       }
+
+       if (HAS_PCH_LPT(dev_priv)) {
+               schicken = I915_READ(SOUTH_CHICKEN2);
+               if (panel->backlight.alternate_pwm_increment)
+                       schicken |= LPT_PWM_GRANULARITY;
+               else
+                       schicken &= ~LPT_PWM_GRANULARITY;
+               I915_WRITE(SOUTH_CHICKEN2, schicken);
+       } else {
+               schicken = I915_READ(SOUTH_CHICKEN1);
+               if (panel->backlight.alternate_pwm_increment)
+                       schicken |= SPT_PWM_GRANULARITY;
+               else
+                       schicken &= ~SPT_PWM_GRANULARITY;
+               I915_WRITE(SOUTH_CHICKEN1, schicken);
+       }
+
+       pch_ctl2 = panel->backlight.max << 16;
+       I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
+
+       pch_ctl1 = 0;
+       if (panel->backlight.active_low_pwm)
+               pch_ctl1 |= BLM_PCH_POLARITY;
+
+       /* After LPT, override is the default. */
+       if (HAS_PCH_LPT(dev_priv))
+               pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
+
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       POSTING_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
+
+       /* This won't stick until the above enable. */
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+}
+
+static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
+
+       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
+       if (cpu_ctl2 & BLM_PWM_ENABLE) {
+               DRM_DEBUG_KMS("cpu backlight already enabled\n");
+               cpu_ctl2 &= ~BLM_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
+       }
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
+               DRM_DEBUG_KMS("pch backlight already enabled\n");
+               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       }
+
+       if (cpu_transcoder == TRANSCODER_EDP)
+               cpu_ctl2 = BLM_TRANSCODER_EDP;
+       else
+               cpu_ctl2 = BLM_PIPE(cpu_transcoder);
+       I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
+       POSTING_READ(BLC_PWM_CPU_CTL2);
+       I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
+
+       /* This won't stick until the above enable. */
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+
+       pch_ctl2 = panel->backlight.max << 16;
+       I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
+
+       pch_ctl1 = 0;
+       if (panel->backlight.active_low_pwm)
+               pch_ctl1 |= BLM_PCH_POLARITY;
+
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       POSTING_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
+}
+
+static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, freq;
+
+       ctl = I915_READ(BLC_PWM_CTL);
+       if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
+               DRM_DEBUG_KMS("backlight already enabled\n");
+               I915_WRITE(BLC_PWM_CTL, 0);
+       }
+
+       freq = panel->backlight.max;
+       if (panel->backlight.combination_mode)
+               freq /= 0xff;
+
+       ctl = freq << 17;
+       if (panel->backlight.combination_mode)
+               ctl |= BLM_LEGACY_MODE;
+       if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm)
+               ctl |= BLM_POLARITY_PNV;
+
+       I915_WRITE(BLC_PWM_CTL, ctl);
+       POSTING_READ(BLC_PWM_CTL);
+
+       /* XXX: combine this into above write? */
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+
+       /*
+        * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
+        * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
+        * that has backlight.
+        */
+       if (IS_GEN(dev_priv, 2))
+               I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
+}
+
+static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
+       u32 ctl, ctl2, freq;
+
+       ctl2 = I915_READ(BLC_PWM_CTL2);
+       if (ctl2 & BLM_PWM_ENABLE) {
+               DRM_DEBUG_KMS("backlight already enabled\n");
+               ctl2 &= ~BLM_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_CTL2, ctl2);
+       }
+
+       freq = panel->backlight.max;
+       if (panel->backlight.combination_mode)
+               freq /= 0xff;
+
+       ctl = freq << 16;
+       I915_WRITE(BLC_PWM_CTL, ctl);
+
+       ctl2 = BLM_PIPE(pipe);
+       if (panel->backlight.combination_mode)
+               ctl2 |= BLM_COMBINATION_MODE;
+       if (panel->backlight.active_low_pwm)
+               ctl2 |= BLM_POLARITY_I965;
+       I915_WRITE(BLC_PWM_CTL2, ctl2);
+       POSTING_READ(BLC_PWM_CTL2);
+       I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
+
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+}
+
+static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
+       u32 ctl, ctl2;
+
+       ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
+       if (ctl2 & BLM_PWM_ENABLE) {
+               DRM_DEBUG_KMS("backlight already enabled\n");
+               ctl2 &= ~BLM_PWM_ENABLE;
+               I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
+       }
+
+       ctl = panel->backlight.max << 16;
+       I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl);
+
+       /* XXX: combine this into above write? */
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+
+       ctl2 = 0;
+       if (panel->backlight.active_low_pwm)
+               ctl2 |= BLM_POLARITY_I965;
+       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
+       POSTING_READ(VLV_BLC_PWM_CTL2(pipe));
+       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
+}
+
+static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
+       u32 pwm_ctl, val;
+
+       /* Controller 1 uses the utility pin. */
+       if (panel->backlight.controller == 1) {
+               val = I915_READ(UTIL_PIN_CTL);
+               if (val & UTIL_PIN_ENABLE) {
+                       DRM_DEBUG_KMS("util pin already enabled\n");
+                       val &= ~UTIL_PIN_ENABLE;
+                       I915_WRITE(UTIL_PIN_CTL, val);
+               }
+
+               val = 0;
+               if (panel->backlight.util_pin_active_low)
+                       val |= UTIL_PIN_POLARITY;
+               I915_WRITE(UTIL_PIN_CTL, val | UTIL_PIN_PIPE(pipe) |
+                               UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
+       }
+
+       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
+               DRM_DEBUG_KMS("backlight already enabled\n");
+               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
+               I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+                               pwm_ctl);
+       }
+
+       I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller),
+                       panel->backlight.max);
+
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+
+       pwm_ctl = 0;
+       if (panel->backlight.active_low_pwm)
+               pwm_ctl |= BXT_BLC_PWM_POLARITY;
+
+       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
+       POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+                       pwm_ctl | BXT_BLC_PWM_ENABLE);
+}
+
+static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pwm_ctl;
+
+       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
+               DRM_DEBUG_KMS("backlight already enabled\n");
+               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
+               I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+                          pwm_ctl);
+       }
+
+       I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller),
+                  panel->backlight.max);
+
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+
+       pwm_ctl = 0;
+       if (panel->backlight.active_low_pwm)
+               pwm_ctl |= BXT_BLC_PWM_POLARITY;
+
+       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
+       POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+                  pwm_ctl | BXT_BLC_PWM_ENABLE);
+}
+
+static void pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       pwm_enable(panel->backlight.pwm);
+       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+}
+
+static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                          const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       if (panel->backlight.level <= panel->backlight.min) {
+               panel->backlight.level = panel->backlight.max;
+               if (panel->backlight.device)
+                       panel->backlight.device->props.brightness =
+                               scale_hw_to_user(connector,
+                                                panel->backlight.level,
+                                                panel->backlight.device->props.max_brightness);
+       }
+
+       panel->backlight.enable(crtc_state, conn_state);
+       panel->backlight.enabled = true;
+       if (panel->backlight.device)
+               panel->backlight.device->props.power = FB_BLANK_UNBLANK;
+}
+
+void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
+
+       if (!panel->backlight.present)
+               return;
+
+       DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       __intel_panel_enable_backlight(crtc_state, conn_state);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+static u32 intel_panel_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 val = 0;
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       if (panel->backlight.enabled) {
+               val = panel->backlight.get(connector);
+               val = intel_panel_compute_brightness(connector, val);
+       }
+
+       mutex_unlock(&dev_priv->backlight_lock);
+
+       DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+       return val;
+}
+
+/* set backlight brightness to level in range [0..max], scaling wrt hw min */
+static void intel_panel_set_backlight(const struct drm_connector_state *conn_state,
+                                     u32 user_level, u32 user_max)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 hw_level;
+
+       if (!panel->backlight.present)
+               return;
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       WARN_ON(panel->backlight.max == 0);
+
+       hw_level = scale_user_to_hw(connector, user_level, user_max);
+       panel->backlight.level = hw_level;
+
+       if (panel->backlight.enabled)
+               intel_panel_actually_set_backlight(conn_state, hw_level);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+static int intel_backlight_device_update_status(struct backlight_device *bd)
+{
+       struct intel_connector *connector = bl_get_data(bd);
+       struct intel_panel *panel = &connector->panel;
+       struct drm_device *dev = connector->base.dev;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
+                     bd->props.brightness, bd->props.max_brightness);
+       intel_panel_set_backlight(connector->base.state, bd->props.brightness,
+                                 bd->props.max_brightness);
+
+       /*
+        * Allow flipping bl_power as a sub-state of enabled. Sadly the
+        * backlight class device does not make it easy to to differentiate
+        * between callbacks for brightness and bl_power, so our backlight_power
+        * callback needs to take this into account.
+        */
+       if (panel->backlight.enabled) {
+               if (panel->backlight.power) {
+                       bool enable = bd->props.power == FB_BLANK_UNBLANK &&
+                               bd->props.brightness != 0;
+                       panel->backlight.power(connector, enable);
+               }
+       } else {
+               bd->props.power = FB_BLANK_POWERDOWN;
+       }
+
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       return 0;
+}
+
+static int intel_backlight_device_get_brightness(struct backlight_device *bd)
+{
+       struct intel_connector *connector = bl_get_data(bd);
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       intel_wakeref_t wakeref;
+       int ret = 0;
+
+       with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) {
+               u32 hw_level;
+
+               drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+
+               hw_level = intel_panel_get_backlight(connector);
+               ret = scale_hw_to_user(connector,
+                                      hw_level, bd->props.max_brightness);
+
+               drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       }
+
+       return ret;
+}
+
+static const struct backlight_ops intel_backlight_device_ops = {
+       .update_status = intel_backlight_device_update_status,
+       .get_brightness = intel_backlight_device_get_brightness,
+};
+
+int intel_backlight_device_register(struct intel_connector *connector)
+{
+       struct intel_panel *panel = &connector->panel;
+       struct backlight_properties props;
+
+       if (WARN_ON(panel->backlight.device))
+               return -ENODEV;
+
+       if (!panel->backlight.present)
+               return 0;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
+
+       /*
+        * Note: Everything should work even if the backlight device max
+        * presented to the userspace is arbitrarily chosen.
+        */
+       props.max_brightness = panel->backlight.max;
+       props.brightness = scale_hw_to_user(connector,
+                                           panel->backlight.level,
+                                           props.max_brightness);
+
+       if (panel->backlight.enabled)
+               props.power = FB_BLANK_UNBLANK;
+       else
+               props.power = FB_BLANK_POWERDOWN;
+
+       /*
+        * Note: using the same name independent of the connector prevents
+        * registration of multiple backlight devices in the driver.
+        */
+       panel->backlight.device =
+               backlight_device_register("intel_backlight",
+                                         connector->base.kdev,
+                                         connector,
+                                         &intel_backlight_device_ops, &props);
+
+       if (IS_ERR(panel->backlight.device)) {
+               DRM_ERROR("Failed to register backlight: %ld\n",
+                         PTR_ERR(panel->backlight.device));
+               panel->backlight.device = NULL;
+               return -ENODEV;
+       }
+
+       DRM_DEBUG_KMS("Connector %s backlight sysfs interface registered\n",
+                     connector->base.name);
+
+       return 0;
+}
+
+void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       if (panel->backlight.device) {
+               backlight_device_unregister(panel->backlight.device);
+               panel->backlight.device = NULL;
+       }
+}
+#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+/*
+ * CNP: PWM clock frequency is 19.2 MHz or 24 MHz.
+ *      PWM increment = 1
+ */
+static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return DIV_ROUND_CLOSEST(KHz(dev_priv->rawclk_freq), pwm_freq_hz);
+}
+
+/*
+ * BXT: PWM clock frequency = 19.2 MHz.
+ */
+static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz);
+}
+
+/*
+ * SPT: This value represents the period of the PWM stream in clock periods
+ * multiplied by 16 (default increment) or 128 (alternate increment selected in
+ * SCHICKEN_1 bit 0). PWM clock is 24 MHz.
+ */
+static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct intel_panel *panel = &connector->panel;
+       u32 mul;
+
+       if (panel->backlight.alternate_pwm_increment)
+               mul = 128;
+       else
+               mul = 16;
+
+       return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul);
+}
+
+/*
+ * LPT: This value represents the period of the PWM stream in clock periods
+ * multiplied by 128 (default increment) or 16 (alternate increment, selected in
+ * LPT SOUTH_CHICKEN2 register bit 5).
+ */
+static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 mul, clock;
+
+       if (panel->backlight.alternate_pwm_increment)
+               mul = 16;
+       else
+               mul = 128;
+
+       if (HAS_PCH_LPT_H(dev_priv))
+               clock = MHz(135); /* LPT:H */
+       else
+               clock = MHz(24); /* LPT:LP */
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
+}
+
+/*
+ * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH
+ * display raw clocks multiplied by 128.
+ */
+static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return DIV_ROUND_CLOSEST(KHz(dev_priv->rawclk_freq), pwm_freq_hz * 128);
+}
+
+/*
+ * Gen2: This field determines the number of time base events (display core
+ * clock frequency/32) in total for a complete cycle of modulated backlight
+ * control.
+ *
+ * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock)
+ * divided by 32.
+ */
+static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int clock;
+
+       if (IS_PINEVIEW(dev_priv))
+               clock = KHz(dev_priv->rawclk_freq);
+       else
+               clock = KHz(dev_priv->cdclk.hw.cdclk);
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
+}
+
+/*
+ * Gen4: This value represents the period of the PWM stream in display core
+ * clocks ([DevCTG] HRAW clocks) multiplied by 128.
+ *
+ */
+static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int clock;
+
+       if (IS_G4X(dev_priv))
+               clock = KHz(dev_priv->rawclk_freq);
+       else
+               clock = KHz(dev_priv->cdclk.hw.cdclk);
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
+}
+
+/*
+ * VLV: This value represents the period of the PWM stream in display core
+ * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks
+ * multiplied by 16. CHV uses a 19.2MHz S0IX clock.
+ */
+static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int mul, clock;
+
+       if ((I915_READ(CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
+               if (IS_CHERRYVIEW(dev_priv))
+                       clock = KHz(19200);
+               else
+                       clock = MHz(25);
+               mul = 16;
+       } else {
+               clock = KHz(dev_priv->rawclk_freq);
+               mul = 128;
+       }
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
+       u32 pwm;
+
+       if (!panel->backlight.hz_to_pwm) {
+               DRM_DEBUG_KMS("backlight frequency conversion not supported\n");
+               return 0;
+       }
+
+       if (pwm_freq_hz) {
+               DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n",
+                             pwm_freq_hz);
+       } else {
+               pwm_freq_hz = 200;
+               DRM_DEBUG_KMS("default backlight frequency %u Hz\n",
+                             pwm_freq_hz);
+       }
+
+       pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
+       if (!pwm) {
+               DRM_DEBUG_KMS("backlight frequency conversion failed\n");
+               return 0;
+       }
+
+       return pwm;
+}
+
+/*
+ * Note: The setup hooks can't assume pipe is set!
+ */
+static u32 get_backlight_min_vbt(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       int min;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       /*
+        * XXX: If the vbt value is 255, it makes min equal to max, which leads
+        * to problems. There are such machines out there. Either our
+        * interpretation is wrong or the vbt has bogus data. Or both. Safeguard
+        * against this by letting the minimum be at most (arbitrarily chosen)
+        * 25% of the max.
+        */
+       min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64);
+       if (min != dev_priv->vbt.backlight.min_brightness) {
+               DRM_DEBUG_KMS("clamping VBT min backlight %d/255 to %d/255\n",
+                             dev_priv->vbt.backlight.min_brightness, min);
+       }
+
+       /* vbt value is a coefficient in range [0..255] */
+       return scale(min, 0, 255, 0, panel->backlight.max);
+}
+
+static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
+       bool alt, cpu_mode;
+
+       if (HAS_PCH_LPT(dev_priv))
+               alt = I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
+       else
+               alt = I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
+       panel->backlight.alternate_pwm_increment = alt;
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+
+       pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
+       panel->backlight.max = pch_ctl2 >> 16;
+
+       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
+
+       if (!panel->backlight.max)
+               panel->backlight.max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       panel->backlight.enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
+
+       cpu_mode = panel->backlight.enabled && HAS_PCH_LPT(dev_priv) &&
+                  !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
+                  (cpu_ctl2 & BLM_PWM_ENABLE);
+       if (cpu_mode)
+               val = pch_get_backlight(connector);
+       else
+               val = lpt_get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       if (cpu_mode) {
+               DRM_DEBUG_KMS("CPU backlight register was enabled, switching to PCH override\n");
+
+               /* Write converted CPU PWM value to PCH override register */
+               lpt_set_backlight(connector->base.state, panel->backlight.level);
+               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
+
+               I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 & ~BLM_PWM_ENABLE);
+       }
+
+       return 0;
+}
+
+static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+
+       pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
+       panel->backlight.max = pch_ctl2 >> 16;
+
+       if (!panel->backlight.max)
+               panel->backlight.max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       val = pch_get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
+       panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
+               (pch_ctl1 & BLM_PCH_PWM_ENABLE);
+
+       return 0;
+}
+
+static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, val;
+
+       ctl = I915_READ(BLC_PWM_CTL);
+
+       if (IS_GEN(dev_priv, 2) || IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
+               panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
+
+       if (IS_PINEVIEW(dev_priv))
+               panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
+
+       panel->backlight.max = ctl >> 17;
+
+       if (!panel->backlight.max) {
+               panel->backlight.max = get_backlight_max_vbt(connector);
+               panel->backlight.max >>= 1;
+       }
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       if (panel->backlight.combination_mode)
+               panel->backlight.max *= 0xff;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       val = i9xx_get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       panel->backlight.enabled = val != 0;
+
+       return 0;
+}
+
+static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, ctl2, val;
+
+       ctl2 = I915_READ(BLC_PWM_CTL2);
+       panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
+       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
+
+       ctl = I915_READ(BLC_PWM_CTL);
+       panel->backlight.max = ctl >> 16;
+
+       if (!panel->backlight.max)
+               panel->backlight.max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       if (panel->backlight.combination_mode)
+               panel->backlight.max *= 0xff;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       val = i9xx_get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
+
+       return 0;
+}
+
+static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, ctl2, val;
+
+       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
+               return -ENODEV;
+
+       ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
+       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
+
+       ctl = I915_READ(VLV_BLC_PWM_CTL(pipe));
+       panel->backlight.max = ctl >> 16;
+
+       if (!panel->backlight.max)
+               panel->backlight.max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       val = _vlv_get_backlight(dev_priv, pipe);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
+
+       return 0;
+}
+
+static int
+bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pwm_ctl, val;
+
+       panel->backlight.controller = dev_priv->vbt.backlight.controller;
+
+       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+
+       /* Controller 1 uses the utility pin. */
+       if (panel->backlight.controller == 1) {
+               val = I915_READ(UTIL_PIN_CTL);
+               panel->backlight.util_pin_active_low =
+                                       val & UTIL_PIN_POLARITY;
+       }
+
+       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
+       panel->backlight.max =
+               I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller));
+
+       if (!panel->backlight.max)
+               panel->backlight.max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       val = bxt_get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
+
+       return 0;
+}
+
+static int
+cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pwm_ctl, val;
+
+       /*
+        * CNP has the BXT implementation of backlight, but with only one
+        * controller. TODO: ICP has multiple controllers but we only use
+        * controller 0 for now.
+        */
+       panel->backlight.controller = 0;
+
+       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+
+       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
+       panel->backlight.max =
+               I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller));
+
+       if (!panel->backlight.max)
+               panel->backlight.max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       panel->backlight.min = get_backlight_min_vbt(connector);
+
+       val = bxt_get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
+
+       panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
+
+       return 0;
+}
+
+static int pwm_setup_backlight(struct intel_connector *connector,
+                              enum pipe pipe)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct intel_panel *panel = &connector->panel;
+       int retval;
+
+       /* Get the PWM chip for backlight control */
+       panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight");
+       if (IS_ERR(panel->backlight.pwm)) {
+               DRM_ERROR("Failed to own the pwm chip\n");
+               panel->backlight.pwm = NULL;
+               return -ENODEV;
+       }
+
+       /*
+        * FIXME: pwm_apply_args() should be removed when switching to
+        * the atomic PWM API.
+        */
+       pwm_apply_args(panel->backlight.pwm);
+
+       retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS,
+                           CRC_PMIC_PWM_PERIOD_NS);
+       if (retval < 0) {
+               DRM_ERROR("Failed to configure the pwm chip\n");
+               pwm_put(panel->backlight.pwm);
+               panel->backlight.pwm = NULL;
+               return retval;
+       }
+
+       panel->backlight.min = 0; /* 0% */
+       panel->backlight.max = 100; /* 100% */
+       panel->backlight.level = DIV_ROUND_UP(
+                                pwm_get_duty_cycle(panel->backlight.pwm) * 100,
+                                CRC_PMIC_PWM_PERIOD_NS);
+       panel->backlight.enabled = panel->backlight.level != 0;
+
+       return 0;
+}
+
+void intel_panel_update_backlight(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       if (!panel->backlight.present)
+               return;
+
+       mutex_lock(&dev_priv->backlight_lock);
+       if (!panel->backlight.enabled)
+               __intel_panel_enable_backlight(crtc_state, conn_state);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_panel *panel = &intel_connector->panel;
+       int ret;
+
+       if (!dev_priv->vbt.backlight.present) {
+               if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
+                       DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n");
+               } else {
+                       DRM_DEBUG_KMS("no backlight present per VBT\n");
+                       return 0;
+               }
+       }
+
+       /* ensure intel_panel has been initialized first */
+       if (WARN_ON(!panel->backlight.setup))
+               return -ENODEV;
+
+       /* set level and max in panel struct */
+       mutex_lock(&dev_priv->backlight_lock);
+       ret = panel->backlight.setup(intel_connector, pipe);
+       mutex_unlock(&dev_priv->backlight_lock);
+
+       if (ret) {
+               DRM_DEBUG_KMS("failed to setup backlight for connector %s\n",
+                             connector->name);
+               return ret;
+       }
+
+       panel->backlight.present = true;
+
+       DRM_DEBUG_KMS("Connector %s backlight initialized, %s, brightness %u/%u\n",
+                     connector->name,
+                     enableddisabled(panel->backlight.enabled),
+                     panel->backlight.level, panel->backlight.max);
+
+       return 0;
+}
+
+static void intel_panel_destroy_backlight(struct intel_panel *panel)
+{
+       /* dispose of the pwm */
+       if (panel->backlight.pwm)
+               pwm_put(panel->backlight.pwm);
+
+       panel->backlight.present = false;
+}
+
+/* Set up chip specific backlight functions */
+static void
+intel_panel_init_backlight_funcs(struct intel_panel *panel)
+{
+       struct intel_connector *connector =
+               container_of(panel, struct intel_connector, panel);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
+           intel_dp_aux_init_backlight_funcs(connector) == 0)
+               return;
+
+       if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
+           intel_dsi_dcs_init_backlight_funcs(connector) == 0)
+               return;
+
+       if (IS_GEN9_LP(dev_priv)) {
+               panel->backlight.setup = bxt_setup_backlight;
+               panel->backlight.enable = bxt_enable_backlight;
+               panel->backlight.disable = bxt_disable_backlight;
+               panel->backlight.set = bxt_set_backlight;
+               panel->backlight.get = bxt_get_backlight;
+               panel->backlight.hz_to_pwm = bxt_hz_to_pwm;
+       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
+               panel->backlight.setup = cnp_setup_backlight;
+               panel->backlight.enable = cnp_enable_backlight;
+               panel->backlight.disable = cnp_disable_backlight;
+               panel->backlight.set = bxt_set_backlight;
+               panel->backlight.get = bxt_get_backlight;
+               panel->backlight.hz_to_pwm = cnp_hz_to_pwm;
+       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
+               panel->backlight.setup = lpt_setup_backlight;
+               panel->backlight.enable = lpt_enable_backlight;
+               panel->backlight.disable = lpt_disable_backlight;
+               panel->backlight.set = lpt_set_backlight;
+               panel->backlight.get = lpt_get_backlight;
+               if (HAS_PCH_LPT(dev_priv))
+                       panel->backlight.hz_to_pwm = lpt_hz_to_pwm;
+               else
+                       panel->backlight.hz_to_pwm = spt_hz_to_pwm;
+       } else if (HAS_PCH_SPLIT(dev_priv)) {
+               panel->backlight.setup = pch_setup_backlight;
+               panel->backlight.enable = pch_enable_backlight;
+               panel->backlight.disable = pch_disable_backlight;
+               panel->backlight.set = pch_set_backlight;
+               panel->backlight.get = pch_get_backlight;
+               panel->backlight.hz_to_pwm = pch_hz_to_pwm;
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
+                       panel->backlight.setup = pwm_setup_backlight;
+                       panel->backlight.enable = pwm_enable_backlight;
+                       panel->backlight.disable = pwm_disable_backlight;
+                       panel->backlight.set = pwm_set_backlight;
+                       panel->backlight.get = pwm_get_backlight;
+               } else {
+                       panel->backlight.setup = vlv_setup_backlight;
+                       panel->backlight.enable = vlv_enable_backlight;
+                       panel->backlight.disable = vlv_disable_backlight;
+                       panel->backlight.set = vlv_set_backlight;
+                       panel->backlight.get = vlv_get_backlight;
+                       panel->backlight.hz_to_pwm = vlv_hz_to_pwm;
+               }
+       } else if (IS_GEN(dev_priv, 4)) {
+               panel->backlight.setup = i965_setup_backlight;
+               panel->backlight.enable = i965_enable_backlight;
+               panel->backlight.disable = i965_disable_backlight;
+               panel->backlight.set = i9xx_set_backlight;
+               panel->backlight.get = i9xx_get_backlight;
+               panel->backlight.hz_to_pwm = i965_hz_to_pwm;
+       } else {
+               panel->backlight.setup = i9xx_setup_backlight;
+               panel->backlight.enable = i9xx_enable_backlight;
+               panel->backlight.disable = i9xx_disable_backlight;
+               panel->backlight.set = i9xx_set_backlight;
+               panel->backlight.get = i9xx_get_backlight;
+               panel->backlight.hz_to_pwm = i9xx_hz_to_pwm;
+       }
+}
+
+int intel_panel_init(struct intel_panel *panel,
+                    struct drm_display_mode *fixed_mode,
+                    struct drm_display_mode *downclock_mode)
+{
+       intel_panel_init_backlight_funcs(panel);
+
+       panel->fixed_mode = fixed_mode;
+       panel->downclock_mode = downclock_mode;
+
+       return 0;
+}
+
+void intel_panel_fini(struct intel_panel *panel)
+{
+       struct intel_connector *intel_connector =
+               container_of(panel, struct intel_connector, panel);
+
+       intel_panel_destroy_backlight(panel);
+
+       if (panel->fixed_mode)
+               drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
+
+       if (panel->downclock_mode)
+               drm_mode_destroy(intel_connector->base.dev,
+                               panel->downclock_mode);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h
new file mode 100644 (file)
index 0000000..cedeea4
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_PANEL_H__
+#define __INTEL_PANEL_H__
+
+#include <linux/types.h>
+
+#include "intel_display.h"
+
+struct drm_connector;
+struct drm_connector_state;
+struct drm_display_mode;
+struct intel_connector;
+struct intel_crtc;
+struct intel_crtc_state;
+struct intel_encoder;
+struct intel_panel;
+
+int intel_panel_init(struct intel_panel *panel,
+                    struct drm_display_mode *fixed_mode,
+                    struct drm_display_mode *downclock_mode);
+void intel_panel_fini(struct intel_panel *panel);
+void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
+                           struct drm_display_mode *adjusted_mode);
+void intel_pch_panel_fitting(struct intel_crtc *crtc,
+                            struct intel_crtc_state *pipe_config,
+                            int fitting_mode);
+void intel_gmch_panel_fitting(struct intel_crtc *crtc,
+                             struct intel_crtc_state *pipe_config,
+                             int fitting_mode);
+void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
+                                   u32 level, u32 max);
+int intel_panel_setup_backlight(struct drm_connector *connector,
+                               enum pipe pipe);
+void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state);
+void intel_panel_update_backlight(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state);
+void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state);
+struct drm_display_mode *
+intel_panel_edid_downclock_mode(struct intel_connector *connector,
+                               const struct drm_display_mode *fixed_mode);
+struct drm_display_mode *
+intel_panel_edid_fixed_mode(struct intel_connector *connector);
+struct drm_display_mode *
+intel_panel_vbt_fixed_mode(struct intel_connector *connector);
+
+#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+int intel_backlight_device_register(struct intel_connector *connector);
+void intel_backlight_device_unregister(struct intel_connector *connector);
+#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+static inline int intel_backlight_device_register(struct intel_connector *connector)
+{
+       return 0;
+}
+static inline void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+}
+#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+#endif /* __INTEL_PANEL_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
new file mode 100644 (file)
index 0000000..0860ae3
--- /dev/null
@@ -0,0 +1,3333 @@
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright © 2006-2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_connector.h"
+#include "intel_drv.h"
+#include "intel_fifo_underrun.h"
+#include "intel_gmbus.h"
+#include "intel_hdmi.h"
+#include "intel_hotplug.h"
+#include "intel_panel.h"
+#include "intel_sdvo.h"
+#include "intel_sdvo_regs.h"
+
+#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)
+#define SDVO_RGB_MASK  (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)
+#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
+#define SDVO_TV_MASK   (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0)
+
+#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
+                       SDVO_TV_MASK)
+
+#define IS_TV(c)       (c->output_flag & SDVO_TV_MASK)
+#define IS_TMDS(c)     (c->output_flag & SDVO_TMDS_MASK)
+#define IS_LVDS(c)     (c->output_flag & SDVO_LVDS_MASK)
+#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
+#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK))
+
+
+static const char * const tv_format_names[] = {
+       "NTSC_M"   , "NTSC_J"  , "NTSC_443",
+       "PAL_B"    , "PAL_D"   , "PAL_G"   ,
+       "PAL_H"    , "PAL_I"   , "PAL_M"   ,
+       "PAL_N"    , "PAL_NC"  , "PAL_60"  ,
+       "SECAM_B"  , "SECAM_D" , "SECAM_G" ,
+       "SECAM_K"  , "SECAM_K1", "SECAM_L" ,
+       "SECAM_60"
+};
+
+#define TV_FORMAT_NUM  ARRAY_SIZE(tv_format_names)
+
+struct intel_sdvo {
+       struct intel_encoder base;
+
+       struct i2c_adapter *i2c;
+       u8 slave_addr;
+
+       struct i2c_adapter ddc;
+
+       /* Register for the SDVO device: SDVOB or SDVOC */
+       i915_reg_t sdvo_reg;
+
+       /* Active outputs controlled by this SDVO output */
+       u16 controlled_output;
+
+       /*
+        * Capabilities of the SDVO device returned by
+        * intel_sdvo_get_capabilities()
+        */
+       struct intel_sdvo_caps caps;
+
+       /* Pixel clock limitations reported by the SDVO device, in kHz */
+       int pixel_clock_min, pixel_clock_max;
+
+       /*
+       * For multiple function SDVO device,
+       * this is for current attached outputs.
+       */
+       u16 attached_output;
+
+       /*
+        * Hotplug activation bits for this device
+        */
+       u16 hotplug_active;
+
+       enum port port;
+
+       bool has_hdmi_monitor;
+       bool has_hdmi_audio;
+
+       /* DDC bus used by this SDVO encoder */
+       u8 ddc_bus;
+
+       /*
+        * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd
+        */
+       u8 dtd_sdvo_flags;
+};
+
+struct intel_sdvo_connector {
+       struct intel_connector base;
+
+       /* Mark the type of connector */
+       u16 output_flag;
+
+       /* This contains all current supported TV format */
+       u8 tv_format_supported[TV_FORMAT_NUM];
+       int   format_supported_num;
+       struct drm_property *tv_format;
+
+       /* add the property for the SDVO-TV */
+       struct drm_property *left;
+       struct drm_property *right;
+       struct drm_property *top;
+       struct drm_property *bottom;
+       struct drm_property *hpos;
+       struct drm_property *vpos;
+       struct drm_property *contrast;
+       struct drm_property *saturation;
+       struct drm_property *hue;
+       struct drm_property *sharpness;
+       struct drm_property *flicker_filter;
+       struct drm_property *flicker_filter_adaptive;
+       struct drm_property *flicker_filter_2d;
+       struct drm_property *tv_chroma_filter;
+       struct drm_property *tv_luma_filter;
+       struct drm_property *dot_crawl;
+
+       /* add the property for the SDVO-TV/LVDS */
+       struct drm_property *brightness;
+
+       /* this is to get the range of margin.*/
+       u32 max_hscan, max_vscan;
+
+       /**
+        * This is set if we treat the device as HDMI, instead of DVI.
+        */
+       bool is_hdmi;
+};
+
+struct intel_sdvo_connector_state {
+       /* base.base: tv.saturation/contrast/hue/brightness */
+       struct intel_digital_connector_state base;
+
+       struct {
+               unsigned overscan_h, overscan_v, hpos, vpos, sharpness;
+               unsigned flicker_filter, flicker_filter_2d, flicker_filter_adaptive;
+               unsigned chroma_filter, luma_filter, dot_crawl;
+       } tv;
+};
+
+static struct intel_sdvo *to_sdvo(struct intel_encoder *encoder)
+{
+       return container_of(encoder, struct intel_sdvo, base);
+}
+
+static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
+{
+       return to_sdvo(intel_attached_encoder(connector));
+}
+
+static struct intel_sdvo_connector *
+to_intel_sdvo_connector(struct drm_connector *connector)
+{
+       return container_of(connector, struct intel_sdvo_connector, base.base);
+}
+
+#define to_intel_sdvo_connector_state(conn_state) \
+       container_of((conn_state), struct intel_sdvo_connector_state, base.base)
+
+static bool
+intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags);
+static bool
+intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
+                             struct intel_sdvo_connector *intel_sdvo_connector,
+                             int type);
+static bool
+intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
+                                  struct intel_sdvo_connector *intel_sdvo_connector);
+
+/*
+ * Writes the SDVOB or SDVOC with the given value, but always writes both
+ * SDVOB and SDVOC to work around apparent hardware issues (according to
+ * comments in the BIOS).
+ */
+static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
+{
+       struct drm_device *dev = intel_sdvo->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 bval = val, cval = val;
+       int i;
+
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               I915_WRITE(intel_sdvo->sdvo_reg, val);
+               POSTING_READ(intel_sdvo->sdvo_reg);
+               /*
+                * HW workaround, need to write this twice for issue
+                * that may result in first write getting masked.
+                */
+               if (HAS_PCH_IBX(dev_priv)) {
+                       I915_WRITE(intel_sdvo->sdvo_reg, val);
+                       POSTING_READ(intel_sdvo->sdvo_reg);
+               }
+               return;
+       }
+
+       if (intel_sdvo->port == PORT_B)
+               cval = I915_READ(GEN3_SDVOC);
+       else
+               bval = I915_READ(GEN3_SDVOB);
+
+       /*
+        * Write the registers twice for luck. Sometimes,
+        * writing them only once doesn't appear to 'stick'.
+        * The BIOS does this too. Yay, magic
+        */
+       for (i = 0; i < 2; i++) {
+               I915_WRITE(GEN3_SDVOB, bval);
+               POSTING_READ(GEN3_SDVOB);
+
+               I915_WRITE(GEN3_SDVOC, cval);
+               POSTING_READ(GEN3_SDVOC);
+       }
+}
+
+static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
+{
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = intel_sdvo->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &addr,
+               },
+               {
+                       .addr = intel_sdvo->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = ch,
+               }
+       };
+       int ret;
+
+       if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
+               return true;
+
+       DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
+       return false;
+}
+
+#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
+/** Mapping of command numbers to names, for debug output */
+static const struct _sdvo_cmd_name {
+       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),
+
+       /* 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),
+
+       /* 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),
+};
+
+#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)
+{
+       int i, pos = 0;
+#define BUF_LEN 256
+       char buffer[BUF_LEN];
+
+#define BUF_PRINT(args...) \
+       pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args)
+
+
+       for (i = 0; i < args_len; i++) {
+               BUF_PRINT("%02X ", ((u8 *)args)[i]);
+       }
+       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)) {
+               BUF_PRINT("(%02X)", cmd);
+       }
+       BUG_ON(pos >= BUF_LEN - 1);
+#undef BUF_PRINT
+#undef BUF_LEN
+
+       DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer);
+}
+
+static const char * const cmd_status_names[] = {
+       "Power on",
+       "Success",
+       "Not supported",
+       "Invalid arg",
+       "Pending",
+       "Target not specified",
+       "Scaling not supported"
+};
+
+static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                  const void *args, int args_len,
+                                  bool unlocked)
+{
+       u8 *buf, status;
+       struct i2c_msg *msgs;
+       int i, ret = true;
+
+       /* Would be simpler to allocate both in one go ? */
+       buf = kzalloc(args_len * 2 + 2, GFP_KERNEL);
+       if (!buf)
+               return false;
+
+       msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL);
+       if (!msgs) {
+               kfree(buf);
+               return false;
+       }
+
+       intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
+
+       for (i = 0; i < args_len; i++) {
+               msgs[i].addr = intel_sdvo->slave_addr;
+               msgs[i].flags = 0;
+               msgs[i].len = 2;
+               msgs[i].buf = buf + 2 *i;
+               buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
+               buf[2*i + 1] = ((u8*)args)[i];
+       }
+       msgs[i].addr = intel_sdvo->slave_addr;
+       msgs[i].flags = 0;
+       msgs[i].len = 2;
+       msgs[i].buf = buf + 2*i;
+       buf[2*i + 0] = SDVO_I2C_OPCODE;
+       buf[2*i + 1] = cmd;
+
+       /* the following two are to read the response */
+       status = SDVO_I2C_CMD_STATUS;
+       msgs[i+1].addr = intel_sdvo->slave_addr;
+       msgs[i+1].flags = 0;
+       msgs[i+1].len = 1;
+       msgs[i+1].buf = &status;
+
+       msgs[i+2].addr = intel_sdvo->slave_addr;
+       msgs[i+2].flags = I2C_M_RD;
+       msgs[i+2].len = 1;
+       msgs[i+2].buf = &status;
+
+       if (unlocked)
+               ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+       else
+               ret = __i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+               ret = false;
+               goto out;
+       }
+       if (ret != i+3) {
+               /* failure in I2C transfer */
+               DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+               ret = false;
+       }
+
+out:
+       kfree(msgs);
+       kfree(buf);
+       return ret;
+}
+
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                const void *args, int args_len)
+{
+       return __intel_sdvo_write_cmd(intel_sdvo, cmd, args, args_len, true);
+}
+
+static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
+                                    void *response, int response_len)
+{
+       u8 retry = 15; /* 5 quick checks, followed by 10 long checks */
+       u8 status;
+       int i, pos = 0;
+#define BUF_LEN 256
+       char buffer[BUF_LEN];
+
+       buffer[0] = '\0';
+
+       /*
+        * The documentation states that all commands will be
+        * processed within 15µs, and that we need only poll
+        * the status byte a maximum of 3 times in order for the
+        * command to be complete.
+        *
+        * Check 5 times in case the hardware failed to read the docs.
+        *
+        * Also beware that the first response by many devices is to
+        * reply PENDING and stall for time. TVs are notorious for
+        * requiring longer than specified to complete their replies.
+        * Originally (in the DDX long ago), the delay was only ever 15ms
+        * with an additional delay of 30ms applied for TVs added later after
+        * many experiments. To accommodate both sets of delays, we do a
+        * sequence of slow checks if the device is falling behind and fails
+        * to reply within 5*15µs.
+        */
+       if (!intel_sdvo_read_byte(intel_sdvo,
+                                 SDVO_I2C_CMD_STATUS,
+                                 &status))
+               goto log_fail;
+
+       while ((status == SDVO_CMD_STATUS_PENDING ||
+               status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && --retry) {
+               if (retry < 10)
+                       msleep(15);
+               else
+                       udelay(15);
+
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_CMD_STATUS,
+                                         &status))
+                       goto log_fail;
+       }
+
+#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]);
+       else
+               BUF_PRINT("(??? %d)", status);
+
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               goto log_fail;
+
+       /* Read the command response */
+       for (i = 0; i < response_len; i++) {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_RETURN_0 + i,
+                                         &((u8 *)response)[i]))
+                       goto log_fail;
+               BUF_PRINT(" %02X", ((u8 *)response)[i]);
+       }
+       BUG_ON(pos >= BUF_LEN - 1);
+#undef BUF_PRINT
+#undef BUF_LEN
+
+       DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer);
+       return true;
+
+log_fail:
+       DRM_DEBUG_KMS("%s: R: ... failed %s\n",
+                     SDVO_NAME(intel_sdvo), buffer);
+       return false;
+}
+
+static int intel_sdvo_get_pixel_multiplier(const struct drm_display_mode *adjusted_mode)
+{
+       if (adjusted_mode->crtc_clock >= 100000)
+               return 1;
+       else if (adjusted_mode->crtc_clock >= 50000)
+               return 2;
+       else
+               return 4;
+}
+
+static bool __intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
+                                               u8 ddc_bus)
+{
+       /* This must be the immediately preceding write before the i2c xfer */
+       return __intel_sdvo_write_cmd(intel_sdvo,
+                                     SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+                                     &ddc_bus, 1, false);
+}
+
+static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
+{
+       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
+               return false;
+
+       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
+}
+
+static bool
+intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len)
+{
+       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0))
+               return false;
+
+       return intel_sdvo_read_response(intel_sdvo, value, len);
+}
+
+static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo)
+{
+       struct intel_sdvo_set_target_input_args targets = {0};
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_TARGET_INPUT,
+                                   &targets, sizeof(targets));
+}
+
+/*
+ * Return whether each input is trained.
+ *
+ * This function is making an assumption about the layout of the response,
+ * which should be checked against the docs.
+ */
+static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2)
+{
+       struct intel_sdvo_get_trained_inputs_response response;
+
+       BUILD_BUG_ON(sizeof(response) != 1);
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS,
+                                 &response, sizeof(response)))
+               return false;
+
+       *input_1 = response.input0_trained;
+       *input_2 = response.input1_trained;
+       return true;
+}
+
+static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,
+                                         u16 outputs)
+{
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_ACTIVE_OUTPUTS,
+                                   &outputs, sizeof(outputs));
+}
+
+static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
+                                         u16 *outputs)
+{
+       return intel_sdvo_get_value(intel_sdvo,
+                                   SDVO_CMD_GET_ACTIVE_OUTPUTS,
+                                   outputs, sizeof(*outputs));
+}
+
+static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
+                                              int mode)
+{
+       u8 state = SDVO_ENCODER_STATE_ON;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               state = SDVO_ENCODER_STATE_ON;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+               state = SDVO_ENCODER_STATE_STANDBY;
+               break;
+       case DRM_MODE_DPMS_SUSPEND:
+               state = SDVO_ENCODER_STATE_SUSPEND;
+               break;
+       case DRM_MODE_DPMS_OFF:
+               state = SDVO_ENCODER_STATE_OFF;
+               break;
+       }
+
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state));
+}
+
+static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo,
+                                                  int *clock_min,
+                                                  int *clock_max)
+{
+       struct intel_sdvo_pixel_clock_range clocks;
+
+       BUILD_BUG_ON(sizeof(clocks) != 4);
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
+                                 &clocks, sizeof(clocks)))
+               return false;
+
+       /* Convert the values from units of 10 kHz to kHz. */
+       *clock_min = clocks.min * 10;
+       *clock_max = clocks.max * 10;
+       return true;
+}
+
+static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo,
+                                        u16 outputs)
+{
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_TARGET_OUTPUT,
+                                   &outputs, sizeof(outputs));
+}
+
+static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
+               intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+}
+
+static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
+               intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+}
+
+static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_timing(intel_sdvo,
+                                    SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_timing(intel_sdvo,
+                                    SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
+                                       struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(intel_sdvo,
+                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool
+intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
+                                        struct intel_sdvo_connector *intel_sdvo_connector,
+                                        u16 clock,
+                                        u16 width,
+                                        u16 height)
+{
+       struct intel_sdvo_preferred_input_timing_args args;
+
+       memset(&args, 0, sizeof(args));
+       args.clock = clock;
+       args.width = width;
+       args.height = height;
+       args.interlace = 0;
+
+       if (IS_LVDS(intel_sdvo_connector)) {
+               const struct drm_display_mode *fixed_mode =
+                       intel_sdvo_connector->base.panel.fixed_mode;
+
+               if (fixed_mode->hdisplay != width ||
+                   fixed_mode->vdisplay != height)
+                       args.scaled = 1;
+       }
+
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
+                                   &args, sizeof(args));
+}
+
+static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo,
+                                                 struct intel_sdvo_dtd *dtd)
+{
+       BUILD_BUG_ON(sizeof(dtd->part1) != 8);
+       BUILD_BUG_ON(sizeof(dtd->part2) != 8);
+       return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
+                                   &dtd->part1, sizeof(dtd->part1)) &&
+               intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
+                                    &dtd->part2, sizeof(dtd->part2));
+}
+
+static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val)
+{
+       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
+}
+
+static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
+                                        const struct drm_display_mode *mode)
+{
+       u16 width, height;
+       u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+       u16 h_sync_offset, v_sync_offset;
+       int mode_clock;
+
+       memset(dtd, 0, sizeof(*dtd));
+
+       width = mode->hdisplay;
+       height = mode->vdisplay;
+
+       /* do some mode translations */
+       h_blank_len = mode->htotal - mode->hdisplay;
+       h_sync_len = mode->hsync_end - mode->hsync_start;
+
+       v_blank_len = mode->vtotal - mode->vdisplay;
+       v_sync_len = mode->vsync_end - mode->vsync_start;
+
+       h_sync_offset = mode->hsync_start - mode->hdisplay;
+       v_sync_offset = mode->vsync_start - mode->vdisplay;
+
+       mode_clock = mode->clock;
+       mode_clock /= 10;
+       dtd->part1.clock = mode_clock;
+
+       dtd->part1.h_active = width & 0xff;
+       dtd->part1.h_blank = h_blank_len & 0xff;
+       dtd->part1.h_high = (((width >> 8) & 0xf) << 4) |
+               ((h_blank_len >> 8) & 0xf);
+       dtd->part1.v_active = height & 0xff;
+       dtd->part1.v_blank = v_blank_len & 0xff;
+       dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
+               ((v_blank_len >> 8) & 0xf);
+
+       dtd->part2.h_sync_off = h_sync_offset & 0xff;
+       dtd->part2.h_sync_width = h_sync_len & 0xff;
+       dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
+               (v_sync_len & 0xf);
+       dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
+               ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
+               ((v_sync_len & 0x30) >> 4);
+
+       dtd->part2.dtd_flags = 0x18;
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE;
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE;
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
+
+       dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
+}
+
+static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode,
+                                        const struct intel_sdvo_dtd *dtd)
+{
+       struct drm_display_mode mode = {};
+
+       mode.hdisplay = dtd->part1.h_active;
+       mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
+       mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
+       mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
+       mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
+       mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
+       mode.htotal = mode.hdisplay + dtd->part1.h_blank;
+       mode.htotal += (dtd->part1.h_high & 0xf) << 8;
+
+       mode.vdisplay = dtd->part1.v_active;
+       mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
+       mode.vsync_start = mode.vdisplay;
+       mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
+       mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
+       mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0;
+       mode.vsync_end = mode.vsync_start +
+               (dtd->part2.v_sync_off_width & 0xf);
+       mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
+       mode.vtotal = mode.vdisplay + dtd->part1.v_blank;
+       mode.vtotal += (dtd->part1.v_high & 0xf) << 8;
+
+       mode.clock = dtd->part1.clock * 10;
+
+       if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
+               mode.flags |= DRM_MODE_FLAG_INTERLACE;
+       if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
+               mode.flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NHSYNC;
+       if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
+               mode.flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NVSYNC;
+
+       drm_mode_set_crtcinfo(&mode, 0);
+
+       drm_mode_copy(pmode, &mode);
+}
+
+static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
+{
+       struct intel_sdvo_encode encode;
+
+       BUILD_BUG_ON(sizeof(encode) != 2);
+       return intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_SUPP_ENCODE,
+                                 &encode, sizeof(encode));
+}
+
+static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
+                                 u8 mode)
+{
+       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1);
+}
+
+static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo,
+                                      u8 mode)
+{
+       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
+}
+
+static bool intel_sdvo_set_audio_state(struct intel_sdvo *intel_sdvo,
+                                      u8 audio_state)
+{
+       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_AUDIO_STAT,
+                                   &audio_state, 1);
+}
+
+#if 0
+static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
+{
+       int i, j;
+       u8 set_buf_index[2];
+       u8 av_split;
+       u8 buf_size;
+       u8 buf[48];
+       u8 *pos;
+
+       intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1);
+
+       for (i = 0; i <= av_split; i++) {
+               set_buf_index[0] = i; set_buf_index[1] = 0;
+               intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX,
+                                    set_buf_index, 2);
+               intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
+               intel_sdvo_read_response(encoder, &buf_size, 1);
+
+               pos = buf;
+               for (j = 0; j <= buf_size; j += 8) {
+                       intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA,
+                                            NULL, 0);
+                       intel_sdvo_read_response(encoder, pos, 8);
+                       pos += 8;
+               }
+       }
+}
+#endif
+
+static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
+                                      unsigned int if_index, u8 tx_rate,
+                                      const u8 *data, unsigned int length)
+{
+       u8 set_buf_index[2] = { if_index, 0 };
+       u8 hbuf_size, tmp[8];
+       int i;
+
+       if (!intel_sdvo_set_value(intel_sdvo,
+                                 SDVO_CMD_SET_HBUF_INDEX,
+                                 set_buf_index, 2))
+               return false;
+
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
+                                 &hbuf_size, 1))
+               return false;
+
+       /* Buffer size is 0 based, hooray! */
+       hbuf_size++;
+
+       DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
+                     if_index, length, hbuf_size);
+
+       if (hbuf_size < length)
+               return false;
+
+       for (i = 0; i < hbuf_size; i += 8) {
+               memset(tmp, 0, 8);
+               if (i < length)
+                       memcpy(tmp, data + i, min_t(unsigned, 8, length - i));
+
+               if (!intel_sdvo_set_value(intel_sdvo,
+                                         SDVO_CMD_SET_HBUF_DATA,
+                                         tmp, 8))
+                       return false;
+       }
+
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_HBUF_TXRATE,
+                                   &tx_rate, 1);
+}
+
+static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
+                                        unsigned int if_index,
+                                        u8 *data, unsigned int length)
+{
+       u8 set_buf_index[2] = { if_index, 0 };
+       u8 hbuf_size, tx_rate, av_split;
+       int i;
+
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_HBUF_AV_SPLIT,
+                                 &av_split, 1))
+               return -ENXIO;
+
+       if (av_split < if_index)
+               return 0;
+
+       if (!intel_sdvo_set_value(intel_sdvo,
+                                 SDVO_CMD_SET_HBUF_INDEX,
+                                 set_buf_index, 2))
+               return -ENXIO;
+
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_HBUF_TXRATE,
+                                 &tx_rate, 1))
+               return -ENXIO;
+
+       if (tx_rate == SDVO_HBUF_TX_DISABLED)
+               return 0;
+
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
+                                 &hbuf_size, 1))
+               return -ENXIO;
+
+       /* Buffer size is 0 based, hooray! */
+       hbuf_size++;
+
+       DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
+                     if_index, length, hbuf_size);
+
+       hbuf_size = min_t(unsigned int, length, hbuf_size);
+
+       for (i = 0; i < hbuf_size; i += 8) {
+               if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
+                       return -ENXIO;
+               if (!intel_sdvo_read_response(intel_sdvo, &data[i],
+                                             min_t(unsigned int, 8, hbuf_size - i)))
+                       return -ENXIO;
+       }
+
+       return hbuf_size;
+}
+
+static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
+                                            struct intel_crtc_state *crtc_state,
+                                            struct drm_connector_state *conn_state)
+{
+       struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       int ret;
+
+       if (!crtc_state->has_hdmi_sink)
+               return true;
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(frame,
+                                                      conn_state->connector,
+                                                      adjusted_mode);
+       if (ret)
+               return false;
+
+       drm_hdmi_avi_infoframe_quant_range(frame,
+                                          conn_state->connector,
+                                          adjusted_mode,
+                                          crtc_state->limited_color_range ?
+                                          HDMI_QUANTIZATION_RANGE_LIMITED :
+                                          HDMI_QUANTIZATION_RANGE_FULL);
+
+       ret = hdmi_avi_infoframe_check(frame);
+       if (WARN_ON(ret))
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
+                                        const struct intel_crtc_state *crtc_state)
+{
+       u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
+       const union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
+       ssize_t len;
+
+       if ((crtc_state->infoframes.enable &
+            intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI)) == 0)
+               return true;
+
+       if (WARN_ON(frame->any.type != HDMI_INFOFRAME_TYPE_AVI))
+               return false;
+
+       len = hdmi_infoframe_pack_only(frame, sdvo_data, sizeof(sdvo_data));
+       if (WARN_ON(len < 0))
+               return false;
+
+       return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
+                                         SDVO_HBUF_TX_VSYNC,
+                                         sdvo_data, len);
+}
+
+static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
+                                        struct intel_crtc_state *crtc_state)
+{
+       u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
+       union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
+       ssize_t len;
+       int ret;
+
+       if (!crtc_state->has_hdmi_sink)
+               return;
+
+       len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
+                                       sdvo_data, sizeof(sdvo_data));
+       if (len < 0) {
+               DRM_DEBUG_KMS("failed to read AVI infoframe\n");
+               return;
+       } else if (len == 0) {
+               return;
+       }
+
+       crtc_state->infoframes.enable |=
+               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
+
+       ret = hdmi_infoframe_unpack(frame, sdvo_data, len);
+       if (ret) {
+               DRM_DEBUG_KMS("Failed to unpack AVI infoframe\n");
+               return;
+       }
+
+       if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
+               DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
+                             frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
+}
+
+static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
+                                    const struct drm_connector_state *conn_state)
+{
+       struct intel_sdvo_tv_format format;
+       u32 format_map;
+
+       format_map = 1 << conn_state->tv.mode;
+       memset(&format, 0, sizeof(format));
+       memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map)));
+
+       BUILD_BUG_ON(sizeof(format) != 6);
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_TV_FORMAT,
+                                   &format, sizeof(format));
+}
+
+static bool
+intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
+                                       const struct drm_display_mode *mode)
+{
+       struct intel_sdvo_dtd output_dtd;
+
+       if (!intel_sdvo_set_target_output(intel_sdvo,
+                                         intel_sdvo->attached_output))
+               return false;
+
+       intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
+       if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
+               return false;
+
+       return true;
+}
+
+/*
+ * Asks the sdvo controller for the preferred input mode given the output mode.
+ * Unfortunately we have to set up the full output mode to do that.
+ */
+static bool
+intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
+                                   struct intel_sdvo_connector *intel_sdvo_connector,
+                                   const struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode)
+{
+       struct intel_sdvo_dtd input_dtd;
+
+       /* Reset the input timing to the screen. Assume always input 0. */
+       if (!intel_sdvo_set_target_input(intel_sdvo))
+               return false;
+
+       if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,
+                                                     intel_sdvo_connector,
+                                                     mode->clock / 10,
+                                                     mode->hdisplay,
+                                                     mode->vdisplay))
+               return false;
+
+       if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
+                                                  &input_dtd))
+               return false;
+
+       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+       intel_sdvo->dtd_sdvo_flags = input_dtd.part2.sdvo_flags;
+
+       return true;
+}
+
+static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
+{
+       unsigned dotclock = pipe_config->port_clock;
+       struct dpll *clock = &pipe_config->dpll;
+
+       /*
+        * SDVO TV has fixed PLL values depend on its clock range,
+        * this mirrors vbios setting.
+        */
+       if (dotclock >= 100000 && dotclock < 140500) {
+               clock->p1 = 2;
+               clock->p2 = 10;
+               clock->n = 3;
+               clock->m1 = 16;
+               clock->m2 = 8;
+       } else if (dotclock >= 140500 && dotclock <= 200000) {
+               clock->p1 = 1;
+               clock->p2 = 10;
+               clock->n = 6;
+               clock->m1 = 12;
+               clock->m2 = 8;
+       } else {
+               WARN(1, "SDVO TV clock out of range: %i\n", dotclock);
+       }
+
+       pipe_config->clock_set = true;
+}
+
+static int intel_sdvo_compute_config(struct intel_encoder *encoder,
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
+{
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+       struct intel_sdvo_connector_state *intel_sdvo_state =
+               to_intel_sdvo_connector_state(conn_state);
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(conn_state->connector);
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       struct drm_display_mode *mode = &pipe_config->base.mode;
+
+       DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
+       pipe_config->pipe_bpp = 8*3;
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       if (HAS_PCH_SPLIT(to_i915(encoder->base.dev)))
+               pipe_config->has_pch_encoder = true;
+
+       /*
+        * We need to construct preferred input timings based on our
+        * output timings.  To do that, we have to set the output
+        * timings, even though this isn't really the right place in
+        * the sequence to do it. Oh well.
+        */
+       if (IS_TV(intel_sdvo_connector)) {
+               if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
+                       return -EINVAL;
+
+               (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+                                                          intel_sdvo_connector,
+                                                          mode,
+                                                          adjusted_mode);
+               pipe_config->sdvo_tv_clock = true;
+       } else if (IS_LVDS(intel_sdvo_connector)) {
+               if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
+                                                            intel_sdvo_connector->base.panel.fixed_mode))
+                       return -EINVAL;
+
+               (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+                                                          intel_sdvo_connector,
+                                                          mode,
+                                                          adjusted_mode);
+       }
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       /*
+        * Make the CRTC code factor in the SDVO pixel multiplier.  The
+        * SDVO device will factor out the multiplier during mode_set.
+        */
+       pipe_config->pixel_multiplier =
+               intel_sdvo_get_pixel_multiplier(adjusted_mode);
+
+       if (intel_sdvo_state->base.force_audio != HDMI_AUDIO_OFF_DVI)
+               pipe_config->has_hdmi_sink = intel_sdvo->has_hdmi_monitor;
+
+       if (intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON ||
+           (intel_sdvo_state->base.force_audio == HDMI_AUDIO_AUTO && intel_sdvo->has_hdmi_audio))
+               pipe_config->has_audio = true;
+
+       if (intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
+               /*
+                * See CEA-861-E - 5.1 Default Encoding Parameters
+                *
+                * FIXME: This bit is only valid when using TMDS encoding and 8
+                * bit per color mode.
+                */
+               if (pipe_config->has_hdmi_sink &&
+                   drm_match_cea_mode(adjusted_mode) > 1)
+                       pipe_config->limited_color_range = true;
+       } else {
+               if (pipe_config->has_hdmi_sink &&
+                   intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED)
+                       pipe_config->limited_color_range = true;
+       }
+
+       /* Clock computation needs to happen after pixel multiplier. */
+       if (IS_TV(intel_sdvo_connector))
+               i9xx_adjust_sdvo_tv_clock(pipe_config);
+
+       /* Set user selected PAR to incoming mode's member */
+       if (intel_sdvo_connector->is_hdmi)
+               adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
+
+       if (!intel_sdvo_compute_avi_infoframe(intel_sdvo,
+                                             pipe_config, conn_state)) {
+               DRM_DEBUG_KMS("bad AVI infoframe\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#define UPDATE_PROPERTY(input, NAME) \
+       do { \
+               val = input; \
+               intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_##NAME, &val, sizeof(val)); \
+       } while (0)
+
+static void intel_sdvo_update_props(struct intel_sdvo *intel_sdvo,
+                                   const struct intel_sdvo_connector_state *sdvo_state)
+{
+       const struct drm_connector_state *conn_state = &sdvo_state->base.base;
+       struct intel_sdvo_connector *intel_sdvo_conn =
+               to_intel_sdvo_connector(conn_state->connector);
+       u16 val;
+
+       if (intel_sdvo_conn->left)
+               UPDATE_PROPERTY(sdvo_state->tv.overscan_h, OVERSCAN_H);
+
+       if (intel_sdvo_conn->top)
+               UPDATE_PROPERTY(sdvo_state->tv.overscan_v, OVERSCAN_V);
+
+       if (intel_sdvo_conn->hpos)
+               UPDATE_PROPERTY(sdvo_state->tv.hpos, HPOS);
+
+       if (intel_sdvo_conn->vpos)
+               UPDATE_PROPERTY(sdvo_state->tv.vpos, VPOS);
+
+       if (intel_sdvo_conn->saturation)
+               UPDATE_PROPERTY(conn_state->tv.saturation, SATURATION);
+
+       if (intel_sdvo_conn->contrast)
+               UPDATE_PROPERTY(conn_state->tv.contrast, CONTRAST);
+
+       if (intel_sdvo_conn->hue)
+               UPDATE_PROPERTY(conn_state->tv.hue, HUE);
+
+       if (intel_sdvo_conn->brightness)
+               UPDATE_PROPERTY(conn_state->tv.brightness, BRIGHTNESS);
+
+       if (intel_sdvo_conn->sharpness)
+               UPDATE_PROPERTY(sdvo_state->tv.sharpness, SHARPNESS);
+
+       if (intel_sdvo_conn->flicker_filter)
+               UPDATE_PROPERTY(sdvo_state->tv.flicker_filter, FLICKER_FILTER);
+
+       if (intel_sdvo_conn->flicker_filter_2d)
+               UPDATE_PROPERTY(sdvo_state->tv.flicker_filter_2d, FLICKER_FILTER_2D);
+
+       if (intel_sdvo_conn->flicker_filter_adaptive)
+               UPDATE_PROPERTY(sdvo_state->tv.flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
+
+       if (intel_sdvo_conn->tv_chroma_filter)
+               UPDATE_PROPERTY(sdvo_state->tv.chroma_filter, TV_CHROMA_FILTER);
+
+       if (intel_sdvo_conn->tv_luma_filter)
+               UPDATE_PROPERTY(sdvo_state->tv.luma_filter, TV_LUMA_FILTER);
+
+       if (intel_sdvo_conn->dot_crawl)
+               UPDATE_PROPERTY(sdvo_state->tv.dot_crawl, DOT_CRAWL);
+
+#undef UPDATE_PROPERTY
+}
+
+static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
+                                 const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
+       const struct intel_sdvo_connector_state *sdvo_state =
+               to_intel_sdvo_connector_state(conn_state);
+       const struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(conn_state->connector);
+       const struct drm_display_mode *mode = &crtc_state->base.mode;
+       struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
+       u32 sdvox;
+       struct intel_sdvo_in_out_map in_out;
+       struct intel_sdvo_dtd input_dtd, output_dtd;
+       int rate;
+
+       intel_sdvo_update_props(intel_sdvo, sdvo_state);
+
+       /*
+        * First, set the input mapping for the first input to our controlled
+        * output. This is only correct if we're a single-input device, in
+        * which case the first input is the output from the appropriate SDVO
+        * channel on the motherboard.  In a two-input device, the first input
+        * will be SDVOB and the second SDVOC.
+        */
+       in_out.in0 = intel_sdvo->attached_output;
+       in_out.in1 = 0;
+
+       intel_sdvo_set_value(intel_sdvo,
+                            SDVO_CMD_SET_IN_OUT_MAP,
+                            &in_out, sizeof(in_out));
+
+       /* Set the output timings to the screen */
+       if (!intel_sdvo_set_target_output(intel_sdvo,
+                                         intel_sdvo->attached_output))
+               return;
+
+       /* lvds has a special fixed output timing. */
+       if (IS_LVDS(intel_sdvo_connector))
+               intel_sdvo_get_dtd_from_mode(&output_dtd,
+                                            intel_sdvo_connector->base.panel.fixed_mode);
+       else
+               intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
+       if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
+               DRM_INFO("Setting output timings on %s failed\n",
+                        SDVO_NAME(intel_sdvo));
+
+       /* Set the input timing to the screen. Assume always input 0. */
+       if (!intel_sdvo_set_target_input(intel_sdvo))
+               return;
+
+       if (crtc_state->has_hdmi_sink) {
+               intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
+               intel_sdvo_set_colorimetry(intel_sdvo,
+                                          SDVO_COLORIMETRY_RGB256);
+               intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state);
+       } else
+               intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
+
+       if (IS_TV(intel_sdvo_connector) &&
+           !intel_sdvo_set_tv_format(intel_sdvo, conn_state))
+               return;
+
+       intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
+
+       if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector))
+               input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags;
+       if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
+               DRM_INFO("Setting input timings on %s failed\n",
+                        SDVO_NAME(intel_sdvo));
+
+       switch (crtc_state->pixel_multiplier) {
+       default:
+               WARN(1, "unknown pixel multiplier specified\n");
+               /* fall through */
+       case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
+       case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
+       case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
+       }
+       if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate))
+               return;
+
+       /* Set the SDVO control regs. */
+       if (INTEL_GEN(dev_priv) >= 4) {
+               /* The real mode polarity is set by the SDVO commands, using
+                * struct intel_sdvo_dtd. */
+               sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
+               if (!HAS_PCH_SPLIT(dev_priv) && crtc_state->limited_color_range)
+                       sdvox |= HDMI_COLOR_RANGE_16_235;
+               if (INTEL_GEN(dev_priv) < 5)
+                       sdvox |= SDVO_BORDER_ENABLE;
+       } else {
+               sdvox = I915_READ(intel_sdvo->sdvo_reg);
+               if (intel_sdvo->port == PORT_B)
+                       sdvox &= SDVOB_PRESERVE_MASK;
+               else
+                       sdvox &= SDVOC_PRESERVE_MASK;
+               sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
+       }
+
+       if (HAS_PCH_CPT(dev_priv))
+               sdvox |= SDVO_PIPE_SEL_CPT(crtc->pipe);
+       else
+               sdvox |= SDVO_PIPE_SEL(crtc->pipe);
+
+       if (INTEL_GEN(dev_priv) >= 4) {
+               /* done in crtc_mode_set as the dpll_md reg must be written early */
+       } else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
+                  IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
+               /* done in crtc_mode_set as it lives inside the dpll register */
+       } else {
+               sdvox |= (crtc_state->pixel_multiplier - 1)
+                       << SDVO_PORT_MULTIPLY_SHIFT;
+       }
+
+       if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL &&
+           INTEL_GEN(dev_priv) < 5)
+               sdvox |= SDVO_STALL_SELECT;
+       intel_sdvo_write_sdvox(intel_sdvo, sdvox);
+}
+
+static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
+{
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(&connector->base);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
+       u16 active_outputs = 0;
+
+       intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
+
+       return active_outputs & intel_sdvo_connector->output_flag;
+}
+
+bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv,
+                            i915_reg_t sdvo_reg, enum pipe *pipe)
+{
+       u32 val;
+
+       val = I915_READ(sdvo_reg);
+
+       /* asserts want to know the pipe even if the port is disabled */
+       if (HAS_PCH_CPT(dev_priv))
+               *pipe = (val & SDVO_PIPE_SEL_MASK_CPT) >> SDVO_PIPE_SEL_SHIFT_CPT;
+       else if (IS_CHERRYVIEW(dev_priv))
+               *pipe = (val & SDVO_PIPE_SEL_MASK_CHV) >> SDVO_PIPE_SEL_SHIFT_CHV;
+       else
+               *pipe = (val & SDVO_PIPE_SEL_MASK) >> SDVO_PIPE_SEL_SHIFT;
+
+       return val & SDVO_ENABLE;
+}
+
+static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
+                                   enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+       u16 active_outputs = 0;
+       bool ret;
+
+       intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
+
+       ret = intel_sdvo_port_enabled(dev_priv, intel_sdvo->sdvo_reg, pipe);
+
+       return ret || active_outputs;
+}
+
+static void intel_sdvo_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+       struct intel_sdvo_dtd dtd;
+       int encoder_pixel_multiplier = 0;
+       int dotclock;
+       u32 flags = 0, sdvox;
+       u8 val;
+       bool ret;
+
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_SDVO);
+
+       sdvox = I915_READ(intel_sdvo->sdvo_reg);
+
+       ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
+       if (!ret) {
+               /*
+                * Some sdvo encoders are not spec compliant and don't
+                * implement the mandatory get_timings function.
+                */
+               DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
+               pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS;
+       } else {
+               if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
+                       flags |= DRM_MODE_FLAG_PHSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NHSYNC;
+
+               if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
+                       flags |= DRM_MODE_FLAG_PVSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NVSYNC;
+       }
+
+       pipe_config->base.adjusted_mode.flags |= flags;
+
+       /*
+        * pixel multiplier readout is tricky: Only on i915g/gm it is stored in
+        * the sdvo port register, on all other platforms it is part of the dpll
+        * state. Since the general pipe state readout happens before the
+        * encoder->get_config we so already have a valid pixel multplier on all
+        * other platfroms.
+        */
+       if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
+               pipe_config->pixel_multiplier =
+                       ((sdvox & SDVO_PORT_MULTIPLY_MASK)
+                        >> SDVO_PORT_MULTIPLY_SHIFT) + 1;
+       }
+
+       dotclock = pipe_config->port_clock;
+
+       if (pipe_config->pixel_multiplier)
+               dotclock /= pipe_config->pixel_multiplier;
+
+       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+
+       /* Cross check the port pixel multiplier with the sdvo encoder state. */
+       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
+                                &val, 1)) {
+               switch (val) {
+               case SDVO_CLOCK_RATE_MULT_1X:
+                       encoder_pixel_multiplier = 1;
+                       break;
+               case SDVO_CLOCK_RATE_MULT_2X:
+                       encoder_pixel_multiplier = 2;
+                       break;
+               case SDVO_CLOCK_RATE_MULT_4X:
+                       encoder_pixel_multiplier = 4;
+                       break;
+               }
+       }
+
+       WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
+            "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
+            pipe_config->pixel_multiplier, encoder_pixel_multiplier);
+
+       if (sdvox & HDMI_COLOR_RANGE_16_235)
+               pipe_config->limited_color_range = true;
+
+       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
+                                &val, 1)) {
+               u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT;
+
+               if ((val & mask) == mask)
+                       pipe_config->has_audio = true;
+       }
+
+       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
+                                &val, 1)) {
+               if (val == SDVO_ENCODE_HDMI)
+                       pipe_config->has_hdmi_sink = true;
+       }
+
+       intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
+}
+
+static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo)
+{
+       intel_sdvo_set_audio_state(intel_sdvo, 0);
+}
+
+static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo,
+                                   const struct intel_crtc_state *crtc_state,
+                                   const struct drm_connector_state *conn_state)
+{
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       struct drm_connector *connector = conn_state->connector;
+       u8 *eld = connector->eld;
+
+       eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
+
+       intel_sdvo_set_audio_state(intel_sdvo, 0);
+
+       intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD,
+                                  SDVO_HBUF_TX_DISABLED,
+                                  eld, drm_eld_size(eld));
+
+       intel_sdvo_set_audio_state(intel_sdvo, SDVO_AUDIO_ELD_VALID |
+                                  SDVO_AUDIO_PRESENCE_DETECT);
+}
+
+static void intel_disable_sdvo(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *old_crtc_state,
+                              const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       u32 temp;
+
+       if (old_crtc_state->has_audio)
+               intel_sdvo_disable_audio(intel_sdvo);
+
+       intel_sdvo_set_active_outputs(intel_sdvo, 0);
+       if (0)
+               intel_sdvo_set_encoder_power_state(intel_sdvo,
+                                                  DRM_MODE_DPMS_OFF);
+
+       temp = I915_READ(intel_sdvo->sdvo_reg);
+
+       temp &= ~SDVO_ENABLE;
+       intel_sdvo_write_sdvox(intel_sdvo, temp);
+
+       /*
+        * HW workaround for IBX, we need to move the port
+        * to transcoder A after disabling it to allow the
+        * matching DP port to be enabled on transcoder A.
+        */
+       if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
+               /*
+                * We get CPU/PCH FIFO underruns on the other pipe when
+                * doing the workaround. Sweep them under the rug.
+                */
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
+               temp &= ~SDVO_PIPE_SEL_MASK;
+               temp |= SDVO_ENABLE | SDVO_PIPE_SEL(PIPE_A);
+               intel_sdvo_write_sdvox(intel_sdvo, temp);
+
+               temp &= ~SDVO_ENABLE;
+               intel_sdvo_write_sdvox(intel_sdvo, temp);
+
+               intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+       }
+}
+
+static void pch_disable_sdvo(struct intel_encoder *encoder,
+                            const struct intel_crtc_state *old_crtc_state,
+                            const struct drm_connector_state *old_conn_state)
+{
+}
+
+static void pch_post_disable_sdvo(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *old_crtc_state,
+                                 const struct drm_connector_state *old_conn_state)
+{
+       intel_disable_sdvo(encoder, old_crtc_state, old_conn_state);
+}
+
+static void intel_enable_sdvo(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config,
+                             const struct drm_connector_state *conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       u32 temp;
+       bool input1, input2;
+       int i;
+       bool success;
+
+       temp = I915_READ(intel_sdvo->sdvo_reg);
+       temp |= SDVO_ENABLE;
+       intel_sdvo_write_sdvox(intel_sdvo, temp);
+
+       for (i = 0; i < 2; i++)
+               intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
+
+       success = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
+       /*
+        * Warn if the device reported failure to sync.
+        *
+        * A lot of SDVO devices fail to notify of sync, but it's
+        * a given it the status is a success, we succeeded.
+        */
+       if (success && !input1) {
+               DRM_DEBUG_KMS("First %s output reported failure to "
+                               "sync\n", SDVO_NAME(intel_sdvo));
+       }
+
+       if (0)
+               intel_sdvo_set_encoder_power_state(intel_sdvo,
+                                                  DRM_MODE_DPMS_ON);
+       intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
+
+       if (pipe_config->has_audio)
+               intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state);
+}
+
+static enum drm_mode_status
+intel_sdvo_mode_valid(struct drm_connector *connector,
+                     struct drm_display_mode *mode)
+{
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(connector);
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (intel_sdvo->pixel_clock_min > mode->clock)
+               return MODE_CLOCK_LOW;
+
+       if (intel_sdvo->pixel_clock_max < mode->clock)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       if (IS_LVDS(intel_sdvo_connector)) {
+               const struct drm_display_mode *fixed_mode =
+                       intel_sdvo_connector->base.panel.fixed_mode;
+
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+
+       return MODE_OK;
+}
+
+static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
+{
+       BUILD_BUG_ON(sizeof(*caps) != 8);
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_DEVICE_CAPS,
+                                 caps, sizeof(*caps)))
+               return false;
+
+       DRM_DEBUG_KMS("SDVO capabilities:\n"
+                     "  vendor_id: %d\n"
+                     "  device_id: %d\n"
+                     "  device_rev_id: %d\n"
+                     "  sdvo_version_major: %d\n"
+                     "  sdvo_version_minor: %d\n"
+                     "  sdvo_inputs_mask: %d\n"
+                     "  smooth_scaling: %d\n"
+                     "  sharp_scaling: %d\n"
+                     "  up_scaling: %d\n"
+                     "  down_scaling: %d\n"
+                     "  stall_support: %d\n"
+                     "  output_flags: %d\n",
+                     caps->vendor_id,
+                     caps->device_id,
+                     caps->device_rev_id,
+                     caps->sdvo_version_major,
+                     caps->sdvo_version_minor,
+                     caps->sdvo_inputs_mask,
+                     caps->smooth_scaling,
+                     caps->sharp_scaling,
+                     caps->up_scaling,
+                     caps->down_scaling,
+                     caps->stall_support,
+                     caps->output_flags);
+
+       return true;
+}
+
+static u16 intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_sdvo->base.base.dev);
+       u16 hotplug;
+
+       if (!I915_HAS_HOTPLUG(dev_priv))
+               return 0;
+
+       /*
+        * HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
+        * on the line.
+        */
+       if (IS_I945G(dev_priv) || IS_I945GM(dev_priv))
+               return 0;
+
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
+                                       &hotplug, sizeof(hotplug)))
+               return 0;
+
+       return hotplug;
+}
+
+static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
+{
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+
+       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
+                            &intel_sdvo->hotplug_active, 2);
+}
+
+static bool intel_sdvo_hotplug(struct intel_encoder *encoder,
+                              struct intel_connector *connector)
+{
+       intel_sdvo_enable_hotplug(encoder);
+
+       return intel_encoder_hotplug(encoder, connector);
+}
+
+static bool
+intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
+{
+       /* Is there more than one type of output? */
+       return hweight16(intel_sdvo->caps.output_flags) > 1;
+}
+
+static struct edid *
+intel_sdvo_get_edid(struct drm_connector *connector)
+{
+       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+       return drm_get_edid(connector, &sdvo->ddc);
+}
+
+/* Mac mini hack -- use the same DDC as the analog connector */
+static struct edid *
+intel_sdvo_get_analog_edid(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+
+       return drm_get_edid(connector,
+                           intel_gmbus_get_adapter(dev_priv,
+                                                   dev_priv->vbt.crt_ddc_pin));
+}
+
+static enum drm_connector_status
+intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
+{
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(connector);
+       enum drm_connector_status status;
+       struct edid *edid;
+
+       edid = intel_sdvo_get_edid(connector);
+
+       if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
+               u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
+
+               /*
+                * Don't use the 1 as the argument of DDC bus switch to get
+                * the EDID. It is used for SDVO SPD ROM.
+                */
+               for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
+                       intel_sdvo->ddc_bus = ddc;
+                       edid = intel_sdvo_get_edid(connector);
+                       if (edid)
+                               break;
+               }
+               /*
+                * If we found the EDID on the other bus,
+                * assume that is the correct DDC bus.
+                */
+               if (edid == NULL)
+                       intel_sdvo->ddc_bus = saved_ddc;
+       }
+
+       /*
+        * When there is no edid and no monitor is connected with VGA
+        * port, try to use the CRT ddc to read the EDID for DVI-connector.
+        */
+       if (edid == NULL)
+               edid = intel_sdvo_get_analog_edid(connector);
+
+       status = connector_status_unknown;
+       if (edid != NULL) {
+               /* DDC bus is shared, match EDID to connector type */
+               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+                       status = connector_status_connected;
+                       if (intel_sdvo_connector->is_hdmi) {
+                               intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
+                               intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
+                       }
+               } else
+                       status = connector_status_disconnected;
+               kfree(edid);
+       }
+
+       return status;
+}
+
+static bool
+intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
+                                 struct edid *edid)
+{
+       bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
+       bool connector_is_digital = !!IS_DIGITAL(sdvo);
+
+       DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n",
+                     connector_is_digital, monitor_is_digital);
+       return connector_is_digital == monitor_is_digital;
+}
+
+static enum drm_connector_status
+intel_sdvo_detect(struct drm_connector *connector, bool force)
+{
+       u16 response;
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+       enum drm_connector_status ret;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_ATTACHED_DISPLAYS,
+                                 &response, 2))
+               return connector_status_unknown;
+
+       DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
+                     response & 0xff, response >> 8,
+                     intel_sdvo_connector->output_flag);
+
+       if (response == 0)
+               return connector_status_disconnected;
+
+       intel_sdvo->attached_output = response;
+
+       intel_sdvo->has_hdmi_monitor = false;
+       intel_sdvo->has_hdmi_audio = false;
+
+       if ((intel_sdvo_connector->output_flag & response) == 0)
+               ret = connector_status_disconnected;
+       else if (IS_TMDS(intel_sdvo_connector))
+               ret = intel_sdvo_tmds_sink_detect(connector);
+       else {
+               struct edid *edid;
+
+               /* if we have an edid check it matches the connection */
+               edid = intel_sdvo_get_edid(connector);
+               if (edid == NULL)
+                       edid = intel_sdvo_get_analog_edid(connector);
+               if (edid != NULL) {
+                       if (intel_sdvo_connector_matches_edid(intel_sdvo_connector,
+                                                             edid))
+                               ret = connector_status_connected;
+                       else
+                               ret = connector_status_disconnected;
+
+                       kfree(edid);
+               } else
+                       ret = connector_status_connected;
+       }
+
+       return ret;
+}
+
+static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
+{
+       struct edid *edid;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       /* set the bus switch and get the modes */
+       edid = intel_sdvo_get_edid(connector);
+
+       /*
+        * Mac mini hack.  On this device, the DVI-I connector shares one DDC
+        * link between analog and digital outputs. So, if the regular SDVO
+        * DDC fails, check to see if the analog output is disconnected, in
+        * which case we'll look there for the digital DDC data.
+        */
+       if (edid == NULL)
+               edid = intel_sdvo_get_analog_edid(connector);
+
+       if (edid != NULL) {
+               if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector),
+                                                     edid)) {
+                       drm_connector_update_edid_property(connector, edid);
+                       drm_add_edid_modes(connector, edid);
+               }
+
+               kfree(edid);
+       }
+}
+
+/*
+ * Set of SDVO TV modes.
+ * Note!  This is in reply order (see loop in get_tv_modes).
+ * XXX: all 60Hz refresh?
+ */
+static const struct drm_display_mode sdvo_tv_modes[] = {
+       { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
+                  416, 0, 200, 201, 232, 233, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
+                  416, 0, 240, 241, 272, 273, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
+                  496, 0, 300, 301, 332, 333, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
+                  736, 0, 350, 351, 382, 383, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
+                  736, 0, 400, 401, 432, 433, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
+                  736, 0, 480, 481, 512, 513, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
+                  800, 0, 480, 481, 512, 513, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
+                  800, 0, 576, 577, 608, 609, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
+                  816, 0, 350, 351, 382, 383, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
+                  816, 0, 400, 401, 432, 433, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
+                  816, 0, 480, 481, 512, 513, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
+                  816, 0, 540, 541, 572, 573, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
+                  816, 0, 576, 577, 608, 609, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
+                  864, 0, 576, 577, 608, 609, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
+                  896, 0, 600, 601, 632, 633, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
+                  928, 0, 624, 625, 656, 657, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
+                  1016, 0, 766, 767, 798, 799, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
+                  1120, 0, 768, 769, 800, 801, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
+                  1376, 0, 1024, 1025, 1056, 1057, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+};
+
+static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
+{
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       const struct drm_connector_state *conn_state = connector->state;
+       struct intel_sdvo_sdtv_resolution_request tv_res;
+       u32 reply = 0, format_map = 0;
+       int i;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       /*
+        * Read the list of supported input resolutions for the selected TV
+        * format.
+        */
+       format_map = 1 << conn_state->tv.mode;
+       memcpy(&tv_res, &format_map,
+              min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));
+
+       if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output))
+               return;
+
+       BUILD_BUG_ON(sizeof(tv_res) != 3);
+       if (!intel_sdvo_write_cmd(intel_sdvo,
+                                 SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+                                 &tv_res, sizeof(tv_res)))
+               return;
+       if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
+               if (reply & (1 << i)) {
+                       struct drm_display_mode *nmode;
+                       nmode = drm_mode_duplicate(connector->dev,
+                                                  &sdvo_tv_modes[i]);
+                       if (nmode)
+                               drm_mode_probed_add(connector, nmode);
+               }
+}
+
+static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
+{
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct drm_display_mode *newmode;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       /*
+        * Fetch modes from VBT. For SDVO prefer the VBT mode since some
+        * SDVO->LVDS transcoders can't cope with the EDID mode.
+        */
+       if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) {
+               newmode = drm_mode_duplicate(connector->dev,
+                                            dev_priv->vbt.sdvo_lvds_vbt_mode);
+               if (newmode != NULL) {
+                       /* Guarantee the mode is preferred */
+                       newmode->type = (DRM_MODE_TYPE_PREFERRED |
+                                        DRM_MODE_TYPE_DRIVER);
+                       drm_mode_probed_add(connector, newmode);
+               }
+       }
+
+       /*
+        * Attempt to get the mode list from DDC.
+        * Assume that the preferred modes are
+        * arranged in priority order.
+        */
+       intel_ddc_get_modes(connector, &intel_sdvo->ddc);
+}
+
+static int intel_sdvo_get_modes(struct drm_connector *connector)
+{
+       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+
+       if (IS_TV(intel_sdvo_connector))
+               intel_sdvo_get_tv_modes(connector);
+       else if (IS_LVDS(intel_sdvo_connector))
+               intel_sdvo_get_lvds_modes(connector);
+       else
+               intel_sdvo_get_ddc_modes(connector);
+
+       return !list_empty(&connector->probed_modes);
+}
+
+static int
+intel_sdvo_connector_atomic_get_property(struct drm_connector *connector,
+                                        const struct drm_connector_state *state,
+                                        struct drm_property *property,
+                                        u64 *val)
+{
+       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+       const struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state((void *)state);
+
+       if (property == intel_sdvo_connector->tv_format) {
+               int i;
+
+               for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
+                       if (state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) {
+                               *val = i;
+
+                               return 0;
+                       }
+
+               WARN_ON(1);
+               *val = 0;
+       } else if (property == intel_sdvo_connector->top ||
+                  property == intel_sdvo_connector->bottom)
+               *val = intel_sdvo_connector->max_vscan - sdvo_state->tv.overscan_v;
+       else if (property == intel_sdvo_connector->left ||
+                property == intel_sdvo_connector->right)
+               *val = intel_sdvo_connector->max_hscan - sdvo_state->tv.overscan_h;
+       else if (property == intel_sdvo_connector->hpos)
+               *val = sdvo_state->tv.hpos;
+       else if (property == intel_sdvo_connector->vpos)
+               *val = sdvo_state->tv.vpos;
+       else if (property == intel_sdvo_connector->saturation)
+               *val = state->tv.saturation;
+       else if (property == intel_sdvo_connector->contrast)
+               *val = state->tv.contrast;
+       else if (property == intel_sdvo_connector->hue)
+               *val = state->tv.hue;
+       else if (property == intel_sdvo_connector->brightness)
+               *val = state->tv.brightness;
+       else if (property == intel_sdvo_connector->sharpness)
+               *val = sdvo_state->tv.sharpness;
+       else if (property == intel_sdvo_connector->flicker_filter)
+               *val = sdvo_state->tv.flicker_filter;
+       else if (property == intel_sdvo_connector->flicker_filter_2d)
+               *val = sdvo_state->tv.flicker_filter_2d;
+       else if (property == intel_sdvo_connector->flicker_filter_adaptive)
+               *val = sdvo_state->tv.flicker_filter_adaptive;
+       else if (property == intel_sdvo_connector->tv_chroma_filter)
+               *val = sdvo_state->tv.chroma_filter;
+       else if (property == intel_sdvo_connector->tv_luma_filter)
+               *val = sdvo_state->tv.luma_filter;
+       else if (property == intel_sdvo_connector->dot_crawl)
+               *val = sdvo_state->tv.dot_crawl;
+       else
+               return intel_digital_connector_atomic_get_property(connector, state, property, val);
+
+       return 0;
+}
+
+static int
+intel_sdvo_connector_atomic_set_property(struct drm_connector *connector,
+                                        struct drm_connector_state *state,
+                                        struct drm_property *property,
+                                        u64 val)
+{
+       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+       struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(state);
+
+       if (property == intel_sdvo_connector->tv_format) {
+               state->tv.mode = intel_sdvo_connector->tv_format_supported[val];
+
+               if (state->crtc) {
+                       struct drm_crtc_state *crtc_state =
+                               drm_atomic_get_new_crtc_state(state->state, state->crtc);
+
+                       crtc_state->connectors_changed = true;
+               }
+       } else if (property == intel_sdvo_connector->top ||
+                  property == intel_sdvo_connector->bottom)
+               /* Cannot set these independent from each other */
+               sdvo_state->tv.overscan_v = intel_sdvo_connector->max_vscan - val;
+       else if (property == intel_sdvo_connector->left ||
+                property == intel_sdvo_connector->right)
+               /* Cannot set these independent from each other */
+               sdvo_state->tv.overscan_h = intel_sdvo_connector->max_hscan - val;
+       else if (property == intel_sdvo_connector->hpos)
+               sdvo_state->tv.hpos = val;
+       else if (property == intel_sdvo_connector->vpos)
+               sdvo_state->tv.vpos = val;
+       else if (property == intel_sdvo_connector->saturation)
+               state->tv.saturation = val;
+       else if (property == intel_sdvo_connector->contrast)
+               state->tv.contrast = val;
+       else if (property == intel_sdvo_connector->hue)
+               state->tv.hue = val;
+       else if (property == intel_sdvo_connector->brightness)
+               state->tv.brightness = val;
+       else if (property == intel_sdvo_connector->sharpness)
+               sdvo_state->tv.sharpness = val;
+       else if (property == intel_sdvo_connector->flicker_filter)
+               sdvo_state->tv.flicker_filter = val;
+       else if (property == intel_sdvo_connector->flicker_filter_2d)
+               sdvo_state->tv.flicker_filter_2d = val;
+       else if (property == intel_sdvo_connector->flicker_filter_adaptive)
+               sdvo_state->tv.flicker_filter_adaptive = val;
+       else if (property == intel_sdvo_connector->tv_chroma_filter)
+               sdvo_state->tv.chroma_filter = val;
+       else if (property == intel_sdvo_connector->tv_luma_filter)
+               sdvo_state->tv.luma_filter = val;
+       else if (property == intel_sdvo_connector->dot_crawl)
+               sdvo_state->tv.dot_crawl = val;
+       else
+               return intel_digital_connector_atomic_set_property(connector, state, property, val);
+
+       return 0;
+}
+
+static int
+intel_sdvo_connector_register(struct drm_connector *connector)
+{
+       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+       int ret;
+
+       ret = intel_connector_register(connector);
+       if (ret)
+               return ret;
+
+       return sysfs_create_link(&connector->kdev->kobj,
+                                &sdvo->ddc.dev.kobj,
+                                sdvo->ddc.dev.kobj.name);
+}
+
+static void
+intel_sdvo_connector_unregister(struct drm_connector *connector)
+{
+       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+
+       sysfs_remove_link(&connector->kdev->kobj,
+                         sdvo->ddc.dev.kobj.name);
+       intel_connector_unregister(connector);
+}
+
+static struct drm_connector_state *
+intel_sdvo_connector_duplicate_state(struct drm_connector *connector)
+{
+       struct intel_sdvo_connector_state *state;
+
+       state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       __drm_atomic_helper_connector_duplicate_state(connector, &state->base.base);
+       return &state->base.base;
+}
+
+static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
+       .detect = intel_sdvo_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_sdvo_connector_atomic_get_property,
+       .atomic_set_property = intel_sdvo_connector_atomic_set_property,
+       .late_register = intel_sdvo_connector_register,
+       .early_unregister = intel_sdvo_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
+};
+
+static int intel_sdvo_atomic_check(struct drm_connector *conn,
+                                  struct drm_connector_state *new_conn_state)
+{
+       struct drm_atomic_state *state = new_conn_state->state;
+       struct drm_connector_state *old_conn_state =
+               drm_atomic_get_old_connector_state(state, conn);
+       struct intel_sdvo_connector_state *old_state =
+               to_intel_sdvo_connector_state(old_conn_state);
+       struct intel_sdvo_connector_state *new_state =
+               to_intel_sdvo_connector_state(new_conn_state);
+
+       if (new_conn_state->crtc &&
+           (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
+            memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
+               struct drm_crtc_state *crtc_state =
+                       drm_atomic_get_new_crtc_state(new_conn_state->state,
+                                                     new_conn_state->crtc);
+
+               crtc_state->connectors_changed = true;
+       }
+
+       return intel_digital_connector_atomic_check(conn, new_conn_state);
+}
+
+static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
+       .get_modes = intel_sdvo_get_modes,
+       .mode_valid = intel_sdvo_mode_valid,
+       .atomic_check = intel_sdvo_atomic_check,
+};
+
+static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
+{
+       struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder));
+
+       i2c_del_adapter(&intel_sdvo->ddc);
+       intel_encoder_destroy(encoder);
+}
+
+static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
+       .destroy = intel_sdvo_enc_destroy,
+};
+
+static void
+intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
+{
+       u16 mask = 0;
+       unsigned int num_bits;
+
+       /*
+        * Make a mask of outputs less than or equal to our own priority in the
+        * list.
+        */
+       switch (sdvo->controlled_output) {
+       case SDVO_OUTPUT_LVDS1:
+               mask |= SDVO_OUTPUT_LVDS1;
+               /* fall through */
+       case SDVO_OUTPUT_LVDS0:
+               mask |= SDVO_OUTPUT_LVDS0;
+               /* fall through */
+       case SDVO_OUTPUT_TMDS1:
+               mask |= SDVO_OUTPUT_TMDS1;
+               /* fall through */
+       case SDVO_OUTPUT_TMDS0:
+               mask |= SDVO_OUTPUT_TMDS0;
+               /* fall through */
+       case SDVO_OUTPUT_RGB1:
+               mask |= SDVO_OUTPUT_RGB1;
+               /* fall through */
+       case SDVO_OUTPUT_RGB0:
+               mask |= SDVO_OUTPUT_RGB0;
+               break;
+       }
+
+       /* Count bits to find what number we are in the priority list. */
+       mask &= sdvo->caps.output_flags;
+       num_bits = hweight16(mask);
+       /* If more than 3 outputs, default to DDC bus 3 for now. */
+       if (num_bits > 3)
+               num_bits = 3;
+
+       /* Corresponds to SDVO_CONTROL_BUS_DDCx */
+       sdvo->ddc_bus = 1 << num_bits;
+}
+
+/*
+ * Choose the appropriate DDC bus for control bus switch command for this
+ * SDVO output based on the controlled output.
+ *
+ * DDC bus number assignment is in a priority order of RGB outputs, then TMDS
+ * outputs, then LVDS outputs.
+ */
+static void
+intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
+                         struct intel_sdvo *sdvo)
+{
+       struct sdvo_device_mapping *mapping;
+
+       if (sdvo->port == PORT_B)
+               mapping = &dev_priv->vbt.sdvo_mappings[0];
+       else
+               mapping = &dev_priv->vbt.sdvo_mappings[1];
+
+       if (mapping->initialized)
+               sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4);
+       else
+               intel_sdvo_guess_ddc_bus(sdvo);
+}
+
+static void
+intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
+                         struct intel_sdvo *sdvo)
+{
+       struct sdvo_device_mapping *mapping;
+       u8 pin;
+
+       if (sdvo->port == PORT_B)
+               mapping = &dev_priv->vbt.sdvo_mappings[0];
+       else
+               mapping = &dev_priv->vbt.sdvo_mappings[1];
+
+       if (mapping->initialized &&
+           intel_gmbus_is_valid_pin(dev_priv, mapping->i2c_pin))
+               pin = mapping->i2c_pin;
+       else
+               pin = GMBUS_PIN_DPB;
+
+       sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
+
+       /*
+        * With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow
+        * our code totally fails once we start using gmbus. Hence fall back to
+        * bit banging for now.
+        */
+       intel_gmbus_force_bit(sdvo->i2c, true);
+}
+
+/* undo any changes intel_sdvo_select_i2c_bus() did to sdvo->i2c */
+static void
+intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo)
+{
+       intel_gmbus_force_bit(sdvo->i2c, false);
+}
+
+static bool
+intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
+{
+       return intel_sdvo_check_supp_encode(intel_sdvo);
+}
+
+static u8
+intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv,
+                         struct intel_sdvo *sdvo)
+{
+       struct sdvo_device_mapping *my_mapping, *other_mapping;
+
+       if (sdvo->port == PORT_B) {
+               my_mapping = &dev_priv->vbt.sdvo_mappings[0];
+               other_mapping = &dev_priv->vbt.sdvo_mappings[1];
+       } else {
+               my_mapping = &dev_priv->vbt.sdvo_mappings[1];
+               other_mapping = &dev_priv->vbt.sdvo_mappings[0];
+       }
+
+       /* If the BIOS described our SDVO device, take advantage of it. */
+       if (my_mapping->slave_addr)
+               return my_mapping->slave_addr;
+
+       /*
+        * If the BIOS only described a different SDVO device, use the
+        * address that it isn't using.
+        */
+       if (other_mapping->slave_addr) {
+               if (other_mapping->slave_addr == 0x70)
+                       return 0x72;
+               else
+                       return 0x70;
+       }
+
+       /*
+        * No SDVO device info is found for another DVO port,
+        * so use mapping assumption we had before BIOS parsing.
+        */
+       if (sdvo->port == PORT_B)
+               return 0x70;
+       else
+               return 0x72;
+}
+
+static int
+intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
+                         struct intel_sdvo *encoder)
+{
+       struct drm_connector *drm_connector;
+       int ret;
+
+       drm_connector = &connector->base.base;
+       ret = drm_connector_init(encoder->base.base.dev,
+                          drm_connector,
+                          &intel_sdvo_connector_funcs,
+                          connector->base.base.connector_type);
+       if (ret < 0)
+               return ret;
+
+       drm_connector_helper_add(drm_connector,
+                                &intel_sdvo_connector_helper_funcs);
+
+       connector->base.base.interlace_allowed = 1;
+       connector->base.base.doublescan_allowed = 0;
+       connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
+
+       intel_connector_attach_encoder(&connector->base, &encoder->base);
+
+       return 0;
+}
+
+static void
+intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
+                              struct intel_sdvo_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.base.dev);
+
+       intel_attach_force_audio_property(&connector->base.base);
+       if (INTEL_GEN(dev_priv) >= 4 && IS_MOBILE(dev_priv)) {
+               intel_attach_broadcast_rgb_property(&connector->base.base);
+       }
+       intel_attach_aspect_ratio_property(&connector->base.base);
+       connector->base.base.state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
+}
+
+static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
+{
+       struct intel_sdvo_connector *sdvo_connector;
+       struct intel_sdvo_connector_state *conn_state;
+
+       sdvo_connector = kzalloc(sizeof(*sdvo_connector), GFP_KERNEL);
+       if (!sdvo_connector)
+               return NULL;
+
+       conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
+       if (!conn_state) {
+               kfree(sdvo_connector);
+               return NULL;
+       }
+
+       __drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
+                                           &conn_state->base.base);
+
+       return sdvo_connector;
+}
+
+static bool
+intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
+{
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
+
+       DRM_DEBUG_KMS("initialising DVI device %d\n", device);
+
+       intel_sdvo_connector = intel_sdvo_connector_alloc();
+       if (!intel_sdvo_connector)
+               return false;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
+       }
+
+       intel_connector = &intel_sdvo_connector->base;
+       connector = &intel_connector->base;
+       if (intel_sdvo_get_hotplug_support(intel_sdvo) &
+               intel_sdvo_connector->output_flag) {
+               intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
+               /*
+                * Some SDVO devices have one-shot hotplug interrupts.
+                * Ensure that they get re-enabled when an interrupt happens.
+                */
+               intel_encoder->hotplug = intel_sdvo_hotplug;
+               intel_sdvo_enable_hotplug(intel_encoder);
+       } else {
+               intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+       }
+       encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
+       connector->connector_type = DRM_MODE_CONNECTOR_DVID;
+
+       if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
+               connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+               intel_sdvo_connector->is_hdmi = true;
+       }
+
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
+       if (intel_sdvo_connector->is_hdmi)
+               intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
+
+       return true;
+}
+
+static bool
+intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
+{
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
+
+       DRM_DEBUG_KMS("initialising TV type %d\n", type);
+
+       intel_sdvo_connector = intel_sdvo_connector_alloc();
+       if (!intel_sdvo_connector)
+               return false;
+
+       intel_connector = &intel_sdvo_connector->base;
+       connector = &intel_connector->base;
+       encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+       connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+
+       intel_sdvo->controlled_output |= type;
+       intel_sdvo_connector->output_flag = type;
+
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
+       if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
+               goto err;
+
+       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+               goto err;
+
+       return true;
+
+err:
+       intel_connector_destroy(connector);
+       return false;
+}
+
+static bool
+intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
+{
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
+
+       DRM_DEBUG_KMS("initialising analog device %d\n", device);
+
+       intel_sdvo_connector = intel_sdvo_connector_alloc();
+       if (!intel_sdvo_connector)
+               return false;
+
+       intel_connector = &intel_sdvo_connector->base;
+       connector = &intel_connector->base;
+       intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+       encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+       connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+       }
+
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
+       return true;
+}
+
+static bool
+intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
+{
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_display_mode *mode;
+
+       DRM_DEBUG_KMS("initialising LVDS device %d\n", device);
+
+       intel_sdvo_connector = intel_sdvo_connector_alloc();
+       if (!intel_sdvo_connector)
+               return false;
+
+       intel_connector = &intel_sdvo_connector->base;
+       connector = &intel_connector->base;
+       encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+       connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+       }
+
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
+       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+               goto err;
+
+       intel_sdvo_get_lvds_modes(connector);
+
+       list_for_each_entry(mode, &connector->probed_modes, head) {
+               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+                       struct drm_display_mode *fixed_mode =
+                               drm_mode_duplicate(connector->dev, mode);
+
+                       intel_panel_init(&intel_connector->panel,
+                                        fixed_mode, NULL);
+                       break;
+               }
+       }
+
+       if (!intel_connector->panel.fixed_mode)
+               goto err;
+
+       return true;
+
+err:
+       intel_connector_destroy(connector);
+       return false;
+}
+
+static bool
+intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags)
+{
+       /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
+
+       if (flags & SDVO_OUTPUT_TMDS0)
+               if (!intel_sdvo_dvi_init(intel_sdvo, 0))
+                       return false;
+
+       if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)
+               if (!intel_sdvo_dvi_init(intel_sdvo, 1))
+                       return false;
+
+       /* TV has no XXX1 function block */
+       if (flags & SDVO_OUTPUT_SVID0)
+               if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0))
+                       return false;
+
+       if (flags & SDVO_OUTPUT_CVBS0)
+               if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0))
+                       return false;
+
+       if (flags & SDVO_OUTPUT_YPRPB0)
+               if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0))
+                       return false;
+
+       if (flags & SDVO_OUTPUT_RGB0)
+               if (!intel_sdvo_analog_init(intel_sdvo, 0))
+                       return false;
+
+       if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)
+               if (!intel_sdvo_analog_init(intel_sdvo, 1))
+                       return false;
+
+       if (flags & SDVO_OUTPUT_LVDS0)
+               if (!intel_sdvo_lvds_init(intel_sdvo, 0))
+                       return false;
+
+       if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)
+               if (!intel_sdvo_lvds_init(intel_sdvo, 1))
+                       return false;
+
+       if ((flags & SDVO_OUTPUT_MASK) == 0) {
+               unsigned char bytes[2];
+
+               intel_sdvo->controlled_output = 0;
+               memcpy(bytes, &intel_sdvo->caps.output_flags, 2);
+               DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
+                             SDVO_NAME(intel_sdvo),
+                             bytes[0], bytes[1]);
+               return false;
+       }
+       intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+
+       return true;
+}
+
+static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
+{
+       struct drm_device *dev = intel_sdvo->base.base.dev;
+       struct drm_connector *connector, *tmp;
+
+       list_for_each_entry_safe(connector, tmp,
+                                &dev->mode_config.connector_list, head) {
+               if (intel_attached_encoder(connector) == &intel_sdvo->base) {
+                       drm_connector_unregister(connector);
+                       intel_connector_destroy(connector);
+               }
+       }
+}
+
+static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
+                                         struct intel_sdvo_connector *intel_sdvo_connector,
+                                         int type)
+{
+       struct drm_device *dev = intel_sdvo->base.base.dev;
+       struct intel_sdvo_tv_format format;
+       u32 format_map, i;
+
+       if (!intel_sdvo_set_target_output(intel_sdvo, type))
+               return false;
+
+       BUILD_BUG_ON(sizeof(format) != 6);
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
+                                 &format, sizeof(format)))
+               return false;
+
+       memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format)));
+
+       if (format_map == 0)
+               return false;
+
+       intel_sdvo_connector->format_supported_num = 0;
+       for (i = 0 ; i < TV_FORMAT_NUM; i++)
+               if (format_map & (1 << i))
+                       intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i;
+
+
+       intel_sdvo_connector->tv_format =
+                       drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                           "mode", intel_sdvo_connector->format_supported_num);
+       if (!intel_sdvo_connector->tv_format)
+               return false;
+
+       for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
+               drm_property_add_enum(intel_sdvo_connector->tv_format, i,
+                                     tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);
+
+       intel_sdvo_connector->base.base.state->tv.mode = intel_sdvo_connector->tv_format_supported[0];
+       drm_object_attach_property(&intel_sdvo_connector->base.base.base,
+                                  intel_sdvo_connector->tv_format, 0);
+       return true;
+
+}
+
+#define _ENHANCEMENT(state_assignment, name, NAME) do { \
+       if (enhancements.name) { \
+               if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \
+                   !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \
+                       return false; \
+               intel_sdvo_connector->name = \
+                       drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
+               if (!intel_sdvo_connector->name) return false; \
+               state_assignment = response; \
+               drm_object_attach_property(&connector->base, \
+                                          intel_sdvo_connector->name, 0); \
+               DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \
+                             data_value[0], data_value[1], response); \
+       } \
+} while (0)
+
+#define ENHANCEMENT(state, name, NAME) _ENHANCEMENT((state)->name, name, NAME)
+
+static bool
+intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
+                                     struct intel_sdvo_connector *intel_sdvo_connector,
+                                     struct intel_sdvo_enhancements_reply enhancements)
+{
+       struct drm_device *dev = intel_sdvo->base.base.dev;
+       struct drm_connector *connector = &intel_sdvo_connector->base.base;
+       struct drm_connector_state *conn_state = connector->state;
+       struct intel_sdvo_connector_state *sdvo_state =
+               to_intel_sdvo_connector_state(conn_state);
+       u16 response, data_value[2];
+
+       /* when horizontal overscan is supported, Add the left/right property */
+       if (enhancements.overscan_h) {
+               if (!intel_sdvo_get_value(intel_sdvo,
+                                         SDVO_CMD_GET_MAX_OVERSCAN_H,
+                                         &data_value, 4))
+                       return false;
+
+               if (!intel_sdvo_get_value(intel_sdvo,
+                                         SDVO_CMD_GET_OVERSCAN_H,
+                                         &response, 2))
+                       return false;
+
+               sdvo_state->tv.overscan_h = response;
+
+               intel_sdvo_connector->max_hscan = data_value[0];
+               intel_sdvo_connector->left =
+                       drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
+               if (!intel_sdvo_connector->left)
+                       return false;
+
+               drm_object_attach_property(&connector->base,
+                                          intel_sdvo_connector->left, 0);
+
+               intel_sdvo_connector->right =
+                       drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
+               if (!intel_sdvo_connector->right)
+                       return false;
+
+               drm_object_attach_property(&connector->base,
+                                             intel_sdvo_connector->right, 0);
+               DRM_DEBUG_KMS("h_overscan: max %d, "
+                             "default %d, current %d\n",
+                             data_value[0], data_value[1], response);
+       }
+
+       if (enhancements.overscan_v) {
+               if (!intel_sdvo_get_value(intel_sdvo,
+                                         SDVO_CMD_GET_MAX_OVERSCAN_V,
+                                         &data_value, 4))
+                       return false;
+
+               if (!intel_sdvo_get_value(intel_sdvo,
+                                         SDVO_CMD_GET_OVERSCAN_V,
+                                         &response, 2))
+                       return false;
+
+               sdvo_state->tv.overscan_v = response;
+
+               intel_sdvo_connector->max_vscan = data_value[0];
+               intel_sdvo_connector->top =
+                       drm_property_create_range(dev, 0,
+                                           "top_margin", 0, data_value[0]);
+               if (!intel_sdvo_connector->top)
+                       return false;
+
+               drm_object_attach_property(&connector->base,
+                                          intel_sdvo_connector->top, 0);
+
+               intel_sdvo_connector->bottom =
+                       drm_property_create_range(dev, 0,
+                                           "bottom_margin", 0, data_value[0]);
+               if (!intel_sdvo_connector->bottom)
+                       return false;
+
+               drm_object_attach_property(&connector->base,
+                                             intel_sdvo_connector->bottom, 0);
+               DRM_DEBUG_KMS("v_overscan: max %d, "
+                             "default %d, current %d\n",
+                             data_value[0], data_value[1], response);
+       }
+
+       ENHANCEMENT(&sdvo_state->tv, hpos, HPOS);
+       ENHANCEMENT(&sdvo_state->tv, vpos, VPOS);
+       ENHANCEMENT(&conn_state->tv, saturation, SATURATION);
+       ENHANCEMENT(&conn_state->tv, contrast, CONTRAST);
+       ENHANCEMENT(&conn_state->tv, hue, HUE);
+       ENHANCEMENT(&conn_state->tv, brightness, BRIGHTNESS);
+       ENHANCEMENT(&sdvo_state->tv, sharpness, SHARPNESS);
+       ENHANCEMENT(&sdvo_state->tv, flicker_filter, FLICKER_FILTER);
+       ENHANCEMENT(&sdvo_state->tv, flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
+       ENHANCEMENT(&sdvo_state->tv, flicker_filter_2d, FLICKER_FILTER_2D);
+       _ENHANCEMENT(sdvo_state->tv.chroma_filter, tv_chroma_filter, TV_CHROMA_FILTER);
+       _ENHANCEMENT(sdvo_state->tv.luma_filter, tv_luma_filter, TV_LUMA_FILTER);
+
+       if (enhancements.dot_crawl) {
+               if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2))
+                       return false;
+
+               sdvo_state->tv.dot_crawl = response & 0x1;
+               intel_sdvo_connector->dot_crawl =
+                       drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
+               if (!intel_sdvo_connector->dot_crawl)
+                       return false;
+
+               drm_object_attach_property(&connector->base,
+                                          intel_sdvo_connector->dot_crawl, 0);
+               DRM_DEBUG_KMS("dot crawl: current %d\n", response);
+       }
+
+       return true;
+}
+
+static bool
+intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
+                                       struct intel_sdvo_connector *intel_sdvo_connector,
+                                       struct intel_sdvo_enhancements_reply enhancements)
+{
+       struct drm_device *dev = intel_sdvo->base.base.dev;
+       struct drm_connector *connector = &intel_sdvo_connector->base.base;
+       u16 response, data_value[2];
+
+       ENHANCEMENT(&connector->state->tv, brightness, BRIGHTNESS);
+
+       return true;
+}
+#undef ENHANCEMENT
+#undef _ENHANCEMENT
+
+static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
+                                              struct intel_sdvo_connector *intel_sdvo_connector)
+{
+       union {
+               struct intel_sdvo_enhancements_reply reply;
+               u16 response;
+       } enhancements;
+
+       BUILD_BUG_ON(sizeof(enhancements) != 2);
+
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
+                                 &enhancements, sizeof(enhancements)) ||
+           enhancements.response == 0) {
+               DRM_DEBUG_KMS("No enhancement is supported\n");
+               return true;
+       }
+
+       if (IS_TV(intel_sdvo_connector))
+               return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply);
+       else if (IS_LVDS(intel_sdvo_connector))
+               return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
+       else
+               return true;
+}
+
+static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
+                                    struct i2c_msg *msgs,
+                                    int num)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+
+       if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+               return -EIO;
+
+       return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
+}
+
+static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+       return sdvo->i2c->algo->functionality(sdvo->i2c);
+}
+
+static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
+       .master_xfer    = intel_sdvo_ddc_proxy_xfer,
+       .functionality  = intel_sdvo_ddc_proxy_func
+};
+
+static void proxy_lock_bus(struct i2c_adapter *adapter,
+                          unsigned int flags)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+       sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags);
+}
+
+static int proxy_trylock_bus(struct i2c_adapter *adapter,
+                            unsigned int flags)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+       return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags);
+}
+
+static void proxy_unlock_bus(struct i2c_adapter *adapter,
+                            unsigned int flags)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+       sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags);
+}
+
+static const struct i2c_lock_operations proxy_lock_ops = {
+       .lock_bus =    proxy_lock_bus,
+       .trylock_bus = proxy_trylock_bus,
+       .unlock_bus =  proxy_unlock_bus,
+};
+
+static bool
+intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
+                         struct drm_i915_private *dev_priv)
+{
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+
+       sdvo->ddc.owner = THIS_MODULE;
+       sdvo->ddc.class = I2C_CLASS_DDC;
+       snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
+       sdvo->ddc.dev.parent = &pdev->dev;
+       sdvo->ddc.algo_data = sdvo;
+       sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
+       sdvo->ddc.lock_ops = &proxy_lock_ops;
+
+       return i2c_add_adapter(&sdvo->ddc) == 0;
+}
+
+static void assert_sdvo_port_valid(const struct drm_i915_private *dev_priv,
+                                  enum port port)
+{
+       if (HAS_PCH_SPLIT(dev_priv))
+               WARN_ON(port != PORT_B);
+       else
+               WARN_ON(port != PORT_B && port != PORT_C);
+}
+
+bool intel_sdvo_init(struct drm_i915_private *dev_priv,
+                    i915_reg_t sdvo_reg, enum port port)
+{
+       struct intel_encoder *intel_encoder;
+       struct intel_sdvo *intel_sdvo;
+       int i;
+
+       assert_sdvo_port_valid(dev_priv, port);
+
+       intel_sdvo = kzalloc(sizeof(*intel_sdvo), GFP_KERNEL);
+       if (!intel_sdvo)
+               return false;
+
+       intel_sdvo->sdvo_reg = sdvo_reg;
+       intel_sdvo->port = port;
+       intel_sdvo->slave_addr =
+               intel_sdvo_get_slave_addr(dev_priv, intel_sdvo) >> 1;
+       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo);
+       if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev_priv))
+               goto err_i2c_bus;
+
+       /* encoder type will be decided later */
+       intel_encoder = &intel_sdvo->base;
+       intel_encoder->type = INTEL_OUTPUT_SDVO;
+       intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
+       intel_encoder->port = port;
+       drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
+                        &intel_sdvo_enc_funcs, 0,
+                        "SDVO %c", port_name(port));
+
+       /* Read the regs to test if we can talk to the device */
+       for (i = 0; i < 0x40; i++) {
+               u8 byte;
+
+               if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
+                       DRM_DEBUG_KMS("No SDVO device found on %s\n",
+                                     SDVO_NAME(intel_sdvo));
+                       goto err;
+               }
+       }
+
+       intel_encoder->compute_config = intel_sdvo_compute_config;
+       if (HAS_PCH_SPLIT(dev_priv)) {
+               intel_encoder->disable = pch_disable_sdvo;
+               intel_encoder->post_disable = pch_post_disable_sdvo;
+       } else {
+               intel_encoder->disable = intel_disable_sdvo;
+       }
+       intel_encoder->pre_enable = intel_sdvo_pre_enable;
+       intel_encoder->enable = intel_enable_sdvo;
+       intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
+       intel_encoder->get_config = intel_sdvo_get_config;
+
+       /* In default case sdvo lvds is false */
+       if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
+               goto err;
+
+       if (intel_sdvo_output_setup(intel_sdvo,
+                                   intel_sdvo->caps.output_flags) != true) {
+               DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
+                             SDVO_NAME(intel_sdvo));
+               /* Output_setup can leave behind connectors! */
+               goto err_output;
+       }
+
+       /*
+        * Only enable the hotplug irq if we need it, to work around noisy
+        * hotplug lines.
+        */
+       if (intel_sdvo->hotplug_active) {
+               if (intel_sdvo->port == PORT_B)
+                       intel_encoder->hpd_pin = HPD_SDVO_B;
+               else
+                       intel_encoder->hpd_pin = HPD_SDVO_C;
+       }
+
+       /*
+        * Cloning SDVO with anything is often impossible, since the SDVO
+        * encoder can request a special input timing mode. And even if that's
+        * not the case we have evidence that cloning a plain unscaled mode with
+        * VGA doesn't really work. Furthermore the cloning flags are way too
+        * simplistic anyway to express such constraints, so just give up on
+        * cloning for SDVO encoders.
+        */
+       intel_sdvo->base.cloneable = 0;
+
+       intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo);
+
+       /* Set the input timing to the screen. Assume always input 0. */
+       if (!intel_sdvo_set_target_input(intel_sdvo))
+               goto err_output;
+
+       if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
+                                                   &intel_sdvo->pixel_clock_min,
+                                                   &intel_sdvo->pixel_clock_max))
+               goto err_output;
+
+       DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
+                       "clock range %dMHz - %dMHz, "
+                       "input 1: %c, input 2: %c, "
+                       "output 1: %c, output 2: %c\n",
+                       SDVO_NAME(intel_sdvo),
+                       intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
+                       intel_sdvo->caps.device_rev_id,
+                       intel_sdvo->pixel_clock_min / 1000,
+                       intel_sdvo->pixel_clock_max / 1000,
+                       (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+                       (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+                       /* check currently supported outputs */
+                       intel_sdvo->caps.output_flags &
+                       (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
+                       intel_sdvo->caps.output_flags &
+                       (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
+       return true;
+
+err_output:
+       intel_sdvo_output_cleanup(intel_sdvo);
+
+err:
+       drm_encoder_cleanup(&intel_encoder->base);
+       i2c_del_adapter(&intel_sdvo->ddc);
+err_i2c_bus:
+       intel_sdvo_unselect_i2c_bus(intel_sdvo);
+       kfree(intel_sdvo);
+
+       return false;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.h b/drivers/gpu/drm/i915/display/intel_sdvo.h
new file mode 100644 (file)
index 0000000..c9e05bc
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_SDVO_H__
+#define __INTEL_SDVO_H__
+
+#include <linux/types.h>
+
+#include <drm/i915_drm.h>
+
+#include "i915_reg.h"
+
+struct drm_i915_private;
+enum pipe;
+
+bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv,
+                            i915_reg_t sdvo_reg, enum pipe *pipe);
+bool intel_sdvo_init(struct drm_i915_private *dev_priv,
+                    i915_reg_t reg, enum port port);
+
+#endif /* __INTEL_SDVO_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo_regs.h b/drivers/gpu/drm/i915/display/intel_sdvo_regs.h
new file mode 100644 (file)
index 0000000..13b9a8e
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#ifndef __INTEL_SDVO_REGS_H__
+#define __INTEL_SDVO_REGS_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+/*
+ * SDVO command definitions and structures.
+ */
+
+#define SDVO_OUTPUT_FIRST   (0)
+#define SDVO_OUTPUT_TMDS0   (1 << 0)
+#define SDVO_OUTPUT_RGB0    (1 << 1)
+#define SDVO_OUTPUT_CVBS0   (1 << 2)
+#define SDVO_OUTPUT_SVID0   (1 << 3)
+#define SDVO_OUTPUT_YPRPB0  (1 << 4)
+#define SDVO_OUTPUT_SCART0  (1 << 5)
+#define SDVO_OUTPUT_LVDS0   (1 << 6)
+#define SDVO_OUTPUT_TMDS1   (1 << 8)
+#define SDVO_OUTPUT_RGB1    (1 << 9)
+#define SDVO_OUTPUT_CVBS1   (1 << 10)
+#define SDVO_OUTPUT_SVID1   (1 << 11)
+#define SDVO_OUTPUT_YPRPB1  (1 << 12)
+#define SDVO_OUTPUT_SCART1  (1 << 13)
+#define SDVO_OUTPUT_LVDS1   (1 << 14)
+#define SDVO_OUTPUT_LAST    (14)
+
+struct intel_sdvo_caps {
+       u8 vendor_id;
+       u8 device_id;
+       u8 device_rev_id;
+       u8 sdvo_version_major;
+       u8 sdvo_version_minor;
+       unsigned int sdvo_inputs_mask:2;
+       unsigned int smooth_scaling:1;
+       unsigned int sharp_scaling:1;
+       unsigned int up_scaling:1;
+       unsigned int down_scaling:1;
+       unsigned int stall_support:1;
+       unsigned int pad:1;
+       u16 output_flags;
+} __packed;
+
+/* Note: SDVO detailed timing flags match EDID misc flags. */
+#define DTD_FLAG_HSYNC_POSITIVE (1 << 1)
+#define DTD_FLAG_VSYNC_POSITIVE (1 << 2)
+#define DTD_FLAG_INTERLACE     (1 << 7)
+
+/* This matches the EDID DTD structure, more or less */
+struct intel_sdvo_dtd {
+       struct {
+               u16 clock;      /* pixel clock, in 10kHz units */
+               u8 h_active;    /* lower 8 bits (pixels) */
+               u8 h_blank;     /* lower 8 bits (pixels) */
+               u8 h_high;      /* upper 4 bits each h_active, h_blank */
+               u8 v_active;    /* lower 8 bits (lines) */
+               u8 v_blank;     /* lower 8 bits (lines) */
+               u8 v_high;      /* upper 4 bits each v_active, v_blank */
+       } part1;
+
+       struct {
+               u8 h_sync_off;  /* lower 8 bits, from hblank start */
+               u8 h_sync_width;        /* lower 8 bits (pixels) */
+               /* lower 4 bits each vsync offset, vsync width */
+               u8 v_sync_off_width;
+               /*
+               * 2 high bits of hsync offset, 2 high bits of hsync width,
+               * bits 4-5 of vsync offset, and 2 high bits of vsync width.
+               */
+               u8 sync_off_width_high;
+               u8 dtd_flags;
+               u8 sdvo_flags;
+               /* bits 6-7 of vsync offset at bits 6-7 */
+               u8 v_sync_off_high;
+               u8 reserved;
+       } part2;
+} __packed;
+
+struct intel_sdvo_pixel_clock_range {
+       u16 min;        /* pixel clock, in 10kHz units */
+       u16 max;        /* pixel clock, in 10kHz units */
+} __packed;
+
+struct intel_sdvo_preferred_input_timing_args {
+       u16 clock;
+       u16 width;
+       u16 height;
+       u8      interlace:1;
+       u8      scaled:1;
+       u8      pad:6;
+} __packed;
+
+/* I2C registers for SDVO */
+#define SDVO_I2C_ARG_0                         0x07
+#define SDVO_I2C_ARG_1                         0x06
+#define SDVO_I2C_ARG_2                         0x05
+#define SDVO_I2C_ARG_3                         0x04
+#define SDVO_I2C_ARG_4                         0x03
+#define SDVO_I2C_ARG_5                         0x02
+#define SDVO_I2C_ARG_6                         0x01
+#define SDVO_I2C_ARG_7                         0x00
+#define SDVO_I2C_OPCODE                                0x08
+#define SDVO_I2C_CMD_STATUS                    0x09
+#define SDVO_I2C_RETURN_0                      0x0a
+#define SDVO_I2C_RETURN_1                      0x0b
+#define SDVO_I2C_RETURN_2                      0x0c
+#define SDVO_I2C_RETURN_3                      0x0d
+#define SDVO_I2C_RETURN_4                      0x0e
+#define SDVO_I2C_RETURN_5                      0x0f
+#define SDVO_I2C_RETURN_6                      0x10
+#define SDVO_I2C_RETURN_7                      0x11
+#define SDVO_I2C_VENDOR_BEGIN                  0x20
+
+/* Status results */
+#define SDVO_CMD_STATUS_POWER_ON               0x0
+#define SDVO_CMD_STATUS_SUCCESS                        0x1
+#define SDVO_CMD_STATUS_NOTSUPP                        0x2
+#define SDVO_CMD_STATUS_INVALID_ARG            0x3
+#define SDVO_CMD_STATUS_PENDING                        0x4
+#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED   0x5
+#define SDVO_CMD_STATUS_SCALING_NOT_SUPP       0x6
+
+/* SDVO commands, argument/result registers */
+
+#define SDVO_CMD_RESET                                 0x01
+
+/* Returns a struct intel_sdvo_caps */
+#define SDVO_CMD_GET_DEVICE_CAPS                       0x02
+
+#define SDVO_CMD_GET_FIRMWARE_REV                      0x86
+# define SDVO_DEVICE_FIRMWARE_MINOR                    SDVO_I2C_RETURN_0
+# define SDVO_DEVICE_FIRMWARE_MAJOR                    SDVO_I2C_RETURN_1
+# define SDVO_DEVICE_FIRMWARE_PATCH                    SDVO_I2C_RETURN_2
+
+/*
+ * Reports which inputs are trained (managed to sync).
+ *
+ * Devices must have trained within 2 vsyncs of a mode change.
+ */
+#define SDVO_CMD_GET_TRAINED_INPUTS                    0x03
+struct intel_sdvo_get_trained_inputs_response {
+       unsigned int input0_trained:1;
+       unsigned int input1_trained:1;
+       unsigned int pad:6;
+} __packed;
+
+/* Returns a struct intel_sdvo_output_flags of active outputs. */
+#define SDVO_CMD_GET_ACTIVE_OUTPUTS                    0x04
+
+/*
+ * Sets the current set of active outputs.
+ *
+ * Takes a struct intel_sdvo_output_flags.  Must be preceded by a SET_IN_OUT_MAP
+ * on multi-output devices.
+ */
+#define SDVO_CMD_SET_ACTIVE_OUTPUTS                    0x05
+
+/*
+ * Returns the current mapping of SDVO inputs to outputs on the device.
+ *
+ * Returns two struct intel_sdvo_output_flags structures.
+ */
+#define SDVO_CMD_GET_IN_OUT_MAP                                0x06
+struct intel_sdvo_in_out_map {
+       u16 in0, in1;
+};
+
+/*
+ * Sets the current mapping of SDVO inputs to outputs on the device.
+ *
+ * Takes two struct i380_sdvo_output_flags structures.
+ */
+#define SDVO_CMD_SET_IN_OUT_MAP                                0x07
+
+/*
+ * Returns a struct intel_sdvo_output_flags of attached displays.
+ */
+#define SDVO_CMD_GET_ATTACHED_DISPLAYS                 0x0b
+
+/*
+ * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging.
+ */
+#define SDVO_CMD_GET_HOT_PLUG_SUPPORT                  0x0c
+
+/*
+ * Takes a struct intel_sdvo_output_flags.
+ */
+#define SDVO_CMD_SET_ACTIVE_HOT_PLUG                   0x0d
+
+/*
+ * Returns a struct intel_sdvo_output_flags of displays with hot plug
+ * interrupts enabled.
+ */
+#define SDVO_CMD_GET_ACTIVE_HOT_PLUG                   0x0e
+
+#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE            0x0f
+struct intel_sdvo_get_interrupt_event_source_response {
+       u16 interrupt_status;
+       unsigned int ambient_light_interrupt:1;
+       unsigned int hdmi_audio_encrypt_change:1;
+       unsigned int pad:6;
+} __packed;
+
+/*
+ * Selects which input is affected by future input commands.
+ *
+ * Commands affected include SET_INPUT_TIMINGS_PART[12],
+ * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12],
+ * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS.
+ */
+#define SDVO_CMD_SET_TARGET_INPUT                      0x10
+struct intel_sdvo_set_target_input_args {
+       unsigned int target_1:1;
+       unsigned int pad:7;
+} __packed;
+
+/*
+ * Takes a struct intel_sdvo_output_flags of which outputs are targeted by
+ * future output commands.
+ *
+ * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12],
+ * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE.
+ */
+#define SDVO_CMD_SET_TARGET_OUTPUT                     0x11
+
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART1               0x12
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART2               0x13
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART1               0x14
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART2               0x15
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1              0x16
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2              0x17
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1              0x18
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2              0x19
+/* Part 1 */
+# define SDVO_DTD_CLOCK_LOW                            SDVO_I2C_ARG_0
+# define SDVO_DTD_CLOCK_HIGH                           SDVO_I2C_ARG_1
+# define SDVO_DTD_H_ACTIVE                             SDVO_I2C_ARG_2
+# define SDVO_DTD_H_BLANK                              SDVO_I2C_ARG_3
+# define SDVO_DTD_H_HIGH                               SDVO_I2C_ARG_4
+# define SDVO_DTD_V_ACTIVE                             SDVO_I2C_ARG_5
+# define SDVO_DTD_V_BLANK                              SDVO_I2C_ARG_6
+# define SDVO_DTD_V_HIGH                               SDVO_I2C_ARG_7
+/* Part 2 */
+# define SDVO_DTD_HSYNC_OFF                            SDVO_I2C_ARG_0
+# define SDVO_DTD_HSYNC_WIDTH                          SDVO_I2C_ARG_1
+# define SDVO_DTD_VSYNC_OFF_WIDTH                      SDVO_I2C_ARG_2
+# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH                  SDVO_I2C_ARG_3
+# define SDVO_DTD_DTD_FLAGS                            SDVO_I2C_ARG_4
+# define SDVO_DTD_DTD_FLAG_INTERLACED                          (1 << 7)
+# define SDVO_DTD_DTD_FLAG_STEREO_MASK                         (3 << 5)
+# define SDVO_DTD_DTD_FLAG_INPUT_MASK                          (3 << 3)
+# define SDVO_DTD_DTD_FLAG_SYNC_MASK                           (3 << 1)
+# define SDVO_DTD_SDVO_FLAS                            SDVO_I2C_ARG_5
+# define SDVO_DTD_SDVO_FLAG_STALL                              (1 << 7)
+# define SDVO_DTD_SDVO_FLAG_CENTERED                           (0 << 6)
+# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT                         (1 << 6)
+# define SDVO_DTD_SDVO_FLAG_SCALING_MASK                       (3 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_NONE                       (0 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP                      (1 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH                     (2 << 4)
+# define SDVO_DTD_VSYNC_OFF_HIGH                       SDVO_I2C_ARG_6
+
+/*
+ * Generates a DTD based on the given width, height, and flags.
+ *
+ * This will be supported by any device supporting scaling or interlaced
+ * modes.
+ */
+#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING         0x1a
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW         SDVO_I2C_ARG_0
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH                SDVO_I2C_ARG_1
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW         SDVO_I2C_ARG_2
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH                SDVO_I2C_ARG_3
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW                SDVO_I2C_ARG_4
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH       SDVO_I2C_ARG_5
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS             SDVO_I2C_ARG_6
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED          (1 << 0)
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED              (1 << 1)
+
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1      0x1b
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2      0x1c
+
+/* Returns a struct intel_sdvo_pixel_clock_range */
+#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE           0x1d
+/* Returns a struct intel_sdvo_pixel_clock_range */
+#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE          0x1e
+
+/* Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */
+#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS                0x1f
+
+/* Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
+#define SDVO_CMD_GET_CLOCK_RATE_MULT                   0x20
+/* Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
+#define SDVO_CMD_SET_CLOCK_RATE_MULT                   0x21
+# define SDVO_CLOCK_RATE_MULT_1X                               (1 << 0)
+# define SDVO_CLOCK_RATE_MULT_2X                               (1 << 1)
+# define SDVO_CLOCK_RATE_MULT_4X                               (1 << 3)
+
+#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS              0x27
+/* 6 bytes of bit flags for TV formats shared by all TV format functions */
+struct intel_sdvo_tv_format {
+       unsigned int ntsc_m:1;
+       unsigned int ntsc_j:1;
+       unsigned int ntsc_443:1;
+       unsigned int pal_b:1;
+       unsigned int pal_d:1;
+       unsigned int pal_g:1;
+       unsigned int pal_h:1;
+       unsigned int pal_i:1;
+
+       unsigned int pal_m:1;
+       unsigned int pal_n:1;
+       unsigned int pal_nc:1;
+       unsigned int pal_60:1;
+       unsigned int secam_b:1;
+       unsigned int secam_d:1;
+       unsigned int secam_g:1;
+       unsigned int secam_k:1;
+
+       unsigned int secam_k1:1;
+       unsigned int secam_l:1;
+       unsigned int secam_60:1;
+       unsigned int hdtv_std_smpte_240m_1080i_59:1;
+       unsigned int hdtv_std_smpte_240m_1080i_60:1;
+       unsigned int hdtv_std_smpte_260m_1080i_59:1;
+       unsigned int hdtv_std_smpte_260m_1080i_60:1;
+       unsigned int hdtv_std_smpte_274m_1080i_50:1;
+
+       unsigned int hdtv_std_smpte_274m_1080i_59:1;
+       unsigned int hdtv_std_smpte_274m_1080i_60:1;
+       unsigned int hdtv_std_smpte_274m_1080p_23:1;
+       unsigned int hdtv_std_smpte_274m_1080p_24:1;
+       unsigned int hdtv_std_smpte_274m_1080p_25:1;
+       unsigned int hdtv_std_smpte_274m_1080p_29:1;
+       unsigned int hdtv_std_smpte_274m_1080p_30:1;
+       unsigned int hdtv_std_smpte_274m_1080p_50:1;
+
+       unsigned int hdtv_std_smpte_274m_1080p_59:1;
+       unsigned int hdtv_std_smpte_274m_1080p_60:1;
+       unsigned int hdtv_std_smpte_295m_1080i_50:1;
+       unsigned int hdtv_std_smpte_295m_1080p_50:1;
+       unsigned int hdtv_std_smpte_296m_720p_59:1;
+       unsigned int hdtv_std_smpte_296m_720p_60:1;
+       unsigned int hdtv_std_smpte_296m_720p_50:1;
+       unsigned int hdtv_std_smpte_293m_480p_59:1;
+
+       unsigned int hdtv_std_smpte_170m_480i_59:1;
+       unsigned int hdtv_std_iturbt601_576i_50:1;
+       unsigned int hdtv_std_iturbt601_576p_50:1;
+       unsigned int hdtv_std_eia_7702a_480i_60:1;
+       unsigned int hdtv_std_eia_7702a_480p_60:1;
+       unsigned int pad:3;
+} __packed;
+
+#define SDVO_CMD_GET_TV_FORMAT                         0x28
+
+#define SDVO_CMD_SET_TV_FORMAT                         0x29
+
+/* Returns the resolutiosn that can be used with the given TV format */
+#define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT           0x83
+struct intel_sdvo_sdtv_resolution_request {
+       unsigned int ntsc_m:1;
+       unsigned int ntsc_j:1;
+       unsigned int ntsc_443:1;
+       unsigned int pal_b:1;
+       unsigned int pal_d:1;
+       unsigned int pal_g:1;
+       unsigned int pal_h:1;
+       unsigned int pal_i:1;
+
+       unsigned int pal_m:1;
+       unsigned int pal_n:1;
+       unsigned int pal_nc:1;
+       unsigned int pal_60:1;
+       unsigned int secam_b:1;
+       unsigned int secam_d:1;
+       unsigned int secam_g:1;
+       unsigned int secam_k:1;
+
+       unsigned int secam_k1:1;
+       unsigned int secam_l:1;
+       unsigned int secam_60:1;
+       unsigned int pad:5;
+} __packed;
+
+struct intel_sdvo_sdtv_resolution_reply {
+       unsigned int res_320x200:1;
+       unsigned int res_320x240:1;
+       unsigned int res_400x300:1;
+       unsigned int res_640x350:1;
+       unsigned int res_640x400:1;
+       unsigned int res_640x480:1;
+       unsigned int res_704x480:1;
+       unsigned int res_704x576:1;
+
+       unsigned int res_720x350:1;
+       unsigned int res_720x400:1;
+       unsigned int res_720x480:1;
+       unsigned int res_720x540:1;
+       unsigned int res_720x576:1;
+       unsigned int res_768x576:1;
+       unsigned int res_800x600:1;
+       unsigned int res_832x624:1;
+
+       unsigned int res_920x766:1;
+       unsigned int res_1024x768:1;
+       unsigned int res_1280x1024:1;
+       unsigned int pad:5;
+} __packed;
+
+/* Get supported resolution with squire pixel aspect ratio that can be
+   scaled for the requested HDTV format */
+#define SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT            0x85
+
+struct intel_sdvo_hdtv_resolution_request {
+       unsigned int hdtv_std_smpte_240m_1080i_59:1;
+       unsigned int hdtv_std_smpte_240m_1080i_60:1;
+       unsigned int hdtv_std_smpte_260m_1080i_59:1;
+       unsigned int hdtv_std_smpte_260m_1080i_60:1;
+       unsigned int hdtv_std_smpte_274m_1080i_50:1;
+       unsigned int hdtv_std_smpte_274m_1080i_59:1;
+       unsigned int hdtv_std_smpte_274m_1080i_60:1;
+       unsigned int hdtv_std_smpte_274m_1080p_23:1;
+
+       unsigned int hdtv_std_smpte_274m_1080p_24:1;
+       unsigned int hdtv_std_smpte_274m_1080p_25:1;
+       unsigned int hdtv_std_smpte_274m_1080p_29:1;
+       unsigned int hdtv_std_smpte_274m_1080p_30:1;
+       unsigned int hdtv_std_smpte_274m_1080p_50:1;
+       unsigned int hdtv_std_smpte_274m_1080p_59:1;
+       unsigned int hdtv_std_smpte_274m_1080p_60:1;
+       unsigned int hdtv_std_smpte_295m_1080i_50:1;
+
+       unsigned int hdtv_std_smpte_295m_1080p_50:1;
+       unsigned int hdtv_std_smpte_296m_720p_59:1;
+       unsigned int hdtv_std_smpte_296m_720p_60:1;
+       unsigned int hdtv_std_smpte_296m_720p_50:1;
+       unsigned int hdtv_std_smpte_293m_480p_59:1;
+       unsigned int hdtv_std_smpte_170m_480i_59:1;
+       unsigned int hdtv_std_iturbt601_576i_50:1;
+       unsigned int hdtv_std_iturbt601_576p_50:1;
+
+       unsigned int hdtv_std_eia_7702a_480i_60:1;
+       unsigned int hdtv_std_eia_7702a_480p_60:1;
+       unsigned int pad:6;
+} __packed;
+
+struct intel_sdvo_hdtv_resolution_reply {
+       unsigned int res_640x480:1;
+       unsigned int res_800x600:1;
+       unsigned int res_1024x768:1;
+       unsigned int res_1280x960:1;
+       unsigned int res_1400x1050:1;
+       unsigned int res_1600x1200:1;
+       unsigned int res_1920x1440:1;
+       unsigned int res_2048x1536:1;
+
+       unsigned int res_2560x1920:1;
+       unsigned int res_3200x2400:1;
+       unsigned int res_3840x2880:1;
+       unsigned int pad1:5;
+
+       unsigned int res_848x480:1;
+       unsigned int res_1064x600:1;
+       unsigned int res_1280x720:1;
+       unsigned int res_1360x768:1;
+       unsigned int res_1704x960:1;
+       unsigned int res_1864x1050:1;
+       unsigned int res_1920x1080:1;
+       unsigned int res_2128x1200:1;
+
+       unsigned int res_2560x1400:1;
+       unsigned int res_2728x1536:1;
+       unsigned int res_3408x1920:1;
+       unsigned int res_4264x2400:1;
+       unsigned int res_5120x2880:1;
+       unsigned int pad2:3;
+
+       unsigned int res_768x480:1;
+       unsigned int res_960x600:1;
+       unsigned int res_1152x720:1;
+       unsigned int res_1124x768:1;
+       unsigned int res_1536x960:1;
+       unsigned int res_1680x1050:1;
+       unsigned int res_1728x1080:1;
+       unsigned int res_1920x1200:1;
+
+       unsigned int res_2304x1440:1;
+       unsigned int res_2456x1536:1;
+       unsigned int res_3072x1920:1;
+       unsigned int res_3840x2400:1;
+       unsigned int res_4608x2880:1;
+       unsigned int pad3:3;
+
+       unsigned int res_1280x1024:1;
+       unsigned int pad4:7;
+
+       unsigned int res_1280x768:1;
+       unsigned int pad5:7;
+} __packed;
+
+/* Get supported power state returns info for encoder and monitor, rely on
+   last SetTargetInput and SetTargetOutput calls */
+#define SDVO_CMD_GET_SUPPORTED_POWER_STATES            0x2a
+/* Get power state returns info for encoder and monitor, rely on last
+   SetTargetInput and SetTargetOutput calls */
+#define SDVO_CMD_GET_POWER_STATE                       0x2b
+#define SDVO_CMD_GET_ENCODER_POWER_STATE               0x2b
+#define SDVO_CMD_SET_ENCODER_POWER_STATE               0x2c
+# define SDVO_ENCODER_STATE_ON                                 (1 << 0)
+# define SDVO_ENCODER_STATE_STANDBY                            (1 << 1)
+# define SDVO_ENCODER_STATE_SUSPEND                            (1 << 2)
+# define SDVO_ENCODER_STATE_OFF                                        (1 << 3)
+# define SDVO_MONITOR_STATE_ON                                 (1 << 4)
+# define SDVO_MONITOR_STATE_STANDBY                            (1 << 5)
+# define SDVO_MONITOR_STATE_SUSPEND                            (1 << 6)
+# define SDVO_MONITOR_STATE_OFF                                        (1 << 7)
+
+#define SDVO_CMD_GET_MAX_PANEL_POWER_SEQUENCING                0x2d
+#define SDVO_CMD_GET_PANEL_POWER_SEQUENCING            0x2e
+#define SDVO_CMD_SET_PANEL_POWER_SEQUENCING            0x2f
+/*
+ * The panel power sequencing parameters are in units of milliseconds.
+ * The high fields are bits 8:9 of the 10-bit values.
+ */
+struct sdvo_panel_power_sequencing {
+       u8 t0;
+       u8 t1;
+       u8 t2;
+       u8 t3;
+       u8 t4;
+
+       unsigned int t0_high:2;
+       unsigned int t1_high:2;
+       unsigned int t2_high:2;
+       unsigned int t3_high:2;
+
+       unsigned int t4_high:2;
+       unsigned int pad:6;
+} __packed;
+
+#define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL               0x30
+struct sdvo_max_backlight_reply {
+       u8 max_value;
+       u8 default_value;
+} __packed;
+
+#define SDVO_CMD_GET_BACKLIGHT_LEVEL                   0x31
+#define SDVO_CMD_SET_BACKLIGHT_LEVEL                   0x32
+
+#define SDVO_CMD_GET_AMBIENT_LIGHT                     0x33
+struct sdvo_get_ambient_light_reply {
+       u16 trip_low;
+       u16 trip_high;
+       u16 value;
+} __packed;
+#define SDVO_CMD_SET_AMBIENT_LIGHT                     0x34
+struct sdvo_set_ambient_light_reply {
+       u16 trip_low;
+       u16 trip_high;
+       unsigned int enable:1;
+       unsigned int pad:7;
+} __packed;
+
+/* Set display power state */
+#define SDVO_CMD_SET_DISPLAY_POWER_STATE               0x7d
+# define SDVO_DISPLAY_STATE_ON                         (1 << 0)
+# define SDVO_DISPLAY_STATE_STANDBY                    (1 << 1)
+# define SDVO_DISPLAY_STATE_SUSPEND                    (1 << 2)
+# define SDVO_DISPLAY_STATE_OFF                                (1 << 3)
+
+#define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS            0x84
+struct intel_sdvo_enhancements_reply {
+       unsigned int flicker_filter:1;
+       unsigned int flicker_filter_adaptive:1;
+       unsigned int flicker_filter_2d:1;
+       unsigned int saturation:1;
+       unsigned int hue:1;
+       unsigned int brightness:1;
+       unsigned int contrast:1;
+       unsigned int overscan_h:1;
+
+       unsigned int overscan_v:1;
+       unsigned int hpos:1;
+       unsigned int vpos:1;
+       unsigned int sharpness:1;
+       unsigned int dot_crawl:1;
+       unsigned int dither:1;
+       unsigned int tv_chroma_filter:1;
+       unsigned int tv_luma_filter:1;
+} __packed;
+
+/* Picture enhancement limits below are dependent on the current TV format,
+ * and thus need to be queried and set after it.
+ */
+#define SDVO_CMD_GET_MAX_FLICKER_FILTER                        0x4d
+#define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE       0x7b
+#define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D             0x52
+#define SDVO_CMD_GET_MAX_SATURATION                    0x55
+#define SDVO_CMD_GET_MAX_HUE                           0x58
+#define SDVO_CMD_GET_MAX_BRIGHTNESS                    0x5b
+#define SDVO_CMD_GET_MAX_CONTRAST                      0x5e
+#define SDVO_CMD_GET_MAX_OVERSCAN_H                    0x61
+#define SDVO_CMD_GET_MAX_OVERSCAN_V                    0x64
+#define SDVO_CMD_GET_MAX_HPOS                          0x67
+#define SDVO_CMD_GET_MAX_VPOS                          0x6a
+#define SDVO_CMD_GET_MAX_SHARPNESS                     0x6d
+#define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER              0x74
+#define SDVO_CMD_GET_MAX_TV_LUMA_FILTER                        0x77
+struct intel_sdvo_enhancement_limits_reply {
+       u16 max_value;
+       u16 default_value;
+} __packed;
+
+#define SDVO_CMD_GET_LVDS_PANEL_INFORMATION            0x7f
+#define SDVO_CMD_SET_LVDS_PANEL_INFORMATION            0x80
+# define SDVO_LVDS_COLOR_DEPTH_18                      (0 << 0)
+# define SDVO_LVDS_COLOR_DEPTH_24                      (1 << 0)
+# define SDVO_LVDS_CONNECTOR_SPWG                      (0 << 2)
+# define SDVO_LVDS_CONNECTOR_OPENLDI                   (1 << 2)
+# define SDVO_LVDS_SINGLE_CHANNEL                      (0 << 4)
+# define SDVO_LVDS_DUAL_CHANNEL                                (1 << 4)
+
+#define SDVO_CMD_GET_FLICKER_FILTER                    0x4e
+#define SDVO_CMD_SET_FLICKER_FILTER                    0x4f
+#define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE           0x50
+#define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE           0x51
+#define SDVO_CMD_GET_FLICKER_FILTER_2D                 0x53
+#define SDVO_CMD_SET_FLICKER_FILTER_2D                 0x54
+#define SDVO_CMD_GET_SATURATION                                0x56
+#define SDVO_CMD_SET_SATURATION                                0x57
+#define SDVO_CMD_GET_HUE                               0x59
+#define SDVO_CMD_SET_HUE                               0x5a
+#define SDVO_CMD_GET_BRIGHTNESS                                0x5c
+#define SDVO_CMD_SET_BRIGHTNESS                                0x5d
+#define SDVO_CMD_GET_CONTRAST                          0x5f
+#define SDVO_CMD_SET_CONTRAST                          0x60
+#define SDVO_CMD_GET_OVERSCAN_H                                0x62
+#define SDVO_CMD_SET_OVERSCAN_H                                0x63
+#define SDVO_CMD_GET_OVERSCAN_V                                0x65
+#define SDVO_CMD_SET_OVERSCAN_V                                0x66
+#define SDVO_CMD_GET_HPOS                              0x68
+#define SDVO_CMD_SET_HPOS                              0x69
+#define SDVO_CMD_GET_VPOS                              0x6b
+#define SDVO_CMD_SET_VPOS                              0x6c
+#define SDVO_CMD_GET_SHARPNESS                         0x6e
+#define SDVO_CMD_SET_SHARPNESS                         0x6f
+#define SDVO_CMD_GET_TV_CHROMA_FILTER                  0x75
+#define SDVO_CMD_SET_TV_CHROMA_FILTER                  0x76
+#define SDVO_CMD_GET_TV_LUMA_FILTER                    0x78
+#define SDVO_CMD_SET_TV_LUMA_FILTER                    0x79
+struct intel_sdvo_enhancements_arg {
+       u16 value;
+} __packed;
+
+#define SDVO_CMD_GET_DOT_CRAWL                         0x70
+#define SDVO_CMD_SET_DOT_CRAWL                         0x71
+# define SDVO_DOT_CRAWL_ON                                     (1 << 0)
+# define SDVO_DOT_CRAWL_DEFAULT_ON                             (1 << 1)
+
+#define SDVO_CMD_GET_DITHER                            0x72
+#define SDVO_CMD_SET_DITHER                            0x73
+# define SDVO_DITHER_ON                                                (1 << 0)
+# define SDVO_DITHER_DEFAULT_ON                                        (1 << 1)
+
+#define SDVO_CMD_SET_CONTROL_BUS_SWITCH                        0x7a
+# define SDVO_CONTROL_BUS_PROM                         (1 << 0)
+# define SDVO_CONTROL_BUS_DDC1                         (1 << 1)
+# define SDVO_CONTROL_BUS_DDC2                         (1 << 2)
+# define SDVO_CONTROL_BUS_DDC3                         (1 << 3)
+
+/* HDMI op codes */
+#define SDVO_CMD_GET_SUPP_ENCODE       0x9d
+#define SDVO_CMD_GET_ENCODE            0x9e
+#define SDVO_CMD_SET_ENCODE            0x9f
+  #define SDVO_ENCODE_DVI      0x0
+  #define SDVO_ENCODE_HDMI     0x1
+#define SDVO_CMD_SET_PIXEL_REPLI       0x8b
+#define SDVO_CMD_GET_PIXEL_REPLI       0x8c
+#define SDVO_CMD_GET_COLORIMETRY_CAP   0x8d
+#define SDVO_CMD_SET_COLORIMETRY       0x8e
+  #define SDVO_COLORIMETRY_RGB256   0x0
+  #define SDVO_COLORIMETRY_RGB220   0x1
+  #define SDVO_COLORIMETRY_YCrCb422 0x3
+  #define SDVO_COLORIMETRY_YCrCb444 0x4
+#define SDVO_CMD_GET_COLORIMETRY       0x8f
+#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90
+#define SDVO_CMD_SET_AUDIO_STAT                0x91
+#define SDVO_CMD_GET_AUDIO_STAT                0x92
+  #define SDVO_AUDIO_ELD_VALID         (1 << 0)
+  #define SDVO_AUDIO_PRESENCE_DETECT   (1 << 1)
+  #define SDVO_AUDIO_CP_READY          (1 << 2)
+#define SDVO_CMD_SET_HBUF_INDEX                0x93
+  #define SDVO_HBUF_INDEX_ELD          0
+  #define SDVO_HBUF_INDEX_AVI_IF       1
+#define SDVO_CMD_GET_HBUF_INDEX                0x94
+#define SDVO_CMD_GET_HBUF_INFO         0x95
+#define SDVO_CMD_SET_HBUF_AV_SPLIT     0x96
+#define SDVO_CMD_GET_HBUF_AV_SPLIT     0x97
+#define SDVO_CMD_SET_HBUF_DATA         0x98
+#define SDVO_CMD_GET_HBUF_DATA         0x99
+#define SDVO_CMD_SET_HBUF_TXRATE       0x9a
+#define SDVO_CMD_GET_HBUF_TXRATE       0x9b
+  #define SDVO_HBUF_TX_DISABLED        (0 << 6)
+  #define SDVO_HBUF_TX_ONCE    (2 << 6)
+  #define SDVO_HBUF_TX_VSYNC   (3 << 6)
+#define SDVO_CMD_GET_AUDIO_TX_INFO     0x9c
+#define SDVO_NEED_TO_STALL  (1 << 7)
+
+struct intel_sdvo_encode {
+       u8 dvi_rev;
+       u8 hdmi_rev;
+} __packed;
+
+#endif /* __INTEL_SDVO_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
new file mode 100644 (file)
index 0000000..5dc594e
--- /dev/null
@@ -0,0 +1,1991 @@
+/*
+ * Copyright © 2006-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file
+ * Integrated TV-out support for the 915GM and 945GM.
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_connector.h"
+#include "intel_drv.h"
+#include "intel_hotplug.h"
+#include "intel_tv.h"
+
+enum tv_margin {
+       TV_MARGIN_LEFT, TV_MARGIN_TOP,
+       TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
+};
+
+struct intel_tv {
+       struct intel_encoder base;
+
+       int type;
+};
+
+struct video_levels {
+       u16 blank, black;
+       u8 burst;
+};
+
+struct color_conversion {
+       u16 ry, gy, by, ay;
+       u16 ru, gu, bu, au;
+       u16 rv, gv, bv, av;
+};
+
+static const u32 filter_table[] = {
+       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+       0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
+       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+       0x28003100, 0x28002F00, 0x00003100, 0x36403000,
+       0x2D002CC0, 0x30003640, 0x2D0036C0,
+       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+       0x28003100, 0x28002F00, 0x00003100,
+};
+
+/*
+ * Color conversion values have 3 separate fixed point formats:
+ *
+ * 10 bit fields (ay, au)
+ *   1.9 fixed point (b.bbbbbbbbb)
+ * 11 bit fields (ry, by, ru, gu, gv)
+ *   exp.mantissa (ee.mmmmmmmmm)
+ *   ee = 00 = 10^-1 (0.mmmmmmmmm)
+ *   ee = 01 = 10^-2 (0.0mmmmmmmmm)
+ *   ee = 10 = 10^-3 (0.00mmmmmmmmm)
+ *   ee = 11 = 10^-4 (0.000mmmmmmmmm)
+ * 12 bit fields (gy, rv, bu)
+ *   exp.mantissa (eee.mmmmmmmmm)
+ *   eee = 000 = 10^-1 (0.mmmmmmmmm)
+ *   eee = 001 = 10^-2 (0.0mmmmmmmmm)
+ *   eee = 010 = 10^-3 (0.00mmmmmmmmm)
+ *   eee = 011 = 10^-4 (0.000mmmmmmmmm)
+ *   eee = 100 = reserved
+ *   eee = 101 = reserved
+ *   eee = 110 = reserved
+ *   eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
+ *
+ * Saturation and contrast are 8 bits, with their own representation:
+ * 8 bit field (saturation, contrast)
+ *   exp.mantissa (ee.mmmmmm)
+ *   ee = 00 = 10^-1 (0.mmmmmm)
+ *   ee = 01 = 10^0 (m.mmmmm)
+ *   ee = 10 = 10^1 (mm.mmmm)
+ *   ee = 11 = 10^2 (mmm.mmm)
+ *
+ * Simple conversion function:
+ *
+ * static u32
+ * float_to_csc_11(float f)
+ * {
+ *     u32 exp;
+ *     u32 mant;
+ *     u32 ret;
+ *
+ *     if (f < 0)
+ *         f = -f;
+ *
+ *     if (f >= 1) {
+ *         exp = 0x7;
+ *        mant = 1 << 8;
+ *     } else {
+ *         for (exp = 0; exp < 3 && f < 0.5; exp++)
+ *        f *= 2.0;
+ *         mant = (f * (1 << 9) + 0.5);
+ *         if (mant >= (1 << 9))
+ *             mant = (1 << 9) - 1;
+ *     }
+ *     ret = (exp << 9) | mant;
+ *     return ret;
+ * }
+ */
+
+/*
+ * Behold, magic numbers!  If we plant them they might grow a big
+ * s-video cable to the sky... or something.
+ *
+ * Pre-converted to appropriate hex value.
+ */
+
+/*
+ * PAL & NTSC values for composite & s-video connections
+ */
+static const struct color_conversion ntsc_m_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
+};
+
+static const struct video_levels ntsc_m_levels_composite = {
+       .blank = 225, .black = 267, .burst = 113,
+};
+
+static const struct color_conversion ntsc_m_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
+};
+
+static const struct video_levels ntsc_m_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 133,
+};
+
+static const struct color_conversion ntsc_j_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
+       .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
+       .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
+};
+
+static const struct video_levels ntsc_j_levels_composite = {
+       .blank = 225, .black = 225, .burst = 113,
+};
+
+static const struct color_conversion ntsc_j_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
+       .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
+       .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
+};
+
+static const struct video_levels ntsc_j_levels_svideo = {
+       .blank = 266, .black = 266, .burst = 133,
+};
+
+static const struct color_conversion pal_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
+       .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
+       .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
+};
+
+static const struct video_levels pal_levels_composite = {
+       .blank = 237, .black = 237, .burst = 118,
+};
+
+static const struct color_conversion pal_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
+       .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
+       .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
+};
+
+static const struct video_levels pal_levels_svideo = {
+       .blank = 280, .black = 280, .burst = 139,
+};
+
+static const struct color_conversion pal_m_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
+};
+
+static const struct video_levels pal_m_levels_composite = {
+       .blank = 225, .black = 267, .burst = 113,
+};
+
+static const struct color_conversion pal_m_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
+};
+
+static const struct video_levels pal_m_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 133,
+};
+
+static const struct color_conversion pal_n_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
+};
+
+static const struct video_levels pal_n_levels_composite = {
+       .blank = 225, .black = 267, .burst = 118,
+};
+
+static const struct color_conversion pal_n_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
+};
+
+static const struct video_levels pal_n_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 139,
+};
+
+/*
+ * Component connections
+ */
+static const struct color_conversion sdtv_csc_yprpb = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
+       .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
+       .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
+};
+
+static const struct color_conversion hdtv_csc_yprpb = {
+       .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
+       .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
+       .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
+};
+
+static const struct video_levels component_levels = {
+       .blank = 279, .black = 279, .burst = 0,
+};
+
+
+struct tv_mode {
+       const char *name;
+
+       u32 clock;
+       u16 refresh; /* in millihertz (for precision) */
+       u8 oversample;
+       u8 hsync_end;
+       u16 hblank_start, hblank_end, htotal;
+       bool progressive : 1, trilevel_sync : 1, component_only : 1;
+       u8 vsync_start_f1, vsync_start_f2, vsync_len;
+       bool veq_ena : 1;
+       u8 veq_start_f1, veq_start_f2, veq_len;
+       u8 vi_end_f1, vi_end_f2;
+       u16 nbr_end;
+       bool burst_ena : 1;
+       u8 hburst_start, hburst_len;
+       u8 vburst_start_f1;
+       u16 vburst_end_f1;
+       u8 vburst_start_f2;
+       u16 vburst_end_f2;
+       u8 vburst_start_f3;
+       u16 vburst_end_f3;
+       u8 vburst_start_f4;
+       u16 vburst_end_f4;
+       /*
+        * subcarrier programming
+        */
+       u16 dda2_size, dda3_size;
+       u8 dda1_inc;
+       u16 dda2_inc, dda3_inc;
+       u32 sc_reset;
+       bool pal_burst : 1;
+       /*
+        * blank/black levels
+        */
+       const struct video_levels *composite_levels, *svideo_levels;
+       const struct color_conversion *composite_color, *svideo_color;
+       const u32 *filter_table;
+};
+
+
+/*
+ * Sub carrier DDA
+ *
+ *  I think this works as follows:
+ *
+ *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
+ *
+ * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
+ *
+ * So,
+ *  dda1_ideal = subcarrier/pixel * 4096
+ *  dda1_inc = floor (dda1_ideal)
+ *  dda2 = dda1_ideal - dda1_inc
+ *
+ *  then pick a ratio for dda2 that gives the closest approximation. If
+ *  you can't get close enough, you can play with dda3 as well. This
+ *  seems likely to happen when dda2 is small as the jumps would be larger
+ *
+ * To invert this,
+ *
+ *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
+ *
+ * The constants below were all computed using a 107.520MHz clock
+ */
+
+/*
+ * Register programming values for TV modes.
+ *
+ * These values account for -1s required.
+ */
+static const struct tv_mode tv_modes[] = {
+       {
+               .name           = "NTSC-M",
+               .clock          = 108000,
+               .refresh        = 59940,
+               .oversample     = 8,
+               .component_only = false,
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start   = 836,              .htotal             = 857,
+
+               .progressive    = false,            .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    135,
+               .dda2_inc       =  20800,           .dda2_size          =  27456,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst      = false,
+
+               .composite_levels = &ntsc_m_levels_composite,
+               .composite_color = &ntsc_m_csc_composite,
+               .svideo_levels  = &ntsc_m_levels_svideo,
+               .svideo_color = &ntsc_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "NTSC-443",
+               .clock          = 108000,
+               .refresh        = 59940,
+               .oversample     = 8,
+               .component_only = false,
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start   = 836,              .htotal             = 857,
+
+               .progressive    = false,            .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =   4093,       .dda2_size      =  27456,
+               .dda3_inc       =    310,       .dda3_size      =    525,
+               .sc_reset   = TV_SC_RESET_NEVER,
+               .pal_burst  = false,
+
+               .composite_levels = &ntsc_m_levels_composite,
+               .composite_color = &ntsc_m_csc_composite,
+               .svideo_levels  = &ntsc_m_levels_svideo,
+               .svideo_color = &ntsc_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "NTSC-J",
+               .clock          = 108000,
+               .refresh        = 59940,
+               .oversample     = 8,
+               .component_only = false,
+
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start = 836,        .htotal             = 857,
+
+               .progressive    = false,    .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,        .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena      = true,       .veq_start_f1       = 0,
+               .veq_start_f2 = 1,          .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    135,
+               .dda2_inc       =  20800,           .dda2_size          =  27456,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst      = false,
+
+               .composite_levels = &ntsc_j_levels_composite,
+               .composite_color = &ntsc_j_csc_composite,
+               .svideo_levels  = &ntsc_j_levels_svideo,
+               .svideo_color = &ntsc_j_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "PAL-M",
+               .clock          = 108000,
+               .refresh        = 59940,
+               .oversample     = 8,
+               .component_only = false,
+
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+               .hsync_end      = 64,             .hblank_end           = 124,
+               .hblank_start = 836,      .htotal               = 857,
+
+               .progressive    = false,            .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    135,
+               .dda2_inc       =  16704,           .dda2_size          =  27456,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_8,
+               .pal_burst  = true,
+
+               .composite_levels = &pal_m_levels_composite,
+               .composite_color = &pal_m_csc_composite,
+               .svideo_levels  = &pal_m_levels_svideo,
+               .svideo_color = &pal_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
+               .name       = "PAL-N",
+               .clock          = 108000,
+               .refresh        = 50000,
+               .oversample     = 8,
+               .component_only = false,
+
+               .hsync_end      = 64,               .hblank_end         = 128,
+               .hblank_start = 844,        .htotal             = 863,
+
+               .progressive  = false,    .trilevel_sync = false,
+
+
+               .vsync_start_f1 = 6,       .vsync_start_f2      = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 24,               .vi_end_f2          = 25,
+               .nbr_end        = 286,
+
+               .burst_ena      = true,
+               .hburst_start = 73,         .hburst_len         = 34,
+               .vburst_start_f1 = 8,       .vburst_end_f1      = 285,
+               .vburst_start_f2 = 8,       .vburst_end_f2      = 286,
+               .vburst_start_f3 = 9,       .vburst_end_f3      = 286,
+               .vburst_start_f4 = 9,       .vburst_end_f4      = 285,
+
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    135,
+               .dda2_inc       =  23578,       .dda2_size      =  27648,
+               .dda3_inc       =    134,       .dda3_size      =    625,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = true,
+
+               .composite_levels = &pal_n_levels_composite,
+               .composite_color = &pal_n_csc_composite,
+               .svideo_levels  = &pal_n_levels_svideo,
+               .svideo_color = &pal_n_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
+               .name       = "PAL",
+               .clock          = 108000,
+               .refresh        = 50000,
+               .oversample     = 8,
+               .component_only = false,
+
+               .hsync_end      = 64,               .hblank_end         = 142,
+               .hblank_start   = 844,      .htotal             = 863,
+
+               .progressive    = false,    .trilevel_sync = false,
+
+               .vsync_start_f1 = 5,        .vsync_start_f2     = 6,
+               .vsync_len      = 5,
+
+               .veq_ena        = true,     .veq_start_f1       = 0,
+               .veq_start_f2   = 1,        .veq_len            = 15,
+
+               .vi_end_f1      = 24,               .vi_end_f2          = 25,
+               .nbr_end        = 286,
+
+               .burst_ena      = true,
+               .hburst_start   = 73,               .hburst_len         = 32,
+               .vburst_start_f1 = 8,               .vburst_end_f1      = 285,
+               .vburst_start_f2 = 8,               .vburst_end_f2      = 286,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 286,
+               .vburst_start_f4 = 9,               .vburst_end_f4      = 285,
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =   4122,       .dda2_size      =  27648,
+               .dda3_inc       =     67,       .dda3_size      =    625,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = true,
+
+               .composite_levels = &pal_levels_composite,
+               .composite_color = &pal_csc_composite,
+               .svideo_levels  = &pal_levels_svideo,
+               .svideo_color = &pal_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "480p",
+               .clock          = 108000,
+               .refresh        = 59940,
+               .oversample     = 4,
+               .component_only = true,
+
+               .hsync_end      = 64,               .hblank_end         = 122,
+               .hblank_start   = 842,              .htotal             = 857,
+
+               .progressive    = true,             .trilevel_sync = false,
+
+               .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
+               .vsync_len      = 12,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 479,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "576p",
+               .clock          = 108000,
+               .refresh        = 50000,
+               .oversample     = 4,
+               .component_only = true,
+
+               .hsync_end      = 64,               .hblank_end         = 139,
+               .hblank_start   = 859,              .htotal             = 863,
+
+               .progressive    = true,             .trilevel_sync = false,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 48,               .vi_end_f2          = 48,
+               .nbr_end        = 575,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@60Hz",
+               .clock          = 148500,
+               .refresh        = 60000,
+               .oversample     = 2,
+               .component_only = true,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1649,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@50Hz",
+               .clock          = 148500,
+               .refresh        = 50000,
+               .oversample     = 2,
+               .component_only = true,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1979,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "1080i@50Hz",
+               .clock          = 148500,
+               .refresh        = 50000,
+               .oversample     = 2,
+               .component_only = true,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2639,
+
+               .progressive    = false,          .trilevel_sync = true,
+
+               .vsync_start_f1 = 4,              .vsync_start_f2     = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = true,     .veq_start_f1       = 4,
+               .veq_start_f2   = 4,        .veq_len            = 10,
+
+
+               .vi_end_f1      = 21,           .vi_end_f2          = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "1080i@60Hz",
+               .clock          = 148500,
+               .refresh        = 60000,
+               .oversample     = 2,
+               .component_only = true,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2199,
+
+               .progressive    = false,            .trilevel_sync = true,
+
+               .vsync_start_f1 = 4,               .vsync_start_f2     = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = true,             .veq_start_f1       = 4,
+               .veq_start_f2   = 4,                .veq_len            = 10,
+
+
+               .vi_end_f1      = 21,               .vi_end_f2          = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+
+       {
+               .name       = "1080p@30Hz",
+               .clock          = 148500,
+               .refresh        = 30000,
+               .oversample     = 2,
+               .component_only = true,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2199,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 8,               .vsync_start_f2     = 8,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,        .veq_start_f1   = 0,
+               .veq_start_f2   = 0,                .veq_len            = 0,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 1079,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+
+       {
+               .name       = "1080p@50Hz",
+               .clock          = 148500,
+               .refresh        = 50000,
+               .oversample     = 1,
+               .component_only = true,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2639,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 8,               .vsync_start_f2     = 8,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,        .veq_start_f1   = 0,
+               .veq_start_f2   = 0,                .veq_len            = 0,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 1079,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+
+       {
+               .name       = "1080p@60Hz",
+               .clock          = 148500,
+               .refresh        = 60000,
+               .oversample     = 1,
+               .component_only = true,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2199,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 8,               .vsync_start_f2     = 8,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,                    .veq_start_f1       = 0,
+               .veq_start_f2   = 0,                .veq_len            = 0,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 1079,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+};
+
+struct intel_tv_connector_state {
+       struct drm_connector_state base;
+
+       /*
+        * May need to override the user margins for
+        * gen3 >1024 wide source vertical centering.
+        */
+       struct {
+               u16 top, bottom;
+       } margins;
+
+       bool bypass_vfilter;
+};
+
+#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
+
+static struct drm_connector_state *
+intel_tv_connector_duplicate_state(struct drm_connector *connector)
+{
+       struct intel_tv_connector_state *state;
+
+       state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
+       return &state->base;
+}
+
+static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
+{
+       return container_of(encoder, struct intel_tv, base);
+}
+
+static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
+{
+       return enc_to_tv(intel_attached_encoder(connector));
+}
+
+static bool
+intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 tmp = I915_READ(TV_CTL);
+
+       *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
+
+       return tmp & TV_ENC_ENABLE;
+}
+
+static void
+intel_enable_tv(struct intel_encoder *encoder,
+               const struct intel_crtc_state *pipe_config,
+               const struct drm_connector_state *conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       /* Prevents vblank waits from timing out in intel_tv_detect_type() */
+       intel_wait_for_vblank(dev_priv,
+                             to_intel_crtc(pipe_config->base.crtc)->pipe);
+
+       I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
+}
+
+static void
+intel_disable_tv(struct intel_encoder *encoder,
+                const struct intel_crtc_state *old_crtc_state,
+                const struct drm_connector_state *old_conn_state)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
+}
+
+static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
+{
+       int format = conn_state->tv.mode;
+
+       return &tv_modes[format];
+}
+
+static enum drm_mode_status
+intel_tv_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
+{
+       const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (mode->clock > max_dotclk)
+               return MODE_CLOCK_HIGH;
+
+       /* Ensure TV refresh is close to desired refresh */
+       if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
+                               < 1000)
+               return MODE_OK;
+
+       return MODE_CLOCK_RANGE;
+}
+
+static int
+intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
+{
+       if (tv_mode->progressive)
+               return tv_mode->nbr_end + 1;
+       else
+               return 2 * (tv_mode->nbr_end + 1);
+}
+
+static void
+intel_tv_mode_to_mode(struct drm_display_mode *mode,
+                     const struct tv_mode *tv_mode)
+{
+       mode->clock = tv_mode->clock /
+               (tv_mode->oversample >> !tv_mode->progressive);
+
+       /*
+        * tv_mode horizontal timings:
+        *
+        * hsync_end
+        *    | hblank_end
+        *    |    | hblank_start
+        *    |    |       | htotal
+        *    |     _______    |
+        *     ____/       \___
+        * \__/                \
+        */
+       mode->hdisplay =
+               tv_mode->hblank_start - tv_mode->hblank_end;
+       mode->hsync_start = mode->hdisplay +
+               tv_mode->htotal - tv_mode->hblank_start;
+       mode->hsync_end = mode->hsync_start +
+               tv_mode->hsync_end;
+       mode->htotal = tv_mode->htotal + 1;
+
+       /*
+        * tv_mode vertical timings:
+        *
+        * vsync_start
+        *    | vsync_end
+        *    |  | vi_end nbr_end
+        *    |  |    |       |
+        *    |  |     _______
+        * \__    ____/       \
+        *    \__/
+        */
+       mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
+       if (tv_mode->progressive) {
+               mode->vsync_start = mode->vdisplay +
+                       tv_mode->vsync_start_f1 + 1;
+               mode->vsync_end = mode->vsync_start +
+                       tv_mode->vsync_len;
+               mode->vtotal = mode->vdisplay +
+                       tv_mode->vi_end_f1 + 1;
+       } else {
+               mode->vsync_start = mode->vdisplay +
+                       tv_mode->vsync_start_f1 + 1 +
+                       tv_mode->vsync_start_f2 + 1;
+               mode->vsync_end = mode->vsync_start +
+                       2 * tv_mode->vsync_len;
+               mode->vtotal = mode->vdisplay +
+                       tv_mode->vi_end_f1 + 1 +
+                       tv_mode->vi_end_f2 + 1;
+       }
+
+       /* TV has it's own notion of sync and other mode flags, so clear them. */
+       mode->flags = 0;
+
+       mode->vrefresh = 0;
+       mode->vrefresh = drm_mode_vrefresh(mode);
+
+       snprintf(mode->name, sizeof(mode->name),
+                "%dx%d%c (%s)",
+                mode->hdisplay, mode->vdisplay,
+                tv_mode->progressive ? 'p' : 'i',
+                tv_mode->name);
+}
+
+static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
+                                     int hdisplay, int left_margin,
+                                     int right_margin)
+{
+       int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
+       int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
+       int new_htotal = mode->htotal * hdisplay /
+               (mode->hdisplay - left_margin - right_margin);
+
+       mode->clock = mode->clock * new_htotal / mode->htotal;
+
+       mode->hdisplay = hdisplay;
+       mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
+       mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
+       mode->htotal = new_htotal;
+}
+
+static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
+                                    int vdisplay, int top_margin,
+                                    int bottom_margin)
+{
+       int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
+       int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
+       int new_vtotal = mode->vtotal * vdisplay /
+               (mode->vdisplay - top_margin - bottom_margin);
+
+       mode->clock = mode->clock * new_vtotal / mode->vtotal;
+
+       mode->vdisplay = vdisplay;
+       mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
+       mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
+       mode->vtotal = new_vtotal;
+}
+
+static void
+intel_tv_get_config(struct intel_encoder *encoder,
+                   struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct drm_display_mode *adjusted_mode =
+               &pipe_config->base.adjusted_mode;
+       struct drm_display_mode mode = {};
+       u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
+       struct tv_mode tv_mode = {};
+       int hdisplay = adjusted_mode->crtc_hdisplay;
+       int vdisplay = adjusted_mode->crtc_vdisplay;
+       int xsize, ysize, xpos, ypos;
+
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
+
+       tv_ctl = I915_READ(TV_CTL);
+       hctl1 = I915_READ(TV_H_CTL_1);
+       hctl3 = I915_READ(TV_H_CTL_3);
+       vctl1 = I915_READ(TV_V_CTL_1);
+       vctl2 = I915_READ(TV_V_CTL_2);
+
+       tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
+       tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
+
+       tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
+       tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
+
+       tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
+       tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
+       tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
+
+       tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
+       tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
+       tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
+
+       tv_mode.clock = pipe_config->port_clock;
+
+       tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
+
+       switch (tv_ctl & TV_OVERSAMPLE_MASK) {
+       case TV_OVERSAMPLE_8X:
+               tv_mode.oversample = 8;
+               break;
+       case TV_OVERSAMPLE_4X:
+               tv_mode.oversample = 4;
+               break;
+       case TV_OVERSAMPLE_2X:
+               tv_mode.oversample = 2;
+               break;
+       default:
+               tv_mode.oversample = 1;
+               break;
+       }
+
+       tmp = I915_READ(TV_WIN_POS);
+       xpos = tmp >> 16;
+       ypos = tmp & 0xffff;
+
+       tmp = I915_READ(TV_WIN_SIZE);
+       xsize = tmp >> 16;
+       ysize = tmp & 0xffff;
+
+       intel_tv_mode_to_mode(&mode, &tv_mode);
+
+       DRM_DEBUG_KMS("TV mode:\n");
+       drm_mode_debug_printmodeline(&mode);
+
+       intel_tv_scale_mode_horiz(&mode, hdisplay,
+                                 xpos, mode.hdisplay - xsize - xpos);
+       intel_tv_scale_mode_vert(&mode, vdisplay,
+                                ypos, mode.vdisplay - ysize - ypos);
+
+       adjusted_mode->crtc_clock = mode.clock;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+               adjusted_mode->crtc_clock /= 2;
+
+       /* pixel counter doesn't work on i965gm TV output */
+       if (IS_I965GM(dev_priv))
+               adjusted_mode->private_flags |=
+                       I915_MODE_FLAG_USE_SCANLINE_COUNTER;
+}
+
+static bool intel_tv_source_too_wide(struct drm_i915_private *dev_priv,
+                                    int hdisplay)
+{
+       return IS_GEN(dev_priv, 3) && hdisplay > 1024;
+}
+
+static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode,
+                                 const struct drm_connector_state *conn_state,
+                                 int vdisplay)
+{
+       return tv_mode->crtc_vdisplay -
+               conn_state->tv.margins.top -
+               conn_state->tv.margins.bottom !=
+               vdisplay;
+}
+
+static int
+intel_tv_compute_config(struct intel_encoder *encoder,
+                       struct intel_crtc_state *pipe_config,
+                       struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_tv_connector_state *tv_conn_state =
+               to_intel_tv_connector_state(conn_state);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
+       struct drm_display_mode *adjusted_mode =
+               &pipe_config->base.adjusted_mode;
+       int hdisplay = adjusted_mode->crtc_hdisplay;
+       int vdisplay = adjusted_mode->crtc_vdisplay;
+
+       if (!tv_mode)
+               return -EINVAL;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
+       pipe_config->pipe_bpp = 8*3;
+
+       pipe_config->port_clock = tv_mode->clock;
+
+       intel_tv_mode_to_mode(adjusted_mode, tv_mode);
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       if (intel_tv_source_too_wide(dev_priv, hdisplay) ||
+           !intel_tv_vert_scaling(adjusted_mode, conn_state, vdisplay)) {
+               int extra, top, bottom;
+
+               extra = adjusted_mode->crtc_vdisplay - vdisplay;
+
+               if (extra < 0) {
+                       DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
+                       return -EINVAL;
+               }
+
+               /* Need to turn off the vertical filter and center the image */
+
+               /* Attempt to maintain the relative sizes of the margins */
+               top = conn_state->tv.margins.top;
+               bottom = conn_state->tv.margins.bottom;
+
+               if (top + bottom)
+                       top = extra * top / (top + bottom);
+               else
+                       top = extra / 2;
+               bottom = extra - top;
+
+               tv_conn_state->margins.top = top;
+               tv_conn_state->margins.bottom = bottom;
+
+               tv_conn_state->bypass_vfilter = true;
+
+               if (!tv_mode->progressive) {
+                       adjusted_mode->clock /= 2;
+                       adjusted_mode->crtc_clock /= 2;
+                       adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
+               }
+       } else {
+               tv_conn_state->margins.top = conn_state->tv.margins.top;
+               tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
+
+               tv_conn_state->bypass_vfilter = false;
+       }
+
+       DRM_DEBUG_KMS("TV mode:\n");
+       drm_mode_debug_printmodeline(adjusted_mode);
+
+       /*
+        * The pipe scanline counter behaviour looks as follows when
+        * using the TV encoder:
+        *
+        * time ->
+        *
+        * dsl=vtotal-1       |             |
+        *                   ||            ||
+        *               ___| |        ___| |
+        *              /     |       /     |
+        *             /      |      /      |
+        * dsl=0   ___/       |_____/       |
+        *        | | |  |  | |
+        *         ^ ^ ^   ^ ^
+        *         | | |   | pipe vblank/first part of tv vblank
+        *         | | |   bottom margin
+        *         | | active
+        *         | top margin
+        *         remainder of tv vblank
+        *
+        * When the TV encoder is used the pipe wants to run faster
+        * than expected rate. During the active portion the TV
+        * encoder stalls the pipe every few lines to keep it in
+        * check. When the TV encoder reaches the bottom margin the
+        * pipe simply stops. Once we reach the TV vblank the pipe is
+        * no longer stalled and it runs at the max rate (apparently
+        * oversample clock on gen3, cdclk on gen4). Once the pipe
+        * reaches the pipe vtotal the pipe stops for the remainder
+        * of the TV vblank/top margin. The pipe starts up again when
+        * the TV encoder exits the top margin.
+        *
+        * To avoid huge hassles for vblank timestamping we scale
+        * the pipe timings as if the pipe always runs at the average
+        * rate it maintains during the active period. This also
+        * gives us a reasonable guesstimate as to the pixel rate.
+        * Due to the variation in the actual pipe speed the scanline
+        * counter will give us slightly erroneous results during the
+        * TV vblank/margins. But since vtotal was selected such that
+        * it matches the average rate of the pipe during the active
+        * portion the error shouldn't cause any serious grief to
+        * vblank timestamps.
+        *
+        * For posterity here is the empirically derived formula
+        * that gives us the maximum length of the pipe vblank
+        * we can use without causing display corruption. Following
+        * this would allow us to have a ticking scanline counter
+        * everywhere except during the bottom margin (there the
+        * pipe always stops). Ie. this would eliminate the second
+        * flat portion of the above graph. However this would also
+        * complicate vblank timestamping as the pipe vtotal would
+        * no longer match the average rate the pipe runs at during
+        * the active portion. Hence following this formula seems
+        * more trouble that it's worth.
+        *
+        * if (IS_GEN(dev_priv, 4)) {
+        *      num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
+        *      den = tv_mode->clock;
+        * } else {
+        *      num = tv_mode->oversample >> !tv_mode->progressive;
+        *      den = 1;
+        * }
+        * max_pipe_vblank_len ~=
+        *      (num * tv_htotal * (tv_vblank_len + top_margin)) /
+        *      (den * pipe_htotal);
+        */
+       intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
+                                 conn_state->tv.margins.left,
+                                 conn_state->tv.margins.right);
+       intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
+                                tv_conn_state->margins.top,
+                                tv_conn_state->margins.bottom);
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+       adjusted_mode->name[0] = '\0';
+
+       /* pixel counter doesn't work on i965gm TV output */
+       if (IS_I965GM(dev_priv))
+               adjusted_mode->private_flags |=
+                       I915_MODE_FLAG_USE_SCANLINE_COUNTER;
+
+       return 0;
+}
+
+static void
+set_tv_mode_timings(struct drm_i915_private *dev_priv,
+                   const struct tv_mode *tv_mode,
+                   bool burst_ena)
+{
+       u32 hctl1, hctl2, hctl3;
+       u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
+
+       hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
+               (tv_mode->htotal << TV_HTOTAL_SHIFT);
+
+       hctl2 = (tv_mode->hburst_start << 16) |
+               (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
+
+       if (burst_ena)
+               hctl2 |= TV_BURST_ENA;
+
+       hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
+               (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
+
+       vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
+               (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
+               (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
+
+       vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
+               (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
+               (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
+
+       vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
+               (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
+               (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
+
+       if (tv_mode->veq_ena)
+               vctl3 |= TV_EQUAL_ENA;
+
+       vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
+               (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
+
+       vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
+               (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
+
+       vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
+               (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
+
+       vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
+               (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
+
+       I915_WRITE(TV_H_CTL_1, hctl1);
+       I915_WRITE(TV_H_CTL_2, hctl2);
+       I915_WRITE(TV_H_CTL_3, hctl3);
+       I915_WRITE(TV_V_CTL_1, vctl1);
+       I915_WRITE(TV_V_CTL_2, vctl2);
+       I915_WRITE(TV_V_CTL_3, vctl3);
+       I915_WRITE(TV_V_CTL_4, vctl4);
+       I915_WRITE(TV_V_CTL_5, vctl5);
+       I915_WRITE(TV_V_CTL_6, vctl6);
+       I915_WRITE(TV_V_CTL_7, vctl7);
+}
+
+static void set_color_conversion(struct drm_i915_private *dev_priv,
+                                const struct color_conversion *color_conversion)
+{
+       if (!color_conversion)
+               return;
+
+       I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
+                  color_conversion->gy);
+       I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
+                  color_conversion->ay);
+       I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
+                  color_conversion->gu);
+       I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
+                  color_conversion->au);
+       I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
+                  color_conversion->gv);
+       I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
+                  color_conversion->av);
+}
+
+static void intel_tv_pre_enable(struct intel_encoder *encoder,
+                               const struct intel_crtc_state *pipe_config,
+                               const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct intel_tv *intel_tv = enc_to_tv(encoder);
+       const struct intel_tv_connector_state *tv_conn_state =
+               to_intel_tv_connector_state(conn_state);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
+       u32 tv_ctl, tv_filter_ctl;
+       u32 scctl1, scctl2, scctl3;
+       int i, j;
+       const struct video_levels *video_levels;
+       const struct color_conversion *color_conversion;
+       bool burst_ena;
+       int xpos, ypos;
+       unsigned int xsize, ysize;
+
+       if (!tv_mode)
+               return; /* can't happen (mode_prepare prevents this) */
+
+       tv_ctl = I915_READ(TV_CTL);
+       tv_ctl &= TV_CTL_SAVE;
+
+       switch (intel_tv->type) {
+       default:
+       case DRM_MODE_CONNECTOR_Unknown:
+       case DRM_MODE_CONNECTOR_Composite:
+               tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
+               video_levels = tv_mode->composite_levels;
+               color_conversion = tv_mode->composite_color;
+               burst_ena = tv_mode->burst_ena;
+               break;
+       case DRM_MODE_CONNECTOR_Component:
+               tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
+               video_levels = &component_levels;
+               if (tv_mode->burst_ena)
+                       color_conversion = &sdtv_csc_yprpb;
+               else
+                       color_conversion = &hdtv_csc_yprpb;
+               burst_ena = false;
+               break;
+       case DRM_MODE_CONNECTOR_SVIDEO:
+               tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
+               video_levels = tv_mode->svideo_levels;
+               color_conversion = tv_mode->svideo_color;
+               burst_ena = tv_mode->burst_ena;
+               break;
+       }
+
+       tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
+
+       switch (tv_mode->oversample) {
+       case 8:
+               tv_ctl |= TV_OVERSAMPLE_8X;
+               break;
+       case 4:
+               tv_ctl |= TV_OVERSAMPLE_4X;
+               break;
+       case 2:
+               tv_ctl |= TV_OVERSAMPLE_2X;
+               break;
+       default:
+               tv_ctl |= TV_OVERSAMPLE_NONE;
+               break;
+       }
+
+       if (tv_mode->progressive)
+               tv_ctl |= TV_PROGRESSIVE;
+       if (tv_mode->trilevel_sync)
+               tv_ctl |= TV_TRILEVEL_SYNC;
+       if (tv_mode->pal_burst)
+               tv_ctl |= TV_PAL_BURST;
+
+       scctl1 = 0;
+       if (tv_mode->dda1_inc)
+               scctl1 |= TV_SC_DDA1_EN;
+       if (tv_mode->dda2_inc)
+               scctl1 |= TV_SC_DDA2_EN;
+       if (tv_mode->dda3_inc)
+               scctl1 |= TV_SC_DDA3_EN;
+       scctl1 |= tv_mode->sc_reset;
+       if (video_levels)
+               scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
+       scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
+
+       scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
+               tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
+
+       scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
+               tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
+
+       /* Enable two fixes for the chips that need them. */
+       if (IS_I915GM(dev_priv))
+               tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
+
+       set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
+
+       I915_WRITE(TV_SC_CTL_1, scctl1);
+       I915_WRITE(TV_SC_CTL_2, scctl2);
+       I915_WRITE(TV_SC_CTL_3, scctl3);
+
+       set_color_conversion(dev_priv, color_conversion);
+
+       if (INTEL_GEN(dev_priv) >= 4)
+               I915_WRITE(TV_CLR_KNOBS, 0x00404000);
+       else
+               I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+
+       if (video_levels)
+               I915_WRITE(TV_CLR_LEVEL,
+                          ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
+                           (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
+
+       assert_pipe_disabled(dev_priv, intel_crtc->pipe);
+
+       /* Filter ctl must be set before TV_WIN_SIZE */
+       tv_filter_ctl = TV_AUTO_SCALE;
+       if (tv_conn_state->bypass_vfilter)
+               tv_filter_ctl |= TV_V_FILTER_BYPASS;
+       I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
+
+       xsize = tv_mode->hblank_start - tv_mode->hblank_end;
+       ysize = intel_tv_mode_vdisplay(tv_mode);
+
+       xpos = conn_state->tv.margins.left;
+       ypos = tv_conn_state->margins.top;
+       xsize -= (conn_state->tv.margins.left +
+                 conn_state->tv.margins.right);
+       ysize -= (tv_conn_state->margins.top +
+                 tv_conn_state->margins.bottom);
+       I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
+       I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
+
+       j = 0;
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
+       I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
+       I915_WRITE(TV_CTL, tv_ctl);
+}
+
+static int
+intel_tv_detect_type(struct intel_tv *intel_tv,
+                     struct drm_connector *connector)
+{
+       struct drm_crtc *crtc = connector->state->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 tv_ctl, save_tv_ctl;
+       u32 tv_dac, save_tv_dac;
+       int type;
+
+       /* Disable TV interrupts around load detect or we'll recurse */
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irq(&dev_priv->irq_lock);
+               i915_disable_pipestat(dev_priv, 0,
+                                     PIPE_HOTPLUG_INTERRUPT_STATUS |
+                                     PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
+               spin_unlock_irq(&dev_priv->irq_lock);
+       }
+
+       save_tv_dac = tv_dac = I915_READ(TV_DAC);
+       save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
+
+       /* Poll for TV detection */
+       tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
+       tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+       tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
+
+       tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
+       tv_dac |= (TVDAC_STATE_CHG_EN |
+                  TVDAC_A_SENSE_CTL |
+                  TVDAC_B_SENSE_CTL |
+                  TVDAC_C_SENSE_CTL |
+                  DAC_CTL_OVERRIDE |
+                  DAC_A_0_7_V |
+                  DAC_B_0_7_V |
+                  DAC_C_0_7_V);
+
+
+       /*
+        * The TV sense state should be cleared to zero on cantiga platform. Otherwise
+        * the TV is misdetected. This is hardware requirement.
+        */
+       if (IS_GM45(dev_priv))
+               tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
+                           TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
+
+       I915_WRITE(TV_CTL, tv_ctl);
+       I915_WRITE(TV_DAC, tv_dac);
+       POSTING_READ(TV_DAC);
+
+       intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
+
+       type = -1;
+       tv_dac = I915_READ(TV_DAC);
+       DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
+       /*
+        *  A B C
+        *  0 1 1 Composite
+        *  1 0 X svideo
+        *  0 0 0 Component
+        */
+       if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+               DRM_DEBUG_KMS("Detected Composite TV connection\n");
+               type = DRM_MODE_CONNECTOR_Composite;
+       } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+               DRM_DEBUG_KMS("Detected S-Video TV connection\n");
+               type = DRM_MODE_CONNECTOR_SVIDEO;
+       } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+               DRM_DEBUG_KMS("Detected Component TV connection\n");
+               type = DRM_MODE_CONNECTOR_Component;
+       } else {
+               DRM_DEBUG_KMS("Unrecognised TV connection\n");
+               type = -1;
+       }
+
+       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+       I915_WRITE(TV_CTL, save_tv_ctl);
+       POSTING_READ(TV_CTL);
+
+       /* For unknown reasons the hw barfs if we don't do this vblank wait. */
+       intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
+
+       /* Restore interrupt config */
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irq(&dev_priv->irq_lock);
+               i915_enable_pipestat(dev_priv, 0,
+                                    PIPE_HOTPLUG_INTERRUPT_STATUS |
+                                    PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
+               spin_unlock_irq(&dev_priv->irq_lock);
+       }
+
+       return type;
+}
+
+/*
+ * Here we set accurate tv format according to connector type
+ * i.e Component TV should not be assigned by NTSC or PAL
+ */
+static void intel_tv_find_better_format(struct drm_connector *connector)
+{
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
+       int i;
+
+       /* Component supports everything so we can keep the current mode */
+       if (intel_tv->type == DRM_MODE_CONNECTOR_Component)
+               return;
+
+       /* If the current mode is fine don't change it */
+       if (!tv_mode->component_only)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+               tv_mode = &tv_modes[i];
+
+               if (!tv_mode->component_only)
+                       break;
+       }
+
+       connector->state->tv.mode = i;
+}
+
+static int
+intel_tv_detect(struct drm_connector *connector,
+               struct drm_modeset_acquire_ctx *ctx,
+               bool force)
+{
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
+       enum drm_connector_status status;
+       int type;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
+                     connector->base.id, connector->name,
+                     force);
+
+       if (force) {
+               struct intel_load_detect_pipe tmp;
+               int ret;
+
+               ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
+               if (ret < 0)
+                       return ret;
+
+               if (ret > 0) {
+                       type = intel_tv_detect_type(intel_tv, connector);
+                       intel_release_load_detect_pipe(connector, &tmp, ctx);
+                       status = type < 0 ?
+                               connector_status_disconnected :
+                               connector_status_connected;
+               } else
+                       status = connector_status_unknown;
+
+               if (status == connector_status_connected) {
+                       intel_tv->type = type;
+                       intel_tv_find_better_format(connector);
+               }
+
+               return status;
+       } else
+               return connector->status;
+}
+
+static const struct input_res {
+       u16 w, h;
+} input_res_table[] = {
+       { 640, 480 },
+       { 800, 600 },
+       { 1024, 768 },
+       { 1280, 1024 },
+       { 848, 480 },
+       { 1280, 720 },
+       { 1920, 1080 },
+};
+
+/* Choose preferred mode according to line number of TV format */
+static bool
+intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
+                          const struct tv_mode *tv_mode)
+{
+       int vdisplay = intel_tv_mode_vdisplay(tv_mode);
+
+       /* prefer 480 line modes for all SD TV modes */
+       if (vdisplay <= 576)
+               vdisplay = 480;
+
+       return vdisplay == mode->vdisplay;
+}
+
+static void
+intel_tv_set_mode_type(struct drm_display_mode *mode,
+                      const struct tv_mode *tv_mode)
+{
+       mode->type = DRM_MODE_TYPE_DRIVER;
+
+       if (intel_tv_is_preferred_mode(mode, tv_mode))
+               mode->type |= DRM_MODE_TYPE_PREFERRED;
+}
+
+static int
+intel_tv_get_modes(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
+       int i, count = 0;
+
+       for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
+               const struct input_res *input = &input_res_table[i];
+               struct drm_display_mode *mode;
+
+               if (input->w > 1024 &&
+                   !tv_mode->progressive &&
+                   !tv_mode->component_only)
+                       continue;
+
+               /* no vertical scaling with wide sources on gen3 */
+               if (IS_GEN(dev_priv, 3) && input->w > 1024 &&
+                   input->h > intel_tv_mode_vdisplay(tv_mode))
+                       continue;
+
+               mode = drm_mode_create(connector->dev);
+               if (!mode)
+                       continue;
+
+               /*
+                * We take the TV mode and scale it to look
+                * like it had the expected h/vdisplay. This
+                * provides the most information to userspace
+                * about the actual timings of the mode. We
+                * do ignore the margins though.
+                */
+               intel_tv_mode_to_mode(mode, tv_mode);
+               if (count == 0) {
+                       DRM_DEBUG_KMS("TV mode:\n");
+                       drm_mode_debug_printmodeline(mode);
+               }
+               intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
+               intel_tv_scale_mode_vert(mode, input->h, 0, 0);
+               intel_tv_set_mode_type(mode, tv_mode);
+
+               drm_mode_set_name(mode);
+
+               drm_mode_probed_add(connector, mode);
+               count++;
+       }
+
+       return count;
+}
+
+static const struct drm_connector_funcs intel_tv_connector_funcs = {
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_tv_connector_duplicate_state,
+};
+
+static int intel_tv_atomic_check(struct drm_connector *connector,
+                                struct drm_connector_state *new_state)
+{
+       struct drm_crtc_state *new_crtc_state;
+       struct drm_connector_state *old_state;
+
+       if (!new_state->crtc)
+               return 0;
+
+       old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
+       new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
+
+       if (old_state->tv.mode != new_state->tv.mode ||
+           old_state->tv.margins.left != new_state->tv.margins.left ||
+           old_state->tv.margins.right != new_state->tv.margins.right ||
+           old_state->tv.margins.top != new_state->tv.margins.top ||
+           old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
+               /* Force a modeset. */
+
+               new_crtc_state->connectors_changed = true;
+       }
+
+       return 0;
+}
+
+static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
+       .detect_ctx = intel_tv_detect,
+       .mode_valid = intel_tv_mode_valid,
+       .get_modes = intel_tv_get_modes,
+       .atomic_check = intel_tv_atomic_check,
+};
+
+static const struct drm_encoder_funcs intel_tv_enc_funcs = {
+       .destroy = intel_encoder_destroy,
+};
+
+void
+intel_tv_init(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = &dev_priv->drm;
+       struct drm_connector *connector;
+       struct intel_tv *intel_tv;
+       struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
+       u32 tv_dac_on, tv_dac_off, save_tv_dac;
+       const char *tv_format_names[ARRAY_SIZE(tv_modes)];
+       int i, initial_mode = 0;
+       struct drm_connector_state *state;
+
+       if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
+               return;
+
+       if (!intel_bios_is_tv_present(dev_priv)) {
+               DRM_DEBUG_KMS("Integrated TV is not present.\n");
+               return;
+       }
+
+       /*
+        * Sanity check the TV output by checking to see if the
+        * DAC register holds a value
+        */
+       save_tv_dac = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
+       tv_dac_on = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+       tv_dac_off = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac);
+
+       /*
+        * If the register does not hold the state change enable
+        * bit, (either as a 0 or a 1), assume it doesn't really
+        * exist
+        */
+       if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
+           (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
+               return;
+
+       intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
+       if (!intel_tv) {
+               return;
+       }
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(intel_tv);
+               return;
+       }
+
+       intel_encoder = &intel_tv->base;
+       connector = &intel_connector->base;
+       state = connector->state;
+
+       /*
+        * The documentation, for the older chipsets at least, recommend
+        * using a polling method rather than hotplug detection for TVs.
+        * This is because in order to perform the hotplug detection, the PLLs
+        * for the TV must be kept alive increasing power drain and starving
+        * bandwidth from other encoders. Notably for instance, it causes
+        * pipe underruns on Crestline when this encoder is supposedly idle.
+        *
+        * More recent chipsets favour HDMI rather than integrated S-Video.
+        */
+       intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+
+       drm_connector_init(dev, connector, &intel_tv_connector_funcs,
+                          DRM_MODE_CONNECTOR_SVIDEO);
+
+       drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
+                        DRM_MODE_ENCODER_TVDAC, "TV");
+
+       intel_encoder->compute_config = intel_tv_compute_config;
+       intel_encoder->get_config = intel_tv_get_config;
+       intel_encoder->pre_enable = intel_tv_pre_enable;
+       intel_encoder->enable = intel_enable_tv;
+       intel_encoder->disable = intel_disable_tv;
+       intel_encoder->get_hw_state = intel_tv_get_hw_state;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
+
+       intel_encoder->type = INTEL_OUTPUT_TVOUT;
+       intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
+       intel_encoder->port = PORT_NONE;
+       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+       intel_encoder->cloneable = 0;
+       intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
+       intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
+
+       /* BIOS margin values */
+       state->tv.margins.left = 54;
+       state->tv.margins.top = 36;
+       state->tv.margins.right = 46;
+       state->tv.margins.bottom = 37;
+
+       state->tv.mode = initial_mode;
+
+       drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+
+       /* Create TV properties then attach current values */
+       for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+               /* 1080p50/1080p60 not supported on gen3 */
+               if (IS_GEN(dev_priv, 3) &&
+                   tv_modes[i].oversample == 1)
+                       break;
+
+               tv_format_names[i] = tv_modes[i].name;
+       }
+       drm_mode_create_tv_properties(dev, i, tv_format_names);
+
+       drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
+                                  state->tv.mode);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.tv_left_margin_property,
+                                  state->tv.margins.left);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.tv_top_margin_property,
+                                  state->tv.margins.top);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.tv_right_margin_property,
+                                  state->tv.margins.right);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.tv_bottom_margin_property,
+                                  state->tv.margins.bottom);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_tv.h b/drivers/gpu/drm/i915/display/intel_tv.h
new file mode 100644 (file)
index 0000000..4451857
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_TV_H__
+#define __INTEL_TV_H__
+
+struct drm_i915_private;
+
+void intel_tv_init(struct drm_i915_private *dev_priv);
+
+#endif /* __INTEL_TV_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
new file mode 100644 (file)
index 0000000..ffec807
--- /dev/null
@@ -0,0 +1,966 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Author: Gaurav K Singh <gaurav.k.singh@intel.com>
+ *         Manasi Navare <manasi.d.navare@intel.com>
+ */
+
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include "intel_vdsc.h"
+
+enum ROW_INDEX_BPP {
+       ROW_INDEX_6BPP = 0,
+       ROW_INDEX_8BPP,
+       ROW_INDEX_10BPP,
+       ROW_INDEX_12BPP,
+       ROW_INDEX_15BPP,
+       MAX_ROW_INDEX
+};
+
+enum COLUMN_INDEX_BPC {
+       COLUMN_INDEX_8BPC = 0,
+       COLUMN_INDEX_10BPC,
+       COLUMN_INDEX_12BPC,
+       COLUMN_INDEX_14BPC,
+       COLUMN_INDEX_16BPC,
+       MAX_COLUMN_INDEX
+};
+
+#define DSC_SUPPORTED_VERSION_MIN              1
+
+/* From DSC_v1.11 spec, rc_parameter_Set syntax element typically constant */
+static u16 rc_buf_thresh[] = {
+       896, 1792, 2688, 3584, 4480, 5376, 6272, 6720, 7168, 7616,
+       7744, 7872, 8000, 8064
+};
+
+struct rc_parameters {
+       u16 initial_xmit_delay;
+       u8 first_line_bpg_offset;
+       u16 initial_offset;
+       u8 flatness_min_qp;
+       u8 flatness_max_qp;
+       u8 rc_quant_incr_limit0;
+       u8 rc_quant_incr_limit1;
+       struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES];
+};
+
+/*
+ * Selected Rate Control Related Parameter Recommended Values
+ * from DSC_v1.11 spec & C Model release: DSC_model_20161212
+ */
+static struct rc_parameters rc_params[][MAX_COLUMN_INDEX] = {
+{
+       /* 6BPP/8BPC */
+       { 768, 15, 6144, 3, 13, 11, 11, {
+               { 0, 4, 0 }, { 1, 6, -2 }, { 3, 8, -2 }, { 4, 8, -4 },
+               { 5, 9, -6 }, { 5, 9, -6 }, { 6, 9, -6 }, { 6, 10, -8 },
+               { 7, 11, -8 }, { 8, 12, -10 }, { 9, 12, -10 }, { 10, 12, -12 },
+               { 10, 12, -12 }, { 11, 12, -12 }, { 13, 14, -12 }
+               }
+       },
+       /* 6BPP/10BPC */
+       { 768, 15, 6144, 7, 17, 15, 15, {
+               { 0, 8, 0 }, { 3, 10, -2 }, { 7, 12, -2 }, { 8, 12, -4 },
+               { 9, 13, -6 }, { 9, 13, -6 }, { 10, 13, -6 }, { 10, 14, -8 },
+               { 11, 15, -8 }, { 12, 16, -10 }, { 13, 16, -10 },
+               { 14, 16, -12 }, { 14, 16, -12 }, { 15, 16, -12 },
+               { 17, 18, -12 }
+               }
+       },
+       /* 6BPP/12BPC */
+       { 768, 15, 6144, 11, 21, 19, 19, {
+               { 0, 12, 0 }, { 5, 14, -2 }, { 11, 16, -2 }, { 12, 16, -4 },
+               { 13, 17, -6 }, { 13, 17, -6 }, { 14, 17, -6 }, { 14, 18, -8 },
+               { 15, 19, -8 }, { 16, 20, -10 }, { 17, 20, -10 },
+               { 18, 20, -12 }, { 18, 20, -12 }, { 19, 20, -12 },
+               { 21, 22, -12 }
+               }
+       },
+       /* 6BPP/14BPC */
+       { 768, 15, 6144, 15, 25, 23, 27, {
+               { 0, 16, 0 }, { 7, 18, -2 }, { 15, 20, -2 }, { 16, 20, -4 },
+               { 17, 21, -6 }, { 17, 21, -6 }, { 18, 21, -6 }, { 18, 22, -8 },
+               { 19, 23, -8 }, { 20, 24, -10 }, { 21, 24, -10 },
+               { 22, 24, -12 }, { 22, 24, -12 }, { 23, 24, -12 },
+               { 25, 26, -12 }
+               }
+       },
+       /* 6BPP/16BPC */
+       { 768, 15, 6144, 19, 29, 27, 27, {
+               { 0, 20, 0 }, { 9, 22, -2 }, { 19, 24, -2 }, { 20, 24, -4 },
+               { 21, 25, -6 }, { 21, 25, -6 }, { 22, 25, -6 }, { 22, 26, -8 },
+               { 23, 27, -8 }, { 24, 28, -10 }, { 25, 28, -10 },
+               { 26, 28, -12 }, { 26, 28, -12 }, { 27, 28, -12 },
+               { 29, 30, -12 }
+               }
+       },
+},
+{
+       /* 8BPP/8BPC */
+       { 512, 12, 6144, 3, 12, 11, 11, {
+               { 0, 4, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
+               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+               { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 }, { 5, 12, -12 },
+               { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
+               }
+       },
+       /* 8BPP/10BPC */
+       { 512, 12, 6144, 7, 16, 15, 15, {
+               { 0, 4, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 5, 10, -2 },
+               { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+               { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
+               { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
+               }
+       },
+       /* 8BPP/12BPC */
+       { 512, 12, 6144, 11, 20, 19, 19, {
+               { 0, 12, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 9, 14, -2 },
+               { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+               { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
+               { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
+               { 21, 23, -12 }
+               }
+       },
+       /* 8BPP/14BPC */
+       { 512, 12, 6144, 15, 24, 23, 23, {
+               { 0, 12, 0 }, { 5, 13, 0 }, { 11, 15, 0 }, { 12, 17, -2 },
+               { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+               { 15, 21, -8 }, { 15, 22, -10 }, { 17, 22, -10 },
+               { 17, 23, -12 }, { 17, 23, -12 }, { 21, 24, -12 },
+               { 24, 25, -12 }
+               }
+       },
+       /* 8BPP/16BPC */
+       { 512, 12, 6144, 19, 28, 27, 27, {
+               { 0, 12, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 15, 20, -2 },
+               { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+               { 19, 25, -8 }, { 19, 26, -10 }, { 21, 26, -10 },
+               { 21, 27, -12 }, { 21, 27, -12 }, { 25, 28, -12 },
+               { 28, 29, -12 }
+               }
+       },
+},
+{
+       /* 10BPP/8BPC */
+       { 410, 15, 5632, 3, 12, 11, 11, {
+               { 0, 3, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 2, 6, -2 },
+               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+               { 3, 9, -8 }, { 3, 9, -10 }, { 5, 10, -10 }, { 5, 10, -10 },
+               { 5, 11, -12 }, { 7, 11, -12 }, { 11, 12, -12 }
+               }
+       },
+       /* 10BPP/10BPC */
+       { 410, 15, 5632, 7, 16, 15, 15, {
+               { 0, 7, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 6, 10, -2 },
+               { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+               { 7, 13, -8 }, { 7, 13, -10 }, { 9, 14, -10 }, { 9, 14, -10 },
+               { 9, 15, -12 }, { 11, 15, -12 }, { 15, 16, -12 }
+               }
+       },
+       /* 10BPP/12BPC */
+       { 410, 15, 5632, 11, 20, 19, 19, {
+               { 0, 11, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 10, 14, -2 },
+               { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+               { 11, 17, -8 }, { 11, 17, -10 }, { 13, 18, -10 },
+               { 13, 18, -10 }, { 13, 19, -12 }, { 15, 19, -12 },
+               { 19, 20, -12 }
+               }
+       },
+       /* 10BPP/14BPC */
+       { 410, 15, 5632, 15, 24, 23, 23, {
+               { 0, 11, 2 }, { 5, 13, 0 }, { 11, 15, 0 }, { 13, 18, -2 },
+               { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+               { 15, 21, -8 }, { 15, 21, -10 }, { 17, 22, -10 },
+               { 17, 22, -10 }, { 17, 23, -12 }, { 19, 23, -12 },
+               { 23, 24, -12 }
+               }
+       },
+       /* 10BPP/16BPC */
+       { 410, 15, 5632, 19, 28, 27, 27, {
+               { 0, 11, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 16, 20, -2 },
+               { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+               { 19, 25, -8 }, { 19, 25, -10 }, { 21, 26, -10 },
+               { 21, 26, -10 }, { 21, 27, -12 }, { 23, 27, -12 },
+               { 27, 28, -12 }
+               }
+       },
+},
+{
+       /* 12BPP/8BPC */
+       { 341, 15, 2048, 3, 12, 11, 11, {
+               { 0, 2, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
+               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+               { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 },
+               { 5, 12, -12 }, { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
+               }
+       },
+       /* 12BPP/10BPC */
+       { 341, 15, 2048, 7, 16, 15, 15, {
+               { 0, 2, 2 }, { 2, 5, 0 }, { 3, 7, 0 }, { 4, 8, -2 },
+               { 6, 9, -4 }, { 7, 10, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+               { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
+               { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
+               }
+       },
+       /* 12BPP/12BPC */
+       { 341, 15, 2048, 11, 20, 19, 19, {
+               { 0, 6, 2 }, { 4, 9, 0 }, { 7, 11, 0 }, { 8, 12, -2 },
+               { 10, 13, -4 }, { 11, 14, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+               { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
+               { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
+               { 21, 23, -12 }
+               }
+       },
+       /* 12BPP/14BPC */
+       { 341, 15, 2048, 15, 24, 23, 23, {
+               { 0, 6, 2 }, { 7, 10, 0 }, { 9, 13, 0 }, { 11, 16, -2 },
+               { 14, 17, -4 }, { 15, 18, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+               { 15, 20, -8 }, { 15, 21, -10 }, { 17, 21, -10 },
+               { 17, 21, -12 }, { 17, 21, -12 }, { 19, 22, -12 },
+               { 22, 23, -12 }
+               }
+       },
+       /* 12BPP/16BPC */
+       { 341, 15, 2048, 19, 28, 27, 27, {
+               { 0, 6, 2 }, { 6, 11, 0 }, { 11, 15, 0 }, { 14, 18, -2 },
+               { 18, 21, -4 }, { 19, 22, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+               { 19, 24, -8 }, { 19, 25, -10 }, { 21, 25, -10 },
+               { 21, 25, -12 }, { 21, 25, -12 }, { 23, 26, -12 },
+               { 26, 27, -12 }
+               }
+       },
+},
+{
+       /* 15BPP/8BPC */
+       { 273, 15, 2048, 3, 12, 11, 11, {
+               { 0, 0, 10 }, { 0, 1, 8 }, { 0, 1, 6 }, { 0, 2, 4 },
+               { 1, 2, 2 }, { 1, 3, 0 }, { 1, 3, -2 }, { 2, 4, -4 },
+               { 2, 5, -6 }, { 3, 5, -8 }, { 4, 6, -10 }, { 4, 7, -10 },
+               { 5, 7, -12 }, { 7, 8, -12 }, { 8, 9, -12 }
+               }
+       },
+       /* 15BPP/10BPC */
+       { 273, 15, 2048, 7, 16, 15, 15, {
+               { 0, 2, 10 }, { 2, 5, 8 }, { 3, 5, 6 }, { 4, 6, 4 },
+               { 5, 6, 2 }, { 5, 7, 0 }, { 5, 7, -2 }, { 6, 8, -4 },
+               { 6, 9, -6 }, { 7, 9, -8 }, { 8, 10, -10 }, { 8, 11, -10 },
+               { 9, 11, -12 }, { 11, 12, -12 }, { 12, 13, -12 }
+               }
+       },
+       /* 15BPP/12BPC */
+       { 273, 15, 2048, 11, 20, 19, 19, {
+               { 0, 4, 10 }, { 2, 7, 8 }, { 4, 9, 6 }, { 6, 11, 4 },
+               { 9, 11, 2 }, { 9, 11, 0 }, { 9, 12, -2 }, { 10, 12, -4 },
+               { 11, 13, -6 }, { 11, 13, -8 }, { 12, 14, -10 },
+               { 13, 15, -10 }, { 13, 15, -12 }, { 15, 16, -12 },
+               { 16, 17, -12 }
+               }
+       },
+       /* 15BPP/14BPC */
+       { 273, 15, 2048, 15, 24, 23, 23, {
+               { 0, 4, 10 }, { 3, 8, 8 }, { 6, 11, 6 }, { 9, 14, 4 },
+               { 13, 15, 2 }, { 13, 15, 0 }, { 13, 16, -2 }, { 14, 16, -4 },
+               { 15, 17, -6 }, { 15, 17, -8 }, { 16, 18, -10 },
+               { 17, 19, -10 }, { 17, 19, -12 }, { 19, 20, -12 },
+               { 20, 21, -12 }
+               }
+       },
+       /* 15BPP/16BPC */
+       { 273, 15, 2048, 19, 28, 27, 27, {
+               { 0, 4, 10 }, { 4, 9, 8 }, { 8, 13, 6 }, { 12, 17, 4 },
+               { 17, 19, 2 }, { 17, 20, 0 }, { 17, 20, -2 }, { 18, 20, -4 },
+               { 19, 21, -6 }, { 19, 21, -8 }, { 20, 22, -10 },
+               { 21, 23, -10 }, { 21, 23, -12 }, { 23, 24, -12 },
+               { 24, 25, -12 }
+               }
+       }
+}
+
+};
+
+static int get_row_index_for_rc_params(u16 compressed_bpp)
+{
+       switch (compressed_bpp) {
+       case 6:
+               return ROW_INDEX_6BPP;
+       case 8:
+               return ROW_INDEX_8BPP;
+       case 10:
+               return ROW_INDEX_10BPP;
+       case 12:
+               return ROW_INDEX_12BPP;
+       case 15:
+               return ROW_INDEX_15BPP;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int get_column_index_for_rc_params(u8 bits_per_component)
+{
+       switch (bits_per_component) {
+       case 8:
+               return COLUMN_INDEX_8BPC;
+       case 10:
+               return COLUMN_INDEX_10BPC;
+       case 12:
+               return COLUMN_INDEX_12BPC;
+       case 14:
+               return COLUMN_INDEX_14BPC;
+       case 16:
+               return COLUMN_INDEX_16BPC;
+       default:
+               return -EINVAL;
+       }
+}
+
+int intel_dp_compute_dsc_params(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config)
+{
+       struct drm_dsc_config *vdsc_cfg = &pipe_config->dp_dsc_cfg;
+       u16 compressed_bpp = pipe_config->dsc_params.compressed_bpp;
+       u8 i = 0;
+       int row_index = 0;
+       int column_index = 0;
+       u8 line_buf_depth = 0;
+
+       vdsc_cfg->pic_width = pipe_config->base.adjusted_mode.crtc_hdisplay;
+       vdsc_cfg->pic_height = pipe_config->base.adjusted_mode.crtc_vdisplay;
+       vdsc_cfg->slice_width = DIV_ROUND_UP(vdsc_cfg->pic_width,
+                                            pipe_config->dsc_params.slice_count);
+       /*
+        * Slice Height of 8 works for all currently available panels. So start
+        * with that if pic_height is an integral multiple of 8.
+        * Eventually add logic to try multiple slice heights.
+        */
+       if (vdsc_cfg->pic_height % 8 == 0)
+               vdsc_cfg->slice_height = 8;
+       else if (vdsc_cfg->pic_height % 4 == 0)
+               vdsc_cfg->slice_height = 4;
+       else
+               vdsc_cfg->slice_height = 2;
+
+       /* Values filled from DSC Sink DPCD */
+       vdsc_cfg->dsc_version_major =
+               (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+                DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT;
+       vdsc_cfg->dsc_version_minor =
+               min(DSC_SUPPORTED_VERSION_MIN,
+                   (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+                    DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT);
+
+       vdsc_cfg->convert_rgb = intel_dp->dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] &
+               DP_DSC_RGB;
+
+       line_buf_depth = drm_dp_dsc_sink_line_buf_depth(intel_dp->dsc_dpcd);
+       if (!line_buf_depth) {
+               DRM_DEBUG_KMS("DSC Sink Line Buffer Depth invalid\n");
+               return -EINVAL;
+       }
+       if (vdsc_cfg->dsc_version_minor == 2)
+               vdsc_cfg->line_buf_depth = (line_buf_depth == DSC_1_2_MAX_LINEBUF_DEPTH_BITS) ?
+                       DSC_1_2_MAX_LINEBUF_DEPTH_VAL : line_buf_depth;
+       else
+               vdsc_cfg->line_buf_depth = (line_buf_depth > DSC_1_1_MAX_LINEBUF_DEPTH_BITS) ?
+                       DSC_1_1_MAX_LINEBUF_DEPTH_BITS : line_buf_depth;
+
+       /* Gen 11 does not support YCbCr */
+       vdsc_cfg->simple_422 = false;
+       /* Gen 11 does not support VBR */
+       vdsc_cfg->vbr_enable = false;
+       vdsc_cfg->block_pred_enable =
+                       intel_dp->dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] &
+               DP_DSC_BLK_PREDICTION_IS_SUPPORTED;
+
+       /* Gen 11 only supports integral values of bpp */
+       vdsc_cfg->bits_per_pixel = compressed_bpp << 4;
+       vdsc_cfg->bits_per_component = pipe_config->pipe_bpp / 3;
+
+       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
+               /*
+                * six 0s are appended to the lsb of each threshold value
+                * internally in h/w.
+                * Only 8 bits are allowed for programming RcBufThreshold
+                */
+               vdsc_cfg->rc_buf_thresh[i] = rc_buf_thresh[i] >> 6;
+       }
+
+       /*
+        * For 6bpp, RC Buffer threshold 12 and 13 need a different value
+        * as per C Model
+        */
+       if (compressed_bpp == 6) {
+               vdsc_cfg->rc_buf_thresh[12] = 0x7C;
+               vdsc_cfg->rc_buf_thresh[13] = 0x7D;
+       }
+
+       row_index = get_row_index_for_rc_params(compressed_bpp);
+       column_index =
+               get_column_index_for_rc_params(vdsc_cfg->bits_per_component);
+
+       if (row_index < 0 || column_index < 0)
+               return -EINVAL;
+
+       vdsc_cfg->first_line_bpg_offset =
+               rc_params[row_index][column_index].first_line_bpg_offset;
+       vdsc_cfg->initial_xmit_delay =
+               rc_params[row_index][column_index].initial_xmit_delay;
+       vdsc_cfg->initial_offset =
+               rc_params[row_index][column_index].initial_offset;
+       vdsc_cfg->flatness_min_qp =
+               rc_params[row_index][column_index].flatness_min_qp;
+       vdsc_cfg->flatness_max_qp =
+               rc_params[row_index][column_index].flatness_max_qp;
+       vdsc_cfg->rc_quant_incr_limit0 =
+               rc_params[row_index][column_index].rc_quant_incr_limit0;
+       vdsc_cfg->rc_quant_incr_limit1 =
+               rc_params[row_index][column_index].rc_quant_incr_limit1;
+
+       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+               vdsc_cfg->rc_range_params[i].range_min_qp =
+                       rc_params[row_index][column_index].rc_range_params[i].range_min_qp;
+               vdsc_cfg->rc_range_params[i].range_max_qp =
+                       rc_params[row_index][column_index].rc_range_params[i].range_max_qp;
+               /*
+                * Range BPG Offset uses 2's complement and is only a 6 bits. So
+                * mask it to get only 6 bits.
+                */
+               vdsc_cfg->rc_range_params[i].range_bpg_offset =
+                       rc_params[row_index][column_index].rc_range_params[i].range_bpg_offset &
+                       DSC_RANGE_BPG_OFFSET_MASK;
+       }
+
+       /*
+        * BitsPerComponent value determines mux_word_size:
+        * When BitsPerComponent is 12bpc, muxWordSize will be equal to 64 bits
+        * When BitsPerComponent is 8 or 10bpc, muxWordSize will be equal to
+        * 48 bits
+        */
+       if (vdsc_cfg->bits_per_component == 8 ||
+           vdsc_cfg->bits_per_component == 10)
+               vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
+       else if (vdsc_cfg->bits_per_component == 12)
+               vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
+
+       /* RC_MODEL_SIZE is a constant across all configurations */
+       vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
+       /* InitialScaleValue is a 6 bit value with 3 fractional bits (U3.3) */
+       vdsc_cfg->initial_scale_value = (vdsc_cfg->rc_model_size << 3) /
+               (vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset);
+
+       return drm_dsc_compute_rc_parameters(vdsc_cfg);
+}
+
+enum intel_display_power_domain
+intel_dsc_power_domain(const struct intel_crtc_state *crtc_state)
+{
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+       /*
+        * On ICL VDSC/joining for eDP transcoder uses a separate power well PW2
+        * This requires POWER_DOMAIN_TRANSCODER_EDP_VDSC power domain.
+        * For any other transcoder, VDSC/joining uses the power well associated
+        * with the pipe/transcoder in use. Hence another reference on the
+        * transcoder power domain will suffice.
+        */
+       if (cpu_transcoder == TRANSCODER_EDP)
+               return POWER_DOMAIN_TRANSCODER_EDP_VDSC;
+       else
+               return POWER_DOMAIN_TRANSCODER(cpu_transcoder);
+}
+
+static void intel_configure_pps_for_dsc_encoder(struct intel_encoder *encoder,
+                                               const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct drm_dsc_config *vdsc_cfg = &crtc_state->dp_dsc_cfg;
+       enum pipe pipe = crtc->pipe;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 pps_val = 0;
+       u32 rc_buf_thresh_dword[4];
+       u32 rc_range_params_dword[8];
+       u8 num_vdsc_instances = (crtc_state->dsc_params.dsc_split) ? 2 : 1;
+       int i = 0;
+
+       /* Populate PICTURE_PARAMETER_SET_0 registers */
+       pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor <<
+               DSC_VER_MIN_SHIFT |
+               vdsc_cfg->bits_per_component << DSC_BPC_SHIFT |
+               vdsc_cfg->line_buf_depth << DSC_LINE_BUF_DEPTH_SHIFT;
+       if (vdsc_cfg->block_pred_enable)
+               pps_val |= DSC_BLOCK_PREDICTION;
+       if (vdsc_cfg->convert_rgb)
+               pps_val |= DSC_COLOR_SPACE_CONVERSION;
+       if (vdsc_cfg->simple_422)
+               pps_val |= DSC_422_ENABLE;
+       if (vdsc_cfg->vbr_enable)
+               pps_val |= DSC_VBR_ENABLE;
+       DRM_INFO("PPS0 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_0, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_0, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_1 registers */
+       pps_val = 0;
+       pps_val |= DSC_BPP(vdsc_cfg->bits_per_pixel);
+       DRM_INFO("PPS1 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_1, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_1, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_2 registers */
+       pps_val = 0;
+       pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) |
+               DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances);
+       DRM_INFO("PPS2 = 0x%08x\n", pps_val);
+       if (encoder->type == INTEL_OUTPUT_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_2, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_2, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_3 registers */
+       pps_val = 0;
+       pps_val |= DSC_SLICE_HEIGHT(vdsc_cfg->slice_height) |
+               DSC_SLICE_WIDTH(vdsc_cfg->slice_width);
+       DRM_INFO("PPS3 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_3, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_3, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_4 registers */
+       pps_val = 0;
+       pps_val |= DSC_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) |
+               DSC_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay);
+       DRM_INFO("PPS4 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_4, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_4, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_5 registers */
+       pps_val = 0;
+       pps_val |= DSC_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) |
+               DSC_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval);
+       DRM_INFO("PPS5 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_5, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_5, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_6 registers */
+       pps_val = 0;
+       pps_val |= DSC_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) |
+               DSC_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) |
+               DSC_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) |
+               DSC_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp);
+       DRM_INFO("PPS6 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_6, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_6, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_7 registers */
+       pps_val = 0;
+       pps_val |= DSC_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) |
+               DSC_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset);
+       DRM_INFO("PPS7 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_7, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_7, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_8 registers */
+       pps_val = 0;
+       pps_val |= DSC_FINAL_OFFSET(vdsc_cfg->final_offset) |
+               DSC_INITIAL_OFFSET(vdsc_cfg->initial_offset);
+       DRM_INFO("PPS8 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_8, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_8, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_9 registers */
+       pps_val = 0;
+       pps_val |= DSC_RC_MODEL_SIZE(DSC_RC_MODEL_SIZE_CONST) |
+               DSC_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST);
+       DRM_INFO("PPS9 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_9, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_9, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_10 registers */
+       pps_val = 0;
+       pps_val |= DSC_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) |
+               DSC_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) |
+               DSC_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) |
+               DSC_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST);
+       DRM_INFO("PPS10 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_10, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_10, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe),
+                                  pps_val);
+       }
+
+       /* Populate Picture parameter set 16 */
+       pps_val = 0;
+       pps_val |= DSC_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) |
+               DSC_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) /
+                                  vdsc_cfg->slice_width) |
+               DSC_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height /
+                                       vdsc_cfg->slice_height);
+       DRM_INFO("PPS16 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_16, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_16, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe),
+                                  pps_val);
+       }
+
+       /* Populate the RC_BUF_THRESH registers */
+       memset(rc_buf_thresh_dword, 0, sizeof(rc_buf_thresh_dword));
+       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
+               rc_buf_thresh_dword[i / 4] |=
+                       (u32)(vdsc_cfg->rc_buf_thresh[i] <<
+                             BITS_PER_BYTE * (i % 4));
+               DRM_INFO(" RC_BUF_THRESH%d = 0x%08x\n", i,
+                        rc_buf_thresh_dword[i / 4]);
+       }
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_RC_BUF_THRESH_0, rc_buf_thresh_dword[0]);
+               I915_WRITE(DSCA_RC_BUF_THRESH_0_UDW, rc_buf_thresh_dword[1]);
+               I915_WRITE(DSCA_RC_BUF_THRESH_1, rc_buf_thresh_dword[2]);
+               I915_WRITE(DSCA_RC_BUF_THRESH_1_UDW, rc_buf_thresh_dword[3]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(DSCC_RC_BUF_THRESH_0,
+                                  rc_buf_thresh_dword[0]);
+                       I915_WRITE(DSCC_RC_BUF_THRESH_0_UDW,
+                                  rc_buf_thresh_dword[1]);
+                       I915_WRITE(DSCC_RC_BUF_THRESH_1,
+                                  rc_buf_thresh_dword[2]);
+                       I915_WRITE(DSCC_RC_BUF_THRESH_1_UDW,
+                                  rc_buf_thresh_dword[3]);
+               }
+       } else {
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_0(pipe),
+                          rc_buf_thresh_dword[0]);
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_0_UDW(pipe),
+                          rc_buf_thresh_dword[1]);
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_1(pipe),
+                          rc_buf_thresh_dword[2]);
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_1_UDW(pipe),
+                          rc_buf_thresh_dword[3]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_0(pipe),
+                                  rc_buf_thresh_dword[0]);
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_0_UDW(pipe),
+                                  rc_buf_thresh_dword[1]);
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_1(pipe),
+                                  rc_buf_thresh_dword[2]);
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_1_UDW(pipe),
+                                  rc_buf_thresh_dword[3]);
+               }
+       }
+
+       /* Populate the RC_RANGE_PARAMETERS registers */
+       memset(rc_range_params_dword, 0, sizeof(rc_range_params_dword));
+       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+               rc_range_params_dword[i / 2] |=
+                       (u32)(((vdsc_cfg->rc_range_params[i].range_bpg_offset <<
+                               RC_BPG_OFFSET_SHIFT) |
+                              (vdsc_cfg->rc_range_params[i].range_max_qp <<
+                               RC_MAX_QP_SHIFT) |
+                              (vdsc_cfg->rc_range_params[i].range_min_qp <<
+                               RC_MIN_QP_SHIFT)) << 16 * (i % 2));
+               DRM_INFO(" RC_RANGE_PARAM_%d = 0x%08x\n", i,
+                        rc_range_params_dword[i / 2]);
+       }
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_0,
+                          rc_range_params_dword[0]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_0_UDW,
+                          rc_range_params_dword[1]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_1,
+                          rc_range_params_dword[2]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_1_UDW,
+                          rc_range_params_dword[3]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_2,
+                          rc_range_params_dword[4]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_2_UDW,
+                          rc_range_params_dword[5]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_3,
+                          rc_range_params_dword[6]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_3_UDW,
+                          rc_range_params_dword[7]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_0,
+                                  rc_range_params_dword[0]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_0_UDW,
+                                  rc_range_params_dword[1]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_1,
+                                  rc_range_params_dword[2]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_1_UDW,
+                                  rc_range_params_dword[3]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_2,
+                                  rc_range_params_dword[4]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_2_UDW,
+                                  rc_range_params_dword[5]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_3,
+                                  rc_range_params_dword[6]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_3_UDW,
+                                  rc_range_params_dword[7]);
+               }
+       } else {
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe),
+                          rc_range_params_dword[0]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe),
+                          rc_range_params_dword[1]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe),
+                          rc_range_params_dword[2]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe),
+                          rc_range_params_dword[3]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe),
+                          rc_range_params_dword[4]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe),
+                          rc_range_params_dword[5]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe),
+                          rc_range_params_dword[6]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe),
+                          rc_range_params_dword[7]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe),
+                                  rc_range_params_dword[0]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe),
+                                  rc_range_params_dword[1]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe),
+                                  rc_range_params_dword[2]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe),
+                                  rc_range_params_dword[3]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe),
+                                  rc_range_params_dword[4]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe),
+                                  rc_range_params_dword[5]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe),
+                                  rc_range_params_dword[6]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe),
+                                  rc_range_params_dword[7]);
+               }
+       }
+}
+
+static void intel_dp_write_dsc_pps_sdp(struct intel_encoder *encoder,
+                                      const struct intel_crtc_state *crtc_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       const struct drm_dsc_config *vdsc_cfg = &crtc_state->dp_dsc_cfg;
+       struct drm_dsc_pps_infoframe dp_dsc_pps_sdp;
+
+       /* Prepare DP SDP PPS header as per DP 1.4 spec, Table 2-123 */
+       drm_dsc_dp_pps_header_init(&dp_dsc_pps_sdp.pps_header);
+
+       /* Fill the PPS payload bytes as per DSC spec 1.2 Table 4-1 */
+       drm_dsc_pps_payload_pack(&dp_dsc_pps_sdp.pps_payload, vdsc_cfg);
+
+       intel_dig_port->write_infoframe(encoder, crtc_state,
+                                       DP_SDP_PPS, &dp_dsc_pps_sdp,
+                                       sizeof(dp_dsc_pps_sdp));
+}
+
+void intel_dsc_enable(struct intel_encoder *encoder,
+                     const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum pipe pipe = crtc->pipe;
+       i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+       u32 dss_ctl1_val = 0;
+       u32 dss_ctl2_val = 0;
+
+       if (!crtc_state->dsc_params.compression_enable)
+               return;
+
+       /* Enable Power wells for VDSC/joining */
+       intel_display_power_get(dev_priv,
+                               intel_dsc_power_domain(crtc_state));
+
+       intel_configure_pps_for_dsc_encoder(encoder, crtc_state);
+
+       intel_dp_write_dsc_pps_sdp(encoder, crtc_state);
+
+       if (crtc_state->cpu_transcoder == TRANSCODER_EDP) {
+               dss_ctl1_reg = DSS_CTL1;
+               dss_ctl2_reg = DSS_CTL2;
+       } else {
+               dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
+               dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+       }
+       dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE;
+       if (crtc_state->dsc_params.dsc_split) {
+               dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
+               dss_ctl1_val |= JOINER_ENABLE;
+       }
+       I915_WRITE(dss_ctl1_reg, dss_ctl1_val);
+       I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
+}
+
+void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+       u32 dss_ctl1_val = 0, dss_ctl2_val = 0;
+
+       if (!old_crtc_state->dsc_params.compression_enable)
+               return;
+
+       if (old_crtc_state->cpu_transcoder == TRANSCODER_EDP) {
+               dss_ctl1_reg = DSS_CTL1;
+               dss_ctl2_reg = DSS_CTL2;
+       } else {
+               dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
+               dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+       }
+       dss_ctl1_val = I915_READ(dss_ctl1_reg);
+       if (dss_ctl1_val & JOINER_ENABLE)
+               dss_ctl1_val &= ~JOINER_ENABLE;
+       I915_WRITE(dss_ctl1_reg, dss_ctl1_val);
+
+       dss_ctl2_val = I915_READ(dss_ctl2_reg);
+       if (dss_ctl2_val & LEFT_BRANCH_VDSC_ENABLE ||
+           dss_ctl2_val & RIGHT_BRANCH_VDSC_ENABLE)
+               dss_ctl2_val &= ~(LEFT_BRANCH_VDSC_ENABLE |
+                                 RIGHT_BRANCH_VDSC_ENABLE);
+       I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
+
+       /* Disable Power wells for VDSC/joining */
+       intel_display_power_put_unchecked(dev_priv,
+                                         intel_dsc_power_domain(old_crtc_state));
+}
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h
new file mode 100644 (file)
index 0000000..90d3f60
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_VDSC_H__
+#define __INTEL_VDSC_H__
+
+struct intel_encoder;
+struct intel_crtc_state;
+struct intel_dp;
+
+void intel_dsc_enable(struct intel_encoder *encoder,
+                     const struct intel_crtc_state *crtc_state);
+void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
+int intel_dp_compute_dsc_params(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config);
+enum intel_display_power_domain
+intel_dsc_power_domain(const struct intel_crtc_state *crtc_state);
+
+#endif /* __INTEL_VDSC_H__ */
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
new file mode 100644 (file)
index 0000000..e272d82
--- /dev/null
@@ -0,0 +1,1996 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Jani Nikula <jani.nikula@intel.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
+
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_connector.h"
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "intel_fifo_underrun.h"
+#include "intel_panel.h"
+#include "intel_sideband.h"
+
+/* return pixels in terms of txbyteclkhs */
+static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
+                      u16 burst_mode_ratio)
+{
+       return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp * burst_mode_ratio,
+                                        8 * 100), lane_count);
+}
+
+/* return pixels equvalent to txbyteclkhs */
+static u16 pixels_from_txbyteclkhs(u16 clk_hs, int bpp, int lane_count,
+                       u16 burst_mode_ratio)
+{
+       return DIV_ROUND_UP((clk_hs * lane_count * 8 * 100),
+                                               (bpp * burst_mode_ratio));
+}
+
+enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt)
+{
+       /* It just so happens the VBT matches register contents. */
+       switch (fmt) {
+       case VID_MODE_FORMAT_RGB888:
+               return MIPI_DSI_FMT_RGB888;
+       case VID_MODE_FORMAT_RGB666:
+               return MIPI_DSI_FMT_RGB666;
+       case VID_MODE_FORMAT_RGB666_PACKED:
+               return MIPI_DSI_FMT_RGB666_PACKED;
+       case VID_MODE_FORMAT_RGB565:
+               return MIPI_DSI_FMT_RGB565;
+       default:
+               MISSING_CASE(fmt);
+               return MIPI_DSI_FMT_RGB666;
+       }
+}
+
+void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
+{
+       struct drm_encoder *encoder = &intel_dsi->base.base;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 mask;
+
+       mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
+               LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
+
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   MIPI_GEN_FIFO_STAT(port), mask, mask,
+                                   100))
+               DRM_ERROR("DPI FIFOs are not empty\n");
+}
+
+static void write_data(struct drm_i915_private *dev_priv,
+                      i915_reg_t reg,
+                      const u8 *data, u32 len)
+{
+       u32 i, j;
+
+       for (i = 0; i < len; i += 4) {
+               u32 val = 0;
+
+               for (j = 0; j < min_t(u32, len - i, 4); j++)
+                       val |= *data++ << 8 * j;
+
+               I915_WRITE(reg, val);
+       }
+}
+
+static void read_data(struct drm_i915_private *dev_priv,
+                     i915_reg_t reg,
+                     u8 *data, u32 len)
+{
+       u32 i, j;
+
+       for (i = 0; i < len; i += 4) {
+               u32 val = I915_READ(reg);
+
+               for (j = 0; j < min_t(u32, len - i, 4); j++)
+                       *data++ = val >> 8 * j;
+       }
+}
+
+static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host,
+                                      const struct mipi_dsi_msg *msg)
+{
+       struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
+       struct drm_device *dev = intel_dsi_host->intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       enum port port = intel_dsi_host->port;
+       struct mipi_dsi_packet packet;
+       ssize_t ret;
+       const u8 *header, *data;
+       i915_reg_t data_reg, ctrl_reg;
+       u32 data_mask, ctrl_mask;
+
+       ret = mipi_dsi_create_packet(&packet, msg);
+       if (ret < 0)
+               return ret;
+
+       header = packet.header;
+       data = packet.payload;
+
+       if (msg->flags & MIPI_DSI_MSG_USE_LPM) {
+               data_reg = MIPI_LP_GEN_DATA(port);
+               data_mask = LP_DATA_FIFO_FULL;
+               ctrl_reg = MIPI_LP_GEN_CTRL(port);
+               ctrl_mask = LP_CTRL_FIFO_FULL;
+       } else {
+               data_reg = MIPI_HS_GEN_DATA(port);
+               data_mask = HS_DATA_FIFO_FULL;
+               ctrl_reg = MIPI_HS_GEN_CTRL(port);
+               ctrl_mask = HS_CTRL_FIFO_FULL;
+       }
+
+       /* note: this is never true for reads */
+       if (packet.payload_length) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_GEN_FIFO_STAT(port),
+                                           data_mask, 0,
+                                           50))
+                       DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
+
+               write_data(dev_priv, data_reg, packet.payload,
+                          packet.payload_length);
+       }
+
+       if (msg->rx_len) {
+               I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
+       }
+
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   MIPI_GEN_FIFO_STAT(port),
+                                   ctrl_mask, 0,
+                                   50)) {
+               DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
+       }
+
+       I915_WRITE(ctrl_reg, header[2] << 16 | header[1] << 8 | header[0]);
+
+       /* ->rx_len is set only for reads */
+       if (msg->rx_len) {
+               data_mask = GEN_READ_DATA_AVAIL;
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_INTR_STAT(port),
+                                           data_mask, data_mask,
+                                           50))
+                       DRM_ERROR("Timeout waiting for read data.\n");
+
+               read_data(dev_priv, data_reg, msg->rx_buf, msg->rx_len);
+       }
+
+       /* XXX: fix for reads and writes */
+       return 4 + packet.payload_length;
+}
+
+static int intel_dsi_host_attach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *dsi)
+{
+       return 0;
+}
+
+static int intel_dsi_host_detach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *dsi)
+{
+       return 0;
+}
+
+static const struct mipi_dsi_host_ops intel_dsi_host_ops = {
+       .attach = intel_dsi_host_attach,
+       .detach = intel_dsi_host_detach,
+       .transfer = intel_dsi_host_transfer,
+};
+
+/*
+ * send a video mode command
+ *
+ * XXX: commands with data in MIPI_DPI_DATA?
+ */
+static int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs,
+                       enum port port)
+{
+       struct drm_encoder *encoder = &intel_dsi->base.base;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 mask;
+
+       /* XXX: pipe, hs */
+       if (hs)
+               cmd &= ~DPI_LP_MODE;
+       else
+               cmd |= DPI_LP_MODE;
+
+       /* clear bit */
+       I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT);
+
+       /* XXX: old code skips write if control unchanged */
+       if (cmd == I915_READ(MIPI_DPI_CONTROL(port)))
+               DRM_DEBUG_KMS("Same special packet %02x twice in a row.\n", cmd);
+
+       I915_WRITE(MIPI_DPI_CONTROL(port), cmd);
+
+       mask = SPL_PKT_SENT_INTERRUPT;
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   MIPI_INTR_STAT(port), mask, mask,
+                                   100))
+               DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
+
+       return 0;
+}
+
+static void band_gap_reset(struct drm_i915_private *dev_priv)
+{
+       vlv_flisdsi_get(dev_priv);
+
+       vlv_flisdsi_write(dev_priv, 0x08, 0x0001);
+       vlv_flisdsi_write(dev_priv, 0x0F, 0x0005);
+       vlv_flisdsi_write(dev_priv, 0x0F, 0x0025);
+       udelay(150);
+       vlv_flisdsi_write(dev_priv, 0x0F, 0x0000);
+       vlv_flisdsi_write(dev_priv, 0x08, 0x0000);
+
+       vlv_flisdsi_put(dev_priv);
+}
+
+static int intel_dsi_compute_config(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
+                                                  base);
+       struct intel_connector *intel_connector = intel_dsi->attached_connector;
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       int ret;
+
+       DRM_DEBUG_KMS("\n");
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
+       if (fixed_mode) {
+               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+
+               if (HAS_GMCH(dev_priv))
+                       intel_gmch_panel_fitting(crtc, pipe_config,
+                                                conn_state->scaling_mode);
+               else
+                       intel_pch_panel_fitting(crtc, pipe_config,
+                                               conn_state->scaling_mode);
+       }
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return -EINVAL;
+
+       /* DSI uses short packets for sync events, so clear mode flags for DSI */
+       adjusted_mode->flags = 0;
+
+       if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB888)
+               pipe_config->pipe_bpp = 24;
+       else
+               pipe_config->pipe_bpp = 18;
+
+       if (IS_GEN9_LP(dev_priv)) {
+               /* Enable Frame time stamp based scanline reporting */
+               adjusted_mode->private_flags |=
+                       I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP;
+
+               /* Dual link goes to DSI transcoder A. */
+               if (intel_dsi->ports == BIT(PORT_C))
+                       pipe_config->cpu_transcoder = TRANSCODER_DSI_C;
+               else
+                       pipe_config->cpu_transcoder = TRANSCODER_DSI_A;
+
+               ret = bxt_dsi_pll_compute(encoder, pipe_config);
+               if (ret)
+                       return -EINVAL;
+       } else {
+               ret = vlv_dsi_pll_compute(encoder, pipe_config);
+               if (ret)
+                       return -EINVAL;
+       }
+
+       pipe_config->clock_set = true;
+
+       return 0;
+}
+
+static bool glk_dsi_enable_io(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       bool cold_boot = false;
+
+       /* Set the MIPI mode
+        * If MIPI_Mode is off, then writing to LP_Wake bit is not reflecting.
+        * Power ON MIPI IO first and then write into IO reset and LP wake bits
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(MIPI_CTRL(port));
+               I915_WRITE(MIPI_CTRL(port), tmp | GLK_MIPIIO_ENABLE);
+       }
+
+       /* Put the IO into reset */
+       tmp = I915_READ(MIPI_CTRL(PORT_A));
+       tmp &= ~GLK_MIPIIO_RESET_RELEASED;
+       I915_WRITE(MIPI_CTRL(PORT_A), tmp);
+
+       /* Program LP Wake */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(MIPI_CTRL(port));
+               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY))
+                       tmp &= ~GLK_LP_WAKE;
+               else
+                       tmp |= GLK_LP_WAKE;
+               I915_WRITE(MIPI_CTRL(port), tmp);
+       }
+
+       /* Wait for Pwr ACK */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_CTRL(port),
+                                           GLK_MIPIIO_PORT_POWERED,
+                                           GLK_MIPIIO_PORT_POWERED,
+                                           20))
+                       DRM_ERROR("MIPIO port is powergated\n");
+       }
+
+       /* Check for cold boot scenario */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               cold_boot |=
+                       !(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY);
+       }
+
+       return cold_boot;
+}
+
+static void glk_dsi_device_ready(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       /* Wait for MIPI PHY status bit to set */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_CTRL(port),
+                                           GLK_PHY_STATUS_PORT_READY,
+                                           GLK_PHY_STATUS_PORT_READY,
+                                           20))
+                       DRM_ERROR("PHY is not ON\n");
+       }
+
+       /* Get IO out of reset */
+       val = I915_READ(MIPI_CTRL(PORT_A));
+       I915_WRITE(MIPI_CTRL(PORT_A), val | GLK_MIPIIO_RESET_RELEASED);
+
+       /* Get IO out of Low power state*/
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY)) {
+                       val = I915_READ(MIPI_DEVICE_READY(port));
+                       val &= ~ULPS_STATE_MASK;
+                       val |= DEVICE_READY;
+                       I915_WRITE(MIPI_DEVICE_READY(port), val);
+                       usleep_range(10, 15);
+               } else {
+                       /* Enter ULPS */
+                       val = I915_READ(MIPI_DEVICE_READY(port));
+                       val &= ~ULPS_STATE_MASK;
+                       val |= (ULPS_STATE_ENTER | DEVICE_READY);
+                       I915_WRITE(MIPI_DEVICE_READY(port), val);
+
+                       /* Wait for ULPS active */
+                       if (intel_wait_for_register(&dev_priv->uncore,
+                                                   MIPI_CTRL(port),
+                                                   GLK_ULPS_NOT_ACTIVE,
+                                                   0,
+                                                   20))
+                               DRM_ERROR("ULPS not active\n");
+
+                       /* Exit ULPS */
+                       val = I915_READ(MIPI_DEVICE_READY(port));
+                       val &= ~ULPS_STATE_MASK;
+                       val |= (ULPS_STATE_EXIT | DEVICE_READY);
+                       I915_WRITE(MIPI_DEVICE_READY(port), val);
+
+                       /* Enter Normal Mode */
+                       val = I915_READ(MIPI_DEVICE_READY(port));
+                       val &= ~ULPS_STATE_MASK;
+                       val |= (ULPS_STATE_NORMAL_OPERATION | DEVICE_READY);
+                       I915_WRITE(MIPI_DEVICE_READY(port), val);
+
+                       val = I915_READ(MIPI_CTRL(port));
+                       val &= ~GLK_LP_WAKE;
+                       I915_WRITE(MIPI_CTRL(port), val);
+               }
+       }
+
+       /* Wait for Stop state */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_CTRL(port),
+                                           GLK_DATA_LANE_STOP_STATE,
+                                           GLK_DATA_LANE_STOP_STATE,
+                                           20))
+                       DRM_ERROR("Date lane not in STOP state\n");
+       }
+
+       /* Wait for AFE LATCH */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           BXT_MIPI_PORT_CTRL(port),
+                                           AFE_LATCHOUT,
+                                           AFE_LATCHOUT,
+                                           20))
+                       DRM_ERROR("D-PHY not entering LP-11 state\n");
+       }
+}
+
+static void bxt_dsi_device_ready(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       DRM_DEBUG_KMS("\n");
+
+       /* Enable MIPI PHY transparent latch */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               val = I915_READ(BXT_MIPI_PORT_CTRL(port));
+               I915_WRITE(BXT_MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD);
+               usleep_range(2000, 2500);
+       }
+
+       /* Clear ULPS and set device ready */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               val = I915_READ(MIPI_DEVICE_READY(port));
+               val &= ~ULPS_STATE_MASK;
+               I915_WRITE(MIPI_DEVICE_READY(port), val);
+               usleep_range(2000, 2500);
+               val |= DEVICE_READY;
+               I915_WRITE(MIPI_DEVICE_READY(port), val);
+       }
+}
+
+static void vlv_dsi_device_ready(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       DRM_DEBUG_KMS("\n");
+
+       vlv_flisdsi_get(dev_priv);
+       /* program rcomp for compliance, reduce from 50 ohms to 45 ohms
+        * needed everytime after power gate */
+       vlv_flisdsi_write(dev_priv, 0x04, 0x0004);
+       vlv_flisdsi_put(dev_priv);
+
+       /* bandgap reset is needed after everytime we do power gate */
+       band_gap_reset(dev_priv);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+
+               I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER);
+               usleep_range(2500, 3000);
+
+               /* Enable MIPI PHY transparent latch
+                * Common bit for both MIPI Port A & MIPI Port C
+                * No similar bit in MIPI Port C reg
+                */
+               val = I915_READ(MIPI_PORT_CTRL(PORT_A));
+               I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD);
+               usleep_range(1000, 1500);
+
+               I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT);
+               usleep_range(2500, 3000);
+
+               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY);
+               usleep_range(2500, 3000);
+       }
+}
+
+static void intel_dsi_device_ready(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (IS_GEMINILAKE(dev_priv))
+               glk_dsi_device_ready(encoder);
+       else if (IS_GEN9_LP(dev_priv))
+               bxt_dsi_device_ready(encoder);
+       else
+               vlv_dsi_device_ready(encoder);
+}
+
+static void glk_dsi_enter_low_power_mode(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       /* Enter ULPS */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               val = I915_READ(MIPI_DEVICE_READY(port));
+               val &= ~ULPS_STATE_MASK;
+               val |= (ULPS_STATE_ENTER | DEVICE_READY);
+               I915_WRITE(MIPI_DEVICE_READY(port), val);
+       }
+
+       /* Wait for MIPI PHY status bit to unset */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_CTRL(port),
+                                           GLK_PHY_STATUS_PORT_READY, 0, 20))
+                       DRM_ERROR("PHY is not turning OFF\n");
+       }
+
+       /* Wait for Pwr ACK bit to unset */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_CTRL(port),
+                                           GLK_MIPIIO_PORT_POWERED, 0, 20))
+                       DRM_ERROR("MIPI IO Port is not powergated\n");
+       }
+}
+
+static void glk_dsi_disable_mipi_io(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+
+       /* Put the IO into reset */
+       tmp = I915_READ(MIPI_CTRL(PORT_A));
+       tmp &= ~GLK_MIPIIO_RESET_RELEASED;
+       I915_WRITE(MIPI_CTRL(PORT_A), tmp);
+
+       /* Wait for MIPI PHY status bit to unset */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (intel_wait_for_register(&dev_priv->uncore,
+                                           MIPI_CTRL(port),
+                                           GLK_PHY_STATUS_PORT_READY, 0, 20))
+                       DRM_ERROR("PHY is not turning OFF\n");
+       }
+
+       /* Clear MIPI mode */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(MIPI_CTRL(port));
+               tmp &= ~GLK_MIPIIO_ENABLE;
+               I915_WRITE(MIPI_CTRL(port), tmp);
+       }
+}
+
+static void glk_dsi_clear_device_ready(struct intel_encoder *encoder)
+{
+       glk_dsi_enter_low_power_mode(encoder);
+       glk_dsi_disable_mipi_io(encoder);
+}
+
+static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+
+       DRM_DEBUG_KMS("\n");
+       for_each_dsi_port(port, intel_dsi->ports) {
+               /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */
+               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
+                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A);
+               u32 val;
+
+               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+                                                       ULPS_STATE_ENTER);
+               usleep_range(2000, 2500);
+
+               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+                                                       ULPS_STATE_EXIT);
+               usleep_range(2000, 2500);
+
+               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+                                                       ULPS_STATE_ENTER);
+               usleep_range(2000, 2500);
+
+               /*
+                * On VLV/CHV, wait till Clock lanes are in LP-00 state for MIPI
+                * Port A only. MIPI Port C has no similar bit for checking.
+                */
+               if ((IS_GEN9_LP(dev_priv) || port == PORT_A) &&
+                   intel_wait_for_register(&dev_priv->uncore,
+                                           port_ctrl, AFE_LATCHOUT, 0,
+                                           30))
+                       DRM_ERROR("DSI LP not going Low\n");
+
+               /* Disable MIPI PHY transparent latch */
+               val = I915_READ(port_ctrl);
+               I915_WRITE(port_ctrl, val & ~LP_OUTPUT_HOLD);
+               usleep_range(1000, 1500);
+
+               I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
+               usleep_range(2000, 2500);
+       }
+}
+
+static void intel_dsi_port_enable(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+
+       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+               u32 temp;
+               if (IS_GEN9_LP(dev_priv)) {
+                       for_each_dsi_port(port, intel_dsi->ports) {
+                               temp = I915_READ(MIPI_CTRL(port));
+                               temp &= ~BXT_PIXEL_OVERLAP_CNT_MASK |
+                                       intel_dsi->pixel_overlap <<
+                                       BXT_PIXEL_OVERLAP_CNT_SHIFT;
+                               I915_WRITE(MIPI_CTRL(port), temp);
+                       }
+               } else {
+                       temp = I915_READ(VLV_CHICKEN_3);
+                       temp &= ~PIXEL_OVERLAP_CNT_MASK |
+                                       intel_dsi->pixel_overlap <<
+                                       PIXEL_OVERLAP_CNT_SHIFT;
+                       I915_WRITE(VLV_CHICKEN_3, temp);
+               }
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
+                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+               u32 temp;
+
+               temp = I915_READ(port_ctrl);
+
+               temp &= ~LANE_CONFIGURATION_MASK;
+               temp &= ~DUAL_LINK_MODE_MASK;
+
+               if (intel_dsi->ports == (BIT(PORT_A) | BIT(PORT_C))) {
+                       temp |= (intel_dsi->dual_link - 1)
+                                               << DUAL_LINK_MODE_SHIFT;
+                       if (IS_BROXTON(dev_priv))
+                               temp |= LANE_CONFIGURATION_DUAL_LINK_A;
+                       else
+                               temp |= crtc->pipe ?
+                                       LANE_CONFIGURATION_DUAL_LINK_B :
+                                       LANE_CONFIGURATION_DUAL_LINK_A;
+               }
+
+               if (intel_dsi->pixel_format != MIPI_DSI_FMT_RGB888)
+                       temp |= DITHERING_ENABLE;
+
+               /* assert ip_tg_enable signal */
+               I915_WRITE(port_ctrl, temp | DPI_ENABLE);
+               POSTING_READ(port_ctrl);
+       }
+}
+
+static void intel_dsi_port_disable(struct intel_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
+                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+               u32 temp;
+
+               /* de-assert ip_tg_enable signal */
+               temp = I915_READ(port_ctrl);
+               I915_WRITE(port_ctrl, temp & ~DPI_ENABLE);
+               POSTING_READ(port_ctrl);
+       }
+}
+
+static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
+                             const struct intel_crtc_state *pipe_config);
+static void intel_dsi_unprepare(struct intel_encoder *encoder);
+
+/*
+ * Panel enable/disable sequences from the VBT spec.
+ *
+ * Note the spec has AssertReset / DeassertReset swapped from their
+ * usual naming. We use the normal names to avoid confusion (so below
+ * they are swapped compared to the spec).
+ *
+ * Steps starting with MIPI refer to VBT sequences, note that for v2
+ * VBTs several steps which have a VBT in v2 are expected to be handled
+ * directly by the driver, by directly driving gpios for example.
+ *
+ * v2 video mode seq         v3 video mode seq         command mode seq
+ * - power on                - MIPIPanelPowerOn        - power on
+ * - wait t1+t2                                        - wait t1+t2
+ * - MIPIDeassertResetPin    - MIPIDeassertResetPin    - MIPIDeassertResetPin
+ * - io lines to lp-11       - io lines to lp-11       - io lines to lp-11
+ * - MIPISendInitialDcsCmds  - MIPISendInitialDcsCmds  - MIPISendInitialDcsCmds
+ *                                                     - MIPITearOn
+ *                                                     - MIPIDisplayOn
+ * - turn on DPI             - turn on DPI             - set pipe to dsr mode
+ * - MIPIDisplayOn           - MIPIDisplayOn
+ * - wait t5                                           - wait t5
+ * - backlight on            - MIPIBacklightOn         - backlight on
+ * ...                       ...                       ... issue mem cmds ...
+ * - backlight off           - MIPIBacklightOff        - backlight off
+ * - wait t6                                           - wait t6
+ * - MIPIDisplayOff
+ * - turn off DPI            - turn off DPI            - disable pipe dsr mode
+ *                                                     - MIPITearOff
+ *                           - MIPIDisplayOff          - MIPIDisplayOff
+ * - io lines to lp-00       - io lines to lp-00       - io lines to lp-00
+ * - MIPIAssertResetPin      - MIPIAssertResetPin      - MIPIAssertResetPin
+ * - wait t3                                           - wait t3
+ * - power off               - MIPIPanelPowerOff       - power off
+ * - wait t4                                           - wait t4
+ */
+
+/*
+ * DSI port enable has to be done before pipe and plane enable, so we do it in
+ * the pre_enable hook instead of the enable hook.
+ */
+static void intel_dsi_pre_enable(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *pipe_config,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       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;
+       enum port port;
+       u32 val;
+       bool glk_cold_boot = false;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+
+       /*
+        * The BIOS may leave the PLL in a wonky state where it doesn't
+        * lock. It needs to be fully powered down to fix it.
+        */
+       if (IS_GEN9_LP(dev_priv)) {
+               bxt_dsi_pll_disable(encoder);
+               bxt_dsi_pll_enable(encoder, pipe_config);
+       } else {
+               vlv_dsi_pll_disable(encoder);
+               vlv_dsi_pll_enable(encoder, pipe_config);
+       }
+
+       if (IS_BROXTON(dev_priv)) {
+               /* Add MIPI IO reset programming for modeset */
+               val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
+               I915_WRITE(BXT_P_CR_GT_DISP_PWRON,
+                                       val | MIPIO_RST_CTRL);
+
+               /* Power up DSI regulator */
+               I915_WRITE(BXT_P_DSI_REGULATOR_CFG, STAP_SELECT);
+               I915_WRITE(BXT_P_DSI_REGULATOR_TX_CTRL, 0);
+       }
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               u32 val;
+
+               /* Disable DPOunit clock gating, can stall pipe */
+               val = I915_READ(DSPCLK_GATE_D);
+               val |= DPOUNIT_CLOCK_GATE_DISABLE;
+               I915_WRITE(DSPCLK_GATE_D, val);
+       }
+
+       if (!IS_GEMINILAKE(dev_priv))
+               intel_dsi_prepare(encoder, pipe_config);
+
+       /* Power on, try both CRC pmic gpio and VBT */
+       if (intel_dsi->gpio_panel)
+               gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
+       intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
+
+       /* Deassert reset */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+
+       if (IS_GEMINILAKE(dev_priv)) {
+               glk_cold_boot = glk_dsi_enable_io(encoder);
+
+               /* Prepare port in cold boot(s3/s4) scenario */
+               if (glk_cold_boot)
+                       intel_dsi_prepare(encoder, pipe_config);
+       }
+
+       /* Put device in ready state (LP-11) */
+       intel_dsi_device_ready(encoder);
+
+       /* Prepare port in normal boot scenario */
+       if (IS_GEMINILAKE(dev_priv) && !glk_cold_boot)
+               intel_dsi_prepare(encoder, pipe_config);
+
+       /* Send initialization commands in LP mode */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+
+       /* Enable port in pre-enable phase itself because as per hw team
+        * recommendation, port should be enabled befor plane & pipe */
+       if (is_cmd_mode(intel_dsi)) {
+               for_each_dsi_port(port, intel_dsi->ports)
+                       I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
+               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_TEAR_ON);
+               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
+       } else {
+               msleep(20); /* XXX */
+               for_each_dsi_port(port, intel_dsi->ports)
+                       dpi_send_cmd(intel_dsi, TURN_ON, false, port);
+               intel_dsi_msleep(intel_dsi, 100);
+
+               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
+
+               intel_dsi_port_enable(encoder, pipe_config);
+       }
+
+       intel_panel_enable_backlight(pipe_config, conn_state);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
+}
+
+/*
+ * DSI port disable has to be done after pipe and plane disable, so we do it in
+ * the post_disable hook.
+ */
+static void intel_dsi_disable(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
+       intel_panel_disable_backlight(old_conn_state);
+
+       /*
+        * According to the spec we should send SHUTDOWN before
+        * MIPI_SEQ_DISPLAY_OFF only for v3+ VBTs, but field testing
+        * has shown that the v3 sequence works for v2 VBTs too
+        */
+       if (is_vid_mode(intel_dsi)) {
+               /* Send Shutdown command to the panel in LP mode */
+               for_each_dsi_port(port, intel_dsi->ports)
+                       dpi_send_cmd(intel_dsi, SHUTDOWN, false, port);
+               msleep(10);
+       }
+}
+
+static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       if (IS_GEMINILAKE(dev_priv))
+               glk_dsi_clear_device_ready(encoder);
+       else
+               vlv_dsi_clear_device_ready(encoder);
+}
+
+static void intel_dsi_post_disable(struct intel_encoder *encoder,
+                                  const struct intel_crtc_state *pipe_config,
+                                  const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (is_vid_mode(intel_dsi)) {
+               for_each_dsi_port(port, intel_dsi->ports)
+                       vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
+
+               intel_dsi_port_disable(encoder);
+               usleep_range(2000, 5000);
+       }
+
+       intel_dsi_unprepare(encoder);
+
+       /*
+        * if disable packets are sent before sending shutdown packet then in
+        * some next enable sequence send turn on packet error is observed
+        */
+       if (is_cmd_mode(intel_dsi))
+               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_TEAR_OFF);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
+
+       /* Transition to LP-00 */
+       intel_dsi_clear_device_ready(encoder);
+
+       if (IS_BROXTON(dev_priv)) {
+               /* Power down DSI regulator to save power */
+               I915_WRITE(BXT_P_DSI_REGULATOR_CFG, STAP_SELECT);
+               I915_WRITE(BXT_P_DSI_REGULATOR_TX_CTRL, HS_IO_CTRL_SELECT);
+
+               /* Add MIPI IO reset programming for modeset */
+               val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
+               I915_WRITE(BXT_P_CR_GT_DISP_PWRON,
+                               val & ~MIPIO_RST_CTRL);
+       }
+
+       if (IS_GEN9_LP(dev_priv)) {
+               bxt_dsi_pll_disable(encoder);
+       } else {
+               u32 val;
+
+               vlv_dsi_pll_disable(encoder);
+
+               val = I915_READ(DSPCLK_GATE_D);
+               val &= ~DPOUNIT_CLOCK_GATE_DISABLE;
+               I915_WRITE(DSPCLK_GATE_D, val);
+       }
+
+       /* Assert reset */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
+
+       /* Power off, try both CRC pmic gpio and VBT */
+       intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
+       if (intel_dsi->gpio_panel)
+               gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0);
+
+       /*
+        * FIXME As we do with eDP, just make a note of the time here
+        * and perform the wait before the next panel power on.
+        */
+       intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
+}
+
+static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       intel_wakeref_t wakeref;
+       enum port port;
+       bool active = false;
+
+       DRM_DEBUG_KMS("\n");
+
+       wakeref = intel_display_power_get_if_enabled(dev_priv,
+                                                    encoder->power_domain);
+       if (!wakeref)
+               return false;
+
+       /*
+        * On Broxton the PLL needs to be enabled with a valid divider
+        * configuration, otherwise accessing DSI registers will hang the
+        * machine. See BSpec North Display Engine registers/MIPI[BXT].
+        */
+       if (IS_GEN9_LP(dev_priv) && !bxt_dsi_pll_is_enabled(dev_priv))
+               goto out_put_power;
+
+       /* XXX: this only works for one DSI output */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               i915_reg_t ctrl_reg = IS_GEN9_LP(dev_priv) ?
+                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+               bool enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
+
+               /*
+                * Due to some hardware limitations on VLV/CHV, the DPI enable
+                * bit in port C control register does not get set. As a
+                * workaround, check pipe B conf instead.
+                */
+               if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
+                   port == PORT_C)
+                       enabled = I915_READ(PIPECONF(PIPE_B)) & PIPECONF_ENABLE;
+
+               /* Try command mode if video mode not enabled */
+               if (!enabled) {
+                       u32 tmp = I915_READ(MIPI_DSI_FUNC_PRG(port));
+                       enabled = tmp & CMD_MODE_DATA_WIDTH_MASK;
+               }
+
+               if (!enabled)
+                       continue;
+
+               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY))
+                       continue;
+
+               if (IS_GEN9_LP(dev_priv)) {
+                       u32 tmp = I915_READ(MIPI_CTRL(port));
+                       tmp &= BXT_PIPE_SELECT_MASK;
+                       tmp >>= BXT_PIPE_SELECT_SHIFT;
+
+                       if (WARN_ON(tmp > PIPE_C))
+                               continue;
+
+                       *pipe = tmp;
+               } else {
+                       *pipe = port == PORT_A ? PIPE_A : PIPE_B;
+               }
+
+               active = true;
+               break;
+       }
+
+out_put_power:
+       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
+
+       return active;
+}
+
+static void bxt_dsi_get_pipe_config(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+       struct drm_display_mode *adjusted_mode_sw;
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       unsigned int lane_count = intel_dsi->lane_count;
+       unsigned int bpp, fmt;
+       enum port port;
+       u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
+       u16 hfp_sw, hsync_sw, hbp_sw;
+       u16 crtc_htotal_sw, crtc_hsync_start_sw, crtc_hsync_end_sw,
+                               crtc_hblank_start_sw, crtc_hblank_end_sw;
+
+       /* FIXME: hw readout should not depend on SW state */
+       adjusted_mode_sw = &crtc->config->base.adjusted_mode;
+
+       /*
+        * Atleast one port is active as encoder->get_config called only if
+        * encoder->get_hw_state() returns true.
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (I915_READ(BXT_MIPI_PORT_CTRL(port)) & DPI_ENABLE)
+                       break;
+       }
+
+       fmt = I915_READ(MIPI_DSI_FUNC_PRG(port)) & VID_MODE_FORMAT_MASK;
+       bpp = mipi_dsi_pixel_format_to_bpp(
+                       pixel_format_from_register_bits(fmt));
+
+       pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
+
+       /* Enable Frame time stamo based scanline reporting */
+       adjusted_mode->private_flags |=
+                       I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP;
+
+       /* In terms of pixels */
+       adjusted_mode->crtc_hdisplay =
+                               I915_READ(BXT_MIPI_TRANS_HACTIVE(port));
+       adjusted_mode->crtc_vdisplay =
+                               I915_READ(BXT_MIPI_TRANS_VACTIVE(port));
+       adjusted_mode->crtc_vtotal =
+                               I915_READ(BXT_MIPI_TRANS_VTOTAL(port));
+
+       hactive = adjusted_mode->crtc_hdisplay;
+       hfp = I915_READ(MIPI_HFP_COUNT(port));
+
+       /*
+        * Meaningful for video mode non-burst sync pulse mode only,
+        * can be zero for non-burst sync events and burst modes
+        */
+       hsync = I915_READ(MIPI_HSYNC_PADDING_COUNT(port));
+       hbp = I915_READ(MIPI_HBP_COUNT(port));
+
+       /* harizontal values are in terms of high speed byte clock */
+       hfp = pixels_from_txbyteclkhs(hfp, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+       hsync = pixels_from_txbyteclkhs(hsync, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+       hbp = pixels_from_txbyteclkhs(hbp, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+
+       if (intel_dsi->dual_link) {
+               hfp *= 2;
+               hsync *= 2;
+               hbp *= 2;
+       }
+
+       /* vertical values are in terms of lines */
+       vfp = I915_READ(MIPI_VFP_COUNT(port));
+       vsync = I915_READ(MIPI_VSYNC_PADDING_COUNT(port));
+       vbp = I915_READ(MIPI_VBP_COUNT(port));
+
+       adjusted_mode->crtc_htotal = hactive + hfp + hsync + hbp;
+       adjusted_mode->crtc_hsync_start = hfp + adjusted_mode->crtc_hdisplay;
+       adjusted_mode->crtc_hsync_end = hsync + adjusted_mode->crtc_hsync_start;
+       adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hdisplay;
+       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal;
+
+       adjusted_mode->crtc_vsync_start = vfp + adjusted_mode->crtc_vdisplay;
+       adjusted_mode->crtc_vsync_end = vsync + adjusted_mode->crtc_vsync_start;
+       adjusted_mode->crtc_vblank_start = adjusted_mode->crtc_vdisplay;
+       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal;
+
+       /*
+        * In BXT DSI there is no regs programmed with few horizontal timings
+        * in Pixels but txbyteclkhs.. So retrieval process adds some
+        * ROUND_UP ERRORS in the process of PIXELS<==>txbyteclkhs.
+        * Actually here for the given adjusted_mode, we are calculating the
+        * value programmed to the port and then back to the horizontal timing
+        * param in pixels. This is the expected value, including roundup errors
+        * And if that is same as retrieved value from port, then
+        * (HW state) adjusted_mode's horizontal timings are corrected to
+        * match with SW state to nullify the errors.
+        */
+       /* Calculating the value programmed to the Port register */
+       hfp_sw = adjusted_mode_sw->crtc_hsync_start -
+                                       adjusted_mode_sw->crtc_hdisplay;
+       hsync_sw = adjusted_mode_sw->crtc_hsync_end -
+                                       adjusted_mode_sw->crtc_hsync_start;
+       hbp_sw = adjusted_mode_sw->crtc_htotal -
+                                       adjusted_mode_sw->crtc_hsync_end;
+
+       if (intel_dsi->dual_link) {
+               hfp_sw /= 2;
+               hsync_sw /= 2;
+               hbp_sw /= 2;
+       }
+
+       hfp_sw = txbyteclkhs(hfp_sw, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+       hsync_sw = txbyteclkhs(hsync_sw, bpp, lane_count,
+                           intel_dsi->burst_mode_ratio);
+       hbp_sw = txbyteclkhs(hbp_sw, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+
+       /* Reverse calculating the adjusted mode parameters from port reg vals*/
+       hfp_sw = pixels_from_txbyteclkhs(hfp_sw, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+       hsync_sw = pixels_from_txbyteclkhs(hsync_sw, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+       hbp_sw = pixels_from_txbyteclkhs(hbp_sw, bpp, lane_count,
+                                               intel_dsi->burst_mode_ratio);
+
+       if (intel_dsi->dual_link) {
+               hfp_sw *= 2;
+               hsync_sw *= 2;
+               hbp_sw *= 2;
+       }
+
+       crtc_htotal_sw = adjusted_mode_sw->crtc_hdisplay + hfp_sw +
+                                                       hsync_sw + hbp_sw;
+       crtc_hsync_start_sw = hfp_sw + adjusted_mode_sw->crtc_hdisplay;
+       crtc_hsync_end_sw = hsync_sw + crtc_hsync_start_sw;
+       crtc_hblank_start_sw = adjusted_mode_sw->crtc_hdisplay;
+       crtc_hblank_end_sw = crtc_htotal_sw;
+
+       if (adjusted_mode->crtc_htotal == crtc_htotal_sw)
+               adjusted_mode->crtc_htotal = adjusted_mode_sw->crtc_htotal;
+
+       if (adjusted_mode->crtc_hsync_start == crtc_hsync_start_sw)
+               adjusted_mode->crtc_hsync_start =
+                                       adjusted_mode_sw->crtc_hsync_start;
+
+       if (adjusted_mode->crtc_hsync_end == crtc_hsync_end_sw)
+               adjusted_mode->crtc_hsync_end =
+                                       adjusted_mode_sw->crtc_hsync_end;
+
+       if (adjusted_mode->crtc_hblank_start == crtc_hblank_start_sw)
+               adjusted_mode->crtc_hblank_start =
+                                       adjusted_mode_sw->crtc_hblank_start;
+
+       if (adjusted_mode->crtc_hblank_end == crtc_hblank_end_sw)
+               adjusted_mode->crtc_hblank_end =
+                                       adjusted_mode_sw->crtc_hblank_end;
+}
+
+static void intel_dsi_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 pclk;
+       DRM_DEBUG_KMS("\n");
+
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
+
+       if (IS_GEN9_LP(dev_priv)) {
+               bxt_dsi_get_pipe_config(encoder, pipe_config);
+               pclk = bxt_dsi_get_pclk(encoder, pipe_config);
+       } else {
+               pclk = vlv_dsi_get_pclk(encoder, pipe_config);
+       }
+
+       if (pclk) {
+               pipe_config->base.adjusted_mode.crtc_clock = pclk;
+               pipe_config->port_clock = pclk;
+       }
+}
+
+/* return txclkesc cycles in terms of divider and duration in us */
+static u16 txclkesc(u32 divider, unsigned int us)
+{
+       switch (divider) {
+       case ESCAPE_CLOCK_DIVIDER_1:
+       default:
+               return 20 * us;
+       case ESCAPE_CLOCK_DIVIDER_2:
+               return 10 * us;
+       case ESCAPE_CLOCK_DIVIDER_4:
+               return 5 * us;
+       }
+}
+
+static void set_dsi_timings(struct drm_encoder *encoder,
+                           const struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+       enum port port;
+       unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+       unsigned int lane_count = intel_dsi->lane_count;
+
+       u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
+
+       hactive = adjusted_mode->crtc_hdisplay;
+       hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay;
+       hsync = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+       hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end;
+
+       if (intel_dsi->dual_link) {
+               hactive /= 2;
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+                       hactive += intel_dsi->pixel_overlap;
+               hfp /= 2;
+               hsync /= 2;
+               hbp /= 2;
+       }
+
+       vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay;
+       vsync = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
+       vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end;
+
+       /* horizontal values are in terms of high speed byte clock */
+       hactive = txbyteclkhs(hactive, bpp, lane_count,
+                             intel_dsi->burst_mode_ratio);
+       hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio);
+       hsync = txbyteclkhs(hsync, bpp, lane_count,
+                           intel_dsi->burst_mode_ratio);
+       hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (IS_GEN9_LP(dev_priv)) {
+                       /*
+                        * Program hdisplay and vdisplay on MIPI transcoder.
+                        * This is different from calculated hactive and
+                        * vactive, as they are calculated per channel basis,
+                        * whereas these values should be based on resolution.
+                        */
+                       I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port),
+                                  adjusted_mode->crtc_hdisplay);
+                       I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port),
+                                  adjusted_mode->crtc_vdisplay);
+                       I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port),
+                                  adjusted_mode->crtc_vtotal);
+               }
+
+               I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
+               I915_WRITE(MIPI_HFP_COUNT(port), hfp);
+
+               /* meaningful for video mode non-burst sync pulse mode only,
+                * can be zero for non-burst sync events and burst modes */
+               I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync);
+               I915_WRITE(MIPI_HBP_COUNT(port), hbp);
+
+               /* vertical values are in terms of lines */
+               I915_WRITE(MIPI_VFP_COUNT(port), vfp);
+               I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync);
+               I915_WRITE(MIPI_VBP_COUNT(port), vbp);
+       }
+}
+
+static u32 pixel_format_to_reg(enum mipi_dsi_pixel_format fmt)
+{
+       switch (fmt) {
+       case MIPI_DSI_FMT_RGB888:
+               return VID_MODE_FORMAT_RGB888;
+       case MIPI_DSI_FMT_RGB666:
+               return VID_MODE_FORMAT_RGB666;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+               return VID_MODE_FORMAT_RGB666_PACKED;
+       case MIPI_DSI_FMT_RGB565:
+               return VID_MODE_FORMAT_RGB565;
+       default:
+               MISSING_CASE(fmt);
+               return VID_MODE_FORMAT_RGB666;
+       }
+}
+
+static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
+                             const struct intel_crtc_state *pipe_config)
+{
+       struct drm_encoder *encoder = &intel_encoder->base;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       enum port port;
+       unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+       u32 val, tmp;
+       u16 mode_hdisplay;
+
+       DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
+
+       mode_hdisplay = adjusted_mode->crtc_hdisplay;
+
+       if (intel_dsi->dual_link) {
+               mode_hdisplay /= 2;
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+                       mode_hdisplay += intel_dsi->pixel_overlap;
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+                       /*
+                        * escape clock divider, 20MHz, shared for A and C.
+                        * device ready must be off when doing this! txclkesc?
+                        */
+                       tmp = I915_READ(MIPI_CTRL(PORT_A));
+                       tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+                       I915_WRITE(MIPI_CTRL(PORT_A), tmp |
+                                       ESCAPE_CLOCK_DIVIDER_1);
+
+                       /* read request priority is per pipe */
+                       tmp = I915_READ(MIPI_CTRL(port));
+                       tmp &= ~READ_REQUEST_PRIORITY_MASK;
+                       I915_WRITE(MIPI_CTRL(port), tmp |
+                                       READ_REQUEST_PRIORITY_HIGH);
+               } else if (IS_GEN9_LP(dev_priv)) {
+                       enum pipe pipe = intel_crtc->pipe;
+
+                       tmp = I915_READ(MIPI_CTRL(port));
+                       tmp &= ~BXT_PIPE_SELECT_MASK;
+
+                       tmp |= BXT_PIPE_SELECT(pipe);
+                       I915_WRITE(MIPI_CTRL(port), tmp);
+               }
+
+               /* XXX: why here, why like this? handling in irq handler?! */
+               I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
+               I915_WRITE(MIPI_INTR_EN(port), 0xffffffff);
+
+               I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
+
+               I915_WRITE(MIPI_DPI_RESOLUTION(port),
+                       adjusted_mode->crtc_vdisplay << VERTICAL_ADDRESS_SHIFT |
+                       mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
+       }
+
+       set_dsi_timings(encoder, adjusted_mode);
+
+       val = intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT;
+       if (is_cmd_mode(intel_dsi)) {
+               val |= intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT;
+               val |= CMD_MODE_DATA_WIDTH_8_BIT; /* XXX */
+       } else {
+               val |= intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT;
+               val |= pixel_format_to_reg(intel_dsi->pixel_format);
+       }
+
+       tmp = 0;
+       if (intel_dsi->eotp_pkt == 0)
+               tmp |= EOT_DISABLE;
+       if (intel_dsi->clock_stop)
+               tmp |= CLOCKSTOP;
+
+       if (IS_GEN9_LP(dev_priv)) {
+               tmp |= BXT_DPHY_DEFEATURE_EN;
+               if (!is_cmd_mode(intel_dsi))
+                       tmp |= BXT_DEFEATURE_DPI_FIFO_CTR;
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
+
+               /* timeouts for recovery. one frame IIUC. if counter expires,
+                * EOT and stop state. */
+
+               /*
+                * In burst mode, value greater than one DPI line Time in byte
+                * clock (txbyteclkhs) To timeout this timer 1+ of the above
+                * said value is recommended.
+                *
+                * In non-burst mode, Value greater than one DPI frame time in
+                * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
+                * said value is recommended.
+                *
+                * In DBI only mode, value greater than one DBI frame time in
+                * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
+                * said value is recommended.
+                */
+
+               if (is_vid_mode(intel_dsi) &&
+                       intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
+                       I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
+                               txbyteclkhs(adjusted_mode->crtc_htotal, bpp,
+                                           intel_dsi->lane_count,
+                                           intel_dsi->burst_mode_ratio) + 1);
+               } else {
+                       I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
+                               txbyteclkhs(adjusted_mode->crtc_vtotal *
+                                           adjusted_mode->crtc_htotal,
+                                           bpp, intel_dsi->lane_count,
+                                           intel_dsi->burst_mode_ratio) + 1);
+               }
+               I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
+               I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
+                                               intel_dsi->turn_arnd_val);
+               I915_WRITE(MIPI_DEVICE_RESET_TIMER(port),
+                                               intel_dsi->rst_timer_val);
+
+               /* dphy stuff */
+
+               /* in terms of low power clock */
+               I915_WRITE(MIPI_INIT_COUNT(port),
+                               txclkesc(intel_dsi->escape_clk_div, 100));
+
+               if (IS_GEN9_LP(dev_priv) && (!intel_dsi->dual_link)) {
+                       /*
+                        * BXT spec says write MIPI_INIT_COUNT for
+                        * both the ports, even if only one is
+                        * getting used. So write the other port
+                        * if not in dual link mode.
+                        */
+                       I915_WRITE(MIPI_INIT_COUNT(port ==
+                                               PORT_A ? PORT_C : PORT_A),
+                                       intel_dsi->init_count);
+               }
+
+               /* recovery disables */
+               I915_WRITE(MIPI_EOT_DISABLE(port), tmp);
+
+               /* in terms of low power clock */
+               I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
+
+               /* in terms of txbyteclkhs. actual high to low switch +
+                * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
+                *
+                * XXX: write MIPI_STOP_STATE_STALL?
+                */
+               I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port),
+                                               intel_dsi->hs_to_lp_count);
+
+               /* XXX: low power clock equivalence in terms of byte clock.
+                * the number of byte clocks occupied in one low power clock.
+                * based on txbyteclkhs and txclkesc.
+                * txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL
+                * ) / 105.???
+                */
+               I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk);
+
+               if (IS_GEMINILAKE(dev_priv)) {
+                       I915_WRITE(MIPI_TLPX_TIME_COUNT(port),
+                                       intel_dsi->lp_byte_clk);
+                       /* Shadow of DPHY reg */
+                       I915_WRITE(MIPI_CLK_LANE_TIMING(port),
+                                       intel_dsi->dphy_reg);
+               }
+
+               /* the bw essential for transmitting 16 long packets containing
+                * 252 bytes meant for dcs write memory command is programmed in
+                * this register in terms of byte clocks. based on dsi transfer
+                * rate and the number of lanes configured the time taken to
+                * transmit 16 long packets in a dsi stream varies. */
+               I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer);
+
+               I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port),
+               intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
+               intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
+
+               if (is_vid_mode(intel_dsi))
+                       /* Some panels might have resolution which is not a
+                        * multiple of 64 like 1366 x 768. Enable RANDOM
+                        * resolution support for such panels by default */
+                       I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port),
+                               intel_dsi->video_frmt_cfg_bits |
+                               intel_dsi->video_mode_format |
+                               IP_TG_CONFIG |
+                               RANDOM_DPI_DISPLAY_RESOLUTION);
+       }
+}
+
+static void intel_dsi_unprepare(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       if (IS_GEMINILAKE(dev_priv))
+               return;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               /* Panel commands can be sent when clock is in LP11 */
+               I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
+
+               if (IS_GEN9_LP(dev_priv))
+                       bxt_dsi_reset_clocks(encoder, port);
+               else
+                       vlv_dsi_reset_clocks(encoder, port);
+               I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
+
+               val = I915_READ(MIPI_DSI_FUNC_PRG(port));
+               val &= ~VID_MODE_FORMAT_MASK;
+               I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
+
+               I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
+       }
+}
+
+static void intel_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+
+       /* dispose of the gpios */
+       if (intel_dsi->gpio_panel)
+               gpiod_put(intel_dsi->gpio_panel);
+
+       intel_encoder_destroy(encoder);
+}
+
+static const struct drm_encoder_funcs intel_dsi_funcs = {
+       .destroy = intel_dsi_encoder_destroy,
+};
+
+static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = {
+       .get_modes = intel_dsi_get_modes,
+       .mode_valid = intel_dsi_mode_valid,
+       .atomic_check = intel_digital_connector_atomic_check,
+};
+
+static const struct drm_connector_funcs intel_dsi_connector_funcs = {
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static enum drm_panel_orientation
+vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_encoder *encoder = connector->encoder;
+       enum intel_display_power_domain power_domain;
+       enum drm_panel_orientation orientation;
+       struct intel_plane *plane;
+       struct intel_crtc *crtc;
+       intel_wakeref_t wakeref;
+       enum pipe pipe;
+       u32 val;
+
+       if (!encoder->get_hw_state(encoder, &pipe))
+               return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+
+       crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+       plane = to_intel_plane(crtc->base.primary);
+
+       power_domain = POWER_DOMAIN_PIPE(pipe);
+       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+       if (!wakeref)
+               return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+
+       val = I915_READ(DSPCNTR(plane->i9xx_plane));
+
+       if (!(val & DISPLAY_PLANE_ENABLE))
+               orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+       else if (val & DISPPLANE_ROTATE_180)
+               orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+       else
+               orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+
+       intel_display_power_put(dev_priv, power_domain, wakeref);
+
+       return orientation;
+}
+
+static enum drm_panel_orientation
+vlv_dsi_get_panel_orientation(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum drm_panel_orientation orientation;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               orientation = vlv_dsi_get_hw_panel_orientation(connector);
+               if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+                       return orientation;
+       }
+
+       return intel_dsi_get_panel_orientation(connector);
+}
+
+static void intel_dsi_add_properties(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       if (connector->panel.fixed_mode) {
+               u32 allowed_scalers;
+
+               allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
+               if (!HAS_GMCH(dev_priv))
+                       allowed_scalers |= 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 =
+                       vlv_dsi_get_panel_orientation(connector);
+               drm_connector_init_panel_orientation_property(
+                               &connector->base,
+                               connector->panel.fixed_mode->hdisplay,
+                               connector->panel.fixed_mode->vdisplay);
+       }
+}
+
+#define NS_KHZ_RATIO           1000000
+
+#define PREPARE_CNT_MAX                0x3F
+#define EXIT_ZERO_CNT_MAX      0x3F
+#define CLK_ZERO_CNT_MAX       0xFF
+#define TRAIL_CNT_MAX          0x1F
+
+static void vlv_dphy_param_init(struct intel_dsi *intel_dsi)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
+       u32 tlpx_ns, extra_byte_count, tlpx_ui;
+       u32 ui_num, ui_den;
+       u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
+       u32 ths_prepare_ns, tclk_trail_ns;
+       u32 tclk_prepare_clkzero, ths_prepare_hszero;
+       u32 lp_to_hs_switch, hs_to_lp_switch;
+       u32 mul;
+
+       tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
+
+       switch (intel_dsi->lane_count) {
+       case 1:
+       case 2:
+               extra_byte_count = 2;
+               break;
+       case 3:
+               extra_byte_count = 4;
+               break;
+       case 4:
+       default:
+               extra_byte_count = 3;
+               break;
+       }
+
+       /* in Kbps */
+       ui_num = NS_KHZ_RATIO;
+       ui_den = intel_dsi_bitrate(intel_dsi);
+
+       tclk_prepare_clkzero = mipi_config->tclk_prepare_clkzero;
+       ths_prepare_hszero = mipi_config->ths_prepare_hszero;
+
+       /*
+        * B060
+        * LP byte clock = TLPX/ (8UI)
+        */
+       intel_dsi->lp_byte_clk = DIV_ROUND_UP(tlpx_ns * ui_den, 8 * ui_num);
+
+       /* DDR clock period = 2 * UI
+        * UI(sec) = 1/(bitrate * 10^3) (bitrate is in KHZ)
+        * UI(nsec) = 10^6 / bitrate
+        * DDR clock period (nsec) = 2 * UI = (2 * 10^6)/ bitrate
+        * DDR clock count  = ns_value / DDR clock period
+        *
+        * For GEMINILAKE dphy_param_reg will be programmed in terms of
+        * HS byte clock count for other platform in HS ddr clock count
+        */
+       mul = IS_GEMINILAKE(dev_priv) ? 8 : 2;
+       ths_prepare_ns = max(mipi_config->ths_prepare,
+                            mipi_config->tclk_prepare);
+
+       /* prepare count */
+       prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * ui_den, ui_num * mul);
+
+       if (prepare_cnt > PREPARE_CNT_MAX) {
+               DRM_DEBUG_KMS("prepare count too high %u\n", prepare_cnt);
+               prepare_cnt = PREPARE_CNT_MAX;
+       }
+
+       /* exit zero count */
+       exit_zero_cnt = DIV_ROUND_UP(
+                               (ths_prepare_hszero - ths_prepare_ns) * ui_den,
+                               ui_num * mul
+                               );
+
+       /*
+        * Exit zero is unified val ths_zero and ths_exit
+        * minimum value for ths_exit = 110ns
+        * min (exit_zero_cnt * 2) = 110/UI
+        * exit_zero_cnt = 55/UI
+        */
+       if (exit_zero_cnt < (55 * ui_den / ui_num) && (55 * ui_den) % ui_num)
+               exit_zero_cnt += 1;
+
+       if (exit_zero_cnt > EXIT_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("exit zero count too high %u\n", exit_zero_cnt);
+               exit_zero_cnt = EXIT_ZERO_CNT_MAX;
+       }
+
+       /* clk zero count */
+       clk_zero_cnt = DIV_ROUND_UP(
+                               (tclk_prepare_clkzero - ths_prepare_ns)
+                               * ui_den, ui_num * mul);
+
+       if (clk_zero_cnt > CLK_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("clock zero count too high %u\n", clk_zero_cnt);
+               clk_zero_cnt = CLK_ZERO_CNT_MAX;
+       }
+
+       /* trail count */
+       tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail);
+       trail_cnt = DIV_ROUND_UP(tclk_trail_ns * ui_den, ui_num * mul);
+
+       if (trail_cnt > TRAIL_CNT_MAX) {
+               DRM_DEBUG_KMS("trail count too high %u\n", trail_cnt);
+               trail_cnt = TRAIL_CNT_MAX;
+       }
+
+       /* B080 */
+       intel_dsi->dphy_reg = exit_zero_cnt << 24 | trail_cnt << 16 |
+                                               clk_zero_cnt << 8 | prepare_cnt;
+
+       /*
+        * LP to HS switch count = 4TLPX + PREP_COUNT * mul + EXIT_ZERO_COUNT *
+        *                                      mul + 10UI + Extra Byte Count
+        *
+        * HS to LP switch count = THS-TRAIL + 2TLPX + Extra Byte Count
+        * Extra Byte Count is calculated according to number of lanes.
+        * High Low Switch Count is the Max of LP to HS and
+        * HS to LP switch count
+        *
+        */
+       tlpx_ui = DIV_ROUND_UP(tlpx_ns * ui_den, ui_num);
+
+       /* B044 */
+       /* FIXME:
+        * The comment above does not match with the code */
+       lp_to_hs_switch = DIV_ROUND_UP(4 * tlpx_ui + prepare_cnt * mul +
+                                               exit_zero_cnt * mul + 10, 8);
+
+       hs_to_lp_switch = DIV_ROUND_UP(mipi_config->ths_trail + 2 * tlpx_ui, 8);
+
+       intel_dsi->hs_to_lp_count = max(lp_to_hs_switch, hs_to_lp_switch);
+       intel_dsi->hs_to_lp_count += extra_byte_count;
+
+       /* B088 */
+       /* LP -> HS for clock lanes
+        * LP clk sync + LP11 + LP01 + tclk_prepare + tclk_zero +
+        *                                              extra byte count
+        * 2TPLX + 1TLPX + 1 TPLX(in ns) + prepare_cnt * 2 + clk_zero_cnt *
+        *                                      2(in UI) + extra byte count
+        * In byteclks = (4TLPX + prepare_cnt * 2 + clk_zero_cnt *2 (in UI)) /
+        *                                      8 + extra byte count
+        */
+       intel_dsi->clk_lp_to_hs_count =
+               DIV_ROUND_UP(
+                       4 * tlpx_ui + prepare_cnt * 2 +
+                       clk_zero_cnt * 2,
+                       8);
+
+       intel_dsi->clk_lp_to_hs_count += extra_byte_count;
+
+       /* HS->LP for Clock Lanes
+        * Low Power clock synchronisations + 1Tx byteclk + tclk_trail +
+        *                                              Extra byte count
+        * 2TLPX + 8UI + (trail_count*2)(in UI) + Extra byte count
+        * In byteclks = (2*TLpx(in UI) + trail_count*2 +8)(in UI)/8 +
+        *                                              Extra byte count
+        */
+       intel_dsi->clk_hs_to_lp_count =
+               DIV_ROUND_UP(2 * tlpx_ui + trail_cnt * 2 + 8,
+                       8);
+       intel_dsi->clk_hs_to_lp_count += extra_byte_count;
+
+       intel_dsi_log_params(intel_dsi);
+}
+
+void vlv_dsi_init(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = &dev_priv->drm;
+       struct intel_dsi *intel_dsi;
+       struct intel_encoder *intel_encoder;
+       struct drm_encoder *encoder;
+       struct intel_connector *intel_connector;
+       struct drm_connector *connector;
+       struct drm_display_mode *current_mode, *fixed_mode;
+       enum port port;
+
+       DRM_DEBUG_KMS("\n");
+
+       /* There is no detection method for MIPI so rely on VBT */
+       if (!intel_bios_is_dsi_present(dev_priv, &port))
+               return;
+
+       if (IS_GEN9_LP(dev_priv))
+               dev_priv->mipi_mmio_base = BXT_MIPI_BASE;
+       else
+               dev_priv->mipi_mmio_base = VLV_MIPI_BASE;
+
+       intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
+       if (!intel_dsi)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(intel_dsi);
+               return;
+       }
+
+       intel_encoder = &intel_dsi->base;
+       encoder = &intel_encoder->base;
+       intel_dsi->attached_connector = intel_connector;
+
+       connector = &intel_connector->base;
+
+       drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
+                        "DSI %c", port_name(port));
+
+       intel_encoder->compute_config = intel_dsi_compute_config;
+       intel_encoder->pre_enable = intel_dsi_pre_enable;
+       intel_encoder->disable = intel_dsi_disable;
+       intel_encoder->post_disable = intel_dsi_post_disable;
+       intel_encoder->get_hw_state = intel_dsi_get_hw_state;
+       intel_encoder->get_config = intel_dsi_get_config;
+       intel_encoder->update_pipe = intel_panel_update_backlight;
+
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       intel_encoder->port = port;
+       intel_encoder->type = INTEL_OUTPUT_DSI;
+       intel_encoder->power_domain = POWER_DOMAIN_PORT_DSI;
+       intel_encoder->cloneable = 0;
+
+       /*
+        * On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI
+        * port C. BXT isn't limited like this.
+        */
+       if (IS_GEN9_LP(dev_priv))
+               intel_encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C);
+       else if (port == PORT_A)
+               intel_encoder->crtc_mask = BIT(PIPE_A);
+       else
+               intel_encoder->crtc_mask = BIT(PIPE_B);
+
+       if (dev_priv->vbt.dsi.config->dual_link)
+               intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C);
+       else
+               intel_dsi->ports = BIT(port);
+
+       intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports;
+       intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports;
+
+       /* Create a DSI host (and a device) for each port. */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               struct intel_dsi_host *host;
+
+               host = intel_dsi_host_init(intel_dsi, &intel_dsi_host_ops,
+                                          port);
+               if (!host)
+                       goto err;
+
+               intel_dsi->dsi_hosts[port] = host;
+       }
+
+       if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
+               DRM_DEBUG_KMS("no device found\n");
+               goto err;
+       }
+
+       /* Use clock read-back from current hw-state for fastboot */
+       current_mode = intel_encoder_current_mode(intel_encoder);
+       if (current_mode) {
+               DRM_DEBUG_KMS("Calculated pclk %d GOP %d\n",
+                             intel_dsi->pclk, current_mode->clock);
+               if (intel_fuzzy_clock_check(intel_dsi->pclk,
+                                           current_mode->clock)) {
+                       DRM_DEBUG_KMS("Using GOP pclk\n");
+                       intel_dsi->pclk = current_mode->clock;
+               }
+
+               kfree(current_mode);
+       }
+
+       vlv_dphy_param_init(intel_dsi);
+
+       /*
+        * In case of BYT with CRC PMIC, we need to use GPIO for
+        * Panel control.
+        */
+       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
+           (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC)) {
+               intel_dsi->gpio_panel =
+                       gpiod_get(dev->dev, "panel", GPIOD_OUT_HIGH);
+
+               if (IS_ERR(intel_dsi->gpio_panel)) {
+                       DRM_ERROR("Failed to own gpio for panel control\n");
+                       intel_dsi->gpio_panel = NULL;
+               }
+       }
+
+       drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
+                          DRM_MODE_CONNECTOR_DSI);
+
+       drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs);
+
+       connector->display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
+
+       mutex_lock(&dev->mode_config.mutex);
+       fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       if (!fixed_mode) {
+               DRM_DEBUG_KMS("no fixed mode\n");
+               goto err_cleanup_connector;
+       }
+
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
+       intel_panel_setup_backlight(connector, INVALID_PIPE);
+
+       intel_dsi_add_properties(intel_connector);
+
+       return;
+
+err_cleanup_connector:
+       drm_connector_cleanup(&intel_connector->base);
+err:
+       drm_encoder_cleanup(&intel_encoder->base);
+       kfree(intel_dsi);
+       kfree(intel_connector);
+}
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c
new file mode 100644 (file)
index 0000000..99cc3e2
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Shobhit Kumar <shobhit.kumar@intel.com>
+ *     Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com>
+ */
+
+#include <linux/kernel.h>
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "intel_sideband.h"
+
+static const u16 lfsr_converts[] = {
+       426, 469, 234, 373, 442, 221, 110, 311, 411,            /* 62 - 70 */
+       461, 486, 243, 377, 188, 350, 175, 343, 427, 213,       /* 71 - 80 */
+       106, 53, 282, 397, 454, 227, 113, 56, 284, 142,         /* 81 - 90 */
+       71, 35, 273, 136, 324, 418, 465, 488, 500, 506          /* 91 - 100 */
+};
+
+/* Get DSI clock from pixel clock */
+static u32 dsi_clk_from_pclk(u32 pclk, enum mipi_dsi_pixel_format fmt,
+                            int lane_count)
+{
+       u32 dsi_clk_khz;
+       u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt);
+
+       /* DSI data rate = pixel clock * bits per pixel / lane count
+          pixel clock is converted from KHz to Hz */
+       dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count);
+
+       return dsi_clk_khz;
+}
+
+static int dsi_calc_mnp(struct drm_i915_private *dev_priv,
+                       struct intel_crtc_state *config,
+                       int target_dsi_clk)
+{
+       unsigned int m_min, m_max, p_min = 2, p_max = 6;
+       unsigned int m, n, p;
+       unsigned int calc_m, calc_p;
+       int delta, ref_clk;
+
+       /* target_dsi_clk is expected in kHz */
+       if (target_dsi_clk < 300000 || target_dsi_clk > 1150000) {
+               DRM_ERROR("DSI CLK Out of Range\n");
+               return -ECHRNG;
+       }
+
+       if (IS_CHERRYVIEW(dev_priv)) {
+               ref_clk = 100000;
+               n = 4;
+               m_min = 70;
+               m_max = 96;
+       } else {
+               ref_clk = 25000;
+               n = 1;
+               m_min = 62;
+               m_max = 92;
+       }
+
+       calc_p = p_min;
+       calc_m = m_min;
+       delta = abs(target_dsi_clk - (m_min * ref_clk) / (p_min * n));
+
+       for (m = m_min; m <= m_max && delta; m++) {
+               for (p = p_min; p <= p_max && delta; p++) {
+                       /*
+                        * Find the optimal m and p divisors with minimal delta
+                        * +/- the required clock
+                        */
+                       int calc_dsi_clk = (m * ref_clk) / (p * n);
+                       int d = abs(target_dsi_clk - calc_dsi_clk);
+                       if (d < delta) {
+                               delta = d;
+                               calc_m = m;
+                               calc_p = p;
+                       }
+               }
+       }
+
+       /* register has log2(N1), this works fine for powers of two */
+       config->dsi_pll.ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2);
+       config->dsi_pll.div =
+               (ffs(n) - 1) << DSI_PLL_N1_DIV_SHIFT |
+               (u32)lfsr_converts[calc_m - 62] << DSI_PLL_M1_DIV_SHIFT;
+
+       return 0;
+}
+
+/*
+ * XXX: The muxing and gating is hard coded for now. Need to add support for
+ * sharing PLLs with two DSI outputs.
+ */
+int vlv_dsi_pll_compute(struct intel_encoder *encoder,
+                       struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       int ret;
+       u32 dsi_clk;
+
+       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
+                                   intel_dsi->lane_count);
+
+       ret = dsi_calc_mnp(dev_priv, config, dsi_clk);
+       if (ret) {
+               DRM_DEBUG_KMS("dsi_calc_mnp failed\n");
+               return ret;
+       }
+
+       if (intel_dsi->ports & (1 << PORT_A))
+               config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+
+       if (intel_dsi->ports & (1 << PORT_C))
+               config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
+
+       config->dsi_pll.ctrl |= DSI_PLL_VCO_EN;
+
+       DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
+                     config->dsi_pll.div, config->dsi_pll.ctrl);
+
+       return 0;
+}
+
+void vlv_dsi_pll_enable(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       DRM_DEBUG_KMS("\n");
+
+       vlv_cck_get(dev_priv);
+
+       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0);
+       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div);
+       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL,
+                     config->dsi_pll.ctrl & ~DSI_PLL_VCO_EN);
+
+       /* wait at least 0.5 us after ungating before enabling VCO,
+        * allow hrtimer subsystem optimization by relaxing timing
+        */
+       usleep_range(10, 50);
+
+       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl);
+
+       if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
+                                               DSI_PLL_LOCK, 20)) {
+
+               vlv_cck_put(dev_priv);
+               DRM_ERROR("DSI PLL lock failed\n");
+               return;
+       }
+       vlv_cck_put(dev_priv);
+
+       DRM_DEBUG_KMS("DSI PLL locked\n");
+}
+
+void vlv_dsi_pll_disable(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 tmp;
+
+       DRM_DEBUG_KMS("\n");
+
+       vlv_cck_get(dev_priv);
+
+       tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
+       tmp &= ~DSI_PLL_VCO_EN;
+       tmp |= DSI_PLL_LDO_GATE;
+       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
+
+       vlv_cck_put(dev_priv);
+}
+
+bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
+{
+       bool enabled;
+       u32 val;
+       u32 mask;
+
+       mask = BXT_DSI_PLL_DO_ENABLE | BXT_DSI_PLL_LOCKED;
+       val = I915_READ(BXT_DSI_PLL_ENABLE);
+       enabled = (val & mask) == mask;
+
+       if (!enabled)
+               return false;
+
+       /*
+        * Dividers must be programmed with valid values. As per BSEPC, for
+        * GEMINLAKE only PORT A divider values are checked while for BXT
+        * both divider values are validated. Check this here for
+        * paranoia, since BIOS is known to misconfigure PLLs in this way at
+        * times, and since accessing DSI registers with invalid dividers
+        * causes a system hang.
+        */
+       val = I915_READ(BXT_DSI_PLL_CTL);
+       if (IS_GEMINILAKE(dev_priv)) {
+               if (!(val & BXT_DSIA_16X_MASK)) {
+                       DRM_DEBUG_DRIVER("Invalid PLL divider (%08x)\n", val);
+                       enabled = false;
+               }
+       } else {
+               if (!(val & BXT_DSIA_16X_MASK) || !(val & BXT_DSIC_16X_MASK)) {
+                       DRM_DEBUG_DRIVER("Invalid PLL divider (%08x)\n", val);
+                       enabled = false;
+               }
+       }
+
+       return enabled;
+}
+
+void bxt_dsi_pll_disable(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val;
+
+       DRM_DEBUG_KMS("\n");
+
+       val = I915_READ(BXT_DSI_PLL_ENABLE);
+       val &= ~BXT_DSI_PLL_DO_ENABLE;
+       I915_WRITE(BXT_DSI_PLL_ENABLE, val);
+
+       /*
+        * PLL lock should deassert within 200us.
+        * Wait up to 1ms before timing out.
+        */
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   BXT_DSI_PLL_ENABLE,
+                                   BXT_DSI_PLL_LOCKED,
+                                   0,
+                                   1))
+               DRM_ERROR("Timeout waiting for PLL lock deassertion\n");
+}
+
+u32 vlv_dsi_get_pclk(struct intel_encoder *encoder,
+                    struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+       u32 dsi_clock, pclk;
+       u32 pll_ctl, pll_div;
+       u32 m = 0, p = 0, n;
+       int refclk = IS_CHERRYVIEW(dev_priv) ? 100000 : 25000;
+       int i;
+
+       DRM_DEBUG_KMS("\n");
+
+       vlv_cck_get(dev_priv);
+       pll_ctl = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
+       pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER);
+       vlv_cck_put(dev_priv);
+
+       config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK;
+       config->dsi_pll.div = pll_div;
+
+       /* mask out other bits and extract the P1 divisor */
+       pll_ctl &= DSI_PLL_P1_POST_DIV_MASK;
+       pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2);
+
+       /* N1 divisor */
+       n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT;
+       n = 1 << n; /* register has log2(N1) */
+
+       /* mask out the other bits and extract the M1 divisor */
+       pll_div &= DSI_PLL_M1_DIV_MASK;
+       pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT;
+
+       while (pll_ctl) {
+               pll_ctl = pll_ctl >> 1;
+               p++;
+       }
+       p--;
+
+       if (!p) {
+               DRM_ERROR("wrong P1 divisor\n");
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) {
+               if (lfsr_converts[i] == pll_div)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(lfsr_converts)) {
+               DRM_ERROR("wrong m_seed programmed\n");
+               return 0;
+       }
+
+       m = i + 62;
+
+       dsi_clock = (m * refclk) / (p * n);
+
+       pclk = DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, bpp);
+
+       return pclk;
+}
+
+u32 bxt_dsi_get_pclk(struct intel_encoder *encoder,
+                    struct intel_crtc_state *config)
+{
+       u32 pclk;
+       u32 dsi_clk;
+       u32 dsi_ratio;
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+
+       config->dsi_pll.ctrl = I915_READ(BXT_DSI_PLL_CTL);
+
+       dsi_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
+
+       dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2;
+
+       pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, bpp);
+
+       DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk);
+       return pclk;
+}
+
+void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
+{
+       u32 temp;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       temp = I915_READ(MIPI_CTRL(port));
+       temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+       I915_WRITE(MIPI_CTRL(port), temp |
+                       intel_dsi->escape_clk_div <<
+                       ESCAPE_CLOCK_DIVIDER_SHIFT);
+}
+
+static void glk_dsi_program_esc_clock(struct drm_device *dev,
+                                  const struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 dsi_rate = 0;
+       u32 pll_ratio = 0;
+       u32 ddr_clk = 0;
+       u32 div1_value = 0;
+       u32 div2_value = 0;
+       u32 txesc1_div = 0;
+       u32 txesc2_div = 0;
+
+       pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
+
+       dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
+
+       ddr_clk = dsi_rate / 2;
+
+       /* Variable divider value */
+       div1_value = DIV_ROUND_CLOSEST(ddr_clk, 20000);
+
+       /* Calculate TXESC1 divider */
+       if (div1_value <= 10)
+               txesc1_div = div1_value;
+       else if ((div1_value > 10) && (div1_value <= 20))
+               txesc1_div = DIV_ROUND_UP(div1_value, 2);
+       else if ((div1_value > 20) && (div1_value <= 30))
+               txesc1_div = DIV_ROUND_UP(div1_value, 4);
+       else if ((div1_value > 30) && (div1_value <= 40))
+               txesc1_div = DIV_ROUND_UP(div1_value, 6);
+       else if ((div1_value > 40) && (div1_value <= 50))
+               txesc1_div = DIV_ROUND_UP(div1_value, 8);
+       else
+               txesc1_div = 10;
+
+       /* Calculate TXESC2 divider */
+       div2_value = DIV_ROUND_UP(div1_value, txesc1_div);
+
+       if (div2_value < 10)
+               txesc2_div = div2_value;
+       else
+               txesc2_div = 10;
+
+       I915_WRITE(MIPIO_TXESC_CLK_DIV1, txesc1_div & GLK_TX_ESC_CLK_DIV1_MASK);
+       I915_WRITE(MIPIO_TXESC_CLK_DIV2, txesc2_div & GLK_TX_ESC_CLK_DIV2_MASK);
+}
+
+/* Program BXT Mipi clocks and dividers */
+static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port,
+                                  const struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 tmp;
+       u32 dsi_rate = 0;
+       u32 pll_ratio = 0;
+       u32 rx_div;
+       u32 tx_div;
+       u32 rx_div_upper;
+       u32 rx_div_lower;
+       u32 mipi_8by3_divider;
+
+       /* Clear old configurations */
+       tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
+       tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
+       tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port));
+       tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port));
+       tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port));
+
+       /* Get the current DSI rate(actual) */
+       pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
+       dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
+
+       /*
+        * tx clock should be <= 20MHz and the div value must be
+        * subtracted by 1 as per bspec
+        */
+       tx_div = DIV_ROUND_UP(dsi_rate, 20000) - 1;
+       /*
+        * rx clock should be <= 150MHz and the div value must be
+        * subtracted by 1 as per bspec
+        */
+       rx_div = DIV_ROUND_UP(dsi_rate, 150000) - 1;
+
+       /*
+        * rx divider value needs to be updated in the
+        * two differnt bit fields in the register hence splitting the
+        * rx divider value accordingly
+        */
+       rx_div_lower = rx_div & RX_DIVIDER_BIT_1_2;
+       rx_div_upper = (rx_div & RX_DIVIDER_BIT_3_4) >> 2;
+
+       mipi_8by3_divider = 0x2;
+
+       tmp |= BXT_MIPI_8X_BY3_DIVIDER(port, mipi_8by3_divider);
+       tmp |= BXT_MIPI_TX_ESCLK_DIVIDER(port, tx_div);
+       tmp |= BXT_MIPI_RX_ESCLK_LOWER_DIVIDER(port, rx_div_lower);
+       tmp |= BXT_MIPI_RX_ESCLK_UPPER_DIVIDER(port, rx_div_upper);
+
+       I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
+}
+
+int bxt_dsi_pll_compute(struct intel_encoder *encoder,
+                       struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u8 dsi_ratio, dsi_ratio_min, dsi_ratio_max;
+       u32 dsi_clk;
+
+       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
+                                   intel_dsi->lane_count);
+
+       /*
+        * From clock diagram, to get PLL ratio divider, divide double of DSI
+        * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to
+        * round 'up' the result
+        */
+       dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ);
+
+       if (IS_BROXTON(dev_priv)) {
+               dsi_ratio_min = BXT_DSI_PLL_RATIO_MIN;
+               dsi_ratio_max = BXT_DSI_PLL_RATIO_MAX;
+       } else {
+               dsi_ratio_min = GLK_DSI_PLL_RATIO_MIN;
+               dsi_ratio_max = GLK_DSI_PLL_RATIO_MAX;
+       }
+
+       if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) {
+               DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n");
+               return -ECHRNG;
+       } else
+               DRM_DEBUG_KMS("DSI PLL calculation is Done!!\n");
+
+       /*
+        * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x
+        * Spec says both have to be programmed, even if one is not getting
+        * used. Configure MIPI_CLOCK_CTL dividers in modeset
+        */
+       config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2;
+
+       /* As per recommendation from hardware team,
+        * Prog PVD ratio =1 if dsi ratio <= 50
+        */
+       if (IS_BROXTON(dev_priv) && dsi_ratio <= 50)
+               config->dsi_pll.ctrl |= BXT_DSI_PLL_PVD_RATIO_1;
+
+       return 0;
+}
+
+void bxt_dsi_pll_enable(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 val;
+
+       DRM_DEBUG_KMS("\n");
+
+       /* Configure PLL vales */
+       I915_WRITE(BXT_DSI_PLL_CTL, config->dsi_pll.ctrl);
+       POSTING_READ(BXT_DSI_PLL_CTL);
+
+       /* Program TX, RX, Dphy clocks */
+       if (IS_BROXTON(dev_priv)) {
+               for_each_dsi_port(port, intel_dsi->ports)
+                       bxt_dsi_program_clocks(encoder->base.dev, port, config);
+       } else {
+               glk_dsi_program_esc_clock(encoder->base.dev, config);
+       }
+
+       /* Enable DSI PLL */
+       val = I915_READ(BXT_DSI_PLL_ENABLE);
+       val |= BXT_DSI_PLL_DO_ENABLE;
+       I915_WRITE(BXT_DSI_PLL_ENABLE, val);
+
+       /* Timeout and fail if PLL not locked */
+       if (intel_wait_for_register(&dev_priv->uncore,
+                                   BXT_DSI_PLL_ENABLE,
+                                   BXT_DSI_PLL_LOCKED,
+                                   BXT_DSI_PLL_LOCKED,
+                                   1)) {
+               DRM_ERROR("Timed out waiting for DSI PLL to lock\n");
+               return;
+       }
+
+       DRM_DEBUG_KMS("DSI PLL locked\n");
+}
+
+void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
+{
+       u32 tmp;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       /* Clear old configurations */
+       if (IS_BROXTON(dev_priv)) {
+               tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
+               tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
+               tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port));
+               tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port));
+               tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port));
+               I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
+       } else {
+               tmp = I915_READ(MIPIO_TXESC_CLK_DIV1);
+               tmp &= ~GLK_TX_ESC_CLK_DIV1_MASK;
+               I915_WRITE(MIPIO_TXESC_CLK_DIV1, tmp);
+
+               tmp = I915_READ(MIPIO_TXESC_CLK_DIV2);
+               tmp &= ~GLK_TX_ESC_CLK_DIV2_MASK;
+               I915_WRITE(MIPIO_TXESC_CLK_DIV2, tmp);
+       }
+       I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
+}
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
deleted file mode 100644 (file)
index 602380f..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include "intel_drv.h"
-#include "intel_dvo_dev.h"
-
-#define CH7017_TV_DISPLAY_MODE         0x00
-#define CH7017_FLICKER_FILTER          0x01
-#define CH7017_VIDEO_BANDWIDTH         0x02
-#define CH7017_TEXT_ENHANCEMENT                0x03
-#define CH7017_START_ACTIVE_VIDEO      0x04
-#define CH7017_HORIZONTAL_POSITION     0x05
-#define CH7017_VERTICAL_POSITION       0x06
-#define CH7017_BLACK_LEVEL             0x07
-#define CH7017_CONTRAST_ENHANCEMENT    0x08
-#define CH7017_TV_PLL                  0x09
-#define CH7017_TV_PLL_M                        0x0a
-#define CH7017_TV_PLL_N                        0x0b
-#define CH7017_SUB_CARRIER_0           0x0c
-#define CH7017_CIV_CONTROL             0x10
-#define CH7017_CIV_0                   0x11
-#define CH7017_CHROMA_BOOST            0x14
-#define CH7017_CLOCK_MODE              0x1c
-#define CH7017_INPUT_CLOCK             0x1d
-#define CH7017_GPIO_CONTROL            0x1e
-#define CH7017_INPUT_DATA_FORMAT       0x1f
-#define CH7017_CONNECTION_DETECT       0x20
-#define CH7017_DAC_CONTROL             0x21
-#define CH7017_BUFFERED_CLOCK_OUTPUT   0x22
-#define CH7017_DEFEAT_VSYNC            0x47
-#define CH7017_TEST_PATTERN            0x48
-
-#define CH7017_POWER_MANAGEMENT                0x49
-/** Enables the TV output path. */
-#define CH7017_TV_EN                   (1 << 0)
-#define CH7017_DAC0_POWER_DOWN         (1 << 1)
-#define CH7017_DAC1_POWER_DOWN         (1 << 2)
-#define CH7017_DAC2_POWER_DOWN         (1 << 3)
-#define CH7017_DAC3_POWER_DOWN         (1 << 4)
-/** Powers down the TV out block, and DAC0-3 */
-#define CH7017_TV_POWER_DOWN_EN                (1 << 5)
-
-#define CH7017_VERSION_ID              0x4a
-
-#define CH7017_DEVICE_ID               0x4b
-#define CH7017_DEVICE_ID_VALUE         0x1b
-#define CH7018_DEVICE_ID_VALUE         0x1a
-#define CH7019_DEVICE_ID_VALUE         0x19
-
-#define CH7017_XCLK_D2_ADJUST          0x53
-#define CH7017_UP_SCALER_COEFF_0       0x55
-#define CH7017_UP_SCALER_COEFF_1       0x56
-#define CH7017_UP_SCALER_COEFF_2       0x57
-#define CH7017_UP_SCALER_COEFF_3       0x58
-#define CH7017_UP_SCALER_COEFF_4       0x59
-#define CH7017_UP_SCALER_VERTICAL_INC_0        0x5a
-#define CH7017_UP_SCALER_VERTICAL_INC_1        0x5b
-#define CH7017_GPIO_INVERT             0x5c
-#define CH7017_UP_SCALER_HORIZONTAL_INC_0      0x5d
-#define CH7017_UP_SCALER_HORIZONTAL_INC_1      0x5e
-
-#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT   0x5f
-/**< Low bits of horizontal active pixel input */
-
-#define CH7017_ACTIVE_INPUT_LINE_OUTPUT        0x60
-/** High bits of horizontal active pixel input */
-#define CH7017_LVDS_HAP_INPUT_MASK     (0x7 << 0)
-/** High bits of vertical active line output */
-#define CH7017_LVDS_VAL_HIGH_MASK      (0x7 << 3)
-
-#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT     0x61
-/**< Low bits of vertical active line output */
-
-#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT  0x62
-/**< Low bits of horizontal active pixel output */
-
-#define CH7017_LVDS_POWER_DOWN         0x63
-/** High bits of horizontal active pixel output */
-#define CH7017_LVDS_HAP_HIGH_MASK      (0x7 << 0)
-/** Enables the LVDS power down state transition */
-#define CH7017_LVDS_POWER_DOWN_EN      (1 << 6)
-/** Enables the LVDS upscaler */
-#define CH7017_LVDS_UPSCALER_EN                (1 << 7)
-#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08
-
-#define CH7017_LVDS_ENCODING           0x64
-#define CH7017_LVDS_DITHER_2D          (1 << 2)
-#define CH7017_LVDS_DITHER_DIS         (1 << 3)
-#define CH7017_LVDS_DUAL_CHANNEL_EN    (1 << 4)
-#define CH7017_LVDS_24_BIT             (1 << 5)
-
-#define CH7017_LVDS_ENCODING_2         0x65
-
-#define CH7017_LVDS_PLL_CONTROL                0x66
-/** Enables the LVDS panel output path */
-#define CH7017_LVDS_PANEN              (1 << 0)
-/** Enables the LVDS panel backlight */
-#define CH7017_LVDS_BKLEN              (1 << 3)
-
-#define CH7017_POWER_SEQUENCING_T1     0x67
-#define CH7017_POWER_SEQUENCING_T2     0x68
-#define CH7017_POWER_SEQUENCING_T3     0x69
-#define CH7017_POWER_SEQUENCING_T4     0x6a
-#define CH7017_POWER_SEQUENCING_T5     0x6b
-#define CH7017_GPIO_DRIVER_TYPE                0x6c
-#define CH7017_GPIO_DATA               0x6d
-#define CH7017_GPIO_DIRECTION_CONTROL  0x6e
-
-#define CH7017_LVDS_PLL_FEEDBACK_DIV   0x71
-# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4
-# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0
-# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80
-
-#define CH7017_LVDS_PLL_VCO_CONTROL    0x72
-# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80
-# define CH7017_LVDS_PLL_VCO_SHIFT     4
-# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0
-
-#define CH7017_OUTPUTS_ENABLE          0x73
-# define CH7017_CHARGE_PUMP_LOW                0x0
-# define CH7017_CHARGE_PUMP_HIGH       0x3
-# define CH7017_LVDS_CHANNEL_A         (1 << 3)
-# define CH7017_LVDS_CHANNEL_B         (1 << 4)
-# define CH7017_TV_DAC_A               (1 << 5)
-# define CH7017_TV_DAC_B               (1 << 6)
-# define CH7017_DDC_SELECT_DC2         (1 << 7)
-
-#define CH7017_LVDS_OUTPUT_AMPLITUDE   0x74
-#define CH7017_LVDS_PLL_EMI_REDUCTION  0x75
-#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
-
-#define CH7017_LVDS_CONTROL_2          0x78
-# define CH7017_LOOP_FILTER_SHIFT      5
-# define CH7017_PHASE_DETECTOR_SHIFT   0
-
-#define CH7017_BANG_LIMIT_CONTROL      0x7f
-
-struct ch7017_priv {
-       u8 dummy;
-};
-
-static void ch7017_dump_regs(struct intel_dvo_device *dvo);
-static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable);
-
-static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
-{
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &addr,
-               },
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = val,
-               }
-       };
-       return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
-}
-
-static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
-{
-       u8 buf[2] = { addr, val };
-       struct i2c_msg msg = {
-               .addr = dvo->slave_addr,
-               .flags = 0,
-               .len = 2,
-               .buf = buf,
-       };
-       return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
-}
-
-/** Probes for a CH7017 on the given bus and slave address. */
-static bool ch7017_init(struct intel_dvo_device *dvo,
-                       struct i2c_adapter *adapter)
-{
-       struct ch7017_priv *priv;
-       const char *str;
-       u8 val;
-
-       priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return false;
-
-       dvo->i2c_bus = adapter;
-       dvo->dev_priv = priv;
-
-       if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
-               goto fail;
-
-       switch (val) {
-       case CH7017_DEVICE_ID_VALUE:
-               str = "ch7017";
-               break;
-       case CH7018_DEVICE_ID_VALUE:
-               str = "ch7018";
-               break;
-       case CH7019_DEVICE_ID_VALUE:
-               str = "ch7019";
-               break;
-       default:
-               DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
-                             "slave %d.\n",
-                             val, adapter->name, dvo->slave_addr);
-               goto fail;
-       }
-
-       DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
-                     str, adapter->name, dvo->slave_addr);
-       return true;
-
-fail:
-       kfree(priv);
-       return false;
-}
-
-static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
-{
-       return connector_status_connected;
-}
-
-static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
-                                             struct drm_display_mode *mode)
-{
-       if (mode->clock > 160000)
-               return MODE_CLOCK_HIGH;
-
-       return MODE_OK;
-}
-
-static void ch7017_mode_set(struct intel_dvo_device *dvo,
-                           const struct drm_display_mode *mode,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       u8 lvds_pll_feedback_div, lvds_pll_vco_control;
-       u8 outputs_enable, lvds_control_2, lvds_power_down;
-       u8 horizontal_active_pixel_input;
-       u8 horizontal_active_pixel_output, vertical_active_line_output;
-       u8 active_input_line_output;
-
-       DRM_DEBUG_KMS("Registers before mode setting\n");
-       ch7017_dump_regs(dvo);
-
-       /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
-       if (mode->clock < 100000) {
-               outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW;
-               lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
-                       (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
-                       (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
-               lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
-                       (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
-                       (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
-               lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
-                       (0 << CH7017_PHASE_DETECTOR_SHIFT);
-       } else {
-               outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH;
-               lvds_pll_feedback_div =
-                       CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
-                       (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
-                       (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
-               lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
-                       (0 << CH7017_PHASE_DETECTOR_SHIFT);
-               if (1) { /* XXX: dual channel panel detection.  Assume yes for now. */
-                       outputs_enable |= CH7017_LVDS_CHANNEL_B;
-                       lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
-                               (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
-                               (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
-               } else {
-                       lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
-                               (1 << CH7017_LVDS_PLL_VCO_SHIFT) |
-                               (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
-               }
-       }
-
-       horizontal_active_pixel_input = mode->hdisplay & 0x00ff;
-
-       vertical_active_line_output = mode->vdisplay & 0x00ff;
-       horizontal_active_pixel_output = mode->hdisplay & 0x00ff;
-
-       active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) |
-                                  (((mode->vdisplay & 0x0700) >> 8) << 3);
-
-       lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
-                         (mode->hdisplay & 0x0700) >> 8;
-
-       ch7017_dpms(dvo, false);
-       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
-                       horizontal_active_pixel_input);
-       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
-                       horizontal_active_pixel_output);
-       ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
-                       vertical_active_line_output);
-       ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT,
-                       active_input_line_output);
-       ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
-       ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
-       ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2);
-       ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable);
-
-       /* Turn the LVDS back on with new settings. */
-       ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down);
-
-       DRM_DEBUG_KMS("Registers after mode setting\n");
-       ch7017_dump_regs(dvo);
-}
-
-/* set the CH7017 power state */
-static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
-{
-       u8 val;
-
-       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
-
-       /* Turn off TV/VGA, and never turn it on since we don't support it. */
-       ch7017_write(dvo, CH7017_POWER_MANAGEMENT,
-                       CH7017_DAC0_POWER_DOWN |
-                       CH7017_DAC1_POWER_DOWN |
-                       CH7017_DAC2_POWER_DOWN |
-                       CH7017_DAC3_POWER_DOWN |
-                       CH7017_TV_POWER_DOWN_EN);
-
-       if (enable) {
-               /* Turn on the LVDS */
-               ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
-                            val & ~CH7017_LVDS_POWER_DOWN_EN);
-       } else {
-               /* Turn off the LVDS */
-               ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
-                            val | CH7017_LVDS_POWER_DOWN_EN);
-       }
-
-       /* XXX: Should actually wait for update power status somehow */
-       msleep(20);
-}
-
-static bool ch7017_get_hw_state(struct intel_dvo_device *dvo)
-{
-       u8 val;
-
-       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
-
-       if (val & CH7017_LVDS_POWER_DOWN_EN)
-               return false;
-       else
-               return true;
-}
-
-static void ch7017_dump_regs(struct intel_dvo_device *dvo)
-{
-       u8 val;
-
-#define DUMP(reg)                                      \
-do {                                                   \
-       ch7017_read(dvo, reg, &val);                    \
-       DRM_DEBUG_KMS(#reg ": %02x\n", val);            \
-} while (0)
-
-       DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
-       DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
-       DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
-       DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT);
-       DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
-       DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
-       DUMP(CH7017_LVDS_CONTROL_2);
-       DUMP(CH7017_OUTPUTS_ENABLE);
-       DUMP(CH7017_LVDS_POWER_DOWN);
-}
-
-static void ch7017_destroy(struct intel_dvo_device *dvo)
-{
-       struct ch7017_priv *priv = dvo->dev_priv;
-
-       if (priv) {
-               kfree(priv);
-               dvo->dev_priv = NULL;
-       }
-}
-
-const struct intel_dvo_dev_ops ch7017_ops = {
-       .init = ch7017_init,
-       .detect = ch7017_detect,
-       .mode_valid = ch7017_mode_valid,
-       .mode_set = ch7017_mode_set,
-       .dpms = ch7017_dpms,
-       .get_hw_state = ch7017_get_hw_state,
-       .dump_regs = ch7017_dump_regs,
-       .destroy = ch7017_destroy,
-};
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
deleted file mode 100644 (file)
index e070beb..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/**************************************************************************
-
-Copyright © 2006 Dave Airlie
-
-All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sub license, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice (including the
-next paragraph) shall be included in all copies or substantial portions
-of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-**************************************************************************/
-
-#include "intel_drv.h"
-#include "intel_dvo_dev.h"
-
-#define CH7xxx_REG_VID         0x4a
-#define CH7xxx_REG_DID         0x4b
-
-#define CH7011_VID             0x83 /* 7010 as well */
-#define CH7010B_VID            0x05
-#define CH7009A_VID            0x84
-#define CH7009B_VID            0x85
-#define CH7301_VID             0x95
-
-#define CH7xxx_VID             0x84
-#define CH7xxx_DID             0x17
-#define CH7010_DID             0x16
-
-#define CH7xxx_NUM_REGS                0x4c
-
-#define CH7xxx_CM              0x1c
-#define CH7xxx_CM_XCM          (1<<0)
-#define CH7xxx_CM_MCP          (1<<2)
-#define CH7xxx_INPUT_CLOCK     0x1d
-#define CH7xxx_GPIO            0x1e
-#define CH7xxx_GPIO_HPIR       (1<<3)
-#define CH7xxx_IDF             0x1f
-
-#define CH7xxx_IDF_HSP         (1<<3)
-#define CH7xxx_IDF_VSP         (1<<4)
-
-#define CH7xxx_CONNECTION_DETECT 0x20
-#define CH7xxx_CDET_DVI                (1<<5)
-
-#define CH7301_DAC_CNTL                0x21
-#define CH7301_HOTPLUG         0x23
-#define CH7xxx_TCTL            0x31
-#define CH7xxx_TVCO            0x32
-#define CH7xxx_TPCP            0x33
-#define CH7xxx_TPD             0x34
-#define CH7xxx_TPVT            0x35
-#define CH7xxx_TLPF            0x36
-#define CH7xxx_TCT             0x37
-#define CH7301_TEST_PATTERN    0x48
-
-#define CH7xxx_PM              0x49
-#define CH7xxx_PM_FPD          (1<<0)
-#define CH7301_PM_DACPD0       (1<<1)
-#define CH7301_PM_DACPD1       (1<<2)
-#define CH7301_PM_DACPD2       (1<<3)
-#define CH7xxx_PM_DVIL         (1<<6)
-#define CH7xxx_PM_DVIP         (1<<7)
-
-#define CH7301_SYNC_POLARITY   0x56
-#define CH7301_SYNC_RGB_YUV    (1<<0)
-#define CH7301_SYNC_POL_DVI    (1<<5)
-
-/** @file
- * driver for the Chrontel 7xxx DVI chip over DVO.
- */
-
-static struct ch7xxx_id_struct {
-       u8 vid;
-       char *name;
-} ch7xxx_ids[] = {
-       { CH7011_VID, "CH7011" },
-       { CH7010B_VID, "CH7010B" },
-       { CH7009A_VID, "CH7009A" },
-       { CH7009B_VID, "CH7009B" },
-       { CH7301_VID, "CH7301" },
-};
-
-static struct ch7xxx_did_struct {
-       u8 did;
-       char *name;
-} ch7xxx_dids[] = {
-       { CH7xxx_DID, "CH7XXX" },
-       { CH7010_DID, "CH7010B" },
-};
-
-struct ch7xxx_priv {
-       bool quiet;
-};
-
-static char *ch7xxx_get_id(u8 vid)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
-               if (ch7xxx_ids[i].vid == vid)
-                       return ch7xxx_ids[i].name;
-       }
-
-       return NULL;
-}
-
-static char *ch7xxx_get_did(u8 did)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
-               if (ch7xxx_dids[i].did == did)
-                       return ch7xxx_dids[i].name;
-       }
-
-       return NULL;
-}
-
-/** Reads an 8 bit register */
-static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
-{
-       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       u8 in_buf[2];
-
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = out_buf,
-               },
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = in_buf,
-               }
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = 0;
-
-       if (i2c_transfer(adapter, msgs, 2) == 2) {
-               *ch = in_buf[0];
-               return true;
-       }
-
-       if (!ch7xxx->quiet) {
-               DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-       return false;
-}
-
-/** Writes an 8 bit register */
-static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
-{
-       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       struct i2c_msg msg = {
-               .addr = dvo->slave_addr,
-               .flags = 0,
-               .len = 2,
-               .buf = out_buf,
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = ch;
-
-       if (i2c_transfer(adapter, &msg, 1) == 1)
-               return true;
-
-       if (!ch7xxx->quiet) {
-               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-
-       return false;
-}
-
-static bool ch7xxx_init(struct intel_dvo_device *dvo,
-                       struct i2c_adapter *adapter)
-{
-       /* this will detect the CH7xxx chip on the specified i2c bus */
-       struct ch7xxx_priv *ch7xxx;
-       u8 vendor, device;
-       char *name, *devid;
-
-       ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
-       if (ch7xxx == NULL)
-               return false;
-
-       dvo->i2c_bus = adapter;
-       dvo->dev_priv = ch7xxx;
-       ch7xxx->quiet = true;
-
-       if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
-               goto out;
-
-       name = ch7xxx_get_id(vendor);
-       if (!name) {
-               DRM_DEBUG_KMS("ch7xxx not detected; got VID 0x%02x from %s slave %d.\n",
-                             vendor, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-
-
-       if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
-               goto out;
-
-       devid = ch7xxx_get_did(device);
-       if (!devid) {
-               DRM_DEBUG_KMS("ch7xxx not detected; got DID 0x%02x from %s slave %d.\n",
-                             device, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-
-       ch7xxx->quiet = false;
-       DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
-                 name, vendor, device);
-       return true;
-out:
-       kfree(ch7xxx);
-       return false;
-}
-
-static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
-{
-       u8 cdet, orig_pm, pm;
-
-       ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
-
-       pm = orig_pm;
-       pm &= ~CH7xxx_PM_FPD;
-       pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
-
-       ch7xxx_writeb(dvo, CH7xxx_PM, pm);
-
-       ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
-
-       ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
-
-       if (cdet & CH7xxx_CDET_DVI)
-               return connector_status_connected;
-       return connector_status_disconnected;
-}
-
-static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
-                                             struct drm_display_mode *mode)
-{
-       if (mode->clock > 165000)
-               return MODE_CLOCK_HIGH;
-
-       return MODE_OK;
-}
-
-static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
-                           const struct drm_display_mode *mode,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       u8 tvco, tpcp, tpd, tlpf, idf;
-
-       if (mode->clock <= 65000) {
-               tvco = 0x23;
-               tpcp = 0x08;
-               tpd = 0x16;
-               tlpf = 0x60;
-       } else {
-               tvco = 0x2d;
-               tpcp = 0x06;
-               tpd = 0x26;
-               tlpf = 0xa0;
-       }
-
-       ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
-       ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
-       ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
-       ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
-       ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
-       ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
-       ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
-
-       ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
-
-       idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
-       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-               idf |= CH7xxx_IDF_HSP;
-
-       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-               idf |= CH7xxx_IDF_VSP;
-
-       ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
-}
-
-/* set the CH7xxx power state */
-static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
-{
-       if (enable)
-               ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
-       else
-               ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
-}
-
-static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
-{
-       u8 val;
-
-       ch7xxx_readb(dvo, CH7xxx_PM, &val);
-
-       if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
-               return true;
-       else
-               return false;
-}
-
-static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
-{
-       int i;
-
-       for (i = 0; i < CH7xxx_NUM_REGS; i++) {
-               u8 val;
-               if ((i % 8) == 0)
-                       DRM_DEBUG_KMS("\n %02X: ", i);
-               ch7xxx_readb(dvo, i, &val);
-               DRM_DEBUG_KMS("%02X ", val);
-       }
-}
-
-static void ch7xxx_destroy(struct intel_dvo_device *dvo)
-{
-       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
-
-       if (ch7xxx) {
-               kfree(ch7xxx);
-               dvo->dev_priv = NULL;
-       }
-}
-
-const struct intel_dvo_dev_ops ch7xxx_ops = {
-       .init = ch7xxx_init,
-       .detect = ch7xxx_detect,
-       .mode_valid = ch7xxx_mode_valid,
-       .mode_set = ch7xxx_mode_set,
-       .dpms = ch7xxx_dpms,
-       .get_hw_state = ch7xxx_get_hw_state,
-       .dump_regs = ch7xxx_dump_regs,
-       .destroy = ch7xxx_destroy,
-};
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
deleted file mode 100644 (file)
index 09dba35..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *    Thomas Richter <thor@math.tu-berlin.de>
- *
- * Minor modifications (Dithering enable):
- *    Thomas Richter <thor@math.tu-berlin.de>
- *
- */
-
-#include "intel_drv.h"
-#include "intel_dvo_dev.h"
-
-/*
- * register definitions for the i82807aa.
- *
- * Documentation on this chipset can be found in datasheet #29069001 at
- * intel.com.
- */
-
-/*
- * VCH Revision & GMBus Base Addr
- */
-#define VR00           0x00
-# define VR00_BASE_ADDRESS_MASK                0x007f
-
-/*
- * Functionality Enable
- */
-#define VR01           0x01
-
-/*
- * Enable the panel fitter
- */
-# define VR01_PANEL_FIT_ENABLE         (1 << 3)
-/*
- * Enables the LCD display.
- *
- * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
- */
-# define VR01_LCD_ENABLE               (1 << 2)
-/* Enables the DVO repeater. */
-# define VR01_DVO_BYPASS_ENABLE                (1 << 1)
-/* Enables the DVO clock */
-# define VR01_DVO_ENABLE               (1 << 0)
-/* Enable dithering for 18bpp panels. Not documented. */
-# define VR01_DITHER_ENABLE             (1 << 4)
-
-/*
- * LCD Interface Format
- */
-#define VR10           0x10
-/* Enables LVDS output instead of CMOS */
-# define VR10_LVDS_ENABLE              (1 << 4)
-/* Enables 18-bit LVDS output. */
-# define VR10_INTERFACE_1X18           (0 << 2)
-/* Enables 24-bit LVDS or CMOS output */
-# define VR10_INTERFACE_1X24           (1 << 2)
-/* Enables 2x18-bit LVDS or CMOS output. */
-# define VR10_INTERFACE_2X18           (2 << 2)
-/* Enables 2x24-bit LVDS output */
-# define VR10_INTERFACE_2X24           (3 << 2)
-/* Mask that defines the depth of the pipeline */
-# define VR10_INTERFACE_DEPTH_MASK      (3 << 2)
-
-/*
- * VR20 LCD Horizontal Display Size
- */
-#define VR20   0x20
-
-/*
- * LCD Vertical Display Size
- */
-#define VR21   0x21
-
-/*
- * Panel power down status
- */
-#define VR30           0x30
-/* Read only bit indicating that the panel is not in a safe poweroff state. */
-# define VR30_PANEL_ON                 (1 << 15)
-
-#define VR40           0x40
-# define VR40_STALL_ENABLE             (1 << 13)
-# define VR40_VERTICAL_INTERP_ENABLE   (1 << 12)
-# define VR40_ENHANCED_PANEL_FITTING   (1 << 11)
-# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10)
-# define VR40_AUTO_RATIO_ENABLE                (1 << 9)
-# define VR40_CLOCK_GATING_ENABLE      (1 << 8)
-
-/*
- * Panel Fitting Vertical Ratio
- * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
- */
-#define VR41           0x41
-
-/*
- * Panel Fitting Horizontal Ratio
- * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
- */
-#define VR42           0x42
-
-/*
- * Horizontal Image Size
- */
-#define VR43           0x43
-
-/* VR80 GPIO 0
- */
-#define VR80       0x80
-#define VR81       0x81
-#define VR82       0x82
-#define VR83       0x83
-#define VR84       0x84
-#define VR85       0x85
-#define VR86       0x86
-#define VR87       0x87
-
-/* VR88 GPIO 8
- */
-#define VR88       0x88
-
-/* Graphics BIOS scratch 0
- */
-#define VR8E       0x8E
-# define VR8E_PANEL_TYPE_MASK          (0xf << 0)
-# define VR8E_PANEL_INTERFACE_CMOS     (0 << 4)
-# define VR8E_PANEL_INTERFACE_LVDS     (1 << 4)
-# define VR8E_FORCE_DEFAULT_PANEL      (1 << 5)
-
-/* Graphics BIOS scratch 1
- */
-#define VR8F       0x8F
-# define VR8F_VCH_PRESENT              (1 << 0)
-# define VR8F_DISPLAY_CONN             (1 << 1)
-# define VR8F_POWER_MASK               (0x3c)
-# define VR8F_POWER_POS                        (2)
-
-/* Some Bios implementations do not restore the DVO state upon
- * resume from standby. Thus, this driver has to handle it
- * instead. The following list contains all registers that
- * require saving.
- */
-static const u16 backup_addresses[] = {
-       0x11, 0x12,
-       0x18, 0x19, 0x1a, 0x1f,
-       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-       0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-       0x8e, 0x8f,
-       0x10            /* this must come last */
-};
-
-
-struct ivch_priv {
-       bool quiet;
-
-       u16 width, height;
-
-       /* Register backup */
-
-       u16 reg_backup[ARRAY_SIZE(backup_addresses)];
-};
-
-
-static void ivch_dump_regs(struct intel_dvo_device *dvo);
-/*
- * Reads a register on the ivch.
- *
- * Each of the 256 registers are 16 bits long.
- */
-static bool ivch_read(struct intel_dvo_device *dvo, int addr, u16 *data)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[1];
-       u8 in_buf[2];
-
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = I2C_M_RD,
-                       .len = 0,
-               },
-               {
-                       .addr = 0,
-                       .flags = I2C_M_NOSTART,
-                       .len = 1,
-                       .buf = out_buf,
-               },
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = I2C_M_RD | I2C_M_NOSTART,
-                       .len = 2,
-                       .buf = in_buf,
-               }
-       };
-
-       out_buf[0] = addr;
-
-       if (i2c_transfer(adapter, msgs, 3) == 3) {
-               *data = (in_buf[1] << 8) | in_buf[0];
-               return true;
-       }
-
-       if (!priv->quiet) {
-               DRM_DEBUG_KMS("Unable to read register 0x%02x from "
-                               "%s:%02x.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-       return false;
-}
-
-/* Writes a 16-bit register on the ivch */
-static bool ivch_write(struct intel_dvo_device *dvo, int addr, u16 data)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[3];
-       struct i2c_msg msg = {
-               .addr = dvo->slave_addr,
-               .flags = 0,
-               .len = 3,
-               .buf = out_buf,
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = data & 0xff;
-       out_buf[2] = data >> 8;
-
-       if (i2c_transfer(adapter, &msg, 1) == 1)
-               return true;
-
-       if (!priv->quiet) {
-               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-
-       return false;
-}
-
-/* Probes the given bus and slave address for an ivch */
-static bool ivch_init(struct intel_dvo_device *dvo,
-                     struct i2c_adapter *adapter)
-{
-       struct ivch_priv *priv;
-       u16 temp;
-       int i;
-
-       priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return false;
-
-       dvo->i2c_bus = adapter;
-       dvo->dev_priv = priv;
-       priv->quiet = true;
-
-       if (!ivch_read(dvo, VR00, &temp))
-               goto out;
-       priv->quiet = false;
-
-       /* Since the identification bits are probably zeroes, which doesn't seem
-        * very unique, check that the value in the base address field matches
-        * the address it's responding on.
-        */
-       if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
-               DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
-                         "(%d vs %d)\n",
-                         (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
-               goto out;
-       }
-
-       ivch_read(dvo, VR20, &priv->width);
-       ivch_read(dvo, VR21, &priv->height);
-
-       /* Make a backup of the registers to be able to restore them
-        * upon suspend.
-        */
-       for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
-               ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
-
-       ivch_dump_regs(dvo);
-
-       return true;
-
-out:
-       kfree(priv);
-       return false;
-}
-
-static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
-{
-       return connector_status_connected;
-}
-
-static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
-                                           struct drm_display_mode *mode)
-{
-       if (mode->clock > 112000)
-               return MODE_CLOCK_HIGH;
-
-       return MODE_OK;
-}
-
-/* Restore the DVO registers after a resume
- * from RAM. Registers have been saved during
- * the initialization.
- */
-static void ivch_reset(struct intel_dvo_device *dvo)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-       int i;
-
-       DRM_DEBUG_KMS("Resetting the IVCH registers\n");
-
-       ivch_write(dvo, VR10, 0x0000);
-
-       for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
-               ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
-}
-
-/* Sets the power state of the panel connected to the ivch */
-static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
-{
-       int i;
-       u16 vr01, vr30, backlight;
-
-       ivch_reset(dvo);
-
-       /* Set the new power state of the panel. */
-       if (!ivch_read(dvo, VR01, &vr01))
-               return;
-
-       if (enable)
-               backlight = 1;
-       else
-               backlight = 0;
-
-       ivch_write(dvo, VR80, backlight);
-
-       if (enable)
-               vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
-       else
-               vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
-
-       ivch_write(dvo, VR01, vr01);
-
-       /* Wait for the panel to make its state transition */
-       for (i = 0; i < 100; i++) {
-               if (!ivch_read(dvo, VR30, &vr30))
-                       break;
-
-               if (((vr30 & VR30_PANEL_ON) != 0) == enable)
-                       break;
-               udelay(1000);
-       }
-       /* wait some more; vch may fail to resync sometimes without this */
-       udelay(16 * 1000);
-}
-
-static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
-{
-       u16 vr01;
-
-       ivch_reset(dvo);
-
-       /* Set the new power state of the panel. */
-       if (!ivch_read(dvo, VR01, &vr01))
-               return false;
-
-       if (vr01 & VR01_LCD_ENABLE)
-               return true;
-       else
-               return false;
-}
-
-static void ivch_mode_set(struct intel_dvo_device *dvo,
-                         const struct drm_display_mode *mode,
-                         const struct drm_display_mode *adjusted_mode)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-       u16 vr40 = 0;
-       u16 vr01 = 0;
-       u16 vr10;
-
-       ivch_reset(dvo);
-
-       vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
-
-       /* Enable dithering for 18 bpp pipelines */
-       vr10 &= VR10_INTERFACE_DEPTH_MASK;
-       if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
-               vr01 = VR01_DITHER_ENABLE;
-
-       vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
-               VR40_HORIZONTAL_INTERP_ENABLE);
-
-       if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
-           mode->vdisplay != adjusted_mode->crtc_vdisplay) {
-               u16 x_ratio, y_ratio;
-
-               vr01 |= VR01_PANEL_FIT_ENABLE;
-               vr40 |= VR40_CLOCK_GATING_ENABLE;
-               x_ratio = (((mode->hdisplay - 1) << 16) /
-                          (adjusted_mode->crtc_hdisplay - 1)) >> 2;
-               y_ratio = (((mode->vdisplay - 1) << 16) /
-                          (adjusted_mode->crtc_vdisplay - 1)) >> 2;
-               ivch_write(dvo, VR42, x_ratio);
-               ivch_write(dvo, VR41, y_ratio);
-       } else {
-               vr01 &= ~VR01_PANEL_FIT_ENABLE;
-               vr40 &= ~VR40_CLOCK_GATING_ENABLE;
-       }
-       vr40 &= ~VR40_AUTO_RATIO_ENABLE;
-
-       ivch_write(dvo, VR01, vr01);
-       ivch_write(dvo, VR40, vr40);
-}
-
-static void ivch_dump_regs(struct intel_dvo_device *dvo)
-{
-       u16 val;
-
-       ivch_read(dvo, VR00, &val);
-       DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
-       ivch_read(dvo, VR01, &val);
-       DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
-       ivch_read(dvo, VR10, &val);
-       DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
-       ivch_read(dvo, VR30, &val);
-       DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
-       ivch_read(dvo, VR40, &val);
-       DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
-
-       /* GPIO registers */
-       ivch_read(dvo, VR80, &val);
-       DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
-       ivch_read(dvo, VR81, &val);
-       DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
-       ivch_read(dvo, VR82, &val);
-       DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
-       ivch_read(dvo, VR83, &val);
-       DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
-       ivch_read(dvo, VR84, &val);
-       DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
-       ivch_read(dvo, VR85, &val);
-       DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
-       ivch_read(dvo, VR86, &val);
-       DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
-       ivch_read(dvo, VR87, &val);
-       DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
-       ivch_read(dvo, VR88, &val);
-       DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
-
-       /* Scratch register 0 - AIM Panel type */
-       ivch_read(dvo, VR8E, &val);
-       DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
-
-       /* Scratch register 1 - Status register */
-       ivch_read(dvo, VR8F, &val);
-       DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
-}
-
-static void ivch_destroy(struct intel_dvo_device *dvo)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-
-       if (priv) {
-               kfree(priv);
-               dvo->dev_priv = NULL;
-       }
-}
-
-const struct intel_dvo_dev_ops ivch_ops = {
-       .init = ivch_init,
-       .dpms = ivch_dpms,
-       .get_hw_state = ivch_get_hw_state,
-       .mode_valid = ivch_mode_valid,
-       .mode_set = ivch_mode_set,
-       .detect = ivch_detect,
-       .dump_regs = ivch_dump_regs,
-       .destroy = ivch_destroy,
-};
diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c
deleted file mode 100644 (file)
index c83a5d8..0000000
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- *
- * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
- *
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "i915_drv.h"
-#include "i915_reg.h"
-#include "intel_drv.h"
-#include "intel_dvo_dev.h"
-
-#define NS2501_VID 0x1305
-#define NS2501_DID 0x6726
-
-#define NS2501_VID_LO 0x00
-#define NS2501_VID_HI 0x01
-#define NS2501_DID_LO 0x02
-#define NS2501_DID_HI 0x03
-#define NS2501_REV 0x04
-#define NS2501_RSVD 0x05
-#define NS2501_FREQ_LO 0x06
-#define NS2501_FREQ_HI 0x07
-
-#define NS2501_REG8 0x08
-#define NS2501_8_VEN (1<<5)
-#define NS2501_8_HEN (1<<4)
-#define NS2501_8_DSEL (1<<3)
-#define NS2501_8_BPAS (1<<2)
-#define NS2501_8_RSVD (1<<1)
-#define NS2501_8_PD (1<<0)
-
-#define NS2501_REG9 0x09
-#define NS2501_9_VLOW (1<<7)
-#define NS2501_9_MSEL_MASK (0x7<<4)
-#define NS2501_9_TSEL (1<<3)
-#define NS2501_9_RSEN (1<<2)
-#define NS2501_9_RSVD (1<<1)
-#define NS2501_9_MDI (1<<0)
-
-#define NS2501_REGC 0x0c
-
-/*
- * The following registers are not part of the official datasheet
- * and are the result of reverse engineering.
- */
-
-/*
- * Register c0 controls how the DVO synchronizes with
- * its input.
- */
-#define NS2501_REGC0 0xc0
-#define NS2501_C0_ENABLE (1<<0)        /* enable the DVO sync in general */
-#define NS2501_C0_HSYNC (1<<1) /* synchronize horizontal with input */
-#define NS2501_C0_VSYNC (1<<2) /* synchronize vertical with input */
-#define NS2501_C0_RESET (1<<7) /* reset the synchronization flip/flops */
-
-/*
- * Register 41 is somehow related to the sync register and sync
- * configuration. It should be 0x32 whenever regC0 is 0x05 (hsync off)
- * and 0x00 otherwise.
- */
-#define NS2501_REG41 0x41
-
-/*
- * this register controls the dithering of the DVO
- * One bit enables it, the other define the dithering depth.
- * The higher the value, the lower the dithering depth.
- */
-#define NS2501_F9_REG 0xf9
-#define NS2501_F9_ENABLE (1<<0)                /* if set, dithering is enabled */
-#define NS2501_F9_DITHER_MASK (0x7f<<1)        /* controls the dither depth */
-#define NS2501_F9_DITHER_SHIFT 1       /* shifts the dither mask */
-
-/*
- * PLL configuration register. This is a pair of registers,
- * one single byte register at 1B, and a pair at 1C,1D.
- * These registers are counters/dividers.
- */
-#define NS2501_REG1B 0x1b /* one byte PLL control register */
-#define NS2501_REG1C 0x1c /* low-part of the second register */
-#define NS2501_REG1D 0x1d /* high-part of the second register */
-
-/*
- * Scaler control registers. Horizontal at b8,b9,
- * vertical at 10,11. The scale factor is computed as
- * 2^16/control-value. The low-byte comes first.
- */
-#define NS2501_REG10 0x10 /* low-byte vertical scaler */
-#define NS2501_REG11 0x11 /* high-byte vertical scaler */
-#define NS2501_REGB8 0xb8 /* low-byte horizontal scaler */
-#define NS2501_REGB9 0xb9 /* high-byte horizontal scaler */
-
-/*
- * Display window definition. This consists of four registers
- * per dimension. One register pair defines the start of the
- * display, one the end.
- * As far as I understand, this defines the window within which
- * the scaler samples the input.
- */
-#define NS2501_REGC1 0xc1 /* low-byte horizontal display start */
-#define NS2501_REGC2 0xc2 /* high-byte horizontal display start */
-#define NS2501_REGC3 0xc3 /* low-byte horizontal display stop */
-#define NS2501_REGC4 0xc4 /* high-byte horizontal display stop */
-#define NS2501_REGC5 0xc5 /* low-byte vertical display start */
-#define NS2501_REGC6 0xc6 /* high-byte vertical display start */
-#define NS2501_REGC7 0xc7 /* low-byte vertical display stop */
-#define NS2501_REGC8 0xc8 /* high-byte vertical display stop */
-
-/*
- * The following register pair seems to define the start of
- * the vertical sync. If automatic syncing is enabled, and the
- * register value defines a sync pulse that is later than the
- * incoming sync, then the register value is ignored and the
- * external hsync triggers the synchronization.
- */
-#define NS2501_REG80 0x80 /* low-byte vsync-start */
-#define NS2501_REG81 0x81 /* high-byte vsync-start */
-
-/*
- * The following register pair seems to define the total number
- * of lines created at the output side of the scaler.
- * This is again a low-high register pair.
- */
-#define NS2501_REG82 0x82 /* output display height, low byte */
-#define NS2501_REG83 0x83 /* output display height, high byte */
-
-/*
- * The following registers define the end of the front-porch
- * in horizontal and vertical position and hence allow to shift
- * the image left/right or up/down.
- */
-#define NS2501_REG98 0x98 /* horizontal start of display + 256, low */
-#define NS2501_REG99 0x99 /* horizontal start of display + 256, high */
-#define NS2501_REG8E 0x8e /* vertical start of the display, low byte */
-#define NS2501_REG8F 0x8f /* vertical start of the display, high byte */
-
-/*
- * The following register pair control the function of the
- * backlight and the DVO output. To enable the corresponding
- * function, the corresponding bit must be set in both registers.
- */
-#define NS2501_REG34 0x34 /* DVO enable functions, first register */
-#define NS2501_REG35 0x35 /* DVO enable functions, second register */
-#define NS2501_34_ENABLE_OUTPUT (1<<0) /* enable DVO output */
-#define NS2501_34_ENABLE_BACKLIGHT (1<<1) /* enable backlight */
-
-/*
- * Registers 9C and 9D define the vertical output offset
- * of the visible region.
- */
-#define NS2501_REG9C 0x9c
-#define NS2501_REG9D 0x9d
-
-/*
- * The register 9F defines the dithering. This requires the
- * scaler to be ON. Bit 0 enables dithering, the remaining
- * bits control the depth of the dither. The higher the value,
- * the LOWER the dithering amplitude. A good value seems to be
- * 15 (total register value).
- */
-#define NS2501_REGF9 0xf9
-#define NS2501_F9_ENABLE_DITHER (1<<0) /* enable dithering */
-#define NS2501_F9_DITHER_MASK (0x7f<<1) /* dither masking */
-#define NS2501_F9_DITHER_SHIFT 1       /* upshift of the dither mask */
-
-enum {
-       MODE_640x480,
-       MODE_800x600,
-       MODE_1024x768,
-};
-
-struct ns2501_reg {
-       u8 offset;
-       u8 value;
-};
-
-/*
- * The following structure keeps the complete configuration of
- * the DVO, given a specific output configuration.
- * This is pretty much guess-work from reverse-engineering, so
- * read all this with a grain of salt.
- */
-struct ns2501_configuration {
-       u8 sync;                /* configuration of the C0 register */
-       u8 conf;                /* configuration register 8 */
-       u8 syncb;               /* configuration register 41 */
-       u8 dither;              /* configuration of the dithering */
-       u8 pll_a;               /* PLL configuration, register A, 1B */
-       u16 pll_b;              /* PLL configuration, register B, 1C/1D */
-       u16 hstart;             /* horizontal start, registers C1/C2 */
-       u16 hstop;              /* horizontal total, registers C3/C4 */
-       u16 vstart;             /* vertical start, registers C5/C6 */
-       u16 vstop;              /* vertical total, registers C7/C8 */
-       u16 vsync;              /* manual vertical sync start, 80/81 */
-       u16 vtotal;             /* number of lines generated, 82/83 */
-       u16 hpos;               /* horizontal position + 256, 98/99  */
-       u16 vpos;               /* vertical position, 8e/8f */
-       u16 voffs;              /* vertical output offset, 9c/9d */
-       u16 hscale;             /* horizontal scaling factor, b8/b9 */
-       u16 vscale;             /* vertical scaling factor, 10/11 */
-};
-
-/*
- * DVO configuration values, partially based on what the BIOS
- * of the Fujitsu Lifebook S6010 writes into registers,
- * partially found by manual tweaking. These configurations assume
- * a 1024x768 panel.
- */
-static const struct ns2501_configuration ns2501_modes[] = {
-       [MODE_640x480] = {
-               .sync   = NS2501_C0_ENABLE | NS2501_C0_VSYNC,
-               .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
-               .syncb  = 0x32,
-               .dither = 0x0f,
-               .pll_a  = 17,
-               .pll_b  = 852,
-               .hstart = 144,
-               .hstop  = 783,
-               .vstart = 22,
-               .vstop  = 514,
-               .vsync  = 2047, /* actually, ignored with this config */
-               .vtotal = 1341,
-               .hpos   = 0,
-               .vpos   = 16,
-               .voffs  = 36,
-               .hscale = 40960,
-               .vscale = 40960
-       },
-       [MODE_800x600] = {
-               .sync   = NS2501_C0_ENABLE |
-                         NS2501_C0_HSYNC | NS2501_C0_VSYNC,
-               .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
-               .syncb  = 0x00,
-               .dither = 0x0f,
-               .pll_a  = 25,
-               .pll_b  = 612,
-               .hstart = 215,
-               .hstop  = 1016,
-               .vstart = 26,
-               .vstop  = 627,
-               .vsync  = 807,
-               .vtotal = 1341,
-               .hpos   = 0,
-               .vpos   = 4,
-               .voffs  = 35,
-               .hscale = 51248,
-               .vscale = 51232
-       },
-       [MODE_1024x768] = {
-               .sync   = NS2501_C0_ENABLE | NS2501_C0_VSYNC,
-               .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
-               .syncb  = 0x32,
-               .dither = 0x0f,
-               .pll_a  = 11,
-               .pll_b  = 1350,
-               .hstart = 276,
-               .hstop  = 1299,
-               .vstart = 15,
-               .vstop  = 1056,
-               .vsync  = 2047,
-               .vtotal = 1341,
-               .hpos   = 0,
-               .vpos   = 7,
-               .voffs  = 27,
-               .hscale = 65535,
-               .vscale = 65535
-       }
-};
-
-/*
- * Other configuration values left by the BIOS of the
- * Fujitsu S6010 in the DVO control registers. Their
- * value does not depend on the BIOS and their meaning
- * is unknown.
- */
-
-static const struct ns2501_reg mode_agnostic_values[] = {
-       /* 08 is mode specific */
-       [0] = { .offset = 0x0a, .value = 0x81, },
-       /* 10,11 are part of the mode specific configuration */
-       [1] = { .offset = 0x12, .value = 0x02, },
-       [2] = { .offset = 0x18, .value = 0x07, },
-       [3] = { .offset = 0x19, .value = 0x00, },
-       [4] = { .offset = 0x1a, .value = 0x00, }, /* PLL?, ignored */
-       /* 1b,1c,1d are part of the mode specific configuration */
-       [5] = { .offset = 0x1e, .value = 0x02, },
-       [6] = { .offset = 0x1f, .value = 0x40, },
-       [7] = { .offset = 0x20, .value = 0x00, },
-       [8] = { .offset = 0x21, .value = 0x00, },
-       [9] = { .offset = 0x22, .value = 0x00, },
-       [10] = { .offset = 0x23, .value = 0x00, },
-       [11] = { .offset = 0x24, .value = 0x00, },
-       [12] = { .offset = 0x25, .value = 0x00, },
-       [13] = { .offset = 0x26, .value = 0x00, },
-       [14] = { .offset = 0x27, .value = 0x00, },
-       [15] = { .offset = 0x7e, .value = 0x18, },
-       /* 80-84 are part of the mode-specific configuration */
-       [16] = { .offset = 0x84, .value = 0x00, },
-       [17] = { .offset = 0x85, .value = 0x00, },
-       [18] = { .offset = 0x86, .value = 0x00, },
-       [19] = { .offset = 0x87, .value = 0x00, },
-       [20] = { .offset = 0x88, .value = 0x00, },
-       [21] = { .offset = 0x89, .value = 0x00, },
-       [22] = { .offset = 0x8a, .value = 0x00, },
-       [23] = { .offset = 0x8b, .value = 0x00, },
-       [24] = { .offset = 0x8c, .value = 0x10, },
-       [25] = { .offset = 0x8d, .value = 0x02, },
-       /* 8e,8f are part of the mode-specific configuration */
-       [26] = { .offset = 0x90, .value = 0xff, },
-       [27] = { .offset = 0x91, .value = 0x07, },
-       [28] = { .offset = 0x92, .value = 0xa0, },
-       [29] = { .offset = 0x93, .value = 0x02, },
-       [30] = { .offset = 0x94, .value = 0x00, },
-       [31] = { .offset = 0x95, .value = 0x00, },
-       [32] = { .offset = 0x96, .value = 0x05, },
-       [33] = { .offset = 0x97, .value = 0x00, },
-       /* 98,99 are part of the mode-specific configuration */
-       [34] = { .offset = 0x9a, .value = 0x88, },
-       [35] = { .offset = 0x9b, .value = 0x00, },
-       /* 9c,9d are part of the mode-specific configuration */
-       [36] = { .offset = 0x9e, .value = 0x25, },
-       [37] = { .offset = 0x9f, .value = 0x03, },
-       [38] = { .offset = 0xa0, .value = 0x28, },
-       [39] = { .offset = 0xa1, .value = 0x01, },
-       [40] = { .offset = 0xa2, .value = 0x28, },
-       [41] = { .offset = 0xa3, .value = 0x05, },
-       /* register 0xa4 is mode specific, but 0x80..0x84 works always */
-       [42] = { .offset = 0xa4, .value = 0x84, },
-       [43] = { .offset = 0xa5, .value = 0x00, },
-       [44] = { .offset = 0xa6, .value = 0x00, },
-       [45] = { .offset = 0xa7, .value = 0x00, },
-       [46] = { .offset = 0xa8, .value = 0x00, },
-       /* 0xa9 to 0xab are mode specific, but have no visible effect */
-       [47] = { .offset = 0xa9, .value = 0x04, },
-       [48] = { .offset = 0xaa, .value = 0x70, },
-       [49] = { .offset = 0xab, .value = 0x4f, },
-       [50] = { .offset = 0xac, .value = 0x00, },
-       [51] = { .offset = 0xad, .value = 0x00, },
-       [52] = { .offset = 0xb6, .value = 0x09, },
-       [53] = { .offset = 0xb7, .value = 0x03, },
-       /* b8,b9 are part of the mode-specific configuration */
-       [54] = { .offset = 0xba, .value = 0x00, },
-       [55] = { .offset = 0xbb, .value = 0x20, },
-       [56] = { .offset = 0xf3, .value = 0x90, },
-       [57] = { .offset = 0xf4, .value = 0x00, },
-       [58] = { .offset = 0xf7, .value = 0x88, },
-       /* f8 is mode specific, but the value does not matter */
-       [59] = { .offset = 0xf8, .value = 0x0a, },
-       [60] = { .offset = 0xf9, .value = 0x00, }
-};
-
-static const struct ns2501_reg regs_init[] = {
-       [0] = { .offset = 0x35, .value = 0xff, },
-       [1] = { .offset = 0x34, .value = 0x00, },
-       [2] = { .offset = 0x08, .value = 0x30, },
-};
-
-struct ns2501_priv {
-       bool quiet;
-       const struct ns2501_configuration *conf;
-};
-
-#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
-
-/*
-** Read a register from the ns2501.
-** Returns true if successful, false otherwise.
-** If it returns false, it might be wise to enable the
-** DVO with the above function.
-*/
-static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
-{
-       struct ns2501_priv *ns = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       u8 in_buf[2];
-
-       struct i2c_msg msgs[] = {
-               {
-                .addr = dvo->slave_addr,
-                .flags = 0,
-                .len = 1,
-                .buf = out_buf,
-                },
-               {
-                .addr = dvo->slave_addr,
-                .flags = I2C_M_RD,
-                .len = 1,
-                .buf = in_buf,
-                }
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = 0;
-
-       if (i2c_transfer(adapter, msgs, 2) == 2) {
-               *ch = in_buf[0];
-               return true;
-       }
-
-       if (!ns->quiet) {
-               DRM_DEBUG_KMS
-                   ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
-                    adapter->name, dvo->slave_addr);
-       }
-
-       return false;
-}
-
-/*
-** Write a register to the ns2501.
-** Returns true if successful, false otherwise.
-** If it returns false, it might be wise to enable the
-** DVO with the above function.
-*/
-static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
-{
-       struct ns2501_priv *ns = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-
-       struct i2c_msg msg = {
-               .addr = dvo->slave_addr,
-               .flags = 0,
-               .len = 2,
-               .buf = out_buf,
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = ch;
-
-       if (i2c_transfer(adapter, &msg, 1) == 1) {
-               return true;
-       }
-
-       if (!ns->quiet) {
-               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
-                             addr, adapter->name, dvo->slave_addr);
-       }
-
-       return false;
-}
-
-/* National Semiconductor 2501 driver for chip on i2c bus
- * scan for the chip on the bus.
- * Hope the VBIOS initialized the PLL correctly so we can
- * talk to it. If not, it will not be seen and not detected.
- * Bummer!
- */
-static bool ns2501_init(struct intel_dvo_device *dvo,
-                       struct i2c_adapter *adapter)
-{
-       /* this will detect the NS2501 chip on the specified i2c bus */
-       struct ns2501_priv *ns;
-       unsigned char ch;
-
-       ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
-       if (ns == NULL)
-               return false;
-
-       dvo->i2c_bus = adapter;
-       dvo->dev_priv = ns;
-       ns->quiet = true;
-
-       if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
-               goto out;
-
-       if (ch != (NS2501_VID & 0xff)) {
-               DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
-                             ch, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-
-       if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
-               goto out;
-
-       if (ch != (NS2501_DID & 0xff)) {
-               DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
-                             ch, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-       ns->quiet = false;
-
-       DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
-
-       return true;
-
-out:
-       kfree(ns);
-       return false;
-}
-
-static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
-{
-       /*
-        * This is a Laptop display, it doesn't have hotplugging.
-        * Even if not, the detection bit of the 2501 is unreliable as
-        * it only works for some display types.
-        * It is even more unreliable as the PLL must be active for
-        * allowing reading from the chiop.
-        */
-       return connector_status_connected;
-}
-
-static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
-                                             struct drm_display_mode *mode)
-{
-       DRM_DEBUG_KMS
-           ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
-            mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
-
-       /*
-        * Currently, these are all the modes I have data from.
-        * More might exist. Unclear how to find the native resolution
-        * of the panel in here so we could always accept it
-        * by disabling the scaler.
-        */
-       if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
-           (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
-           (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
-               return MODE_OK;
-       } else {
-               return MODE_ONE_SIZE;   /* Is this a reasonable error? */
-       }
-}
-
-static void ns2501_mode_set(struct intel_dvo_device *dvo,
-                           const struct drm_display_mode *mode,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       const struct ns2501_configuration *conf;
-       struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-       int mode_idx, i;
-
-       DRM_DEBUG_KMS
-           ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
-            mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
-
-       DRM_DEBUG_KMS("Detailed requested mode settings are:\n"
-                       "clock          : %d kHz\n"
-                       "hdisplay       : %d\n"
-                       "hblank start   : %d\n"
-                       "hblank end     : %d\n"
-                       "hsync start    : %d\n"
-                       "hsync end      : %d\n"
-                       "htotal         : %d\n"
-                       "hskew          : %d\n"
-                       "vdisplay       : %d\n"
-                       "vblank start   : %d\n"
-                       "hblank end     : %d\n"
-                       "vsync start    : %d\n"
-                       "vsync end      : %d\n"
-                       "vtotal         : %d\n",
-                       adjusted_mode->crtc_clock,
-                       adjusted_mode->crtc_hdisplay,
-                       adjusted_mode->crtc_hblank_start,
-                       adjusted_mode->crtc_hblank_end,
-                       adjusted_mode->crtc_hsync_start,
-                       adjusted_mode->crtc_hsync_end,
-                       adjusted_mode->crtc_htotal,
-                       adjusted_mode->crtc_hskew,
-                       adjusted_mode->crtc_vdisplay,
-                       adjusted_mode->crtc_vblank_start,
-                       adjusted_mode->crtc_vblank_end,
-                       adjusted_mode->crtc_vsync_start,
-                       adjusted_mode->crtc_vsync_end,
-                       adjusted_mode->crtc_vtotal);
-
-       if (mode->hdisplay == 640 && mode->vdisplay == 480)
-               mode_idx = MODE_640x480;
-       else if (mode->hdisplay == 800 && mode->vdisplay == 600)
-               mode_idx = MODE_800x600;
-       else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
-               mode_idx = MODE_1024x768;
-       else
-               return;
-
-       /* Hopefully doing it every time won't hurt... */
-       for (i = 0; i < ARRAY_SIZE(regs_init); i++)
-               ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
-
-       /* Write the mode-agnostic values */
-       for (i = 0; i < ARRAY_SIZE(mode_agnostic_values); i++)
-               ns2501_writeb(dvo, mode_agnostic_values[i].offset,
-                               mode_agnostic_values[i].value);
-
-       /* Write now the mode-specific configuration */
-       conf = ns2501_modes + mode_idx;
-       ns->conf = conf;
-
-       ns2501_writeb(dvo, NS2501_REG8, conf->conf);
-       ns2501_writeb(dvo, NS2501_REG1B, conf->pll_a);
-       ns2501_writeb(dvo, NS2501_REG1C, conf->pll_b & 0xff);
-       ns2501_writeb(dvo, NS2501_REG1D, conf->pll_b >> 8);
-       ns2501_writeb(dvo, NS2501_REGC1, conf->hstart & 0xff);
-       ns2501_writeb(dvo, NS2501_REGC2, conf->hstart >> 8);
-       ns2501_writeb(dvo, NS2501_REGC3, conf->hstop & 0xff);
-       ns2501_writeb(dvo, NS2501_REGC4, conf->hstop >> 8);
-       ns2501_writeb(dvo, NS2501_REGC5, conf->vstart & 0xff);
-       ns2501_writeb(dvo, NS2501_REGC6, conf->vstart >> 8);
-       ns2501_writeb(dvo, NS2501_REGC7, conf->vstop & 0xff);
-       ns2501_writeb(dvo, NS2501_REGC8, conf->vstop >> 8);
-       ns2501_writeb(dvo, NS2501_REG80, conf->vsync & 0xff);
-       ns2501_writeb(dvo, NS2501_REG81, conf->vsync >> 8);
-       ns2501_writeb(dvo, NS2501_REG82, conf->vtotal & 0xff);
-       ns2501_writeb(dvo, NS2501_REG83, conf->vtotal >> 8);
-       ns2501_writeb(dvo, NS2501_REG98, conf->hpos & 0xff);
-       ns2501_writeb(dvo, NS2501_REG99, conf->hpos >> 8);
-       ns2501_writeb(dvo, NS2501_REG8E, conf->vpos & 0xff);
-       ns2501_writeb(dvo, NS2501_REG8F, conf->vpos >> 8);
-       ns2501_writeb(dvo, NS2501_REG9C, conf->voffs & 0xff);
-       ns2501_writeb(dvo, NS2501_REG9D, conf->voffs >> 8);
-       ns2501_writeb(dvo, NS2501_REGB8, conf->hscale & 0xff);
-       ns2501_writeb(dvo, NS2501_REGB9, conf->hscale >> 8);
-       ns2501_writeb(dvo, NS2501_REG10, conf->vscale & 0xff);
-       ns2501_writeb(dvo, NS2501_REG11, conf->vscale >> 8);
-       ns2501_writeb(dvo, NS2501_REGF9, conf->dither);
-       ns2501_writeb(dvo, NS2501_REG41, conf->syncb);
-       ns2501_writeb(dvo, NS2501_REGC0, conf->sync);
-}
-
-/* set the NS2501 power state */
-static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
-{
-       unsigned char ch;
-
-       if (!ns2501_readb(dvo, NS2501_REG8, &ch))
-               return false;
-
-       return ch & NS2501_8_PD;
-}
-
-/* set the NS2501 power state */
-static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
-{
-       struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-
-       DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
-
-       if (enable) {
-               ns2501_writeb(dvo, NS2501_REGC0, ns->conf->sync | 0x08);
-
-               ns2501_writeb(dvo, NS2501_REG41, ns->conf->syncb);
-
-               ns2501_writeb(dvo, NS2501_REG34, NS2501_34_ENABLE_OUTPUT);
-               msleep(15);
-
-               ns2501_writeb(dvo, NS2501_REG8,
-                               ns->conf->conf | NS2501_8_BPAS);
-               if (!(ns->conf->conf & NS2501_8_BPAS))
-                       ns2501_writeb(dvo, NS2501_REG8, ns->conf->conf);
-               msleep(200);
-
-               ns2501_writeb(dvo, NS2501_REG34,
-                       NS2501_34_ENABLE_OUTPUT | NS2501_34_ENABLE_BACKLIGHT);
-
-               ns2501_writeb(dvo, NS2501_REGC0, ns->conf->sync);
-       } else {
-               ns2501_writeb(dvo, NS2501_REG34, NS2501_34_ENABLE_OUTPUT);
-               msleep(200);
-
-               ns2501_writeb(dvo, NS2501_REG8, NS2501_8_VEN | NS2501_8_HEN |
-                               NS2501_8_BPAS);
-               msleep(15);
-
-               ns2501_writeb(dvo, NS2501_REG34, 0x00);
-       }
-}
-
-static void ns2501_destroy(struct intel_dvo_device *dvo)
-{
-       struct ns2501_priv *ns = dvo->dev_priv;
-
-       if (ns) {
-               kfree(ns);
-               dvo->dev_priv = NULL;
-       }
-}
-
-const struct intel_dvo_dev_ops ns2501_ops = {
-       .init = ns2501_init,
-       .detect = ns2501_detect,
-       .mode_valid = ns2501_mode_valid,
-       .mode_set = ns2501_mode_set,
-       .dpms = ns2501_dpms,
-       .get_hw_state = ns2501_get_hw_state,
-       .destroy = ns2501_destroy,
-};
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
deleted file mode 100644 (file)
index 04698ea..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/**************************************************************************
-
-Copyright © 2006 Dave Airlie
-
-All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sub license, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice (including the
-next paragraph) shall be included in all copies or substantial portions
-of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-**************************************************************************/
-
-#include "intel_drv.h"
-#include "intel_dvo_dev.h"
-
-#define SIL164_VID 0x0001
-#define SIL164_DID 0x0006
-
-#define SIL164_VID_LO 0x00
-#define SIL164_VID_HI 0x01
-#define SIL164_DID_LO 0x02
-#define SIL164_DID_HI 0x03
-#define SIL164_REV    0x04
-#define SIL164_RSVD   0x05
-#define SIL164_FREQ_LO 0x06
-#define SIL164_FREQ_HI 0x07
-
-#define SIL164_REG8 0x08
-#define SIL164_8_VEN (1<<5)
-#define SIL164_8_HEN (1<<4)
-#define SIL164_8_DSEL (1<<3)
-#define SIL164_8_BSEL (1<<2)
-#define SIL164_8_EDGE (1<<1)
-#define SIL164_8_PD   (1<<0)
-
-#define SIL164_REG9 0x09
-#define SIL164_9_VLOW (1<<7)
-#define SIL164_9_MSEL_MASK (0x7<<4)
-#define SIL164_9_TSEL (1<<3)
-#define SIL164_9_RSEN (1<<2)
-#define SIL164_9_HTPLG (1<<1)
-#define SIL164_9_MDI (1<<0)
-
-#define SIL164_REGC 0x0c
-
-struct sil164_priv {
-       //I2CDevRec d;
-       bool quiet;
-};
-
-#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
-
-static bool sil164_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
-{
-       struct sil164_priv *sil = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       u8 in_buf[2];
-
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = out_buf,
-               },
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = in_buf,
-               }
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = 0;
-
-       if (i2c_transfer(adapter, msgs, 2) == 2) {
-               *ch = in_buf[0];
-               return true;
-       }
-
-       if (!sil->quiet) {
-               DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-       return false;
-}
-
-static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
-{
-       struct sil164_priv *sil = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       struct i2c_msg msg = {
-               .addr = dvo->slave_addr,
-               .flags = 0,
-               .len = 2,
-               .buf = out_buf,
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = ch;
-
-       if (i2c_transfer(adapter, &msg, 1) == 1)
-               return true;
-
-       if (!sil->quiet) {
-               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-
-       return false;
-}
-
-/* Silicon Image 164 driver for chip on i2c bus */
-static bool sil164_init(struct intel_dvo_device *dvo,
-                       struct i2c_adapter *adapter)
-{
-       /* this will detect the SIL164 chip on the specified i2c bus */
-       struct sil164_priv *sil;
-       unsigned char ch;
-
-       sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
-       if (sil == NULL)
-               return false;
-
-       dvo->i2c_bus = adapter;
-       dvo->dev_priv = sil;
-       sil->quiet = true;
-
-       if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
-               goto out;
-
-       if (ch != (SIL164_VID & 0xff)) {
-               DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
-                         ch, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-
-       if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
-               goto out;
-
-       if (ch != (SIL164_DID & 0xff)) {
-               DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
-                         ch, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-       sil->quiet = false;
-
-       DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
-       return true;
-
-out:
-       kfree(sil);
-       return false;
-}
-
-static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
-{
-       u8 reg9;
-
-       sil164_readb(dvo, SIL164_REG9, &reg9);
-
-       if (reg9 & SIL164_9_HTPLG)
-               return connector_status_connected;
-       else
-               return connector_status_disconnected;
-}
-
-static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
-                                             struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
-static void sil164_mode_set(struct intel_dvo_device *dvo,
-                           const struct drm_display_mode *mode,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       /* As long as the basics are set up, since we don't have clock
-        * dependencies in the mode setup, we can just leave the
-        * registers alone and everything will work fine.
-        */
-       /* recommended programming sequence from doc */
-       /*sil164_writeb(sil, 0x08, 0x30);
-         sil164_writeb(sil, 0x09, 0x00);
-         sil164_writeb(sil, 0x0a, 0x90);
-         sil164_writeb(sil, 0x0c, 0x89);
-         sil164_writeb(sil, 0x08, 0x31);*/
-       /* don't do much */
-       return;
-}
-
-/* set the SIL164 power state */
-static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
-{
-       int ret;
-       unsigned char ch;
-
-       ret = sil164_readb(dvo, SIL164_REG8, &ch);
-       if (ret == false)
-               return;
-
-       if (enable)
-               ch |= SIL164_8_PD;
-       else
-               ch &= ~SIL164_8_PD;
-
-       sil164_writeb(dvo, SIL164_REG8, ch);
-       return;
-}
-
-static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
-{
-       int ret;
-       unsigned char ch;
-
-       ret = sil164_readb(dvo, SIL164_REG8, &ch);
-       if (ret == false)
-               return false;
-
-       if (ch & SIL164_8_PD)
-               return true;
-       else
-               return false;
-}
-
-static void sil164_dump_regs(struct intel_dvo_device *dvo)
-{
-       u8 val;
-
-       sil164_readb(dvo, SIL164_FREQ_LO, &val);
-       DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
-       sil164_readb(dvo, SIL164_FREQ_HI, &val);
-       DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
-       sil164_readb(dvo, SIL164_REG8, &val);
-       DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val);
-       sil164_readb(dvo, SIL164_REG9, &val);
-       DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val);
-       sil164_readb(dvo, SIL164_REGC, &val);
-       DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val);
-}
-
-static void sil164_destroy(struct intel_dvo_device *dvo)
-{
-       struct sil164_priv *sil = dvo->dev_priv;
-
-       if (sil) {
-               kfree(sil);
-               dvo->dev_priv = NULL;
-       }
-}
-
-const struct intel_dvo_dev_ops sil164_ops = {
-       .init = sil164_init,
-       .detect = sil164_detect,
-       .mode_valid = sil164_mode_valid,
-       .mode_set = sil164_mode_set,
-       .dpms = sil164_dpms,
-       .get_hw_state = sil164_get_hw_state,
-       .dump_regs = sil164_dump_regs,
-       .destroy = sil164_destroy,
-};
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
deleted file mode 100644 (file)
index 623114e..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright © 2007 Dave Mueller
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Dave Mueller <dave.mueller@gmx.ch>
- *
- */
-
-#include "intel_drv.h"
-#include "intel_dvo_dev.h"
-
-/* register definitions according to the TFP410 data sheet */
-#define TFP410_VID             0x014C
-#define TFP410_DID             0x0410
-
-#define TFP410_VID_LO          0x00
-#define TFP410_VID_HI          0x01
-#define TFP410_DID_LO          0x02
-#define TFP410_DID_HI          0x03
-#define TFP410_REV             0x04
-
-#define TFP410_CTL_1           0x08
-#define TFP410_CTL_1_TDIS      (1<<6)
-#define TFP410_CTL_1_VEN       (1<<5)
-#define TFP410_CTL_1_HEN       (1<<4)
-#define TFP410_CTL_1_DSEL      (1<<3)
-#define TFP410_CTL_1_BSEL      (1<<2)
-#define TFP410_CTL_1_EDGE      (1<<1)
-#define TFP410_CTL_1_PD                (1<<0)
-
-#define TFP410_CTL_2           0x09
-#define TFP410_CTL_2_VLOW      (1<<7)
-#define TFP410_CTL_2_MSEL_MASK (0x7<<4)
-#define TFP410_CTL_2_MSEL      (1<<4)
-#define TFP410_CTL_2_TSEL      (1<<3)
-#define TFP410_CTL_2_RSEN      (1<<2)
-#define TFP410_CTL_2_HTPLG     (1<<1)
-#define TFP410_CTL_2_MDI       (1<<0)
-
-#define TFP410_CTL_3           0x0A
-#define TFP410_CTL_3_DK_MASK   (0x7<<5)
-#define TFP410_CTL_3_DK                (1<<5)
-#define TFP410_CTL_3_DKEN      (1<<4)
-#define TFP410_CTL_3_CTL_MASK  (0x7<<1)
-#define TFP410_CTL_3_CTL       (1<<1)
-
-#define TFP410_USERCFG         0x0B
-
-#define TFP410_DE_DLY          0x32
-
-#define TFP410_DE_CTL          0x33
-#define TFP410_DE_CTL_DEGEN    (1<<6)
-#define TFP410_DE_CTL_VSPOL    (1<<5)
-#define TFP410_DE_CTL_HSPOL    (1<<4)
-#define TFP410_DE_CTL_DEDLY8   (1<<0)
-
-#define TFP410_DE_TOP          0x34
-
-#define TFP410_DE_CNT_LO       0x36
-#define TFP410_DE_CNT_HI       0x37
-
-#define TFP410_DE_LIN_LO       0x38
-#define TFP410_DE_LIN_HI       0x39
-
-#define TFP410_H_RES_LO                0x3A
-#define TFP410_H_RES_HI                0x3B
-
-#define TFP410_V_RES_LO                0x3C
-#define TFP410_V_RES_HI                0x3D
-
-struct tfp410_priv {
-       bool quiet;
-};
-
-static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
-{
-       struct tfp410_priv *tfp = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       u8 in_buf[2];
-
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = out_buf,
-               },
-               {
-                       .addr = dvo->slave_addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = in_buf,
-               }
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = 0;
-
-       if (i2c_transfer(adapter, msgs, 2) == 2) {
-               *ch = in_buf[0];
-               return true;
-       }
-
-       if (!tfp->quiet) {
-               DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-       return false;
-}
-
-static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
-{
-       struct tfp410_priv *tfp = dvo->dev_priv;
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       u8 out_buf[2];
-       struct i2c_msg msg = {
-               .addr = dvo->slave_addr,
-               .flags = 0,
-               .len = 2,
-               .buf = out_buf,
-       };
-
-       out_buf[0] = addr;
-       out_buf[1] = ch;
-
-       if (i2c_transfer(adapter, &msg, 1) == 1)
-               return true;
-
-       if (!tfp->quiet) {
-               DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, adapter->name, dvo->slave_addr);
-       }
-
-       return false;
-}
-
-static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
-{
-       u8 ch1, ch2;
-
-       if (tfp410_readb(dvo, addr+0, &ch1) &&
-           tfp410_readb(dvo, addr+1, &ch2))
-               return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
-
-       return -1;
-}
-
-/* Ti TFP410 driver for chip on i2c bus */
-static bool tfp410_init(struct intel_dvo_device *dvo,
-                       struct i2c_adapter *adapter)
-{
-       /* this will detect the tfp410 chip on the specified i2c bus */
-       struct tfp410_priv *tfp;
-       int id;
-
-       tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
-       if (tfp == NULL)
-               return false;
-
-       dvo->i2c_bus = adapter;
-       dvo->dev_priv = tfp;
-       tfp->quiet = true;
-
-       if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
-               DRM_DEBUG_KMS("tfp410 not detected got VID %X: from %s "
-                               "Slave %d.\n",
-                         id, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-
-       if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
-               DRM_DEBUG_KMS("tfp410 not detected got DID %X: from %s "
-                               "Slave %d.\n",
-                         id, adapter->name, dvo->slave_addr);
-               goto out;
-       }
-       tfp->quiet = false;
-       return true;
-out:
-       kfree(tfp);
-       return false;
-}
-
-static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
-{
-       enum drm_connector_status ret = connector_status_disconnected;
-       u8 ctl2;
-
-       if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
-               if (ctl2 & TFP410_CTL_2_RSEN)
-                       ret = connector_status_connected;
-               else
-                       ret = connector_status_disconnected;
-       }
-
-       return ret;
-}
-
-static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
-                                             struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
-static void tfp410_mode_set(struct intel_dvo_device *dvo,
-                           const struct drm_display_mode *mode,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       /* As long as the basics are set up, since we don't have clock dependencies
-       * in the mode setup, we can just leave the registers alone and everything
-       * will work fine.
-       */
-       /* don't do much */
-       return;
-}
-
-/* set the tfp410 power state */
-static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
-{
-       u8 ctl1;
-
-       if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
-               return;
-
-       if (enable)
-               ctl1 |= TFP410_CTL_1_PD;
-       else
-               ctl1 &= ~TFP410_CTL_1_PD;
-
-       tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
-}
-
-static bool tfp410_get_hw_state(struct intel_dvo_device *dvo)
-{
-       u8 ctl1;
-
-       if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
-               return false;
-
-       if (ctl1 & TFP410_CTL_1_PD)
-               return true;
-       else
-               return false;
-}
-
-static void tfp410_dump_regs(struct intel_dvo_device *dvo)
-{
-       u8 val, val2;
-
-       tfp410_readb(dvo, TFP410_REV, &val);
-       DRM_DEBUG_KMS("TFP410_REV: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_CTL_1, &val);
-       DRM_DEBUG_KMS("TFP410_CTL1: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_CTL_2, &val);
-       DRM_DEBUG_KMS("TFP410_CTL2: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_CTL_3, &val);
-       DRM_DEBUG_KMS("TFP410_CTL3: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_USERCFG, &val);
-       DRM_DEBUG_KMS("TFP410_USERCFG: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_DE_DLY, &val);
-       DRM_DEBUG_KMS("TFP410_DE_DLY: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_DE_CTL, &val);
-       DRM_DEBUG_KMS("TFP410_DE_CTL: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_DE_TOP, &val);
-       DRM_DEBUG_KMS("TFP410_DE_TOP: 0x%02X\n", val);
-       tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
-       tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
-       DRM_DEBUG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
-       tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
-       tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
-       DRM_DEBUG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
-       tfp410_readb(dvo, TFP410_H_RES_LO, &val);
-       tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
-       DRM_DEBUG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);
-       tfp410_readb(dvo, TFP410_V_RES_LO, &val);
-       tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
-       DRM_DEBUG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
-}
-
-static void tfp410_destroy(struct intel_dvo_device *dvo)
-{
-       struct tfp410_priv *tfp = dvo->dev_priv;
-
-       if (tfp) {
-               kfree(tfp);
-               dvo->dev_priv = NULL;
-       }
-}
-
-const struct intel_dvo_dev_ops tfp410_ops = {
-       .init = tfp410_init,
-       .detect = tfp410_detect,
-       .mode_valid = tfp410_mode_valid,
-       .mode_set = tfp410_mode_set,
-       .dpms = tfp410_dpms,
-       .get_hw_state = tfp410_get_hw_state,
-       .dump_regs = tfp410_dump_regs,
-       .destroy = tfp410_destroy,
-};
index f584868208236f9750f041735ee0803f0a7330c0..7bee60c40394e101770fe68dbbf288163740a626 100644 (file)
 #include <drm/drm_debugfs.h>
 #include <drm/drm_fourcc.h>
 
+#include "display/intel_dp.h"
+#include "display/intel_hdmi.h"
+
 #include "gem/i915_gem_context.h"
 #include "gt/intel_reset.h"
 
 #include "i915_debugfs.h"
 #include "i915_irq.h"
 #include "intel_csr.h"
-#include "intel_dp.h"
 #include "intel_drv.h"
 #include "intel_fbc.h"
 #include "intel_guc_submission.h"
 #include "intel_hdcp.h"
-#include "intel_hdmi.h"
 #include "intel_pm.h"
 #include "intel_psr.h"
 #include "intel_sideband.h"
index 65d599065709cf98b80786656394b48903fe9399..a9a26fe65266c866d32f645ae6be57a8ca45e157 100644 (file)
@@ -47,6 +47,9 @@
 #include <drm/drm_probe_helper.h>
 #include <drm/i915_drm.h>
 
+#include "display/intel_dp.h"
+#include "display/intel_gmbus.h"
+
 #include "gem/i915_gem_context.h"
 #include "gem/i915_gem_ioctls.h"
 #include "gt/intel_gt_pm.h"
 #include "intel_bw.h"
 #include "intel_cdclk.h"
 #include "intel_csr.h"
-#include "intel_dp.h"
 #include "intel_drv.h"
 #include "intel_fbdev.h"
-#include "intel_gmbus.h"
 #include "intel_hotplug.h"
 #include "intel_overlay.h"
 #include "intel_pipe_crc.h"
index 581201bcb81ad0cb0375d826f6b969f063998c6f..1e38a60a8ec7f48c495d17860091549c80d08645 100644 (file)
 
 #include <drm/i915_drm.h>
 
+#include "display/intel_gmbus.h"
+
 #include "i915_reg.h"
 #include "intel_drv.h"
 #include "intel_fbc.h"
-#include "intel_gmbus.h"
 
 static void i915_save_display(struct drm_i915_private *dev_priv)
 {
diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c
deleted file mode 100644 (file)
index 74448e6..0000000
+++ /dev/null
@@ -1,1589 +0,0 @@
-/*
- * Copyright © 2018 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *   Madhav Chauhan <madhav.chauhan@intel.com>
- *   Jani Nikula <jani.nikula@intel.com>
- */
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_mipi_dsi.h>
-
-#include "intel_atomic.h"
-#include "intel_combo_phy.h"
-#include "intel_connector.h"
-#include "intel_ddi.h"
-#include "intel_dsi.h"
-#include "intel_panel.h"
-
-static inline int header_credits_available(struct drm_i915_private *dev_priv,
-                                          enum transcoder dsi_trans)
-{
-       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK)
-               >> FREE_HEADER_CREDIT_SHIFT;
-}
-
-static inline int payload_credits_available(struct drm_i915_private *dev_priv,
-                                           enum transcoder dsi_trans)
-{
-       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK)
-               >> FREE_PLOAD_CREDIT_SHIFT;
-}
-
-static void wait_for_header_credits(struct drm_i915_private *dev_priv,
-                                   enum transcoder dsi_trans)
-{
-       if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
-                       MAX_HEADER_CREDIT, 100))
-               DRM_ERROR("DSI header credits not released\n");
-}
-
-static void wait_for_payload_credits(struct drm_i915_private *dev_priv,
-                                    enum transcoder dsi_trans)
-{
-       if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
-                       MAX_PLOAD_CREDIT, 100))
-               DRM_ERROR("DSI payload credits not released\n");
-}
-
-static enum transcoder dsi_port_to_transcoder(enum port port)
-{
-       if (port == PORT_A)
-               return TRANSCODER_DSI_0;
-       else
-               return TRANSCODER_DSI_1;
-}
-
-static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct mipi_dsi_device *dsi;
-       enum port port;
-       enum transcoder dsi_trans;
-       int ret;
-
-       /* wait for header/payload credits to be released */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               wait_for_header_credits(dev_priv, dsi_trans);
-               wait_for_payload_credits(dev_priv, dsi_trans);
-       }
-
-       /* send nop DCS command */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi = intel_dsi->dsi_hosts[port]->device;
-               dsi->mode_flags |= MIPI_DSI_MODE_LPM;
-               dsi->channel = 0;
-               ret = mipi_dsi_dcs_nop(dsi);
-               if (ret < 0)
-                       DRM_ERROR("error sending DCS NOP command\n");
-       }
-
-       /* wait for header credits to be released */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               wait_for_header_credits(dev_priv, dsi_trans);
-       }
-
-       /* wait for LP TX in progress bit to be cleared */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               if (wait_for_us(!(I915_READ(DSI_LP_MSG(dsi_trans)) &
-                                 LPTX_IN_PROGRESS), 20))
-                       DRM_ERROR("LPTX bit not cleared\n");
-       }
-}
-
-static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data,
-                              u32 len)
-{
-       struct intel_dsi *intel_dsi = host->intel_dsi;
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-       enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
-       int free_credits;
-       int i, j;
-
-       for (i = 0; i < len; i += 4) {
-               u32 tmp = 0;
-
-               free_credits = payload_credits_available(dev_priv, dsi_trans);
-               if (free_credits < 1) {
-                       DRM_ERROR("Payload credit not available\n");
-                       return false;
-               }
-
-               for (j = 0; j < min_t(u32, len - i, 4); j++)
-                       tmp |= *data++ << 8 * j;
-
-               I915_WRITE(DSI_CMD_TXPYLD(dsi_trans), tmp);
-       }
-
-       return true;
-}
-
-static int dsi_send_pkt_hdr(struct intel_dsi_host *host,
-                           struct mipi_dsi_packet pkt, bool enable_lpdt)
-{
-       struct intel_dsi *intel_dsi = host->intel_dsi;
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-       enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
-       u32 tmp;
-       int free_credits;
-
-       /* check if header credit available */
-       free_credits = header_credits_available(dev_priv, dsi_trans);
-       if (free_credits < 1) {
-               DRM_ERROR("send pkt header failed, not enough hdr credits\n");
-               return -1;
-       }
-
-       tmp = I915_READ(DSI_CMD_TXHDR(dsi_trans));
-
-       if (pkt.payload)
-               tmp |= PAYLOAD_PRESENT;
-       else
-               tmp &= ~PAYLOAD_PRESENT;
-
-       tmp &= ~VBLANK_FENCE;
-
-       if (enable_lpdt)
-               tmp |= LP_DATA_TRANSFER;
-
-       tmp &= ~(PARAM_WC_MASK | VC_MASK | DT_MASK);
-       tmp |= ((pkt.header[0] & VC_MASK) << VC_SHIFT);
-       tmp |= ((pkt.header[0] & DT_MASK) << DT_SHIFT);
-       tmp |= (pkt.header[1] << PARAM_WC_LOWER_SHIFT);
-       tmp |= (pkt.header[2] << PARAM_WC_UPPER_SHIFT);
-       I915_WRITE(DSI_CMD_TXHDR(dsi_trans), tmp);
-
-       return 0;
-}
-
-static int dsi_send_pkt_payld(struct intel_dsi_host *host,
-                             struct mipi_dsi_packet pkt)
-{
-       /* payload queue can accept *256 bytes*, check limit */
-       if (pkt.payload_length > MAX_PLOAD_CREDIT * 4) {
-               DRM_ERROR("payload size exceeds max queue limit\n");
-               return -1;
-       }
-
-       /* load data into command payload queue */
-       if (!add_payld_to_queue(host, pkt.payload,
-                               pkt.payload_length)) {
-               DRM_ERROR("adding payload to queue failed\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-       int lane;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-
-               /*
-                * Program voltage swing and pre-emphasis level values as per
-                * table in BSPEC under DDI buffer programing
-                */
-               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
-               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
-               tmp |= SCALING_MODE_SEL(0x2);
-               tmp |= TAP2_DISABLE | TAP3_DISABLE;
-               tmp |= RTERM_SELECT(0x6);
-               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
-
-               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
-               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
-               tmp |= SCALING_MODE_SEL(0x2);
-               tmp |= TAP2_DISABLE | TAP3_DISABLE;
-               tmp |= RTERM_SELECT(0x6);
-               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
-
-               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
-               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
-                        RCOMP_SCALAR_MASK);
-               tmp |= SWING_SEL_UPPER(0x2);
-               tmp |= SWING_SEL_LOWER(0x2);
-               tmp |= RCOMP_SCALAR(0x98);
-               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
-
-               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
-               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
-                        RCOMP_SCALAR_MASK);
-               tmp |= SWING_SEL_UPPER(0x2);
-               tmp |= SWING_SEL_LOWER(0x2);
-               tmp |= RCOMP_SCALAR(0x98);
-               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
-
-               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
-               tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
-                        CURSOR_COEFF_MASK);
-               tmp |= POST_CURSOR_1(0x0);
-               tmp |= POST_CURSOR_2(0x0);
-               tmp |= CURSOR_COEFF(0x3f);
-               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
-
-               for (lane = 0; lane <= 3; lane++) {
-                       /* Bspec: must not use GRP register for write */
-                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(lane, port));
-                       tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
-                                CURSOR_COEFF_MASK);
-                       tmp |= POST_CURSOR_1(0x0);
-                       tmp |= POST_CURSOR_2(0x0);
-                       tmp |= CURSOR_COEFF(0x3f);
-                       I915_WRITE(ICL_PORT_TX_DW4_LN(lane, port), tmp);
-               }
-       }
-}
-
-static void configure_dual_link_mode(struct intel_encoder *encoder,
-                                    const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 dss_ctl1;
-
-       dss_ctl1 = I915_READ(DSS_CTL1);
-       dss_ctl1 |= SPLITTER_ENABLE;
-       dss_ctl1 &= ~OVERLAP_PIXELS_MASK;
-       dss_ctl1 |= OVERLAP_PIXELS(intel_dsi->pixel_overlap);
-
-       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
-               const struct drm_display_mode *adjusted_mode =
-                                       &pipe_config->base.adjusted_mode;
-               u32 dss_ctl2;
-               u16 hactive = adjusted_mode->crtc_hdisplay;
-               u16 dl_buffer_depth;
-
-               dss_ctl1 &= ~DUAL_LINK_MODE_INTERLEAVE;
-               dl_buffer_depth = hactive / 2 + intel_dsi->pixel_overlap;
-
-               if (dl_buffer_depth > MAX_DL_BUFFER_TARGET_DEPTH)
-                       DRM_ERROR("DL buffer depth exceed max value\n");
-
-               dss_ctl1 &= ~LEFT_DL_BUF_TARGET_DEPTH_MASK;
-               dss_ctl1 |= LEFT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
-               dss_ctl2 = I915_READ(DSS_CTL2);
-               dss_ctl2 &= ~RIGHT_DL_BUF_TARGET_DEPTH_MASK;
-               dss_ctl2 |= RIGHT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
-               I915_WRITE(DSS_CTL2, dss_ctl2);
-       } else {
-               /* Interleave */
-               dss_ctl1 |= DUAL_LINK_MODE_INTERLEAVE;
-       }
-
-       I915_WRITE(DSS_CTL1, dss_ctl1);
-}
-
-static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-       u32 afe_clk_khz; /* 8X Clock */
-       u32 esc_clk_div_m;
-
-       afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp,
-                                       intel_dsi->lane_count);
-
-       esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               I915_WRITE(ICL_DSI_ESC_CLK_DIV(port),
-                          esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
-               POSTING_READ(ICL_DSI_ESC_CLK_DIV(port));
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port),
-                          esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
-               POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port));
-       }
-}
-
-static void get_dsi_io_power_domains(struct drm_i915_private *dev_priv,
-                                    struct intel_dsi *intel_dsi)
-{
-       enum port port;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               WARN_ON(intel_dsi->io_wakeref[port]);
-               intel_dsi->io_wakeref[port] =
-                       intel_display_power_get(dev_priv,
-                                               port == PORT_A ?
-                                               POWER_DOMAIN_PORT_DDI_A_IO :
-                                               POWER_DOMAIN_PORT_DDI_B_IO);
-       }
-}
-
-static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
-               tmp |= COMBO_PHY_MODE_DSI;
-               I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
-       }
-
-       get_dsi_io_power_domains(dev_priv, intel_dsi);
-}
-
-static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       for_each_dsi_port(port, intel_dsi->ports)
-               intel_combo_phy_power_up_lanes(dev_priv, port, true,
-                                              intel_dsi->lane_count, false);
-}
-
-static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-       int lane;
-
-       /* Step 4b(i) set loadgen select for transmit and aux lanes */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
-               tmp &= ~LOADGEN_SELECT;
-               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
-               for (lane = 0; lane <= 3; lane++) {
-                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(lane, port));
-                       tmp &= ~LOADGEN_SELECT;
-                       if (lane != 2)
-                               tmp |= LOADGEN_SELECT;
-                       I915_WRITE(ICL_PORT_TX_DW4_LN(lane, port), tmp);
-               }
-       }
-
-       /* Step 4b(ii) set latency optimization for transmit and aux lanes */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
-               tmp &= ~FRC_LATENCY_OPTIM_MASK;
-               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
-               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
-               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
-               tmp &= ~FRC_LATENCY_OPTIM_MASK;
-               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
-               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
-       }
-
-}
-
-static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 tmp;
-       enum port port;
-
-       /* clear common keeper enable bit */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
-               tmp &= ~COMMON_KEEPER_EN;
-               I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp);
-               tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port));
-               tmp &= ~COMMON_KEEPER_EN;
-               I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp);
-       }
-
-       /*
-        * Set SUS Clock Config bitfield to 11b
-        * Note: loadgen select program is done
-        * as part of lane phy sequence configuration
-        */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_PORT_CL_DW5(port));
-               tmp |= SUS_CLOCK_CONFIG;
-               I915_WRITE(ICL_PORT_CL_DW5(port), tmp);
-       }
-
-       /* Clear training enable to change swing values */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
-               tmp &= ~TX_TRAINING_EN;
-               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
-               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
-               tmp &= ~TX_TRAINING_EN;
-               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
-       }
-
-       /* Program swing and de-emphasis */
-       dsi_program_swing_and_deemphasis(encoder);
-
-       /* Set training enable to trigger update */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
-               tmp |= TX_TRAINING_EN;
-               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
-               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
-               tmp |= TX_TRAINING_EN;
-               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
-       }
-}
-
-static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 tmp;
-       enum port port;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(DDI_BUF_CTL(port));
-               tmp |= DDI_BUF_CTL_ENABLE;
-               I915_WRITE(DDI_BUF_CTL(port), tmp);
-
-               if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) &
-                                 DDI_BUF_IS_IDLE),
-                                 500))
-                       DRM_ERROR("DDI port:%c buffer idle\n", port_name(port));
-       }
-}
-
-static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 tmp;
-       enum port port;
-
-       /* Program T-INIT master registers */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port));
-               tmp &= ~MASTER_INIT_TIMER_MASK;
-               tmp |= intel_dsi->init_count;
-               I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp);
-       }
-
-       /* Program DPHY clock lanes timings */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               I915_WRITE(DPHY_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg);
-
-               /* shadow register inside display core */
-               I915_WRITE(DSI_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg);
-       }
-
-       /* Program DPHY data lanes timings */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               I915_WRITE(DPHY_DATA_TIMING_PARAM(port),
-                          intel_dsi->dphy_data_lane_reg);
-
-               /* shadow register inside display core */
-               I915_WRITE(DSI_DATA_TIMING_PARAM(port),
-                          intel_dsi->dphy_data_lane_reg);
-       }
-
-       /*
-        * If DSI link operating at or below an 800 MHz,
-        * TA_SURE should be override and programmed to
-        * a value '0' inside TA_PARAM_REGISTERS otherwise
-        * leave all fields at HW default values.
-        */
-       if (intel_dsi_bitrate(intel_dsi) <= 800000) {
-               for_each_dsi_port(port, intel_dsi->ports) {
-                       tmp = I915_READ(DPHY_TA_TIMING_PARAM(port));
-                       tmp &= ~TA_SURE_MASK;
-                       tmp |= TA_SURE_OVERRIDE | TA_SURE(0);
-                       I915_WRITE(DPHY_TA_TIMING_PARAM(port), tmp);
-
-                       /* shadow register inside display core */
-                       tmp = I915_READ(DSI_TA_TIMING_PARAM(port));
-                       tmp &= ~TA_SURE_MASK;
-                       tmp |= TA_SURE_OVERRIDE | TA_SURE(0);
-                       I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp);
-               }
-       }
-}
-
-static void gen11_dsi_gate_clocks(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 tmp;
-       enum port port;
-
-       mutex_lock(&dev_priv->dpll_lock);
-       tmp = I915_READ(DPCLKA_CFGCR0_ICL);
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp |= DPCLKA_CFGCR0_DDI_CLK_OFF(port);
-       }
-
-       I915_WRITE(DPCLKA_CFGCR0_ICL, tmp);
-       mutex_unlock(&dev_priv->dpll_lock);
-}
-
-static void gen11_dsi_ungate_clocks(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 tmp;
-       enum port port;
-
-       mutex_lock(&dev_priv->dpll_lock);
-       tmp = I915_READ(DPCLKA_CFGCR0_ICL);
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
-       }
-
-       I915_WRITE(DPCLKA_CFGCR0_ICL, tmp);
-       mutex_unlock(&dev_priv->dpll_lock);
-}
-
-static void gen11_dsi_map_pll(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
-       enum port port;
-       u32 val;
-
-       mutex_lock(&dev_priv->dpll_lock);
-
-       val = I915_READ(DPCLKA_CFGCR0_ICL);
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
-               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
-       }
-       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
-       }
-       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-
-       POSTING_READ(DPCLKA_CFGCR0_ICL);
-
-       mutex_unlock(&dev_priv->dpll_lock);
-}
-
-static void
-gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       enum pipe pipe = intel_crtc->pipe;
-       u32 tmp;
-       enum port port;
-       enum transcoder dsi_trans;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               tmp = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans));
-
-               if (intel_dsi->eotp_pkt)
-                       tmp &= ~EOTP_DISABLED;
-               else
-                       tmp |= EOTP_DISABLED;
-
-               /* enable link calibration if freq > 1.5Gbps */
-               if (intel_dsi_bitrate(intel_dsi) >= 1500 * 1000) {
-                       tmp &= ~LINK_CALIBRATION_MASK;
-                       tmp |= CALIBRATION_ENABLED_INITIAL_ONLY;
-               }
-
-               /* configure continuous clock */
-               tmp &= ~CONTINUOUS_CLK_MASK;
-               if (intel_dsi->clock_stop)
-                       tmp |= CLK_ENTER_LP_AFTER_DATA;
-               else
-                       tmp |= CLK_HS_CONTINUOUS;
-
-               /* configure buffer threshold limit to minimum */
-               tmp &= ~PIX_BUF_THRESHOLD_MASK;
-               tmp |= PIX_BUF_THRESHOLD_1_4;
-
-               /* set virtual channel to '0' */
-               tmp &= ~PIX_VIRT_CHAN_MASK;
-               tmp |= PIX_VIRT_CHAN(0);
-
-               /* program BGR transmission */
-               if (intel_dsi->bgr_enabled)
-                       tmp |= BGR_TRANSMISSION;
-
-               /* select pixel format */
-               tmp &= ~PIX_FMT_MASK;
-               switch (intel_dsi->pixel_format) {
-               default:
-                       MISSING_CASE(intel_dsi->pixel_format);
-                       /* fallthrough */
-               case MIPI_DSI_FMT_RGB565:
-                       tmp |= PIX_FMT_RGB565;
-                       break;
-               case MIPI_DSI_FMT_RGB666_PACKED:
-                       tmp |= PIX_FMT_RGB666_PACKED;
-                       break;
-               case MIPI_DSI_FMT_RGB666:
-                       tmp |= PIX_FMT_RGB666_LOOSE;
-                       break;
-               case MIPI_DSI_FMT_RGB888:
-                       tmp |= PIX_FMT_RGB888;
-                       break;
-               }
-
-               /* program DSI operation mode */
-               if (is_vid_mode(intel_dsi)) {
-                       tmp &= ~OP_MODE_MASK;
-                       switch (intel_dsi->video_mode_format) {
-                       default:
-                               MISSING_CASE(intel_dsi->video_mode_format);
-                               /* fallthrough */
-                       case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS:
-                               tmp |= VIDEO_MODE_SYNC_EVENT;
-                               break;
-                       case VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE:
-                               tmp |= VIDEO_MODE_SYNC_PULSE;
-                               break;
-                       }
-               }
-
-               I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp);
-       }
-
-       /* enable port sync mode if dual link */
-       if (intel_dsi->dual_link) {
-               for_each_dsi_port(port, intel_dsi->ports) {
-                       dsi_trans = dsi_port_to_transcoder(port);
-                       tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans));
-                       tmp |= PORT_SYNC_MODE_ENABLE;
-                       I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp);
-               }
-
-               /* configure stream splitting */
-               configure_dual_link_mode(encoder, pipe_config);
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-
-               /* select data lane width */
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
-               tmp &= ~DDI_PORT_WIDTH_MASK;
-               tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count);
-
-               /* select input pipe */
-               tmp &= ~TRANS_DDI_EDP_INPUT_MASK;
-               switch (pipe) {
-               default:
-                       MISSING_CASE(pipe);
-                       /* fallthrough */
-               case PIPE_A:
-                       tmp |= TRANS_DDI_EDP_INPUT_A_ON;
-                       break;
-               case PIPE_B:
-                       tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
-                       break;
-               case PIPE_C:
-                       tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
-                       break;
-               }
-
-               /* enable DDI buffer */
-               tmp |= TRANS_DDI_FUNC_ENABLE;
-               I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp);
-       }
-
-       /* wait for link ready */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               if (wait_for_us((I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)) &
-                               LINK_READY), 2500))
-                       DRM_ERROR("DSI link not ready\n");
-       }
-}
-
-static void
-gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       const struct drm_display_mode *adjusted_mode =
-                                       &pipe_config->base.adjusted_mode;
-       enum port port;
-       enum transcoder dsi_trans;
-       /* horizontal timings */
-       u16 htotal, hactive, hsync_start, hsync_end, hsync_size;
-       u16 hfront_porch, hback_porch;
-       /* vertical timings */
-       u16 vtotal, vactive, vsync_start, vsync_end, vsync_shift;
-
-       hactive = adjusted_mode->crtc_hdisplay;
-       htotal = adjusted_mode->crtc_htotal;
-       hsync_start = adjusted_mode->crtc_hsync_start;
-       hsync_end = adjusted_mode->crtc_hsync_end;
-       hsync_size  = hsync_end - hsync_start;
-       hfront_porch = (adjusted_mode->crtc_hsync_start -
-                       adjusted_mode->crtc_hdisplay);
-       hback_porch = (adjusted_mode->crtc_htotal -
-                      adjusted_mode->crtc_hsync_end);
-       vactive = adjusted_mode->crtc_vdisplay;
-       vtotal = adjusted_mode->crtc_vtotal;
-       vsync_start = adjusted_mode->crtc_vsync_start;
-       vsync_end = adjusted_mode->crtc_vsync_end;
-       vsync_shift = hsync_start - htotal / 2;
-
-       if (intel_dsi->dual_link) {
-               hactive /= 2;
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-                       hactive += intel_dsi->pixel_overlap;
-               htotal /= 2;
-       }
-
-       /* minimum hactive as per bspec: 256 pixels */
-       if (adjusted_mode->crtc_hdisplay < 256)
-               DRM_ERROR("hactive is less then 256 pixels\n");
-
-       /* if RGB666 format, then hactive must be multiple of 4 pixels */
-       if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB666 && hactive % 4 != 0)
-               DRM_ERROR("hactive pixels are not multiple of 4\n");
-
-       /* program TRANS_HTOTAL register */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               I915_WRITE(HTOTAL(dsi_trans),
-                          (hactive - 1) | ((htotal - 1) << 16));
-       }
-
-       /* TRANS_HSYNC register to be programmed only for video mode */
-       if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) {
-               if (intel_dsi->video_mode_format ==
-                   VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE) {
-                       /* BSPEC: hsync size should be atleast 16 pixels */
-                       if (hsync_size < 16)
-                               DRM_ERROR("hsync size < 16 pixels\n");
-               }
-
-               if (hback_porch < 16)
-                       DRM_ERROR("hback porch < 16 pixels\n");
-
-               if (intel_dsi->dual_link) {
-                       hsync_start /= 2;
-                       hsync_end /= 2;
-               }
-
-               for_each_dsi_port(port, intel_dsi->ports) {
-                       dsi_trans = dsi_port_to_transcoder(port);
-                       I915_WRITE(HSYNC(dsi_trans),
-                                  (hsync_start - 1) | ((hsync_end - 1) << 16));
-               }
-       }
-
-       /* program TRANS_VTOTAL register */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               /*
-                * FIXME: Programing this by assuming progressive mode, since
-                * non-interlaced info from VBT is not saved inside
-                * struct drm_display_mode.
-                * For interlace mode: program required pixel minus 2
-                */
-               I915_WRITE(VTOTAL(dsi_trans),
-                          (vactive - 1) | ((vtotal - 1) << 16));
-       }
-
-       if (vsync_end < vsync_start || vsync_end > vtotal)
-               DRM_ERROR("Invalid vsync_end value\n");
-
-       if (vsync_start < vactive)
-               DRM_ERROR("vsync_start less than vactive\n");
-
-       /* program TRANS_VSYNC register */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               I915_WRITE(VSYNC(dsi_trans),
-                          (vsync_start - 1) | ((vsync_end - 1) << 16));
-       }
-
-       /*
-        * FIXME: It has to be programmed only for interlaced
-        * modes. Put the check condition here once interlaced
-        * info available as described above.
-        * program TRANS_VSYNCSHIFT register
-        */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               I915_WRITE(VSYNCSHIFT(dsi_trans), vsync_shift);
-       }
-}
-
-static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       enum transcoder dsi_trans;
-       u32 tmp;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               tmp = I915_READ(PIPECONF(dsi_trans));
-               tmp |= PIPECONF_ENABLE;
-               I915_WRITE(PIPECONF(dsi_trans), tmp);
-
-               /* wait for transcoder to be enabled */
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           PIPECONF(dsi_trans),
-                                           I965_PIPECONF_ACTIVE,
-                                           I965_PIPECONF_ACTIVE, 10))
-                       DRM_ERROR("DSI transcoder not enabled\n");
-       }
-}
-
-static void gen11_dsi_setup_timeouts(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       enum transcoder dsi_trans;
-       u32 tmp, hs_tx_timeout, lp_rx_timeout, ta_timeout, divisor, mul;
-
-       /*
-        * escape clock count calculation:
-        * BYTE_CLK_COUNT = TIME_NS/(8 * UI)
-        * UI (nsec) = (10^6)/Bitrate
-        * TIME_NS = (BYTE_CLK_COUNT * 8 * 10^6)/ Bitrate
-        * ESCAPE_CLK_COUNT  = TIME_NS/ESC_CLK_NS
-        */
-       divisor = intel_dsi_tlpx_ns(intel_dsi) * intel_dsi_bitrate(intel_dsi) * 1000;
-       mul = 8 * 1000000;
-       hs_tx_timeout = DIV_ROUND_UP(intel_dsi->hs_tx_timeout * mul,
-                                    divisor);
-       lp_rx_timeout = DIV_ROUND_UP(intel_dsi->lp_rx_timeout * mul, divisor);
-       ta_timeout = DIV_ROUND_UP(intel_dsi->turn_arnd_val * mul, divisor);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-
-               /* program hst_tx_timeout */
-               tmp = I915_READ(DSI_HSTX_TO(dsi_trans));
-               tmp &= ~HSTX_TIMEOUT_VALUE_MASK;
-               tmp |= HSTX_TIMEOUT_VALUE(hs_tx_timeout);
-               I915_WRITE(DSI_HSTX_TO(dsi_trans), tmp);
-
-               /* FIXME: DSI_CALIB_TO */
-
-               /* program lp_rx_host timeout */
-               tmp = I915_READ(DSI_LPRX_HOST_TO(dsi_trans));
-               tmp &= ~LPRX_TIMEOUT_VALUE_MASK;
-               tmp |= LPRX_TIMEOUT_VALUE(lp_rx_timeout);
-               I915_WRITE(DSI_LPRX_HOST_TO(dsi_trans), tmp);
-
-               /* FIXME: DSI_PWAIT_TO */
-
-               /* program turn around timeout */
-               tmp = I915_READ(DSI_TA_TO(dsi_trans));
-               tmp &= ~TA_TIMEOUT_VALUE_MASK;
-               tmp |= TA_TIMEOUT_VALUE(ta_timeout);
-               I915_WRITE(DSI_TA_TO(dsi_trans), tmp);
-       }
-}
-
-static void
-gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config)
-{
-       /* step 4a: power up all lanes of the DDI used by DSI */
-       gen11_dsi_power_up_lanes(encoder);
-
-       /* step 4b: configure lane sequencing of the Combo-PHY transmitters */
-       gen11_dsi_config_phy_lanes_sequence(encoder);
-
-       /* step 4c: configure voltage swing and skew */
-       gen11_dsi_voltage_swing_program_seq(encoder);
-
-       /* enable DDI buffer */
-       gen11_dsi_enable_ddi_buffer(encoder);
-
-       /* setup D-PHY timings */
-       gen11_dsi_setup_dphy_timings(encoder);
-
-       /* step 4h: setup DSI protocol timeouts */
-       gen11_dsi_setup_timeouts(encoder);
-
-       /* Step (4h, 4i, 4j, 4k): Configure transcoder */
-       gen11_dsi_configure_transcoder(encoder, pipe_config);
-
-       /* Step 4l: Gate DDI clocks */
-       gen11_dsi_gate_clocks(encoder);
-}
-
-static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct mipi_dsi_device *dsi;
-       enum port port;
-       enum transcoder dsi_trans;
-       u32 tmp;
-       int ret;
-
-       /* set maximum return packet size */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-
-               /*
-                * FIXME: This uses the number of DW's currently in the payload
-                * receive queue. This is probably not what we want here.
-                */
-               tmp = I915_READ(DSI_CMD_RXCTL(dsi_trans));
-               tmp &= NUMBER_RX_PLOAD_DW_MASK;
-               /* multiply "Number Rx Payload DW" by 4 to get max value */
-               tmp = tmp * 4;
-               dsi = intel_dsi->dsi_hosts[port]->device;
-               ret = mipi_dsi_set_maximum_return_packet_size(dsi, tmp);
-               if (ret < 0)
-                       DRM_ERROR("error setting max return pkt size%d\n", tmp);
-       }
-
-       /* panel power on related mipi dsi vbt sequences */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
-
-       /* ensure all panel commands dispatched before enabling transcoder */
-       wait_for_cmds_dispatched_to_panel(encoder);
-}
-
-static void gen11_dsi_pre_pll_enable(struct intel_encoder *encoder,
-                                    const struct intel_crtc_state *pipe_config,
-                                    const struct drm_connector_state *conn_state)
-{
-       /* step2: enable IO power */
-       gen11_dsi_enable_io_power(encoder);
-
-       /* step3: enable DSI PLL */
-       gen11_dsi_program_esc_clk_div(encoder);
-}
-
-static void gen11_dsi_pre_enable(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       /* step3b */
-       gen11_dsi_map_pll(encoder, pipe_config);
-
-       /* step4: enable DSI port and DPHY */
-       gen11_dsi_enable_port_and_phy(encoder, pipe_config);
-
-       /* step5: program and powerup panel */
-       gen11_dsi_powerup_panel(encoder);
-
-       /* step6c: configure transcoder timings */
-       gen11_dsi_set_transcoder_timings(encoder, pipe_config);
-
-       /* step6d: enable dsi transcoder */
-       gen11_dsi_enable_transcoder(encoder);
-
-       /* step7: enable backlight */
-       intel_panel_enable_backlight(pipe_config, conn_state);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
-}
-
-static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       enum transcoder dsi_trans;
-       u32 tmp;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-
-               /* disable transcoder */
-               tmp = I915_READ(PIPECONF(dsi_trans));
-               tmp &= ~PIPECONF_ENABLE;
-               I915_WRITE(PIPECONF(dsi_trans), tmp);
-
-               /* wait for transcoder to be disabled */
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           PIPECONF(dsi_trans),
-                                           I965_PIPECONF_ACTIVE, 0, 50))
-                       DRM_ERROR("DSI trancoder not disabled\n");
-       }
-}
-
-static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
-
-       /* ensure cmds dispatched to panel */
-       wait_for_cmds_dispatched_to_panel(encoder);
-}
-
-static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       enum transcoder dsi_trans;
-       u32 tmp;
-
-       /* put dsi link in ULPS */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               tmp = I915_READ(DSI_LP_MSG(dsi_trans));
-               tmp |= LINK_ENTER_ULPS;
-               tmp &= ~LINK_ULPS_TYPE_LP11;
-               I915_WRITE(DSI_LP_MSG(dsi_trans), tmp);
-
-               if (wait_for_us((I915_READ(DSI_LP_MSG(dsi_trans)) &
-                               LINK_IN_ULPS),
-                               10))
-                       DRM_ERROR("DSI link not in ULPS\n");
-       }
-
-       /* disable ddi function */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
-               tmp &= ~TRANS_DDI_FUNC_ENABLE;
-               I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp);
-       }
-
-       /* disable port sync mode if dual link */
-       if (intel_dsi->dual_link) {
-               for_each_dsi_port(port, intel_dsi->ports) {
-                       dsi_trans = dsi_port_to_transcoder(port);
-                       tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans));
-                       tmp &= ~PORT_SYNC_MODE_ENABLE;
-                       I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp);
-               }
-       }
-}
-
-static void gen11_dsi_disable_port(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 tmp;
-       enum port port;
-
-       gen11_dsi_ungate_clocks(encoder);
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(DDI_BUF_CTL(port));
-               tmp &= ~DDI_BUF_CTL_ENABLE;
-               I915_WRITE(DDI_BUF_CTL(port), tmp);
-
-               if (wait_for_us((I915_READ(DDI_BUF_CTL(port)) &
-                                DDI_BUF_IS_IDLE),
-                                8))
-                       DRM_ERROR("DDI port:%c buffer not idle\n",
-                                 port_name(port));
-       }
-       gen11_dsi_gate_clocks(encoder);
-}
-
-static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               intel_wakeref_t wakeref;
-
-               wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
-               intel_display_power_put(dev_priv,
-                                       port == PORT_A ?
-                                       POWER_DOMAIN_PORT_DDI_A_IO :
-                                       POWER_DOMAIN_PORT_DDI_B_IO,
-                                       wakeref);
-       }
-
-       /* set mode to DDI */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
-               tmp &= ~COMBO_PHY_MODE_DSI;
-               I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
-       }
-}
-
-static void gen11_dsi_disable(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       /* step1: turn off backlight */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
-       intel_panel_disable_backlight(old_conn_state);
-
-       /* step2d,e: disable transcoder and wait */
-       gen11_dsi_disable_transcoder(encoder);
-
-       /* step2f,g: powerdown panel */
-       gen11_dsi_powerdown_panel(encoder);
-
-       /* step2h,i,j: deconfig trancoder */
-       gen11_dsi_deconfigure_trancoder(encoder);
-
-       /* step3: disable port */
-       gen11_dsi_disable_port(encoder);
-
-       /* step4: disable IO power */
-       gen11_dsi_disable_io_power(encoder);
-}
-
-static void gen11_dsi_get_timings(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *pipe_config)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct drm_display_mode *adjusted_mode =
-                                       &pipe_config->base.adjusted_mode;
-
-       if (intel_dsi->dual_link) {
-               adjusted_mode->crtc_hdisplay *= 2;
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-                       adjusted_mode->crtc_hdisplay -=
-                                               intel_dsi->pixel_overlap;
-               adjusted_mode->crtc_htotal *= 2;
-       }
-       adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hdisplay;
-       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal;
-
-       if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) {
-               if (intel_dsi->dual_link) {
-                       adjusted_mode->crtc_hsync_start *= 2;
-                       adjusted_mode->crtc_hsync_end *= 2;
-               }
-       }
-       adjusted_mode->crtc_vblank_start = adjusted_mode->crtc_vdisplay;
-       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal;
-}
-
-static void gen11_dsi_get_config(struct intel_encoder *encoder,
-                                struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       /* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */
-       pipe_config->port_clock =
-               cnl_calc_wrpll_link(dev_priv, &pipe_config->dpll_hw_state);
-
-       pipe_config->base.adjusted_mode.crtc_clock = intel_dsi->pclk;
-       if (intel_dsi->dual_link)
-               pipe_config->base.adjusted_mode.crtc_clock *= 2;
-
-       gen11_dsi_get_timings(encoder, pipe_config);
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
-       pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
-}
-
-static int gen11_dsi_compute_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config,
-                                   struct drm_connector_state *conn_state)
-{
-       struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
-                                                  base);
-       struct intel_connector *intel_connector = intel_dsi->attached_connector;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       const struct drm_display_mode *fixed_mode =
-                                       intel_connector->panel.fixed_mode;
-       struct drm_display_mode *adjusted_mode =
-                                       &pipe_config->base.adjusted_mode;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-       intel_fixed_panel_mode(fixed_mode, adjusted_mode);
-       intel_pch_panel_fitting(crtc, pipe_config, conn_state->scaling_mode);
-
-       adjusted_mode->flags = 0;
-
-       /* Dual link goes to trancoder DSI'0' */
-       if (intel_dsi->ports == BIT(PORT_B))
-               pipe_config->cpu_transcoder = TRANSCODER_DSI_1;
-       else
-               pipe_config->cpu_transcoder = TRANSCODER_DSI_0;
-
-       pipe_config->clock_set = true;
-       pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5;
-
-       return 0;
-}
-
-static void gen11_dsi_get_power_domains(struct intel_encoder *encoder,
-                                       struct intel_crtc_state *crtc_state)
-{
-       get_dsi_io_power_domains(to_i915(encoder->base.dev),
-                                enc_to_intel_dsi(&encoder->base));
-}
-
-static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
-                                  enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum transcoder dsi_trans;
-       intel_wakeref_t wakeref;
-       enum port port;
-       bool ret = false;
-       u32 tmp;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               dsi_trans = dsi_port_to_transcoder(port);
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
-               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
-               case TRANS_DDI_EDP_INPUT_A_ON:
-                       *pipe = PIPE_A;
-                       break;
-               case TRANS_DDI_EDP_INPUT_B_ONOFF:
-                       *pipe = PIPE_B;
-                       break;
-               case TRANS_DDI_EDP_INPUT_C_ONOFF:
-                       *pipe = PIPE_C;
-                       break;
-               default:
-                       DRM_ERROR("Invalid PIPE input\n");
-                       goto out;
-               }
-
-               tmp = I915_READ(PIPECONF(dsi_trans));
-               ret = tmp & PIPECONF_ENABLE;
-       }
-out:
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-       return ret;
-}
-
-static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
-{
-       intel_encoder_destroy(encoder);
-}
-
-static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
-       .destroy = gen11_dsi_encoder_destroy,
-};
-
-static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static const struct drm_connector_helper_funcs gen11_dsi_connector_helper_funcs = {
-       .get_modes = intel_dsi_get_modes,
-       .mode_valid = intel_dsi_mode_valid,
-       .atomic_check = intel_digital_connector_atomic_check,
-};
-
-static int gen11_dsi_host_attach(struct mipi_dsi_host *host,
-                                struct mipi_dsi_device *dsi)
-{
-       return 0;
-}
-
-static int gen11_dsi_host_detach(struct mipi_dsi_host *host,
-                                struct mipi_dsi_device *dsi)
-{
-       return 0;
-}
-
-static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host,
-                                      const struct mipi_dsi_msg *msg)
-{
-       struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
-       struct mipi_dsi_packet dsi_pkt;
-       ssize_t ret;
-       bool enable_lpdt = false;
-
-       ret = mipi_dsi_create_packet(&dsi_pkt, msg);
-       if (ret < 0)
-               return ret;
-
-       if (msg->flags & MIPI_DSI_MSG_USE_LPM)
-               enable_lpdt = true;
-
-       /* send packet header */
-       ret  = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt);
-       if (ret < 0)
-               return ret;
-
-       /* only long packet contains payload */
-       if (mipi_dsi_packet_format_is_long(msg->type)) {
-               ret = dsi_send_pkt_payld(intel_dsi_host, dsi_pkt);
-               if (ret < 0)
-                       return ret;
-       }
-
-       //TODO: add payload receive code if needed
-
-       ret = sizeof(dsi_pkt.header) + dsi_pkt.payload_length;
-
-       return ret;
-}
-
-static const struct mipi_dsi_host_ops gen11_dsi_host_ops = {
-       .attach = gen11_dsi_host_attach,
-       .detach = gen11_dsi_host_detach,
-       .transfer = gen11_dsi_host_transfer,
-};
-
-#define ICL_PREPARE_CNT_MAX    0x7
-#define ICL_CLK_ZERO_CNT_MAX   0xf
-#define ICL_TRAIL_CNT_MAX      0x7
-#define ICL_TCLK_PRE_CNT_MAX   0x3
-#define ICL_TCLK_POST_CNT_MAX  0x7
-#define ICL_HS_ZERO_CNT_MAX    0xf
-#define ICL_EXIT_ZERO_CNT_MAX  0x7
-
-static void icl_dphy_param_init(struct intel_dsi *intel_dsi)
-{
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
-       u32 tlpx_ns;
-       u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
-       u32 ths_prepare_ns, tclk_trail_ns;
-       u32 hs_zero_cnt;
-       u32 tclk_pre_cnt, tclk_post_cnt;
-
-       tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
-
-       tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail);
-       ths_prepare_ns = max(mipi_config->ths_prepare,
-                            mipi_config->tclk_prepare);
-
-       /*
-        * prepare cnt in escape clocks
-        * this field represents a hexadecimal value with a precision
-        * of 1.2 – i.e. the most significant bit is the integer
-        * and the least significant 2 bits are fraction bits.
-        * so, the field can represent a range of 0.25 to 1.75
-        */
-       prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * 4, tlpx_ns);
-       if (prepare_cnt > ICL_PREPARE_CNT_MAX) {
-               DRM_DEBUG_KMS("prepare_cnt out of range (%d)\n", prepare_cnt);
-               prepare_cnt = ICL_PREPARE_CNT_MAX;
-       }
-
-       /* clk zero count in escape clocks */
-       clk_zero_cnt = DIV_ROUND_UP(mipi_config->tclk_prepare_clkzero -
-                                   ths_prepare_ns, tlpx_ns);
-       if (clk_zero_cnt > ICL_CLK_ZERO_CNT_MAX) {
-               DRM_DEBUG_KMS("clk_zero_cnt out of range (%d)\n", clk_zero_cnt);
-               clk_zero_cnt = ICL_CLK_ZERO_CNT_MAX;
-       }
-
-       /* trail cnt in escape clocks*/
-       trail_cnt = DIV_ROUND_UP(tclk_trail_ns, tlpx_ns);
-       if (trail_cnt > ICL_TRAIL_CNT_MAX) {
-               DRM_DEBUG_KMS("trail_cnt out of range (%d)\n", trail_cnt);
-               trail_cnt = ICL_TRAIL_CNT_MAX;
-       }
-
-       /* tclk pre count in escape clocks */
-       tclk_pre_cnt = DIV_ROUND_UP(mipi_config->tclk_pre, tlpx_ns);
-       if (tclk_pre_cnt > ICL_TCLK_PRE_CNT_MAX) {
-               DRM_DEBUG_KMS("tclk_pre_cnt out of range (%d)\n", tclk_pre_cnt);
-               tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX;
-       }
-
-       /* tclk post count in escape clocks */
-       tclk_post_cnt = DIV_ROUND_UP(mipi_config->tclk_post, tlpx_ns);
-       if (tclk_post_cnt > ICL_TCLK_POST_CNT_MAX) {
-               DRM_DEBUG_KMS("tclk_post_cnt out of range (%d)\n", tclk_post_cnt);
-               tclk_post_cnt = ICL_TCLK_POST_CNT_MAX;
-       }
-
-       /* hs zero cnt in escape clocks */
-       hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero -
-                                  ths_prepare_ns, tlpx_ns);
-       if (hs_zero_cnt > ICL_HS_ZERO_CNT_MAX) {
-               DRM_DEBUG_KMS("hs_zero_cnt out of range (%d)\n", hs_zero_cnt);
-               hs_zero_cnt = ICL_HS_ZERO_CNT_MAX;
-       }
-
-       /* hs exit zero cnt in escape clocks */
-       exit_zero_cnt = DIV_ROUND_UP(mipi_config->ths_exit, tlpx_ns);
-       if (exit_zero_cnt > ICL_EXIT_ZERO_CNT_MAX) {
-               DRM_DEBUG_KMS("exit_zero_cnt out of range (%d)\n", exit_zero_cnt);
-               exit_zero_cnt = ICL_EXIT_ZERO_CNT_MAX;
-       }
-
-       /* clock lane dphy timings */
-       intel_dsi->dphy_reg = (CLK_PREPARE_OVERRIDE |
-                              CLK_PREPARE(prepare_cnt) |
-                              CLK_ZERO_OVERRIDE |
-                              CLK_ZERO(clk_zero_cnt) |
-                              CLK_PRE_OVERRIDE |
-                              CLK_PRE(tclk_pre_cnt) |
-                              CLK_POST_OVERRIDE |
-                              CLK_POST(tclk_post_cnt) |
-                              CLK_TRAIL_OVERRIDE |
-                              CLK_TRAIL(trail_cnt));
-
-       /* data lanes dphy timings */
-       intel_dsi->dphy_data_lane_reg = (HS_PREPARE_OVERRIDE |
-                                        HS_PREPARE(prepare_cnt) |
-                                        HS_ZERO_OVERRIDE |
-                                        HS_ZERO(hs_zero_cnt) |
-                                        HS_TRAIL_OVERRIDE |
-                                        HS_TRAIL(trail_cnt) |
-                                        HS_EXIT_OVERRIDE |
-                                        HS_EXIT(exit_zero_cnt));
-
-       intel_dsi_log_params(intel_dsi);
-}
-
-void icl_dsi_init(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_dsi *intel_dsi;
-       struct intel_encoder *encoder;
-       struct intel_connector *intel_connector;
-       struct drm_connector *connector;
-       struct drm_display_mode *fixed_mode;
-       enum port port;
-
-       if (!intel_bios_is_dsi_present(dev_priv, &port))
-               return;
-
-       intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
-       if (!intel_dsi)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_dsi);
-               return;
-       }
-
-       encoder = &intel_dsi->base;
-       intel_dsi->attached_connector = intel_connector;
-       connector = &intel_connector->base;
-
-       /* register DSI encoder with DRM subsystem */
-       drm_encoder_init(dev, &encoder->base, &gen11_dsi_encoder_funcs,
-                        DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
-
-       encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
-       encoder->pre_enable = gen11_dsi_pre_enable;
-       encoder->disable = gen11_dsi_disable;
-       encoder->port = port;
-       encoder->get_config = gen11_dsi_get_config;
-       encoder->update_pipe = intel_panel_update_backlight;
-       encoder->compute_config = gen11_dsi_compute_config;
-       encoder->get_hw_state = gen11_dsi_get_hw_state;
-       encoder->type = INTEL_OUTPUT_DSI;
-       encoder->cloneable = 0;
-       encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C);
-       encoder->power_domain = POWER_DOMAIN_PORT_DSI;
-       encoder->get_power_domains = gen11_dsi_get_power_domains;
-
-       /* register DSI connector with DRM subsystem */
-       drm_connector_init(dev, connector, &gen11_dsi_connector_funcs,
-                          DRM_MODE_CONNECTOR_DSI);
-       drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-       connector->interlace_allowed = false;
-       connector->doublescan_allowed = false;
-       intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       /* attach connector to encoder */
-       intel_connector_attach_encoder(intel_connector, encoder);
-
-       mutex_lock(&dev->mode_config.mutex);
-       fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
-       mutex_unlock(&dev->mode_config.mutex);
-
-       if (!fixed_mode) {
-               DRM_ERROR("DSI fixed mode info missing\n");
-               goto err;
-       }
-
-       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
-
-       if (dev_priv->vbt.dsi.config->dual_link)
-               intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B);
-       else
-               intel_dsi->ports = BIT(port);
-
-       intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports;
-       intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               struct intel_dsi_host *host;
-
-               host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port);
-               if (!host)
-                       goto err;
-
-               intel_dsi->dsi_hosts[port] = host;
-       }
-
-       if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
-               DRM_DEBUG_KMS("no device found\n");
-               goto err;
-       }
-
-       icl_dphy_param_init(intel_dsi);
-       return;
-
-err:
-       drm_encoder_cleanup(&encoder->base);
-       kfree(intel_dsi);
-       kfree(intel_connector);
-}
index 1c037dfa83f5389e9aaf4089261e11dc2a50ed97..270719fabbc58c49c71fadb6e9fd11247b7d3bc0 100644 (file)
@@ -28,8 +28,9 @@
 #include <drm/drm_dp_helper.h>
 #include <drm/i915_drm.h>
 
+#include "display/intel_gmbus.h"
+
 #include "i915_drv.h"
-#include "intel_gmbus.h"
 
 #define _INTEL_BIOS_PRIVATE
 #include "intel_vbt_defs.h"
index 073b6c3ab7cc4e1d907b338c8aadac14ab9ef938..41310f8e5a2abed3d48568a8ed088c6c004e07ff 100644 (file)
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 
+#include "display/intel_panel.h"
+
 #include "i915_drv.h"
 #include "intel_connector.h"
 #include "intel_drv.h"
 #include "intel_hdcp.h"
-#include "intel_panel.h"
 
 int intel_connector_init(struct intel_connector *connector)
 {
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
deleted file mode 100644 (file)
index 3fcf2f8..0000000
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*
- * Copyright © 2006-2007 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- */
-
-#include <linux/dmi.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_connector.h"
-#include "intel_crt.h"
-#include "intel_ddi.h"
-#include "intel_drv.h"
-#include "intel_fifo_underrun.h"
-#include "intel_gmbus.h"
-#include "intel_hotplug.h"
-
-/* Here's the desired hotplug mode */
-#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |               \
-                          ADPA_CRT_HOTPLUG_WARMUP_10MS |               \
-                          ADPA_CRT_HOTPLUG_SAMPLE_4S |                 \
-                          ADPA_CRT_HOTPLUG_VOLTAGE_50 |                \
-                          ADPA_CRT_HOTPLUG_VOLREF_325MV |              \
-                          ADPA_CRT_HOTPLUG_ENABLE)
-
-struct intel_crt {
-       struct intel_encoder base;
-       /* DPMS state is stored in the connector, which we need in the
-        * encoder's enable/disable callbacks */
-       struct intel_connector *connector;
-       bool force_hotplug_required;
-       i915_reg_t adpa_reg;
-};
-
-static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
-{
-       return container_of(encoder, struct intel_crt, base);
-}
-
-static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
-{
-       return intel_encoder_to_crt(intel_attached_encoder(connector));
-}
-
-bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
-                           i915_reg_t adpa_reg, enum pipe *pipe)
-{
-       u32 val;
-
-       val = I915_READ(adpa_reg);
-
-       /* asserts want to know the pipe even if the port is disabled */
-       if (HAS_PCH_CPT(dev_priv))
-               *pipe = (val & ADPA_PIPE_SEL_MASK_CPT) >> ADPA_PIPE_SEL_SHIFT_CPT;
-       else
-               *pipe = (val & ADPA_PIPE_SEL_MASK) >> ADPA_PIPE_SEL_SHIFT;
-
-       return val & ADPA_DAC_ENABLE;
-}
-
-static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
-                                  enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       intel_wakeref_t wakeref;
-       bool ret;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       ret = intel_crt_port_enabled(dev_priv, crt->adpa_reg, pipe);
-
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-
-       return ret;
-}
-
-static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       u32 tmp, flags = 0;
-
-       tmp = I915_READ(crt->adpa_reg);
-
-       if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NHSYNC;
-
-       if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
-               flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NVSYNC;
-
-       return flags;
-}
-
-static void intel_crt_get_config(struct intel_encoder *encoder,
-                                struct intel_crtc_state *pipe_config)
-{
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG);
-
-       pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
-
-       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
-}
-
-static void hsw_crt_get_config(struct intel_encoder *encoder,
-                              struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       intel_ddi_get_config(encoder, pipe_config);
-
-       pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
-                                             DRM_MODE_FLAG_NHSYNC |
-                                             DRM_MODE_FLAG_PVSYNC |
-                                             DRM_MODE_FLAG_NVSYNC);
-       pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
-
-       pipe_config->base.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv);
-}
-
-/* Note: The caller is required to filter out dpms modes not supported by the
- * platform. */
-static void intel_crt_set_dpms(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              int mode)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
-       u32 adpa;
-
-       if (INTEL_GEN(dev_priv) >= 5)
-               adpa = ADPA_HOTPLUG_BITS;
-       else
-               adpa = 0;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-               adpa |= ADPA_HSYNC_ACTIVE_HIGH;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-               adpa |= ADPA_VSYNC_ACTIVE_HIGH;
-
-       /* For CPT allow 3 pipe config, for others just use A or B */
-       if (HAS_PCH_LPT(dev_priv))
-               ; /* Those bits don't exist here */
-       else if (HAS_PCH_CPT(dev_priv))
-               adpa |= ADPA_PIPE_SEL_CPT(crtc->pipe);
-       else
-               adpa |= ADPA_PIPE_SEL(crtc->pipe);
-
-       if (!HAS_PCH_SPLIT(dev_priv))
-               I915_WRITE(BCLRPAT(crtc->pipe), 0);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               adpa |= ADPA_DAC_ENABLE;
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-               adpa |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
-               break;
-       case DRM_MODE_DPMS_SUSPEND:
-               adpa |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
-               break;
-       case DRM_MODE_DPMS_OFF:
-               adpa |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
-               break;
-       }
-
-       I915_WRITE(crt->adpa_reg, adpa);
-}
-
-static void intel_disable_crt(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-{
-       intel_crt_set_dpms(encoder, old_crtc_state, DRM_MODE_DPMS_OFF);
-}
-
-static void pch_disable_crt(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *old_crtc_state,
-                           const struct drm_connector_state *old_conn_state)
-{
-}
-
-static void pch_post_disable_crt(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *old_crtc_state,
-                                const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_crt(encoder, old_crtc_state, old_conn_state);
-}
-
-static void hsw_disable_crt(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *old_crtc_state,
-                           const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       WARN_ON(!old_crtc_state->has_pch_encoder);
-
-       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-}
-
-static void hsw_post_disable_crt(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *old_crtc_state,
-                                const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       intel_ddi_disable_pipe_clock(old_crtc_state);
-
-       pch_post_disable_crt(encoder, old_crtc_state, old_conn_state);
-
-       lpt_disable_pch_transcoder(dev_priv);
-       lpt_disable_iclkip(dev_priv);
-
-       intel_ddi_fdi_post_disable(encoder, old_crtc_state, old_conn_state);
-
-       WARN_ON(!old_crtc_state->has_pch_encoder);
-
-       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-}
-
-static void hsw_pre_pll_enable_crt(struct intel_encoder *encoder,
-                                  const struct intel_crtc_state *crtc_state,
-                                  const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       WARN_ON(!crtc_state->has_pch_encoder);
-
-       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-}
-
-static void hsw_pre_enable_crt(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       enum pipe pipe = crtc->pipe;
-
-       WARN_ON(!crtc_state->has_pch_encoder);
-
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
-
-       dev_priv->display.fdi_link_train(crtc, crtc_state);
-
-       intel_ddi_enable_pipe_clock(crtc_state);
-}
-
-static void hsw_enable_crt(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *crtc_state,
-                          const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       enum pipe pipe = crtc->pipe;
-
-       WARN_ON(!crtc_state->has_pch_encoder);
-
-       intel_crt_set_dpms(encoder, crtc_state, DRM_MODE_DPMS_ON);
-
-       intel_wait_for_vblank(dev_priv, pipe);
-       intel_wait_for_vblank(dev_priv, pipe);
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
-       intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-}
-
-static void intel_enable_crt(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *crtc_state,
-                            const struct drm_connector_state *conn_state)
-{
-       intel_crt_set_dpms(encoder, crtc_state, DRM_MODE_DPMS_ON);
-}
-
-static enum drm_mode_status
-intel_crt_mode_valid(struct drm_connector *connector,
-                    struct drm_display_mode *mode)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int max_dotclk = dev_priv->max_dotclk_freq;
-       int max_clock;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       if (mode->clock < 25000)
-               return MODE_CLOCK_LOW;
-
-       if (HAS_PCH_LPT(dev_priv))
-               max_clock = 180000;
-       else if (IS_VALLEYVIEW(dev_priv))
-               /*
-                * 270 MHz due to current DPLL limits,
-                * DAC limit supposedly 355 MHz.
-                */
-               max_clock = 270000;
-       else if (IS_GEN_RANGE(dev_priv, 3, 4))
-               max_clock = 400000;
-       else
-               max_clock = 350000;
-       if (mode->clock > max_clock)
-               return MODE_CLOCK_HIGH;
-
-       if (mode->clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       /* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */
-       if (HAS_PCH_LPT(dev_priv) &&
-           (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2))
-               return MODE_CLOCK_HIGH;
-
-       /* HSW/BDW FDI limited to 4k */
-       if (mode->hdisplay > 4096)
-               return MODE_H_ILLEGAL;
-
-       return MODE_OK;
-}
-
-static int intel_crt_compute_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config,
-                                   struct drm_connector_state *conn_state)
-{
-       struct drm_display_mode *adjusted_mode =
-               &pipe_config->base.adjusted_mode;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       return 0;
-}
-
-static int pch_crt_compute_config(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *pipe_config,
-                                 struct drm_connector_state *conn_state)
-{
-       struct drm_display_mode *adjusted_mode =
-               &pipe_config->base.adjusted_mode;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       pipe_config->has_pch_encoder = true;
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       return 0;
-}
-
-static int hsw_crt_compute_config(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *pipe_config,
-                                 struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct drm_display_mode *adjusted_mode =
-               &pipe_config->base.adjusted_mode;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       /* HSW/BDW FDI limited to 4k */
-       if (adjusted_mode->crtc_hdisplay > 4096 ||
-           adjusted_mode->crtc_hblank_start > 4096)
-               return -EINVAL;
-
-       pipe_config->has_pch_encoder = true;
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       /* LPT FDI RX only supports 8bpc. */
-       if (HAS_PCH_LPT(dev_priv)) {
-               if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) {
-                       DRM_DEBUG_KMS("LPT only supports 24bpp\n");
-                       return -EINVAL;
-               }
-
-               pipe_config->pipe_bpp = 24;
-       }
-
-       /* FDI must always be 2.7 GHz */
-       pipe_config->port_clock = 135000 * 2;
-
-       return 0;
-}
-
-static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct intel_crt *crt = intel_attached_crt(connector);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 adpa;
-       bool ret;
-
-       /* The first time through, trigger an explicit detection cycle */
-       if (crt->force_hotplug_required) {
-               bool turn_off_dac = HAS_PCH_SPLIT(dev_priv);
-               u32 save_adpa;
-
-               crt->force_hotplug_required = 0;
-
-               save_adpa = adpa = I915_READ(crt->adpa_reg);
-               DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
-
-               adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
-               if (turn_off_dac)
-                       adpa &= ~ADPA_DAC_ENABLE;
-
-               I915_WRITE(crt->adpa_reg, adpa);
-
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           crt->adpa_reg,
-                                           ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 0,
-                                           1000))
-                       DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
-
-               if (turn_off_dac) {
-                       I915_WRITE(crt->adpa_reg, save_adpa);
-                       POSTING_READ(crt->adpa_reg);
-               }
-       }
-
-       /* Check the status to see if both blue and green are on now */
-       adpa = I915_READ(crt->adpa_reg);
-       if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
-               ret = true;
-       else
-               ret = false;
-       DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
-
-       return ret;
-}
-
-static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct intel_crt *crt = intel_attached_crt(connector);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       bool reenable_hpd;
-       u32 adpa;
-       bool ret;
-       u32 save_adpa;
-
-       /*
-        * Doing a force trigger causes a hpd interrupt to get sent, which can
-        * get us stuck in a loop if we're polling:
-        *  - We enable power wells and reset the ADPA
-        *  - output_poll_exec does force probe on VGA, triggering a hpd
-        *  - HPD handler waits for poll to unlock dev->mode_config.mutex
-        *  - output_poll_exec shuts off the ADPA, unlocks
-        *    dev->mode_config.mutex
-        *  - HPD handler runs, resets ADPA and brings us back to the start
-        *
-        * Just disable HPD interrupts here to prevent this
-        */
-       reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin);
-
-       save_adpa = adpa = I915_READ(crt->adpa_reg);
-       DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
-
-       adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
-
-       I915_WRITE(crt->adpa_reg, adpa);
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   crt->adpa_reg,
-                                   ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 0,
-                                   1000)) {
-               DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
-               I915_WRITE(crt->adpa_reg, save_adpa);
-       }
-
-       /* Check the status to see if both blue and green are on now */
-       adpa = I915_READ(crt->adpa_reg);
-       if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
-               ret = true;
-       else
-               ret = false;
-
-       DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
-
-       if (reenable_hpd)
-               intel_hpd_enable(dev_priv, crt->base.hpd_pin);
-
-       return ret;
-}
-
-static bool intel_crt_detect_hotplug(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 stat;
-       bool ret = false;
-       int i, tries = 0;
-
-       if (HAS_PCH_SPLIT(dev_priv))
-               return intel_ironlake_crt_detect_hotplug(connector);
-
-       if (IS_VALLEYVIEW(dev_priv))
-               return valleyview_crt_detect_hotplug(connector);
-
-       /*
-        * On 4 series desktop, CRT detect sequence need to be done twice
-        * to get a reliable result.
-        */
-
-       if (IS_G45(dev_priv))
-               tries = 2;
-       else
-               tries = 1;
-
-       for (i = 0; i < tries ; i++) {
-               /* turn on the FORCE_DETECT */
-               i915_hotplug_interrupt_update(dev_priv,
-                                             CRT_HOTPLUG_FORCE_DETECT,
-                                             CRT_HOTPLUG_FORCE_DETECT);
-               /* wait for FORCE_DETECT to go off */
-               if (intel_wait_for_register(&dev_priv->uncore, PORT_HOTPLUG_EN,
-                                           CRT_HOTPLUG_FORCE_DETECT, 0,
-                                           1000))
-                       DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
-       }
-
-       stat = I915_READ(PORT_HOTPLUG_STAT);
-       if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
-               ret = true;
-
-       /* clear the interrupt we just generated, if any */
-       I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
-
-       i915_hotplug_interrupt_update(dev_priv, CRT_HOTPLUG_FORCE_DETECT, 0);
-
-       return ret;
-}
-
-static struct edid *intel_crt_get_edid(struct drm_connector *connector,
-                               struct i2c_adapter *i2c)
-{
-       struct edid *edid;
-
-       edid = drm_get_edid(connector, i2c);
-
-       if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
-               DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n");
-               intel_gmbus_force_bit(i2c, true);
-               edid = drm_get_edid(connector, i2c);
-               intel_gmbus_force_bit(i2c, false);
-       }
-
-       return edid;
-}
-
-/* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */
-static int intel_crt_ddc_get_modes(struct drm_connector *connector,
-                               struct i2c_adapter *adapter)
-{
-       struct edid *edid;
-       int ret;
-
-       edid = intel_crt_get_edid(connector, adapter);
-       if (!edid)
-               return 0;
-
-       ret = intel_connector_update_modes(connector, edid);
-       kfree(edid);
-
-       return ret;
-}
-
-static bool intel_crt_detect_ddc(struct drm_connector *connector)
-{
-       struct intel_crt *crt = intel_attached_crt(connector);
-       struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev);
-       struct edid *edid;
-       struct i2c_adapter *i2c;
-       bool ret = false;
-
-       BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
-
-       i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
-       edid = intel_crt_get_edid(connector, i2c);
-
-       if (edid) {
-               bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
-
-               /*
-                * This may be a DVI-I connector with a shared DDC
-                * link between analog and digital outputs, so we
-                * have to check the EDID input spec of the attached device.
-                */
-               if (!is_digital) {
-                       DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
-                       ret = true;
-               } else {
-                       DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
-               }
-       } else {
-               DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
-       }
-
-       kfree(edid);
-
-       return ret;
-}
-
-static enum drm_connector_status
-intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
-{
-       struct drm_device *dev = crt->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_uncore *uncore = &dev_priv->uncore;
-       u32 save_bclrpat;
-       u32 save_vtotal;
-       u32 vtotal, vactive;
-       u32 vsample;
-       u32 vblank, vblank_start, vblank_end;
-       u32 dsl;
-       i915_reg_t bclrpat_reg, vtotal_reg,
-               vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg;
-       u8 st00;
-       enum drm_connector_status status;
-
-       DRM_DEBUG_KMS("starting load-detect on CRT\n");
-
-       bclrpat_reg = BCLRPAT(pipe);
-       vtotal_reg = VTOTAL(pipe);
-       vblank_reg = VBLANK(pipe);
-       vsync_reg = VSYNC(pipe);
-       pipeconf_reg = PIPECONF(pipe);
-       pipe_dsl_reg = PIPEDSL(pipe);
-
-       save_bclrpat = intel_uncore_read(uncore, bclrpat_reg);
-       save_vtotal = intel_uncore_read(uncore, vtotal_reg);
-       vblank = intel_uncore_read(uncore, vblank_reg);
-
-       vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
-       vactive = (save_vtotal & 0x7ff) + 1;
-
-       vblank_start = (vblank & 0xfff) + 1;
-       vblank_end = ((vblank >> 16) & 0xfff) + 1;
-
-       /* Set the border color to purple. */
-       intel_uncore_write(uncore, bclrpat_reg, 0x500050);
-
-       if (!IS_GEN(dev_priv, 2)) {
-               u32 pipeconf = intel_uncore_read(uncore, pipeconf_reg);
-               intel_uncore_write(uncore,
-                                  pipeconf_reg,
-                                  pipeconf | PIPECONF_FORCE_BORDER);
-               intel_uncore_posting_read(uncore, pipeconf_reg);
-               /* Wait for next Vblank to substitue
-                * border color for Color info */
-               intel_wait_for_vblank(dev_priv, pipe);
-               st00 = intel_uncore_read8(uncore, _VGA_MSR_WRITE);
-               status = ((st00 & (1 << 4)) != 0) ?
-                       connector_status_connected :
-                       connector_status_disconnected;
-
-               intel_uncore_write(uncore, pipeconf_reg, pipeconf);
-       } else {
-               bool restore_vblank = false;
-               int count, detect;
-
-               /*
-               * If there isn't any border, add some.
-               * Yes, this will flicker
-               */
-               if (vblank_start <= vactive && vblank_end >= vtotal) {
-                       u32 vsync = I915_READ(vsync_reg);
-                       u32 vsync_start = (vsync & 0xffff) + 1;
-
-                       vblank_start = vsync_start;
-                       intel_uncore_write(uncore,
-                                          vblank_reg,
-                                          (vblank_start - 1) |
-                                          ((vblank_end - 1) << 16));
-                       restore_vblank = true;
-               }
-               /* sample in the vertical border, selecting the larger one */
-               if (vblank_start - vactive >= vtotal - vblank_end)
-                       vsample = (vblank_start + vactive) >> 1;
-               else
-                       vsample = (vtotal + vblank_end) >> 1;
-
-               /*
-                * Wait for the border to be displayed
-                */
-               while (intel_uncore_read(uncore, pipe_dsl_reg) >= vactive)
-                       ;
-               while ((dsl = intel_uncore_read(uncore, pipe_dsl_reg)) <=
-                      vsample)
-                       ;
-               /*
-                * Watch ST00 for an entire scanline
-                */
-               detect = 0;
-               count = 0;
-               do {
-                       count++;
-                       /* Read the ST00 VGA status register */
-                       st00 = intel_uncore_read8(uncore, _VGA_MSR_WRITE);
-                       if (st00 & (1 << 4))
-                               detect++;
-               } while ((intel_uncore_read(uncore, pipe_dsl_reg) == dsl));
-
-               /* restore vblank if necessary */
-               if (restore_vblank)
-                       intel_uncore_write(uncore, vblank_reg, vblank);
-               /*
-                * If more than 3/4 of the scanline detected a monitor,
-                * then it is assumed to be present. This works even on i830,
-                * where there isn't any way to force the border color across
-                * the screen
-                */
-               status = detect * 4 > count * 3 ?
-                        connector_status_connected :
-                        connector_status_disconnected;
-       }
-
-       /* Restore previous settings */
-       intel_uncore_write(uncore, bclrpat_reg, save_bclrpat);
-
-       return status;
-}
-
-static int intel_spurious_crt_detect_dmi_callback(const struct dmi_system_id *id)
-{
-       DRM_DEBUG_DRIVER("Skipping CRT detection for %s\n", id->ident);
-       return 1;
-}
-
-static const struct dmi_system_id intel_spurious_crt_detect[] = {
-       {
-               .callback = intel_spurious_crt_detect_dmi_callback,
-               .ident = "ACER ZGB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
-               },
-       },
-       {
-               .callback = intel_spurious_crt_detect_dmi_callback,
-               .ident = "Intel DZ77BH-55K",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-                       DMI_MATCH(DMI_BOARD_NAME, "DZ77BH-55K"),
-               },
-       },
-       { }
-};
-
-static int
-intel_crt_detect(struct drm_connector *connector,
-                struct drm_modeset_acquire_ctx *ctx,
-                bool force)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_crt *crt = intel_attached_crt(connector);
-       struct intel_encoder *intel_encoder = &crt->base;
-       intel_wakeref_t wakeref;
-       int status, ret;
-       struct intel_load_detect_pipe tmp;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
-                     connector->base.id, connector->name,
-                     force);
-
-       if (i915_modparams.load_detect_test) {
-               wakeref = intel_display_power_get(dev_priv,
-                                                 intel_encoder->power_domain);
-               goto load_detect;
-       }
-
-       /* Skip machines without VGA that falsely report hotplug events */
-       if (dmi_check_system(intel_spurious_crt_detect))
-               return connector_status_disconnected;
-
-       wakeref = intel_display_power_get(dev_priv,
-                                         intel_encoder->power_domain);
-
-       if (I915_HAS_HOTPLUG(dev_priv)) {
-               /* We can not rely on the HPD pin always being correctly wired
-                * up, for example many KVM do not pass it through, and so
-                * only trust an assertion that the monitor is connected.
-                */
-               if (intel_crt_detect_hotplug(connector)) {
-                       DRM_DEBUG_KMS("CRT detected via hotplug\n");
-                       status = connector_status_connected;
-                       goto out;
-               } else
-                       DRM_DEBUG_KMS("CRT not detected via hotplug\n");
-       }
-
-       if (intel_crt_detect_ddc(connector)) {
-               status = connector_status_connected;
-               goto out;
-       }
-
-       /* Load detection is broken on HPD capable machines. Whoever wants a
-        * broken monitor (without edid) to work behind a broken kvm (that fails
-        * to have the right resistors for HP detection) needs to fix this up.
-        * For now just bail out. */
-       if (I915_HAS_HOTPLUG(dev_priv)) {
-               status = connector_status_disconnected;
-               goto out;
-       }
-
-load_detect:
-       if (!force) {
-               status = connector->status;
-               goto out;
-       }
-
-       /* for pre-945g platforms use load detect */
-       ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
-       if (ret > 0) {
-               if (intel_crt_detect_ddc(connector))
-                       status = connector_status_connected;
-               else if (INTEL_GEN(dev_priv) < 4)
-                       status = intel_crt_load_detect(crt,
-                               to_intel_crtc(connector->state->crtc)->pipe);
-               else if (i915_modparams.load_detect_test)
-                       status = connector_status_disconnected;
-               else
-                       status = connector_status_unknown;
-               intel_release_load_detect_pipe(connector, &tmp, ctx);
-       } else if (ret == 0) {
-               status = connector_status_unknown;
-       } else {
-               status = ret;
-       }
-
-out:
-       intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
-       return status;
-}
-
-static int intel_crt_get_modes(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crt *crt = intel_attached_crt(connector);
-       struct intel_encoder *intel_encoder = &crt->base;
-       intel_wakeref_t wakeref;
-       struct i2c_adapter *i2c;
-       int ret;
-
-       wakeref = intel_display_power_get(dev_priv,
-                                         intel_encoder->power_domain);
-
-       i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
-       ret = intel_crt_ddc_get_modes(connector, i2c);
-       if (ret || !IS_G4X(dev_priv))
-               goto out;
-
-       /* Try to probe digital port for output in DVI-I -> VGA mode. */
-       i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB);
-       ret = intel_crt_ddc_get_modes(connector, i2c);
-
-out:
-       intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
-
-       return ret;
-}
-
-void intel_crt_reset(struct drm_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_crt *crt = intel_encoder_to_crt(to_intel_encoder(encoder));
-
-       if (INTEL_GEN(dev_priv) >= 5) {
-               u32 adpa;
-
-               adpa = I915_READ(crt->adpa_reg);
-               adpa &= ~ADPA_CRT_HOTPLUG_MASK;
-               adpa |= ADPA_HOTPLUG_BITS;
-               I915_WRITE(crt->adpa_reg, adpa);
-               POSTING_READ(crt->adpa_reg);
-
-               DRM_DEBUG_KMS("crt adpa set to 0x%x\n", adpa);
-               crt->force_hotplug_required = 1;
-       }
-
-}
-
-/*
- * Routines for controlling stuff on the analog port
- */
-
-static const struct drm_connector_funcs intel_crt_connector_funcs = {
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-};
-
-static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
-       .detect_ctx = intel_crt_detect,
-       .mode_valid = intel_crt_mode_valid,
-       .get_modes = intel_crt_get_modes,
-};
-
-static const struct drm_encoder_funcs intel_crt_enc_funcs = {
-       .reset = intel_crt_reset,
-       .destroy = intel_encoder_destroy,
-};
-
-void intel_crt_init(struct drm_i915_private *dev_priv)
-{
-       struct drm_connector *connector;
-       struct intel_crt *crt;
-       struct intel_connector *intel_connector;
-       i915_reg_t adpa_reg;
-       u32 adpa;
-
-       if (HAS_PCH_SPLIT(dev_priv))
-               adpa_reg = PCH_ADPA;
-       else if (IS_VALLEYVIEW(dev_priv))
-               adpa_reg = VLV_ADPA;
-       else
-               adpa_reg = ADPA;
-
-       adpa = I915_READ(adpa_reg);
-       if ((adpa & ADPA_DAC_ENABLE) == 0) {
-               /*
-                * On some machines (some IVB at least) CRT can be
-                * fused off, but there's no known fuse bit to
-                * indicate that. On these machine the ADPA register
-                * works normally, except the DAC enable bit won't
-                * take. So the only way to tell is attempt to enable
-                * it and see what happens.
-                */
-               I915_WRITE(adpa_reg, adpa | ADPA_DAC_ENABLE |
-                          ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
-               if ((I915_READ(adpa_reg) & ADPA_DAC_ENABLE) == 0)
-                       return;
-               I915_WRITE(adpa_reg, adpa);
-       }
-
-       crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
-       if (!crt)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(crt);
-               return;
-       }
-
-       connector = &intel_connector->base;
-       crt->connector = intel_connector;
-       drm_connector_init(&dev_priv->drm, &intel_connector->base,
-                          &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
-
-       drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs,
-                        DRM_MODE_ENCODER_DAC, "CRT");
-
-       intel_connector_attach_encoder(intel_connector, &crt->base);
-
-       crt->base.type = INTEL_OUTPUT_ANALOG;
-       crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI);
-       if (IS_I830(dev_priv))
-               crt->base.crtc_mask = (1 << 0);
-       else
-               crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-
-       if (IS_GEN(dev_priv, 2))
-               connector->interlace_allowed = 0;
-       else
-               connector->interlace_allowed = 1;
-       connector->doublescan_allowed = 0;
-
-       crt->adpa_reg = adpa_reg;
-
-       crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
-
-       if (I915_HAS_HOTPLUG(dev_priv) &&
-           !dmi_check_system(intel_spurious_crt_detect)) {
-               crt->base.hpd_pin = HPD_CRT;
-               crt->base.hotplug = intel_encoder_hotplug;
-       }
-
-       if (HAS_DDI(dev_priv)) {
-               crt->base.port = PORT_E;
-               crt->base.get_config = hsw_crt_get_config;
-               crt->base.get_hw_state = intel_ddi_get_hw_state;
-               crt->base.compute_config = hsw_crt_compute_config;
-               crt->base.pre_pll_enable = hsw_pre_pll_enable_crt;
-               crt->base.pre_enable = hsw_pre_enable_crt;
-               crt->base.enable = hsw_enable_crt;
-               crt->base.disable = hsw_disable_crt;
-               crt->base.post_disable = hsw_post_disable_crt;
-       } else {
-               if (HAS_PCH_SPLIT(dev_priv)) {
-                       crt->base.compute_config = pch_crt_compute_config;
-                       crt->base.disable = pch_disable_crt;
-                       crt->base.post_disable = pch_post_disable_crt;
-               } else {
-                       crt->base.compute_config = intel_crt_compute_config;
-                       crt->base.disable = intel_disable_crt;
-               }
-               crt->base.port = PORT_NONE;
-               crt->base.get_config = intel_crt_get_config;
-               crt->base.get_hw_state = intel_crt_get_hw_state;
-               crt->base.enable = intel_enable_crt;
-       }
-       intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
-
-       if (!I915_HAS_HOTPLUG(dev_priv))
-               intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-
-       /*
-        * Configure the automatic hotplug detection stuff
-        */
-       crt->force_hotplug_required = 0;
-
-       /*
-        * TODO: find a proper way to discover whether we need to set the the
-        * polarity and link reversal bits or not, instead of relying on the
-        * BIOS.
-        */
-       if (HAS_PCH_LPT(dev_priv)) {
-               u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
-                                FDI_RX_LINK_REVERSAL_OVERRIDE;
-
-               dev_priv->fdi_rx_config = I915_READ(FDI_RX_CTL(PIPE_A)) & fdi_config;
-       }
-
-       intel_crt_reset(&crt->base.base);
-}
diff --git a/drivers/gpu/drm/i915/intel_crt.h b/drivers/gpu/drm/i915/intel_crt.h
deleted file mode 100644 (file)
index 1b3fba3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_CRT_H__
-#define __INTEL_CRT_H__
-
-#include "i915_reg.h"
-
-enum pipe;
-struct drm_encoder;
-struct drm_i915_private;
-struct drm_i915_private;
-
-bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
-                           i915_reg_t adpa_reg, enum pipe *pipe);
-void intel_crt_init(struct drm_i915_private *dev_priv);
-void intel_crt_reset(struct drm_encoder *encoder);
-
-#endif /* __INTEL_CRT_H__ */
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
deleted file mode 100644 (file)
index 7925a17..0000000
+++ /dev/null
@@ -1,4335 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Eugeni Dodonov <eugeni.dodonov@intel.com>
- *
- */
-
-#include <drm/drm_scdc_helper.h>
-
-#include "i915_drv.h"
-#include "intel_audio.h"
-#include "intel_combo_phy.h"
-#include "intel_connector.h"
-#include "intel_ddi.h"
-#include "intel_dp.h"
-#include "intel_dp_link_training.h"
-#include "intel_dpio_phy.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_fifo_underrun.h"
-#include "intel_gmbus.h"
-#include "intel_hdcp.h"
-#include "intel_hdmi.h"
-#include "intel_hotplug.h"
-#include "intel_lspcon.h"
-#include "intel_panel.h"
-#include "intel_psr.h"
-#include "intel_vdsc.h"
-
-struct ddi_buf_trans {
-       u32 trans1;     /* balance leg enable, de-emph level */
-       u32 trans2;     /* vref sel, vswing */
-       u8 i_boost;     /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */
-};
-
-static const u8 index_to_dp_signal_levels[] = {
-       [0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0,
-       [1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1,
-       [2] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2,
-       [3] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3,
-       [4] = DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0,
-       [5] = DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1,
-       [6] = DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2,
-       [7] = DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0,
-       [8] = DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1,
-       [9] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0,
-};
-
-/* HDMI/DVI modes ignore everything but the last 2 items. So we share
- * them for both DP and FDI transports, allowing those ports to
- * automatically adapt to HDMI connections as well
- */
-static const struct ddi_buf_trans hsw_ddi_translations_dp[] = {
-       { 0x00FFFFFF, 0x0006000E, 0x0 },
-       { 0x00D75FFF, 0x0005000A, 0x0 },
-       { 0x00C30FFF, 0x00040006, 0x0 },
-       { 0x80AAAFFF, 0x000B0000, 0x0 },
-       { 0x00FFFFFF, 0x0005000A, 0x0 },
-       { 0x00D75FFF, 0x000C0004, 0x0 },
-       { 0x80C30FFF, 0x000B0000, 0x0 },
-       { 0x00FFFFFF, 0x00040006, 0x0 },
-       { 0x80D75FFF, 0x000B0000, 0x0 },
-};
-
-static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = {
-       { 0x00FFFFFF, 0x0007000E, 0x0 },
-       { 0x00D75FFF, 0x000F000A, 0x0 },
-       { 0x00C30FFF, 0x00060006, 0x0 },
-       { 0x00AAAFFF, 0x001E0000, 0x0 },
-       { 0x00FFFFFF, 0x000F000A, 0x0 },
-       { 0x00D75FFF, 0x00160004, 0x0 },
-       { 0x00C30FFF, 0x001E0000, 0x0 },
-       { 0x00FFFFFF, 0x00060006, 0x0 },
-       { 0x00D75FFF, 0x001E0000, 0x0 },
-};
-
-static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = {
-                                       /* Idx  NT mV d T mV d  db      */
-       { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0:   400     400     0       */
-       { 0x00E79FFF, 0x000E000C, 0x0 },/* 1:   400     500     2       */
-       { 0x00D75FFF, 0x0005000A, 0x0 },/* 2:   400     600     3.5     */
-       { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3:   600     600     0       */
-       { 0x00E79FFF, 0x001D0007, 0x0 },/* 4:   600     750     2       */
-       { 0x00D75FFF, 0x000C0004, 0x0 },/* 5:   600     900     3.5     */
-       { 0x00FFFFFF, 0x00040006, 0x0 },/* 6:   800     800     0       */
-       { 0x80E79FFF, 0x00030002, 0x0 },/* 7:   800     1000    2       */
-       { 0x00FFFFFF, 0x00140005, 0x0 },/* 8:   850     850     0       */
-       { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9:   900     900     0       */
-       { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10:  950     950     0       */
-       { 0x80FFFFFF, 0x00030002, 0x0 },/* 11:  1000    1000    0       */
-};
-
-static const struct ddi_buf_trans bdw_ddi_translations_edp[] = {
-       { 0x00FFFFFF, 0x00000012, 0x0 },
-       { 0x00EBAFFF, 0x00020011, 0x0 },
-       { 0x00C71FFF, 0x0006000F, 0x0 },
-       { 0x00AAAFFF, 0x000E000A, 0x0 },
-       { 0x00FFFFFF, 0x00020011, 0x0 },
-       { 0x00DB6FFF, 0x0005000F, 0x0 },
-       { 0x00BEEFFF, 0x000A000C, 0x0 },
-       { 0x00FFFFFF, 0x0005000F, 0x0 },
-       { 0x00DB6FFF, 0x000A000C, 0x0 },
-};
-
-static const struct ddi_buf_trans bdw_ddi_translations_dp[] = {
-       { 0x00FFFFFF, 0x0007000E, 0x0 },
-       { 0x00D75FFF, 0x000E000A, 0x0 },
-       { 0x00BEFFFF, 0x00140006, 0x0 },
-       { 0x80B2CFFF, 0x001B0002, 0x0 },
-       { 0x00FFFFFF, 0x000E000A, 0x0 },
-       { 0x00DB6FFF, 0x00160005, 0x0 },
-       { 0x80C71FFF, 0x001A0002, 0x0 },
-       { 0x00F7DFFF, 0x00180004, 0x0 },
-       { 0x80D75FFF, 0x001B0002, 0x0 },
-};
-
-static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = {
-       { 0x00FFFFFF, 0x0001000E, 0x0 },
-       { 0x00D75FFF, 0x0004000A, 0x0 },
-       { 0x00C30FFF, 0x00070006, 0x0 },
-       { 0x00AAAFFF, 0x000C0000, 0x0 },
-       { 0x00FFFFFF, 0x0004000A, 0x0 },
-       { 0x00D75FFF, 0x00090004, 0x0 },
-       { 0x00C30FFF, 0x000C0000, 0x0 },
-       { 0x00FFFFFF, 0x00070006, 0x0 },
-       { 0x00D75FFF, 0x000C0000, 0x0 },
-};
-
-static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
-                                       /* Idx  NT mV d T mV df db      */
-       { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0:   400     400     0       */
-       { 0x00D75FFF, 0x000E000A, 0x0 },/* 1:   400     600     3.5     */
-       { 0x00BEFFFF, 0x00140006, 0x0 },/* 2:   400     800     6       */
-       { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3:   450     450     0       */
-       { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4:   600     600     0       */
-       { 0x00D7FFFF, 0x00140006, 0x0 },/* 5:   600     800     2.5     */
-       { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6:   600     1000    4.5     */
-       { 0x00FFFFFF, 0x00140006, 0x0 },/* 7:   800     800     0       */
-       { 0x80E79FFF, 0x001B0002, 0x0 },/* 8:   800     1000    2       */
-       { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9:   1000    1000    0       */
-};
-
-/* Skylake H and S */
-static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
-       { 0x00002016, 0x000000A0, 0x0 },
-       { 0x00005012, 0x0000009B, 0x0 },
-       { 0x00007011, 0x00000088, 0x0 },
-       { 0x80009010, 0x000000C0, 0x1 },
-       { 0x00002016, 0x0000009B, 0x0 },
-       { 0x00005012, 0x00000088, 0x0 },
-       { 0x80007011, 0x000000C0, 0x1 },
-       { 0x00002016, 0x000000DF, 0x0 },
-       { 0x80005012, 0x000000C0, 0x1 },
-};
-
-/* Skylake U */
-static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = {
-       { 0x0000201B, 0x000000A2, 0x0 },
-       { 0x00005012, 0x00000088, 0x0 },
-       { 0x80007011, 0x000000CD, 0x1 },
-       { 0x80009010, 0x000000C0, 0x1 },
-       { 0x0000201B, 0x0000009D, 0x0 },
-       { 0x80005012, 0x000000C0, 0x1 },
-       { 0x80007011, 0x000000C0, 0x1 },
-       { 0x00002016, 0x00000088, 0x0 },
-       { 0x80005012, 0x000000C0, 0x1 },
-};
-
-/* Skylake Y */
-static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = {
-       { 0x00000018, 0x000000A2, 0x0 },
-       { 0x00005012, 0x00000088, 0x0 },
-       { 0x80007011, 0x000000CD, 0x3 },
-       { 0x80009010, 0x000000C0, 0x3 },
-       { 0x00000018, 0x0000009D, 0x0 },
-       { 0x80005012, 0x000000C0, 0x3 },
-       { 0x80007011, 0x000000C0, 0x3 },
-       { 0x00000018, 0x00000088, 0x0 },
-       { 0x80005012, 0x000000C0, 0x3 },
-};
-
-/* Kabylake H and S */
-static const struct ddi_buf_trans kbl_ddi_translations_dp[] = {
-       { 0x00002016, 0x000000A0, 0x0 },
-       { 0x00005012, 0x0000009B, 0x0 },
-       { 0x00007011, 0x00000088, 0x0 },
-       { 0x80009010, 0x000000C0, 0x1 },
-       { 0x00002016, 0x0000009B, 0x0 },
-       { 0x00005012, 0x00000088, 0x0 },
-       { 0x80007011, 0x000000C0, 0x1 },
-       { 0x00002016, 0x00000097, 0x0 },
-       { 0x80005012, 0x000000C0, 0x1 },
-};
-
-/* Kabylake U */
-static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = {
-       { 0x0000201B, 0x000000A1, 0x0 },
-       { 0x00005012, 0x00000088, 0x0 },
-       { 0x80007011, 0x000000CD, 0x3 },
-       { 0x80009010, 0x000000C0, 0x3 },
-       { 0x0000201B, 0x0000009D, 0x0 },
-       { 0x80005012, 0x000000C0, 0x3 },
-       { 0x80007011, 0x000000C0, 0x3 },
-       { 0x00002016, 0x0000004F, 0x0 },
-       { 0x80005012, 0x000000C0, 0x3 },
-};
-
-/* Kabylake Y */
-static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = {
-       { 0x00001017, 0x000000A1, 0x0 },
-       { 0x00005012, 0x00000088, 0x0 },
-       { 0x80007011, 0x000000CD, 0x3 },
-       { 0x8000800F, 0x000000C0, 0x3 },
-       { 0x00001017, 0x0000009D, 0x0 },
-       { 0x80005012, 0x000000C0, 0x3 },
-       { 0x80007011, 0x000000C0, 0x3 },
-       { 0x00001017, 0x0000004C, 0x0 },
-       { 0x80005012, 0x000000C0, 0x3 },
-};
-
-/*
- * Skylake/Kabylake H and S
- * eDP 1.4 low vswing translation parameters
- */
-static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
-       { 0x00000018, 0x000000A8, 0x0 },
-       { 0x00004013, 0x000000A9, 0x0 },
-       { 0x00007011, 0x000000A2, 0x0 },
-       { 0x00009010, 0x0000009C, 0x0 },
-       { 0x00000018, 0x000000A9, 0x0 },
-       { 0x00006013, 0x000000A2, 0x0 },
-       { 0x00007011, 0x000000A6, 0x0 },
-       { 0x00000018, 0x000000AB, 0x0 },
-       { 0x00007013, 0x0000009F, 0x0 },
-       { 0x00000018, 0x000000DF, 0x0 },
-};
-
-/*
- * Skylake/Kabylake U
- * eDP 1.4 low vswing translation parameters
- */
-static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = {
-       { 0x00000018, 0x000000A8, 0x0 },
-       { 0x00004013, 0x000000A9, 0x0 },
-       { 0x00007011, 0x000000A2, 0x0 },
-       { 0x00009010, 0x0000009C, 0x0 },
-       { 0x00000018, 0x000000A9, 0x0 },
-       { 0x00006013, 0x000000A2, 0x0 },
-       { 0x00007011, 0x000000A6, 0x0 },
-       { 0x00002016, 0x000000AB, 0x0 },
-       { 0x00005013, 0x0000009F, 0x0 },
-       { 0x00000018, 0x000000DF, 0x0 },
-};
-
-/*
- * Skylake/Kabylake Y
- * eDP 1.4 low vswing translation parameters
- */
-static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = {
-       { 0x00000018, 0x000000A8, 0x0 },
-       { 0x00004013, 0x000000AB, 0x0 },
-       { 0x00007011, 0x000000A4, 0x0 },
-       { 0x00009010, 0x000000DF, 0x0 },
-       { 0x00000018, 0x000000AA, 0x0 },
-       { 0x00006013, 0x000000A4, 0x0 },
-       { 0x00007011, 0x0000009D, 0x0 },
-       { 0x00000018, 0x000000A0, 0x0 },
-       { 0x00006012, 0x000000DF, 0x0 },
-       { 0x00000018, 0x0000008A, 0x0 },
-};
-
-/* Skylake/Kabylake U, H and S */
-static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
-       { 0x00000018, 0x000000AC, 0x0 },
-       { 0x00005012, 0x0000009D, 0x0 },
-       { 0x00007011, 0x00000088, 0x0 },
-       { 0x00000018, 0x000000A1, 0x0 },
-       { 0x00000018, 0x00000098, 0x0 },
-       { 0x00004013, 0x00000088, 0x0 },
-       { 0x80006012, 0x000000CD, 0x1 },
-       { 0x00000018, 0x000000DF, 0x0 },
-       { 0x80003015, 0x000000CD, 0x1 },        /* Default */
-       { 0x80003015, 0x000000C0, 0x1 },
-       { 0x80000018, 0x000000C0, 0x1 },
-};
-
-/* Skylake/Kabylake Y */
-static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = {
-       { 0x00000018, 0x000000A1, 0x0 },
-       { 0x00005012, 0x000000DF, 0x0 },
-       { 0x80007011, 0x000000CB, 0x3 },
-       { 0x00000018, 0x000000A4, 0x0 },
-       { 0x00000018, 0x0000009D, 0x0 },
-       { 0x00004013, 0x00000080, 0x0 },
-       { 0x80006013, 0x000000C0, 0x3 },
-       { 0x00000018, 0x0000008A, 0x0 },
-       { 0x80003015, 0x000000C0, 0x3 },        /* Default */
-       { 0x80003015, 0x000000C0, 0x3 },
-       { 0x80000018, 0x000000C0, 0x3 },
-};
-
-struct bxt_ddi_buf_trans {
-       u8 margin;      /* swing value */
-       u8 scale;       /* scale value */
-       u8 enable;      /* scale enable */
-       u8 deemphasis;
-};
-
-static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
-                                       /* Idx  NT mV diff      db  */
-       { 52,  0x9A, 0, 128, }, /* 0:   400             0   */
-       { 78,  0x9A, 0, 85,  }, /* 1:   400             3.5 */
-       { 104, 0x9A, 0, 64,  }, /* 2:   400             6   */
-       { 154, 0x9A, 0, 43,  }, /* 3:   400             9.5 */
-       { 77,  0x9A, 0, 128, }, /* 4:   600             0   */
-       { 116, 0x9A, 0, 85,  }, /* 5:   600             3.5 */
-       { 154, 0x9A, 0, 64,  }, /* 6:   600             6   */
-       { 102, 0x9A, 0, 128, }, /* 7:   800             0   */
-       { 154, 0x9A, 0, 85,  }, /* 8:   800             3.5 */
-       { 154, 0x9A, 1, 128, }, /* 9:   1200            0   */
-};
-
-static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = {
-                                       /* Idx  NT mV diff      db  */
-       { 26, 0, 0, 128, },     /* 0:   200             0   */
-       { 38, 0, 0, 112, },     /* 1:   200             1.5 */
-       { 48, 0, 0, 96,  },     /* 2:   200             4   */
-       { 54, 0, 0, 69,  },     /* 3:   200             6   */
-       { 32, 0, 0, 128, },     /* 4:   250             0   */
-       { 48, 0, 0, 104, },     /* 5:   250             1.5 */
-       { 54, 0, 0, 85,  },     /* 6:   250             4   */
-       { 43, 0, 0, 128, },     /* 7:   300             0   */
-       { 54, 0, 0, 101, },     /* 8:   300             1.5 */
-       { 48, 0, 0, 128, },     /* 9:   300             0   */
-};
-
-/* BSpec has 2 recommended values - entries 0 and 8.
- * Using the entry with higher vswing.
- */
-static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
-                                       /* Idx  NT mV diff      db  */
-       { 52,  0x9A, 0, 128, }, /* 0:   400             0   */
-       { 52,  0x9A, 0, 85,  }, /* 1:   400             3.5 */
-       { 52,  0x9A, 0, 64,  }, /* 2:   400             6   */
-       { 42,  0x9A, 0, 43,  }, /* 3:   400             9.5 */
-       { 77,  0x9A, 0, 128, }, /* 4:   600             0   */
-       { 77,  0x9A, 0, 85,  }, /* 5:   600             3.5 */
-       { 77,  0x9A, 0, 64,  }, /* 6:   600             6   */
-       { 102, 0x9A, 0, 128, }, /* 7:   800             0   */
-       { 102, 0x9A, 0, 85,  }, /* 8:   800             3.5 */
-       { 154, 0x9A, 1, 128, }, /* 9:   1200            0   */
-};
-
-struct cnl_ddi_buf_trans {
-       u8 dw2_swing_sel;
-       u8 dw7_n_scalar;
-       u8 dw4_cursor_coeff;
-       u8 dw4_post_cursor_2;
-       u8 dw4_post_cursor_1;
-};
-
-/* Voltage Swing Programming for VccIO 0.85V for DP */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_85V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x5D, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
-       { 0xA, 0x6A, 0x38, 0x00, 0x07 },        /* 350   500      3.1   */
-       { 0xB, 0x7A, 0x32, 0x00, 0x0D },        /* 350   700      6.0   */
-       { 0x6, 0x7C, 0x2D, 0x00, 0x12 },        /* 350   900      8.2   */
-       { 0xA, 0x69, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
-       { 0xB, 0x7A, 0x36, 0x00, 0x09 },        /* 500   700      2.9   */
-       { 0x6, 0x7C, 0x30, 0x00, 0x0F },        /* 500   900      5.1   */
-       { 0xB, 0x7D, 0x3C, 0x00, 0x03 },        /* 650   725      0.9   */
-       { 0x6, 0x7C, 0x34, 0x00, 0x0B },        /* 600   900      3.5   */
-       { 0x6, 0x7B, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 0.85V for HDMI */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_85V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x60, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
-       { 0xB, 0x73, 0x36, 0x00, 0x09 },        /* 450   650      3.2   */
-       { 0x6, 0x7F, 0x31, 0x00, 0x0E },        /* 450   850      5.5   */
-       { 0xB, 0x73, 0x3F, 0x00, 0x00 },        /* 650   650      0.0   */
-       { 0x6, 0x7F, 0x37, 0x00, 0x08 },        /* 650   850      2.3   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 850   850      0.0   */
-       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
-};
-
-/* Voltage Swing Programming for VccIO 0.85V for eDP */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_85V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x66, 0x3A, 0x00, 0x05 },        /* 384   500      2.3   */
-       { 0x0, 0x7F, 0x38, 0x00, 0x07 },        /* 153   200      2.3   */
-       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 192   250      2.3   */
-       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 230   300      2.3   */
-       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 269   350      2.3   */
-       { 0xA, 0x66, 0x3C, 0x00, 0x03 },        /* 446   500      1.0   */
-       { 0xB, 0x70, 0x3C, 0x00, 0x03 },        /* 460   600      2.3   */
-       { 0xC, 0x75, 0x3C, 0x00, 0x03 },        /* 537   700      2.3   */
-       { 0x2, 0x7F, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 0.95V for DP */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_95V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x5D, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
-       { 0xA, 0x6A, 0x38, 0x00, 0x07 },        /* 350   500      3.1   */
-       { 0xB, 0x7A, 0x32, 0x00, 0x0D },        /* 350   700      6.0   */
-       { 0x6, 0x7C, 0x2D, 0x00, 0x12 },        /* 350   900      8.2   */
-       { 0xA, 0x69, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
-       { 0xB, 0x7A, 0x36, 0x00, 0x09 },        /* 500   700      2.9   */
-       { 0x6, 0x7C, 0x30, 0x00, 0x0F },        /* 500   900      5.1   */
-       { 0xB, 0x7D, 0x3C, 0x00, 0x03 },        /* 650   725      0.9   */
-       { 0x6, 0x7C, 0x34, 0x00, 0x0B },        /* 600   900      3.5   */
-       { 0x6, 0x7B, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 0.95V for HDMI */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_95V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x5C, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
-       { 0xB, 0x69, 0x37, 0x00, 0x08 },        /* 400   600      3.5   */
-       { 0x5, 0x76, 0x31, 0x00, 0x0E },        /* 400   800      6.0   */
-       { 0xA, 0x5E, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
-       { 0xB, 0x69, 0x3F, 0x00, 0x00 },        /* 600   600      0.0   */
-       { 0xB, 0x79, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
-       { 0x6, 0x7D, 0x32, 0x00, 0x0D },        /* 600   1000     4.4   */
-       { 0x5, 0x76, 0x3F, 0x00, 0x00 },        /* 800   800      0.0   */
-       { 0x6, 0x7D, 0x39, 0x00, 0x06 },        /* 800   1000     1.9   */
-       { 0x6, 0x7F, 0x39, 0x00, 0x06 },        /* 850   1050     1.8   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 1050  1050     0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 0.95V for eDP */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_95V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x61, 0x3A, 0x00, 0x05 },        /* 384   500      2.3   */
-       { 0x0, 0x7F, 0x38, 0x00, 0x07 },        /* 153   200      2.3   */
-       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 192   250      2.3   */
-       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 230   300      2.3   */
-       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 269   350      2.3   */
-       { 0xA, 0x61, 0x3C, 0x00, 0x03 },        /* 446   500      1.0   */
-       { 0xB, 0x68, 0x39, 0x00, 0x06 },        /* 460   600      2.3   */
-       { 0xC, 0x6E, 0x39, 0x00, 0x06 },        /* 537   700      2.3   */
-       { 0x4, 0x7F, 0x3A, 0x00, 0x05 },        /* 460   600      2.3   */
-       { 0x2, 0x7F, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 1.05V for DP */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_1_05V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x58, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
-       { 0xB, 0x64, 0x37, 0x00, 0x08 },        /* 400   600      3.5   */
-       { 0x5, 0x70, 0x31, 0x00, 0x0E },        /* 400   800      6.0   */
-       { 0x6, 0x7F, 0x2C, 0x00, 0x13 },        /* 400   1050     8.4   */
-       { 0xB, 0x64, 0x3F, 0x00, 0x00 },        /* 600   600      0.0   */
-       { 0x5, 0x73, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
-       { 0x6, 0x7F, 0x30, 0x00, 0x0F },        /* 550   1050     5.6   */
-       { 0x5, 0x76, 0x3E, 0x00, 0x01 },        /* 850   900      0.5   */
-       { 0x6, 0x7F, 0x36, 0x00, 0x09 },        /* 750   1050     2.9   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 1050  1050     0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 1.05V for HDMI */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_1_05V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x58, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
-       { 0xB, 0x64, 0x37, 0x00, 0x08 },        /* 400   600      3.5   */
-       { 0x5, 0x70, 0x31, 0x00, 0x0E },        /* 400   800      6.0   */
-       { 0xA, 0x5B, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
-       { 0xB, 0x64, 0x3F, 0x00, 0x00 },        /* 600   600      0.0   */
-       { 0x5, 0x73, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
-       { 0x6, 0x7C, 0x32, 0x00, 0x0D },        /* 600   1000     4.4   */
-       { 0x5, 0x70, 0x3F, 0x00, 0x00 },        /* 800   800      0.0   */
-       { 0x6, 0x7C, 0x39, 0x00, 0x06 },        /* 800   1000     1.9   */
-       { 0x6, 0x7F, 0x39, 0x00, 0x06 },        /* 850   1050     1.8   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 1050  1050     0.0   */
-};
-
-/* Voltage Swing Programming for VccIO 1.05V for eDP */
-static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x5E, 0x3A, 0x00, 0x05 },        /* 384   500      2.3   */
-       { 0x0, 0x7F, 0x38, 0x00, 0x07 },        /* 153   200      2.3   */
-       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 192   250      2.3   */
-       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 230   300      2.3   */
-       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 269   350      2.3   */
-       { 0xA, 0x5E, 0x3C, 0x00, 0x03 },        /* 446   500      1.0   */
-       { 0xB, 0x64, 0x39, 0x00, 0x06 },        /* 460   600      2.3   */
-       { 0xE, 0x6A, 0x39, 0x00, 0x06 },        /* 537   700      2.3   */
-       { 0x2, 0x7F, 0x3F, 0x00, 0x00 },        /* 400   400      0.0   */
-};
-
-/* icl_combo_phy_ddi_translations */
-static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x35, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
-       { 0xA, 0x4F, 0x37, 0x00, 0x08 },        /* 350   500      3.1   */
-       { 0xC, 0x71, 0x2F, 0x00, 0x10 },        /* 350   700      6.0   */
-       { 0x6, 0x7F, 0x2B, 0x00, 0x14 },        /* 350   900      8.2   */
-       { 0xA, 0x4C, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
-       { 0xC, 0x73, 0x34, 0x00, 0x0B },        /* 500   700      2.9   */
-       { 0x6, 0x7F, 0x2F, 0x00, 0x10 },        /* 500   900      5.1   */
-       { 0xC, 0x6C, 0x3C, 0x00, 0x03 },        /* 650   700      0.6   */
-       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   900      3.5   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
-};
-
-static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = {
-                                               /* NT mV Trans mV db    */
-       { 0x0, 0x7F, 0x3F, 0x00, 0x00 },        /* 200   200      0.0   */
-       { 0x8, 0x7F, 0x38, 0x00, 0x07 },        /* 200   250      1.9   */
-       { 0x1, 0x7F, 0x33, 0x00, 0x0C },        /* 200   300      3.5   */
-       { 0x9, 0x7F, 0x31, 0x00, 0x0E },        /* 200   350      4.9   */
-       { 0x8, 0x7F, 0x3F, 0x00, 0x00 },        /* 250   250      0.0   */
-       { 0x1, 0x7F, 0x38, 0x00, 0x07 },        /* 250   300      1.6   */
-       { 0x9, 0x7F, 0x35, 0x00, 0x0A },        /* 250   350      2.9   */
-       { 0x1, 0x7F, 0x3F, 0x00, 0x00 },        /* 300   300      0.0   */
-       { 0x9, 0x7F, 0x38, 0x00, 0x07 },        /* 300   350      1.3   */
-       { 0x9, 0x7F, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
-};
-
-static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x35, 0x3F, 0x00, 0x00 },        /* 350   350      0.0   */
-       { 0xA, 0x4F, 0x37, 0x00, 0x08 },        /* 350   500      3.1   */
-       { 0xC, 0x71, 0x2F, 0x00, 0x10 },        /* 350   700      6.0   */
-       { 0x6, 0x7F, 0x2B, 0x00, 0x14 },        /* 350   900      8.2   */
-       { 0xA, 0x4C, 0x3F, 0x00, 0x00 },        /* 500   500      0.0   */
-       { 0xC, 0x73, 0x34, 0x00, 0x0B },        /* 500   700      2.9   */
-       { 0x6, 0x7F, 0x2F, 0x00, 0x10 },        /* 500   900      5.1   */
-       { 0xC, 0x6C, 0x3C, 0x00, 0x03 },        /* 650   700      0.6   */
-       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   900      3.5   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 900   900      0.0   */
-};
-
-static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = {
-                                               /* NT mV Trans mV db    */
-       { 0xA, 0x60, 0x3F, 0x00, 0x00 },        /* 450   450      0.0   */
-       { 0xB, 0x73, 0x36, 0x00, 0x09 },        /* 450   650      3.2   */
-       { 0x6, 0x7F, 0x31, 0x00, 0x0E },        /* 450   850      5.5   */
-       { 0xB, 0x73, 0x3F, 0x00, 0x00 },        /* 650   650      0.0   ALS */
-       { 0x6, 0x7F, 0x37, 0x00, 0x08 },        /* 650   850      2.3   */
-       { 0x6, 0x7F, 0x3F, 0x00, 0x00 },        /* 850   850      0.0   */
-       { 0x6, 0x7F, 0x35, 0x00, 0x0A },        /* 600   850      3.0   */
-};
-
-struct icl_mg_phy_ddi_buf_trans {
-       u32 cri_txdeemph_override_5_0;
-       u32 cri_txdeemph_override_11_6;
-       u32 cri_txdeemph_override_17_12;
-};
-
-static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations[] = {
-                               /* Voltage swing  pre-emphasis */
-       { 0x0, 0x1B, 0x00 },    /* 0              0   */
-       { 0x0, 0x23, 0x08 },    /* 0              1   */
-       { 0x0, 0x2D, 0x12 },    /* 0              2   */
-       { 0x0, 0x00, 0x00 },    /* 0              3   */
-       { 0x0, 0x23, 0x00 },    /* 1              0   */
-       { 0x0, 0x2B, 0x09 },    /* 1              1   */
-       { 0x0, 0x2E, 0x11 },    /* 1              2   */
-       { 0x0, 0x2F, 0x00 },    /* 2              0   */
-       { 0x0, 0x33, 0x0C },    /* 2              1   */
-       { 0x0, 0x00, 0x00 },    /* 3              0   */
-};
-
-static const struct ddi_buf_trans *
-bdw_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       if (dev_priv->vbt.edp.low_vswing) {
-               *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
-               return bdw_ddi_translations_edp;
-       } else {
-               *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
-               return bdw_ddi_translations_dp;
-       }
-}
-
-static const struct ddi_buf_trans *
-skl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       if (IS_SKL_ULX(dev_priv)) {
-               *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
-               return skl_y_ddi_translations_dp;
-       } else if (IS_SKL_ULT(dev_priv)) {
-               *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp);
-               return skl_u_ddi_translations_dp;
-       } else {
-               *n_entries = ARRAY_SIZE(skl_ddi_translations_dp);
-               return skl_ddi_translations_dp;
-       }
-}
-
-static const struct ddi_buf_trans *
-kbl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       if (IS_KBL_ULX(dev_priv) || IS_CFL_ULX(dev_priv)) {
-               *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp);
-               return kbl_y_ddi_translations_dp;
-       } else if (IS_KBL_ULT(dev_priv) || IS_CFL_ULT(dev_priv)) {
-               *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp);
-               return kbl_u_ddi_translations_dp;
-       } else {
-               *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp);
-               return kbl_ddi_translations_dp;
-       }
-}
-
-static const struct ddi_buf_trans *
-skl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       if (dev_priv->vbt.edp.low_vswing) {
-               if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv) ||
-                   IS_CFL_ULX(dev_priv)) {
-                       *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp);
-                       return skl_y_ddi_translations_edp;
-               } else if (IS_SKL_ULT(dev_priv) || IS_KBL_ULT(dev_priv) ||
-                          IS_CFL_ULT(dev_priv)) {
-                       *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp);
-                       return skl_u_ddi_translations_edp;
-               } else {
-                       *n_entries = ARRAY_SIZE(skl_ddi_translations_edp);
-                       return skl_ddi_translations_edp;
-               }
-       }
-
-       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv))
-               return kbl_get_buf_trans_dp(dev_priv, n_entries);
-       else
-               return skl_get_buf_trans_dp(dev_priv, n_entries);
-}
-
-static const struct ddi_buf_trans *
-skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv) ||
-           IS_CFL_ULX(dev_priv)) {
-               *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi);
-               return skl_y_ddi_translations_hdmi;
-       } else {
-               *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
-               return skl_ddi_translations_hdmi;
-       }
-}
-
-static int skl_buf_trans_num_entries(enum port port, int n_entries)
-{
-       /* Only DDIA and DDIE can select the 10th register with DP */
-       if (port == PORT_A || port == PORT_E)
-               return min(n_entries, 10);
-       else
-               return min(n_entries, 9);
-}
-
-static const struct ddi_buf_trans *
-intel_ddi_get_buf_trans_dp(struct drm_i915_private *dev_priv,
-                          enum port port, int *n_entries)
-{
-       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) {
-               const struct ddi_buf_trans *ddi_translations =
-                       kbl_get_buf_trans_dp(dev_priv, n_entries);
-               *n_entries = skl_buf_trans_num_entries(port, *n_entries);
-               return ddi_translations;
-       } else if (IS_SKYLAKE(dev_priv)) {
-               const struct ddi_buf_trans *ddi_translations =
-                       skl_get_buf_trans_dp(dev_priv, n_entries);
-               *n_entries = skl_buf_trans_num_entries(port, *n_entries);
-               return ddi_translations;
-       } else if (IS_BROADWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
-               return  bdw_ddi_translations_dp;
-       } else if (IS_HASWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp);
-               return hsw_ddi_translations_dp;
-       }
-
-       *n_entries = 0;
-       return NULL;
-}
-
-static const struct ddi_buf_trans *
-intel_ddi_get_buf_trans_edp(struct drm_i915_private *dev_priv,
-                           enum port port, int *n_entries)
-{
-       if (IS_GEN9_BC(dev_priv)) {
-               const struct ddi_buf_trans *ddi_translations =
-                       skl_get_buf_trans_edp(dev_priv, n_entries);
-               *n_entries = skl_buf_trans_num_entries(port, *n_entries);
-               return ddi_translations;
-       } else if (IS_BROADWELL(dev_priv)) {
-               return bdw_get_buf_trans_edp(dev_priv, n_entries);
-       } else if (IS_HASWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp);
-               return hsw_ddi_translations_dp;
-       }
-
-       *n_entries = 0;
-       return NULL;
-}
-
-static const struct ddi_buf_trans *
-intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv,
-                           int *n_entries)
-{
-       if (IS_BROADWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi);
-               return bdw_ddi_translations_fdi;
-       } else if (IS_HASWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi);
-               return hsw_ddi_translations_fdi;
-       }
-
-       *n_entries = 0;
-       return NULL;
-}
-
-static const struct ddi_buf_trans *
-intel_ddi_get_buf_trans_hdmi(struct drm_i915_private *dev_priv,
-                            int *n_entries)
-{
-       if (IS_GEN9_BC(dev_priv)) {
-               return skl_get_buf_trans_hdmi(dev_priv, n_entries);
-       } else if (IS_BROADWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
-               return bdw_ddi_translations_hdmi;
-       } else if (IS_HASWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
-               return hsw_ddi_translations_hdmi;
-       }
-
-       *n_entries = 0;
-       return NULL;
-}
-
-static const struct bxt_ddi_buf_trans *
-bxt_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       *n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
-       return bxt_ddi_translations_dp;
-}
-
-static const struct bxt_ddi_buf_trans *
-bxt_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       if (dev_priv->vbt.edp.low_vswing) {
-               *n_entries = ARRAY_SIZE(bxt_ddi_translations_edp);
-               return bxt_ddi_translations_edp;
-       }
-
-       return bxt_get_buf_trans_dp(dev_priv, n_entries);
-}
-
-static const struct bxt_ddi_buf_trans *
-bxt_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       *n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi);
-       return bxt_ddi_translations_hdmi;
-}
-
-static const struct cnl_ddi_buf_trans *
-cnl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
-
-       if (voltage == VOLTAGE_INFO_0_85V) {
-               *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V);
-               return cnl_ddi_translations_hdmi_0_85V;
-       } else if (voltage == VOLTAGE_INFO_0_95V) {
-               *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V);
-               return cnl_ddi_translations_hdmi_0_95V;
-       } else if (voltage == VOLTAGE_INFO_1_05V) {
-               *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V);
-               return cnl_ddi_translations_hdmi_1_05V;
-       } else {
-               *n_entries = 1; /* shut up gcc */
-               MISSING_CASE(voltage);
-       }
-       return NULL;
-}
-
-static const struct cnl_ddi_buf_trans *
-cnl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
-
-       if (voltage == VOLTAGE_INFO_0_85V) {
-               *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V);
-               return cnl_ddi_translations_dp_0_85V;
-       } else if (voltage == VOLTAGE_INFO_0_95V) {
-               *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V);
-               return cnl_ddi_translations_dp_0_95V;
-       } else if (voltage == VOLTAGE_INFO_1_05V) {
-               *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V);
-               return cnl_ddi_translations_dp_1_05V;
-       } else {
-               *n_entries = 1; /* shut up gcc */
-               MISSING_CASE(voltage);
-       }
-       return NULL;
-}
-
-static const struct cnl_ddi_buf_trans *
-cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
-{
-       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
-
-       if (dev_priv->vbt.edp.low_vswing) {
-               if (voltage == VOLTAGE_INFO_0_85V) {
-                       *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V);
-                       return cnl_ddi_translations_edp_0_85V;
-               } else if (voltage == VOLTAGE_INFO_0_95V) {
-                       *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V);
-                       return cnl_ddi_translations_edp_0_95V;
-               } else if (voltage == VOLTAGE_INFO_1_05V) {
-                       *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V);
-                       return cnl_ddi_translations_edp_1_05V;
-               } else {
-                       *n_entries = 1; /* shut up gcc */
-                       MISSING_CASE(voltage);
-               }
-               return NULL;
-       } else {
-               return cnl_get_buf_trans_dp(dev_priv, 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)
-{
-       if (type == INTEL_OUTPUT_HDMI) {
-               *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
-               return icl_combo_phy_ddi_translations_hdmi;
-       } else if (rate > 540000 && type == INTEL_OUTPUT_EDP) {
-               *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
-               return icl_combo_phy_ddi_translations_edp_hbr3;
-       } else if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) {
-               *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
-               return icl_combo_phy_ddi_translations_edp_hbr2;
-       }
-
-       *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
-       return icl_combo_phy_ddi_translations_dp_hbr2;
-}
-
-static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port port)
-{
-       int n_entries, level, default_entry;
-
-       level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
-
-       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,
-                                               0, &n_entries);
-               else
-                       n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
-               default_entry = n_entries - 1;
-       } else if (IS_CANNONLAKE(dev_priv)) {
-               cnl_get_buf_trans_hdmi(dev_priv, &n_entries);
-               default_entry = n_entries - 1;
-       } else if (IS_GEN9_LP(dev_priv)) {
-               bxt_get_buf_trans_hdmi(dev_priv, &n_entries);
-               default_entry = n_entries - 1;
-       } else if (IS_GEN9_BC(dev_priv)) {
-               intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
-               default_entry = 8;
-       } else if (IS_BROADWELL(dev_priv)) {
-               intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
-               default_entry = 7;
-       } else if (IS_HASWELL(dev_priv)) {
-               intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
-               default_entry = 6;
-       } else {
-               WARN(1, "ddi translation table missing\n");
-               return 0;
-       }
-
-       /* Choose a good default if VBT is badly populated */
-       if (level == HDMI_LEVEL_SHIFT_UNKNOWN || level >= n_entries)
-               level = default_entry;
-
-       if (WARN_ON_ONCE(n_entries == 0))
-               return 0;
-       if (WARN_ON_ONCE(level >= n_entries))
-               level = n_entries - 1;
-
-       return level;
-}
-
-/*
- * Starting with Haswell, DDI port buffers must be programmed with correct
- * values in advance. This function programs the correct values for
- * DP/eDP/FDI use cases.
- */
-static void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder,
-                                        const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 iboost_bit = 0;
-       int i, n_entries;
-       enum port port = encoder->port;
-       const struct ddi_buf_trans *ddi_translations;
-
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
-               ddi_translations = intel_ddi_get_buf_trans_fdi(dev_priv,
-                                                              &n_entries);
-       else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
-               ddi_translations = intel_ddi_get_buf_trans_edp(dev_priv, port,
-                                                              &n_entries);
-       else
-               ddi_translations = intel_ddi_get_buf_trans_dp(dev_priv, port,
-                                                             &n_entries);
-
-       /* If we're boosting the current, set bit 31 of trans1 */
-       if (IS_GEN9_BC(dev_priv) &&
-           dev_priv->vbt.ddi_port_info[port].dp_boost_level)
-               iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
-
-       for (i = 0; i < n_entries; i++) {
-               I915_WRITE(DDI_BUF_TRANS_LO(port, i),
-                          ddi_translations[i].trans1 | iboost_bit);
-               I915_WRITE(DDI_BUF_TRANS_HI(port, i),
-                          ddi_translations[i].trans2);
-       }
-}
-
-/*
- * Starting with Haswell, DDI port buffers must be programmed with correct
- * values in advance. This function programs the correct values for
- * HDMI/DVI use cases.
- */
-static void intel_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder,
-                                          int level)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 iboost_bit = 0;
-       int n_entries;
-       enum port port = encoder->port;
-       const struct ddi_buf_trans *ddi_translations;
-
-       ddi_translations = intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
-
-       if (WARN_ON_ONCE(!ddi_translations))
-               return;
-       if (WARN_ON_ONCE(level >= n_entries))
-               level = n_entries - 1;
-
-       /* If we're boosting the current, set bit 31 of trans1 */
-       if (IS_GEN9_BC(dev_priv) &&
-           dev_priv->vbt.ddi_port_info[port].hdmi_boost_level)
-               iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
-
-       /* Entry 9 is for HDMI: */
-       I915_WRITE(DDI_BUF_TRANS_LO(port, 9),
-                  ddi_translations[level].trans1 | iboost_bit);
-       I915_WRITE(DDI_BUF_TRANS_HI(port, 9),
-                  ddi_translations[level].trans2);
-}
-
-static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
-                                   enum port port)
-{
-       i915_reg_t reg = DDI_BUF_CTL(port);
-       int i;
-
-       for (i = 0; i < 16; i++) {
-               udelay(1);
-               if (I915_READ(reg) & DDI_BUF_IS_IDLE)
-                       return;
-       }
-       DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
-}
-
-static u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll)
-{
-       switch (pll->info->id) {
-       case DPLL_ID_WRPLL1:
-               return PORT_CLK_SEL_WRPLL1;
-       case DPLL_ID_WRPLL2:
-               return PORT_CLK_SEL_WRPLL2;
-       case DPLL_ID_SPLL:
-               return PORT_CLK_SEL_SPLL;
-       case DPLL_ID_LCPLL_810:
-               return PORT_CLK_SEL_LCPLL_810;
-       case DPLL_ID_LCPLL_1350:
-               return PORT_CLK_SEL_LCPLL_1350;
-       case DPLL_ID_LCPLL_2700:
-               return PORT_CLK_SEL_LCPLL_2700;
-       default:
-               MISSING_CASE(pll->info->id);
-               return PORT_CLK_SEL_NONE;
-       }
-}
-
-static u32 icl_pll_to_ddi_clk_sel(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state)
-{
-       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
-       int clock = crtc_state->port_clock;
-       const enum intel_dpll_id id = pll->info->id;
-
-       switch (id) {
-       default:
-               /*
-                * DPLL_ID_ICL_DPLL0 and DPLL_ID_ICL_DPLL1 should not be used
-                * here, so do warn if this get passed in
-                */
-               MISSING_CASE(id);
-               return DDI_CLK_SEL_NONE;
-       case DPLL_ID_ICL_TBTPLL:
-               switch (clock) {
-               case 162000:
-                       return DDI_CLK_SEL_TBT_162;
-               case 270000:
-                       return DDI_CLK_SEL_TBT_270;
-               case 540000:
-                       return DDI_CLK_SEL_TBT_540;
-               case 810000:
-                       return DDI_CLK_SEL_TBT_810;
-               default:
-                       MISSING_CASE(clock);
-                       return DDI_CLK_SEL_NONE;
-               }
-       case DPLL_ID_ICL_MGPLL1:
-       case DPLL_ID_ICL_MGPLL2:
-       case DPLL_ID_ICL_MGPLL3:
-       case DPLL_ID_ICL_MGPLL4:
-               return DDI_CLK_SEL_MG;
-       }
-}
-
-/* Starting with Haswell, different DDI ports can work in FDI mode for
- * connection to the PCH-located connectors. For this, it is necessary to train
- * both the DDI port and PCH receiver for the desired DDI buffer settings.
- *
- * The recommended port to work in FDI mode is DDI E, which we use here. Also,
- * please note that when FDI mode is active on DDI E, it shares 2 lines with
- * DDI A (which is used for eDP)
- */
-
-void hsw_fdi_link_train(struct intel_crtc *crtc,
-                       const struct intel_crtc_state *crtc_state)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_encoder *encoder;
-       u32 temp, i, rx_ctl_val, ddi_pll_sel;
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
-               WARN_ON(encoder->type != INTEL_OUTPUT_ANALOG);
-               intel_prepare_dp_ddi_buffers(encoder, crtc_state);
-       }
-
-       /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the
-        * mode set "sequence for CRT port" document:
-        * - TP1 to TP2 time with the default value
-        * - FDI delay to 90h
-        *
-        * WaFDIAutoLinkSetTimingOverrride:hsw
-        */
-       I915_WRITE(FDI_RX_MISC(PIPE_A), FDI_RX_PWRDN_LANE1_VAL(2) |
-                                 FDI_RX_PWRDN_LANE0_VAL(2) |
-                                 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
-
-       /* Enable the PCH Receiver FDI PLL */
-       rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
-                    FDI_RX_PLL_ENABLE |
-                    FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
-       I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
-       POSTING_READ(FDI_RX_CTL(PIPE_A));
-       udelay(220);
-
-       /* Switch from Rawclk to PCDclk */
-       rx_ctl_val |= FDI_PCDCLK;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
-
-       /* Configure Port Clock Select */
-       ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll);
-       I915_WRITE(PORT_CLK_SEL(PORT_E), ddi_pll_sel);
-       WARN_ON(ddi_pll_sel != PORT_CLK_SEL_SPLL);
-
-       /* Start the training iterating through available voltages and emphasis,
-        * testing each value twice. */
-       for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) {
-               /* Configure DP_TP_CTL with auto-training */
-               I915_WRITE(DP_TP_CTL(PORT_E),
-                                       DP_TP_CTL_FDI_AUTOTRAIN |
-                                       DP_TP_CTL_ENHANCED_FRAME_ENABLE |
-                                       DP_TP_CTL_LINK_TRAIN_PAT1 |
-                                       DP_TP_CTL_ENABLE);
-
-               /* Configure and enable DDI_BUF_CTL for DDI E with next voltage.
-                * DDI E does not support port reversal, the functionality is
-                * achieved on the PCH side in FDI_RX_CTL, so no need to set the
-                * port reversal bit */
-               I915_WRITE(DDI_BUF_CTL(PORT_E),
-                          DDI_BUF_CTL_ENABLE |
-                          ((crtc_state->fdi_lanes - 1) << 1) |
-                          DDI_BUF_TRANS_SELECT(i / 2));
-               POSTING_READ(DDI_BUF_CTL(PORT_E));
-
-               udelay(600);
-
-               /* Program PCH FDI Receiver TU */
-               I915_WRITE(FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64));
-
-               /* Enable PCH FDI Receiver with auto-training */
-               rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO;
-               I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
-               POSTING_READ(FDI_RX_CTL(PIPE_A));
-
-               /* Wait for FDI receiver lane calibration */
-               udelay(30);
-
-               /* Unset FDI_RX_MISC pwrdn lanes */
-               temp = I915_READ(FDI_RX_MISC(PIPE_A));
-               temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
-               I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
-               POSTING_READ(FDI_RX_MISC(PIPE_A));
-
-               /* Wait for FDI auto training time */
-               udelay(5);
-
-               temp = I915_READ(DP_TP_STATUS(PORT_E));
-               if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
-                       DRM_DEBUG_KMS("FDI link training done on step %d\n", i);
-                       break;
-               }
-
-               /*
-                * Leave things enabled even if we failed to train FDI.
-                * Results in less fireworks from the state checker.
-                */
-               if (i == ARRAY_SIZE(hsw_ddi_translations_fdi) * 2 - 1) {
-                       DRM_ERROR("FDI link training failed!\n");
-                       break;
-               }
-
-               rx_ctl_val &= ~FDI_RX_ENABLE;
-               I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
-               POSTING_READ(FDI_RX_CTL(PIPE_A));
-
-               temp = I915_READ(DDI_BUF_CTL(PORT_E));
-               temp &= ~DDI_BUF_CTL_ENABLE;
-               I915_WRITE(DDI_BUF_CTL(PORT_E), temp);
-               POSTING_READ(DDI_BUF_CTL(PORT_E));
-
-               /* Disable DP_TP_CTL and FDI_RX_CTL and retry */
-               temp = I915_READ(DP_TP_CTL(PORT_E));
-               temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
-               temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
-               I915_WRITE(DP_TP_CTL(PORT_E), temp);
-               POSTING_READ(DP_TP_CTL(PORT_E));
-
-               intel_wait_ddi_buf_idle(dev_priv, PORT_E);
-
-               /* Reset FDI_RX_MISC pwrdn lanes */
-               temp = I915_READ(FDI_RX_MISC(PIPE_A));
-               temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
-               temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
-               I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
-               POSTING_READ(FDI_RX_MISC(PIPE_A));
-       }
-
-       /* Enable normal pixel sending for FDI */
-       I915_WRITE(DP_TP_CTL(PORT_E),
-                  DP_TP_CTL_FDI_AUTOTRAIN |
-                  DP_TP_CTL_LINK_TRAIN_NORMAL |
-                  DP_TP_CTL_ENHANCED_FRAME_ENABLE |
-                  DP_TP_CTL_ENABLE);
-}
-
-static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_digital_port *intel_dig_port =
-               enc_to_dig_port(&encoder->base);
-
-       intel_dp->DP = intel_dig_port->saved_port_bits |
-               DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
-       intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
-}
-
-static struct intel_encoder *
-intel_ddi_get_crtc_encoder(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct intel_encoder *encoder, *ret = NULL;
-       int num_encoders = 0;
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
-               ret = encoder;
-               num_encoders++;
-       }
-
-       if (num_encoders != 1)
-               WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders,
-                    pipe_name(crtc->pipe));
-
-       BUG_ON(ret == NULL);
-       return ret;
-}
-
-static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
-                                  i915_reg_t reg)
-{
-       int refclk;
-       int n, p, r;
-       u32 wrpll;
-
-       wrpll = I915_READ(reg);
-       switch (wrpll & WRPLL_REF_MASK) {
-       case WRPLL_REF_SPECIAL_HSW:
-               /*
-                * muxed-SSC for BDW.
-                * non-SSC for non-ULT HSW. Check FUSE_STRAP3
-                * for the non-SSC reference frequency.
-                */
-               if (IS_HASWELL(dev_priv) && !IS_HSW_ULT(dev_priv)) {
-                       if (I915_READ(FUSE_STRAP3) & HSW_REF_CLK_SELECT)
-                               refclk = 24;
-                       else
-                               refclk = 135;
-                       break;
-               }
-               /* fall through */
-       case WRPLL_REF_PCH_SSC:
-               /*
-                * We could calculate spread here, but our checking
-                * code only cares about 5% accuracy, and spread is a max of
-                * 0.5% downspread.
-                */
-               refclk = 135;
-               break;
-       case WRPLL_REF_LCPLL:
-               refclk = 2700;
-               break;
-       default:
-               MISSING_CASE(wrpll);
-               return 0;
-       }
-
-       r = wrpll & WRPLL_DIVIDER_REF_MASK;
-       p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
-       n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
-
-       /* Convert to KHz, p & r have a fixed point portion */
-       return (refclk * n * 100) / (p * r);
-}
-
-static int skl_calc_wrpll_link(const struct intel_dpll_hw_state *pll_state)
-{
-       u32 p0, p1, p2, dco_freq;
-
-       p0 = pll_state->cfgcr2 & DPLL_CFGCR2_PDIV_MASK;
-       p2 = pll_state->cfgcr2 & DPLL_CFGCR2_KDIV_MASK;
-
-       if (pll_state->cfgcr2 &  DPLL_CFGCR2_QDIV_MODE(1))
-               p1 = (pll_state->cfgcr2 & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8;
-       else
-               p1 = 1;
-
-
-       switch (p0) {
-       case DPLL_CFGCR2_PDIV_1:
-               p0 = 1;
-               break;
-       case DPLL_CFGCR2_PDIV_2:
-               p0 = 2;
-               break;
-       case DPLL_CFGCR2_PDIV_3:
-               p0 = 3;
-               break;
-       case DPLL_CFGCR2_PDIV_7:
-               p0 = 7;
-               break;
-       }
-
-       switch (p2) {
-       case DPLL_CFGCR2_KDIV_5:
-               p2 = 5;
-               break;
-       case DPLL_CFGCR2_KDIV_2:
-               p2 = 2;
-               break;
-       case DPLL_CFGCR2_KDIV_3:
-               p2 = 3;
-               break;
-       case DPLL_CFGCR2_KDIV_1:
-               p2 = 1;
-               break;
-       }
-
-       dco_freq = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK)
-               * 24 * 1000;
-
-       dco_freq += (((pll_state->cfgcr1 & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9)
-                    * 24 * 1000) / 0x8000;
-
-       if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
-               return 0;
-
-       return dco_freq / (p0 * p1 * p2 * 5);
-}
-
-int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
-                       struct intel_dpll_hw_state *pll_state)
-{
-       u32 p0, p1, p2, dco_freq, ref_clock;
-
-       p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
-       p2 = pll_state->cfgcr1 & DPLL_CFGCR1_KDIV_MASK;
-
-       if (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1))
-               p1 = (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >>
-                       DPLL_CFGCR1_QDIV_RATIO_SHIFT;
-       else
-               p1 = 1;
-
-
-       switch (p0) {
-       case DPLL_CFGCR1_PDIV_2:
-               p0 = 2;
-               break;
-       case DPLL_CFGCR1_PDIV_3:
-               p0 = 3;
-               break;
-       case DPLL_CFGCR1_PDIV_5:
-               p0 = 5;
-               break;
-       case DPLL_CFGCR1_PDIV_7:
-               p0 = 7;
-               break;
-       }
-
-       switch (p2) {
-       case DPLL_CFGCR1_KDIV_1:
-               p2 = 1;
-               break;
-       case DPLL_CFGCR1_KDIV_2:
-               p2 = 2;
-               break;
-       case DPLL_CFGCR1_KDIV_3:
-               p2 = 3;
-               break;
-       }
-
-       ref_clock = cnl_hdmi_pll_ref_clock(dev_priv);
-
-       dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK)
-               * ref_clock;
-
-       dco_freq += (((pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
-                     DPLL_CFGCR0_DCO_FRACTION_SHIFT) * ref_clock) / 0x8000;
-
-       if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
-               return 0;
-
-       return dco_freq / (p0 * p1 * p2 * 5);
-}
-
-static int icl_calc_tbt_pll_link(struct drm_i915_private *dev_priv,
-                                enum port port)
-{
-       u32 val = I915_READ(DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK;
-
-       switch (val) {
-       case DDI_CLK_SEL_NONE:
-               return 0;
-       case DDI_CLK_SEL_TBT_162:
-               return 162000;
-       case DDI_CLK_SEL_TBT_270:
-               return 270000;
-       case DDI_CLK_SEL_TBT_540:
-               return 540000;
-       case DDI_CLK_SEL_TBT_810:
-               return 810000;
-       default:
-               MISSING_CASE(val);
-               return 0;
-       }
-}
-
-static int icl_calc_mg_pll_link(struct drm_i915_private *dev_priv,
-                               const struct intel_dpll_hw_state *pll_state)
-{
-       u32 m1, m2_int, m2_frac, div1, div2, ref_clock;
-       u64 tmp;
-
-       ref_clock = dev_priv->cdclk.hw.ref;
-
-       m1 = pll_state->mg_pll_div1 & MG_PLL_DIV1_FBPREDIV_MASK;
-       m2_int = pll_state->mg_pll_div0 & MG_PLL_DIV0_FBDIV_INT_MASK;
-       m2_frac = (pll_state->mg_pll_div0 & MG_PLL_DIV0_FRACNEN_H) ?
-               (pll_state->mg_pll_div0 & MG_PLL_DIV0_FBDIV_FRAC_MASK) >>
-               MG_PLL_DIV0_FBDIV_FRAC_SHIFT : 0;
-
-       switch (pll_state->mg_clktop2_hsclkctl &
-               MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK) {
-       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2:
-               div1 = 2;
-               break;
-       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3:
-               div1 = 3;
-               break;
-       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5:
-               div1 = 5;
-               break;
-       case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7:
-               div1 = 7;
-               break;
-       default:
-               MISSING_CASE(pll_state->mg_clktop2_hsclkctl);
-               return 0;
-       }
-
-       div2 = (pll_state->mg_clktop2_hsclkctl &
-               MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK) >>
-               MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT;
-
-       /* div2 value of 0 is same as 1 means no div */
-       if (div2 == 0)
-               div2 = 1;
-
-       /*
-        * Adjust the original formula to delay the division by 2^22 in order to
-        * minimize possible rounding errors.
-        */
-       tmp = (u64)m1 * m2_int * ref_clock +
-             (((u64)m1 * m2_frac * ref_clock) >> 22);
-       tmp = div_u64(tmp, 5 * div1 * div2);
-
-       return tmp;
-}
-
-static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
-{
-       int dotclock;
-
-       if (pipe_config->has_pch_encoder)
-               dotclock = intel_dotclock_calculate(pipe_config->port_clock,
-                                                   &pipe_config->fdi_m_n);
-       else if (intel_crtc_has_dp_encoder(pipe_config))
-               dotclock = intel_dotclock_calculate(pipe_config->port_clock,
-                                                   &pipe_config->dp_m_n);
-       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36)
-               dotclock = pipe_config->port_clock * 2 / 3;
-       else
-               dotclock = pipe_config->port_clock;
-
-       if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
-           !intel_crtc_has_dp_encoder(pipe_config))
-               dotclock *= 2;
-
-       if (pipe_config->pixel_multiplier)
-               dotclock /= pipe_config->pixel_multiplier;
-
-       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
-}
-
-static void icl_ddi_clock_get(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dpll_hw_state *pll_state = &pipe_config->dpll_hw_state;
-       enum port port = encoder->port;
-       int link_clock;
-
-       if (intel_port_is_combophy(dev_priv, port)) {
-               link_clock = cnl_calc_wrpll_link(dev_priv, pll_state);
-       } else {
-               enum intel_dpll_id pll_id = intel_get_shared_dpll_id(dev_priv,
-                                               pipe_config->shared_dpll);
-
-               if (pll_id == DPLL_ID_ICL_TBTPLL)
-                       link_clock = icl_calc_tbt_pll_link(dev_priv, port);
-               else
-                       link_clock = icl_calc_mg_pll_link(dev_priv, pll_state);
-       }
-
-       pipe_config->port_clock = link_clock;
-
-       ddi_dotclock_get(pipe_config);
-}
-
-static void cnl_ddi_clock_get(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dpll_hw_state *pll_state = &pipe_config->dpll_hw_state;
-       int link_clock;
-
-       if (pll_state->cfgcr0 & DPLL_CFGCR0_HDMI_MODE) {
-               link_clock = cnl_calc_wrpll_link(dev_priv, pll_state);
-       } else {
-               link_clock = pll_state->cfgcr0 & DPLL_CFGCR0_LINK_RATE_MASK;
-
-               switch (link_clock) {
-               case DPLL_CFGCR0_LINK_RATE_810:
-                       link_clock = 81000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_1080:
-                       link_clock = 108000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_1350:
-                       link_clock = 135000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_1620:
-                       link_clock = 162000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_2160:
-                       link_clock = 216000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_2700:
-                       link_clock = 270000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_3240:
-                       link_clock = 324000;
-                       break;
-               case DPLL_CFGCR0_LINK_RATE_4050:
-                       link_clock = 405000;
-                       break;
-               default:
-                       WARN(1, "Unsupported link rate\n");
-                       break;
-               }
-               link_clock *= 2;
-       }
-
-       pipe_config->port_clock = link_clock;
-
-       ddi_dotclock_get(pipe_config);
-}
-
-static void skl_ddi_clock_get(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config)
-{
-       struct intel_dpll_hw_state *pll_state = &pipe_config->dpll_hw_state;
-       int link_clock;
-
-       /*
-        * ctrl1 register is already shifted for each pll, just use 0 to get
-        * the internal shift for each field
-        */
-       if (pll_state->ctrl1 & DPLL_CTRL1_HDMI_MODE(0)) {
-               link_clock = skl_calc_wrpll_link(pll_state);
-       } else {
-               link_clock = pll_state->ctrl1 & DPLL_CTRL1_LINK_RATE_MASK(0);
-               link_clock >>= DPLL_CTRL1_LINK_RATE_SHIFT(0);
-
-               switch (link_clock) {
-               case DPLL_CTRL1_LINK_RATE_810:
-                       link_clock = 81000;
-                       break;
-               case DPLL_CTRL1_LINK_RATE_1080:
-                       link_clock = 108000;
-                       break;
-               case DPLL_CTRL1_LINK_RATE_1350:
-                       link_clock = 135000;
-                       break;
-               case DPLL_CTRL1_LINK_RATE_1620:
-                       link_clock = 162000;
-                       break;
-               case DPLL_CTRL1_LINK_RATE_2160:
-                       link_clock = 216000;
-                       break;
-               case DPLL_CTRL1_LINK_RATE_2700:
-                       link_clock = 270000;
-                       break;
-               default:
-                       WARN(1, "Unsupported link rate\n");
-                       break;
-               }
-               link_clock *= 2;
-       }
-
-       pipe_config->port_clock = link_clock;
-
-       ddi_dotclock_get(pipe_config);
-}
-
-static void hsw_ddi_clock_get(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       int link_clock = 0;
-       u32 val, pll;
-
-       val = hsw_pll_to_ddi_pll_sel(pipe_config->shared_dpll);
-       switch (val & PORT_CLK_SEL_MASK) {
-       case PORT_CLK_SEL_LCPLL_810:
-               link_clock = 81000;
-               break;
-       case PORT_CLK_SEL_LCPLL_1350:
-               link_clock = 135000;
-               break;
-       case PORT_CLK_SEL_LCPLL_2700:
-               link_clock = 270000;
-               break;
-       case PORT_CLK_SEL_WRPLL1:
-               link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(0));
-               break;
-       case PORT_CLK_SEL_WRPLL2:
-               link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(1));
-               break;
-       case PORT_CLK_SEL_SPLL:
-               pll = I915_READ(SPLL_CTL) & SPLL_FREQ_MASK;
-               if (pll == SPLL_FREQ_810MHz)
-                       link_clock = 81000;
-               else if (pll == SPLL_FREQ_1350MHz)
-                       link_clock = 135000;
-               else if (pll == SPLL_FREQ_2700MHz)
-                       link_clock = 270000;
-               else {
-                       WARN(1, "bad spll freq\n");
-                       return;
-               }
-               break;
-       default:
-               WARN(1, "bad port clock sel\n");
-               return;
-       }
-
-       pipe_config->port_clock = link_clock * 2;
-
-       ddi_dotclock_get(pipe_config);
-}
-
-static int bxt_calc_pll_link(const struct intel_dpll_hw_state *pll_state)
-{
-       struct dpll clock;
-
-       clock.m1 = 2;
-       clock.m2 = (pll_state->pll0 & PORT_PLL_M2_MASK) << 22;
-       if (pll_state->pll3 & PORT_PLL_M2_FRAC_ENABLE)
-               clock.m2 |= pll_state->pll2 & PORT_PLL_M2_FRAC_MASK;
-       clock.n = (pll_state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT;
-       clock.p1 = (pll_state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT;
-       clock.p2 = (pll_state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT;
-
-       return chv_calc_dpll_params(100000, &clock);
-}
-
-static void bxt_ddi_clock_get(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config)
-{
-       pipe_config->port_clock =
-               bxt_calc_pll_link(&pipe_config->dpll_hw_state);
-
-       ddi_dotclock_get(pipe_config);
-}
-
-static void intel_ddi_clock_get(struct intel_encoder *encoder,
-                               struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_ddi_clock_get(encoder, pipe_config);
-       else if (IS_CANNONLAKE(dev_priv))
-               cnl_ddi_clock_get(encoder, pipe_config);
-       else if (IS_GEN9_LP(dev_priv))
-               bxt_ddi_clock_get(encoder, pipe_config);
-       else if (IS_GEN9_BC(dev_priv))
-               skl_ddi_clock_get(encoder, pipe_config);
-       else if (INTEL_GEN(dev_priv) <= 8)
-               hsw_ddi_clock_get(encoder, pipe_config);
-}
-
-void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       u32 temp;
-
-       if (!intel_crtc_has_dp_encoder(crtc_state))
-               return;
-
-       WARN_ON(transcoder_is_dsi(cpu_transcoder));
-
-       temp = TRANS_MSA_SYNC_CLK;
-
-       if (crtc_state->limited_color_range)
-               temp |= TRANS_MSA_CEA_RANGE;
-
-       switch (crtc_state->pipe_bpp) {
-       case 18:
-               temp |= TRANS_MSA_6_BPC;
-               break;
-       case 24:
-               temp |= TRANS_MSA_8_BPC;
-               break;
-       case 30:
-               temp |= TRANS_MSA_10_BPC;
-               break;
-       case 36:
-               temp |= TRANS_MSA_12_BPC;
-               break;
-       default:
-               MISSING_CASE(crtc_state->pipe_bpp);
-               break;
-       }
-
-       /*
-        * As per DP 1.2 spec section 2.3.4.3 while sending
-        * YCBCR 444 signals we should program MSA MISC1/0 fields with
-        * colorspace information. The output colorspace encoding is BT601.
-        */
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
-               temp |= TRANS_MSA_SAMPLING_444 | TRANS_MSA_CLRSP_YCBCR;
-       /*
-        * As per DP 1.4a spec section 2.2.4.3 [MSA Field for Indication
-        * of Color Encoding Format and Content Color Gamut] while sending
-        * YCBCR 420 signals we should program MSA MISC1 fields which
-        * indicate VSC SDP for the Pixel Encoding/Colorimetry Format.
-        */
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
-               temp |= TRANS_MSA_USE_VSC_SDP;
-       I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp);
-}
-
-void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
-                                   bool state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       u32 temp;
-
-       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
-       if (state == true)
-               temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
-       else
-               temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
-       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
-}
-
-void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum pipe pipe = crtc->pipe;
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       enum port port = encoder->port;
-       u32 temp;
-
-       /* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */
-       temp = TRANS_DDI_FUNC_ENABLE;
-       temp |= TRANS_DDI_SELECT_PORT(port);
-
-       switch (crtc_state->pipe_bpp) {
-       case 18:
-               temp |= TRANS_DDI_BPC_6;
-               break;
-       case 24:
-               temp |= TRANS_DDI_BPC_8;
-               break;
-       case 30:
-               temp |= TRANS_DDI_BPC_10;
-               break;
-       case 36:
-               temp |= TRANS_DDI_BPC_12;
-               break;
-       default:
-               BUG();
-       }
-
-       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
-               temp |= TRANS_DDI_PVSYNC;
-       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
-               temp |= TRANS_DDI_PHSYNC;
-
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               switch (pipe) {
-               case PIPE_A:
-                       /* On Haswell, can only use the always-on power well for
-                        * eDP when not using the panel fitter, and when not
-                        * using motion blur mitigation (which we don't
-                        * support). */
-                       if (crtc_state->pch_pfit.force_thru)
-                               temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
-                       else
-                               temp |= TRANS_DDI_EDP_INPUT_A_ON;
-                       break;
-               case PIPE_B:
-                       temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
-                       break;
-               case PIPE_C:
-                       temp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
-                       break;
-               default:
-                       BUG();
-                       break;
-               }
-       }
-
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
-               if (crtc_state->has_hdmi_sink)
-                       temp |= TRANS_DDI_MODE_SELECT_HDMI;
-               else
-                       temp |= TRANS_DDI_MODE_SELECT_DVI;
-
-               if (crtc_state->hdmi_scrambling)
-                       temp |= TRANS_DDI_HDMI_SCRAMBLING;
-               if (crtc_state->hdmi_high_tmds_clock_ratio)
-                       temp |= TRANS_DDI_HIGH_TMDS_CHAR_RATE;
-       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
-               temp |= TRANS_DDI_MODE_SELECT_FDI;
-               temp |= (crtc_state->fdi_lanes - 1) << 1;
-       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
-               temp |= TRANS_DDI_MODE_SELECT_DP_MST;
-               temp |= DDI_PORT_WIDTH(crtc_state->lane_count);
-       } else {
-               temp |= TRANS_DDI_MODE_SELECT_DP_SST;
-               temp |= DDI_PORT_WIDTH(crtc_state->lane_count);
-       }
-
-       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
-}
-
-void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
-       u32 val = I915_READ(reg);
-
-       val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
-       val |= TRANS_DDI_PORT_NONE;
-       I915_WRITE(reg, val);
-
-       if (dev_priv->quirks & QUIRK_INCREASE_DDI_DISABLED_TIME &&
-           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
-               DRM_DEBUG_KMS("Quirk Increase DDI disabled time\n");
-               /* Quirk time at 100ms for reliable operation */
-               msleep(100);
-       }
-}
-
-int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
-                                    bool enable)
-{
-       struct drm_device *dev = intel_encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       intel_wakeref_t wakeref;
-       enum pipe pipe = 0;
-       int ret = 0;
-       u32 tmp;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    intel_encoder->power_domain);
-       if (WARN_ON(!wakeref))
-               return -ENXIO;
-
-       if (WARN_ON(!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
-               ret = -EIO;
-               goto out;
-       }
-
-       tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe));
-       if (enable)
-               tmp |= TRANS_DDI_HDCP_SIGNALLING;
-       else
-               tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
-       I915_WRITE(TRANS_DDI_FUNC_CTL(pipe), tmp);
-out:
-       intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
-       return ret;
-}
-
-bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
-{
-       struct drm_device *dev = intel_connector->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_encoder *encoder = intel_connector->encoder;
-       int type = intel_connector->base.connector_type;
-       enum port port = encoder->port;
-       enum transcoder cpu_transcoder;
-       intel_wakeref_t wakeref;
-       enum pipe pipe = 0;
-       u32 tmp;
-       bool ret;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       if (!encoder->get_hw_state(encoder, &pipe)) {
-               ret = false;
-               goto out;
-       }
-
-       if (HAS_TRANSCODER_EDP(dev_priv) && port == PORT_A)
-               cpu_transcoder = TRANSCODER_EDP;
-       else
-               cpu_transcoder = (enum transcoder) pipe;
-
-       tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
-
-       switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
-       case TRANS_DDI_MODE_SELECT_HDMI:
-       case TRANS_DDI_MODE_SELECT_DVI:
-               ret = type == DRM_MODE_CONNECTOR_HDMIA;
-               break;
-
-       case TRANS_DDI_MODE_SELECT_DP_SST:
-               ret = type == DRM_MODE_CONNECTOR_eDP ||
-                     type == DRM_MODE_CONNECTOR_DisplayPort;
-               break;
-
-       case TRANS_DDI_MODE_SELECT_DP_MST:
-               /* if the transcoder is in MST state then
-                * connector isn't connected */
-               ret = false;
-               break;
-
-       case TRANS_DDI_MODE_SELECT_FDI:
-               ret = type == DRM_MODE_CONNECTOR_VGA;
-               break;
-
-       default:
-               ret = false;
-               break;
-       }
-
-out:
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-
-       return ret;
-}
-
-static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
-                                       u8 *pipe_mask, bool *is_dp_mst)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum port port = encoder->port;
-       intel_wakeref_t wakeref;
-       enum pipe p;
-       u32 tmp;
-       u8 mst_pipe_mask;
-
-       *pipe_mask = 0;
-       *is_dp_mst = false;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return;
-
-       tmp = I915_READ(DDI_BUF_CTL(port));
-       if (!(tmp & DDI_BUF_CTL_ENABLE))
-               goto out;
-
-       if (HAS_TRANSCODER_EDP(dev_priv) && port == PORT_A) {
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
-
-               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
-               default:
-                       MISSING_CASE(tmp & TRANS_DDI_EDP_INPUT_MASK);
-                       /* fallthrough */
-               case TRANS_DDI_EDP_INPUT_A_ON:
-               case TRANS_DDI_EDP_INPUT_A_ONOFF:
-                       *pipe_mask = BIT(PIPE_A);
-                       break;
-               case TRANS_DDI_EDP_INPUT_B_ONOFF:
-                       *pipe_mask = BIT(PIPE_B);
-                       break;
-               case TRANS_DDI_EDP_INPUT_C_ONOFF:
-                       *pipe_mask = BIT(PIPE_C);
-                       break;
-               }
-
-               goto out;
-       }
-
-       mst_pipe_mask = 0;
-       for_each_pipe(dev_priv, p) {
-               enum transcoder cpu_transcoder = (enum transcoder)p;
-
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
-
-               if ((tmp & TRANS_DDI_PORT_MASK) != TRANS_DDI_SELECT_PORT(port))
-                       continue;
-
-               if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
-                   TRANS_DDI_MODE_SELECT_DP_MST)
-                       mst_pipe_mask |= BIT(p);
-
-               *pipe_mask |= BIT(p);
-       }
-
-       if (!*pipe_mask)
-               DRM_DEBUG_KMS("No pipe for ddi port %c found\n",
-                             port_name(port));
-
-       if (!mst_pipe_mask && hweight8(*pipe_mask) > 1) {
-               DRM_DEBUG_KMS("Multiple pipes for non DP-MST port %c (pipe_mask %02x)\n",
-                             port_name(port), *pipe_mask);
-               *pipe_mask = BIT(ffs(*pipe_mask) - 1);
-       }
-
-       if (mst_pipe_mask && mst_pipe_mask != *pipe_mask)
-               DRM_DEBUG_KMS("Conflicting MST and non-MST encoders for port %c (pipe_mask %02x mst_pipe_mask %02x)\n",
-                             port_name(port), *pipe_mask, mst_pipe_mask);
-       else
-               *is_dp_mst = mst_pipe_mask;
-
-out:
-       if (*pipe_mask && IS_GEN9_LP(dev_priv)) {
-               tmp = I915_READ(BXT_PHY_CTL(port));
-               if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK |
-                           BXT_PHY_LANE_POWERDOWN_ACK |
-                           BXT_PHY_LANE_ENABLED)) != BXT_PHY_LANE_ENABLED)
-                       DRM_ERROR("Port %c enabled but PHY powered down? "
-                                 "(PHY_CTL %08x)\n", port_name(port), tmp);
-       }
-
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-}
-
-bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
-                           enum pipe *pipe)
-{
-       u8 pipe_mask;
-       bool is_mst;
-
-       intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);
-
-       if (is_mst || !pipe_mask)
-               return false;
-
-       *pipe = ffs(pipe_mask) - 1;
-
-       return true;
-}
-
-static inline enum intel_display_power_domain
-intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port)
-{
-       /* CNL+ HW requires corresponding AUX IOs to be powered up for PSR with
-        * DC states enabled at the same time, while for driver initiated AUX
-        * transfers we need the same AUX IOs to be powered but with DC states
-        * disabled. Accordingly use the AUX power domain here which leaves DC
-        * states enabled.
-        * However, for non-A AUX ports the corresponding non-EDP transcoders
-        * would have already enabled power well 2 and DC_OFF. This means we can
-        * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a
-        * specific AUX_IO reference without powering up any extra wells.
-        * Note that PSR is enabled only on Port A even though this function
-        * returns the correct domain for other ports too.
-        */
-       return dig_port->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
-                                             intel_aux_power_domain(dig_port);
-}
-
-static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
-                                       struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port;
-
-       /*
-        * TODO: Add support for MST encoders. Atm, the following should never
-        * happen since fake-MST encoders don't set their get_power_domains()
-        * hook.
-        */
-       if (WARN_ON(intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)))
-               return;
-
-       dig_port = enc_to_dig_port(&encoder->base);
-       intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
-
-       /*
-        * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
-        * ports.
-        */
-       if (intel_crtc_has_dp_encoder(crtc_state) ||
-           intel_port_is_tc(dev_priv, encoder->port))
-               intel_display_power_get(dev_priv,
-                                       intel_ddi_main_link_aux_domain(dig_port));
-
-       /*
-        * VDSC power is needed when DSC is enabled
-        */
-       if (crtc_state->dsc_params.compression_enable)
-               intel_display_power_get(dev_priv,
-                                       intel_dsc_power_domain(crtc_state));
-}
-
-void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
-       enum port port = encoder->port;
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-
-       if (cpu_transcoder != TRANSCODER_EDP)
-               I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
-                          TRANS_CLK_SEL_PORT(port));
-}
-
-void intel_ddi_disable_pipe_clock(const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-
-       if (cpu_transcoder != TRANSCODER_EDP)
-               I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
-                          TRANS_CLK_SEL_DISABLED);
-}
-
-static void _skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
-                               enum port port, u8 iboost)
-{
-       u32 tmp;
-
-       tmp = I915_READ(DISPIO_CR_TX_BMU_CR0);
-       tmp &= ~(BALANCE_LEG_MASK(port) | BALANCE_LEG_DISABLE(port));
-       if (iboost)
-               tmp |= iboost << BALANCE_LEG_SHIFT(port);
-       else
-               tmp |= BALANCE_LEG_DISABLE(port);
-       I915_WRITE(DISPIO_CR_TX_BMU_CR0, tmp);
-}
-
-static void skl_ddi_set_iboost(struct intel_encoder *encoder,
-                              int level, enum intel_output_type type)
-{
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       u8 iboost;
-
-       if (type == INTEL_OUTPUT_HDMI)
-               iboost = dev_priv->vbt.ddi_port_info[port].hdmi_boost_level;
-       else
-               iboost = dev_priv->vbt.ddi_port_info[port].dp_boost_level;
-
-       if (iboost == 0) {
-               const struct ddi_buf_trans *ddi_translations;
-               int n_entries;
-
-               if (type == INTEL_OUTPUT_HDMI)
-                       ddi_translations = intel_ddi_get_buf_trans_hdmi(dev_priv, &n_entries);
-               else if (type == INTEL_OUTPUT_EDP)
-                       ddi_translations = intel_ddi_get_buf_trans_edp(dev_priv, port, &n_entries);
-               else
-                       ddi_translations = intel_ddi_get_buf_trans_dp(dev_priv, port, &n_entries);
-
-               if (WARN_ON_ONCE(!ddi_translations))
-                       return;
-               if (WARN_ON_ONCE(level >= n_entries))
-                       level = n_entries - 1;
-
-               iboost = ddi_translations[level].i_boost;
-       }
-
-       /* Make sure that the requested I_boost is valid */
-       if (iboost && iboost != 0x1 && iboost != 0x3 && iboost != 0x7) {
-               DRM_ERROR("Invalid I_boost value %u\n", iboost);
-               return;
-       }
-
-       _skl_ddi_set_iboost(dev_priv, port, iboost);
-
-       if (port == PORT_A && intel_dig_port->max_lanes == 4)
-               _skl_ddi_set_iboost(dev_priv, PORT_E, iboost);
-}
-
-static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                   int level, enum intel_output_type type)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       const struct bxt_ddi_buf_trans *ddi_translations;
-       enum port port = encoder->port;
-       int n_entries;
-
-       if (type == INTEL_OUTPUT_HDMI)
-               ddi_translations = bxt_get_buf_trans_hdmi(dev_priv, &n_entries);
-       else if (type == INTEL_OUTPUT_EDP)
-               ddi_translations = bxt_get_buf_trans_edp(dev_priv, &n_entries);
-       else
-               ddi_translations = bxt_get_buf_trans_dp(dev_priv, &n_entries);
-
-       if (WARN_ON_ONCE(!ddi_translations))
-               return;
-       if (WARN_ON_ONCE(level >= n_entries))
-               level = n_entries - 1;
-
-       bxt_ddi_phy_set_signal_level(dev_priv, port,
-                                    ddi_translations[level].margin,
-                                    ddi_translations[level].scale,
-                                    ddi_translations[level].enable,
-                                    ddi_translations[level].deemphasis);
-}
-
-u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = encoder->port;
-       int n_entries;
-
-       if (INTEL_GEN(dev_priv) >= 11) {
-               if (intel_port_is_combophy(dev_priv, port))
-                       icl_get_combo_buf_trans(dev_priv, port, encoder->type,
-                                               intel_dp->link_rate, &n_entries);
-               else
-                       n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
-       } else if (IS_CANNONLAKE(dev_priv)) {
-               if (encoder->type == INTEL_OUTPUT_EDP)
-                       cnl_get_buf_trans_edp(dev_priv, &n_entries);
-               else
-                       cnl_get_buf_trans_dp(dev_priv, &n_entries);
-       } else if (IS_GEN9_LP(dev_priv)) {
-               if (encoder->type == INTEL_OUTPUT_EDP)
-                       bxt_get_buf_trans_edp(dev_priv, &n_entries);
-               else
-                       bxt_get_buf_trans_dp(dev_priv, &n_entries);
-       } else {
-               if (encoder->type == INTEL_OUTPUT_EDP)
-                       intel_ddi_get_buf_trans_edp(dev_priv, port, &n_entries);
-               else
-                       intel_ddi_get_buf_trans_dp(dev_priv, port, &n_entries);
-       }
-
-       if (WARN_ON(n_entries < 1))
-               n_entries = 1;
-       if (WARN_ON(n_entries > ARRAY_SIZE(index_to_dp_signal_levels)))
-               n_entries = ARRAY_SIZE(index_to_dp_signal_levels);
-
-       return index_to_dp_signal_levels[n_entries - 1] &
-               DP_TRAIN_VOLTAGE_SWING_MASK;
-}
-
-/*
- * We assume that the full set of pre-emphasis values can be
- * used on all DDI platforms. Should that change we need to
- * rethink this code.
- */
-u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder, u8 voltage_swing)
-{
-       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-               return DP_TRAIN_PRE_EMPH_LEVEL_3;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-               return DP_TRAIN_PRE_EMPH_LEVEL_2;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-               return DP_TRAIN_PRE_EMPH_LEVEL_1;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
-       default:
-               return DP_TRAIN_PRE_EMPH_LEVEL_0;
-       }
-}
-
-static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
-                                  int level, enum intel_output_type type)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       const struct cnl_ddi_buf_trans *ddi_translations;
-       enum port port = encoder->port;
-       int n_entries, ln;
-       u32 val;
-
-       if (type == INTEL_OUTPUT_HDMI)
-               ddi_translations = cnl_get_buf_trans_hdmi(dev_priv, &n_entries);
-       else if (type == INTEL_OUTPUT_EDP)
-               ddi_translations = cnl_get_buf_trans_edp(dev_priv, &n_entries);
-       else
-               ddi_translations = cnl_get_buf_trans_dp(dev_priv, &n_entries);
-
-       if (WARN_ON_ONCE(!ddi_translations))
-               return;
-       if (WARN_ON_ONCE(level >= n_entries))
-               level = n_entries - 1;
-
-       /* Set PORT_TX_DW5 Scaling Mode Sel to 010b. */
-       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
-       val &= ~SCALING_MODE_SEL_MASK;
-       val |= SCALING_MODE_SEL(2);
-       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
-
-       /* Program PORT_TX_DW2 */
-       val = I915_READ(CNL_PORT_TX_DW2_LN0(port));
-       val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
-                RCOMP_SCALAR_MASK);
-       val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_sel);
-       val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_sel);
-       /* Rcomp scalar is fixed as 0x98 for every table entry */
-       val |= RCOMP_SCALAR(0x98);
-       I915_WRITE(CNL_PORT_TX_DW2_GRP(port), val);
-
-       /* Program PORT_TX_DW4 */
-       /* We cannot write to GRP. It would overrite individual loadgen */
-       for (ln = 0; ln < 4; ln++) {
-               val = I915_READ(CNL_PORT_TX_DW4_LN(ln, port));
-               val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
-                        CURSOR_COEFF_MASK);
-               val |= POST_CURSOR_1(ddi_translations[level].dw4_post_cursor_1);
-               val |= POST_CURSOR_2(ddi_translations[level].dw4_post_cursor_2);
-               val |= CURSOR_COEFF(ddi_translations[level].dw4_cursor_coeff);
-               I915_WRITE(CNL_PORT_TX_DW4_LN(ln, port), val);
-       }
-
-       /* Program PORT_TX_DW5 */
-       /* All DW5 values are fixed for every table entry */
-       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
-       val &= ~RTERM_SELECT_MASK;
-       val |= RTERM_SELECT(6);
-       val |= TAP3_DISABLE;
-       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
-
-       /* Program PORT_TX_DW7 */
-       val = I915_READ(CNL_PORT_TX_DW7_LN0(port));
-       val &= ~N_SCALAR_MASK;
-       val |= N_SCALAR(ddi_translations[level].dw7_n_scalar);
-       I915_WRITE(CNL_PORT_TX_DW7_GRP(port), val);
-}
-
-static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                   int level, enum intel_output_type type)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       int width, rate, ln;
-       u32 val;
-
-       if (type == INTEL_OUTPUT_HDMI) {
-               width = 4;
-               rate = 0; /* Rate is always < than 6GHz for HDMI */
-       } else {
-               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-               width = intel_dp->lane_count;
-               rate = intel_dp->link_rate;
-       }
-
-       /*
-        * 1. If port type is eDP or DP,
-        * set PORT_PCS_DW1 cmnkeeper_enable to 1b,
-        * else clear to 0b.
-        */
-       val = I915_READ(CNL_PORT_PCS_DW1_LN0(port));
-       if (type != INTEL_OUTPUT_HDMI)
-               val |= COMMON_KEEPER_EN;
-       else
-               val &= ~COMMON_KEEPER_EN;
-       I915_WRITE(CNL_PORT_PCS_DW1_GRP(port), val);
-
-       /* 2. Program loadgen select */
-       /*
-        * Program PORT_TX_DW4_LN depending on Bit rate and used lanes
-        * <= 6 GHz and 4 lanes (LN0=0, LN1=1, LN2=1, LN3=1)
-        * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0)
-        * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0)
-        */
-       for (ln = 0; ln <= 3; ln++) {
-               val = I915_READ(CNL_PORT_TX_DW4_LN(ln, port));
-               val &= ~LOADGEN_SELECT;
-
-               if ((rate <= 600000 && width == 4 && ln >= 1)  ||
-                   (rate <= 600000 && width < 4 && (ln == 1 || ln == 2))) {
-                       val |= LOADGEN_SELECT;
-               }
-               I915_WRITE(CNL_PORT_TX_DW4_LN(ln, port), val);
-       }
-
-       /* 3. Set PORT_CL_DW5 SUS Clock Config to 11b */
-       val = I915_READ(CNL_PORT_CL1CM_DW5);
-       val |= SUS_CLOCK_CONFIG;
-       I915_WRITE(CNL_PORT_CL1CM_DW5, val);
-
-       /* 4. Clear training enable to change swing values */
-       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
-       val &= ~TX_TRAINING_EN;
-       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
-
-       /* 5. Program swing and de-emphasis */
-       cnl_ddi_vswing_program(encoder, level, type);
-
-       /* 6. Set training enable to trigger update */
-       val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
-       val |= TX_TRAINING_EN;
-       I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
-}
-
-static void icl_ddi_combo_vswing_program(struct drm_i915_private *dev_priv,
-                                       u32 level, enum port port, int type,
-                                       int rate)
-{
-       const struct cnl_ddi_buf_trans *ddi_translations = NULL;
-       u32 n_entries, val;
-       int ln;
-
-       ddi_translations = icl_get_combo_buf_trans(dev_priv, port, type,
-                                                  rate, &n_entries);
-       if (!ddi_translations)
-               return;
-
-       if (level >= n_entries) {
-               DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.", level, n_entries - 1);
-               level = n_entries - 1;
-       }
-
-       /* Set PORT_TX_DW5 */
-       val = I915_READ(ICL_PORT_TX_DW5_LN0(port));
-       val &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK |
-                 TAP2_DISABLE | TAP3_DISABLE);
-       val |= SCALING_MODE_SEL(0x2);
-       val |= RTERM_SELECT(0x6);
-       val |= TAP3_DISABLE;
-       I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
-
-       /* Program PORT_TX_DW2 */
-       val = I915_READ(ICL_PORT_TX_DW2_LN0(port));
-       val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
-                RCOMP_SCALAR_MASK);
-       val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_sel);
-       val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_sel);
-       /* Program Rcomp scalar for every table entry */
-       val |= RCOMP_SCALAR(0x98);
-       I915_WRITE(ICL_PORT_TX_DW2_GRP(port), val);
-
-       /* Program PORT_TX_DW4 */
-       /* We cannot write to GRP. It would overwrite individual loadgen. */
-       for (ln = 0; ln <= 3; ln++) {
-               val = I915_READ(ICL_PORT_TX_DW4_LN(ln, port));
-               val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
-                        CURSOR_COEFF_MASK);
-               val |= POST_CURSOR_1(ddi_translations[level].dw4_post_cursor_1);
-               val |= POST_CURSOR_2(ddi_translations[level].dw4_post_cursor_2);
-               val |= CURSOR_COEFF(ddi_translations[level].dw4_cursor_coeff);
-               I915_WRITE(ICL_PORT_TX_DW4_LN(ln, port), val);
-       }
-
-       /* Program PORT_TX_DW7 */
-       val = I915_READ(ICL_PORT_TX_DW7_LN0(port));
-       val &= ~N_SCALAR_MASK;
-       val |= N_SCALAR(ddi_translations[level].dw7_n_scalar);
-       I915_WRITE(ICL_PORT_TX_DW7_GRP(port), val);
-}
-
-static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                             u32 level,
-                                             enum intel_output_type type)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       int width = 0;
-       int rate = 0;
-       u32 val;
-       int ln = 0;
-
-       if (type == INTEL_OUTPUT_HDMI) {
-               width = 4;
-               /* Rate is always < than 6GHz for HDMI */
-       } else {
-               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-               width = intel_dp->lane_count;
-               rate = intel_dp->link_rate;
-       }
-
-       /*
-        * 1. If port type is eDP or DP,
-        * set PORT_PCS_DW1 cmnkeeper_enable to 1b,
-        * else clear to 0b.
-        */
-       val = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
-       if (type == INTEL_OUTPUT_HDMI)
-               val &= ~COMMON_KEEPER_EN;
-       else
-               val |= COMMON_KEEPER_EN;
-       I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), val);
-
-       /* 2. Program loadgen select */
-       /*
-        * Program PORT_TX_DW4_LN depending on Bit rate and used lanes
-        * <= 6 GHz and 4 lanes (LN0=0, LN1=1, LN2=1, LN3=1)
-        * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0)
-        * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0)
-        */
-       for (ln = 0; ln <= 3; ln++) {
-               val = I915_READ(ICL_PORT_TX_DW4_LN(ln, port));
-               val &= ~LOADGEN_SELECT;
-
-               if ((rate <= 600000 && width == 4 && ln >= 1) ||
-                   (rate <= 600000 && width < 4 && (ln == 1 || ln == 2))) {
-                       val |= LOADGEN_SELECT;
-               }
-               I915_WRITE(ICL_PORT_TX_DW4_LN(ln, port), val);
-       }
-
-       /* 3. Set PORT_CL_DW5 SUS Clock Config to 11b */
-       val = I915_READ(ICL_PORT_CL_DW5(port));
-       val |= SUS_CLOCK_CONFIG;
-       I915_WRITE(ICL_PORT_CL_DW5(port), val);
-
-       /* 4. Clear training enable to change swing values */
-       val = I915_READ(ICL_PORT_TX_DW5_LN0(port));
-       val &= ~TX_TRAINING_EN;
-       I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
-
-       /* 5. Program swing and de-emphasis */
-       icl_ddi_combo_vswing_program(dev_priv, level, port, type, rate);
-
-       /* 6. Set training enable to trigger update */
-       val = I915_READ(ICL_PORT_TX_DW5_LN0(port));
-       val |= TX_TRAINING_EN;
-       I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
-}
-
-static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                          int link_clock,
-                                          u32 level)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       const struct icl_mg_phy_ddi_buf_trans *ddi_translations;
-       u32 n_entries, val;
-       int ln;
-
-       n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
-       ddi_translations = icl_mg_phy_ddi_translations;
-       /* The table does not have values for level 3 and level 9. */
-       if (level >= n_entries || level == 3 || level == 9) {
-               DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.",
-                             level, n_entries - 2);
-               level = n_entries - 2;
-       }
-
-       /* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_TX1_LINK_PARAMS(ln, port));
-               val &= ~CRI_USE_FS32;
-               I915_WRITE(MG_TX1_LINK_PARAMS(ln, port), val);
-
-               val = I915_READ(MG_TX2_LINK_PARAMS(ln, port));
-               val &= ~CRI_USE_FS32;
-               I915_WRITE(MG_TX2_LINK_PARAMS(ln, port), val);
-       }
-
-       /* Program MG_TX_SWINGCTRL with values from vswing table */
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_TX1_SWINGCTRL(ln, port));
-               val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
-               val |= CRI_TXDEEMPH_OVERRIDE_17_12(
-                       ddi_translations[level].cri_txdeemph_override_17_12);
-               I915_WRITE(MG_TX1_SWINGCTRL(ln, port), val);
-
-               val = I915_READ(MG_TX2_SWINGCTRL(ln, port));
-               val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
-               val |= CRI_TXDEEMPH_OVERRIDE_17_12(
-                       ddi_translations[level].cri_txdeemph_override_17_12);
-               I915_WRITE(MG_TX2_SWINGCTRL(ln, port), val);
-       }
-
-       /* Program MG_TX_DRVCTRL with values from vswing table */
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_TX1_DRVCTRL(ln, port));
-               val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
-                        CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
-               val |= CRI_TXDEEMPH_OVERRIDE_5_0(
-                       ddi_translations[level].cri_txdeemph_override_5_0) |
-                       CRI_TXDEEMPH_OVERRIDE_11_6(
-                               ddi_translations[level].cri_txdeemph_override_11_6) |
-                       CRI_TXDEEMPH_OVERRIDE_EN;
-               I915_WRITE(MG_TX1_DRVCTRL(ln, port), val);
-
-               val = I915_READ(MG_TX2_DRVCTRL(ln, port));
-               val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
-                        CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
-               val |= CRI_TXDEEMPH_OVERRIDE_5_0(
-                       ddi_translations[level].cri_txdeemph_override_5_0) |
-                       CRI_TXDEEMPH_OVERRIDE_11_6(
-                               ddi_translations[level].cri_txdeemph_override_11_6) |
-                       CRI_TXDEEMPH_OVERRIDE_EN;
-               I915_WRITE(MG_TX2_DRVCTRL(ln, port), val);
-
-               /* FIXME: Program CRI_LOADGEN_SEL after the spec is updated */
-       }
-
-       /*
-        * Program MG_CLKHUB<LN, port being used> with value from frequency table
-        * In case of Legacy mode on MG PHY, both TX1 and TX2 enabled so use the
-        * values from table for which TX1 and TX2 enabled.
-        */
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_CLKHUB(ln, port));
-               if (link_clock < 300000)
-                       val |= CFG_LOW_RATE_LKREN_EN;
-               else
-                       val &= ~CFG_LOW_RATE_LKREN_EN;
-               I915_WRITE(MG_CLKHUB(ln, port), val);
-       }
-
-       /* Program the MG_TX_DCC<LN, port being used> based on the link frequency */
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_TX1_DCC(ln, port));
-               val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
-               if (link_clock <= 500000) {
-                       val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
-               } else {
-                       val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
-                               CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
-               }
-               I915_WRITE(MG_TX1_DCC(ln, port), val);
-
-               val = I915_READ(MG_TX2_DCC(ln, port));
-               val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
-               if (link_clock <= 500000) {
-                       val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
-               } else {
-                       val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
-                               CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
-               }
-               I915_WRITE(MG_TX2_DCC(ln, port), val);
-       }
-
-       /* Program MG_TX_PISO_READLOAD with values from vswing table */
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_TX1_PISO_READLOAD(ln, port));
-               val |= CRI_CALCINIT;
-               I915_WRITE(MG_TX1_PISO_READLOAD(ln, port), val);
-
-               val = I915_READ(MG_TX2_PISO_READLOAD(ln, port));
-               val |= CRI_CALCINIT;
-               I915_WRITE(MG_TX2_PISO_READLOAD(ln, port), val);
-       }
-}
-
-static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                   int link_clock,
-                                   u32 level,
-                                   enum intel_output_type type)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-
-       if (intel_port_is_combophy(dev_priv, port))
-               icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
-       else
-               icl_mg_phy_ddi_vswing_sequence(encoder, link_clock, level);
-}
-
-static u32 translate_signal_level(int signal_levels)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(index_to_dp_signal_levels); i++) {
-               if (index_to_dp_signal_levels[i] == signal_levels)
-                       return i;
-       }
-
-       WARN(1, "Unsupported voltage swing/pre-emphasis level: 0x%x\n",
-            signal_levels);
-
-       return 0;
-}
-
-static u32 intel_ddi_dp_level(struct intel_dp *intel_dp)
-{
-       u8 train_set = intel_dp->train_set[0];
-       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
-                                        DP_TRAIN_PRE_EMPHASIS_MASK);
-
-       return translate_signal_level(signal_levels);
-}
-
-u32 bxt_signal_levels(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
-       struct intel_encoder *encoder = &dport->base;
-       int level = intel_ddi_dp_level(intel_dp);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
-                                       level, encoder->type);
-       else if (IS_CANNONLAKE(dev_priv))
-               cnl_ddi_vswing_sequence(encoder, level, encoder->type);
-       else
-               bxt_ddi_vswing_sequence(encoder, level, encoder->type);
-
-       return 0;
-}
-
-u32 ddi_signal_levels(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
-       struct intel_encoder *encoder = &dport->base;
-       int level = intel_ddi_dp_level(intel_dp);
-
-       if (IS_GEN9_BC(dev_priv))
-               skl_ddi_set_iboost(encoder, level, encoder->type);
-
-       return DDI_BUF_TRANS_SELECT(level);
-}
-
-static inline
-u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv,
-                             enum port port)
-{
-       if (intel_port_is_combophy(dev_priv, port)) {
-               return ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(port);
-       } else if (intel_port_is_tc(dev_priv, port)) {
-               enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-
-               return ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port);
-       }
-
-       return 0;
-}
-
-static void icl_map_plls_to_ports(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
-       enum port port = encoder->port;
-       u32 val;
-
-       mutex_lock(&dev_priv->dpll_lock);
-
-       val = I915_READ(DPCLKA_CFGCR0_ICL);
-       WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0);
-
-       if (intel_port_is_combophy(dev_priv, port)) {
-               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
-               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
-               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-               POSTING_READ(DPCLKA_CFGCR0_ICL);
-       }
-
-       val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port);
-       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-
-       mutex_unlock(&dev_priv->dpll_lock);
-}
-
-static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       u32 val;
-
-       mutex_lock(&dev_priv->dpll_lock);
-
-       val = I915_READ(DPCLKA_CFGCR0_ICL);
-       val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port);
-       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-
-       mutex_unlock(&dev_priv->dpll_lock);
-}
-
-void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val;
-       enum port port;
-       u32 port_mask;
-       bool ddi_clk_needed;
-
-       /*
-        * In case of DP MST, we sanitize the primary encoder only, not the
-        * virtual ones.
-        */
-       if (encoder->type == INTEL_OUTPUT_DP_MST)
-               return;
-
-       if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) {
-               u8 pipe_mask;
-               bool is_mst;
-
-               intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);
-               /*
-                * In the unlikely case that BIOS enables DP in MST mode, just
-                * warn since our MST HW readout is incomplete.
-                */
-               if (WARN_ON(is_mst))
-                       return;
-       }
-
-       port_mask = BIT(encoder->port);
-       ddi_clk_needed = encoder->base.crtc;
-
-       if (encoder->type == INTEL_OUTPUT_DSI) {
-               struct intel_encoder *other_encoder;
-
-               port_mask = intel_dsi_encoder_ports(encoder);
-               /*
-                * Sanity check that we haven't incorrectly registered another
-                * encoder using any of the ports of this DSI encoder.
-                */
-               for_each_intel_encoder(&dev_priv->drm, other_encoder) {
-                       if (other_encoder == encoder)
-                               continue;
-
-                       if (WARN_ON(port_mask & BIT(other_encoder->port)))
-                               return;
-               }
-               /*
-                * For DSI we keep the ddi clocks gated
-                * except during enable/disable sequence.
-                */
-               ddi_clk_needed = false;
-       }
-
-       val = I915_READ(DPCLKA_CFGCR0_ICL);
-       for_each_port_masked(port, port_mask) {
-               bool ddi_clk_ungated = !(val &
-                                        icl_dpclka_cfgcr0_clk_off(dev_priv,
-                                                                  port));
-
-               if (ddi_clk_needed == ddi_clk_ungated)
-                       continue;
-
-               /*
-                * Punt on the case now where clock is gated, but it would
-                * be needed by the port. Something else is really broken then.
-                */
-               if (WARN_ON(ddi_clk_needed))
-                       continue;
-
-               DRM_NOTE("Port %c is disabled/in DSI mode with an ungated DDI clock, gate it\n",
-                        port_name(port));
-               val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port);
-               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-       }
-}
-
-static void intel_ddi_clk_select(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       u32 val;
-       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
-
-       if (WARN_ON(!pll))
-               return;
-
-       mutex_lock(&dev_priv->dpll_lock);
-
-       if (INTEL_GEN(dev_priv) >= 11) {
-               if (!intel_port_is_combophy(dev_priv, port))
-                       I915_WRITE(DDI_CLK_SEL(port),
-                                  icl_pll_to_ddi_clk_sel(encoder, crtc_state));
-       } else if (IS_CANNONLAKE(dev_priv)) {
-               /* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */
-               val = I915_READ(DPCLKA_CFGCR0);
-               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
-               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
-               I915_WRITE(DPCLKA_CFGCR0, val);
-
-               /*
-                * Configure DPCLKA_CFGCR0 to turn on the clock for the DDI.
-                * This step and the step before must be done with separate
-                * register writes.
-                */
-               val = I915_READ(DPCLKA_CFGCR0);
-               val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
-               I915_WRITE(DPCLKA_CFGCR0, val);
-       } else if (IS_GEN9_BC(dev_priv)) {
-               /* DDI -> PLL mapping  */
-               val = I915_READ(DPLL_CTRL2);
-
-               val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
-                        DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
-               val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) |
-                       DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
-
-               I915_WRITE(DPLL_CTRL2, val);
-
-       } else if (INTEL_GEN(dev_priv) < 9) {
-               I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
-       }
-
-       mutex_unlock(&dev_priv->dpll_lock);
-}
-
-static void intel_ddi_clk_disable(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-
-       if (INTEL_GEN(dev_priv) >= 11) {
-               if (!intel_port_is_combophy(dev_priv, port))
-                       I915_WRITE(DDI_CLK_SEL(port), DDI_CLK_SEL_NONE);
-       } else if (IS_CANNONLAKE(dev_priv)) {
-               I915_WRITE(DPCLKA_CFGCR0, I915_READ(DPCLKA_CFGCR0) |
-                          DPCLKA_CFGCR0_DDI_CLK_OFF(port));
-       } else if (IS_GEN9_BC(dev_priv)) {
-               I915_WRITE(DPLL_CTRL2, I915_READ(DPLL_CTRL2) |
-                          DPLL_CTRL2_DDI_CLK_OFF(port));
-       } else if (INTEL_GEN(dev_priv) < 9) {
-               I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
-       }
-}
-
-static void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port)
-{
-       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-       enum port port = dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       u32 val;
-       int ln;
-
-       if (tc_port == PORT_TC_NONE)
-               return;
-
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_DP_MODE(ln, port));
-               val |= MG_DP_MODE_CFG_TR2PWR_GATING |
-                      MG_DP_MODE_CFG_TRPWR_GATING |
-                      MG_DP_MODE_CFG_CLNPWR_GATING |
-                      MG_DP_MODE_CFG_DIGPWR_GATING |
-                      MG_DP_MODE_CFG_GAONPWR_GATING;
-               I915_WRITE(MG_DP_MODE(ln, port), val);
-       }
-
-       val = I915_READ(MG_MISC_SUS0(tc_port));
-       val |= MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(3) |
-              MG_MISC_SUS0_CFG_TR2PWR_GATING |
-              MG_MISC_SUS0_CFG_CL2PWR_GATING |
-              MG_MISC_SUS0_CFG_GAONPWR_GATING |
-              MG_MISC_SUS0_CFG_TRPWR_GATING |
-              MG_MISC_SUS0_CFG_CL1PWR_GATING |
-              MG_MISC_SUS0_CFG_DGPWR_GATING;
-       I915_WRITE(MG_MISC_SUS0(tc_port), val);
-}
-
-static void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port)
-{
-       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-       enum port port = dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       u32 val;
-       int ln;
-
-       if (tc_port == PORT_TC_NONE)
-               return;
-
-       for (ln = 0; ln < 2; ln++) {
-               val = I915_READ(MG_DP_MODE(ln, port));
-               val &= ~(MG_DP_MODE_CFG_TR2PWR_GATING |
-                        MG_DP_MODE_CFG_TRPWR_GATING |
-                        MG_DP_MODE_CFG_CLNPWR_GATING |
-                        MG_DP_MODE_CFG_DIGPWR_GATING |
-                        MG_DP_MODE_CFG_GAONPWR_GATING);
-               I915_WRITE(MG_DP_MODE(ln, port), val);
-       }
-
-       val = I915_READ(MG_MISC_SUS0(tc_port));
-       val &= ~(MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK |
-                MG_MISC_SUS0_CFG_TR2PWR_GATING |
-                MG_MISC_SUS0_CFG_CL2PWR_GATING |
-                MG_MISC_SUS0_CFG_GAONPWR_GATING |
-                MG_MISC_SUS0_CFG_TRPWR_GATING |
-                MG_MISC_SUS0_CFG_CL1PWR_GATING |
-                MG_MISC_SUS0_CFG_DGPWR_GATING);
-       I915_WRITE(MG_MISC_SUS0(tc_port), val);
-}
-
-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;
-
-       if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT)
-               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:
-               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);
-
-               switch (lane_info) {
-               case 0x1:
-               case 0x4:
-                       break;
-               case 0x2:
-                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE;
-                       break;
-               case 0x3:
-                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE |
-                              MG_DP_MODE_CFG_DP_X2_MODE;
-                       break;
-               case 0x8:
-                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE;
-                       break;
-               case 0xC:
-                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE |
-                              MG_DP_MODE_CFG_DP_X2_MODE;
-                       break;
-               case 0xF:
-                       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;
-                       break;
-               default:
-                       MISSING_CASE(lane_info);
-               }
-               break;
-
-       case TC_PORT_LEGACY:
-               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;
-               break;
-
-       default:
-               MISSING_CASE(intel_dig_port->tc_type);
-               return;
-       }
-
-       I915_WRITE(MG_DP_MODE(0, port), ln0);
-       I915_WRITE(MG_DP_MODE(1, port), ln1);
-}
-
-static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
-                                       const struct intel_crtc_state *crtc_state)
-{
-       if (!crtc_state->fec_enable)
-               return;
-
-       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0)
-               DRM_DEBUG_KMS("Failed to set FEC_READY in the sink\n");
-}
-
-static void intel_ddi_enable_fec(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       u32 val;
-
-       if (!crtc_state->fec_enable)
-               return;
-
-       val = I915_READ(DP_TP_CTL(port));
-       val |= DP_TP_CTL_FEC_ENABLE;
-       I915_WRITE(DP_TP_CTL(port), val);
-
-       if (intel_wait_for_register(&dev_priv->uncore, DP_TP_STATUS(port),
-                                   DP_TP_STATUS_FEC_ENABLE_LIVE,
-                                   DP_TP_STATUS_FEC_ENABLE_LIVE,
-                                   1))
-               DRM_ERROR("Timed out waiting for FEC Enable Status\n");
-}
-
-static void intel_ddi_disable_fec_state(struct intel_encoder *encoder,
-                                       const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       u32 val;
-
-       if (!crtc_state->fec_enable)
-               return;
-
-       val = I915_READ(DP_TP_CTL(port));
-       val &= ~DP_TP_CTL_FEC_ENABLE;
-       I915_WRITE(DP_TP_CTL(port), val);
-       POSTING_READ(DP_TP_CTL(port));
-}
-
-static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
-                                   const struct intel_crtc_state *crtc_state,
-                                   const struct drm_connector_state *conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
-       int level = intel_ddi_dp_level(intel_dp);
-
-       WARN_ON(is_mst && (port == PORT_A || port == PORT_E));
-
-       intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
-                                crtc_state->lane_count, is_mst);
-
-       intel_edp_panel_on(intel_dp);
-
-       intel_ddi_clk_select(encoder, crtc_state);
-
-       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);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
-                                       level, encoder->type);
-       else if (IS_CANNONLAKE(dev_priv))
-               cnl_ddi_vswing_sequence(encoder, level, encoder->type);
-       else if (IS_GEN9_LP(dev_priv))
-               bxt_ddi_vswing_sequence(encoder, level, encoder->type);
-       else
-               intel_prepare_dp_ddi_buffers(encoder, crtc_state);
-
-       if (intel_port_is_combophy(dev_priv, port)) {
-               bool lane_reversal =
-                       dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
-
-               intel_combo_phy_power_up_lanes(dev_priv, port, false,
-                                              crtc_state->lane_count,
-                                              lane_reversal);
-       }
-
-       intel_ddi_init_dp_buf_reg(encoder);
-       if (!is_mst)
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
-       intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
-                                             true);
-       intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
-       intel_dp_start_link_train(intel_dp);
-       if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
-               intel_dp_stop_link_train(intel_dp);
-
-       intel_ddi_enable_fec(encoder, crtc_state);
-
-       icl_enable_phy_clock_gating(dig_port);
-
-       if (!is_mst)
-               intel_ddi_enable_pipe_clock(crtc_state);
-
-       intel_dsc_enable(encoder, crtc_state);
-}
-
-static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
-                                     const struct intel_crtc_state *crtc_state,
-                                     const struct drm_connector_state *conn_state)
-{
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
-       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       int level = intel_ddi_hdmi_level(dev_priv, port);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-
-       intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
-       intel_ddi_clk_select(encoder, crtc_state);
-
-       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);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
-                                       level, INTEL_OUTPUT_HDMI);
-       else if (IS_CANNONLAKE(dev_priv))
-               cnl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
-       else if (IS_GEN9_LP(dev_priv))
-               bxt_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
-       else
-               intel_prepare_hdmi_ddi_buffers(encoder, level);
-
-       icl_enable_phy_clock_gating(dig_port);
-
-       if (IS_GEN9_BC(dev_priv))
-               skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI);
-
-       intel_ddi_enable_pipe_clock(crtc_state);
-
-       intel_dig_port->set_infoframes(encoder,
-                                      crtc_state->has_infoframe,
-                                      crtc_state, conn_state);
-}
-
-static void intel_ddi_pre_enable(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum pipe pipe = crtc->pipe;
-
-       /*
-        * When called from DP MST code:
-        * - conn_state will be NULL
-        * - encoder will be the main encoder (ie. mst->primary)
-        * - the main connector associated with this port
-        *   won't be active or linked to a crtc
-        * - crtc_state will be the state of the first stream to
-        *   be activated on this port, and it may not be the same
-        *   stream that will be deactivated last, but each stream
-        *   should have a state that is identical when it comes to
-        *   the DP link parameteres
-        */
-
-       WARN_ON(crtc_state->has_pch_encoder);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_map_plls_to_ports(encoder, crtc_state);
-
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
-
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
-               intel_ddi_pre_enable_hdmi(encoder, crtc_state, conn_state);
-       } else {
-               struct intel_lspcon *lspcon =
-                               enc_to_intel_lspcon(&encoder->base);
-
-               intel_ddi_pre_enable_dp(encoder, crtc_state, conn_state);
-               if (lspcon->active) {
-                       struct intel_digital_port *dig_port =
-                                       enc_to_dig_port(&encoder->base);
-
-                       dig_port->set_infoframes(encoder,
-                                                crtc_state->has_infoframe,
-                                                crtc_state, conn_state);
-               }
-       }
-}
-
-static void intel_disable_ddi_buf(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       bool wait = false;
-       u32 val;
-
-       val = I915_READ(DDI_BUF_CTL(port));
-       if (val & DDI_BUF_CTL_ENABLE) {
-               val &= ~DDI_BUF_CTL_ENABLE;
-               I915_WRITE(DDI_BUF_CTL(port), val);
-               wait = true;
-       }
-
-       val = I915_READ(DP_TP_CTL(port));
-       val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
-       val |= DP_TP_CTL_LINK_TRAIN_PAT1;
-       I915_WRITE(DP_TP_CTL(port), val);
-
-       /* Disable FEC in DP Sink */
-       intel_ddi_disable_fec_state(encoder, crtc_state);
-
-       if (wait)
-               intel_wait_ddi_buf_idle(dev_priv, port);
-}
-
-static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
-                                     const struct intel_crtc_state *old_crtc_state,
-                                     const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       struct intel_dp *intel_dp = &dig_port->dp;
-       bool is_mst = intel_crtc_has_type(old_crtc_state,
-                                         INTEL_OUTPUT_DP_MST);
-
-       if (!is_mst) {
-               intel_ddi_disable_pipe_clock(old_crtc_state);
-               /*
-                * Power down sink before disabling the port, otherwise we end
-                * up getting interrupts from the sink on detecting link loss.
-                */
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
-       }
-
-       intel_disable_ddi_buf(encoder, old_crtc_state);
-
-       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);
-
-       intel_ddi_clk_disable(encoder);
-}
-
-static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
-                                       const struct intel_crtc_state *old_crtc_state,
-                                       const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
-
-       dig_port->set_infoframes(encoder, false,
-                                old_crtc_state, old_conn_state);
-
-       intel_ddi_disable_pipe_clock(old_crtc_state);
-
-       intel_disable_ddi_buf(encoder, old_crtc_state);
-
-       intel_display_power_put_unchecked(dev_priv,
-                                         dig_port->ddi_io_power_domain);
-
-       intel_ddi_clk_disable(encoder);
-
-       intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
-}
-
-static void intel_ddi_post_disable(struct intel_encoder *encoder,
-                                  const struct intel_crtc_state *old_crtc_state,
-                                  const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       /*
-        * When called from DP MST code:
-        * - old_conn_state will be NULL
-        * - encoder will be the main encoder (ie. mst->primary)
-        * - the main connector associated with this port
-        *   won't be active or linked to a crtc
-        * - old_crtc_state will be the state of the last stream to
-        *   be deactivated on this port, and it may not be the same
-        *   stream that was activated last, but each stream
-        *   should have a state that is identical when it comes to
-        *   the DP link parameteres
-        */
-
-       if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
-               intel_ddi_post_disable_hdmi(encoder,
-                                           old_crtc_state, old_conn_state);
-       else
-               intel_ddi_post_disable_dp(encoder,
-                                         old_crtc_state, old_conn_state);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_unmap_plls_to_ports(encoder);
-}
-
-void intel_ddi_fdi_post_disable(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *old_crtc_state,
-                               const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val;
-
-       /*
-        * Bspec lists this as both step 13 (before DDI_BUF_CTL disable)
-        * and step 18 (after clearing PORT_CLK_SEL). Based on a BUN,
-        * step 13 is the correct place for it. Step 18 is where it was
-        * originally before the BUN.
-        */
-       val = I915_READ(FDI_RX_CTL(PIPE_A));
-       val &= ~FDI_RX_ENABLE;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
-
-       intel_disable_ddi_buf(encoder, old_crtc_state);
-       intel_ddi_clk_disable(encoder);
-
-       val = I915_READ(FDI_RX_MISC(PIPE_A));
-       val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
-       val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
-       I915_WRITE(FDI_RX_MISC(PIPE_A), val);
-
-       val = I915_READ(FDI_RX_CTL(PIPE_A));
-       val &= ~FDI_PCDCLK;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
-
-       val = I915_READ(FDI_RX_CTL(PIPE_A));
-       val &= ~FDI_RX_PLL_ENABLE;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
-}
-
-static void intel_enable_ddi_dp(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *crtc_state,
-                               const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = encoder->port;
-
-       if (port == PORT_A && INTEL_GEN(dev_priv) < 9)
-               intel_dp_stop_link_train(intel_dp);
-
-       intel_edp_backlight_on(crtc_state, conn_state);
-       intel_psr_enable(intel_dp, crtc_state);
-       intel_dp_ycbcr_420_enable(intel_dp, crtc_state);
-       intel_edp_drrs_enable(intel_dp, crtc_state);
-
-       if (crtc_state->has_audio)
-               intel_audio_codec_enable(encoder, crtc_state, conn_state);
-}
-
-static i915_reg_t
-gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv,
-                              enum port port)
-{
-       static const i915_reg_t regs[] = {
-               [PORT_A] = CHICKEN_TRANS_EDP,
-               [PORT_B] = CHICKEN_TRANS_A,
-               [PORT_C] = CHICKEN_TRANS_B,
-               [PORT_D] = CHICKEN_TRANS_C,
-               [PORT_E] = CHICKEN_TRANS_A,
-       };
-
-       WARN_ON(INTEL_GEN(dev_priv) < 9);
-
-       if (WARN_ON(port < PORT_A || port > PORT_E))
-               port = PORT_A;
-
-       return regs[port];
-}
-
-static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       struct drm_connector *connector = conn_state->connector;
-       enum port port = encoder->port;
-
-       if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
-                                              crtc_state->hdmi_high_tmds_clock_ratio,
-                                              crtc_state->hdmi_scrambling))
-               DRM_ERROR("[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n",
-                         connector->base.id, connector->name);
-
-       /* Display WA #1143: skl,kbl,cfl */
-       if (IS_GEN9_BC(dev_priv)) {
-               /*
-                * For some reason these chicken bits have been
-                * stuffed into a transcoder register, event though
-                * the bits affect a specific DDI port rather than
-                * a specific transcoder.
-                */
-               i915_reg_t reg = gen9_chicken_trans_reg_by_port(dev_priv, port);
-               u32 val;
-
-               val = I915_READ(reg);
-
-               if (port == PORT_E)
-                       val |= DDIE_TRAINING_OVERRIDE_ENABLE |
-                               DDIE_TRAINING_OVERRIDE_VALUE;
-               else
-                       val |= DDI_TRAINING_OVERRIDE_ENABLE |
-                               DDI_TRAINING_OVERRIDE_VALUE;
-
-               I915_WRITE(reg, val);
-               POSTING_READ(reg);
-
-               udelay(1);
-
-               if (port == PORT_E)
-                       val &= ~(DDIE_TRAINING_OVERRIDE_ENABLE |
-                                DDIE_TRAINING_OVERRIDE_VALUE);
-               else
-                       val &= ~(DDI_TRAINING_OVERRIDE_ENABLE |
-                                DDI_TRAINING_OVERRIDE_VALUE);
-
-               I915_WRITE(reg, val);
-       }
-
-       /* In HDMI/DVI mode, the port width, and swing/emphasis values
-        * are ignored so nothing special needs to be done besides
-        * enabling the port.
-        */
-       I915_WRITE(DDI_BUF_CTL(port),
-                  dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE);
-
-       if (crtc_state->has_audio)
-               intel_audio_codec_enable(encoder, crtc_state, conn_state);
-}
-
-static void intel_enable_ddi(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *crtc_state,
-                            const struct drm_connector_state *conn_state)
-{
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
-               intel_enable_ddi_hdmi(encoder, crtc_state, conn_state);
-       else
-               intel_enable_ddi_dp(encoder, crtc_state, conn_state);
-
-       /* Enable hdcp if it's desired */
-       if (conn_state->content_protection ==
-           DRM_MODE_CONTENT_PROTECTION_DESIRED)
-               intel_hdcp_enable(to_intel_connector(conn_state->connector));
-}
-
-static void intel_disable_ddi_dp(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *old_crtc_state,
-                                const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-       intel_dp->link_trained = false;
-
-       if (old_crtc_state->has_audio)
-               intel_audio_codec_disable(encoder,
-                                         old_crtc_state, old_conn_state);
-
-       intel_edp_drrs_disable(intel_dp, old_crtc_state);
-       intel_psr_disable(intel_dp, old_crtc_state);
-       intel_edp_backlight_off(old_conn_state);
-       /* Disable the decompression in DP Sink */
-       intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state,
-                                             false);
-}
-
-static void intel_disable_ddi_hdmi(struct intel_encoder *encoder,
-                                  const struct intel_crtc_state *old_crtc_state,
-                                  const struct drm_connector_state *old_conn_state)
-{
-       struct drm_connector *connector = old_conn_state->connector;
-
-       if (old_crtc_state->has_audio)
-               intel_audio_codec_disable(encoder,
-                                         old_crtc_state, old_conn_state);
-
-       if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
-                                              false, false))
-               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Failed to reset sink scrambling/TMDS bit clock ratio\n",
-                             connector->base.id, connector->name);
-}
-
-static void intel_disable_ddi(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-{
-       intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
-
-       if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
-               intel_disable_ddi_hdmi(encoder, old_crtc_state, old_conn_state);
-       else
-               intel_disable_ddi_dp(encoder, old_crtc_state, old_conn_state);
-}
-
-static void intel_ddi_update_pipe_dp(struct intel_encoder *encoder,
-                                    const struct intel_crtc_state *crtc_state,
-                                    const struct drm_connector_state *conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-       intel_ddi_set_pipe_settings(crtc_state);
-
-       intel_psr_update(intel_dp, crtc_state);
-       intel_edp_drrs_enable(intel_dp, crtc_state);
-
-       intel_panel_update_backlight(encoder, crtc_state, conn_state);
-}
-
-static void intel_ddi_update_pipe(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
-               intel_ddi_update_pipe_dp(encoder, crtc_state, conn_state);
-
-       if (conn_state->content_protection ==
-           DRM_MODE_CONTENT_PROTECTION_DESIRED)
-               intel_hdcp_enable(to_intel_connector(conn_state->connector));
-       else if (conn_state->content_protection ==
-                DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
-               intel_hdcp_disable(to_intel_connector(conn_state->connector));
-}
-
-static void intel_ddi_set_fia_lane_count(struct intel_encoder *encoder,
-                                        const struct intel_crtc_state *pipe_config,
-                                        enum port port)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       u32 val = I915_READ(PORT_TX_DFLEXDPMLE1);
-       bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
-
-       val &= ~DFLEXDPMLE1_DPMLETC_MASK(tc_port);
-       switch (pipe_config->lane_count) {
-       case 1:
-               val |= (lane_reversal) ? DFLEXDPMLE1_DPMLETC_ML3(tc_port) :
-               DFLEXDPMLE1_DPMLETC_ML0(tc_port);
-               break;
-       case 2:
-               val |= (lane_reversal) ? DFLEXDPMLE1_DPMLETC_ML3_2(tc_port) :
-               DFLEXDPMLE1_DPMLETC_ML1_0(tc_port);
-               break;
-       case 4:
-               val |= DFLEXDPMLE1_DPMLETC_ML3_0(tc_port);
-               break;
-       default:
-               MISSING_CASE(pipe_config->lane_count);
-       }
-       I915_WRITE(PORT_TX_DFLEXDPMLE1, val);
-}
-
-static void
-intel_ddi_pre_pll_enable(struct intel_encoder *encoder,
-                        const struct intel_crtc_state *crtc_state,
-                        const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       enum port port = encoder->port;
-
-       if (intel_crtc_has_dp_encoder(crtc_state) ||
-           intel_port_is_tc(dev_priv, encoder->port))
-               intel_display_power_get(dev_priv,
-                                       intel_ddi_main_link_aux_domain(dig_port));
-
-       if (IS_GEN9_LP(dev_priv))
-               bxt_ddi_phy_set_lane_optim_mask(encoder,
-                                               crtc_state->lane_lat_optim_mask);
-
-       /*
-        * 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)
-               return;
-
-       intel_ddi_set_fia_lane_count(encoder, crtc_state, port);
-}
-
-static void
-intel_ddi_post_pll_disable(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *crtc_state,
-                          const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-
-       if (intel_crtc_has_dp_encoder(crtc_state) ||
-           intel_port_is_tc(dev_priv, encoder->port))
-               intel_display_power_put_unchecked(dev_priv,
-                                                 intel_ddi_main_link_aux_domain(dig_port));
-}
-
-static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv =
-               to_i915(intel_dig_port->base.base.dev);
-       enum port port = intel_dig_port->base.port;
-       u32 val;
-       bool wait = false;
-
-       if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) {
-               val = I915_READ(DDI_BUF_CTL(port));
-               if (val & DDI_BUF_CTL_ENABLE) {
-                       val &= ~DDI_BUF_CTL_ENABLE;
-                       I915_WRITE(DDI_BUF_CTL(port), val);
-                       wait = true;
-               }
-
-               val = I915_READ(DP_TP_CTL(port));
-               val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
-               val |= DP_TP_CTL_LINK_TRAIN_PAT1;
-               I915_WRITE(DP_TP_CTL(port), val);
-               POSTING_READ(DP_TP_CTL(port));
-
-               if (wait)
-                       intel_wait_ddi_buf_idle(dev_priv, port);
-       }
-
-       val = DP_TP_CTL_ENABLE |
-             DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
-       if (intel_dp->link_mst)
-               val |= DP_TP_CTL_MODE_MST;
-       else {
-               val |= DP_TP_CTL_MODE_SST;
-               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-                       val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
-       }
-       I915_WRITE(DP_TP_CTL(port), val);
-       POSTING_READ(DP_TP_CTL(port));
-
-       intel_dp->DP |= DDI_BUF_CTL_ENABLE;
-       I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP);
-       POSTING_READ(DDI_BUF_CTL(port));
-
-       udelay(600);
-}
-
-static bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
-                                      enum transcoder cpu_transcoder)
-{
-       if (cpu_transcoder == TRANSCODER_EDP)
-               return false;
-
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO))
-               return false;
-
-       return I915_READ(HSW_AUD_PIN_ELD_CP_VLD) &
-               AUDIO_OUTPUT_ENABLE(cpu_transcoder);
-}
-
-void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
-                                        struct intel_crtc_state *crtc_state)
-{
-       if (INTEL_GEN(dev_priv) >= 11 && crtc_state->port_clock > 594000)
-               crtc_state->min_voltage_level = 1;
-       else if (IS_CANNONLAKE(dev_priv) && crtc_state->port_clock > 594000)
-               crtc_state->min_voltage_level = 2;
-}
-
-void intel_ddi_get_config(struct intel_encoder *encoder,
-                         struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       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 */
-       if (WARN_ON(transcoder_is_dsi(cpu_transcoder)))
-               return;
-
-       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
-       if (temp & TRANS_DDI_PHSYNC)
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NHSYNC;
-       if (temp & TRANS_DDI_PVSYNC)
-               flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NVSYNC;
-
-       pipe_config->base.adjusted_mode.flags |= flags;
-
-       switch (temp & TRANS_DDI_BPC_MASK) {
-       case TRANS_DDI_BPC_6:
-               pipe_config->pipe_bpp = 18;
-               break;
-       case TRANS_DDI_BPC_8:
-               pipe_config->pipe_bpp = 24;
-               break;
-       case TRANS_DDI_BPC_10:
-               pipe_config->pipe_bpp = 30;
-               break;
-       case TRANS_DDI_BPC_12:
-               pipe_config->pipe_bpp = 36;
-               break;
-       default:
-               break;
-       }
-
-       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);
-
-               if (pipe_config->infoframes.enable)
-                       pipe_config->has_infoframe = true;
-
-               if (temp & TRANS_DDI_HDMI_SCRAMBLING)
-                       pipe_config->hdmi_scrambling = true;
-               if (temp & TRANS_DDI_HIGH_TMDS_CHAR_RATE)
-                       pipe_config->hdmi_high_tmds_clock_ratio = true;
-               /* fall through */
-       case TRANS_DDI_MODE_SELECT_DVI:
-               pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI);
-               pipe_config->lane_count = 4;
-               break;
-       case TRANS_DDI_MODE_SELECT_FDI:
-               pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG);
-               break;
-       case TRANS_DDI_MODE_SELECT_DP_SST:
-               if (encoder->type == INTEL_OUTPUT_EDP)
-                       pipe_config->output_types |= BIT(INTEL_OUTPUT_EDP);
-               else
-                       pipe_config->output_types |= BIT(INTEL_OUTPUT_DP);
-               pipe_config->lane_count =
-                       ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
-               intel_dp_get_m_n(intel_crtc, pipe_config);
-               break;
-       case TRANS_DDI_MODE_SELECT_DP_MST:
-               pipe_config->output_types |= BIT(INTEL_OUTPUT_DP_MST);
-               pipe_config->lane_count =
-                       ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
-               intel_dp_get_m_n(intel_crtc, pipe_config);
-               break;
-       default:
-               break;
-       }
-
-       pipe_config->has_audio =
-               intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder);
-
-       if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.bpp &&
-           pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) {
-               /*
-                * This is a big fat ugly hack.
-                *
-                * Some machines in UEFI boot mode provide us a VBT that has 18
-                * bpp and 1.62 GHz link bandwidth for eDP, which for reasons
-                * unknown we fail to light up. Yet the same BIOS boots up with
-                * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as
-                * max, not what it tells us to use.
-                *
-                * Note: This will still be broken if the eDP panel is not lit
-                * up by the BIOS, and thus we can't get the mode at module
-                * load.
-                */
-               DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n",
-                             pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp);
-               dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
-       }
-
-       intel_ddi_clock_get(encoder, pipe_config);
-
-       if (IS_GEN9_LP(dev_priv))
-               pipe_config->lane_lat_optim_mask =
-                       bxt_ddi_phy_get_lane_lat_optim_mask(encoder);
-
-       intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
-
-       intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
-
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_AVI,
-                            &pipe_config->infoframes.avi);
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_SPD,
-                            &pipe_config->infoframes.spd);
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_VENDOR,
-                            &pipe_config->infoframes.hdmi);
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_DRM,
-                            &pipe_config->infoframes.drm);
-}
-
-static enum intel_output_type
-intel_ddi_compute_output_type(struct intel_encoder *encoder,
-                             struct intel_crtc_state *crtc_state,
-                             struct drm_connector_state *conn_state)
-{
-       switch (conn_state->connector->connector_type) {
-       case DRM_MODE_CONNECTOR_HDMIA:
-               return INTEL_OUTPUT_HDMI;
-       case DRM_MODE_CONNECTOR_eDP:
-               return INTEL_OUTPUT_EDP;
-       case DRM_MODE_CONNECTOR_DisplayPort:
-               return INTEL_OUTPUT_DP;
-       default:
-               MISSING_CASE(conn_state->connector->connector_type);
-               return INTEL_OUTPUT_UNUSED;
-       }
-}
-
-static int intel_ddi_compute_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config,
-                                   struct drm_connector_state *conn_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       int ret;
-
-       if (HAS_TRANSCODER_EDP(dev_priv) && port == PORT_A)
-               pipe_config->cpu_transcoder = TRANSCODER_EDP;
-
-       if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
-               ret = intel_hdmi_compute_config(encoder, pipe_config, conn_state);
-       else
-               ret = intel_dp_compute_config(encoder, pipe_config, conn_state);
-       if (ret)
-               return ret;
-
-       if (IS_HASWELL(dev_priv) && crtc->pipe == PIPE_A &&
-           pipe_config->cpu_transcoder == TRANSCODER_EDP)
-               pipe_config->pch_pfit.force_thru =
-                       pipe_config->pch_pfit.enabled ||
-                       pipe_config->crc_enabled;
-
-       if (IS_GEN9_LP(dev_priv))
-               pipe_config->lane_lat_optim_mask =
-                       bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count);
-
-       intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
-
-       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,
-       .destroy = intel_ddi_encoder_destroy,
-};
-
-static struct intel_connector *
-intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
-{
-       struct intel_connector *connector;
-       enum port port = intel_dig_port->base.port;
-
-       connector = intel_connector_alloc();
-       if (!connector)
-               return NULL;
-
-       intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
-       intel_dig_port->dp.prepare_link_retrain =
-               intel_ddi_prepare_link_retrain;
-
-       if (!intel_dp_init_connector(intel_dig_port, connector)) {
-               kfree(connector);
-               return NULL;
-       }
-
-       return connector;
-}
-
-static int modeset_pipe(struct drm_crtc *crtc,
-                       struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_atomic_state *state;
-       struct drm_crtc_state *crtc_state;
-       int ret;
-
-       state = drm_atomic_state_alloc(crtc->dev);
-       if (!state)
-               return -ENOMEM;
-
-       state->acquire_ctx = ctx;
-
-       crtc_state = drm_atomic_get_crtc_state(state, crtc);
-       if (IS_ERR(crtc_state)) {
-               ret = PTR_ERR(crtc_state);
-               goto out;
-       }
-
-       crtc_state->connectors_changed = true;
-
-       ret = drm_atomic_commit(state);
-out:
-       drm_atomic_state_put(state);
-
-       return ret;
-}
-
-static int intel_hdmi_reset_link(struct intel_encoder *encoder,
-                                struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
-       struct intel_connector *connector = hdmi->attached_connector;
-       struct i2c_adapter *adapter =
-               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
-       struct drm_connector_state *conn_state;
-       struct intel_crtc_state *crtc_state;
-       struct intel_crtc *crtc;
-       u8 config;
-       int ret;
-
-       if (!connector || connector->base.status != connector_status_connected)
-               return 0;
-
-       ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
-                              ctx);
-       if (ret)
-               return ret;
-
-       conn_state = connector->base.state;
-
-       crtc = to_intel_crtc(conn_state->crtc);
-       if (!crtc)
-               return 0;
-
-       ret = drm_modeset_lock(&crtc->base.mutex, ctx);
-       if (ret)
-               return ret;
-
-       crtc_state = to_intel_crtc_state(crtc->base.state);
-
-       WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
-
-       if (!crtc_state->base.active)
-               return 0;
-
-       if (!crtc_state->hdmi_high_tmds_clock_ratio &&
-           !crtc_state->hdmi_scrambling)
-               return 0;
-
-       if (conn_state->commit &&
-           !try_wait_for_completion(&conn_state->commit->hw_done))
-               return 0;
-
-       ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
-       if (ret < 0) {
-               DRM_ERROR("Failed to read TMDS config: %d\n", ret);
-               return 0;
-       }
-
-       if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
-           crtc_state->hdmi_high_tmds_clock_ratio &&
-           !!(config & SCDC_SCRAMBLING_ENABLE) ==
-           crtc_state->hdmi_scrambling)
-               return 0;
-
-       /*
-        * HDMI 2.0 says that one should not send scrambled data
-        * prior to configuring the sink scrambling, and that
-        * TMDS clock/data transmission should be suspended when
-        * changing the TMDS clock rate in the sink. So let's
-        * just do a full modeset here, even though some sinks
-        * would be perfectly happy if were to just reconfigure
-        * the SCDC settings on the fly.
-        */
-       return modeset_pipe(&crtc->base, ctx);
-}
-
-static bool intel_ddi_hotplug(struct intel_encoder *encoder,
-                             struct intel_connector *connector)
-{
-       struct drm_modeset_acquire_ctx ctx;
-       bool changed;
-       int ret;
-
-       changed = intel_encoder_hotplug(encoder, connector);
-
-       drm_modeset_acquire_init(&ctx, 0);
-
-       for (;;) {
-               if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
-                       ret = intel_hdmi_reset_link(encoder, &ctx);
-               else
-                       ret = intel_dp_retrain_link(encoder, &ctx);
-
-               if (ret == -EDEADLK) {
-                       drm_modeset_backoff(&ctx);
-                       continue;
-               }
-
-               break;
-       }
-
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-       WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
-
-       return changed;
-}
-
-static struct intel_connector *
-intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
-{
-       struct intel_connector *connector;
-       enum port port = intel_dig_port->base.port;
-
-       connector = intel_connector_alloc();
-       if (!connector)
-               return NULL;
-
-       intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
-       intel_hdmi_init_connector(intel_dig_port, connector);
-
-       return connector;
-}
-
-static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dport)
-{
-       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
-
-       if (dport->base.port != PORT_A)
-               return false;
-
-       if (dport->saved_port_bits & DDI_A_4_LANES)
-               return false;
-
-       /* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only
-        *                     supported configuration
-        */
-       if (IS_GEN9_LP(dev_priv))
-               return true;
-
-       /* Cannonlake: Most of SKUs don't support DDI_E, and the only
-        *             one who does also have a full A/E split called
-        *             DDI_F what makes DDI_E useless. However for this
-        *             case let's trust VBT info.
-        */
-       if (IS_CANNONLAKE(dev_priv) &&
-           !intel_bios_is_port_present(dev_priv, PORT_E))
-               return true;
-
-       return false;
-}
-
-static int
-intel_ddi_max_lanes(struct intel_digital_port *intel_dport)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_dport->base.base.dev);
-       enum port port = intel_dport->base.port;
-       int max_lanes = 4;
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               return max_lanes;
-
-       if (port == PORT_A || port == PORT_E) {
-               if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)
-                       max_lanes = port == PORT_A ? 4 : 0;
-               else
-                       /* Both A and E share 2 lanes */
-                       max_lanes = 2;
-       }
-
-       /*
-        * Some BIOS might fail to set this bit on port A if eDP
-        * wasn't lit up at boot.  Force this bit set when needed
-        * so we use the proper lane count for our calculations.
-        */
-       if (intel_ddi_a_force_4_lanes(intel_dport)) {
-               DRM_DEBUG_KMS("Forcing DDI_A_4_LANES for port A\n");
-               intel_dport->saved_port_bits |= DDI_A_4_LANES;
-               max_lanes = 4;
-       }
-
-       return max_lanes;
-}
-
-void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
-{
-       struct ddi_vbt_port_info *port_info =
-               &dev_priv->vbt.ddi_port_info[port];
-       struct intel_digital_port *intel_dig_port;
-       struct intel_encoder *intel_encoder;
-       struct drm_encoder *encoder;
-       bool init_hdmi, init_dp, init_lspcon = false;
-       enum pipe pipe;
-
-       init_hdmi = port_info->supports_dvi || port_info->supports_hdmi;
-       init_dp = port_info->supports_dp;
-
-       if (intel_bios_is_lspcon_present(dev_priv, port)) {
-               /*
-                * Lspcon device needs to be driven with DP connector
-                * with special detection sequence. So make sure DP
-                * is initialized before lspcon.
-                */
-               init_dp = true;
-               init_lspcon = true;
-               init_hdmi = false;
-               DRM_DEBUG_KMS("VBT says port %c has lspcon\n", port_name(port));
-       }
-
-       if (!init_dp && !init_hdmi) {
-               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, respect it\n",
-                             port_name(port));
-               return;
-       }
-
-       intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
-       if (!intel_dig_port)
-               return;
-
-       intel_encoder = &intel_dig_port->base;
-       encoder = &intel_encoder->base;
-
-       drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
-                        DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
-
-       intel_encoder->hotplug = intel_ddi_hotplug;
-       intel_encoder->compute_output_type = intel_ddi_compute_output_type;
-       intel_encoder->compute_config = intel_ddi_compute_config;
-       intel_encoder->enable = intel_enable_ddi;
-       intel_encoder->pre_pll_enable = intel_ddi_pre_pll_enable;
-       intel_encoder->post_pll_disable = intel_ddi_post_pll_disable;
-       intel_encoder->pre_enable = intel_ddi_pre_enable;
-       intel_encoder->disable = intel_disable_ddi;
-       intel_encoder->post_disable = intel_ddi_post_disable;
-       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->get_power_domains = intel_ddi_get_power_domains;
-       intel_encoder->type = INTEL_OUTPUT_DDI;
-       intel_encoder->power_domain = intel_port_to_power_domain(port);
-       intel_encoder->port = port;
-       intel_encoder->cloneable = 0;
-       for_each_pipe(dev_priv, pipe)
-               intel_encoder->crtc_mask |= BIT(pipe);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
-                       DDI_BUF_PORT_REVERSAL;
-       else
-               intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
-                       (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES);
-       intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
-       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;
-
-       switch (port) {
-       case PORT_A:
-               intel_dig_port->ddi_io_power_domain =
-                       POWER_DOMAIN_PORT_DDI_A_IO;
-               break;
-       case PORT_B:
-               intel_dig_port->ddi_io_power_domain =
-                       POWER_DOMAIN_PORT_DDI_B_IO;
-               break;
-       case PORT_C:
-               intel_dig_port->ddi_io_power_domain =
-                       POWER_DOMAIN_PORT_DDI_C_IO;
-               break;
-       case PORT_D:
-               intel_dig_port->ddi_io_power_domain =
-                       POWER_DOMAIN_PORT_DDI_D_IO;
-               break;
-       case PORT_E:
-               intel_dig_port->ddi_io_power_domain =
-                       POWER_DOMAIN_PORT_DDI_E_IO;
-               break;
-       case PORT_F:
-               intel_dig_port->ddi_io_power_domain =
-                       POWER_DOMAIN_PORT_DDI_F_IO;
-               break;
-       default:
-               MISSING_CASE(port);
-       }
-
-       if (init_dp) {
-               if (!intel_ddi_init_dp_connector(intel_dig_port))
-                       goto err;
-
-               intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
-       }
-
-       /* In theory we don't need the encoder->type check, but leave it just in
-        * case we have some really bad VBTs... */
-       if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
-               if (!intel_ddi_init_hdmi_connector(intel_dig_port))
-                       goto err;
-       }
-
-       if (init_lspcon) {
-               if (lspcon_init(intel_dig_port))
-                       /* TODO: handle hdmi info frame part */
-                       DRM_DEBUG_KMS("LSPCON init success on port %c\n",
-                               port_name(port));
-               else
-                       /*
-                        * LSPCON init faied, but DP init was success, so
-                        * lets try to drive as DP++ port.
-                        */
-                       DRM_ERROR("LSPCON init failed on port %c\n",
-                               port_name(port));
-       }
-
-       intel_infoframe_init(intel_dig_port);
-
-       if (intel_port_is_tc(dev_priv, port))
-               intel_digital_port_connected(intel_encoder);
-
-       return;
-
-err:
-       drm_encoder_cleanup(encoder);
-       kfree(intel_dig_port);
-}
diff --git a/drivers/gpu/drm/i915/intel_ddi.h b/drivers/gpu/drm/i915/intel_ddi.h
deleted file mode 100644 (file)
index a08365d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DDI_H__
-#define __INTEL_DDI_H__
-
-#include <drm/i915_drm.h>
-
-#include "intel_display.h"
-
-struct drm_connector_state;
-struct drm_i915_private;
-struct intel_connector;
-struct intel_crtc;
-struct intel_crtc_state;
-struct intel_dp;
-struct intel_dpll_hw_state;
-struct intel_encoder;
-
-void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
-                               const struct intel_crtc_state *old_crtc_state,
-                               const struct drm_connector_state *old_conn_state);
-void hsw_fdi_link_train(struct intel_crtc *crtc,
-                       const struct intel_crtc_state *crtc_state);
-void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port);
-bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe);
-void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state);
-void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state);
-void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state);
-void intel_ddi_disable_pipe_clock(const  struct intel_crtc_state *crtc_state);
-void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state);
-bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
-void intel_ddi_get_config(struct intel_encoder *encoder,
-                         struct intel_crtc_state *pipe_config);
-void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
-                                   bool state);
-void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
-                                        struct intel_crtc_state *crtc_state);
-u32 bxt_signal_levels(struct intel_dp *intel_dp);
-u32 ddi_signal_levels(struct intel_dp *intel_dp);
-u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder);
-u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder,
-                                u8 voltage_swing);
-int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
-                                    bool enable);
-void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
-int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
-                       struct intel_dpll_hw_state *state);
-
-#endif /* __INTEL_DDI_H__ */
index 0bf1e09acf22342089ba2f41852df8c05d69b4e4..65007709a08896bc8d2f86b1a2adfeb13fd703b0 100644 (file)
 #include <drm/drm_rect.h>
 #include <drm/i915_drm.h>
 
+#include "display/intel_crt.h"
+#include "display/intel_ddi.h"
+#include "display/intel_dp.h"
+#include "display/intel_dsi.h"
+#include "display/intel_dvo.h"
+#include "display/intel_gmbus.h"
+#include "display/intel_hdmi.h"
+#include "display/intel_lvds.h"
+#include "display/intel_sdvo.h"
+#include "display/intel_tv.h"
+#include "display/intel_vdsc.h"
+
 #include "i915_drv.h"
 #include "i915_trace.h"
 #include "intel_acpi.h"
 #include "intel_bw.h"
 #include "intel_color.h"
 #include "intel_cdclk.h"
-#include "intel_crt.h"
-#include "intel_ddi.h"
-#include "intel_dp.h"
 #include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_dvo.h"
 #include "intel_fbc.h"
 #include "intel_fbdev.h"
 #include "intel_fifo_underrun.h"
 #include "intel_frontbuffer.h"
-#include "intel_gmbus.h"
 #include "intel_hdcp.h"
-#include "intel_hdmi.h"
 #include "intel_hotplug.h"
-#include "intel_lvds.h"
 #include "intel_overlay.h"
 #include "intel_pipe_crc.h"
 #include "intel_pm.h"
 #include "intel_psr.h"
 #include "intel_quirks.h"
-#include "intel_sdvo.h"
 #include "intel_sideband.h"
 #include "intel_sprite.h"
-#include "intel_tv.h"
-#include "intel_vdsc.h"
 
 /* Primary plane formats for gen <= 3 */
 static const u32 i8xx_primary_formats[] = {
index c672c8080a938ddfd00588d9d1cd008693baaf0e..c93ad512014ce2cca2757e4c6e3c0735a135b7c4 100644 (file)
@@ -5,13 +5,14 @@
 
 #include <linux/vgaarb.h>
 
+#include "display/intel_crt.h"
+#include "display/intel_dp.h"
+
 #include "i915_drv.h"
 #include "i915_irq.h"
 #include "intel_cdclk.h"
 #include "intel_combo_phy.h"
-#include "intel_crt.h"
 #include "intel_csr.h"
-#include "intel_dp.h"
 #include "intel_dpio_phy.h"
 #include "intel_drv.h"
 #include "intel_hotplug.h"
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
deleted file mode 100644 (file)
index 4336df4..0000000
+++ /dev/null
@@ -1,7577 +0,0 @@
-/*
- * Copyright © 2008 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Keith Packard <keithp@keithp.com>
- *
- */
-
-#include <linux/export.h>
-#include <linux/i2c.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <asm/byteorder.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_dp_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_hdcp.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/i915_drm.h>
-
-#include "i915_debugfs.h"
-#include "i915_drv.h"
-#include "intel_atomic.h"
-#include "intel_audio.h"
-#include "intel_connector.h"
-#include "intel_ddi.h"
-#include "intel_dp.h"
-#include "intel_dp_link_training.h"
-#include "intel_dp_mst.h"
-#include "intel_dpio_phy.h"
-#include "intel_drv.h"
-#include "intel_fifo_underrun.h"
-#include "intel_hdcp.h"
-#include "intel_hdmi.h"
-#include "intel_hotplug.h"
-#include "intel_lspcon.h"
-#include "intel_lvds.h"
-#include "intel_panel.h"
-#include "intel_psr.h"
-#include "intel_sideband.h"
-#include "intel_vdsc.h"
-
-#define DP_DPRX_ESI_LEN 14
-
-/* DP DSC small joiner has 2 FIFOs each of 640 x 6 bytes */
-#define DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER     61440
-#define DP_DSC_MIN_SUPPORTED_BPC               8
-#define DP_DSC_MAX_SUPPORTED_BPC               10
-
-/* DP DSC throughput values used for slice count calculations KPixels/s */
-#define DP_DSC_PEAK_PIXEL_RATE                 2720000
-#define DP_DSC_MAX_ENC_THROUGHPUT_0            340000
-#define DP_DSC_MAX_ENC_THROUGHPUT_1            400000
-
-/* DP DSC FEC Overhead factor = (100 - 2.4)/100 */
-#define DP_DSC_FEC_OVERHEAD_FACTOR             976
-
-/* Compliance test status bits  */
-#define INTEL_DP_RESOLUTION_SHIFT_MASK 0
-#define INTEL_DP_RESOLUTION_PREFERRED  (1 << INTEL_DP_RESOLUTION_SHIFT_MASK)
-#define INTEL_DP_RESOLUTION_STANDARD   (2 << INTEL_DP_RESOLUTION_SHIFT_MASK)
-#define INTEL_DP_RESOLUTION_FAILSAFE   (3 << INTEL_DP_RESOLUTION_SHIFT_MASK)
-
-struct dp_link_dpll {
-       int clock;
-       struct dpll dpll;
-};
-
-static const struct dp_link_dpll g4x_dpll[] = {
-       { 162000,
-               { .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } },
-       { 270000,
-               { .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } }
-};
-
-static const struct dp_link_dpll pch_dpll[] = {
-       { 162000,
-               { .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } },
-       { 270000,
-               { .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } }
-};
-
-static const struct dp_link_dpll vlv_dpll[] = {
-       { 162000,
-               { .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } },
-       { 270000,
-               { .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } }
-};
-
-/*
- * CHV supports eDP 1.4 that have  more link rates.
- * Below only provides the fixed rate but exclude variable rate.
- */
-static const struct dp_link_dpll chv_dpll[] = {
-       /*
-        * CHV requires to program fractional division for m2.
-        * m2 is stored in fixed point format using formula below
-        * (m2_int << 22) | m2_fraction
-        */
-       { 162000,       /* m2_int = 32, m2_fraction = 1677722 */
-               { .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } },
-       { 270000,       /* m2_int = 27, m2_fraction = 0 */
-               { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } },
-};
-
-/* Constants for DP DSC configurations */
-static const u8 valid_dsc_bpp[] = {6, 8, 10, 12, 15};
-
-/* With Single pipe configuration, HW is capable of supporting maximum
- * of 4 slices per line.
- */
-static const u8 valid_dsc_slicecount[] = {1, 2, 4};
-
-/**
- * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU or PCH)
- * @intel_dp: DP struct
- *
- * If a CPU or PCH DP output is attached to an eDP panel, this function
- * will return true, and false otherwise.
- */
-bool intel_dp_is_edp(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-
-       return intel_dig_port->base.type == INTEL_OUTPUT_EDP;
-}
-
-static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
-{
-       return enc_to_intel_dp(&intel_attached_encoder(connector)->base);
-}
-
-static void intel_dp_link_down(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *old_crtc_state);
-static bool edp_panel_vdd_on(struct intel_dp *intel_dp);
-static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
-static void vlv_init_panel_power_sequencer(struct intel_encoder *encoder,
-                                          const struct intel_crtc_state *crtc_state);
-static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe);
-static void intel_dp_unset_edid(struct intel_dp *intel_dp);
-
-/* update sink rates from dpcd */
-static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
-{
-       static const int dp_rates[] = {
-               162000, 270000, 540000, 810000
-       };
-       int i, max_rate;
-
-       max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
-
-       for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
-               if (dp_rates[i] > max_rate)
-                       break;
-               intel_dp->sink_rates[i] = dp_rates[i];
-       }
-
-       intel_dp->num_sink_rates = i;
-}
-
-/* Get length of rates array potentially limited by max_rate. */
-static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate)
-{
-       int i;
-
-       /* Limit results by potentially reduced max rate */
-       for (i = 0; i < len; i++) {
-               if (rates[len - i - 1] <= max_rate)
-                       return len - i;
-       }
-
-       return 0;
-}
-
-/* Get length of common rates array potentially limited by max_rate. */
-static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
-                                         int max_rate)
-{
-       return intel_dp_rate_limit_len(intel_dp->common_rates,
-                                      intel_dp->num_common_rates, max_rate);
-}
-
-/* Theoretical max between source and sink */
-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);
-
-       return min3(source_max, sink_max, fia_max);
-}
-
-int intel_dp_max_lane_count(struct intel_dp *intel_dp)
-{
-       return intel_dp->max_link_lane_count;
-}
-
-int
-intel_dp_link_required(int pixel_clock, int bpp)
-{
-       /* pixel_clock is in kHz, divide bpp by 8 for bit to Byte conversion */
-       return DIV_ROUND_UP(pixel_clock * bpp, 8);
-}
-
-int
-intel_dp_max_data_rate(int max_link_clock, int max_lanes)
-{
-       /* max_link_clock is the link symbol clock (LS_Clk) in kHz and not the
-        * link rate that is generally expressed in Gbps. Since, 8 bits of data
-        * is transmitted every LS_Clk per lane, there is no need to account for
-        * the channel encoding that is done in the PHY layer here.
-        */
-
-       return max_link_clock * max_lanes;
-}
-
-static int
-intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *encoder = &intel_dig_port->base;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       int max_dotclk = dev_priv->max_dotclk_freq;
-       int ds_max_dotclk;
-
-       int type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
-
-       if (type != DP_DS_PORT_TYPE_VGA)
-               return max_dotclk;
-
-       ds_max_dotclk = drm_dp_downstream_max_clock(intel_dp->dpcd,
-                                                   intel_dp->downstream_ports);
-
-       if (ds_max_dotclk != 0)
-               max_dotclk = min(max_dotclk, ds_max_dotclk);
-
-       return max_dotclk;
-}
-
-static int cnl_max_source_rate(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 port port = dig_port->base.port;
-
-       u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
-
-       /* Low voltage SKUs are limited to max of 5.4G */
-       if (voltage == VOLTAGE_INFO_0_85V)
-               return 540000;
-
-       /* For this SKU 8.1G is supported in all ports */
-       if (IS_CNL_WITH_PORT_F(dev_priv))
-               return 810000;
-
-       /* For other SKUs, max rate on ports A and D is 5.4G */
-       if (port == PORT_A || port == PORT_D)
-               return 540000;
-
-       return 810000;
-}
-
-static int icl_max_source_rate(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 port port = dig_port->base.port;
-
-       if (intel_port_is_combophy(dev_priv, port) &&
-           !IS_ELKHARTLAKE(dev_priv) &&
-           !intel_dp_is_edp(intel_dp))
-               return 540000;
-
-       return 810000;
-}
-
-static void
-intel_dp_set_source_rates(struct intel_dp *intel_dp)
-{
-       /* The values must be in increasing order */
-       static const int cnl_rates[] = {
-               162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000
-       };
-       static const int bxt_rates[] = {
-               162000, 216000, 243000, 270000, 324000, 432000, 540000
-       };
-       static const int skl_rates[] = {
-               162000, 216000, 270000, 324000, 432000, 540000
-       };
-       static const int hsw_rates[] = {
-               162000, 270000, 540000
-       };
-       static const int g4x_rates[] = {
-               162000, 270000
-       };
-       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);
-       const struct ddi_vbt_port_info *info =
-               &dev_priv->vbt.ddi_port_info[dig_port->base.port];
-       const int *source_rates;
-       int size, max_rate = 0, vbt_max_rate = info->dp_max_link_rate;
-
-       /* This should only be done once */
-       WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates);
-
-       if (INTEL_GEN(dev_priv) >= 10) {
-               source_rates = cnl_rates;
-               size = ARRAY_SIZE(cnl_rates);
-               if (IS_GEN(dev_priv, 10))
-                       max_rate = cnl_max_source_rate(intel_dp);
-               else
-                       max_rate = icl_max_source_rate(intel_dp);
-       } else if (IS_GEN9_LP(dev_priv)) {
-               source_rates = bxt_rates;
-               size = ARRAY_SIZE(bxt_rates);
-       } else if (IS_GEN9_BC(dev_priv)) {
-               source_rates = skl_rates;
-               size = ARRAY_SIZE(skl_rates);
-       } else if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
-                  IS_BROADWELL(dev_priv)) {
-               source_rates = hsw_rates;
-               size = ARRAY_SIZE(hsw_rates);
-       } else {
-               source_rates = g4x_rates;
-               size = ARRAY_SIZE(g4x_rates);
-       }
-
-       if (max_rate && vbt_max_rate)
-               max_rate = min(max_rate, vbt_max_rate);
-       else if (vbt_max_rate)
-               max_rate = vbt_max_rate;
-
-       if (max_rate)
-               size = intel_dp_rate_limit_len(source_rates, size, max_rate);
-
-       intel_dp->source_rates = source_rates;
-       intel_dp->num_source_rates = size;
-}
-
-static int intersect_rates(const int *source_rates, int source_len,
-                          const int *sink_rates, int sink_len,
-                          int *common_rates)
-{
-       int i = 0, j = 0, k = 0;
-
-       while (i < source_len && j < sink_len) {
-               if (source_rates[i] == sink_rates[j]) {
-                       if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-                               return k;
-                       common_rates[k] = source_rates[i];
-                       ++k;
-                       ++i;
-                       ++j;
-               } else if (source_rates[i] < sink_rates[j]) {
-                       ++i;
-               } else {
-                       ++j;
-               }
-       }
-       return k;
-}
-
-/* return index of rate in rates array, or -1 if not found */
-static int intel_dp_rate_index(const int *rates, int len, int rate)
-{
-       int i;
-
-       for (i = 0; i < len; i++)
-               if (rate == rates[i])
-                       return i;
-
-       return -1;
-}
-
-static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
-{
-       WARN_ON(!intel_dp->num_source_rates || !intel_dp->num_sink_rates);
-
-       intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates,
-                                                    intel_dp->num_source_rates,
-                                                    intel_dp->sink_rates,
-                                                    intel_dp->num_sink_rates,
-                                                    intel_dp->common_rates);
-
-       /* Paranoia, there should always be something in common. */
-       if (WARN_ON(intel_dp->num_common_rates == 0)) {
-               intel_dp->common_rates[0] = 162000;
-               intel_dp->num_common_rates = 1;
-       }
-}
-
-static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
-                                      u8 lane_count)
-{
-       /*
-        * FIXME: we need to synchronize the current link parameters with
-        * hardware readout. Currently fast link training doesn't work on
-        * boot-up.
-        */
-       if (link_rate == 0 ||
-           link_rate > intel_dp->max_link_rate)
-               return false;
-
-       if (lane_count == 0 ||
-           lane_count > intel_dp_max_lane_count(intel_dp))
-               return false;
-
-       return true;
-}
-
-static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
-                                                    int link_rate,
-                                                    u8 lane_count)
-{
-       const struct drm_display_mode *fixed_mode =
-               intel_dp->attached_connector->panel.fixed_mode;
-       int mode_rate, max_rate;
-
-       mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
-       max_rate = intel_dp_max_data_rate(link_rate, lane_count);
-       if (mode_rate > max_rate)
-               return false;
-
-       return true;
-}
-
-int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
-                                           int link_rate, u8 lane_count)
-{
-       int index;
-
-       index = intel_dp_rate_index(intel_dp->common_rates,
-                                   intel_dp->num_common_rates,
-                                   link_rate);
-       if (index > 0) {
-               if (intel_dp_is_edp(intel_dp) &&
-                   !intel_dp_can_link_train_fallback_for_edp(intel_dp,
-                                                             intel_dp->common_rates[index - 1],
-                                                             lane_count)) {
-                       DRM_DEBUG_KMS("Retrying Link training for eDP with same parameters\n");
-                       return 0;
-               }
-               intel_dp->max_link_rate = intel_dp->common_rates[index - 1];
-               intel_dp->max_link_lane_count = lane_count;
-       } else if (lane_count > 1) {
-               if (intel_dp_is_edp(intel_dp) &&
-                   !intel_dp_can_link_train_fallback_for_edp(intel_dp,
-                                                             intel_dp_max_common_rate(intel_dp),
-                                                             lane_count >> 1)) {
-                       DRM_DEBUG_KMS("Retrying Link training for eDP with same parameters\n");
-                       return 0;
-               }
-               intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
-               intel_dp->max_link_lane_count = lane_count >> 1;
-       } else {
-               DRM_ERROR("Link Training Unsuccessful\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-static enum drm_mode_status
-intel_dp_mode_valid(struct drm_connector *connector,
-                   struct drm_display_mode *mode)
-{
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       int target_clock = mode->clock;
-       int max_rate, mode_rate, max_lanes, max_link_clock;
-       int max_dotclk;
-       u16 dsc_max_output_bpp = 0;
-       u8 dsc_slice_count = 0;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
-
-       if (intel_dp_is_edp(intel_dp) && fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-
-               target_clock = fixed_mode->clock;
-       }
-
-       max_link_clock = intel_dp_max_link_rate(intel_dp);
-       max_lanes = intel_dp_max_lane_count(intel_dp);
-
-       max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
-       mode_rate = intel_dp_link_required(target_clock, 18);
-
-       /*
-        * Output bpp is stored in 6.4 format so right shift by 4 to get the
-        * integer value since we support only integer values of bpp.
-        */
-       if ((INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) &&
-           drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) {
-               if (intel_dp_is_edp(intel_dp)) {
-                       dsc_max_output_bpp =
-                               drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4;
-                       dsc_slice_count =
-                               drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
-                                                               true);
-               } else if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) {
-                       dsc_max_output_bpp =
-                               intel_dp_dsc_get_output_bpp(max_link_clock,
-                                                           max_lanes,
-                                                           target_clock,
-                                                           mode->hdisplay) >> 4;
-                       dsc_slice_count =
-                               intel_dp_dsc_get_slice_count(intel_dp,
-                                                            target_clock,
-                                                            mode->hdisplay);
-               }
-       }
-
-       if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) ||
-           target_clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       if (mode->clock < 10000)
-               return MODE_CLOCK_LOW;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
-               return MODE_H_ILLEGAL;
-
-       return MODE_OK;
-}
-
-u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
-{
-       int i;
-       u32 v = 0;
-
-       if (src_bytes > 4)
-               src_bytes = 4;
-       for (i = 0; i < src_bytes; i++)
-               v |= ((u32)src[i]) << ((3 - i) * 8);
-       return v;
-}
-
-static void intel_dp_unpack_aux(u32 src, u8 *dst, int dst_bytes)
-{
-       int i;
-       if (dst_bytes > 4)
-               dst_bytes = 4;
-       for (i = 0; i < dst_bytes; i++)
-               dst[i] = src >> ((3-i) * 8);
-}
-
-static void
-intel_dp_init_panel_power_sequencer(struct intel_dp *intel_dp);
-static void
-intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
-                                             bool force_disable_vdd);
-static void
-intel_dp_pps_init(struct intel_dp *intel_dp);
-
-static intel_wakeref_t
-pps_lock(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       intel_wakeref_t wakeref;
-
-       /*
-        * See intel_power_sequencer_reset() why we need
-        * a power domain reference here.
-        */
-       wakeref = intel_display_power_get(dev_priv,
-                                         intel_aux_power_domain(dp_to_dig_port(intel_dp)));
-
-       mutex_lock(&dev_priv->pps_mutex);
-
-       return wakeref;
-}
-
-static intel_wakeref_t
-pps_unlock(struct intel_dp *intel_dp, intel_wakeref_t wakeref)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       mutex_unlock(&dev_priv->pps_mutex);
-       intel_display_power_put(dev_priv,
-                               intel_aux_power_domain(dp_to_dig_port(intel_dp)),
-                               wakeref);
-       return 0;
-}
-
-#define with_pps_lock(dp, wf) \
-       for ((wf) = pps_lock(dp); (wf); (wf) = pps_unlock((dp), (wf)))
-
-static void
-vlv_power_sequencer_kick(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum pipe pipe = intel_dp->pps_pipe;
-       bool pll_enabled, release_cl_override = false;
-       enum dpio_phy phy = DPIO_PHY(pipe);
-       enum dpio_channel ch = vlv_pipe_to_channel(pipe);
-       u32 DP;
-
-       if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
-                "skipping pipe %c power sequencer kick due to port %c being active\n",
-                pipe_name(pipe), port_name(intel_dig_port->base.port)))
-               return;
-
-       DRM_DEBUG_KMS("kicking pipe %c power sequencer for port %c\n",
-                     pipe_name(pipe), port_name(intel_dig_port->base.port));
-
-       /* Preserve the BIOS-computed detected bit. This is
-        * supposed to be read-only.
-        */
-       DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
-       DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
-       DP |= DP_PORT_WIDTH(1);
-       DP |= DP_LINK_TRAIN_PAT_1;
-
-       if (IS_CHERRYVIEW(dev_priv))
-               DP |= DP_PIPE_SEL_CHV(pipe);
-       else
-               DP |= DP_PIPE_SEL(pipe);
-
-       pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE;
-
-       /*
-        * The DPLL for the pipe must be enabled for this to work.
-        * So enable temporarily it if it's not already enabled.
-        */
-       if (!pll_enabled) {
-               release_cl_override = IS_CHERRYVIEW(dev_priv) &&
-                       !chv_phy_powergate_ch(dev_priv, phy, ch, true);
-
-               if (vlv_force_pll_on(dev_priv, pipe, IS_CHERRYVIEW(dev_priv) ?
-                                    &chv_dpll[0].dpll : &vlv_dpll[0].dpll)) {
-                       DRM_ERROR("Failed to force on pll for pipe %c!\n",
-                                 pipe_name(pipe));
-                       return;
-               }
-       }
-
-       /*
-        * Similar magic as in intel_dp_enable_port().
-        * We _must_ do this port enable + disable trick
-        * to make this power sequencer lock onto the port.
-        * Otherwise even VDD force bit won't work.
-        */
-       I915_WRITE(intel_dp->output_reg, DP);
-       POSTING_READ(intel_dp->output_reg);
-
-       I915_WRITE(intel_dp->output_reg, DP | DP_PORT_EN);
-       POSTING_READ(intel_dp->output_reg);
-
-       I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
-       POSTING_READ(intel_dp->output_reg);
-
-       if (!pll_enabled) {
-               vlv_force_pll_off(dev_priv, pipe);
-
-               if (release_cl_override)
-                       chv_phy_powergate_ch(dev_priv, phy, ch, false);
-       }
-}
-
-static enum pipe vlv_find_free_pps(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder;
-       unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
-
-       /*
-        * We don't have power sequencer currently.
-        * Pick one that's not used by other ports.
-        */
-       for_each_intel_dp(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-               if (encoder->type == INTEL_OUTPUT_EDP) {
-                       WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
-                               intel_dp->active_pipe != intel_dp->pps_pipe);
-
-                       if (intel_dp->pps_pipe != INVALID_PIPE)
-                               pipes &= ~(1 << intel_dp->pps_pipe);
-               } else {
-                       WARN_ON(intel_dp->pps_pipe != INVALID_PIPE);
-
-                       if (intel_dp->active_pipe != INVALID_PIPE)
-                               pipes &= ~(1 << intel_dp->active_pipe);
-               }
-       }
-
-       if (pipes == 0)
-               return INVALID_PIPE;
-
-       return ffs(pipes) - 1;
-}
-
-static enum pipe
-vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum pipe pipe;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       /* We should never land here with regular DP ports */
-       WARN_ON(!intel_dp_is_edp(intel_dp));
-
-       WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
-               intel_dp->active_pipe != intel_dp->pps_pipe);
-
-       if (intel_dp->pps_pipe != INVALID_PIPE)
-               return intel_dp->pps_pipe;
-
-       pipe = vlv_find_free_pps(dev_priv);
-
-       /*
-        * Didn't find one. This should not happen since there
-        * are two power sequencers and up to two eDP ports.
-        */
-       if (WARN_ON(pipe == INVALID_PIPE))
-               pipe = PIPE_A;
-
-       vlv_steal_power_sequencer(dev_priv, pipe);
-       intel_dp->pps_pipe = pipe;
-
-       DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n",
-                     pipe_name(intel_dp->pps_pipe),
-                     port_name(intel_dig_port->base.port));
-
-       /* init power sequencer on this pipe and port */
-       intel_dp_init_panel_power_sequencer(intel_dp);
-       intel_dp_init_panel_power_sequencer_registers(intel_dp, true);
-
-       /*
-        * Even vdd force doesn't work until we've made
-        * the power sequencer lock in on the port.
-        */
-       vlv_power_sequencer_kick(intel_dp);
-
-       return intel_dp->pps_pipe;
-}
-
-static int
-bxt_power_sequencer_idx(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       int backlight_controller = dev_priv->vbt.backlight.controller;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       /* We should never land here with regular DP ports */
-       WARN_ON(!intel_dp_is_edp(intel_dp));
-
-       if (!intel_dp->pps_reset)
-               return backlight_controller;
-
-       intel_dp->pps_reset = false;
-
-       /*
-        * Only the HW needs to be reprogrammed, the SW state is fixed and
-        * has been setup during connector init.
-        */
-       intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
-
-       return backlight_controller;
-}
-
-typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
-                              enum pipe pipe);
-
-static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
-                              enum pipe pipe)
-{
-       return I915_READ(PP_STATUS(pipe)) & PP_ON;
-}
-
-static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
-                               enum pipe pipe)
-{
-       return I915_READ(PP_CONTROL(pipe)) & EDP_FORCE_VDD;
-}
-
-static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
-                        enum pipe pipe)
-{
-       return true;
-}
-
-static enum pipe
-vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
-                    enum port port,
-                    vlv_pipe_check pipe_check)
-{
-       enum pipe pipe;
-
-       for (pipe = PIPE_A; pipe <= PIPE_B; pipe++) {
-               u32 port_sel = I915_READ(PP_ON_DELAYS(pipe)) &
-                       PANEL_PORT_SELECT_MASK;
-
-               if (port_sel != PANEL_PORT_SELECT_VLV(port))
-                       continue;
-
-               if (!pipe_check(dev_priv, pipe))
-                       continue;
-
-               return pipe;
-       }
-
-       return INVALID_PIPE;
-}
-
-static void
-vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum port port = intel_dig_port->base.port;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       /* try to find a pipe with this port selected */
-       /* first pick one where the panel is on */
-       intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
-                                                 vlv_pipe_has_pp_on);
-       /* didn't find one? pick one where vdd is on */
-       if (intel_dp->pps_pipe == INVALID_PIPE)
-               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
-                                                         vlv_pipe_has_vdd_on);
-       /* didn't find one? pick one with just the correct port */
-       if (intel_dp->pps_pipe == INVALID_PIPE)
-               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
-                                                         vlv_pipe_any);
-
-       /* didn't find one? just let vlv_power_sequencer_pipe() pick one when needed */
-       if (intel_dp->pps_pipe == INVALID_PIPE) {
-               DRM_DEBUG_KMS("no initial power sequencer for port %c\n",
-                             port_name(port));
-               return;
-       }
-
-       DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n",
-                     port_name(port), pipe_name(intel_dp->pps_pipe));
-
-       intel_dp_init_panel_power_sequencer(intel_dp);
-       intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
-}
-
-void intel_power_sequencer_reset(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder;
-
-       if (WARN_ON(!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
-                   !IS_GEN9_LP(dev_priv)))
-               return;
-
-       /*
-        * We can't grab pps_mutex here due to deadlock with power_domain
-        * mutex when power_domain functions are called while holding pps_mutex.
-        * That also means that in order to use pps_pipe the code needs to
-        * hold both a power domain reference and pps_mutex, and the power domain
-        * reference get/put must be done while _not_ holding pps_mutex.
-        * pps_{lock,unlock}() do these steps in the correct order, so one
-        * should use them always.
-        */
-
-       for_each_intel_dp(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-               WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
-
-               if (encoder->type != INTEL_OUTPUT_EDP)
-                       continue;
-
-               if (IS_GEN9_LP(dev_priv))
-                       intel_dp->pps_reset = true;
-               else
-                       intel_dp->pps_pipe = INVALID_PIPE;
-       }
-}
-
-struct pps_registers {
-       i915_reg_t pp_ctrl;
-       i915_reg_t pp_stat;
-       i915_reg_t pp_on;
-       i915_reg_t pp_off;
-       i915_reg_t pp_div;
-};
-
-static void intel_pps_get_registers(struct intel_dp *intel_dp,
-                                   struct pps_registers *regs)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       int pps_idx = 0;
-
-       memset(regs, 0, sizeof(*regs));
-
-       if (IS_GEN9_LP(dev_priv))
-               pps_idx = bxt_power_sequencer_idx(intel_dp);
-       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               pps_idx = vlv_power_sequencer_pipe(intel_dp);
-
-       regs->pp_ctrl = PP_CONTROL(pps_idx);
-       regs->pp_stat = PP_STATUS(pps_idx);
-       regs->pp_on = PP_ON_DELAYS(pps_idx);
-       regs->pp_off = PP_OFF_DELAYS(pps_idx);
-
-       /* Cycle delay moved from PP_DIVISOR to PP_CONTROL */
-       if (IS_GEN9_LP(dev_priv) || INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
-               regs->pp_div = INVALID_MMIO_REG;
-       else
-               regs->pp_div = PP_DIVISOR(pps_idx);
-}
-
-static i915_reg_t
-_pp_ctrl_reg(struct intel_dp *intel_dp)
-{
-       struct pps_registers regs;
-
-       intel_pps_get_registers(intel_dp, &regs);
-
-       return regs.pp_ctrl;
-}
-
-static i915_reg_t
-_pp_stat_reg(struct intel_dp *intel_dp)
-{
-       struct pps_registers regs;
-
-       intel_pps_get_registers(intel_dp, &regs);
-
-       return regs.pp_stat;
-}
-
-/* Reboot notifier handler to shutdown panel power to guarantee T12 timing
-   This function only applicable when panel PM state is not to be tracked */
-static int edp_notify_handler(struct notifier_block *this, unsigned long code,
-                             void *unused)
-{
-       struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp),
-                                                edp_notifier);
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       intel_wakeref_t wakeref;
-
-       if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART)
-               return 0;
-
-       with_pps_lock(intel_dp, wakeref) {
-               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-                       enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
-                       i915_reg_t pp_ctrl_reg, pp_div_reg;
-                       u32 pp_div;
-
-                       pp_ctrl_reg = PP_CONTROL(pipe);
-                       pp_div_reg  = PP_DIVISOR(pipe);
-                       pp_div = I915_READ(pp_div_reg);
-                       pp_div &= PP_REFERENCE_DIVIDER_MASK;
-
-                       /* 0x1F write to PP_DIV_REG sets max cycle delay */
-                       I915_WRITE(pp_div_reg, pp_div | 0x1F);
-                       I915_WRITE(pp_ctrl_reg, PANEL_UNLOCK_REGS);
-                       msleep(intel_dp->panel_power_cycle_delay);
-               }
-       }
-
-       return 0;
-}
-
-static bool edp_have_panel_power(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-           intel_dp->pps_pipe == INVALID_PIPE)
-               return false;
-
-       return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
-}
-
-static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-           intel_dp->pps_pipe == INVALID_PIPE)
-               return false;
-
-       return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD;
-}
-
-static void
-intel_dp_check_edp(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) {
-               WARN(1, "eDP powered off while attempting aux channel communication.\n");
-               DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
-                             I915_READ(_pp_stat_reg(intel_dp)),
-                             I915_READ(_pp_ctrl_reg(intel_dp)));
-       }
-}
-
-static u32
-intel_dp_aux_wait_done(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
-       i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
-       u32 status;
-       bool done;
-
-#define C (((status = intel_uncore_read_notrace(&i915->uncore, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
-       done = wait_event_timeout(i915->gmbus_wait_queue, C,
-                                 msecs_to_jiffies_timeout(10));
-
-       /* just trace the final value */
-       trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
-
-       if (!done)
-               DRM_ERROR("dp aux hw did not signal timeout!\n");
-#undef C
-
-       return status;
-}
-
-static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (index)
-               return 0;
-
-       /*
-        * The clock divider is based off the hrawclk, and would like to run at
-        * 2MHz.  So, take the hrawclk value and divide by 2000 and use that
-        */
-       return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
-}
-
-static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-
-       if (index)
-               return 0;
-
-       /*
-        * The clock divider is based off the cdclk or PCH rawclk, and would
-        * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
-        * divide by 2000 and use that
-        */
-       if (dig_port->aux_ch == AUX_CH_A)
-               return DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.cdclk, 2000);
-       else
-               return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
-}
-
-static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-
-       if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
-               /* Workaround for non-ULT HSW */
-               switch (index) {
-               case 0: return 63;
-               case 1: return 72;
-               default: return 0;
-               }
-       }
-
-       return ilk_get_aux_clock_divider(intel_dp, index);
-}
-
-static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
-{
-       /*
-        * SKL doesn't need us to program the AUX clock divider (Hardware will
-        * derive the clock from CDCLK automatically). We still implement the
-        * get_aux_clock_divider vfunc to plug-in into the existing code.
-        */
-       return index ? 0 : 1;
-}
-
-static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
-                               int send_bytes,
-                               u32 aux_clock_divider)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv =
-                       to_i915(intel_dig_port->base.base.dev);
-       u32 precharge, timeout;
-
-       if (IS_GEN(dev_priv, 6))
-               precharge = 3;
-       else
-               precharge = 5;
-
-       if (IS_BROADWELL(dev_priv))
-               timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
-       else
-               timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
-
-       return DP_AUX_CH_CTL_SEND_BUSY |
-              DP_AUX_CH_CTL_DONE |
-              DP_AUX_CH_CTL_INTERRUPT |
-              DP_AUX_CH_CTL_TIME_OUT_ERROR |
-              timeout |
-              DP_AUX_CH_CTL_RECEIVE_ERROR |
-              (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
-              (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
-              (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
-}
-
-static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
-                               int send_bytes,
-                               u32 unused)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       u32 ret;
-
-       ret = DP_AUX_CH_CTL_SEND_BUSY |
-             DP_AUX_CH_CTL_DONE |
-             DP_AUX_CH_CTL_INTERRUPT |
-             DP_AUX_CH_CTL_TIME_OUT_ERROR |
-             DP_AUX_CH_CTL_TIME_OUT_MAX |
-             DP_AUX_CH_CTL_RECEIVE_ERROR |
-             (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
-             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)
-               ret |= DP_AUX_CH_CTL_TBT_IO;
-
-       return ret;
-}
-
-static int
-intel_dp_aux_xfer(struct intel_dp *intel_dp,
-                 const u8 *send, int send_bytes,
-                 u8 *recv, int recv_size,
-                 u32 aux_send_ctl_flags)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *i915 =
-                       to_i915(intel_dig_port->base.base.dev);
-       struct intel_uncore *uncore = &i915->uncore;
-       i915_reg_t ch_ctl, ch_data[5];
-       u32 aux_clock_divider;
-       enum intel_display_power_domain aux_domain =
-               intel_aux_power_domain(intel_dig_port);
-       intel_wakeref_t aux_wakeref;
-       intel_wakeref_t pps_wakeref;
-       int i, ret, recv_bytes;
-       int try, clock = 0;
-       u32 status;
-       bool vdd;
-
-       ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
-       for (i = 0; i < ARRAY_SIZE(ch_data); i++)
-               ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
-
-       aux_wakeref = intel_display_power_get(i915, aux_domain);
-       pps_wakeref = pps_lock(intel_dp);
-
-       /*
-        * We will be called with VDD already enabled for dpcd/edid/oui reads.
-        * In such cases we want to leave VDD enabled and it's up to upper layers
-        * to turn it off. But for eg. i2c-dev access we need to turn it on/off
-        * ourselves.
-        */
-       vdd = edp_panel_vdd_on(intel_dp);
-
-       /* dp aux is extremely sensitive to irq latency, hence request the
-        * lowest possible wakeup latency and so prevent the cpu from going into
-        * deep sleep states.
-        */
-       pm_qos_update_request(&i915->pm_qos, 0);
-
-       intel_dp_check_edp(intel_dp);
-
-       /* Try to wait for any previous AUX channel activity */
-       for (try = 0; try < 3; try++) {
-               status = intel_uncore_read_notrace(uncore, ch_ctl);
-               if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
-                       break;
-               msleep(1);
-       }
-       /* just trace the final value */
-       trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
-
-       if (try == 3) {
-               static u32 last_status = -1;
-               const u32 status = intel_uncore_read(uncore, ch_ctl);
-
-               if (status != last_status) {
-                       WARN(1, "dp_aux_ch not started status 0x%08x\n",
-                            status);
-                       last_status = status;
-               }
-
-               ret = -EBUSY;
-               goto out;
-       }
-
-       /* Only 5 data registers! */
-       if (WARN_ON(send_bytes > 20 || recv_size > 20)) {
-               ret = -E2BIG;
-               goto out;
-       }
-
-       while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
-               u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
-                                                         send_bytes,
-                                                         aux_clock_divider);
-
-               send_ctl |= aux_send_ctl_flags;
-
-               /* Must try at least 3 times according to DP spec */
-               for (try = 0; try < 5; try++) {
-                       /* Load the send data into the aux channel data registers */
-                       for (i = 0; i < send_bytes; i += 4)
-                               intel_uncore_write(uncore,
-                                                  ch_data[i >> 2],
-                                                  intel_dp_pack_aux(send + i,
-                                                                    send_bytes - i));
-
-                       /* Send the command and wait for it to complete */
-                       intel_uncore_write(uncore, ch_ctl, send_ctl);
-
-                       status = intel_dp_aux_wait_done(intel_dp);
-
-                       /* Clear done status and any errors */
-                       intel_uncore_write(uncore,
-                                          ch_ctl,
-                                          status |
-                                          DP_AUX_CH_CTL_DONE |
-                                          DP_AUX_CH_CTL_TIME_OUT_ERROR |
-                                          DP_AUX_CH_CTL_RECEIVE_ERROR);
-
-                       /* DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
-                        *   400us delay required for errors and timeouts
-                        *   Timeout errors from the HW already meet this
-                        *   requirement so skip to next iteration
-                        */
-                       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
-                               continue;
-
-                       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
-                               usleep_range(400, 500);
-                               continue;
-                       }
-                       if (status & DP_AUX_CH_CTL_DONE)
-                               goto done;
-               }
-       }
-
-       if ((status & DP_AUX_CH_CTL_DONE) == 0) {
-               DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
-               ret = -EBUSY;
-               goto out;
-       }
-
-done:
-       /* Check for timeout or receive error.
-        * Timeouts occur when the sink is not connected
-        */
-       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
-               DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
-               ret = -EIO;
-               goto out;
-       }
-
-       /* Timeouts occur when the device isn't connected, so they're
-        * "normal" -- don't fill the kernel log with these */
-       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
-               DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status);
-               ret = -ETIMEDOUT;
-               goto out;
-       }
-
-       /* Unload any bytes sent back from the other side */
-       recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
-                     DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
-
-       /*
-        * By BSpec: "Message sizes of 0 or >20 are not allowed."
-        * We have no idea of what happened so we return -EBUSY so
-        * drm layer takes care for the necessary retries.
-        */
-       if (recv_bytes == 0 || recv_bytes > 20) {
-               DRM_DEBUG_KMS("Forbidden recv_bytes = %d on aux transaction\n",
-                             recv_bytes);
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (recv_bytes > recv_size)
-               recv_bytes = recv_size;
-
-       for (i = 0; i < recv_bytes; i += 4)
-               intel_dp_unpack_aux(intel_uncore_read(uncore, ch_data[i >> 2]),
-                                   recv + i, recv_bytes - i);
-
-       ret = recv_bytes;
-out:
-       pm_qos_update_request(&i915->pm_qos, PM_QOS_DEFAULT_VALUE);
-
-       if (vdd)
-               edp_panel_vdd_off(intel_dp, false);
-
-       pps_unlock(intel_dp, pps_wakeref);
-       intel_display_power_put_async(i915, aux_domain, aux_wakeref);
-
-       return ret;
-}
-
-#define BARE_ADDRESS_SIZE      3
-#define HEADER_SIZE            (BARE_ADDRESS_SIZE + 1)
-
-static void
-intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
-                   const struct drm_dp_aux_msg *msg)
-{
-       txbuf[0] = (msg->request << 4) | ((msg->address >> 16) & 0xf);
-       txbuf[1] = (msg->address >> 8) & 0xff;
-       txbuf[2] = msg->address & 0xff;
-       txbuf[3] = msg->size - 1;
-}
-
-static ssize_t
-intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
-{
-       struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
-       u8 txbuf[20], rxbuf[20];
-       size_t txsize, rxsize;
-       int ret;
-
-       intel_dp_aux_header(txbuf, msg);
-
-       switch (msg->request & ~DP_AUX_I2C_MOT) {
-       case DP_AUX_NATIVE_WRITE:
-       case DP_AUX_I2C_WRITE:
-       case DP_AUX_I2C_WRITE_STATUS_UPDATE:
-               txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
-               rxsize = 2; /* 0 or 1 data bytes */
-
-               if (WARN_ON(txsize > 20))
-                       return -E2BIG;
-
-               WARN_ON(!msg->buffer != !msg->size);
-
-               if (msg->buffer)
-                       memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
-
-               ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
-                                       rxbuf, rxsize, 0);
-               if (ret > 0) {
-                       msg->reply = rxbuf[0] >> 4;
-
-                       if (ret > 1) {
-                               /* Number of bytes written in a short write. */
-                               ret = clamp_t(int, rxbuf[1], 0, msg->size);
-                       } else {
-                               /* Return payload size. */
-                               ret = msg->size;
-                       }
-               }
-               break;
-
-       case DP_AUX_NATIVE_READ:
-       case DP_AUX_I2C_READ:
-               txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
-               rxsize = msg->size + 1;
-
-               if (WARN_ON(rxsize > 20))
-                       return -E2BIG;
-
-               ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
-                                       rxbuf, rxsize, 0);
-               if (ret > 0) {
-                       msg->reply = rxbuf[0] >> 4;
-                       /*
-                        * Assume happy day, and copy the data. The caller is
-                        * expected to check msg->reply before touching it.
-                        *
-                        * Return payload size.
-                        */
-                       ret--;
-                       memcpy(msg->buffer, rxbuf + 1, ret);
-               }
-               break;
-
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-
-static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       enum aux_ch aux_ch = dig_port->aux_ch;
-
-       switch (aux_ch) {
-       case AUX_CH_B:
-       case AUX_CH_C:
-       case AUX_CH_D:
-               return DP_AUX_CH_CTL(aux_ch);
-       default:
-               MISSING_CASE(aux_ch);
-               return DP_AUX_CH_CTL(AUX_CH_B);
-       }
-}
-
-static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       enum aux_ch aux_ch = dig_port->aux_ch;
-
-       switch (aux_ch) {
-       case AUX_CH_B:
-       case AUX_CH_C:
-       case AUX_CH_D:
-               return DP_AUX_CH_DATA(aux_ch, index);
-       default:
-               MISSING_CASE(aux_ch);
-               return DP_AUX_CH_DATA(AUX_CH_B, index);
-       }
-}
-
-static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       enum aux_ch aux_ch = dig_port->aux_ch;
-
-       switch (aux_ch) {
-       case AUX_CH_A:
-               return DP_AUX_CH_CTL(aux_ch);
-       case AUX_CH_B:
-       case AUX_CH_C:
-       case AUX_CH_D:
-               return PCH_DP_AUX_CH_CTL(aux_ch);
-       default:
-               MISSING_CASE(aux_ch);
-               return DP_AUX_CH_CTL(AUX_CH_A);
-       }
-}
-
-static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       enum aux_ch aux_ch = dig_port->aux_ch;
-
-       switch (aux_ch) {
-       case AUX_CH_A:
-               return DP_AUX_CH_DATA(aux_ch, index);
-       case AUX_CH_B:
-       case AUX_CH_C:
-       case AUX_CH_D:
-               return PCH_DP_AUX_CH_DATA(aux_ch, index);
-       default:
-               MISSING_CASE(aux_ch);
-               return DP_AUX_CH_DATA(AUX_CH_A, index);
-       }
-}
-
-static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       enum aux_ch aux_ch = dig_port->aux_ch;
-
-       switch (aux_ch) {
-       case AUX_CH_A:
-       case AUX_CH_B:
-       case AUX_CH_C:
-       case AUX_CH_D:
-       case AUX_CH_E:
-       case AUX_CH_F:
-               return DP_AUX_CH_CTL(aux_ch);
-       default:
-               MISSING_CASE(aux_ch);
-               return DP_AUX_CH_CTL(AUX_CH_A);
-       }
-}
-
-static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       enum aux_ch aux_ch = dig_port->aux_ch;
-
-       switch (aux_ch) {
-       case AUX_CH_A:
-       case AUX_CH_B:
-       case AUX_CH_C:
-       case AUX_CH_D:
-       case AUX_CH_E:
-       case AUX_CH_F:
-               return DP_AUX_CH_DATA(aux_ch, index);
-       default:
-               MISSING_CASE(aux_ch);
-               return DP_AUX_CH_DATA(AUX_CH_A, index);
-       }
-}
-
-static void
-intel_dp_aux_fini(struct intel_dp *intel_dp)
-{
-       kfree(intel_dp->aux.name);
-}
-
-static void
-intel_dp_aux_init(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *encoder = &dig_port->base;
-
-       if (INTEL_GEN(dev_priv) >= 9) {
-               intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
-               intel_dp->aux_ch_data_reg = skl_aux_data_reg;
-       } else if (HAS_PCH_SPLIT(dev_priv)) {
-               intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg;
-               intel_dp->aux_ch_data_reg = ilk_aux_data_reg;
-       } else {
-               intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg;
-               intel_dp->aux_ch_data_reg = g4x_aux_data_reg;
-       }
-
-       if (INTEL_GEN(dev_priv) >= 9)
-               intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
-       else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
-               intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
-       else if (HAS_PCH_SPLIT(dev_priv))
-               intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
-       else
-               intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
-
-       if (INTEL_GEN(dev_priv) >= 9)
-               intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
-       else
-               intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
-
-       drm_dp_aux_init(&intel_dp->aux);
-
-       /* Failure to allocate our preferred name is not critical */
-       intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c",
-                                      port_name(encoder->port));
-       intel_dp->aux.transfer = intel_dp_aux_transfer;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-       int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1];
-
-       return max_rate >= 540000;
-}
-
-bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp)
-{
-       int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1];
-
-       return max_rate >= 810000;
-}
-
-static void
-intel_dp_set_clock(struct intel_encoder *encoder,
-                  struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       const struct dp_link_dpll *divisor = NULL;
-       int i, count = 0;
-
-       if (IS_G4X(dev_priv)) {
-               divisor = g4x_dpll;
-               count = ARRAY_SIZE(g4x_dpll);
-       } else if (HAS_PCH_SPLIT(dev_priv)) {
-               divisor = pch_dpll;
-               count = ARRAY_SIZE(pch_dpll);
-       } else if (IS_CHERRYVIEW(dev_priv)) {
-               divisor = chv_dpll;
-               count = ARRAY_SIZE(chv_dpll);
-       } else if (IS_VALLEYVIEW(dev_priv)) {
-               divisor = vlv_dpll;
-               count = ARRAY_SIZE(vlv_dpll);
-       }
-
-       if (divisor && count) {
-               for (i = 0; i < count; i++) {
-                       if (pipe_config->port_clock == divisor[i].clock) {
-                               pipe_config->dpll = divisor[i].dpll;
-                               pipe_config->clock_set = true;
-                               break;
-                       }
-               }
-       }
-}
-
-static void snprintf_int_array(char *str, size_t len,
-                              const int *array, int nelem)
-{
-       int i;
-
-       str[0] = '\0';
-
-       for (i = 0; i < nelem; i++) {
-               int r = snprintf(str, len, "%s%d", i ? ", " : "", array[i]);
-               if (r >= len)
-                       return;
-               str += r;
-               len -= r;
-       }
-}
-
-static void intel_dp_print_rates(struct intel_dp *intel_dp)
-{
-       char str[128]; /* FIXME: too big for stack? */
-
-       if ((drm_debug & DRM_UT_KMS) == 0)
-               return;
-
-       snprintf_int_array(str, sizeof(str),
-                          intel_dp->source_rates, intel_dp->num_source_rates);
-       DRM_DEBUG_KMS("source rates: %s\n", str);
-
-       snprintf_int_array(str, sizeof(str),
-                          intel_dp->sink_rates, intel_dp->num_sink_rates);
-       DRM_DEBUG_KMS("sink rates: %s\n", str);
-
-       snprintf_int_array(str, sizeof(str),
-                          intel_dp->common_rates, intel_dp->num_common_rates);
-       DRM_DEBUG_KMS("common rates: %s\n", str);
-}
-
-int
-intel_dp_max_link_rate(struct intel_dp *intel_dp)
-{
-       int len;
-
-       len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate);
-       if (WARN_ON(len <= 0))
-               return 162000;
-
-       return intel_dp->common_rates[len - 1];
-}
-
-int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
-{
-       int i = intel_dp_rate_index(intel_dp->sink_rates,
-                                   intel_dp->num_sink_rates, rate);
-
-       if (WARN_ON(i < 0))
-               i = 0;
-
-       return i;
-}
-
-void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
-                          u8 *link_bw, u8 *rate_select)
-{
-       /* eDP 1.4 rate select method. */
-       if (intel_dp->use_rate_select) {
-               *link_bw = 0;
-               *rate_select =
-                       intel_dp_rate_select(intel_dp, port_clock);
-       } else {
-               *link_bw = drm_dp_link_rate_to_bw_code(port_clock);
-               *rate_select = 0;
-       }
-}
-
-static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp,
-                                        const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       return INTEL_GEN(dev_priv) >= 11 &&
-               pipe_config->cpu_transcoder != TRANSCODER_A;
-}
-
-static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       return intel_dp_source_supports_fec(intel_dp, pipe_config) &&
-               drm_dp_sink_supports_fec(intel_dp->fec_capable);
-}
-
-static bool intel_dp_source_supports_dsc(struct intel_dp *intel_dp,
-                                        const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       return INTEL_GEN(dev_priv) >= 10 &&
-               pipe_config->cpu_transcoder != TRANSCODER_A;
-}
-
-static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       if (!intel_dp_is_edp(intel_dp) && !pipe_config->fec_enable)
-               return false;
-
-       return intel_dp_source_supports_dsc(intel_dp, pipe_config) &&
-               drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
-}
-
-static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
-                               struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-       int bpp, bpc;
-
-       bpp = pipe_config->pipe_bpp;
-       bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, intel_dp->downstream_ports);
-
-       if (bpc > 0)
-               bpp = min(bpp, 3*bpc);
-
-       if (intel_dp_is_edp(intel_dp)) {
-               /* Get bpp from vbt only for panels that dont have bpp in edid */
-               if (intel_connector->base.display_info.bpc == 0 &&
-                   dev_priv->vbt.edp.bpp && dev_priv->vbt.edp.bpp < bpp) {
-                       DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
-                                     dev_priv->vbt.edp.bpp);
-                       bpp = dev_priv->vbt.edp.bpp;
-               }
-       }
-
-       return bpp;
-}
-
-/* Adjust link config limits based on compliance test requests. */
-void
-intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
-                                 struct intel_crtc_state *pipe_config,
-                                 struct link_config_limits *limits)
-{
-       /* For DP Compliance we override the computed bpp for the pipe */
-       if (intel_dp->compliance.test_data.bpc != 0) {
-               int bpp = 3 * intel_dp->compliance.test_data.bpc;
-
-               limits->min_bpp = limits->max_bpp = bpp;
-               pipe_config->dither_force_disable = bpp == 6 * 3;
-
-               DRM_DEBUG_KMS("Setting pipe_bpp to %d\n", bpp);
-       }
-
-       /* Use values requested by Compliance Test Request */
-       if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
-               int index;
-
-               /* Validate the compliance test data since max values
-                * might have changed due to link train fallback.
-                */
-               if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate,
-                                              intel_dp->compliance.test_lane_count)) {
-                       index = intel_dp_rate_index(intel_dp->common_rates,
-                                                   intel_dp->num_common_rates,
-                                                   intel_dp->compliance.test_link_rate);
-                       if (index >= 0)
-                               limits->min_clock = limits->max_clock = index;
-                       limits->min_lane_count = limits->max_lane_count =
-                               intel_dp->compliance.test_lane_count;
-               }
-       }
-}
-
-static int intel_dp_output_bpp(const struct intel_crtc_state *crtc_state, int bpp)
-{
-       /*
-        * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
-        * format of the number of bytes per pixel will be half the number
-        * of bytes of RGB pixel.
-        */
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
-               bpp /= 2;
-
-       return bpp;
-}
-
-/* Optimize link config in order: max bpp, min clock, min lanes */
-static int
-intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
-                                 struct intel_crtc_state *pipe_config,
-                                 const struct link_config_limits *limits)
-{
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       int bpp, clock, lane_count;
-       int mode_rate, link_clock, link_avail;
-
-       for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
-               mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
-                                                  bpp);
-
-               for (clock = limits->min_clock; clock <= limits->max_clock; clock++) {
-                       for (lane_count = limits->min_lane_count;
-                            lane_count <= limits->max_lane_count;
-                            lane_count <<= 1) {
-                               link_clock = intel_dp->common_rates[clock];
-                               link_avail = intel_dp_max_data_rate(link_clock,
-                                                                   lane_count);
-
-                               if (mode_rate <= link_avail) {
-                                       pipe_config->lane_count = lane_count;
-                                       pipe_config->pipe_bpp = bpp;
-                                       pipe_config->port_clock = link_clock;
-
-                                       return 0;
-                               }
-                       }
-               }
-       }
-
-       return -EINVAL;
-}
-
-static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc)
-{
-       int i, num_bpc;
-       u8 dsc_bpc[3] = {0};
-
-       num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd,
-                                                      dsc_bpc);
-       for (i = 0; i < num_bpc; i++) {
-               if (dsc_max_bpc >= dsc_bpc[i])
-                       return dsc_bpc[i] * 3;
-       }
-
-       return 0;
-}
-
-static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
-                                      struct intel_crtc_state *pipe_config,
-                                      struct drm_connector_state *conn_state,
-                                      struct link_config_limits *limits)
-{
-       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);
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       u8 dsc_max_bpc;
-       int pipe_bpp;
-       int ret;
-
-       pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) &&
-               intel_dp_supports_fec(intel_dp, pipe_config);
-
-       if (!intel_dp_supports_dsc(intel_dp, pipe_config))
-               return -EINVAL;
-
-       dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC,
-                           conn_state->max_requested_bpc);
-
-       pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc);
-       if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) {
-               DRM_DEBUG_KMS("No DSC support for less than 8bpc\n");
-               return -EINVAL;
-       }
-
-       /*
-        * For now enable DSC for max bpp, max link rate, max lane count.
-        * Optimize this later for the minimum possible link rate/lane count
-        * with DSC enabled for the requested mode.
-        */
-       pipe_config->pipe_bpp = pipe_bpp;
-       pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
-       pipe_config->lane_count = limits->max_lane_count;
-
-       if (intel_dp_is_edp(intel_dp)) {
-               pipe_config->dsc_params.compressed_bpp =
-                       min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4,
-                             pipe_config->pipe_bpp);
-               pipe_config->dsc_params.slice_count =
-                       drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
-                                                       true);
-       } else {
-               u16 dsc_max_output_bpp;
-               u8 dsc_dp_slice_count;
-
-               dsc_max_output_bpp =
-                       intel_dp_dsc_get_output_bpp(pipe_config->port_clock,
-                                                   pipe_config->lane_count,
-                                                   adjusted_mode->crtc_clock,
-                                                   adjusted_mode->crtc_hdisplay);
-               dsc_dp_slice_count =
-                       intel_dp_dsc_get_slice_count(intel_dp,
-                                                    adjusted_mode->crtc_clock,
-                                                    adjusted_mode->crtc_hdisplay);
-               if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
-                       DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n");
-                       return -EINVAL;
-               }
-               pipe_config->dsc_params.compressed_bpp = min_t(u16,
-                                                              dsc_max_output_bpp >> 4,
-                                                              pipe_config->pipe_bpp);
-               pipe_config->dsc_params.slice_count = dsc_dp_slice_count;
-       }
-       /*
-        * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate
-        * is greater than the maximum Cdclock and if slice count is even
-        * then we need to use 2 VDSC instances.
-        */
-       if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
-               if (pipe_config->dsc_params.slice_count > 1) {
-                       pipe_config->dsc_params.dsc_split = true;
-               } else {
-                       DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n");
-                       return -EINVAL;
-               }
-       }
-
-       ret = intel_dp_compute_dsc_params(intel_dp, pipe_config);
-       if (ret < 0) {
-               DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d "
-                             "Compressed BPP = %d\n",
-                             pipe_config->pipe_bpp,
-                             pipe_config->dsc_params.compressed_bpp);
-               return ret;
-       }
-
-       pipe_config->dsc_params.compression_enable = true;
-       DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d "
-                     "Compressed Bpp = %d Slice Count = %d\n",
-                     pipe_config->pipe_bpp,
-                     pipe_config->dsc_params.compressed_bpp,
-                     pipe_config->dsc_params.slice_count);
-
-       return 0;
-}
-
-int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state)
-{
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
-               return 6 * 3;
-       else
-               return 8 * 3;
-}
-
-static int
-intel_dp_compute_link_config(struct intel_encoder *encoder,
-                            struct intel_crtc_state *pipe_config,
-                            struct drm_connector_state *conn_state)
-{
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct link_config_limits limits;
-       int common_len;
-       int ret;
-
-       common_len = intel_dp_common_len_rate_limit(intel_dp,
-                                                   intel_dp->max_link_rate);
-
-       /* No common link rates between source and sink */
-       WARN_ON(common_len <= 0);
-
-       limits.min_clock = 0;
-       limits.max_clock = common_len - 1;
-
-       limits.min_lane_count = 1;
-       limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
-
-       limits.min_bpp = intel_dp_min_bpp(pipe_config);
-       limits.max_bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
-
-       if (intel_dp_is_edp(intel_dp)) {
-               /*
-                * Use the maximum clock and number of lanes the eDP panel
-                * advertizes being capable of. The panels are generally
-                * designed to support only a single clock and lane
-                * configuration, and typically these values correspond to the
-                * native resolution of the panel.
-                */
-               limits.min_lane_count = limits.max_lane_count;
-               limits.min_clock = limits.max_clock;
-       }
-
-       intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
-
-       DRM_DEBUG_KMS("DP link computation with max lane count %i "
-                     "max rate %d max bpp %d pixel clock %iKHz\n",
-                     limits.max_lane_count,
-                     intel_dp->common_rates[limits.max_clock],
-                     limits.max_bpp, adjusted_mode->crtc_clock);
-
-       /*
-        * Optimize for slow and wide. This is the place to add alternative
-        * optimization policy.
-        */
-       ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits);
-
-       /* enable compression if the mode doesn't fit available BW */
-       DRM_DEBUG_KMS("Force DSC en = %d\n", intel_dp->force_dsc_en);
-       if (ret || intel_dp->force_dsc_en) {
-               ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
-                                                 conn_state, &limits);
-               if (ret < 0)
-                       return ret;
-       }
-
-       if (pipe_config->dsc_params.compression_enable) {
-               DRM_DEBUG_KMS("DP lane count %d clock %d Input bpp %d Compressed bpp %d\n",
-                             pipe_config->lane_count, pipe_config->port_clock,
-                             pipe_config->pipe_bpp,
-                             pipe_config->dsc_params.compressed_bpp);
-
-               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
-                             intel_dp_link_required(adjusted_mode->crtc_clock,
-                                                    pipe_config->dsc_params.compressed_bpp),
-                             intel_dp_max_data_rate(pipe_config->port_clock,
-                                                    pipe_config->lane_count));
-       } else {
-               DRM_DEBUG_KMS("DP lane count %d clock %d bpp %d\n",
-                             pipe_config->lane_count, pipe_config->port_clock,
-                             pipe_config->pipe_bpp);
-
-               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
-                             intel_dp_link_required(adjusted_mode->crtc_clock,
-                                                    pipe_config->pipe_bpp),
-                             intel_dp_max_data_rate(pipe_config->port_clock,
-                                                    pipe_config->lane_count));
-       }
-       return 0;
-}
-
-static int
-intel_dp_ycbcr420_config(struct intel_dp *intel_dp,
-                        struct drm_connector *connector,
-                        struct intel_crtc_state *crtc_state)
-{
-       const struct drm_display_info *info = &connector->display_info;
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       int ret;
-
-       if (!drm_mode_is_420_only(info, adjusted_mode) ||
-           !intel_dp_get_colorimetry_status(intel_dp) ||
-           !connector->ycbcr_420_allowed)
-               return 0;
-
-       crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
-
-       /* YCBCR 420 output conversion needs a scaler */
-       ret = skl_update_scaler_crtc(crtc_state);
-       if (ret) {
-               DRM_DEBUG_KMS("Scaler allocation for output failed\n");
-               return ret;
-       }
-
-       intel_pch_panel_fitting(crtc, crtc_state, DRM_MODE_SCALE_FULLSCREEN);
-
-       return 0;
-}
-
-bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       const struct intel_digital_connector_state *intel_conn_state =
-               to_intel_digital_connector_state(conn_state);
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-
-       if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
-               /*
-                * See:
-                * CEA-861-E - 5.1 Default Encoding Parameters
-                * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
-                */
-               return crtc_state->pipe_bpp != 18 &&
-                       drm_default_rgb_quant_range(adjusted_mode) ==
-                       HDMI_QUANTIZATION_RANGE_LIMITED;
-       } else {
-               return intel_conn_state->broadcast_rgb ==
-                       INTEL_BROADCAST_RGB_LIMITED;
-       }
-}
-
-int
-intel_dp_compute_config(struct intel_encoder *encoder,
-                       struct intel_crtc_state *pipe_config,
-                       struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
-       enum port port = encoder->port;
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-       struct intel_digital_connector_state *intel_conn_state =
-               to_intel_digital_connector_state(conn_state);
-       bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
-                                          DP_DPCD_QUIRK_CONSTANT_N);
-       int ret = 0, output_bpp;
-
-       if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
-               pipe_config->has_pch_encoder = true;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-       if (lspcon->active)
-               lspcon_ycbcr420_config(&intel_connector->base, pipe_config);
-       else
-               ret = intel_dp_ycbcr420_config(intel_dp, &intel_connector->base,
-                                              pipe_config);
-
-       if (ret)
-               return ret;
-
-       pipe_config->has_drrs = false;
-       if (IS_G4X(dev_priv) || port == PORT_A)
-               pipe_config->has_audio = false;
-       else if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
-               pipe_config->has_audio = intel_dp->has_audio;
-       else
-               pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
-
-       if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
-               intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
-                                      adjusted_mode);
-
-               if (INTEL_GEN(dev_priv) >= 9) {
-                       ret = skl_update_scaler_crtc(pipe_config);
-                       if (ret)
-                               return ret;
-               }
-
-               if (HAS_GMCH(dev_priv))
-                       intel_gmch_panel_fitting(intel_crtc, pipe_config,
-                                                conn_state->scaling_mode);
-               else
-                       intel_pch_panel_fitting(intel_crtc, pipe_config,
-                                               conn_state->scaling_mode);
-       }
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       if (HAS_GMCH(dev_priv) &&
-           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
-               return -EINVAL;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
-               return -EINVAL;
-
-       ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state);
-       if (ret < 0)
-               return ret;
-
-       pipe_config->limited_color_range =
-               intel_dp_limited_color_range(pipe_config, conn_state);
-
-       if (pipe_config->dsc_params.compression_enable)
-               output_bpp = pipe_config->dsc_params.compressed_bpp;
-       else
-               output_bpp = intel_dp_output_bpp(pipe_config, pipe_config->pipe_bpp);
-
-       intel_link_compute_m_n(output_bpp,
-                              pipe_config->lane_count,
-                              adjusted_mode->crtc_clock,
-                              pipe_config->port_clock,
-                              &pipe_config->dp_m_n,
-                              constant_n);
-
-       if (intel_connector->panel.downclock_mode != NULL &&
-               dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
-                       pipe_config->has_drrs = true;
-                       intel_link_compute_m_n(output_bpp,
-                                              pipe_config->lane_count,
-                                              intel_connector->panel.downclock_mode->clock,
-                                              pipe_config->port_clock,
-                                              &pipe_config->dp_m2_n2,
-                                              constant_n);
-       }
-
-       if (!HAS_DDI(dev_priv))
-               intel_dp_set_clock(encoder, pipe_config);
-
-       intel_psr_compute_config(intel_dp, pipe_config);
-
-       return 0;
-}
-
-void intel_dp_set_link_params(struct intel_dp *intel_dp,
-                             int link_rate, u8 lane_count,
-                             bool link_mst)
-{
-       intel_dp->link_trained = false;
-       intel_dp->link_rate = link_rate;
-       intel_dp->lane_count = lane_count;
-       intel_dp->link_mst = link_mst;
-}
-
-static void intel_dp_prepare(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = encoder->port;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-
-       intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
-                                pipe_config->lane_count,
-                                intel_crtc_has_type(pipe_config,
-                                                    INTEL_OUTPUT_DP_MST));
-
-       /*
-        * There are four kinds of DP registers:
-        *
-        *      IBX PCH
-        *      SNB CPU
-        *      IVB CPU
-        *      CPT PCH
-        *
-        * IBX PCH and CPU are the same for almost everything,
-        * except that the CPU DP PLL is configured in this
-        * register
-        *
-        * CPT PCH is quite different, having many bits moved
-        * to the TRANS_DP_CTL register instead. That
-        * configuration happens (oddly) in ironlake_pch_enable
-        */
-
-       /* Preserve the BIOS-computed detected bit. This is
-        * supposed to be read-only.
-        */
-       intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
-
-       /* Handle DP bits in common between all three register formats */
-       intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
-       intel_dp->DP |= DP_PORT_WIDTH(pipe_config->lane_count);
-
-       /* Split out the IBX/CPU vs CPT settings */
-
-       if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) {
-               if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-                       intel_dp->DP |= DP_SYNC_HS_HIGH;
-               if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-                       intel_dp->DP |= DP_SYNC_VS_HIGH;
-               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
-
-               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-                       intel_dp->DP |= DP_ENHANCED_FRAMING;
-
-               intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe);
-       } else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
-               u32 trans_dp;
-
-               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
-
-               trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
-               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-                       trans_dp |= TRANS_DP_ENH_FRAMING;
-               else
-                       trans_dp &= ~TRANS_DP_ENH_FRAMING;
-               I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
-       } else {
-               if (IS_G4X(dev_priv) && pipe_config->limited_color_range)
-                       intel_dp->DP |= DP_COLOR_RANGE_16_235;
-
-               if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-                       intel_dp->DP |= DP_SYNC_HS_HIGH;
-               if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-                       intel_dp->DP |= DP_SYNC_VS_HIGH;
-               intel_dp->DP |= DP_LINK_TRAIN_OFF;
-
-               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-                       intel_dp->DP |= DP_ENHANCED_FRAMING;
-
-               if (IS_CHERRYVIEW(dev_priv))
-                       intel_dp->DP |= DP_PIPE_SEL_CHV(crtc->pipe);
-               else
-                       intel_dp->DP |= DP_PIPE_SEL(crtc->pipe);
-       }
-}
-
-#define IDLE_ON_MASK           (PP_ON | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
-#define IDLE_ON_VALUE          (PP_ON | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
-
-#define IDLE_OFF_MASK          (PP_ON | PP_SEQUENCE_MASK | 0                     | 0)
-#define IDLE_OFF_VALUE         (0     | PP_SEQUENCE_NONE | 0                     | 0)
-
-#define IDLE_CYCLE_MASK                (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
-#define IDLE_CYCLE_VALUE       (0     | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
-
-static void intel_pps_verify_state(struct intel_dp *intel_dp);
-
-static void wait_panel_status(struct intel_dp *intel_dp,
-                                      u32 mask,
-                                      u32 value)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       i915_reg_t pp_stat_reg, pp_ctrl_reg;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       intel_pps_verify_state(intel_dp);
-
-       pp_stat_reg = _pp_stat_reg(intel_dp);
-       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-
-       DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n",
-                       mask, value,
-                       I915_READ(pp_stat_reg),
-                       I915_READ(pp_ctrl_reg));
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   pp_stat_reg, mask, value,
-                                   5000))
-               DRM_ERROR("Panel status timeout: status %08x control %08x\n",
-                               I915_READ(pp_stat_reg),
-                               I915_READ(pp_ctrl_reg));
-
-       DRM_DEBUG_KMS("Wait complete\n");
-}
-
-static void wait_panel_on(struct intel_dp *intel_dp)
-{
-       DRM_DEBUG_KMS("Wait for panel power on\n");
-       wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
-}
-
-static void wait_panel_off(struct intel_dp *intel_dp)
-{
-       DRM_DEBUG_KMS("Wait for panel power off time\n");
-       wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
-}
-
-static void wait_panel_power_cycle(struct intel_dp *intel_dp)
-{
-       ktime_t panel_power_on_time;
-       s64 panel_power_off_duration;
-
-       DRM_DEBUG_KMS("Wait for panel power cycle\n");
-
-       /* take the difference of currrent time and panel power off time
-        * and then make panel wait for t11_t12 if needed. */
-       panel_power_on_time = ktime_get_boottime();
-       panel_power_off_duration = ktime_ms_delta(panel_power_on_time, intel_dp->panel_power_off_time);
-
-       /* When we disable the VDD override bit last we have to do the manual
-        * wait. */
-       if (panel_power_off_duration < (s64)intel_dp->panel_power_cycle_delay)
-               wait_remaining_ms_from_jiffies(jiffies,
-                                      intel_dp->panel_power_cycle_delay - panel_power_off_duration);
-
-       wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
-}
-
-static void wait_backlight_on(struct intel_dp *intel_dp)
-{
-       wait_remaining_ms_from_jiffies(intel_dp->last_power_on,
-                                      intel_dp->backlight_on_delay);
-}
-
-static void edp_wait_backlight_off(struct intel_dp *intel_dp)
-{
-       wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off,
-                                      intel_dp->backlight_off_delay);
-}
-
-/* Read the current pp_control value, unlocking the register if it
- * is locked
- */
-
-static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u32 control;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       control = I915_READ(_pp_ctrl_reg(intel_dp));
-       if (WARN_ON(!HAS_DDI(dev_priv) &&
-                   (control & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS)) {
-               control &= ~PANEL_UNLOCK_MASK;
-               control |= PANEL_UNLOCK_REGS;
-       }
-       return control;
-}
-
-/*
- * Must be paired with edp_panel_vdd_off().
- * Must hold pps_mutex around the whole on/off sequence.
- * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
- */
-static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       u32 pp;
-       i915_reg_t pp_stat_reg, pp_ctrl_reg;
-       bool need_to_disable = !intel_dp->want_panel_vdd;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return false;
-
-       cancel_delayed_work(&intel_dp->panel_vdd_work);
-       intel_dp->want_panel_vdd = true;
-
-       if (edp_have_panel_vdd(intel_dp))
-               return need_to_disable;
-
-       intel_display_power_get(dev_priv,
-                               intel_aux_power_domain(intel_dig_port));
-
-       DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
-                     port_name(intel_dig_port->base.port));
-
-       if (!edp_have_panel_power(intel_dp))
-               wait_panel_power_cycle(intel_dp);
-
-       pp = ironlake_get_pp_control(intel_dp);
-       pp |= EDP_FORCE_VDD;
-
-       pp_stat_reg = _pp_stat_reg(intel_dp);
-       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-
-       I915_WRITE(pp_ctrl_reg, pp);
-       POSTING_READ(pp_ctrl_reg);
-       DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
-                       I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
-       /*
-        * If the panel wasn't on, delay before accessing aux channel
-        */
-       if (!edp_have_panel_power(intel_dp)) {
-               DRM_DEBUG_KMS("eDP port %c panel power wasn't enabled\n",
-                             port_name(intel_dig_port->base.port));
-               msleep(intel_dp->panel_power_up_delay);
-       }
-
-       return need_to_disable;
-}
-
-/*
- * Must be paired with intel_edp_panel_vdd_off() or
- * intel_edp_panel_off().
- * Nested calls to these functions are not allowed since
- * we drop the lock. Caller must use some higher level
- * locking to prevent nested calls from other threads.
- */
-void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
-{
-       intel_wakeref_t wakeref;
-       bool vdd;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       vdd = false;
-       with_pps_lock(intel_dp, wakeref)
-               vdd = edp_panel_vdd_on(intel_dp);
-       I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
-            port_name(dp_to_dig_port(intel_dp)->base.port));
-}
-
-static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port =
-               dp_to_dig_port(intel_dp);
-       u32 pp;
-       i915_reg_t pp_stat_reg, pp_ctrl_reg;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       WARN_ON(intel_dp->want_panel_vdd);
-
-       if (!edp_have_panel_vdd(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("Turning eDP port %c VDD off\n",
-                     port_name(intel_dig_port->base.port));
-
-       pp = ironlake_get_pp_control(intel_dp);
-       pp &= ~EDP_FORCE_VDD;
-
-       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-       pp_stat_reg = _pp_stat_reg(intel_dp);
-
-       I915_WRITE(pp_ctrl_reg, pp);
-       POSTING_READ(pp_ctrl_reg);
-
-       /* Make sure sequencer is idle before allowing subsequent activity */
-       DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
-       I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
-
-       if ((pp & PANEL_POWER_ON) == 0)
-               intel_dp->panel_power_off_time = ktime_get_boottime();
-
-       intel_display_power_put_unchecked(dev_priv,
-                                         intel_aux_power_domain(intel_dig_port));
-}
-
-static void edp_panel_vdd_work(struct work_struct *__work)
-{
-       struct intel_dp *intel_dp =
-               container_of(to_delayed_work(__work),
-                            struct intel_dp, panel_vdd_work);
-       intel_wakeref_t wakeref;
-
-       with_pps_lock(intel_dp, wakeref) {
-               if (!intel_dp->want_panel_vdd)
-                       edp_panel_vdd_off_sync(intel_dp);
-       }
-}
-
-static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
-{
-       unsigned long delay;
-
-       /*
-        * Queue the timer to fire a long time from now (relative to the power
-        * down delay) to keep the panel power up across a sequence of
-        * operations.
-        */
-       delay = msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5);
-       schedule_delayed_work(&intel_dp->panel_vdd_work, delay);
-}
-
-/*
- * Must be paired with edp_panel_vdd_on().
- * Must hold pps_mutex around the whole on/off sequence.
- * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
- */
-static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
-            port_name(dp_to_dig_port(intel_dp)->base.port));
-
-       intel_dp->want_panel_vdd = false;
-
-       if (sync)
-               edp_panel_vdd_off_sync(intel_dp);
-       else
-               edp_panel_vdd_schedule_off(intel_dp);
-}
-
-static void edp_panel_on(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u32 pp;
-       i915_reg_t pp_ctrl_reg;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("Turn eDP port %c panel power on\n",
-                     port_name(dp_to_dig_port(intel_dp)->base.port));
-
-       if (WARN(edp_have_panel_power(intel_dp),
-                "eDP port %c panel power already on\n",
-                port_name(dp_to_dig_port(intel_dp)->base.port)))
-               return;
-
-       wait_panel_power_cycle(intel_dp);
-
-       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-       pp = ironlake_get_pp_control(intel_dp);
-       if (IS_GEN(dev_priv, 5)) {
-               /* ILK workaround: disable reset around power sequence */
-               pp &= ~PANEL_POWER_RESET;
-               I915_WRITE(pp_ctrl_reg, pp);
-               POSTING_READ(pp_ctrl_reg);
-       }
-
-       pp |= PANEL_POWER_ON;
-       if (!IS_GEN(dev_priv, 5))
-               pp |= PANEL_POWER_RESET;
-
-       I915_WRITE(pp_ctrl_reg, pp);
-       POSTING_READ(pp_ctrl_reg);
-
-       wait_panel_on(intel_dp);
-       intel_dp->last_power_on = jiffies;
-
-       if (IS_GEN(dev_priv, 5)) {
-               pp |= PANEL_POWER_RESET; /* restore panel reset bit */
-               I915_WRITE(pp_ctrl_reg, pp);
-               POSTING_READ(pp_ctrl_reg);
-       }
-}
-
-void intel_edp_panel_on(struct intel_dp *intel_dp)
-{
-       intel_wakeref_t wakeref;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       with_pps_lock(intel_dp, wakeref)
-               edp_panel_on(intel_dp);
-}
-
-
-static void edp_panel_off(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       u32 pp;
-       i915_reg_t pp_ctrl_reg;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("Turn eDP port %c panel power off\n",
-                     port_name(dig_port->base.port));
-
-       WARN(!intel_dp->want_panel_vdd, "Need eDP port %c VDD to turn off panel\n",
-            port_name(dig_port->base.port));
-
-       pp = ironlake_get_pp_control(intel_dp);
-       /* We need to switch off panel power _and_ force vdd, for otherwise some
-        * panels get very unhappy and cease to work. */
-       pp &= ~(PANEL_POWER_ON | PANEL_POWER_RESET | EDP_FORCE_VDD |
-               EDP_BLC_ENABLE);
-
-       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-
-       intel_dp->want_panel_vdd = false;
-
-       I915_WRITE(pp_ctrl_reg, pp);
-       POSTING_READ(pp_ctrl_reg);
-
-       wait_panel_off(intel_dp);
-       intel_dp->panel_power_off_time = ktime_get_boottime();
-
-       /* We got a reference when we enabled the VDD. */
-       intel_display_power_put_unchecked(dev_priv, intel_aux_power_domain(dig_port));
-}
-
-void intel_edp_panel_off(struct intel_dp *intel_dp)
-{
-       intel_wakeref_t wakeref;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       with_pps_lock(intel_dp, wakeref)
-               edp_panel_off(intel_dp);
-}
-
-/* Enable backlight in the panel power control. */
-static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       intel_wakeref_t wakeref;
-
-       /*
-        * If we enable the backlight right away following a panel power
-        * on, we may see slight flicker as the panel syncs with the eDP
-        * link.  So delay a bit to make sure the image is solid before
-        * allowing it to appear.
-        */
-       wait_backlight_on(intel_dp);
-
-       with_pps_lock(intel_dp, wakeref) {
-               i915_reg_t pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-               u32 pp;
-
-               pp = ironlake_get_pp_control(intel_dp);
-               pp |= EDP_BLC_ENABLE;
-
-               I915_WRITE(pp_ctrl_reg, pp);
-               POSTING_READ(pp_ctrl_reg);
-       }
-}
-
-/* Enable backlight PWM and backlight PP control. */
-void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
-                           const struct drm_connector_state *conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(conn_state->best_encoder);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_panel_enable_backlight(crtc_state, conn_state);
-       _intel_edp_backlight_on(intel_dp);
-}
-
-/* Disable backlight in the panel power control. */
-static void _intel_edp_backlight_off(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       intel_wakeref_t wakeref;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       with_pps_lock(intel_dp, wakeref) {
-               i915_reg_t pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-               u32 pp;
-
-               pp = ironlake_get_pp_control(intel_dp);
-               pp &= ~EDP_BLC_ENABLE;
-
-               I915_WRITE(pp_ctrl_reg, pp);
-               POSTING_READ(pp_ctrl_reg);
-       }
-
-       intel_dp->last_backlight_off = jiffies;
-       edp_wait_backlight_off(intel_dp);
-}
-
-/* Disable backlight PP control and backlight PWM. */
-void intel_edp_backlight_off(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(old_conn_state->best_encoder);
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       _intel_edp_backlight_off(intel_dp);
-       intel_panel_disable_backlight(old_conn_state);
-}
-
-/*
- * Hook for controlling the panel power control backlight through the bl_power
- * sysfs attribute. Take care to handle multiple calls.
- */
-static void intel_edp_backlight_power(struct intel_connector *connector,
-                                     bool enable)
-{
-       struct intel_dp *intel_dp = intel_attached_dp(&connector->base);
-       intel_wakeref_t wakeref;
-       bool is_enabled;
-
-       is_enabled = false;
-       with_pps_lock(intel_dp, wakeref)
-               is_enabled = ironlake_get_pp_control(intel_dp) & EDP_BLC_ENABLE;
-       if (is_enabled == enable)
-               return;
-
-       DRM_DEBUG_KMS("panel power control backlight %s\n",
-                     enable ? "enable" : "disable");
-
-       if (enable)
-               _intel_edp_backlight_on(intel_dp);
-       else
-               _intel_edp_backlight_off(intel_dp);
-}
-
-static void assert_dp_port(struct intel_dp *intel_dp, bool state)
-{
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-       bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN;
-
-       I915_STATE_WARN(cur_state != state,
-                       "DP port %c state assertion failure (expected %s, current %s)\n",
-                       port_name(dig_port->base.port),
-                       onoff(state), onoff(cur_state));
-}
-#define assert_dp_port_disabled(d) assert_dp_port((d), false)
-
-static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
-{
-       bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE;
-
-       I915_STATE_WARN(cur_state != state,
-                       "eDP PLL state assertion failure (expected %s, current %s)\n",
-                       onoff(state), onoff(cur_state));
-}
-#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
-#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
-
-static void ironlake_edp_pll_on(struct intel_dp *intel_dp,
-                               const struct intel_crtc_state *pipe_config)
-{
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-
-       assert_pipe_disabled(dev_priv, crtc->pipe);
-       assert_dp_port_disabled(intel_dp);
-       assert_edp_pll_disabled(dev_priv);
-
-       DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
-                     pipe_config->port_clock);
-
-       intel_dp->DP &= ~DP_PLL_FREQ_MASK;
-
-       if (pipe_config->port_clock == 162000)
-               intel_dp->DP |= DP_PLL_FREQ_162MHZ;
-       else
-               intel_dp->DP |= DP_PLL_FREQ_270MHZ;
-
-       I915_WRITE(DP_A, intel_dp->DP);
-       POSTING_READ(DP_A);
-       udelay(500);
-
-       /*
-        * [DevILK] Work around required when enabling DP PLL
-        * while a pipe is enabled going to FDI:
-        * 1. Wait for the start of vertical blank on the enabled pipe going to FDI
-        * 2. Program DP PLL enable
-        */
-       if (IS_GEN(dev_priv, 5))
-               intel_wait_for_vblank_if_active(dev_priv, !crtc->pipe);
-
-       intel_dp->DP |= DP_PLL_ENABLE;
-
-       I915_WRITE(DP_A, intel_dp->DP);
-       POSTING_READ(DP_A);
-       udelay(200);
-}
-
-static void ironlake_edp_pll_off(struct intel_dp *intel_dp,
-                                const struct intel_crtc_state *old_crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-
-       assert_pipe_disabled(dev_priv, crtc->pipe);
-       assert_dp_port_disabled(intel_dp);
-       assert_edp_pll_enabled(dev_priv);
-
-       DRM_DEBUG_KMS("disabling eDP PLL\n");
-
-       intel_dp->DP &= ~DP_PLL_ENABLE;
-
-       I915_WRITE(DP_A, intel_dp->DP);
-       POSTING_READ(DP_A);
-       udelay(200);
-}
-
-static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
-{
-       /*
-        * DPCD 1.2+ should support BRANCH_DEVICE_CTRL, and thus
-        * be capable of signalling downstream hpd with a long pulse.
-        * Whether or not that means D3 is safe to use is not clear,
-        * but let's assume so until proven otherwise.
-        *
-        * FIXME should really check all downstream ports...
-        */
-       return intel_dp->dpcd[DP_DPCD_REV] == 0x11 &&
-               intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
-               intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
-}
-
-void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
-                                          const struct intel_crtc_state *crtc_state,
-                                          bool enable)
-{
-       int ret;
-
-       if (!crtc_state->dsc_params.compression_enable)
-               return;
-
-       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_DSC_ENABLE,
-                                enable ? DP_DECOMPRESSION_EN : 0);
-       if (ret < 0)
-               DRM_DEBUG_KMS("Failed to %s sink decompression state\n",
-                             enable ? "enable" : "disable");
-}
-
-/* If the sink supports it, try to set the power state appropriately */
-void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
-{
-       int ret, i;
-
-       /* Should have a valid DPCD by this point */
-       if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
-               return;
-
-       if (mode != DRM_MODE_DPMS_ON) {
-               if (downstream_hpd_needs_d0(intel_dp))
-                       return;
-
-               ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
-                                        DP_SET_POWER_D3);
-       } else {
-               struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
-
-               /*
-                * When turning on, we need to retry for 1ms to give the sink
-                * time to wake up.
-                */
-               for (i = 0; i < 3; i++) {
-                       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
-                                                DP_SET_POWER_D0);
-                       if (ret == 1)
-                               break;
-                       msleep(1);
-               }
-
-               if (ret == 1 && lspcon->active)
-                       lspcon_wait_pcon_mode(lspcon);
-       }
-
-       if (ret != 1)
-               DRM_DEBUG_KMS("failed to %s sink power state\n",
-                             mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
-}
-
-static bool cpt_dp_port_selected(struct drm_i915_private *dev_priv,
-                                enum port port, enum pipe *pipe)
-{
-       enum pipe p;
-
-       for_each_pipe(dev_priv, p) {
-               u32 val = I915_READ(TRANS_DP_CTL(p));
-
-               if ((val & TRANS_DP_PORT_SEL_MASK) == TRANS_DP_PORT_SEL(port)) {
-                       *pipe = p;
-                       return true;
-               }
-       }
-
-       DRM_DEBUG_KMS("No pipe for DP port %c found\n", port_name(port));
-
-       /* must initialize pipe to something for the asserts */
-       *pipe = PIPE_A;
-
-       return false;
-}
-
-bool intel_dp_port_enabled(struct drm_i915_private *dev_priv,
-                          i915_reg_t dp_reg, enum port port,
-                          enum pipe *pipe)
-{
-       bool ret;
-       u32 val;
-
-       val = I915_READ(dp_reg);
-
-       ret = val & DP_PORT_EN;
-
-       /* asserts want to know the pipe even if the port is disabled */
-       if (IS_IVYBRIDGE(dev_priv) && port == PORT_A)
-               *pipe = (val & DP_PIPE_SEL_MASK_IVB) >> DP_PIPE_SEL_SHIFT_IVB;
-       else if (HAS_PCH_CPT(dev_priv) && port != PORT_A)
-               ret &= cpt_dp_port_selected(dev_priv, port, pipe);
-       else if (IS_CHERRYVIEW(dev_priv))
-               *pipe = (val & DP_PIPE_SEL_MASK_CHV) >> DP_PIPE_SEL_SHIFT_CHV;
-       else
-               *pipe = (val & DP_PIPE_SEL_MASK) >> DP_PIPE_SEL_SHIFT;
-
-       return ret;
-}
-
-static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
-                                 enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       intel_wakeref_t wakeref;
-       bool ret;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       ret = intel_dp_port_enabled(dev_priv, intel_dp->output_reg,
-                                   encoder->port, pipe);
-
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-
-       return ret;
-}
-
-static void intel_dp_get_config(struct intel_encoder *encoder,
-                               struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       u32 tmp, flags = 0;
-       enum port port = encoder->port;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-
-       if (encoder->type == INTEL_OUTPUT_EDP)
-               pipe_config->output_types |= BIT(INTEL_OUTPUT_EDP);
-       else
-               pipe_config->output_types |= BIT(INTEL_OUTPUT_DP);
-
-       tmp = I915_READ(intel_dp->output_reg);
-
-       pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A;
-
-       if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
-               u32 trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
-
-               if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH)
-                       flags |= DRM_MODE_FLAG_PHSYNC;
-               else
-                       flags |= DRM_MODE_FLAG_NHSYNC;
-
-               if (trans_dp & TRANS_DP_VSYNC_ACTIVE_HIGH)
-                       flags |= DRM_MODE_FLAG_PVSYNC;
-               else
-                       flags |= DRM_MODE_FLAG_NVSYNC;
-       } else {
-               if (tmp & DP_SYNC_HS_HIGH)
-                       flags |= DRM_MODE_FLAG_PHSYNC;
-               else
-                       flags |= DRM_MODE_FLAG_NHSYNC;
-
-               if (tmp & DP_SYNC_VS_HIGH)
-                       flags |= DRM_MODE_FLAG_PVSYNC;
-               else
-                       flags |= DRM_MODE_FLAG_NVSYNC;
-       }
-
-       pipe_config->base.adjusted_mode.flags |= flags;
-
-       if (IS_G4X(dev_priv) && tmp & DP_COLOR_RANGE_16_235)
-               pipe_config->limited_color_range = true;
-
-       pipe_config->lane_count =
-               ((tmp & DP_PORT_WIDTH_MASK) >> DP_PORT_WIDTH_SHIFT) + 1;
-
-       intel_dp_get_m_n(crtc, pipe_config);
-
-       if (port == PORT_A) {
-               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ)
-                       pipe_config->port_clock = 162000;
-               else
-                       pipe_config->port_clock = 270000;
-       }
-
-       pipe_config->base.adjusted_mode.crtc_clock =
-               intel_dotclock_calculate(pipe_config->port_clock,
-                                        &pipe_config->dp_m_n);
-
-       if (intel_dp_is_edp(intel_dp) && dev_priv->vbt.edp.bpp &&
-           pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) {
-               /*
-                * This is a big fat ugly hack.
-                *
-                * Some machines in UEFI boot mode provide us a VBT that has 18
-                * bpp and 1.62 GHz link bandwidth for eDP, which for reasons
-                * unknown we fail to light up. Yet the same BIOS boots up with
-                * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as
-                * max, not what it tells us to use.
-                *
-                * Note: This will still be broken if the eDP panel is not lit
-                * up by the BIOS, and thus we can't get the mode at module
-                * load.
-                */
-               DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n",
-                             pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp);
-               dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
-       }
-}
-
-static void intel_disable_dp(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *old_crtc_state,
-                            const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
-       intel_dp->link_trained = false;
-
-       if (old_crtc_state->has_audio)
-               intel_audio_codec_disable(encoder,
-                                         old_crtc_state, old_conn_state);
-
-       /* Make sure the panel is off before trying to change the mode. But also
-        * ensure that we have vdd while we switch off the panel. */
-       intel_edp_panel_vdd_on(intel_dp);
-       intel_edp_backlight_off(old_conn_state);
-       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
-       intel_edp_panel_off(intel_dp);
-}
-
-static void g4x_disable_dp(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *old_crtc_state,
-                          const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_dp(encoder, old_crtc_state, old_conn_state);
-}
-
-static void vlv_disable_dp(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *old_crtc_state,
-                          const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_dp(encoder, old_crtc_state, old_conn_state);
-}
-
-static void g4x_post_disable_dp(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *old_crtc_state,
-                               const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = encoder->port;
-
-       /*
-        * Bspec does not list a specific disable sequence for g4x DP.
-        * Follow the ilk+ sequence (disable pipe before the port) for
-        * g4x DP as it does not suffer from underruns like the normal
-        * g4x modeset sequence (disable pipe after the port).
-        */
-       intel_dp_link_down(encoder, old_crtc_state);
-
-       /* Only ilk+ has port A */
-       if (port == PORT_A)
-               ironlake_edp_pll_off(intel_dp, old_crtc_state);
-}
-
-static void vlv_post_disable_dp(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *old_crtc_state,
-                               const struct drm_connector_state *old_conn_state)
-{
-       intel_dp_link_down(encoder, old_crtc_state);
-}
-
-static void chv_post_disable_dp(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *old_crtc_state,
-                               const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       intel_dp_link_down(encoder, old_crtc_state);
-
-       vlv_dpio_get(dev_priv);
-
-       /* Assert data lane reset */
-       chv_data_lane_soft_reset(encoder, old_crtc_state, true);
-
-       vlv_dpio_put(dev_priv);
-}
-
-static void
-_intel_dp_set_link_train(struct intel_dp *intel_dp,
-                        u32 *DP,
-                        u8 dp_train_pat)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum port port = intel_dig_port->base.port;
-       u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
-
-       if (dp_train_pat & train_pat_mask)
-               DRM_DEBUG_KMS("Using DP training pattern TPS%d\n",
-                             dp_train_pat & train_pat_mask);
-
-       if (HAS_DDI(dev_priv)) {
-               u32 temp = I915_READ(DP_TP_CTL(port));
-
-               if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
-                       temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
-               else
-                       temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
-
-               temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
-               switch (dp_train_pat & train_pat_mask) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
-
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
-                       break;
-               case DP_TRAINING_PATTERN_4:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT4;
-                       break;
-               }
-               I915_WRITE(DP_TP_CTL(port), temp);
-
-       } else if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) ||
-                  (HAS_PCH_CPT(dev_priv) && port != PORT_A)) {
-               *DP &= ~DP_LINK_TRAIN_MASK_CPT;
-
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       *DP |= DP_LINK_TRAIN_OFF_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       *DP |= DP_LINK_TRAIN_PAT_1_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
-                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
-                       break;
-               }
-
-       } else {
-               *DP &= ~DP_LINK_TRAIN_MASK;
-
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       *DP |= DP_LINK_TRAIN_OFF;
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       *DP |= DP_LINK_TRAIN_PAT_1;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       *DP |= DP_LINK_TRAIN_PAT_2;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
-                       *DP |= DP_LINK_TRAIN_PAT_2;
-                       break;
-               }
-       }
-}
-
-static void intel_dp_enable_port(struct intel_dp *intel_dp,
-                                const struct intel_crtc_state *old_crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       /* enable with pattern 1 (as per spec) */
-
-       intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
-
-       /*
-        * Magic for VLV/CHV. We _must_ first set up the register
-        * without actually enabling the port, and then do another
-        * write to enable the port. Otherwise link training will
-        * fail when the power sequencer is freshly used for this port.
-        */
-       intel_dp->DP |= DP_PORT_EN;
-       if (old_crtc_state->has_audio)
-               intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
-
-       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-       POSTING_READ(intel_dp->output_reg);
-}
-
-static void intel_enable_dp(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *pipe_config,
-                           const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       u32 dp_reg = I915_READ(intel_dp->output_reg);
-       enum pipe pipe = crtc->pipe;
-       intel_wakeref_t wakeref;
-
-       if (WARN_ON(dp_reg & DP_PORT_EN))
-               return;
-
-       with_pps_lock(intel_dp, wakeref) {
-               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-                       vlv_init_panel_power_sequencer(encoder, pipe_config);
-
-               intel_dp_enable_port(intel_dp, pipe_config);
-
-               edp_panel_vdd_on(intel_dp);
-               edp_panel_on(intel_dp);
-               edp_panel_vdd_off(intel_dp, true);
-       }
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               unsigned int lane_mask = 0x0;
-
-               if (IS_CHERRYVIEW(dev_priv))
-                       lane_mask = intel_dp_unused_lane_mask(pipe_config->lane_count);
-
-               vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
-                                   lane_mask);
-       }
-
-       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
-       intel_dp_start_link_train(intel_dp);
-       intel_dp_stop_link_train(intel_dp);
-
-       if (pipe_config->has_audio) {
-               DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
-                                pipe_name(pipe));
-               intel_audio_codec_enable(encoder, pipe_config, conn_state);
-       }
-}
-
-static void g4x_enable_dp(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *pipe_config,
-                         const struct drm_connector_state *conn_state)
-{
-       intel_enable_dp(encoder, pipe_config, conn_state);
-       intel_edp_backlight_on(pipe_config, conn_state);
-}
-
-static void vlv_enable_dp(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *pipe_config,
-                         const struct drm_connector_state *conn_state)
-{
-       intel_edp_backlight_on(pipe_config, conn_state);
-}
-
-static void g4x_pre_enable_dp(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config,
-                             const struct drm_connector_state *conn_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = encoder->port;
-
-       intel_dp_prepare(encoder, pipe_config);
-
-       /* Only ilk+ has port A */
-       if (port == PORT_A)
-               ironlake_edp_pll_on(intel_dp, pipe_config);
-}
-
-static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
-       enum pipe pipe = intel_dp->pps_pipe;
-       i915_reg_t pp_on_reg = PP_ON_DELAYS(pipe);
-
-       WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
-
-       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
-               return;
-
-       edp_panel_vdd_off_sync(intel_dp);
-
-       /*
-        * VLV seems to get confused when multiple power sequencers
-        * have the same port selected (even if only one has power/vdd
-        * enabled). The failure manifests as vlv_wait_port_ready() failing
-        * CHV on the other hand doesn't seem to mind having the same port
-        * selected in multiple power sequencers, but let's clear the
-        * port select always when logically disconnecting a power sequencer
-        * from a port.
-        */
-       DRM_DEBUG_KMS("detaching pipe %c power sequencer from port %c\n",
-                     pipe_name(pipe), port_name(intel_dig_port->base.port));
-       I915_WRITE(pp_on_reg, 0);
-       POSTING_READ(pp_on_reg);
-
-       intel_dp->pps_pipe = INVALID_PIPE;
-}
-
-static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe)
-{
-       struct intel_encoder *encoder;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       for_each_intel_dp(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-               enum port port = encoder->port;
-
-               WARN(intel_dp->active_pipe == pipe,
-                    "stealing pipe %c power sequencer from active (e)DP port %c\n",
-                    pipe_name(pipe), port_name(port));
-
-               if (intel_dp->pps_pipe != pipe)
-                       continue;
-
-               DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
-                             pipe_name(pipe), port_name(port));
-
-               /* make sure vdd is off before we steal it */
-               vlv_detach_power_sequencer(intel_dp);
-       }
-}
-
-static void vlv_init_panel_power_sequencer(struct intel_encoder *encoder,
-                                          const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
-
-       if (intel_dp->pps_pipe != INVALID_PIPE &&
-           intel_dp->pps_pipe != crtc->pipe) {
-               /*
-                * If another power sequencer was being used on this
-                * port previously make sure to turn off vdd there while
-                * we still have control of it.
-                */
-               vlv_detach_power_sequencer(intel_dp);
-       }
-
-       /*
-        * We may be stealing the power
-        * sequencer from another port.
-        */
-       vlv_steal_power_sequencer(dev_priv, crtc->pipe);
-
-       intel_dp->active_pipe = crtc->pipe;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       /* now it's all ours */
-       intel_dp->pps_pipe = crtc->pipe;
-
-       DRM_DEBUG_KMS("initializing pipe %c power sequencer for port %c\n",
-                     pipe_name(intel_dp->pps_pipe), port_name(encoder->port));
-
-       /* init power sequencer on this pipe and port */
-       intel_dp_init_panel_power_sequencer(intel_dp);
-       intel_dp_init_panel_power_sequencer_registers(intel_dp, true);
-}
-
-static void vlv_pre_enable_dp(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config,
-                             const struct drm_connector_state *conn_state)
-{
-       vlv_phy_pre_encoder_enable(encoder, pipe_config);
-
-       intel_enable_dp(encoder, pipe_config, conn_state);
-}
-
-static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config,
-                                 const struct drm_connector_state *conn_state)
-{
-       intel_dp_prepare(encoder, pipe_config);
-
-       vlv_phy_pre_pll_enable(encoder, pipe_config);
-}
-
-static void chv_pre_enable_dp(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config,
-                             const struct drm_connector_state *conn_state)
-{
-       chv_phy_pre_encoder_enable(encoder, pipe_config);
-
-       intel_enable_dp(encoder, pipe_config, conn_state);
-
-       /* Second common lane will stay alive on its own now */
-       chv_phy_release_cl2_override(encoder);
-}
-
-static void chv_dp_pre_pll_enable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config,
-                                 const struct drm_connector_state *conn_state)
-{
-       intel_dp_prepare(encoder, pipe_config);
-
-       chv_phy_pre_pll_enable(encoder, pipe_config);
-}
-
-static void chv_dp_post_pll_disable(struct intel_encoder *encoder,
-                                   const struct intel_crtc_state *old_crtc_state,
-                                   const struct drm_connector_state *old_conn_state)
-{
-       chv_phy_post_pll_disable(encoder, old_crtc_state);
-}
-
-/*
- * Fetch AUX CH registers 0x202 - 0x207 which contain
- * link status information
- */
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
-{
-       return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
-                               DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
-}
-
-/* These are source-specific values. */
-u8
-intel_dp_voltage_max(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       enum port port = encoder->port;
-
-       if (HAS_DDI(dev_priv))
-               return intel_ddi_dp_voltage_max(encoder);
-       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
-       else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A)
-               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
-       else if (HAS_PCH_CPT(dev_priv) && port != PORT_A)
-               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
-       else
-               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
-}
-
-u8
-intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, u8 voltage_swing)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       enum port port = encoder->port;
-
-       if (HAS_DDI(dev_priv)) {
-               return intel_ddi_dp_pre_emphasis_max(encoder, voltage_swing);
-       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
-               default:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
-               }
-       } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) {
-               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
-               default:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
-               }
-       } else {
-               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
-               default:
-                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
-               }
-       }
-}
-
-static u32 vlv_signal_levels(struct intel_dp *intel_dp)
-{
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       unsigned long demph_reg_value, preemph_reg_value,
-               uniqtranscale_reg_value;
-       u8 train_set = intel_dp->train_set[0];
-
-       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPH_LEVEL_0:
-               preemph_reg_value = 0x0004000;
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       demph_reg_value = 0x2B405555;
-                       uniqtranscale_reg_value = 0x552AB83A;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       demph_reg_value = 0x2B404040;
-                       uniqtranscale_reg_value = 0x5548B83A;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       demph_reg_value = 0x2B245555;
-                       uniqtranscale_reg_value = 0x5560B83A;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
-                       demph_reg_value = 0x2B405555;
-                       uniqtranscale_reg_value = 0x5598DA3A;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_1:
-               preemph_reg_value = 0x0002000;
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       demph_reg_value = 0x2B404040;
-                       uniqtranscale_reg_value = 0x5552B83A;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       demph_reg_value = 0x2B404848;
-                       uniqtranscale_reg_value = 0x5580B83A;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       demph_reg_value = 0x2B404040;
-                       uniqtranscale_reg_value = 0x55ADDA3A;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_2:
-               preemph_reg_value = 0x0000000;
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       demph_reg_value = 0x2B305555;
-                       uniqtranscale_reg_value = 0x5570B83A;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       demph_reg_value = 0x2B2B4040;
-                       uniqtranscale_reg_value = 0x55ADDA3A;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_3:
-               preemph_reg_value = 0x0006000;
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       demph_reg_value = 0x1B405555;
-                       uniqtranscale_reg_value = 0x55ADDA3A;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       default:
-               return 0;
-       }
-
-       vlv_set_phy_signal_level(encoder, demph_reg_value, preemph_reg_value,
-                                uniqtranscale_reg_value, 0);
-
-       return 0;
-}
-
-static u32 chv_signal_levels(struct intel_dp *intel_dp)
-{
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       u32 deemph_reg_value, margin_reg_value;
-       bool uniq_trans_scale = false;
-       u8 train_set = intel_dp->train_set[0];
-
-       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPH_LEVEL_0:
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       deemph_reg_value = 128;
-                       margin_reg_value = 52;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       deemph_reg_value = 128;
-                       margin_reg_value = 77;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       deemph_reg_value = 128;
-                       margin_reg_value = 102;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
-                       deemph_reg_value = 128;
-                       margin_reg_value = 154;
-                       uniq_trans_scale = true;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_1:
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       deemph_reg_value = 85;
-                       margin_reg_value = 78;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       deemph_reg_value = 85;
-                       margin_reg_value = 116;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-                       deemph_reg_value = 85;
-                       margin_reg_value = 154;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_2:
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       deemph_reg_value = 64;
-                       margin_reg_value = 104;
-                       break;
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-                       deemph_reg_value = 64;
-                       margin_reg_value = 154;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_3:
-               switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-                       deemph_reg_value = 43;
-                       margin_reg_value = 154;
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       default:
-               return 0;
-       }
-
-       chv_set_phy_signal_level(encoder, deemph_reg_value,
-                                margin_reg_value, uniq_trans_scale);
-
-       return 0;
-}
-
-static u32
-g4x_signal_levels(u8 train_set)
-{
-       u32 signal_levels = 0;
-
-       switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
-       default:
-               signal_levels |= DP_VOLTAGE_0_4;
-               break;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
-               signal_levels |= DP_VOLTAGE_0_6;
-               break;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
-               signal_levels |= DP_VOLTAGE_0_8;
-               break;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
-               signal_levels |= DP_VOLTAGE_1_2;
-               break;
-       }
-       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPH_LEVEL_0:
-       default:
-               signal_levels |= DP_PRE_EMPHASIS_0;
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_1:
-               signal_levels |= DP_PRE_EMPHASIS_3_5;
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_2:
-               signal_levels |= DP_PRE_EMPHASIS_6;
-               break;
-       case DP_TRAIN_PRE_EMPH_LEVEL_3:
-               signal_levels |= DP_PRE_EMPHASIS_9_5;
-               break;
-       }
-       return signal_levels;
-}
-
-/* SNB CPU eDP voltage swing and pre-emphasis control */
-static u32
-snb_cpu_edp_signal_levels(u8 train_set)
-{
-       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
-                                        DP_TRAIN_PRE_EMPHASIS_MASK);
-       switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
-               return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B;
-       default:
-               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
-                             "0x%x\n", signal_levels);
-               return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
-       }
-}
-
-/* IVB CPU eDP voltage swing and pre-emphasis control */
-static u32
-ivb_cpu_edp_signal_levels(u8 train_set)
-{
-       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
-                                        DP_TRAIN_PRE_EMPHASIS_MASK);
-       switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return EDP_LINK_TRAIN_400MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
-               return EDP_LINK_TRAIN_400MV_6DB_IVB;
-
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return EDP_LINK_TRAIN_600MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return EDP_LINK_TRAIN_600MV_3_5DB_IVB;
-
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return EDP_LINK_TRAIN_800MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return EDP_LINK_TRAIN_800MV_3_5DB_IVB;
-
-       default:
-               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
-                             "0x%x\n", signal_levels);
-               return EDP_LINK_TRAIN_500MV_0DB_IVB;
-       }
-}
-
-void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum port port = intel_dig_port->base.port;
-       u32 signal_levels, mask = 0;
-       u8 train_set = intel_dp->train_set[0];
-
-       if (IS_GEN9_LP(dev_priv) || INTEL_GEN(dev_priv) >= 10) {
-               signal_levels = bxt_signal_levels(intel_dp);
-       } else if (HAS_DDI(dev_priv)) {
-               signal_levels = ddi_signal_levels(intel_dp);
-               mask = DDI_BUF_EMP_MASK;
-       } else if (IS_CHERRYVIEW(dev_priv)) {
-               signal_levels = chv_signal_levels(intel_dp);
-       } else if (IS_VALLEYVIEW(dev_priv)) {
-               signal_levels = vlv_signal_levels(intel_dp);
-       } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) {
-               signal_levels = ivb_cpu_edp_signal_levels(train_set);
-               mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
-       } else if (IS_GEN(dev_priv, 6) && port == PORT_A) {
-               signal_levels = snb_cpu_edp_signal_levels(train_set);
-               mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB;
-       } else {
-               signal_levels = g4x_signal_levels(train_set);
-               mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK;
-       }
-
-       if (mask)
-               DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels);
-
-       DRM_DEBUG_KMS("Using vswing level %d\n",
-               train_set & DP_TRAIN_VOLTAGE_SWING_MASK);
-       DRM_DEBUG_KMS("Using pre-emphasis level %d\n",
-               (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
-                       DP_TRAIN_PRE_EMPHASIS_SHIFT);
-
-       intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels;
-
-       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-       POSTING_READ(intel_dp->output_reg);
-}
-
-void
-intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
-                                      u8 dp_train_pat)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv =
-               to_i915(intel_dig_port->base.base.dev);
-
-       _intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat);
-
-       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-       POSTING_READ(intel_dp->output_reg);
-}
-
-void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum port port = intel_dig_port->base.port;
-       u32 val;
-
-       if (!HAS_DDI(dev_priv))
-               return;
-
-       val = I915_READ(DP_TP_CTL(port));
-       val &= ~DP_TP_CTL_LINK_TRAIN_MASK;
-       val |= DP_TP_CTL_LINK_TRAIN_IDLE;
-       I915_WRITE(DP_TP_CTL(port), val);
-
-       /*
-        * On PORT_A we can have only eDP in SST mode. There the only reason
-        * we need to set idle transmission mode is to work around a HW issue
-        * where we enable the pipe while not in idle link-training mode.
-        * In this case there is requirement to wait for a minimum number of
-        * idle patterns to be sent.
-        */
-       if (port == PORT_A)
-               return;
-
-       if (intel_wait_for_register(&dev_priv->uncore, DP_TP_STATUS(port),
-                                   DP_TP_STATUS_IDLE_DONE,
-                                   DP_TP_STATUS_IDLE_DONE,
-                                   1))
-               DRM_ERROR("Timed out waiting for DP idle patterns\n");
-}
-
-static void
-intel_dp_link_down(struct intel_encoder *encoder,
-                  const struct intel_crtc_state *old_crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
-       enum port port = encoder->port;
-       u32 DP = intel_dp->DP;
-
-       if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) ||
-           (HAS_PCH_CPT(dev_priv) && port != PORT_A)) {
-               DP &= ~DP_LINK_TRAIN_MASK_CPT;
-               DP |= DP_LINK_TRAIN_PAT_IDLE_CPT;
-       } else {
-               DP &= ~DP_LINK_TRAIN_MASK;
-               DP |= DP_LINK_TRAIN_PAT_IDLE;
-       }
-       I915_WRITE(intel_dp->output_reg, DP);
-       POSTING_READ(intel_dp->output_reg);
-
-       DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
-       I915_WRITE(intel_dp->output_reg, DP);
-       POSTING_READ(intel_dp->output_reg);
-
-       /*
-        * HW workaround for IBX, we need to move the port
-        * to transcoder A after disabling it to allow the
-        * matching HDMI port to be enabled on transcoder A.
-        */
-       if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B && port != PORT_A) {
-               /*
-                * We get CPU/PCH FIFO underruns on the other pipe when
-                * doing the workaround. Sweep them under the rug.
-                */
-               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-
-               /* always enable with pattern 1 (as per spec) */
-               DP &= ~(DP_PIPE_SEL_MASK | DP_LINK_TRAIN_MASK);
-               DP |= DP_PORT_EN | DP_PIPE_SEL(PIPE_A) |
-                       DP_LINK_TRAIN_PAT_1;
-               I915_WRITE(intel_dp->output_reg, DP);
-               POSTING_READ(intel_dp->output_reg);
-
-               DP &= ~DP_PORT_EN;
-               I915_WRITE(intel_dp->output_reg, DP);
-               POSTING_READ(intel_dp->output_reg);
-
-               intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
-               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-       }
-
-       msleep(intel_dp->panel_power_down_delay);
-
-       intel_dp->DP = DP;
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               intel_wakeref_t wakeref;
-
-               with_pps_lock(intel_dp, wakeref)
-                       intel_dp->active_pipe = INVALID_PIPE;
-       }
-}
-
-static void
-intel_dp_extended_receiver_capabilities(struct intel_dp *intel_dp)
-{
-       u8 dpcd_ext[6];
-
-       /*
-        * Prior to DP1.3 the bit represented by
-        * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
-        * if it is set DP_DPCD_REV at 0000h could be at a value less than
-        * the true capability of the panel. The only way to check is to
-        * then compare 0000h and 2200h.
-        */
-       if (!(intel_dp->dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
-             DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
-               return;
-
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_DP13_DPCD_REV,
-                            &dpcd_ext, sizeof(dpcd_ext)) != sizeof(dpcd_ext)) {
-               DRM_ERROR("DPCD failed read at extended capabilities\n");
-               return;
-       }
-
-       if (intel_dp->dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
-               DRM_DEBUG_KMS("DPCD extended DPCD rev less than base DPCD rev\n");
-               return;
-       }
-
-       if (!memcmp(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext)))
-               return;
-
-       DRM_DEBUG_KMS("Base DPCD: %*ph\n",
-                     (int)sizeof(intel_dp->dpcd), intel_dp->dpcd);
-
-       memcpy(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext));
-}
-
-bool
-intel_dp_read_dpcd(struct intel_dp *intel_dp)
-{
-       if (drm_dp_dpcd_read(&intel_dp->aux, 0x000, intel_dp->dpcd,
-                            sizeof(intel_dp->dpcd)) < 0)
-               return false; /* aux transfer failed */
-
-       intel_dp_extended_receiver_capabilities(intel_dp);
-
-       DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd);
-
-       return intel_dp->dpcd[DP_DPCD_REV] != 0;
-}
-
-bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
-{
-       u8 dprx = 0;
-
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
-                             &dprx) != 1)
-               return false;
-       return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
-}
-
-static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp)
-{
-       /*
-        * Clear the cached register set to avoid using stale values
-        * for the sinks that do not support DSC.
-        */
-       memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
-
-       /* Clear fec_capable to avoid using stale values */
-       intel_dp->fec_capable = 0;
-
-       /* Cache the DSC DPCD if eDP or DP rev >= 1.4 */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x14 ||
-           intel_dp->edp_dpcd[0] >= DP_EDP_14) {
-               if (drm_dp_dpcd_read(&intel_dp->aux, DP_DSC_SUPPORT,
-                                    intel_dp->dsc_dpcd,
-                                    sizeof(intel_dp->dsc_dpcd)) < 0)
-                       DRM_ERROR("Failed to read DPCD register 0x%x\n",
-                                 DP_DSC_SUPPORT);
-
-               DRM_DEBUG_KMS("DSC DPCD: %*ph\n",
-                             (int)sizeof(intel_dp->dsc_dpcd),
-                             intel_dp->dsc_dpcd);
-
-               /* FEC is supported only on DP 1.4 */
-               if (!intel_dp_is_edp(intel_dp) &&
-                   drm_dp_dpcd_readb(&intel_dp->aux, DP_FEC_CAPABILITY,
-                                     &intel_dp->fec_capable) < 0)
-                       DRM_ERROR("Failed to read FEC DPCD register\n");
-
-               DRM_DEBUG_KMS("FEC CAPABILITY: %x\n", intel_dp->fec_capable);
-       }
-}
-
-static bool
-intel_edp_init_dpcd(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv =
-               to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
-
-       /* this function is meant to be called only once */
-       WARN_ON(intel_dp->dpcd[DP_DPCD_REV] != 0);
-
-       if (!intel_dp_read_dpcd(intel_dp))
-               return false;
-
-       drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
-                        drm_dp_is_branch(intel_dp->dpcd));
-
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
-               dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
-                       DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
-
-       /*
-        * Read the eDP display control registers.
-        *
-        * Do this independent of DP_DPCD_DISPLAY_CONTROL_CAPABLE bit in
-        * DP_EDP_CONFIGURATION_CAP, because some buggy displays do not have it
-        * set, but require eDP 1.4+ detection (e.g. for supported link rates
-        * method). The display control registers should read zero if they're
-        * not supported anyway.
-        */
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
-                            intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
-                            sizeof(intel_dp->edp_dpcd))
-               DRM_DEBUG_KMS("eDP DPCD: %*ph\n", (int) sizeof(intel_dp->edp_dpcd),
-                             intel_dp->edp_dpcd);
-
-       /*
-        * This has to be called after intel_dp->edp_dpcd is filled, PSR checks
-        * for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1]
-        */
-       intel_psr_init_dpcd(intel_dp);
-
-       /* Read the eDP 1.4+ supported link rates. */
-       if (intel_dp->edp_dpcd[0] >= DP_EDP_14) {
-               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
-               int i;
-
-               drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
-                               sink_rates, sizeof(sink_rates));
-
-               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
-                       int val = le16_to_cpu(sink_rates[i]);
-
-                       if (val == 0)
-                               break;
-
-                       /* Value read multiplied by 200kHz gives the per-lane
-                        * link rate in kHz. The source rates are, however,
-                        * stored in terms of LS_Clk kHz. The full conversion
-                        * back to symbols is
-                        * (val * 200kHz)*(8/10 ch. encoding)*(1/8 bit to Byte)
-                        */
-                       intel_dp->sink_rates[i] = (val * 200) / 10;
-               }
-               intel_dp->num_sink_rates = i;
-       }
-
-       /*
-        * Use DP_LINK_RATE_SET if DP_SUPPORTED_LINK_RATES are available,
-        * default to DP_MAX_LINK_RATE and DP_LINK_BW_SET otherwise.
-        */
-       if (intel_dp->num_sink_rates)
-               intel_dp->use_rate_select = true;
-       else
-               intel_dp_set_sink_rates(intel_dp);
-
-       intel_dp_set_common_rates(intel_dp);
-
-       /* Read the eDP DSC DPCD registers */
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               intel_dp_get_dsc_sink_cap(intel_dp);
-
-       return true;
-}
-
-
-static bool
-intel_dp_get_dpcd(struct intel_dp *intel_dp)
-{
-       if (!intel_dp_read_dpcd(intel_dp))
-               return false;
-
-       /* Don't clobber cached eDP rates. */
-       if (!intel_dp_is_edp(intel_dp)) {
-               intel_dp_set_sink_rates(intel_dp);
-               intel_dp_set_common_rates(intel_dp);
-       }
-
-       /*
-        * Some eDP panels do not set a valid value for sink count, that is why
-        * it don't care about read it here and in intel_edp_init_dpcd().
-        */
-       if (!intel_dp_is_edp(intel_dp)) {
-               u8 count;
-               ssize_t r;
-
-               r = drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, &count);
-               if (r < 1)
-                       return false;
-
-               /*
-                * Sink count can change between short pulse hpd hence
-                * a member variable in intel_dp will track any changes
-                * between short pulse interrupts.
-                */
-               intel_dp->sink_count = DP_GET_SINK_COUNT(count);
-
-               /*
-                * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
-                * a dongle is present but no display. Unless we require to know
-                * if a dongle is present or not, we don't need to update
-                * downstream port information. So, an early return here saves
-                * time from performing other operations which are not required.
-                */
-               if (!intel_dp->sink_count)
-                       return false;
-       }
-
-       if (!drm_dp_is_branch(intel_dp->dpcd))
-               return true; /* native DP sink */
-
-       if (intel_dp->dpcd[DP_DPCD_REV] == 0x10)
-               return true; /* no per-port downstream info */
-
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_DOWNSTREAM_PORT_0,
-                            intel_dp->downstream_ports,
-                            DP_MAX_DOWNSTREAM_PORTS) < 0)
-               return false; /* downstream port status fetch failed */
-
-       return true;
-}
-
-static bool
-intel_dp_sink_can_mst(struct intel_dp *intel_dp)
-{
-       u8 mstm_cap;
-
-       if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
-               return false;
-
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_MSTM_CAP, &mstm_cap) != 1)
-               return false;
-
-       return mstm_cap & DP_MST_CAP;
-}
-
-static bool
-intel_dp_can_mst(struct intel_dp *intel_dp)
-{
-       return i915_modparams.enable_dp_mst &&
-               intel_dp->can_mst &&
-               intel_dp_sink_can_mst(intel_dp);
-}
-
-static void
-intel_dp_configure_mst(struct intel_dp *intel_dp)
-{
-       struct intel_encoder *encoder =
-               &dp_to_dig_port(intel_dp)->base;
-       bool sink_can_mst = intel_dp_sink_can_mst(intel_dp);
-
-       DRM_DEBUG_KMS("MST support? port %c: %s, sink: %s, modparam: %s\n",
-                     port_name(encoder->port), yesno(intel_dp->can_mst),
-                     yesno(sink_can_mst), yesno(i915_modparams.enable_dp_mst));
-
-       if (!intel_dp->can_mst)
-               return;
-
-       intel_dp->is_mst = sink_can_mst &&
-               i915_modparams.enable_dp_mst;
-
-       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
-                                       intel_dp->is_mst);
-}
-
-static bool
-intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
-{
-       return drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT_ESI,
-                               sink_irq_vector, DP_DPRX_ESI_LEN) ==
-               DP_DPRX_ESI_LEN;
-}
-
-u16 intel_dp_dsc_get_output_bpp(int link_clock, u8 lane_count,
-                               int mode_clock, int mode_hdisplay)
-{
-       u16 bits_per_pixel, max_bpp_small_joiner_ram;
-       int i;
-
-       /*
-        * Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)*
-        * (LinkSymbolClock)* 8 * ((100-FECOverhead)/100)*(TimeSlotsPerMTP)
-        * FECOverhead = 2.4%, for SST -> TimeSlotsPerMTP is 1,
-        * for MST -> TimeSlotsPerMTP has to be calculated
-        */
-       bits_per_pixel = (link_clock * lane_count * 8 *
-                         DP_DSC_FEC_OVERHEAD_FACTOR) /
-               mode_clock;
-
-       /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */
-       max_bpp_small_joiner_ram = DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER /
-               mode_hdisplay;
-
-       /*
-        * Greatest allowed DSC BPP = MIN (output BPP from avaialble Link BW
-        * check, output bpp from small joiner RAM check)
-        */
-       bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram);
-
-       /* Error out if the max bpp is less than smallest allowed valid bpp */
-       if (bits_per_pixel < valid_dsc_bpp[0]) {
-               DRM_DEBUG_KMS("Unsupported BPP %d\n", bits_per_pixel);
-               return 0;
-       }
-
-       /* Find the nearest match in the array of known BPPs from VESA */
-       for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
-               if (bits_per_pixel < valid_dsc_bpp[i + 1])
-                       break;
-       }
-       bits_per_pixel = valid_dsc_bpp[i];
-
-       /*
-        * Compressed BPP in U6.4 format so multiply by 16, for Gen 11,
-        * fractional part is 0
-        */
-       return bits_per_pixel << 4;
-}
-
-u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
-                               int mode_clock,
-                               int mode_hdisplay)
-{
-       u8 min_slice_count, i;
-       int max_slice_width;
-
-       if (mode_clock <= DP_DSC_PEAK_PIXEL_RATE)
-               min_slice_count = DIV_ROUND_UP(mode_clock,
-                                              DP_DSC_MAX_ENC_THROUGHPUT_0);
-       else
-               min_slice_count = DIV_ROUND_UP(mode_clock,
-                                              DP_DSC_MAX_ENC_THROUGHPUT_1);
-
-       max_slice_width = drm_dp_dsc_sink_max_slice_width(intel_dp->dsc_dpcd);
-       if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) {
-               DRM_DEBUG_KMS("Unsupported slice width %d by DP DSC Sink device\n",
-                             max_slice_width);
-               return 0;
-       }
-       /* Also take into account max slice width */
-       min_slice_count = min_t(u8, min_slice_count,
-                               DIV_ROUND_UP(mode_hdisplay,
-                                            max_slice_width));
-
-       /* Find the closest match to the valid slice count values */
-       for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) {
-               if (valid_dsc_slicecount[i] >
-                   drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
-                                                   false))
-                       break;
-               if (min_slice_count  <= valid_dsc_slicecount[i])
-                       return valid_dsc_slicecount[i];
-       }
-
-       DRM_DEBUG_KMS("Unsupported Slice Count %d\n", min_slice_count);
-       return 0;
-}
-
-static void
-intel_pixel_encoding_setup_vsc(struct intel_dp *intel_dp,
-                              const struct intel_crtc_state *crtc_state)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct dp_sdp vsc_sdp = {};
-
-       /* Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119 */
-       vsc_sdp.sdp_header.HB0 = 0;
-       vsc_sdp.sdp_header.HB1 = 0x7;
-
-       /*
-        * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
-        * Colorimetry Format indication.
-        */
-       vsc_sdp.sdp_header.HB2 = 0x5;
-
-       /*
-        * VSC SDP supporting 3D stereo, + PSR2, + Pixel Encoding/
-        * Colorimetry Format indication (HB2 = 05h).
-        */
-       vsc_sdp.sdp_header.HB3 = 0x13;
-
-       /*
-        * YCbCr 420 = 3h DB16[7:4] ITU-R BT.601 = 0h, ITU-R BT.709 = 1h
-        * DB16[3:0] DP 1.4a spec, Table 2-120
-        */
-       vsc_sdp.db[16] = 0x3 << 4; /* 0x3 << 4 , YCbCr 420*/
-       /* RGB->YCBCR color conversion uses the BT.709 color space. */
-       vsc_sdp.db[16] |= 0x1; /* 0x1, ITU-R BT.709 */
-
-       /*
-        * For pixel encoding formats YCbCr444, YCbCr422, YCbCr420, and Y Only,
-        * the following Component Bit Depth values are defined:
-        * 001b = 8bpc.
-        * 010b = 10bpc.
-        * 011b = 12bpc.
-        * 100b = 16bpc.
-        */
-       switch (crtc_state->pipe_bpp) {
-       case 24: /* 8bpc */
-               vsc_sdp.db[17] = 0x1;
-               break;
-       case 30: /* 10bpc */
-               vsc_sdp.db[17] = 0x2;
-               break;
-       case 36: /* 12bpc */
-               vsc_sdp.db[17] = 0x3;
-               break;
-       case 48: /* 16bpc */
-               vsc_sdp.db[17] = 0x4;
-               break;
-       default:
-               MISSING_CASE(crtc_state->pipe_bpp);
-               break;
-       }
-
-       /*
-        * Dynamic Range (Bit 7)
-        * 0 = VESA range, 1 = CTA range.
-        * all YCbCr are always limited range
-        */
-       vsc_sdp.db[17] |= 0x80;
-
-       /*
-        * Content Type (Bits 2:0)
-        * 000b = Not defined.
-        * 001b = Graphics.
-        * 010b = Photo.
-        * 011b = Video.
-        * 100b = Game
-        * All other values are RESERVED.
-        * Note: See CTA-861-G for the definition and expected
-        * processing by a stream sink for the above contect types.
-        */
-       vsc_sdp.db[18] = 0;
-
-       intel_dig_port->write_infoframe(&intel_dig_port->base,
-                       crtc_state, DP_SDP_VSC, &vsc_sdp, sizeof(vsc_sdp));
-}
-
-void intel_dp_ycbcr_420_enable(struct intel_dp *intel_dp,
-                              const struct intel_crtc_state *crtc_state)
-{
-       if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
-               return;
-
-       intel_pixel_encoding_setup_vsc(intel_dp, crtc_state);
-}
-
-static u8 intel_dp_autotest_link_training(struct intel_dp *intel_dp)
-{
-       int status = 0;
-       int test_link_rate;
-       u8 test_lane_count, test_link_bw;
-       /* (DP CTS 1.2)
-        * 4.3.1.11
-        */
-       /* Read the TEST_LANE_COUNT and TEST_LINK_RTAE fields (DP CTS 3.1.4) */
-       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LANE_COUNT,
-                                  &test_lane_count);
-
-       if (status <= 0) {
-               DRM_DEBUG_KMS("Lane count read failed\n");
-               return DP_TEST_NAK;
-       }
-       test_lane_count &= DP_MAX_LANE_COUNT_MASK;
-
-       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE,
-                                  &test_link_bw);
-       if (status <= 0) {
-               DRM_DEBUG_KMS("Link Rate read failed\n");
-               return DP_TEST_NAK;
-       }
-       test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw);
-
-       /* Validate the requested link rate and lane count */
-       if (!intel_dp_link_params_valid(intel_dp, test_link_rate,
-                                       test_lane_count))
-               return DP_TEST_NAK;
-
-       intel_dp->compliance.test_lane_count = test_lane_count;
-       intel_dp->compliance.test_link_rate = test_link_rate;
-
-       return DP_TEST_ACK;
-}
-
-static u8 intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
-{
-       u8 test_pattern;
-       u8 test_misc;
-       __be16 h_width, v_height;
-       int status = 0;
-
-       /* Read the TEST_PATTERN (DP CTS 3.1.5) */
-       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_PATTERN,
-                                  &test_pattern);
-       if (status <= 0) {
-               DRM_DEBUG_KMS("Test pattern read failed\n");
-               return DP_TEST_NAK;
-       }
-       if (test_pattern != DP_COLOR_RAMP)
-               return DP_TEST_NAK;
-
-       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_H_WIDTH_HI,
-                                 &h_width, 2);
-       if (status <= 0) {
-               DRM_DEBUG_KMS("H Width read failed\n");
-               return DP_TEST_NAK;
-       }
-
-       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_V_HEIGHT_HI,
-                                 &v_height, 2);
-       if (status <= 0) {
-               DRM_DEBUG_KMS("V Height read failed\n");
-               return DP_TEST_NAK;
-       }
-
-       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_MISC0,
-                                  &test_misc);
-       if (status <= 0) {
-               DRM_DEBUG_KMS("TEST MISC read failed\n");
-               return DP_TEST_NAK;
-       }
-       if ((test_misc & DP_TEST_COLOR_FORMAT_MASK) != DP_COLOR_FORMAT_RGB)
-               return DP_TEST_NAK;
-       if (test_misc & DP_TEST_DYNAMIC_RANGE_CEA)
-               return DP_TEST_NAK;
-       switch (test_misc & DP_TEST_BIT_DEPTH_MASK) {
-       case DP_TEST_BIT_DEPTH_6:
-               intel_dp->compliance.test_data.bpc = 6;
-               break;
-       case DP_TEST_BIT_DEPTH_8:
-               intel_dp->compliance.test_data.bpc = 8;
-               break;
-       default:
-               return DP_TEST_NAK;
-       }
-
-       intel_dp->compliance.test_data.video_pattern = test_pattern;
-       intel_dp->compliance.test_data.hdisplay = be16_to_cpu(h_width);
-       intel_dp->compliance.test_data.vdisplay = be16_to_cpu(v_height);
-       /* Set test active flag here so userspace doesn't interrupt things */
-       intel_dp->compliance.test_active = 1;
-
-       return DP_TEST_ACK;
-}
-
-static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
-{
-       u8 test_result = DP_TEST_ACK;
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-       struct drm_connector *connector = &intel_connector->base;
-
-       if (intel_connector->detect_edid == NULL ||
-           connector->edid_corrupt ||
-           intel_dp->aux.i2c_defer_count > 6) {
-               /* Check EDID read for NACKs, DEFERs and corruption
-                * (DP CTS 1.2 Core r1.1)
-                *    4.2.2.4 : Failed EDID read, I2C_NAK
-                *    4.2.2.5 : Failed EDID read, I2C_DEFER
-                *    4.2.2.6 : EDID corruption detected
-                * Use failsafe mode for all cases
-                */
-               if (intel_dp->aux.i2c_nack_count > 0 ||
-                       intel_dp->aux.i2c_defer_count > 0)
-                       DRM_DEBUG_KMS("EDID read had %d NACKs, %d DEFERs\n",
-                                     intel_dp->aux.i2c_nack_count,
-                                     intel_dp->aux.i2c_defer_count);
-               intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_FAILSAFE;
-       } else {
-               struct edid *block = intel_connector->detect_edid;
-
-               /* We have to write the checksum
-                * of the last block read
-                */
-               block += intel_connector->detect_edid->extensions;
-
-               if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
-                                      block->checksum) <= 0)
-                       DRM_DEBUG_KMS("Failed to write EDID checksum\n");
-
-               test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE;
-               intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_PREFERRED;
-       }
-
-       /* Set test active flag here so userspace doesn't interrupt things */
-       intel_dp->compliance.test_active = 1;
-
-       return test_result;
-}
-
-static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
-{
-       u8 test_result = DP_TEST_NAK;
-       return test_result;
-}
-
-static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
-{
-       u8 response = DP_TEST_NAK;
-       u8 request = 0;
-       int status;
-
-       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_REQUEST, &request);
-       if (status <= 0) {
-               DRM_DEBUG_KMS("Could not read test request from sink\n");
-               goto update_status;
-       }
-
-       switch (request) {
-       case DP_TEST_LINK_TRAINING:
-               DRM_DEBUG_KMS("LINK_TRAINING test requested\n");
-               response = intel_dp_autotest_link_training(intel_dp);
-               break;
-       case DP_TEST_LINK_VIDEO_PATTERN:
-               DRM_DEBUG_KMS("TEST_PATTERN test requested\n");
-               response = intel_dp_autotest_video_pattern(intel_dp);
-               break;
-       case DP_TEST_LINK_EDID_READ:
-               DRM_DEBUG_KMS("EDID test requested\n");
-               response = intel_dp_autotest_edid(intel_dp);
-               break;
-       case DP_TEST_LINK_PHY_TEST_PATTERN:
-               DRM_DEBUG_KMS("PHY_PATTERN test requested\n");
-               response = intel_dp_autotest_phy_pattern(intel_dp);
-               break;
-       default:
-               DRM_DEBUG_KMS("Invalid test request '%02x'\n", request);
-               break;
-       }
-
-       if (response & DP_TEST_ACK)
-               intel_dp->compliance.test_type = request;
-
-update_status:
-       status = drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, response);
-       if (status <= 0)
-               DRM_DEBUG_KMS("Could not write test response to sink\n");
-}
-
-static int
-intel_dp_check_mst_status(struct intel_dp *intel_dp)
-{
-       bool bret;
-
-       if (intel_dp->is_mst) {
-               u8 esi[DP_DPRX_ESI_LEN] = { 0 };
-               int ret = 0;
-               int retry;
-               bool handled;
-
-               WARN_ON_ONCE(intel_dp->active_mst_links < 0);
-               bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
-go_again:
-               if (bret == true) {
-
-                       /* check link status - esi[10] = 0x200c */
-                       if (intel_dp->active_mst_links > 0 &&
-                           !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
-                               DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
-                               intel_dp_start_link_train(intel_dp);
-                               intel_dp_stop_link_train(intel_dp);
-                       }
-
-                       DRM_DEBUG_KMS("got esi %3ph\n", esi);
-                       ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
-
-                       if (handled) {
-                               for (retry = 0; retry < 3; retry++) {
-                                       int wret;
-                                       wret = drm_dp_dpcd_write(&intel_dp->aux,
-                                                                DP_SINK_COUNT_ESI+1,
-                                                                &esi[1], 3);
-                                       if (wret == 3) {
-                                               break;
-                                       }
-                               }
-
-                               bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
-                               if (bret == true) {
-                                       DRM_DEBUG_KMS("got esi2 %3ph\n", esi);
-                                       goto go_again;
-                               }
-                       } else
-                               ret = 0;
-
-                       return ret;
-               } else {
-                       DRM_DEBUG_KMS("failed to get ESI - device may have failed\n");
-                       intel_dp->is_mst = false;
-                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
-                                                       intel_dp->is_mst);
-               }
-       }
-       return -EINVAL;
-}
-
-static bool
-intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
-{
-       u8 link_status[DP_LINK_STATUS_SIZE];
-
-       if (!intel_dp->link_trained)
-               return false;
-
-       /*
-        * While PSR source HW is enabled, it will control main-link sending
-        * frames, enabling and disabling it so trying to do a retrain will fail
-        * as the link would or not be on or it could mix training patterns
-        * and frame data at the same time causing retrain to fail.
-        * Also when exiting PSR, HW will retrain the link anyways fixing
-        * any link status error.
-        */
-       if (intel_psr_enabled(intel_dp))
-               return false;
-
-       if (!intel_dp_get_link_status(intel_dp, link_status))
-               return false;
-
-       /*
-        * Validate the cached values of intel_dp->link_rate and
-        * intel_dp->lane_count before attempting to retrain.
-        */
-       if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
-                                       intel_dp->lane_count))
-               return false;
-
-       /* Retrain if Channel EQ or CR not ok */
-       return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
-}
-
-int intel_dp_retrain_link(struct intel_encoder *encoder,
-                         struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_connector *connector = intel_dp->attached_connector;
-       struct drm_connector_state *conn_state;
-       struct intel_crtc_state *crtc_state;
-       struct intel_crtc *crtc;
-       int ret;
-
-       /* FIXME handle the MST connectors as well */
-
-       if (!connector || connector->base.status != connector_status_connected)
-               return 0;
-
-       ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
-                              ctx);
-       if (ret)
-               return ret;
-
-       conn_state = connector->base.state;
-
-       crtc = to_intel_crtc(conn_state->crtc);
-       if (!crtc)
-               return 0;
-
-       ret = drm_modeset_lock(&crtc->base.mutex, ctx);
-       if (ret)
-               return ret;
-
-       crtc_state = to_intel_crtc_state(crtc->base.state);
-
-       WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
-
-       if (!crtc_state->base.active)
-               return 0;
-
-       if (conn_state->commit &&
-           !try_wait_for_completion(&conn_state->commit->hw_done))
-               return 0;
-
-       if (!intel_dp_needs_link_retrain(intel_dp))
-               return 0;
-
-       /* Suppress underruns caused by re-training */
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
-       if (crtc_state->has_pch_encoder)
-               intel_set_pch_fifo_underrun_reporting(dev_priv,
-                                                     intel_crtc_pch_transcoder(crtc), false);
-
-       intel_dp_start_link_train(intel_dp);
-       intel_dp_stop_link_train(intel_dp);
-
-       /* Keep underrun reporting disabled until things are stable */
-       intel_wait_for_vblank(dev_priv, crtc->pipe);
-
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true);
-       if (crtc_state->has_pch_encoder)
-               intel_set_pch_fifo_underrun_reporting(dev_priv,
-                                                     intel_crtc_pch_transcoder(crtc), true);
-
-       return 0;
-}
-
-/*
- * If display is now connected check links status,
- * there has been known issues of link loss triggering
- * long pulse.
- *
- * Some sinks (eg. ASUS PB287Q) seem to perform some
- * weird HPD ping pong during modesets. So we can apparently
- * end up with HPD going low during a modeset, and then
- * going back up soon after. And once that happens we must
- * retrain the link to get a picture. That's in case no
- * userspace component reacted to intermittent HPD dip.
- */
-static bool intel_dp_hotplug(struct intel_encoder *encoder,
-                            struct intel_connector *connector)
-{
-       struct drm_modeset_acquire_ctx ctx;
-       bool changed;
-       int ret;
-
-       changed = intel_encoder_hotplug(encoder, connector);
-
-       drm_modeset_acquire_init(&ctx, 0);
-
-       for (;;) {
-               ret = intel_dp_retrain_link(encoder, &ctx);
-
-               if (ret == -EDEADLK) {
-                       drm_modeset_backoff(&ctx);
-                       continue;
-               }
-
-               break;
-       }
-
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-       WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
-
-       return changed;
-}
-
-static void intel_dp_check_service_irq(struct intel_dp *intel_dp)
-{
-       u8 val;
-
-       if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
-               return;
-
-       if (drm_dp_dpcd_readb(&intel_dp->aux,
-                             DP_DEVICE_SERVICE_IRQ_VECTOR, &val) != 1 || !val)
-               return;
-
-       drm_dp_dpcd_writeb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, val);
-
-       if (val & DP_AUTOMATED_TEST_REQUEST)
-               intel_dp_handle_test_request(intel_dp);
-
-       if (val & DP_CP_IRQ)
-               intel_hdcp_handle_cp_irq(intel_dp->attached_connector);
-
-       if (val & DP_SINK_SPECIFIC_IRQ)
-               DRM_DEBUG_DRIVER("Sink specific irq unhandled\n");
-}
-
-/*
- * According to DP spec
- * 5.1.2:
- *  1. Read DPCD
- *  2. Configure link according to Receiver Capabilities
- *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
- *  4. Check link status on receipt of hot-plug interrupt
- *
- * intel_dp_short_pulse -  handles short pulse interrupts
- * when full detection is not required.
- * Returns %true if short pulse is handled and full detection
- * is NOT required and %false otherwise.
- */
-static bool
-intel_dp_short_pulse(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u8 old_sink_count = intel_dp->sink_count;
-       bool ret;
-
-       /*
-        * Clearing compliance test variables to allow capturing
-        * of values for next automated test request.
-        */
-       memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
-
-       /*
-        * Now read the DPCD to see if it's actually running
-        * If the current value of sink count doesn't match with
-        * the value that was stored earlier or dpcd read failed
-        * we need to do full detection
-        */
-       ret = intel_dp_get_dpcd(intel_dp);
-
-       if ((old_sink_count != intel_dp->sink_count) || !ret) {
-               /* No need to proceed if we are going to do full detect */
-               return false;
-       }
-
-       intel_dp_check_service_irq(intel_dp);
-
-       /* Handle CEC interrupts, if any */
-       drm_dp_cec_irq(&intel_dp->aux);
-
-       /* defer to the hotplug work for link retraining if needed */
-       if (intel_dp_needs_link_retrain(intel_dp))
-               return false;
-
-       intel_psr_short_pulse(intel_dp);
-
-       if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
-               DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
-               /* Send a Hotplug Uevent to userspace to start modeset */
-               drm_kms_helper_hotplug_event(&dev_priv->drm);
-       }
-
-       return true;
-}
-
-/* XXX this is probably wrong for multiple downstream ports */
-static enum drm_connector_status
-intel_dp_detect_dpcd(struct intel_dp *intel_dp)
-{
-       struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
-       u8 *dpcd = intel_dp->dpcd;
-       u8 type;
-
-       if (WARN_ON(intel_dp_is_edp(intel_dp)))
-               return connector_status_connected;
-
-       if (lspcon->active)
-               lspcon_resume(lspcon);
-
-       if (!intel_dp_get_dpcd(intel_dp))
-               return connector_status_disconnected;
-
-       /* if there's no downstream port, we're done */
-       if (!drm_dp_is_branch(dpcd))
-               return connector_status_connected;
-
-       /* If we're HPD-aware, SINK_COUNT changes dynamically */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
-           intel_dp->downstream_ports[0] & DP_DS_PORT_HPD) {
-
-               return intel_dp->sink_count ?
-               connector_status_connected : connector_status_disconnected;
-       }
-
-       if (intel_dp_can_mst(intel_dp))
-               return connector_status_connected;
-
-       /* If no HPD, poke DDC gently */
-       if (drm_probe_ddc(&intel_dp->aux.ddc))
-               return connector_status_connected;
-
-       /* Well we tried, say unknown for unreliable port types */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
-               type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
-               if (type == DP_DS_PORT_TYPE_VGA ||
-                   type == DP_DS_PORT_TYPE_NON_EDID)
-                       return connector_status_unknown;
-       } else {
-               type = intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
-                       DP_DWN_STRM_PORT_TYPE_MASK;
-               if (type == DP_DWN_STRM_PORT_TYPE_ANALOG ||
-                   type == DP_DWN_STRM_PORT_TYPE_OTHER)
-                       return connector_status_unknown;
-       }
-
-       /* Anything else is out of spec, warn and ignore */
-       DRM_DEBUG_KMS("Broken DP branch device, ignoring\n");
-       return connector_status_disconnected;
-}
-
-static enum drm_connector_status
-edp_detect(struct intel_dp *intel_dp)
-{
-       return connector_status_connected;
-}
-
-static bool ibx_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 bit;
-
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_B:
-               bit = SDE_PORTB_HOTPLUG;
-               break;
-       case HPD_PORT_C:
-               bit = SDE_PORTC_HOTPLUG;
-               break;
-       case HPD_PORT_D:
-               bit = SDE_PORTD_HOTPLUG;
-               break;
-       default:
-               MISSING_CASE(encoder->hpd_pin);
-               return false;
-       }
-
-       return I915_READ(SDEISR) & bit;
-}
-
-static bool cpt_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 bit;
-
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_B:
-               bit = SDE_PORTB_HOTPLUG_CPT;
-               break;
-       case HPD_PORT_C:
-               bit = SDE_PORTC_HOTPLUG_CPT;
-               break;
-       case HPD_PORT_D:
-               bit = SDE_PORTD_HOTPLUG_CPT;
-               break;
-       default:
-               MISSING_CASE(encoder->hpd_pin);
-               return false;
-       }
-
-       return I915_READ(SDEISR) & bit;
-}
-
-static bool spt_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 bit;
-
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_A:
-               bit = SDE_PORTA_HOTPLUG_SPT;
-               break;
-       case HPD_PORT_E:
-               bit = SDE_PORTE_HOTPLUG_SPT;
-               break;
-       default:
-               return cpt_digital_port_connected(encoder);
-       }
-
-       return I915_READ(SDEISR) & bit;
-}
-
-static bool g4x_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 bit;
-
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_B:
-               bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
-               break;
-       case HPD_PORT_C:
-               bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
-               break;
-       case HPD_PORT_D:
-               bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
-               break;
-       default:
-               MISSING_CASE(encoder->hpd_pin);
-               return false;
-       }
-
-       return I915_READ(PORT_HOTPLUG_STAT) & bit;
-}
-
-static bool gm45_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 bit;
-
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_B:
-               bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
-               break;
-       case HPD_PORT_C:
-               bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
-               break;
-       case HPD_PORT_D:
-               bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
-               break;
-       default:
-               MISSING_CASE(encoder->hpd_pin);
-               return false;
-       }
-
-       return I915_READ(PORT_HOTPLUG_STAT) & bit;
-}
-
-static bool ilk_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (encoder->hpd_pin == HPD_PORT_A)
-               return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
-       else
-               return ibx_digital_port_connected(encoder);
-}
-
-static bool snb_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (encoder->hpd_pin == HPD_PORT_A)
-               return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
-       else
-               return cpt_digital_port_connected(encoder);
-}
-
-static bool ivb_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (encoder->hpd_pin == HPD_PORT_A)
-               return I915_READ(DEISR) & DE_DP_A_HOTPLUG_IVB;
-       else
-               return cpt_digital_port_connected(encoder);
-}
-
-static bool bdw_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (encoder->hpd_pin == HPD_PORT_A)
-               return I915_READ(GEN8_DE_PORT_ISR) & GEN8_PORT_DP_A_HOTPLUG;
-       else
-               return cpt_digital_port_connected(encoder);
-}
-
-static bool bxt_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 bit;
-
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_A:
-               bit = BXT_DE_PORT_HP_DDIA;
-               break;
-       case HPD_PORT_B:
-               bit = BXT_DE_PORT_HP_DDIB;
-               break;
-       case HPD_PORT_C:
-               bit = BXT_DE_PORT_HP_DDIC;
-               break;
-       default:
-               MISSING_CASE(encoder->hpd_pin);
-               return false;
-       }
-
-       return I915_READ(GEN8_DE_PORT_ISR) & bit;
-}
-
-static bool icl_combo_port_connected(struct drm_i915_private *dev_priv,
-                                    struct intel_digital_port *intel_dig_port)
-{
-       enum port port = intel_dig_port->base.port;
-
-       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);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-
-       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);
-       else
-               MISSING_CASE(encoder->hpd_pin);
-
-       return false;
-}
-
-/*
- * intel_digital_port_connected - is the specified port connected?
- * @encoder: intel_encoder
- *
- * In cases where there's a connector physically connected but it can't be used
- * by our hardware we also return false, since the rest of the driver should
- * pretty much treat the port as disconnected. This is relevant for type-C
- * (starting on ICL) where there's ownership involved.
- *
- * Return %true if port is connected, %false otherwise.
- */
-static bool __intel_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (HAS_GMCH(dev_priv)) {
-               if (IS_GM45(dev_priv))
-                       return gm45_digital_port_connected(encoder);
-               else
-                       return g4x_digital_port_connected(encoder);
-       }
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               return icl_digital_port_connected(encoder);
-       else if (IS_GEN(dev_priv, 10) || IS_GEN9_BC(dev_priv))
-               return spt_digital_port_connected(encoder);
-       else if (IS_GEN9_LP(dev_priv))
-               return bxt_digital_port_connected(encoder);
-       else if (IS_GEN(dev_priv, 8))
-               return bdw_digital_port_connected(encoder);
-       else if (IS_GEN(dev_priv, 7))
-               return ivb_digital_port_connected(encoder);
-       else if (IS_GEN(dev_priv, 6))
-               return snb_digital_port_connected(encoder);
-       else if (IS_GEN(dev_priv, 5))
-               return ilk_digital_port_connected(encoder);
-
-       MISSING_CASE(INTEL_GEN(dev_priv));
-       return false;
-}
-
-bool intel_digital_port_connected(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       bool is_connected = false;
-       intel_wakeref_t wakeref;
-
-       with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref)
-               is_connected = __intel_digital_port_connected(encoder);
-
-       return is_connected;
-}
-
-static struct edid *
-intel_dp_get_edid(struct intel_dp *intel_dp)
-{
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-
-       /* use cached edid if we have one */
-       if (intel_connector->edid) {
-               /* invalid edid */
-               if (IS_ERR(intel_connector->edid))
-                       return NULL;
-
-               return drm_edid_duplicate(intel_connector->edid);
-       } else
-               return drm_get_edid(&intel_connector->base,
-                                   &intel_dp->aux.ddc);
-}
-
-static void
-intel_dp_set_edid(struct intel_dp *intel_dp)
-{
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-       struct edid *edid;
-
-       intel_dp_unset_edid(intel_dp);
-       edid = intel_dp_get_edid(intel_dp);
-       intel_connector->detect_edid = edid;
-
-       intel_dp->has_audio = drm_detect_monitor_audio(edid);
-       drm_dp_cec_set_edid(&intel_dp->aux, edid);
-}
-
-static void
-intel_dp_unset_edid(struct intel_dp *intel_dp)
-{
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-
-       drm_dp_cec_unset_edid(&intel_dp->aux);
-       kfree(intel_connector->detect_edid);
-       intel_connector->detect_edid = NULL;
-
-       intel_dp->has_audio = false;
-}
-
-static int
-intel_dp_detect(struct drm_connector *connector,
-               struct drm_modeset_acquire_ctx *ctx,
-               bool force)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *encoder = &dig_port->base;
-       enum drm_connector_status status;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-       WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
-
-       /* Can't disconnect eDP */
-       if (intel_dp_is_edp(intel_dp))
-               status = edp_detect(intel_dp);
-       else if (intel_digital_port_connected(encoder))
-               status = intel_dp_detect_dpcd(intel_dp);
-       else
-               status = connector_status_disconnected;
-
-       if (status == connector_status_disconnected) {
-               memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
-               memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
-
-               if (intel_dp->is_mst) {
-                       DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
-                                     intel_dp->is_mst,
-                                     intel_dp->mst_mgr.mst_state);
-                       intel_dp->is_mst = false;
-                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
-                                                       intel_dp->is_mst);
-               }
-
-               goto out;
-       }
-
-       if (intel_dp->reset_link_params) {
-               /* Initial max link lane count */
-               intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
-
-               /* Initial max link rate */
-               intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
-
-               intel_dp->reset_link_params = false;
-       }
-
-       intel_dp_print_rates(intel_dp);
-
-       /* Read DP Sink DSC Cap DPCD regs for DP v1.4 */
-       if (INTEL_GEN(dev_priv) >= 11)
-               intel_dp_get_dsc_sink_cap(intel_dp);
-
-       drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
-                        drm_dp_is_branch(intel_dp->dpcd));
-
-       intel_dp_configure_mst(intel_dp);
-
-       if (intel_dp->is_mst) {
-               /*
-                * If we are in MST mode then this connector
-                * won't appear connected or have anything
-                * with EDID on it
-                */
-               status = connector_status_disconnected;
-               goto out;
-       }
-
-       /*
-        * Some external monitors do not signal loss of link synchronization
-        * with an IRQ_HPD, so force a link status check.
-        */
-       if (!intel_dp_is_edp(intel_dp)) {
-               int ret;
-
-               ret = intel_dp_retrain_link(encoder, ctx);
-               if (ret)
-                       return ret;
-       }
-
-       /*
-        * Clearing NACK and defer counts to get their exact values
-        * while reading EDID which are required by Compliance tests
-        * 4.2.2.4 and 4.2.2.5
-        */
-       intel_dp->aux.i2c_nack_count = 0;
-       intel_dp->aux.i2c_defer_count = 0;
-
-       intel_dp_set_edid(intel_dp);
-       if (intel_dp_is_edp(intel_dp) ||
-           to_intel_connector(connector)->detect_edid)
-               status = connector_status_connected;
-
-       intel_dp_check_service_irq(intel_dp);
-
-out:
-       if (status != connector_status_connected && !intel_dp->is_mst)
-               intel_dp_unset_edid(intel_dp);
-
-       return status;
-}
-
-static void
-intel_dp_force(struct drm_connector *connector)
-{
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &dig_port->base;
-       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
-       enum intel_display_power_domain aux_domain =
-               intel_aux_power_domain(dig_port);
-       intel_wakeref_t wakeref;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-       intel_dp_unset_edid(intel_dp);
-
-       if (connector->status != connector_status_connected)
-               return;
-
-       wakeref = intel_display_power_get(dev_priv, aux_domain);
-
-       intel_dp_set_edid(intel_dp);
-
-       intel_display_power_put(dev_priv, aux_domain, wakeref);
-}
-
-static int intel_dp_get_modes(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct edid *edid;
-
-       edid = intel_connector->detect_edid;
-       if (edid) {
-               int ret = intel_connector_update_modes(connector, edid);
-               if (ret)
-                       return ret;
-       }
-
-       /* if eDP has no EDID, fall back to fixed mode */
-       if (intel_dp_is_edp(intel_attached_dp(connector)) &&
-           intel_connector->panel.fixed_mode) {
-               struct drm_display_mode *mode;
-
-               mode = drm_mode_duplicate(connector->dev,
-                                         intel_connector->panel.fixed_mode);
-               if (mode) {
-                       drm_mode_probed_add(connector, mode);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static int
-intel_dp_connector_register(struct drm_connector *connector)
-{
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct drm_device *dev = connector->dev;
-       int ret;
-
-       ret = intel_connector_register(connector);
-       if (ret)
-               return ret;
-
-       i915_debugfs_connector_add(connector);
-
-       DRM_DEBUG_KMS("registering %s bus for %s\n",
-                     intel_dp->aux.name, connector->kdev->kobj.name);
-
-       intel_dp->aux.dev = connector->kdev;
-       ret = drm_dp_aux_register(&intel_dp->aux);
-       if (!ret)
-               drm_dp_cec_register_connector(&intel_dp->aux,
-                                             connector->name, dev->dev);
-       return ret;
-}
-
-static void
-intel_dp_connector_unregister(struct drm_connector *connector)
-{
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-
-       drm_dp_cec_unregister_connector(&intel_dp->aux);
-       drm_dp_aux_unregister(&intel_dp->aux);
-       intel_connector_unregister(connector);
-}
-
-void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
-{
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-
-       intel_dp_mst_encoder_cleanup(intel_dig_port);
-       if (intel_dp_is_edp(intel_dp)) {
-               intel_wakeref_t wakeref;
-
-               cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-               /*
-                * vdd might still be enabled do to the delayed vdd off.
-                * Make sure vdd is actually turned off here.
-                */
-               with_pps_lock(intel_dp, wakeref)
-                       edp_panel_vdd_off_sync(intel_dp);
-
-               if (intel_dp->edp_notifier.notifier_call) {
-                       unregister_reboot_notifier(&intel_dp->edp_notifier);
-                       intel_dp->edp_notifier.notifier_call = NULL;
-               }
-       }
-
-       intel_dp_aux_fini(intel_dp);
-}
-
-static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
-{
-       intel_dp_encoder_flush_work(encoder);
-
-       drm_encoder_cleanup(encoder);
-       kfree(enc_to_dig_port(encoder));
-}
-
-void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
-       intel_wakeref_t wakeref;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return;
-
-       /*
-        * vdd might still be enabled do to the delayed vdd off.
-        * Make sure vdd is actually turned off here.
-        */
-       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-       with_pps_lock(intel_dp, wakeref)
-               edp_panel_vdd_off_sync(intel_dp);
-}
-
-static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
-{
-       long ret;
-
-#define C (hdcp->cp_irq_count_cached != atomic_read(&hdcp->cp_irq_count))
-       ret = wait_event_interruptible_timeout(hdcp->cp_irq_queue, C,
-                                              msecs_to_jiffies(timeout));
-
-       if (!ret)
-               DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
-}
-
-static
-int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
-                               u8 *an)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_dig_port->base.base);
-       static const struct drm_dp_aux_msg msg = {
-               .request = DP_AUX_NATIVE_WRITE,
-               .address = DP_AUX_HDCP_AKSV,
-               .size = DRM_HDCP_KSV_LEN,
-       };
-       u8 txbuf[HEADER_SIZE + DRM_HDCP_KSV_LEN] = {}, rxbuf[2], reply = 0;
-       ssize_t dpcd_ret;
-       int ret;
-
-       /* Output An first, that's easy */
-       dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AN,
-                                    an, DRM_HDCP_AN_LEN);
-       if (dpcd_ret != DRM_HDCP_AN_LEN) {
-               DRM_DEBUG_KMS("Failed to write An over DP/AUX (%zd)\n",
-                             dpcd_ret);
-               return dpcd_ret >= 0 ? -EIO : dpcd_ret;
-       }
-
-       /*
-        * Since Aksv is Oh-So-Secret, we can't access it in software. So in
-        * order to get it on the wire, we need to create the AUX header as if
-        * we were writing the data, and then tickle the hardware to output the
-        * data once the header is sent out.
-        */
-       intel_dp_aux_header(txbuf, &msg);
-
-       ret = intel_dp_aux_xfer(intel_dp, txbuf, HEADER_SIZE + msg.size,
-                               rxbuf, sizeof(rxbuf),
-                               DP_AUX_CH_CTL_AUX_AKSV_SELECT);
-       if (ret < 0) {
-               DRM_DEBUG_KMS("Write Aksv over DP/AUX failed (%d)\n", ret);
-               return ret;
-       } else if (ret == 0) {
-               DRM_DEBUG_KMS("Aksv write over DP/AUX was empty\n");
-               return -EIO;
-       }
-
-       reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK;
-       if (reply != DP_AUX_NATIVE_REPLY_ACK) {
-               DRM_DEBUG_KMS("Aksv write: no DP_AUX_NATIVE_REPLY_ACK %x\n",
-                             reply);
-               return -EIO;
-       }
-       return 0;
-}
-
-static int intel_dp_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
-                                  u8 *bksv)
-{
-       ssize_t ret;
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
-                              DRM_HDCP_KSV_LEN);
-       if (ret != DRM_HDCP_KSV_LEN) {
-               DRM_DEBUG_KMS("Read Bksv from DP/AUX failed (%zd)\n", ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-       return 0;
-}
-
-static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
-                                     u8 *bstatus)
-{
-       ssize_t ret;
-       /*
-        * For some reason the HDMI and DP HDCP specs call this register
-        * definition by different names. In the HDMI spec, it's called BSTATUS,
-        * but in DP it's called BINFO.
-        */
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BINFO,
-                              bstatus, DRM_HDCP_BSTATUS_LEN);
-       if (ret != DRM_HDCP_BSTATUS_LEN) {
-               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-       return 0;
-}
-
-static
-int intel_dp_hdcp_read_bcaps(struct intel_digital_port *intel_dig_port,
-                            u8 *bcaps)
-{
-       ssize_t ret;
-
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
-                              bcaps, 1);
-       if (ret != 1) {
-               DRM_DEBUG_KMS("Read bcaps from DP/AUX failed (%zd)\n", ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-
-       return 0;
-}
-
-static
-int intel_dp_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
-                                  bool *repeater_present)
-{
-       ssize_t ret;
-       u8 bcaps;
-
-       ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
-       if (ret)
-               return ret;
-
-       *repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
-       return 0;
-}
-
-static
-int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
-                               u8 *ri_prime)
-{
-       ssize_t ret;
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
-                              ri_prime, DRM_HDCP_RI_LEN);
-       if (ret != DRM_HDCP_RI_LEN) {
-               DRM_DEBUG_KMS("Read Ri' from DP/AUX failed (%zd)\n", ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-       return 0;
-}
-
-static
-int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
-                                bool *ksv_ready)
-{
-       ssize_t ret;
-       u8 bstatus;
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
-                              &bstatus, 1);
-       if (ret != 1) {
-               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-       *ksv_ready = bstatus & DP_BSTATUS_READY;
-       return 0;
-}
-
-static
-int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
-                               int num_downstream, u8 *ksv_fifo)
-{
-       ssize_t ret;
-       int i;
-
-       /* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
-       for (i = 0; i < num_downstream; i += 3) {
-               size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
-               ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
-                                      DP_AUX_HDCP_KSV_FIFO,
-                                      ksv_fifo + i * DRM_HDCP_KSV_LEN,
-                                      len);
-               if (ret != len) {
-                       DRM_DEBUG_KMS("Read ksv[%d] from DP/AUX failed (%zd)\n",
-                                     i, ret);
-                       return ret >= 0 ? -EIO : ret;
-               }
-       }
-       return 0;
-}
-
-static
-int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
-                                   int i, u32 *part)
-{
-       ssize_t ret;
-
-       if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
-               return -EINVAL;
-
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
-                              DP_AUX_HDCP_V_PRIME(i), part,
-                              DRM_HDCP_V_PRIME_PART_LEN);
-       if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
-               DRM_DEBUG_KMS("Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-       return 0;
-}
-
-static
-int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
-                                   bool enable)
-{
-       /* Not used for single stream DisplayPort setups */
-       return 0;
-}
-
-static
-bool intel_dp_hdcp_check_link(struct intel_digital_port *intel_dig_port)
-{
-       ssize_t ret;
-       u8 bstatus;
-
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
-                              &bstatus, 1);
-       if (ret != 1) {
-               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
-               return false;
-       }
-
-       return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
-}
-
-static
-int intel_dp_hdcp_capable(struct intel_digital_port *intel_dig_port,
-                         bool *hdcp_capable)
-{
-       ssize_t ret;
-       u8 bcaps;
-
-       ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
-       if (ret)
-               return ret;
-
-       *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
-       return 0;
-}
-
-struct hdcp2_dp_errata_stream_type {
-       u8      msg_id;
-       u8      stream_type;
-} __packed;
-
-static struct hdcp2_dp_msg_data {
-       u8 msg_id;
-       u32 offset;
-       bool msg_detectable;
-       u32 timeout;
-       u32 timeout2; /* Added for non_paired situation */
-       } hdcp2_msg_data[] = {
-               {HDCP_2_2_AKE_INIT, DP_HDCP_2_2_AKE_INIT_OFFSET, false, 0, 0},
-               {HDCP_2_2_AKE_SEND_CERT, DP_HDCP_2_2_AKE_SEND_CERT_OFFSET,
-                               false, HDCP_2_2_CERT_TIMEOUT_MS, 0},
-               {HDCP_2_2_AKE_NO_STORED_KM, DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET,
-                               false, 0, 0},
-               {HDCP_2_2_AKE_STORED_KM, DP_HDCP_2_2_AKE_STORED_KM_OFFSET,
-                               false, 0, 0},
-               {HDCP_2_2_AKE_SEND_HPRIME, DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET,
-                               true, HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS,
-                               HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS},
-               {HDCP_2_2_AKE_SEND_PAIRING_INFO,
-                               DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET, true,
-                               HDCP_2_2_PAIRING_TIMEOUT_MS, 0},
-               {HDCP_2_2_LC_INIT, DP_HDCP_2_2_LC_INIT_OFFSET, false, 0, 0},
-               {HDCP_2_2_LC_SEND_LPRIME, DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET,
-                               false, HDCP_2_2_DP_LPRIME_TIMEOUT_MS, 0},
-               {HDCP_2_2_SKE_SEND_EKS, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET, false,
-                               0, 0},
-               {HDCP_2_2_REP_SEND_RECVID_LIST,
-                               DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET, true,
-                               HDCP_2_2_RECVID_LIST_TIMEOUT_MS, 0},
-               {HDCP_2_2_REP_SEND_ACK, DP_HDCP_2_2_REP_SEND_ACK_OFFSET, false,
-                               0, 0},
-               {HDCP_2_2_REP_STREAM_MANAGE,
-                               DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET, false,
-                               0, 0},
-               {HDCP_2_2_REP_STREAM_READY, DP_HDCP_2_2_REP_STREAM_READY_OFFSET,
-                               false, HDCP_2_2_STREAM_READY_TIMEOUT_MS, 0},
-/* local define to shovel this through the write_2_2 interface */
-#define HDCP_2_2_ERRATA_DP_STREAM_TYPE 50
-               {HDCP_2_2_ERRATA_DP_STREAM_TYPE,
-                               DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET, false,
-                               0, 0},
-               };
-
-static inline
-int intel_dp_hdcp2_read_rx_status(struct intel_digital_port *intel_dig_port,
-                                 u8 *rx_status)
-{
-       ssize_t ret;
-
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
-                              DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status,
-                              HDCP_2_2_DP_RXSTATUS_LEN);
-       if (ret != HDCP_2_2_DP_RXSTATUS_LEN) {
-               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
-               return ret >= 0 ? -EIO : ret;
-       }
-
-       return 0;
-}
-
-static
-int hdcp2_detect_msg_availability(struct intel_digital_port *intel_dig_port,
-                                 u8 msg_id, bool *msg_ready)
-{
-       u8 rx_status;
-       int ret;
-
-       *msg_ready = false;
-       ret = intel_dp_hdcp2_read_rx_status(intel_dig_port, &rx_status);
-       if (ret < 0)
-               return ret;
-
-       switch (msg_id) {
-       case HDCP_2_2_AKE_SEND_HPRIME:
-               if (HDCP_2_2_DP_RXSTATUS_H_PRIME(rx_status))
-                       *msg_ready = true;
-               break;
-       case HDCP_2_2_AKE_SEND_PAIRING_INFO:
-               if (HDCP_2_2_DP_RXSTATUS_PAIRING(rx_status))
-                       *msg_ready = true;
-               break;
-       case HDCP_2_2_REP_SEND_RECVID_LIST:
-               if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
-                       *msg_ready = true;
-               break;
-       default:
-               DRM_ERROR("Unidentified msg_id: %d\n", msg_id);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static ssize_t
-intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port,
-                           struct hdcp2_dp_msg_data *hdcp2_msg_data)
-{
-       struct intel_dp *dp = &intel_dig_port->dp;
-       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
-       u8 msg_id = hdcp2_msg_data->msg_id;
-       int ret, timeout;
-       bool msg_ready = false;
-
-       if (msg_id == HDCP_2_2_AKE_SEND_HPRIME && !hdcp->is_paired)
-               timeout = hdcp2_msg_data->timeout2;
-       else
-               timeout = hdcp2_msg_data->timeout;
-
-       /*
-        * There is no way to detect the CERT, LPRIME and STREAM_READY
-        * availability. So Wait for timeout and read the msg.
-        */
-       if (!hdcp2_msg_data->msg_detectable) {
-               mdelay(timeout);
-               ret = 0;
-       } else {
-               /*
-                * As we want to check the msg availability at timeout, Ignoring
-                * the timeout at wait for CP_IRQ.
-                */
-               intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout);
-               ret = hdcp2_detect_msg_availability(intel_dig_port,
-                                                   msg_id, &msg_ready);
-               if (!msg_ready)
-                       ret = -ETIMEDOUT;
-       }
-
-       if (ret)
-               DRM_DEBUG_KMS("msg_id %d, ret %d, timeout(mSec): %d\n",
-                             hdcp2_msg_data->msg_id, ret, timeout);
-
-       return ret;
-}
-
-static struct hdcp2_dp_msg_data *get_hdcp2_dp_msg_data(u8 msg_id)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hdcp2_msg_data); i++)
-               if (hdcp2_msg_data[i].msg_id == msg_id)
-                       return &hdcp2_msg_data[i];
-
-       return NULL;
-}
-
-static
-int intel_dp_hdcp2_write_msg(struct intel_digital_port *intel_dig_port,
-                            void *buf, size_t size)
-{
-       struct intel_dp *dp = &intel_dig_port->dp;
-       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
-       unsigned int offset;
-       u8 *byte = buf;
-       ssize_t ret, bytes_to_write, len;
-       struct hdcp2_dp_msg_data *hdcp2_msg_data;
-
-       hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte);
-       if (!hdcp2_msg_data)
-               return -EINVAL;
-
-       offset = hdcp2_msg_data->offset;
-
-       /* No msg_id in DP HDCP2.2 msgs */
-       bytes_to_write = size - 1;
-       byte++;
-
-       hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count);
-
-       while (bytes_to_write) {
-               len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ?
-                               DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write;
-
-               ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux,
-                                       offset, (void *)byte, len);
-               if (ret < 0)
-                       return ret;
-
-               bytes_to_write -= ret;
-               byte += ret;
-               offset += ret;
-       }
-
-       return size;
-}
-
-static
-ssize_t get_receiver_id_list_size(struct intel_digital_port *intel_dig_port)
-{
-       u8 rx_info[HDCP_2_2_RXINFO_LEN];
-       u32 dev_cnt;
-       ssize_t ret;
-
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
-                              DP_HDCP_2_2_REG_RXINFO_OFFSET,
-                              (void *)rx_info, HDCP_2_2_RXINFO_LEN);
-       if (ret != HDCP_2_2_RXINFO_LEN)
-               return ret >= 0 ? -EIO : ret;
-
-       dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
-                  HDCP_2_2_DEV_COUNT_LO(rx_info[1]));
-
-       if (dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
-               dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
-
-       ret = sizeof(struct hdcp2_rep_send_receiverid_list) -
-               HDCP_2_2_RECEIVER_IDS_MAX_LEN +
-               (dev_cnt * HDCP_2_2_RECEIVER_ID_LEN);
-
-       return ret;
-}
-
-static
-int intel_dp_hdcp2_read_msg(struct intel_digital_port *intel_dig_port,
-                           u8 msg_id, void *buf, size_t size)
-{
-       unsigned int offset;
-       u8 *byte = buf;
-       ssize_t ret, bytes_to_recv, len;
-       struct hdcp2_dp_msg_data *hdcp2_msg_data;
-
-       hdcp2_msg_data = get_hdcp2_dp_msg_data(msg_id);
-       if (!hdcp2_msg_data)
-               return -EINVAL;
-       offset = hdcp2_msg_data->offset;
-
-       ret = intel_dp_hdcp2_wait_for_msg(intel_dig_port, hdcp2_msg_data);
-       if (ret < 0)
-               return ret;
-
-       if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) {
-               ret = get_receiver_id_list_size(intel_dig_port);
-               if (ret < 0)
-                       return ret;
-
-               size = ret;
-       }
-       bytes_to_recv = size - 1;
-
-       /* DP adaptation msgs has no msg_id */
-       byte++;
-
-       while (bytes_to_recv) {
-               len = bytes_to_recv > DP_AUX_MAX_PAYLOAD_BYTES ?
-                     DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv;
-
-               ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, offset,
-                                      (void *)byte, len);
-               if (ret < 0) {
-                       DRM_DEBUG_KMS("msg_id %d, ret %zd\n", msg_id, ret);
-                       return ret;
-               }
-
-               bytes_to_recv -= ret;
-               byte += ret;
-               offset += ret;
-       }
-       byte = buf;
-       *byte = msg_id;
-
-       return size;
-}
-
-static
-int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *intel_dig_port,
-                                     bool is_repeater, u8 content_type)
-{
-       struct hdcp2_dp_errata_stream_type stream_type_msg;
-
-       if (is_repeater)
-               return 0;
-
-       /*
-        * Errata for DP: As Stream type is used for encryption, Receiver
-        * should be communicated with stream type for the decryption of the
-        * content.
-        * Repeater will be communicated with stream type as a part of it's
-        * auth later in time.
-        */
-       stream_type_msg.msg_id = HDCP_2_2_ERRATA_DP_STREAM_TYPE;
-       stream_type_msg.stream_type = content_type;
-
-       return intel_dp_hdcp2_write_msg(intel_dig_port, &stream_type_msg,
-                                       sizeof(stream_type_msg));
-}
-
-static
-int intel_dp_hdcp2_check_link(struct intel_digital_port *intel_dig_port)
-{
-       u8 rx_status;
-       int ret;
-
-       ret = intel_dp_hdcp2_read_rx_status(intel_dig_port, &rx_status);
-       if (ret)
-               return ret;
-
-       if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rx_status))
-               ret = HDCP_REAUTH_REQUEST;
-       else if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rx_status))
-               ret = HDCP_LINK_INTEGRITY_FAILURE;
-       else if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
-               ret = HDCP_TOPOLOGY_CHANGE;
-
-       return ret;
-}
-
-static
-int intel_dp_hdcp2_capable(struct intel_digital_port *intel_dig_port,
-                          bool *capable)
-{
-       u8 rx_caps[3];
-       int ret;
-
-       *capable = false;
-       ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
-                              DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
-                              rx_caps, HDCP_2_2_RXCAPS_LEN);
-       if (ret != HDCP_2_2_RXCAPS_LEN)
-               return ret >= 0 ? -EIO : ret;
-
-       if (rx_caps[0] == HDCP_2_2_RX_CAPS_VERSION_VAL &&
-           HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2]))
-               *capable = true;
-
-       return 0;
-}
-
-static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
-       .write_an_aksv = intel_dp_hdcp_write_an_aksv,
-       .read_bksv = intel_dp_hdcp_read_bksv,
-       .read_bstatus = intel_dp_hdcp_read_bstatus,
-       .repeater_present = intel_dp_hdcp_repeater_present,
-       .read_ri_prime = intel_dp_hdcp_read_ri_prime,
-       .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
-       .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
-       .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
-       .toggle_signalling = intel_dp_hdcp_toggle_signalling,
-       .check_link = intel_dp_hdcp_check_link,
-       .hdcp_capable = intel_dp_hdcp_capable,
-       .write_2_2_msg = intel_dp_hdcp2_write_msg,
-       .read_2_2_msg = intel_dp_hdcp2_read_msg,
-       .config_stream_type = intel_dp_hdcp2_config_stream_type,
-       .check_2_2_link = intel_dp_hdcp2_check_link,
-       .hdcp_2_2_capable = intel_dp_hdcp2_capable,
-       .protocol = HDCP_PROTOCOL_DP,
-};
-
-static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       if (!edp_have_panel_vdd(intel_dp))
-               return;
-
-       /*
-        * The VDD bit needs a power domain reference, so if the bit is
-        * already enabled when we boot or resume, grab this reference and
-        * schedule a vdd off, so we don't hold on to the reference
-        * indefinitely.
-        */
-       DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
-       intel_display_power_get(dev_priv, intel_aux_power_domain(dig_port));
-
-       edp_panel_vdd_schedule_off(intel_dp);
-}
-
-static enum pipe vlv_active_pipe(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       enum pipe pipe;
-
-       if (intel_dp_port_enabled(dev_priv, intel_dp->output_reg,
-                                 encoder->port, &pipe))
-               return pipe;
-
-       return INVALID_PIPE;
-}
-
-void intel_dp_encoder_reset(struct drm_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
-       intel_wakeref_t wakeref;
-
-       if (!HAS_DDI(dev_priv))
-               intel_dp->DP = I915_READ(intel_dp->output_reg);
-
-       if (lspcon->active)
-               lspcon_resume(lspcon);
-
-       intel_dp->reset_link_params = true;
-
-       if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
-           !intel_dp_is_edp(intel_dp))
-               return;
-
-       with_pps_lock(intel_dp, wakeref) {
-               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-                       intel_dp->active_pipe = vlv_active_pipe(intel_dp);
-
-               if (intel_dp_is_edp(intel_dp)) {
-                       /*
-                        * Reinit the power sequencer, in case BIOS did
-                        * something nasty with it.
-                        */
-                       intel_dp_pps_init(intel_dp);
-                       intel_edp_panel_vdd_sanitize(intel_dp);
-               }
-       }
-}
-
-static const struct drm_connector_funcs intel_dp_connector_funcs = {
-       .force = intel_dp_force,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .late_register = intel_dp_connector_register,
-       .early_unregister = intel_dp_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
-       .detect_ctx = intel_dp_detect,
-       .get_modes = intel_dp_get_modes,
-       .mode_valid = intel_dp_mode_valid,
-       .atomic_check = intel_digital_connector_atomic_check,
-};
-
-static const struct drm_encoder_funcs intel_dp_enc_funcs = {
-       .reset = intel_dp_encoder_reset,
-       .destroy = intel_dp_encoder_destroy,
-};
-
-enum irqreturn
-intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
-{
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-
-       if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
-               /*
-                * vdd off can generate a long pulse on eDP which
-                * would require vdd on to handle it, and thus we
-                * would end up in an endless cycle of
-                * "vdd off -> long hpd -> vdd on -> detect -> vdd off -> ..."
-                */
-               DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
-                             port_name(intel_dig_port->base.port));
-               return IRQ_HANDLED;
-       }
-
-       DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
-                     port_name(intel_dig_port->base.port),
-                     long_hpd ? "long" : "short");
-
-       if (long_hpd) {
-               intel_dp->reset_link_params = true;
-               return IRQ_NONE;
-       }
-
-       if (intel_dp->is_mst) {
-               if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
-                       /*
-                        * If we were in MST mode, and device is not
-                        * there, get out of MST mode
-                        */
-                       DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
-                                     intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
-                       intel_dp->is_mst = false;
-                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
-                                                       intel_dp->is_mst);
-
-                       return IRQ_NONE;
-               }
-       }
-
-       if (!intel_dp->is_mst) {
-               bool handled;
-
-               handled = intel_dp_short_pulse(intel_dp);
-
-               if (!handled)
-                       return IRQ_NONE;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* check the VBT to see whether the eDP is on another port */
-bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
-{
-       /*
-        * eDP not supported on g4x. so bail out early just
-        * for a bit extra safety in case the VBT is bonkers.
-        */
-       if (INTEL_GEN(dev_priv) < 5)
-               return false;
-
-       if (INTEL_GEN(dev_priv) < 9 && port == PORT_A)
-               return true;
-
-       return intel_bios_is_port_edp(dev_priv, port);
-}
-
-static void
-intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       enum port port = dp_to_dig_port(intel_dp)->base.port;
-
-       if (!IS_G4X(dev_priv) && port != PORT_A)
-               intel_attach_force_audio_property(connector);
-
-       intel_attach_broadcast_rgb_property(connector);
-       if (HAS_GMCH(dev_priv))
-               drm_connector_attach_max_bpc_property(connector, 6, 10);
-       else if (INTEL_GEN(dev_priv) >= 5)
-               drm_connector_attach_max_bpc_property(connector, 6, 12);
-
-       if (intel_dp_is_edp(intel_dp)) {
-               u32 allowed_scalers;
-
-               allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
-               if (!HAS_GMCH(dev_priv))
-                       allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
-
-               drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
-
-               connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
-
-       }
-}
-
-static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp)
-{
-       intel_dp->panel_power_off_time = ktime_get_boottime();
-       intel_dp->last_power_on = jiffies;
-       intel_dp->last_backlight_off = jiffies;
-}
-
-static void
-intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u32 pp_on, pp_off, pp_ctl;
-       struct pps_registers regs;
-
-       intel_pps_get_registers(intel_dp, &regs);
-
-       pp_ctl = ironlake_get_pp_control(intel_dp);
-
-       /* Ensure PPS is unlocked */
-       if (!HAS_DDI(dev_priv))
-               I915_WRITE(regs.pp_ctrl, pp_ctl);
-
-       pp_on = I915_READ(regs.pp_on);
-       pp_off = I915_READ(regs.pp_off);
-
-       /* Pull timing values out of registers */
-       seq->t1_t3 = REG_FIELD_GET(PANEL_POWER_UP_DELAY_MASK, pp_on);
-       seq->t8 = REG_FIELD_GET(PANEL_LIGHT_ON_DELAY_MASK, pp_on);
-       seq->t9 = REG_FIELD_GET(PANEL_LIGHT_OFF_DELAY_MASK, pp_off);
-       seq->t10 = REG_FIELD_GET(PANEL_POWER_DOWN_DELAY_MASK, pp_off);
-
-       if (i915_mmio_reg_valid(regs.pp_div)) {
-               u32 pp_div;
-
-               pp_div = I915_READ(regs.pp_div);
-
-               seq->t11_t12 = REG_FIELD_GET(PANEL_POWER_CYCLE_DELAY_MASK, pp_div) * 1000;
-       } else {
-               seq->t11_t12 = REG_FIELD_GET(BXT_POWER_CYCLE_DELAY_MASK, pp_ctl) * 1000;
-       }
-}
-
-static void
-intel_pps_dump_state(const char *state_name, const struct edp_power_seq *seq)
-{
-       DRM_DEBUG_KMS("%s t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
-                     state_name,
-                     seq->t1_t3, seq->t8, seq->t9, seq->t10, seq->t11_t12);
-}
-
-static void
-intel_pps_verify_state(struct intel_dp *intel_dp)
-{
-       struct edp_power_seq hw;
-       struct edp_power_seq *sw = &intel_dp->pps_delays;
-
-       intel_pps_readout_hw_state(intel_dp, &hw);
-
-       if (hw.t1_t3 != sw->t1_t3 || hw.t8 != sw->t8 || hw.t9 != sw->t9 ||
-           hw.t10 != sw->t10 || hw.t11_t12 != sw->t11_t12) {
-               DRM_ERROR("PPS state mismatch\n");
-               intel_pps_dump_state("sw", sw);
-               intel_pps_dump_state("hw", &hw);
-       }
-}
-
-static void
-intel_dp_init_panel_power_sequencer(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct edp_power_seq cur, vbt, spec,
-               *final = &intel_dp->pps_delays;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       /* already initialized? */
-       if (final->t11_t12 != 0)
-               return;
-
-       intel_pps_readout_hw_state(intel_dp, &cur);
-
-       intel_pps_dump_state("cur", &cur);
-
-       vbt = dev_priv->vbt.edp.pps;
-       /* On Toshiba Satellite P50-C-18C system the VBT T12 delay
-        * of 500ms appears to be too short. Ocassionally the panel
-        * just fails to power back on. Increasing the delay to 800ms
-        * seems sufficient to avoid this problem.
-        */
-       if (dev_priv->quirks & QUIRK_INCREASE_T12_DELAY) {
-               vbt.t11_t12 = max_t(u16, vbt.t11_t12, 1300 * 10);
-               DRM_DEBUG_KMS("Increasing T12 panel delay as per the quirk to %d\n",
-                             vbt.t11_t12);
-       }
-       /* T11_T12 delay is special and actually in units of 100ms, but zero
-        * based in the hw (so we need to add 100 ms). But the sw vbt
-        * table multiplies it with 1000 to make it in units of 100usec,
-        * too. */
-       vbt.t11_t12 += 100 * 10;
-
-       /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of
-        * our hw here, which are all in 100usec. */
-       spec.t1_t3 = 210 * 10;
-       spec.t8 = 50 * 10; /* no limit for t8, use t7 instead */
-       spec.t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */
-       spec.t10 = 500 * 10;
-       /* This one is special and actually in units of 100ms, but zero
-        * based in the hw (so we need to add 100 ms). But the sw vbt
-        * table multiplies it with 1000 to make it in units of 100usec,
-        * too. */
-       spec.t11_t12 = (510 + 100) * 10;
-
-       intel_pps_dump_state("vbt", &vbt);
-
-       /* Use the max of the register settings and vbt. If both are
-        * unset, fall back to the spec limits. */
-#define assign_final(field)    final->field = (max(cur.field, vbt.field) == 0 ? \
-                                      spec.field : \
-                                      max(cur.field, vbt.field))
-       assign_final(t1_t3);
-       assign_final(t8);
-       assign_final(t9);
-       assign_final(t10);
-       assign_final(t11_t12);
-#undef assign_final
-
-#define get_delay(field)       (DIV_ROUND_UP(final->field, 10))
-       intel_dp->panel_power_up_delay = get_delay(t1_t3);
-       intel_dp->backlight_on_delay = get_delay(t8);
-       intel_dp->backlight_off_delay = get_delay(t9);
-       intel_dp->panel_power_down_delay = get_delay(t10);
-       intel_dp->panel_power_cycle_delay = get_delay(t11_t12);
-#undef get_delay
-
-       DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
-                     intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
-                     intel_dp->panel_power_cycle_delay);
-
-       DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
-                     intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
-
-       /*
-        * We override the HW backlight delays to 1 because we do manual waits
-        * on them. For T8, even BSpec recommends doing it. For T9, if we
-        * don't do this, we'll end up waiting for the backlight off delay
-        * twice: once when we do the manual sleep, and once when we disable
-        * the panel and wait for the PP_STATUS bit to become zero.
-        */
-       final->t8 = 1;
-       final->t9 = 1;
-
-       /*
-        * HW has only a 100msec granularity for t11_t12 so round it up
-        * accordingly.
-        */
-       final->t11_t12 = roundup(final->t11_t12, 100 * 10);
-}
-
-static void
-intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
-                                             bool force_disable_vdd)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u32 pp_on, pp_off, port_sel = 0;
-       int div = dev_priv->rawclk_freq / 1000;
-       struct pps_registers regs;
-       enum port port = dp_to_dig_port(intel_dp)->base.port;
-       const struct edp_power_seq *seq = &intel_dp->pps_delays;
-
-       lockdep_assert_held(&dev_priv->pps_mutex);
-
-       intel_pps_get_registers(intel_dp, &regs);
-
-       /*
-        * On some VLV machines the BIOS can leave the VDD
-        * enabled even on power sequencers which aren't
-        * hooked up to any port. This would mess up the
-        * power domain tracking the first time we pick
-        * one of these power sequencers for use since
-        * edp_panel_vdd_on() would notice that the VDD was
-        * already on and therefore wouldn't grab the power
-        * domain reference. Disable VDD first to avoid this.
-        * This also avoids spuriously turning the VDD on as
-        * soon as the new power sequencer gets initialized.
-        */
-       if (force_disable_vdd) {
-               u32 pp = ironlake_get_pp_control(intel_dp);
-
-               WARN(pp & PANEL_POWER_ON, "Panel power already on\n");
-
-               if (pp & EDP_FORCE_VDD)
-                       DRM_DEBUG_KMS("VDD already on, disabling first\n");
-
-               pp &= ~EDP_FORCE_VDD;
-
-               I915_WRITE(regs.pp_ctrl, pp);
-       }
-
-       pp_on = REG_FIELD_PREP(PANEL_POWER_UP_DELAY_MASK, seq->t1_t3) |
-               REG_FIELD_PREP(PANEL_LIGHT_ON_DELAY_MASK, seq->t8);
-       pp_off = REG_FIELD_PREP(PANEL_LIGHT_OFF_DELAY_MASK, seq->t9) |
-               REG_FIELD_PREP(PANEL_POWER_DOWN_DELAY_MASK, seq->t10);
-
-       /* Haswell doesn't have any port selection bits for the panel
-        * power sequencer any more. */
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               port_sel = PANEL_PORT_SELECT_VLV(port);
-       } else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) {
-               switch (port) {
-               case PORT_A:
-                       port_sel = PANEL_PORT_SELECT_DPA;
-                       break;
-               case PORT_C:
-                       port_sel = PANEL_PORT_SELECT_DPC;
-                       break;
-               case PORT_D:
-                       port_sel = PANEL_PORT_SELECT_DPD;
-                       break;
-               default:
-                       MISSING_CASE(port);
-                       break;
-               }
-       }
-
-       pp_on |= port_sel;
-
-       I915_WRITE(regs.pp_on, pp_on);
-       I915_WRITE(regs.pp_off, pp_off);
-
-       /*
-        * Compute the divisor for the pp clock, simply match the Bspec formula.
-        */
-       if (i915_mmio_reg_valid(regs.pp_div)) {
-               I915_WRITE(regs.pp_div,
-                          REG_FIELD_PREP(PP_REFERENCE_DIVIDER_MASK, (100 * div) / 2 - 1) |
-                          REG_FIELD_PREP(PANEL_POWER_CYCLE_DELAY_MASK, DIV_ROUND_UP(seq->t11_t12, 1000)));
-       } else {
-               u32 pp_ctl;
-
-               pp_ctl = I915_READ(regs.pp_ctrl);
-               pp_ctl &= ~BXT_POWER_CYCLE_DELAY_MASK;
-               pp_ctl |= REG_FIELD_PREP(BXT_POWER_CYCLE_DELAY_MASK, DIV_ROUND_UP(seq->t11_t12, 1000));
-               I915_WRITE(regs.pp_ctrl, pp_ctl);
-       }
-
-       DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
-                     I915_READ(regs.pp_on),
-                     I915_READ(regs.pp_off),
-                     i915_mmio_reg_valid(regs.pp_div) ?
-                     I915_READ(regs.pp_div) :
-                     (I915_READ(regs.pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK));
-}
-
-static void intel_dp_pps_init(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               vlv_initial_power_sequencer_setup(intel_dp);
-       } else {
-               intel_dp_init_panel_power_sequencer(intel_dp);
-               intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
-       }
-}
-
-/**
- * intel_dp_set_drrs_state - program registers for RR switch to take effect
- * @dev_priv: i915 device
- * @crtc_state: a pointer to the active intel_crtc_state
- * @refresh_rate: RR to be programmed
- *
- * This function gets called when refresh rate (RR) has to be changed from
- * one frequency to another. Switches can be between high and low RR
- * supported by the panel or to any other RR based on media playback (in
- * this case, RR value needs to be passed from user space).
- *
- * The caller of this function needs to take a lock on dev_priv->drrs.
- */
-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;
-
-       if (refresh_rate <= 0) {
-               DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
-               return;
-       }
-
-       if (intel_dp == NULL) {
-               DRM_DEBUG_KMS("DRRS not supported.\n");
-               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;
-       }
-
-       if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
-               DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
-               return;
-       }
-
-       if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
-                       refresh_rate)
-               index = DRRS_LOW_RR;
-
-       if (index == dev_priv->drrs.refresh_rate_type) {
-               DRM_DEBUG_KMS(
-                       "DRRS requested for previously set RR...ignoring\n");
-               return;
-       }
-
-       if (!crtc_state->base.active) {
-               DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
-               return;
-       }
-
-       if (INTEL_GEN(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
-               switch (index) {
-               case DRRS_HIGH_RR:
-                       intel_dp_set_m_n(crtc_state, M1_N1);
-                       break;
-               case DRRS_LOW_RR:
-                       intel_dp_set_m_n(crtc_state, M2_N2);
-                       break;
-               case DRRS_MAX_RR:
-               default:
-                       DRM_ERROR("Unsupported refreshrate type\n");
-               }
-       } else if (INTEL_GEN(dev_priv) > 6) {
-               i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
-               u32 val;
-
-               val = I915_READ(reg);
-               if (index > DRRS_HIGH_RR) {
-                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-                               val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
-                       else
-                               val |= PIPECONF_EDP_RR_MODE_SWITCH;
-               } else {
-                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
-                       else
-                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
-               }
-               I915_WRITE(reg, val);
-       }
-
-       dev_priv->drrs.refresh_rate_type = index;
-
-       DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
-}
-
-/**
- * intel_edp_drrs_enable - init drrs struct if supported
- * @intel_dp: DP struct
- * @crtc_state: A pointer to the active crtc state.
- *
- * Initializes frontbuffer_bits and drrs.dp
- */
-void intel_edp_drrs_enable(struct intel_dp *intel_dp,
-                          const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (!crtc_state->has_drrs) {
-               DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
-               return;
-       }
-
-       if (dev_priv->psr.enabled) {
-               DRM_DEBUG_KMS("PSR enabled. Not enabling DRRS.\n");
-               return;
-       }
-
-       mutex_lock(&dev_priv->drrs.mutex);
-       if (dev_priv->drrs.dp) {
-               DRM_DEBUG_KMS("DRRS already enabled\n");
-               goto unlock;
-       }
-
-       dev_priv->drrs.busy_frontbuffer_bits = 0;
-
-       dev_priv->drrs.dp = intel_dp;
-
-unlock:
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_disable - Disable DRRS
- * @intel_dp: DP struct
- * @old_crtc_state: Pointer to old crtc_state.
- *
- */
-void intel_edp_drrs_disable(struct intel_dp *intel_dp,
-                           const struct intel_crtc_state *old_crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (!old_crtc_state->has_drrs)
-               return;
-
-       mutex_lock(&dev_priv->drrs.mutex);
-       if (!dev_priv->drrs.dp) {
-               mutex_unlock(&dev_priv->drrs.mutex);
-               return;
-       }
-
-       if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(dev_priv, old_crtc_state,
-                       intel_dp->attached_connector->panel.fixed_mode->vrefresh);
-
-       dev_priv->drrs.dp = NULL;
-       mutex_unlock(&dev_priv->drrs.mutex);
-
-       cancel_delayed_work_sync(&dev_priv->drrs.work);
-}
-
-static void intel_edp_drrs_downclock_work(struct work_struct *work)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(work, typeof(*dev_priv), drrs.work.work);
-       struct intel_dp *intel_dp;
-
-       mutex_lock(&dev_priv->drrs.mutex);
-
-       intel_dp = dev_priv->drrs.dp;
-
-       if (!intel_dp)
-               goto unlock;
-
-       /*
-        * The delayed work can race with an invalidate hence we need to
-        * recheck.
-        */
-
-       if (dev_priv->drrs.busy_frontbuffer_bits)
-               goto unlock;
-
-       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) {
-               struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
-
-               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
-                       intel_dp->attached_connector->panel.downclock_mode->vrefresh);
-       }
-
-unlock:
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_invalidate - Disable Idleness DRRS
- * @dev_priv: i915 device
- * @frontbuffer_bits: frontbuffer plane tracking bits
- *
- * This function gets called everytime rendering on the given planes start.
- * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
- *
- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
- */
-void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
-                              unsigned int frontbuffer_bits)
-{
-       struct drm_crtc *crtc;
-       enum pipe pipe;
-
-       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
-               return;
-
-       cancel_delayed_work(&dev_priv->drrs.work);
-
-       mutex_lock(&dev_priv->drrs.mutex);
-       if (!dev_priv->drrs.dp) {
-               mutex_unlock(&dev_priv->drrs.mutex);
-               return;
-       }
-
-       crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
-       pipe = to_intel_crtc(crtc)->pipe;
-
-       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
-       dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
-
-       /* invalidate means busy screen hence upclock */
-       if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
-                       dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
-
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_flush - Restart Idleness DRRS
- * @dev_priv: i915 device
- * @frontbuffer_bits: frontbuffer plane tracking bits
- *
- * This function gets called every time rendering on the given planes has
- * completed or flip on a crtc is completed. So DRRS should be upclocked
- * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
- * if no other planes are dirty.
- *
- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
- */
-void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
-                         unsigned int frontbuffer_bits)
-{
-       struct drm_crtc *crtc;
-       enum pipe pipe;
-
-       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
-               return;
-
-       cancel_delayed_work(&dev_priv->drrs.work);
-
-       mutex_lock(&dev_priv->drrs.mutex);
-       if (!dev_priv->drrs.dp) {
-               mutex_unlock(&dev_priv->drrs.mutex);
-               return;
-       }
-
-       crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
-       pipe = to_intel_crtc(crtc)->pipe;
-
-       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
-       dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
-
-       /* flush means busy screen hence upclock */
-       if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
-                               dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
-
-       /*
-        * flush also means no more activity hence schedule downclock, if all
-        * other fbs are quiescent too
-        */
-       if (!dev_priv->drrs.busy_frontbuffer_bits)
-               schedule_delayed_work(&dev_priv->drrs.work,
-                               msecs_to_jiffies(1000));
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * DOC: Display Refresh Rate Switching (DRRS)
- *
- * Display Refresh Rate Switching (DRRS) is a power conservation feature
- * which enables swtching between low and high refresh rates,
- * dynamically, based on the usage scenario. This feature is applicable
- * for internal panels.
- *
- * Indication that the panel supports DRRS is given by the panel EDID, which
- * would list multiple refresh rates for one resolution.
- *
- * DRRS is of 2 types - static and seamless.
- * Static DRRS involves changing refresh rate (RR) by doing a full modeset
- * (may appear as a blink on screen) and is used in dock-undock scenario.
- * Seamless DRRS involves changing RR without any visual effect to the user
- * and can be used during normal system usage. This is done by programming
- * certain registers.
- *
- * Support for static/seamless DRRS may be indicated in the VBT based on
- * inputs from the panel spec.
- *
- * DRRS saves power by switching to low RR based on usage scenarios.
- *
- * The implementation is based on frontbuffer tracking implementation.  When
- * there is a disturbance on the screen triggered by user activity or a periodic
- * system activity, DRRS is disabled (RR is changed to high RR).  When there is
- * no movement on screen, after a timeout of 1 second, a switch to low RR is
- * made.
- *
- * For integration with frontbuffer tracking code, intel_edp_drrs_invalidate()
- * and intel_edp_drrs_flush() are called.
- *
- * DRRS can be further extended to support other internal panels and also
- * the scenario of video playback wherein RR is set based on the rate
- * requested by userspace.
- */
-
-/**
- * intel_dp_drrs_init - Init basic DRRS work and mutex.
- * @connector: eDP connector
- * @fixed_mode: preferred mode of panel
- *
- * This function is  called only once at driver load to initialize basic
- * DRRS stuff.
- *
- * Returns:
- * Downclock mode if panel supports it, else return NULL.
- * DRRS support is determined by the presence of downclock mode (apart
- * from VBT setting).
- */
-static struct drm_display_mode *
-intel_dp_drrs_init(struct intel_connector *connector,
-                  struct drm_display_mode *fixed_mode)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct drm_display_mode *downclock_mode = NULL;
-
-       INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
-       mutex_init(&dev_priv->drrs.mutex);
-
-       if (INTEL_GEN(dev_priv) <= 6) {
-               DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n");
-               return NULL;
-       }
-
-       if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
-               DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
-               return NULL;
-       }
-
-       downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode);
-       if (!downclock_mode) {
-               DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
-               return NULL;
-       }
-
-       dev_priv->drrs.type = dev_priv->vbt.drrs_type;
-
-       dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
-       DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
-       return downclock_mode;
-}
-
-static bool intel_edp_init_connector(struct intel_dp *intel_dp,
-                                    struct intel_connector *intel_connector)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct drm_device *dev = &dev_priv->drm;
-       struct drm_connector *connector = &intel_connector->base;
-       struct drm_display_mode *fixed_mode = NULL;
-       struct drm_display_mode *downclock_mode = NULL;
-       bool has_dpcd;
-       enum pipe pipe = INVALID_PIPE;
-       intel_wakeref_t wakeref;
-       struct edid *edid;
-
-       if (!intel_dp_is_edp(intel_dp))
-               return true;
-
-       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, edp_panel_vdd_work);
-
-       /*
-        * On IBX/CPT we may get here with LVDS already registered. Since the
-        * driver uses the only internal power sequencer available for both
-        * eDP and LVDS bail out early in this case to prevent interfering
-        * with an already powered-on LVDS power sequencer.
-        */
-       if (intel_get_lvds_encoder(dev_priv)) {
-               WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
-               DRM_INFO("LVDS was detected, not registering eDP\n");
-
-               return false;
-       }
-
-       with_pps_lock(intel_dp, wakeref) {
-               intel_dp_init_panel_power_timestamps(intel_dp);
-               intel_dp_pps_init(intel_dp);
-               intel_edp_panel_vdd_sanitize(intel_dp);
-       }
-
-       /* Cache DPCD and EDID for edp. */
-       has_dpcd = intel_edp_init_dpcd(intel_dp);
-
-       if (!has_dpcd) {
-               /* if this fails, presume the device is a ghost */
-               DRM_INFO("failed to retrieve link info, disabling eDP\n");
-               goto out_vdd_off;
-       }
-
-       mutex_lock(&dev->mode_config.mutex);
-       edid = drm_get_edid(connector, &intel_dp->aux.ddc);
-       if (edid) {
-               if (drm_add_edid_modes(connector, edid)) {
-                       drm_connector_update_edid_property(connector,
-                                                               edid);
-               } else {
-                       kfree(edid);
-                       edid = ERR_PTR(-EINVAL);
-               }
-       } else {
-               edid = ERR_PTR(-ENOENT);
-       }
-       intel_connector->edid = edid;
-
-       fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
-       if (fixed_mode)
-               downclock_mode = intel_dp_drrs_init(intel_connector, fixed_mode);
-
-       /* fallback to VBT if available for eDP */
-       if (!fixed_mode)
-               fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
-       mutex_unlock(&dev->mode_config.mutex);
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               intel_dp->edp_notifier.notifier_call = edp_notify_handler;
-               register_reboot_notifier(&intel_dp->edp_notifier);
-
-               /*
-                * Figure out the current pipe for the initial backlight setup.
-                * If the current pipe isn't valid, try the PPS pipe, and if that
-                * fails just assume pipe A.
-                */
-               pipe = vlv_active_pipe(intel_dp);
-
-               if (pipe != PIPE_A && pipe != PIPE_B)
-                       pipe = intel_dp->pps_pipe;
-
-               if (pipe != PIPE_A && pipe != PIPE_B)
-                       pipe = PIPE_A;
-
-               DRM_DEBUG_KMS("using pipe %c for initial backlight setup\n",
-                             pipe_name(pipe));
-       }
-
-       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
-       intel_connector->panel.backlight.power = intel_edp_backlight_power;
-       intel_panel_setup_backlight(connector, pipe);
-
-       if (fixed_mode)
-               drm_connector_init_panel_orientation_property(
-                       connector, fixed_mode->hdisplay, fixed_mode->vdisplay);
-
-       return true;
-
-out_vdd_off:
-       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-       /*
-        * vdd might still be enabled do to the delayed vdd off.
-        * Make sure vdd is actually turned off here.
-        */
-       with_pps_lock(intel_dp, wakeref)
-               edp_panel_vdd_off_sync(intel_dp);
-
-       return false;
-}
-
-static void intel_dp_modeset_retry_work_fn(struct work_struct *work)
-{
-       struct intel_connector *intel_connector;
-       struct drm_connector *connector;
-
-       intel_connector = container_of(work, typeof(*intel_connector),
-                                      modeset_retry_work);
-       connector = &intel_connector->base;
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
-                     connector->name);
-
-       /* Grab the locks before changing connector property*/
-       mutex_lock(&connector->dev->mode_config.mutex);
-       /* Set connector link status to BAD and send a Uevent to notify
-        * userspace to do a modeset.
-        */
-       drm_connector_set_link_status_property(connector,
-                                              DRM_MODE_LINK_STATUS_BAD);
-       mutex_unlock(&connector->dev->mode_config.mutex);
-       /* Send Hotplug uevent so userspace can reprobe */
-       drm_kms_helper_hotplug_event(connector->dev);
-}
-
-bool
-intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
-                       struct intel_connector *intel_connector)
-{
-       struct drm_connector *connector = &intel_connector->base;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct drm_device *dev = intel_encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum port port = intel_encoder->port;
-       int type;
-
-       /* Initialize the work for modeset in case of link train failure */
-       INIT_WORK(&intel_connector->modeset_retry_work,
-                 intel_dp_modeset_retry_work_fn);
-
-       if (WARN(intel_dig_port->max_lanes < 1,
-                "Not enough lanes (%d) for DP on port %c\n",
-                intel_dig_port->max_lanes, port_name(port)))
-               return false;
-
-       intel_dp_set_source_rates(intel_dp);
-
-       intel_dp->reset_link_params = true;
-       intel_dp->pps_pipe = INVALID_PIPE;
-       intel_dp->active_pipe = INVALID_PIPE;
-
-       /* Preserve the current hw state. */
-       intel_dp->DP = I915_READ(intel_dp->output_reg);
-       intel_dp->attached_connector = intel_connector;
-
-       if (intel_dp_is_port_edp(dev_priv, port)) {
-               /*
-                * Currently we don't support eDP on TypeC ports, although in
-                * theory it could work on TypeC legacy ports.
-                */
-               WARN_ON(intel_port_is_tc(dev_priv, port));
-               type = DRM_MODE_CONNECTOR_eDP;
-       } else {
-               type = DRM_MODE_CONNECTOR_DisplayPort;
-       }
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               intel_dp->active_pipe = vlv_active_pipe(intel_dp);
-
-       /*
-        * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
-        * for DP the encoder type can be set by the caller to
-        * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
-        */
-       if (type == DRM_MODE_CONNECTOR_eDP)
-               intel_encoder->type = INTEL_OUTPUT_EDP;
-
-       /* eDP only on port B and/or C on vlv/chv */
-       if (WARN_ON((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-                   intel_dp_is_edp(intel_dp) &&
-                   port != PORT_B && port != PORT_C))
-               return false;
-
-       DRM_DEBUG_KMS("Adding %s connector on port %c\n",
-                       type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
-                       port_name(port));
-
-       drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
-       drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
-
-       if (!HAS_GMCH(dev_priv))
-               connector->interlace_allowed = true;
-       connector->doublescan_allowed = 0;
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               connector->ycbcr_420_allowed = true;
-
-       intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
-
-       intel_dp_aux_init(intel_dp);
-
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
-
-       if (HAS_DDI(dev_priv))
-               intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
-       else
-               intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       /* init MST on ports that can support it */
-       if (HAS_DP_MST(dev_priv) && !intel_dp_is_edp(intel_dp) &&
-           (port == PORT_B || port == PORT_C ||
-            port == PORT_D || port == PORT_F))
-               intel_dp_mst_encoder_init(intel_dig_port,
-                                         intel_connector->base.base.id);
-
-       if (!intel_edp_init_connector(intel_dp, intel_connector)) {
-               intel_dp_aux_fini(intel_dp);
-               intel_dp_mst_encoder_cleanup(intel_dig_port);
-               goto fail;
-       }
-
-       intel_dp_add_properties(intel_dp, connector);
-
-       if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) {
-               int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim);
-               if (ret)
-                       DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
-       }
-
-       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
-        * 0xd.  Failure to do so will result in spurious interrupts being
-        * generated on the port when a cable is not attached.
-        */
-       if (IS_G45(dev_priv)) {
-               u32 temp = I915_READ(PEG_BAND_GAP_DATA);
-               I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
-       }
-
-       return true;
-
-fail:
-       drm_connector_cleanup(connector);
-
-       return false;
-}
-
-bool intel_dp_init(struct drm_i915_private *dev_priv,
-                  i915_reg_t output_reg,
-                  enum port port)
-{
-       struct intel_digital_port *intel_dig_port;
-       struct intel_encoder *intel_encoder;
-       struct drm_encoder *encoder;
-       struct intel_connector *intel_connector;
-
-       intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
-       if (!intel_dig_port)
-               return false;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector)
-               goto err_connector_alloc;
-
-       intel_encoder = &intel_dig_port->base;
-       encoder = &intel_encoder->base;
-
-       if (drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
-                            &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
-                            "DP %c", port_name(port)))
-               goto err_encoder_init;
-
-       intel_encoder->hotplug = intel_dp_hotplug;
-       intel_encoder->compute_config = intel_dp_compute_config;
-       intel_encoder->get_hw_state = intel_dp_get_hw_state;
-       intel_encoder->get_config = intel_dp_get_config;
-       intel_encoder->update_pipe = intel_panel_update_backlight;
-       intel_encoder->suspend = intel_dp_encoder_suspend;
-       if (IS_CHERRYVIEW(dev_priv)) {
-               intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
-               intel_encoder->pre_enable = chv_pre_enable_dp;
-               intel_encoder->enable = vlv_enable_dp;
-               intel_encoder->disable = vlv_disable_dp;
-               intel_encoder->post_disable = chv_post_disable_dp;
-               intel_encoder->post_pll_disable = chv_dp_post_pll_disable;
-       } else if (IS_VALLEYVIEW(dev_priv)) {
-               intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable;
-               intel_encoder->pre_enable = vlv_pre_enable_dp;
-               intel_encoder->enable = vlv_enable_dp;
-               intel_encoder->disable = vlv_disable_dp;
-               intel_encoder->post_disable = vlv_post_disable_dp;
-       } else {
-               intel_encoder->pre_enable = g4x_pre_enable_dp;
-               intel_encoder->enable = g4x_enable_dp;
-               intel_encoder->disable = g4x_disable_dp;
-               intel_encoder->post_disable = g4x_post_disable_dp;
-       }
-
-       intel_dig_port->dp.output_reg = output_reg;
-       intel_dig_port->max_lanes = 4;
-
-       intel_encoder->type = INTEL_OUTPUT_DP;
-       intel_encoder->power_domain = intel_port_to_power_domain(port);
-       if (IS_CHERRYVIEW(dev_priv)) {
-               if (port == PORT_D)
-                       intel_encoder->crtc_mask = 1 << 2;
-               else
-                       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       } else {
-               intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       }
-       intel_encoder->cloneable = 0;
-       intel_encoder->port = port;
-
-       intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
-
-       if (port != PORT_A)
-               intel_infoframe_init(intel_dig_port);
-
-       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
-       if (!intel_dp_init_connector(intel_dig_port, intel_connector))
-               goto err_init_connector;
-
-       return true;
-
-err_init_connector:
-       drm_encoder_cleanup(encoder);
-err_encoder_init:
-       kfree(intel_connector);
-err_connector_alloc:
-       kfree(intel_dig_port);
-       return false;
-}
-
-void intel_dp_mst_suspend(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder;
-
-       for_each_intel_encoder(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp;
-
-               if (encoder->type != INTEL_OUTPUT_DDI)
-                       continue;
-
-               intel_dp = enc_to_intel_dp(&encoder->base);
-
-               if (!intel_dp->can_mst)
-                       continue;
-
-               if (intel_dp->is_mst)
-                       drm_dp_mst_topology_mgr_suspend(&intel_dp->mst_mgr);
-       }
-}
-
-void intel_dp_mst_resume(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder;
-
-       for_each_intel_encoder(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp;
-               int ret;
-
-               if (encoder->type != INTEL_OUTPUT_DDI)
-                       continue;
-
-               intel_dp = enc_to_intel_dp(&encoder->base);
-
-               if (!intel_dp->can_mst)
-                       continue;
-
-               ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr);
-               if (ret) {
-                       intel_dp->is_mst = false;
-                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
-                                                       false);
-               }
-       }
-}
diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h
deleted file mode 100644 (file)
index da70b1a..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DP_H__
-#define __INTEL_DP_H__
-
-#include <linux/types.h>
-
-#include <drm/i915_drm.h>
-
-#include "i915_reg.h"
-
-enum pipe;
-struct drm_connector_state;
-struct drm_encoder;
-struct drm_i915_private;
-struct drm_modeset_acquire_ctx;
-struct intel_connector;
-struct intel_crtc_state;
-struct intel_digital_port;
-struct intel_dp;
-struct intel_encoder;
-
-struct link_config_limits {
-       int min_clock, max_clock;
-       int min_lane_count, max_lane_count;
-       int min_bpp, max_bpp;
-};
-
-void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
-                                      struct intel_crtc_state *pipe_config,
-                                      struct link_config_limits *limits);
-bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state);
-int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state);
-bool intel_dp_port_enabled(struct drm_i915_private *dev_priv,
-                          i915_reg_t dp_reg, enum port port,
-                          enum pipe *pipe);
-bool intel_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg,
-                  enum port port);
-bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
-                            struct intel_connector *intel_connector);
-void intel_dp_set_link_params(struct intel_dp *intel_dp,
-                             int link_rate, u8 lane_count,
-                             bool link_mst);
-int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
-                                           int link_rate, u8 lane_count);
-int intel_dp_retrain_link(struct intel_encoder *encoder,
-                         struct drm_modeset_acquire_ctx *ctx);
-void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
-void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
-                                          const struct intel_crtc_state *crtc_state,
-                                          bool enable);
-void intel_dp_encoder_reset(struct drm_encoder *encoder);
-void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
-void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
-int intel_dp_compute_config(struct intel_encoder *encoder,
-                           struct intel_crtc_state *pipe_config,
-                           struct drm_connector_state *conn_state);
-bool intel_dp_is_edp(struct intel_dp *intel_dp);
-bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port);
-enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
-                                 bool long_hpd);
-void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
-                           const struct drm_connector_state *conn_state);
-void intel_edp_backlight_off(const struct drm_connector_state *conn_state);
-void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
-void intel_edp_panel_on(struct intel_dp *intel_dp);
-void intel_edp_panel_off(struct intel_dp *intel_dp);
-void intel_dp_mst_suspend(struct drm_i915_private *dev_priv);
-void intel_dp_mst_resume(struct drm_i915_private *dev_priv);
-int intel_dp_max_link_rate(struct intel_dp *intel_dp);
-int intel_dp_max_lane_count(struct intel_dp *intel_dp);
-int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
-void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-u32 intel_dp_pack_aux(const u8 *src, int src_bytes);
-
-void intel_edp_drrs_enable(struct intel_dp *intel_dp,
-                          const struct intel_crtc_state *crtc_state);
-void intel_edp_drrs_disable(struct intel_dp *intel_dp,
-                           const struct intel_crtc_state *crtc_state);
-void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
-                              unsigned int frontbuffer_bits);
-void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
-                         unsigned int frontbuffer_bits);
-
-void
-intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
-                                      u8 dp_train_pat);
-void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp);
-void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
-u8
-intel_dp_voltage_max(struct intel_dp *intel_dp);
-u8
-intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, u8 voltage_swing);
-void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
-                          u8 *link_bw, u8 *rate_select);
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
-bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
-u16 intel_dp_dsc_get_output_bpp(int link_clock, u8 lane_count,
-                               int mode_clock, int mode_hdisplay);
-u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, int mode_clock,
-                               int mode_hdisplay);
-
-bool intel_dp_read_dpcd(struct intel_dp *intel_dp);
-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)
-{
-       return ~((1 << lane_count) - 1) & 0xf;
-}
-
-#endif /* __INTEL_DP_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/intel_dp_aux_backlight.c
deleted file mode 100644 (file)
index 7ded95a..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright © 2015 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- */
-
-#include "intel_dp_aux_backlight.h"
-#include "intel_drv.h"
-
-static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable)
-{
-       u8 reg_val = 0;
-
-       /* Early return when display use other mechanism to enable backlight. */
-       if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP))
-               return;
-
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER,
-                             &reg_val) < 0) {
-               DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
-                             DP_EDP_DISPLAY_CONTROL_REGISTER);
-               return;
-       }
-       if (enable)
-               reg_val |= DP_EDP_BACKLIGHT_ENABLE;
-       else
-               reg_val &= ~(DP_EDP_BACKLIGHT_ENABLE);
-
-       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER,
-                              reg_val) != 1) {
-               DRM_DEBUG_KMS("Failed to %s aux backlight\n",
-                             enable ? "enable" : "disable");
-       }
-}
-
-/*
- * Read the current backlight value from DPCD register(s) based
- * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
- */
-static u32 intel_dp_aux_get_backlight(struct intel_connector *connector)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-       u8 read_val[2] = { 0x0 };
-       u16 level = 0;
-
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
-                            &read_val, sizeof(read_val)) < 0) {
-               DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
-                             DP_EDP_BACKLIGHT_BRIGHTNESS_MSB);
-               return 0;
-       }
-       level = read_val[0];
-       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
-               level = (read_val[0] << 8 | read_val[1]);
-
-       return level;
-}
-
-/*
- * Sends the current backlight level over the aux channel, checking if its using
- * 8-bit or 16 bit value (MSB and LSB)
- */
-static void
-intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-       u8 vals[2] = { 0x0 };
-
-       vals[0] = level;
-
-       /* Write the MSB and/or LSB */
-       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) {
-               vals[0] = (level & 0xFF00) >> 8;
-               vals[1] = (level & 0xFF);
-       }
-       if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
-                             vals, sizeof(vals)) < 0) {
-               DRM_DEBUG_KMS("Failed to write aux backlight level\n");
-               return;
-       }
-}
-
-/*
- * Set PWM Frequency divider to match desired frequency in vbt.
- * The PWM Frequency is calculated as 27Mhz / (F x P).
- * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the
- *             EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h)
- * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the
- *             EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h)
- */
-static bool intel_dp_aux_set_pwm_freq(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-       int freq, fxp, fxp_min, fxp_max, fxp_actual, f = 1;
-       u8 pn, pn_min, pn_max;
-
-       /* Find desired value of (F x P)
-        * Note that, if F x P is out of supported range, the maximum value or
-        * minimum value will applied automatically. So no need to check that.
-        */
-       freq = dev_priv->vbt.backlight.pwm_freq_hz;
-       DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq);
-       if (!freq) {
-               DRM_DEBUG_KMS("Use panel default backlight frequency\n");
-               return false;
-       }
-
-       fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq);
-
-       /* Use highest possible value of Pn for more granularity of brightness
-        * adjustment while satifying the conditions below.
-        * - Pn is in the range of Pn_min and Pn_max
-        * - F is in the range of 1 and 255
-        * - FxP is within 25% of desired value.
-        *   Note: 25% is arbitrary value and may need some tweak.
-        */
-       if (drm_dp_dpcd_readb(&intel_dp->aux,
-                              DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min) != 1) {
-               DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n");
-               return false;
-       }
-       if (drm_dp_dpcd_readb(&intel_dp->aux,
-                              DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max) != 1) {
-               DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n");
-               return false;
-       }
-       pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
-       pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
-
-       fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4);
-       fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4);
-       if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) {
-               DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n");
-               return false;
-       }
-
-       for (pn = pn_max; pn >= pn_min; pn--) {
-               f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255);
-               fxp_actual = f << pn;
-               if (fxp_min <= fxp_actual && fxp_actual <= fxp_max)
-                       break;
-       }
-
-       if (drm_dp_dpcd_writeb(&intel_dp->aux,
-                              DP_EDP_PWMGEN_BIT_COUNT, pn) < 0) {
-               DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
-               return false;
-       }
-       if (drm_dp_dpcd_writeb(&intel_dp->aux,
-                              DP_EDP_BACKLIGHT_FREQ_SET, (u8) f) < 0) {
-               DRM_DEBUG_KMS("Failed to write aux backlight freq\n");
-               return false;
-       }
-       return true;
-}
-
-static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                         const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-       u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode;
-
-       if (drm_dp_dpcd_readb(&intel_dp->aux,
-                       DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) {
-               DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
-                             DP_EDP_BACKLIGHT_MODE_SET_REGISTER);
-               return;
-       }
-
-       new_dpcd_buf = dpcd_buf;
-       edp_backlight_mode = dpcd_buf & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK;
-
-       switch (edp_backlight_mode) {
-       case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM:
-       case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET:
-       case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT:
-               new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK;
-               new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD;
-               break;
-
-       /* Do nothing when it is already DPCD mode */
-       case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD:
-       default:
-               break;
-       }
-
-       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP)
-               if (intel_dp_aux_set_pwm_freq(connector))
-                       new_dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE;
-
-       if (new_dpcd_buf != dpcd_buf) {
-               if (drm_dp_dpcd_writeb(&intel_dp->aux,
-                       DP_EDP_BACKLIGHT_MODE_SET_REGISTER, new_dpcd_buf) < 0) {
-                       DRM_DEBUG_KMS("Failed to write aux backlight mode\n");
-               }
-       }
-
-       set_aux_backlight_enable(intel_dp, true);
-       intel_dp_aux_set_backlight(conn_state, connector->panel.backlight.level);
-}
-
-static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       set_aux_backlight_enable(enc_to_intel_dp(old_conn_state->best_encoder), false);
-}
-
-static int intel_dp_aux_setup_backlight(struct intel_connector *connector,
-                                       enum pipe pipe)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-       struct intel_panel *panel = &connector->panel;
-
-       if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
-               panel->backlight.max = 0xFFFF;
-       else
-               panel->backlight.max = 0xFF;
-
-       panel->backlight.min = 0;
-       panel->backlight.level = intel_dp_aux_get_backlight(connector);
-
-       panel->backlight.enabled = panel->backlight.level != 0;
-
-       return 0;
-}
-
-static bool
-intel_dp_aux_display_control_capable(struct intel_connector *connector)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-
-       /* Check the eDP Display control capabilities registers to determine if
-        * the panel can support backlight control over the aux channel
-        */
-       if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
-           (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) &&
-           !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
-               DRM_DEBUG_KMS("AUX Backlight Control Supported!\n");
-               return true;
-       }
-       return false;
-}
-
-int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector)
-{
-       struct intel_panel *panel = &intel_connector->panel;
-
-       if (!i915_modparams.enable_dpcd_backlight)
-               return -ENODEV;
-
-       if (!intel_dp_aux_display_control_capable(intel_connector))
-               return -ENODEV;
-
-       panel->backlight.setup = intel_dp_aux_setup_backlight;
-       panel->backlight.enable = intel_dp_aux_enable_backlight;
-       panel->backlight.disable = intel_dp_aux_disable_backlight;
-       panel->backlight.set = intel_dp_aux_set_backlight;
-       panel->backlight.get = intel_dp_aux_get_backlight;
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/i915/intel_dp_aux_backlight.h b/drivers/gpu/drm/i915/intel_dp_aux_backlight.h
deleted file mode 100644 (file)
index ed60c28..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DP_AUX_BACKLIGHT_H__
-#define __INTEL_DP_AUX_BACKLIGHT_H__
-
-struct intel_connector;
-
-int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector);
-
-#endif /* __INTEL_DP_AUX_BACKLIGHT_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
deleted file mode 100644 (file)
index 9b1fcce..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright © 2008-2015 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include "intel_dp.h"
-#include "intel_dp_link_training.h"
-#include "intel_drv.h"
-
-static void
-intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
-{
-
-       DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x",
-                     link_status[0], link_status[1], link_status[2],
-                     link_status[3], link_status[4], link_status[5]);
-}
-
-static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-                      const u8 link_status[DP_LINK_STATUS_SIZE])
-{
-       u8 v = 0;
-       u8 p = 0;
-       int lane;
-       u8 voltage_max;
-       u8 preemph_max;
-
-       for (lane = 0; lane < intel_dp->lane_count; lane++) {
-               u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
-               u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
-
-               if (this_v > v)
-                       v = this_v;
-               if (this_p > p)
-                       p = this_p;
-       }
-
-       voltage_max = intel_dp_voltage_max(intel_dp);
-       if (v >= voltage_max)
-               v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
-
-       preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
-       if (p >= preemph_max)
-               p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
-
-       for (lane = 0; lane < 4; lane++)
-               intel_dp->train_set[lane] = v | p;
-}
-
-static bool
-intel_dp_set_link_train(struct intel_dp *intel_dp,
-                       u8 dp_train_pat)
-{
-       u8 buf[sizeof(intel_dp->train_set) + 1];
-       int ret, len;
-
-       intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
-
-       buf[0] = dp_train_pat;
-       if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
-           DP_TRAINING_PATTERN_DISABLE) {
-               /* don't write DP_TRAINING_LANEx_SET on disable */
-               len = 1;
-       } else {
-               /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
-               memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
-               len = intel_dp->lane_count + 1;
-       }
-
-       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
-                               buf, len);
-
-       return ret == len;
-}
-
-static bool
-intel_dp_reset_link_train(struct intel_dp *intel_dp,
-                       u8 dp_train_pat)
-{
-       memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
-       intel_dp_set_signal_levels(intel_dp);
-       return intel_dp_set_link_train(intel_dp, dp_train_pat);
-}
-
-static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp)
-{
-       int ret;
-
-       intel_dp_set_signal_levels(intel_dp);
-
-       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
-                               intel_dp->train_set, intel_dp->lane_count);
-
-       return ret == intel_dp->lane_count;
-}
-
-static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
-{
-       int lane;
-
-       for (lane = 0; lane < intel_dp->lane_count; lane++)
-               if ((intel_dp->train_set[lane] &
-                    DP_TRAIN_MAX_SWING_REACHED) == 0)
-                       return false;
-
-       return true;
-}
-
-/* Enable corresponding port and start training pattern 1 */
-static bool
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
-{
-       u8 voltage;
-       int voltage_tries, cr_tries, max_cr_tries;
-       bool max_vswing_reached = false;
-       u8 link_config[2];
-       u8 link_bw, rate_select;
-
-       if (intel_dp->prepare_link_retrain)
-               intel_dp->prepare_link_retrain(intel_dp);
-
-       intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
-                             &link_bw, &rate_select);
-
-       if (link_bw)
-               DRM_DEBUG_KMS("Using LINK_BW_SET value %02x\n", link_bw);
-       else
-               DRM_DEBUG_KMS("Using LINK_RATE_SET value %02x\n", rate_select);
-
-       /* Write the link configuration data */
-       link_config[0] = link_bw;
-       link_config[1] = intel_dp->lane_count;
-       if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-               link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-       drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
-
-       /* eDP 1.4 rate select method. */
-       if (!link_bw)
-               drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
-                                 &rate_select, 1);
-
-       link_config[0] = 0;
-       link_config[1] = DP_SET_ANSI_8B10B;
-       drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
-
-       intel_dp->DP |= DP_PORT_EN;
-
-       /* clock recovery */
-       if (!intel_dp_reset_link_train(intel_dp,
-                                      DP_TRAINING_PATTERN_1 |
-                                      DP_LINK_SCRAMBLING_DISABLE)) {
-               DRM_ERROR("failed to enable link training\n");
-               return false;
-       }
-
-       /*
-        * The DP 1.4 spec defines the max clock recovery retries value
-        * as 10 but for pre-DP 1.4 devices we set a very tolerant
-        * retry limit of 80 (4 voltage levels x 4 preemphasis levels x
-        * x 5 identical voltage retries). Since the previous specs didn't
-        * define a limit and created the possibility of an infinite loop
-        * we want to prevent any sync from triggering that corner case.
-        */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
-               max_cr_tries = 10;
-       else
-               max_cr_tries = 80;
-
-       voltage_tries = 1;
-       for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
-               u8 link_status[DP_LINK_STATUS_SIZE];
-
-               drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
-
-               if (!intel_dp_get_link_status(intel_dp, link_status)) {
-                       DRM_ERROR("failed to get link status\n");
-                       return false;
-               }
-
-               if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
-                       DRM_DEBUG_KMS("clock recovery OK\n");
-                       return true;
-               }
-
-               if (voltage_tries == 5) {
-                       DRM_DEBUG_KMS("Same voltage tried 5 times\n");
-                       return false;
-               }
-
-               if (max_vswing_reached) {
-                       DRM_DEBUG_KMS("Max Voltage Swing reached\n");
-                       return false;
-               }
-
-               voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
-
-               /* Update training set as requested by target */
-               intel_get_adjust_train(intel_dp, link_status);
-               if (!intel_dp_update_link_train(intel_dp)) {
-                       DRM_ERROR("failed to update link training\n");
-                       return false;
-               }
-
-               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
-                   voltage)
-                       ++voltage_tries;
-               else
-                       voltage_tries = 1;
-
-               if (intel_dp_link_max_vswing_reached(intel_dp))
-                       max_vswing_reached = true;
-
-       }
-       DRM_ERROR("Failed clock recovery %d times, giving up!\n", max_cr_tries);
-       return false;
-}
-
-/*
- * Pick training pattern for channel equalization. Training pattern 4 for HBR3
- * or for 1.4 devices that support it, training Pattern 3 for HBR2
- * or 1.2 devices that support it, Training Pattern 2 otherwise.
- */
-static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
-{
-       bool source_tps3, sink_tps3, source_tps4, sink_tps4;
-
-       /*
-        * Intel platforms that support HBR3 also support TPS4. It is mandatory
-        * for all downstream devices that support HBR3. There are no known eDP
-        * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
-        * specification.
-        */
-       source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
-       sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
-       if (source_tps4 && sink_tps4) {
-               return DP_TRAINING_PATTERN_4;
-       } else if (intel_dp->link_rate == 810000) {
-               if (!source_tps4)
-                       DRM_DEBUG_KMS("8.1 Gbps link rate without source HBR3/TPS4 support\n");
-               if (!sink_tps4)
-                       DRM_DEBUG_KMS("8.1 Gbps link rate without sink TPS4 support\n");
-       }
-       /*
-        * Intel platforms that support HBR2 also support TPS3. TPS3 support is
-        * also mandatory for downstream devices that support HBR2. However, not
-        * all sinks follow the spec.
-        */
-       source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
-       sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
-       if (source_tps3 && sink_tps3) {
-               return  DP_TRAINING_PATTERN_3;
-       } else if (intel_dp->link_rate >= 540000) {
-               if (!source_tps3)
-                       DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n");
-               if (!sink_tps3)
-                       DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without sink TPS3 support\n");
-       }
-
-       return DP_TRAINING_PATTERN_2;
-}
-
-static bool
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
-{
-       int tries;
-       u32 training_pattern;
-       u8 link_status[DP_LINK_STATUS_SIZE];
-       bool channel_eq = false;
-
-       training_pattern = intel_dp_training_pattern(intel_dp);
-       /* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
-       if (training_pattern != DP_TRAINING_PATTERN_4)
-               training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
-
-       /* channel equalization */
-       if (!intel_dp_set_link_train(intel_dp,
-                                    training_pattern)) {
-               DRM_ERROR("failed to start channel equalization\n");
-               return false;
-       }
-
-       for (tries = 0; tries < 5; tries++) {
-
-               drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
-               if (!intel_dp_get_link_status(intel_dp, link_status)) {
-                       DRM_ERROR("failed to get link status\n");
-                       break;
-               }
-
-               /* Make sure clock is still ok */
-               if (!drm_dp_clock_recovery_ok(link_status,
-                                             intel_dp->lane_count)) {
-                       intel_dp_dump_link_status(link_status);
-                       DRM_DEBUG_KMS("Clock recovery check failed, cannot "
-                                     "continue channel equalization\n");
-                       break;
-               }
-
-               if (drm_dp_channel_eq_ok(link_status,
-                                        intel_dp->lane_count)) {
-                       channel_eq = true;
-                       DRM_DEBUG_KMS("Channel EQ done. DP Training "
-                                     "successful\n");
-                       break;
-               }
-
-               /* Update training set as requested by target */
-               intel_get_adjust_train(intel_dp, link_status);
-               if (!intel_dp_update_link_train(intel_dp)) {
-                       DRM_ERROR("failed to update link training\n");
-                       break;
-               }
-       }
-
-       /* Try 5 times, else fail and try at lower BW */
-       if (tries == 5) {
-               intel_dp_dump_link_status(link_status);
-               DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
-       }
-
-       intel_dp_set_idle_link_train(intel_dp);
-
-       return channel_eq;
-
-}
-
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
-{
-       intel_dp->link_trained = true;
-
-       intel_dp_set_link_train(intel_dp,
-                               DP_TRAINING_PATTERN_DISABLE);
-}
-
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
-{
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-
-       if (!intel_dp_link_training_clock_recovery(intel_dp))
-               goto failure_handling;
-       if (!intel_dp_link_training_channel_equalization(intel_dp))
-               goto failure_handling;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
-                     intel_connector->base.base.id,
-                     intel_connector->base.name,
-                     intel_dp->link_rate, intel_dp->lane_count);
-       return;
-
- failure_handling:
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
-                     intel_connector->base.base.id,
-                     intel_connector->base.name,
-                     intel_dp->link_rate, intel_dp->lane_count);
-       if (!intel_dp_get_link_train_fallback_values(intel_dp,
-                                                    intel_dp->link_rate,
-                                                    intel_dp->lane_count))
-               /* Schedule a Hotplug Uevent to userspace to start modeset */
-               schedule_work(&intel_connector->modeset_retry_work);
-       return;
-}
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.h b/drivers/gpu/drm/i915/intel_dp_link_training.h
deleted file mode 100644 (file)
index 174566a..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DP_LINK_TRAINING_H__
-#define __INTEL_DP_LINK_TRAINING_H__
-
-struct intel_dp;
-
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
-void intel_dp_stop_link_train(struct intel_dp *intel_dp);
-
-#endif /* __INTEL_DP_LINK_TRAINING_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
deleted file mode 100644 (file)
index 0caf645..0000000
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
- * Copyright © 2008 Intel Corporation
- *             2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- */
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_probe_helper.h>
-
-#include "i915_drv.h"
-#include "intel_atomic.h"
-#include "intel_audio.h"
-#include "intel_connector.h"
-#include "intel_ddi.h"
-#include "intel_dp.h"
-#include "intel_dp_mst.h"
-#include "intel_dpio_phy.h"
-#include "intel_drv.h"
-
-static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
-                                           struct intel_crtc_state *crtc_state,
-                                           struct drm_connector_state *conn_state,
-                                           struct link_config_limits *limits)
-{
-       struct drm_atomic_state *state = crtc_state->base.state;
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_dp *intel_dp = &intel_mst->primary->dp;
-       struct intel_connector *connector =
-               to_intel_connector(conn_state->connector);
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       void *port = connector->port;
-       bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
-                                          DP_DPCD_QUIRK_CONSTANT_N);
-       int bpp, slots = -EINVAL;
-
-       crtc_state->lane_count = limits->max_lane_count;
-       crtc_state->port_clock = limits->max_clock;
-
-       for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
-               crtc_state->pipe_bpp = bpp;
-
-               crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock,
-                                                      crtc_state->pipe_bpp);
-
-               slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
-                                                     port, crtc_state->pbn);
-               if (slots == -EDEADLK)
-                       return slots;
-               if (slots >= 0)
-                       break;
-       }
-
-       if (slots < 0) {
-               DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots);
-               return slots;
-       }
-
-       intel_link_compute_m_n(crtc_state->pipe_bpp,
-                              crtc_state->lane_count,
-                              adjusted_mode->crtc_clock,
-                              crtc_state->port_clock,
-                              &crtc_state->dp_m_n,
-                              constant_n);
-       crtc_state->dp_m_n.tu = slots;
-
-       return 0;
-}
-
-static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
-                                      struct intel_crtc_state *pipe_config,
-                                      struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_dp *intel_dp = &intel_mst->primary->dp;
-       struct intel_connector *connector =
-               to_intel_connector(conn_state->connector);
-       struct intel_digital_connector_state *intel_conn_state =
-               to_intel_digital_connector_state(conn_state);
-       const struct drm_display_mode *adjusted_mode =
-               &pipe_config->base.adjusted_mode;
-       void *port = connector->port;
-       struct link_config_limits limits;
-       int ret;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-       pipe_config->has_pch_encoder = false;
-
-       if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
-               pipe_config->has_audio =
-                       drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, port);
-       else
-               pipe_config->has_audio =
-                       intel_conn_state->force_audio == HDMI_AUDIO_ON;
-
-       /*
-        * for MST we always configure max link bw - the spec doesn't
-        * seem to suggest we should do otherwise.
-        */
-       limits.min_clock =
-       limits.max_clock = intel_dp_max_link_rate(intel_dp);
-
-       limits.min_lane_count =
-       limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
-
-       limits.min_bpp = intel_dp_min_bpp(pipe_config);
-       limits.max_bpp = pipe_config->pipe_bpp;
-
-       intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
-
-       ret = intel_dp_mst_compute_link_config(encoder, pipe_config,
-                                              conn_state, &limits);
-       if (ret)
-               return ret;
-
-       pipe_config->limited_color_range =
-               intel_dp_limited_color_range(pipe_config, conn_state);
-
-       if (IS_GEN9_LP(dev_priv))
-               pipe_config->lane_lat_optim_mask =
-                       bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count);
-
-       intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
-
-       return 0;
-}
-
-static int
-intel_dp_mst_atomic_check(struct drm_connector *connector,
-                         struct drm_connector_state *new_conn_state)
-{
-       struct drm_atomic_state *state = new_conn_state->state;
-       struct drm_connector_state *old_conn_state =
-               drm_atomic_get_old_connector_state(state, connector);
-       struct intel_connector *intel_connector =
-               to_intel_connector(connector);
-       struct drm_crtc *new_crtc = new_conn_state->crtc;
-       struct drm_crtc_state *crtc_state;
-       struct drm_dp_mst_topology_mgr *mgr;
-       int ret;
-
-       ret = intel_digital_connector_atomic_check(connector, new_conn_state);
-       if (ret)
-               return ret;
-
-       if (!old_conn_state->crtc)
-               return 0;
-
-       /* We only want to free VCPI if this state disables the CRTC on this
-        * connector
-        */
-       if (new_crtc) {
-               crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
-
-               if (!crtc_state ||
-                   !drm_atomic_crtc_needs_modeset(crtc_state) ||
-                   crtc_state->enable)
-                       return 0;
-       }
-
-       mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr;
-       ret = drm_dp_atomic_release_vcpi_slots(state, mgr,
-                                              intel_connector->port);
-
-       return ret;
-}
-
-static void intel_mst_disable_dp(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *old_crtc_state,
-                                const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct intel_connector *connector =
-               to_intel_connector(old_conn_state->connector);
-       int ret;
-
-       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
-
-       drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
-
-       ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
-       if (ret) {
-               DRM_ERROR("failed to update payload %d\n", ret);
-       }
-       if (old_crtc_state->has_audio)
-               intel_audio_codec_disable(encoder,
-                                         old_crtc_state, old_conn_state);
-}
-
-static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
-                                     const struct intel_crtc_state *old_crtc_state,
-                                     const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct intel_connector *connector =
-               to_intel_connector(old_conn_state->connector);
-
-       intel_ddi_disable_pipe_clock(old_crtc_state);
-
-       /* this can fail */
-       drm_dp_check_act_status(&intel_dp->mst_mgr);
-       /* and this can also fail */
-       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
-
-       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
-
-       /*
-        * Power down mst path before disabling the port, otherwise we end
-        * up getting interrupts from the sink upon detecting link loss.
-        */
-       drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port,
-                                    false);
-
-       intel_dp->active_mst_links--;
-
-       intel_mst->connector = NULL;
-       if (intel_dp->active_mst_links == 0) {
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
-               intel_dig_port->base.post_disable(&intel_dig_port->base,
-                                                 old_crtc_state, NULL);
-       }
-
-       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
-}
-
-static void intel_mst_pre_pll_enable_dp(struct intel_encoder *encoder,
-                                       const struct intel_crtc_state *pipe_config,
-                                       const struct drm_connector_state *conn_state)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-
-       if (intel_dp->active_mst_links == 0)
-               intel_dig_port->base.pre_pll_enable(&intel_dig_port->base,
-                                                   pipe_config, NULL);
-}
-
-static void intel_mst_post_pll_disable_dp(struct intel_encoder *encoder,
-                                         const struct intel_crtc_state *old_crtc_state,
-                                         const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-
-       if (intel_dp->active_mst_links == 0)
-               intel_dig_port->base.post_pll_disable(&intel_dig_port->base,
-                                                     old_crtc_state,
-                                                     old_conn_state);
-}
-
-static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
-                                   const struct intel_crtc_state *pipe_config,
-                                   const struct drm_connector_state *conn_state)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = intel_dig_port->base.port;
-       struct intel_connector *connector =
-               to_intel_connector(conn_state->connector);
-       int ret;
-       u32 temp;
-
-       /* MST encoders are bound to a crtc, not to a connector,
-        * force the mapping here for get_hw_state.
-        */
-       connector->encoder = encoder;
-       intel_mst->connector = connector;
-
-       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
-
-       if (intel_dp->active_mst_links == 0)
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
-
-       drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true);
-
-       if (intel_dp->active_mst_links == 0)
-               intel_dig_port->base.pre_enable(&intel_dig_port->base,
-                                               pipe_config, NULL);
-
-       ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
-                                      connector->port,
-                                      pipe_config->pbn,
-                                      pipe_config->dp_m_n.tu);
-       if (!ret)
-               DRM_ERROR("failed to allocate vcpi\n");
-
-       intel_dp->active_mst_links++;
-       temp = I915_READ(DP_TP_STATUS(port));
-       I915_WRITE(DP_TP_STATUS(port), temp);
-
-       ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
-
-       intel_ddi_enable_pipe_clock(pipe_config);
-}
-
-static void intel_mst_enable_dp(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *pipe_config,
-                               const struct drm_connector_state *conn_state)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = intel_dig_port->base.port;
-
-       DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   DP_TP_STATUS(port),
-                                   DP_TP_STATUS_ACT_SENT,
-                                   DP_TP_STATUS_ACT_SENT,
-                                   1))
-               DRM_ERROR("Timed out waiting for ACT sent\n");
-
-       drm_dp_check_act_status(&intel_dp->mst_mgr);
-
-       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
-       if (pipe_config->has_audio)
-               intel_audio_codec_enable(encoder, pipe_config, conn_state);
-}
-
-static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
-                                     enum pipe *pipe)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       *pipe = intel_mst->pipe;
-       if (intel_mst->connector)
-               return true;
-       return false;
-}
-
-static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
-                                       struct intel_crtc_state *pipe_config)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
-       struct intel_digital_port *intel_dig_port = intel_mst->primary;
-
-       intel_ddi_get_config(&intel_dig_port->base, pipe_config);
-}
-
-static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_dp *intel_dp = intel_connector->mst_port;
-       struct edid *edid;
-       int ret;
-
-       if (drm_connector_is_unregistered(connector))
-               return intel_connector_update_modes(connector, NULL);
-
-       edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
-       ret = intel_connector_update_modes(connector, edid);
-       kfree(edid);
-
-       return ret;
-}
-
-static enum drm_connector_status
-intel_dp_mst_detect(struct drm_connector *connector, bool force)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_dp *intel_dp = intel_connector->mst_port;
-
-       if (drm_connector_is_unregistered(connector))
-               return connector_status_disconnected;
-       return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr,
-                                     intel_connector->port);
-}
-
-static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
-       .detect = intel_dp_mst_detect,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static int intel_dp_mst_get_modes(struct drm_connector *connector)
-{
-       return intel_dp_mst_get_ddc_modes(connector);
-}
-
-static enum drm_mode_status
-intel_dp_mst_mode_valid(struct drm_connector *connector,
-                       struct drm_display_mode *mode)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_dp *intel_dp = intel_connector->mst_port;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-       int max_rate, mode_rate, max_lanes, max_link_clock;
-
-       if (drm_connector_is_unregistered(connector))
-               return MODE_ERROR;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       max_link_clock = intel_dp_max_link_rate(intel_dp);
-       max_lanes = intel_dp_max_lane_count(intel_dp);
-
-       max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
-       mode_rate = intel_dp_link_required(mode->clock, 18);
-
-       /* TODO - validate mode against available PBN for link */
-       if (mode->clock < 10000)
-               return MODE_CLOCK_LOW;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
-               return MODE_H_ILLEGAL;
-
-       if (mode_rate > max_rate || mode->clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       return MODE_OK;
-}
-
-static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
-                                                        struct drm_connector_state *state)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_dp *intel_dp = intel_connector->mst_port;
-       struct intel_crtc *crtc = to_intel_crtc(state->crtc);
-
-       return &intel_dp->mst_encoders[crtc->pipe]->base.base;
-}
-
-static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
-       .get_modes = intel_dp_mst_get_modes,
-       .mode_valid = intel_dp_mst_mode_valid,
-       .atomic_best_encoder = intel_mst_atomic_best_encoder,
-       .atomic_check = intel_dp_mst_atomic_check,
-};
-
-static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
-{
-       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
-
-       drm_encoder_cleanup(encoder);
-       kfree(intel_mst);
-}
-
-static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {
-       .destroy = intel_dp_mst_encoder_destroy,
-};
-
-static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
-{
-       if (connector->encoder && connector->base.state->crtc) {
-               enum pipe pipe;
-               if (!connector->encoder->get_hw_state(connector->encoder, &pipe))
-                       return false;
-               return true;
-       }
-       return false;
-}
-
-static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop)
-{
-       struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_device *dev = intel_dig_port->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_connector *intel_connector;
-       struct drm_connector *connector;
-       enum pipe pipe;
-       int ret;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector)
-               return NULL;
-
-       intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
-       intel_connector->mst_port = intel_dp;
-       intel_connector->port = port;
-       drm_dp_mst_get_port_malloc(port);
-
-       connector = &intel_connector->base;
-       ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
-                                DRM_MODE_CONNECTOR_DisplayPort);
-       if (ret) {
-               intel_connector_free(intel_connector);
-               return NULL;
-       }
-
-       drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
-
-       for_each_pipe(dev_priv, pipe) {
-               struct drm_encoder *enc =
-                       &intel_dp->mst_encoders[pipe]->base.base;
-
-               ret = drm_connector_attach_encoder(&intel_connector->base, enc);
-               if (ret)
-                       goto err;
-       }
-
-       drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
-       drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
-
-       ret = drm_connector_set_path_property(connector, pathprop);
-       if (ret)
-               goto err;
-
-       intel_attach_force_audio_property(connector);
-       intel_attach_broadcast_rgb_property(connector);
-       drm_connector_attach_max_bpc_property(connector, 6, 12);
-
-       return connector;
-
-err:
-       drm_connector_cleanup(connector);
-       return NULL;
-}
-
-static void intel_dp_register_mst_connector(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-
-       if (dev_priv->fbdev)
-               drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper,
-                                               connector);
-
-       drm_connector_register(connector);
-}
-
-static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
-                                          struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name);
-       drm_connector_unregister(connector);
-
-       if (dev_priv->fbdev)
-               drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper,
-                                                  connector);
-
-       drm_connector_put(connector);
-}
-
-static const struct drm_dp_mst_topology_cbs mst_cbs = {
-       .add_connector = intel_dp_add_mst_connector,
-       .register_connector = intel_dp_register_mst_connector,
-       .destroy_connector = intel_dp_destroy_mst_connector,
-};
-
-static struct intel_dp_mst_encoder *
-intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe)
-{
-       struct intel_dp_mst_encoder *intel_mst;
-       struct intel_encoder *intel_encoder;
-       struct drm_device *dev = intel_dig_port->base.base.dev;
-
-       intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
-
-       if (!intel_mst)
-               return NULL;
-
-       intel_mst->pipe = pipe;
-       intel_encoder = &intel_mst->base;
-       intel_mst->primary = intel_dig_port;
-
-       drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
-                        DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
-
-       intel_encoder->type = INTEL_OUTPUT_DP_MST;
-       intel_encoder->power_domain = intel_dig_port->base.power_domain;
-       intel_encoder->port = intel_dig_port->base.port;
-       intel_encoder->crtc_mask = 0x7;
-       intel_encoder->cloneable = 0;
-
-       intel_encoder->compute_config = intel_dp_mst_compute_config;
-       intel_encoder->disable = intel_mst_disable_dp;
-       intel_encoder->post_disable = intel_mst_post_disable_dp;
-       intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp;
-       intel_encoder->post_pll_disable = intel_mst_post_pll_disable_dp;
-       intel_encoder->pre_enable = intel_mst_pre_enable_dp;
-       intel_encoder->enable = intel_mst_enable_dp;
-       intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
-       intel_encoder->get_config = intel_dp_mst_enc_get_config;
-
-       return intel_mst;
-
-}
-
-static bool
-intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
-{
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
-       enum pipe pipe;
-
-       for_each_pipe(dev_priv, pipe)
-               intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
-       return true;
-}
-
-int
-intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
-{
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = intel_dig_port->base.base.dev;
-       int ret;
-
-       intel_dp->can_mst = true;
-       intel_dp->mst_mgr.cbs = &mst_cbs;
-
-       /* create encoders */
-       intel_dp_create_fake_mst_encoders(intel_dig_port);
-       ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
-                                          &intel_dp->aux, 16, 3, conn_base_id);
-       if (ret) {
-               intel_dp->can_mst = false;
-               return ret;
-       }
-       return 0;
-}
-
-void
-intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port)
-{
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-
-       if (!intel_dp->can_mst)
-               return;
-
-       drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr);
-       /* encoders will get killed by normal cleanup */
-}
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.h b/drivers/gpu/drm/i915/intel_dp_mst.h
deleted file mode 100644 (file)
index 1470c6e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DP_MST_H__
-#define __INTEL_DP_MST_H__
-
-struct intel_digital_port;
-
-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);
-
-#endif /* __INTEL_DP_MST_H__ */
index bdbe4175982710711569f8485745885e37f593c1..7ccf7f3974dbbbd2e647bed48964b1e0641dfe2d 100644 (file)
@@ -21,7 +21,8 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "intel_dp.h"
+#include "display/intel_dp.h"
+
 #include "intel_dpio_phy.h"
 #include "intel_drv.h"
 #include "intel_sideband.h"
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
deleted file mode 100644 (file)
index 5fec02a..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2018 Intel Corporation
- */
-
-#include <drm/drm_mipi_dsi.h>
-#include "intel_dsi.h"
-
-int intel_dsi_bitrate(const struct intel_dsi *intel_dsi)
-{
-       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-
-       if (WARN_ON(bpp < 0))
-               bpp = 16;
-
-       return intel_dsi->pclk * bpp / intel_dsi->lane_count;
-}
-
-int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi)
-{
-       switch (intel_dsi->escape_clk_div) {
-       default:
-       case 0:
-               return 50;
-       case 1:
-               return 100;
-       case 2:
-               return 200;
-       }
-}
-
-int intel_dsi_get_modes(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_display_mode *mode;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (!intel_connector->panel.fixed_mode) {
-               DRM_DEBUG_KMS("no fixed mode\n");
-               return 0;
-       }
-
-       mode = drm_mode_duplicate(connector->dev,
-                                 intel_connector->panel.fixed_mode);
-       if (!mode) {
-               DRM_DEBUG_KMS("drm_mode_duplicate failed\n");
-               return 0;
-       }
-
-       drm_mode_probed_add(connector, mode);
-       return 1;
-}
-
-enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
-                                         struct drm_display_mode *mode)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       if (fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-               if (fixed_mode->clock > max_dotclk)
-                       return MODE_CLOCK_HIGH;
-       }
-
-       return MODE_OK;
-}
-
-struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
-                                          const struct mipi_dsi_host_ops *funcs,
-                                          enum port port)
-{
-       struct intel_dsi_host *host;
-       struct mipi_dsi_device *device;
-
-       host = kzalloc(sizeof(*host), GFP_KERNEL);
-       if (!host)
-               return NULL;
-
-       host->base.ops = funcs;
-       host->intel_dsi = intel_dsi;
-       host->port = port;
-
-       /*
-        * We should call mipi_dsi_host_register(&host->base) here, but we don't
-        * have a host->dev, and we don't have OF stuff either. So just use the
-        * dsi framework as a library and hope for the best. Create the dsi
-        * devices by ourselves here too. Need to be careful though, because we
-        * don't initialize any of the driver model devices here.
-        */
-       device = kzalloc(sizeof(*device), GFP_KERNEL);
-       if (!device) {
-               kfree(host);
-               return NULL;
-       }
-
-       device->host = &host->base;
-       host->device = device;
-
-       return host;
-}
-
-enum drm_panel_orientation
-intel_dsi_get_panel_orientation(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum drm_panel_orientation orientation;
-
-       orientation = dev_priv->vbt.dsi.orientation;
-       if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
-               return orientation;
-
-       orientation = dev_priv->vbt.orientation;
-       if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
-               return orientation;
-
-       return DRM_MODE_PANEL_ORIENTATION_NORMAL;
-}
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
deleted file mode 100644 (file)
index 6d20434..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _INTEL_DSI_H
-#define _INTEL_DSI_H
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_mipi_dsi.h>
-#include "intel_drv.h"
-
-#define INTEL_DSI_VIDEO_MODE   0
-#define INTEL_DSI_COMMAND_MODE 1
-
-/* Dual Link support */
-#define DSI_DUAL_LINK_NONE             0
-#define DSI_DUAL_LINK_FRONT_BACK       1
-#define DSI_DUAL_LINK_PIXEL_ALT                2
-
-struct intel_dsi_host;
-
-struct intel_dsi {
-       struct intel_encoder base;
-
-       struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
-       intel_wakeref_t io_wakeref[I915_MAX_PORTS];
-
-       /* GPIO Desc for CRC based Panel control */
-       struct gpio_desc *gpio_panel;
-
-       struct intel_connector *attached_connector;
-
-       /* bit mask of ports being driven */
-       u16 ports;
-
-       /* if true, use HS mode, otherwise LP */
-       bool hs;
-
-       /* virtual channel */
-       int channel;
-
-       /* Video mode or command mode */
-       u16 operation_mode;
-
-       /* number of DSI lanes */
-       unsigned int lane_count;
-
-       /*
-        * video mode pixel format
-        *
-        * XXX: consolidate on .format in struct mipi_dsi_device.
-        */
-       enum mipi_dsi_pixel_format pixel_format;
-
-       /* video mode format for MIPI_VIDEO_MODE_FORMAT register */
-       u32 video_mode_format;
-
-       /* eot for MIPI_EOT_DISABLE register */
-       u8 eotp_pkt;
-       u8 clock_stop;
-
-       u8 escape_clk_div;
-       u8 dual_link;
-
-       u16 dcs_backlight_ports;
-       u16 dcs_cabc_ports;
-
-       /* RGB or BGR */
-       bool bgr_enabled;
-
-       u8 pixel_overlap;
-       u32 port_bits;
-       u32 bw_timer;
-       u32 dphy_reg;
-
-       /* data lanes dphy timing */
-       u32 dphy_data_lane_reg;
-       u32 video_frmt_cfg_bits;
-       u16 lp_byte_clk;
-
-       /* timeouts in byte clocks */
-       u16 hs_tx_timeout;
-       u16 lp_rx_timeout;
-       u16 turn_arnd_val;
-       u16 rst_timer_val;
-       u16 hs_to_lp_count;
-       u16 clk_lp_to_hs_count;
-       u16 clk_hs_to_lp_count;
-
-       u16 init_count;
-       u32 pclk;
-       u16 burst_mode_ratio;
-
-       /* all delays in ms */
-       u16 backlight_off_delay;
-       u16 backlight_on_delay;
-       u16 panel_on_delay;
-       u16 panel_off_delay;
-       u16 panel_pwr_cycle_delay;
-};
-
-struct intel_dsi_host {
-       struct mipi_dsi_host base;
-       struct intel_dsi *intel_dsi;
-       enum port port;
-
-       /* our little hack */
-       struct mipi_dsi_device *device;
-};
-
-static inline struct intel_dsi_host *to_intel_dsi_host(struct mipi_dsi_host *h)
-{
-       return container_of(h, struct intel_dsi_host, base);
-}
-
-#define for_each_dsi_port(__port, __ports_mask) for_each_port_masked(__port, __ports_mask)
-
-static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
-{
-       return container_of(encoder, struct intel_dsi, base.base);
-}
-
-static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
-{
-       return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
-}
-
-static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
-{
-       return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE;
-}
-
-static inline u16 intel_dsi_encoder_ports(struct intel_encoder *encoder)
-{
-       return enc_to_intel_dsi(&encoder->base)->ports;
-}
-
-/* icl_dsi.c */
-void icl_dsi_init(struct drm_i915_private *dev_priv);
-
-/* intel_dsi.c */
-int intel_dsi_bitrate(const struct intel_dsi *intel_dsi);
-int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi);
-enum drm_panel_orientation
-intel_dsi_get_panel_orientation(struct intel_connector *connector);
-
-/* vlv_dsi.c */
-void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
-enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt);
-int intel_dsi_get_modes(struct drm_connector *connector);
-enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
-                                         struct drm_display_mode *mode);
-struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
-                                          const struct mipi_dsi_host_ops *funcs,
-                                          enum port port);
-void vlv_dsi_init(struct drm_i915_private *dev_priv);
-
-/* vlv_dsi_pll.c */
-int vlv_dsi_pll_compute(struct intel_encoder *encoder,
-                       struct intel_crtc_state *config);
-void vlv_dsi_pll_enable(struct intel_encoder *encoder,
-                       const struct intel_crtc_state *config);
-void vlv_dsi_pll_disable(struct intel_encoder *encoder);
-u32 vlv_dsi_get_pclk(struct intel_encoder *encoder,
-                    struct intel_crtc_state *config);
-void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port);
-
-bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
-int bxt_dsi_pll_compute(struct intel_encoder *encoder,
-                       struct intel_crtc_state *config);
-void bxt_dsi_pll_enable(struct intel_encoder *encoder,
-                       const struct intel_crtc_state *config);
-void bxt_dsi_pll_disable(struct intel_encoder *encoder);
-u32 bxt_dsi_get_pclk(struct intel_encoder *encoder,
-                    struct intel_crtc_state *config);
-void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port);
-
-/* intel_dsi_vbt.c */
-bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id);
-void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
-                                enum mipi_seq seq_id);
-void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec);
-void intel_dsi_log_params(struct intel_dsi *intel_dsi);
-
-#endif /* _INTEL_DSI_H */
diff --git a/drivers/gpu/drm/i915/intel_dsi_dcs_backlight.c b/drivers/gpu/drm/i915/intel_dsi_dcs_backlight.c
deleted file mode 100644 (file)
index 8c33262..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Deepak M <m.deepak at intel.com>
- */
-
-#include <drm/drm_mipi_dsi.h>
-#include <video/mipi_display.h>
-
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_dsi_dcs_backlight.h"
-
-#define CONTROL_DISPLAY_BCTRL          (1 << 5)
-#define CONTROL_DISPLAY_DD             (1 << 3)
-#define CONTROL_DISPLAY_BL             (1 << 2)
-
-#define POWER_SAVE_OFF                 (0 << 0)
-#define POWER_SAVE_LOW                 (1 << 0)
-#define POWER_SAVE_MEDIUM              (2 << 0)
-#define POWER_SAVE_HIGH                        (3 << 0)
-#define POWER_SAVE_OUTDOOR_MODE                (4 << 0)
-
-#define PANEL_PWM_MAX_VALUE            0xFF
-
-static u32 dcs_get_backlight(struct intel_connector *connector)
-{
-       struct intel_encoder *encoder = connector->encoder;
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct mipi_dsi_device *dsi_device;
-       u8 data = 0;
-       enum port port;
-
-       /* FIXME: Need to take care of 16 bit brightness level */
-       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
-               dsi_device = intel_dsi->dsi_hosts[port]->device;
-               mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
-                                 &data, sizeof(data));
-               break;
-       }
-
-       return data;
-}
-
-static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder);
-       struct mipi_dsi_device *dsi_device;
-       u8 data = level;
-       enum port port;
-
-       /* FIXME: Need to take care of 16 bit brightness level */
-       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
-               dsi_device = intel_dsi->dsi_hosts[port]->device;
-               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
-                                  &data, sizeof(data));
-       }
-}
-
-static void dcs_disable_backlight(const struct drm_connector_state *conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder);
-       struct mipi_dsi_device *dsi_device;
-       enum port port;
-
-       dcs_set_backlight(conn_state, 0);
-
-       for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) {
-               u8 cabc = POWER_SAVE_OFF;
-
-               dsi_device = intel_dsi->dsi_hosts[port]->device;
-               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,
-                                  &cabc, sizeof(cabc));
-       }
-
-       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
-               u8 ctrl = 0;
-
-               dsi_device = intel_dsi->dsi_hosts[port]->device;
-
-               mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,
-                                 &ctrl, sizeof(ctrl));
-
-               ctrl &= ~CONTROL_DISPLAY_BL;
-               ctrl &= ~CONTROL_DISPLAY_DD;
-               ctrl &= ~CONTROL_DISPLAY_BCTRL;
-
-               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,
-                                  &ctrl, sizeof(ctrl));
-       }
-}
-
-static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder);
-       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
-       struct mipi_dsi_device *dsi_device;
-       enum port port;
-
-       for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
-               u8 ctrl = 0;
-
-               dsi_device = intel_dsi->dsi_hosts[port]->device;
-
-               mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,
-                                 &ctrl, sizeof(ctrl));
-
-               ctrl |= CONTROL_DISPLAY_BL;
-               ctrl |= CONTROL_DISPLAY_DD;
-               ctrl |= CONTROL_DISPLAY_BCTRL;
-
-               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,
-                                  &ctrl, sizeof(ctrl));
-       }
-
-       for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) {
-               u8 cabc = POWER_SAVE_MEDIUM;
-
-               dsi_device = intel_dsi->dsi_hosts[port]->device;
-               mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,
-                                  &cabc, sizeof(cabc));
-       }
-
-       dcs_set_backlight(conn_state, panel->backlight.level);
-}
-
-static int dcs_setup_backlight(struct intel_connector *connector,
-                              enum pipe unused)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       panel->backlight.max = PANEL_PWM_MAX_VALUE;
-       panel->backlight.level = PANEL_PWM_MAX_VALUE;
-
-       return 0;
-}
-
-int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector)
-{
-       struct drm_device *dev = intel_connector->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_encoder *encoder = intel_connector->encoder;
-       struct intel_panel *panel = &intel_connector->panel;
-
-       if (dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS)
-               return -ENODEV;
-
-       if (WARN_ON(encoder->type != INTEL_OUTPUT_DSI))
-               return -EINVAL;
-
-       panel->backlight.setup = dcs_setup_backlight;
-       panel->backlight.enable = dcs_enable_backlight;
-       panel->backlight.disable = dcs_disable_backlight;
-       panel->backlight.set = dcs_set_backlight;
-       panel->backlight.get = dcs_get_backlight;
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/i915/intel_dsi_dcs_backlight.h b/drivers/gpu/drm/i915/intel_dsi_dcs_backlight.h
deleted file mode 100644 (file)
index eb01947..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DSI_DCS_BACKLIGHT_H__
-#define __INTEL_DSI_DCS_BACKLIGHT_H__
-
-struct intel_connector;
-
-int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
-
-#endif /* __INTEL_DSI_DCS_BACKLIGHT_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c
deleted file mode 100644 (file)
index e5b1786..0000000
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright © 2014 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Shobhit Kumar <shobhit.kumar@intel.com>
- *
- */
-
-#include <linux/gpio/consumer.h>
-#include <linux/mfd/intel_soc_pmic.h>
-#include <linux/slab.h>
-
-#include <asm/intel-mid.h>
-#include <asm/unaligned.h>
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-
-#include <video/mipi_display.h>
-
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_sideband.h"
-
-#define MIPI_TRANSFER_MODE_SHIFT       0
-#define MIPI_VIRTUAL_CHANNEL_SHIFT     1
-#define MIPI_PORT_SHIFT                        3
-
-/* base offsets for gpio pads */
-#define VLV_GPIO_NC_0_HV_DDI0_HPD      0x4130
-#define VLV_GPIO_NC_1_HV_DDI0_DDC_SDA  0x4120
-#define VLV_GPIO_NC_2_HV_DDI0_DDC_SCL  0x4110
-#define VLV_GPIO_NC_3_PANEL0_VDDEN     0x4140
-#define VLV_GPIO_NC_4_PANEL0_BKLTEN    0x4150
-#define VLV_GPIO_NC_5_PANEL0_BKLTCTL   0x4160
-#define VLV_GPIO_NC_6_HV_DDI1_HPD      0x4180
-#define VLV_GPIO_NC_7_HV_DDI1_DDC_SDA  0x4190
-#define VLV_GPIO_NC_8_HV_DDI1_DDC_SCL  0x4170
-#define VLV_GPIO_NC_9_PANEL1_VDDEN     0x4100
-#define VLV_GPIO_NC_10_PANEL1_BKLTEN   0x40E0
-#define VLV_GPIO_NC_11_PANEL1_BKLTCTL  0x40F0
-
-#define VLV_GPIO_PCONF0(base_offset)   (base_offset)
-#define VLV_GPIO_PAD_VAL(base_offset)  ((base_offset) + 8)
-
-struct gpio_map {
-       u16 base_offset;
-       bool init;
-};
-
-static struct gpio_map vlv_gpio_table[] = {
-       { VLV_GPIO_NC_0_HV_DDI0_HPD },
-       { VLV_GPIO_NC_1_HV_DDI0_DDC_SDA },
-       { VLV_GPIO_NC_2_HV_DDI0_DDC_SCL },
-       { VLV_GPIO_NC_3_PANEL0_VDDEN },
-       { VLV_GPIO_NC_4_PANEL0_BKLTEN },
-       { VLV_GPIO_NC_5_PANEL0_BKLTCTL },
-       { VLV_GPIO_NC_6_HV_DDI1_HPD },
-       { VLV_GPIO_NC_7_HV_DDI1_DDC_SDA },
-       { VLV_GPIO_NC_8_HV_DDI1_DDC_SCL },
-       { VLV_GPIO_NC_9_PANEL1_VDDEN },
-       { VLV_GPIO_NC_10_PANEL1_BKLTEN },
-       { VLV_GPIO_NC_11_PANEL1_BKLTCTL },
-};
-
-#define CHV_GPIO_IDX_START_N           0
-#define CHV_GPIO_IDX_START_E           73
-#define CHV_GPIO_IDX_START_SW          100
-#define CHV_GPIO_IDX_START_SE          198
-
-#define CHV_VBT_MAX_PINS_PER_FMLY      15
-
-#define CHV_GPIO_PAD_CFG0(f, i)                (0x4400 + (f) * 0x400 + (i) * 8)
-#define  CHV_GPIO_GPIOEN               (1 << 15)
-#define  CHV_GPIO_GPIOCFG_GPIO         (0 << 8)
-#define  CHV_GPIO_GPIOCFG_GPO          (1 << 8)
-#define  CHV_GPIO_GPIOCFG_GPI          (2 << 8)
-#define  CHV_GPIO_GPIOCFG_HIZ          (3 << 8)
-#define  CHV_GPIO_GPIOTXSTATE(state)   ((!!(state)) << 1)
-
-#define CHV_GPIO_PAD_CFG1(f, i)                (0x4400 + (f) * 0x400 + (i) * 8 + 4)
-#define  CHV_GPIO_CFGLOCK              (1 << 31)
-
-/* ICL DSI Display GPIO Pins */
-#define  ICL_GPIO_DDSP_HPD_A           0
-#define  ICL_GPIO_L_VDDEN_1            1
-#define  ICL_GPIO_L_BKLTEN_1           2
-#define  ICL_GPIO_DDPA_CTRLCLK_1       3
-#define  ICL_GPIO_DDPA_CTRLDATA_1      4
-#define  ICL_GPIO_DDSP_HPD_B           5
-#define  ICL_GPIO_L_VDDEN_2            6
-#define  ICL_GPIO_L_BKLTEN_2           7
-#define  ICL_GPIO_DDPA_CTRLCLK_2       8
-#define  ICL_GPIO_DDPA_CTRLDATA_2      9
-
-static inline enum port intel_dsi_seq_port_to_port(u8 port)
-{
-       return port ? PORT_C : PORT_A;
-}
-
-static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
-                                      const u8 *data)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-       struct mipi_dsi_device *dsi_device;
-       u8 type, flags, seq_port;
-       u16 len;
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       flags = *data++;
-       type = *data++;
-
-       len = *((u16 *) data);
-       data += 2;
-
-       seq_port = (flags >> MIPI_PORT_SHIFT) & 3;
-
-       /* For DSI single link on Port A & C, the seq_port value which is
-        * parsed from Sequence Block#53 of VBT has been set to 0
-        * Now, read/write of packets for the DSI single link on Port A and
-        * Port C will based on the DVO port from VBT block 2.
-        */
-       if (intel_dsi->ports == (1 << PORT_C))
-               port = PORT_C;
-       else
-               port = intel_dsi_seq_port_to_port(seq_port);
-
-       dsi_device = intel_dsi->dsi_hosts[port]->device;
-       if (!dsi_device) {
-               DRM_DEBUG_KMS("no dsi device for port %c\n", port_name(port));
-               goto out;
-       }
-
-       if ((flags >> MIPI_TRANSFER_MODE_SHIFT) & 1)
-               dsi_device->mode_flags &= ~MIPI_DSI_MODE_LPM;
-       else
-               dsi_device->mode_flags |= MIPI_DSI_MODE_LPM;
-
-       dsi_device->channel = (flags >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 3;
-
-       switch (type) {
-       case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
-               mipi_dsi_generic_write(dsi_device, NULL, 0);
-               break;
-       case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
-               mipi_dsi_generic_write(dsi_device, data, 1);
-               break;
-       case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
-               mipi_dsi_generic_write(dsi_device, data, 2);
-               break;
-       case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
-       case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
-       case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
-               DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n");
-               break;
-       case MIPI_DSI_GENERIC_LONG_WRITE:
-               mipi_dsi_generic_write(dsi_device, data, len);
-               break;
-       case MIPI_DSI_DCS_SHORT_WRITE:
-               mipi_dsi_dcs_write_buffer(dsi_device, data, 1);
-               break;
-       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
-               mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
-               break;
-       case MIPI_DSI_DCS_READ:
-               DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n");
-               break;
-       case MIPI_DSI_DCS_LONG_WRITE:
-               mipi_dsi_dcs_write_buffer(dsi_device, data, len);
-               break;
-       }
-
-       if (INTEL_GEN(dev_priv) < 11)
-               vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
-
-out:
-       data += len;
-
-       return data;
-}
-
-static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data)
-{
-       u32 delay = *((const u32 *) data);
-
-       DRM_DEBUG_KMS("\n");
-
-       usleep_range(delay, delay + 10);
-       data += 4;
-
-       return data;
-}
-
-static void vlv_exec_gpio(struct drm_i915_private *dev_priv,
-                         u8 gpio_source, u8 gpio_index, bool value)
-{
-       struct gpio_map *map;
-       u16 pconf0, padval;
-       u32 tmp;
-       u8 port;
-
-       if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) {
-               DRM_DEBUG_KMS("unknown gpio index %u\n", gpio_index);
-               return;
-       }
-
-       map = &vlv_gpio_table[gpio_index];
-
-       if (dev_priv->vbt.dsi.seq_version >= 3) {
-               /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */
-               port = IOSF_PORT_GPIO_NC;
-       } else {
-               if (gpio_source == 0) {
-                       port = IOSF_PORT_GPIO_NC;
-               } else if (gpio_source == 1) {
-                       DRM_DEBUG_KMS("SC gpio not supported\n");
-                       return;
-               } else {
-                       DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source);
-                       return;
-               }
-       }
-
-       pconf0 = VLV_GPIO_PCONF0(map->base_offset);
-       padval = VLV_GPIO_PAD_VAL(map->base_offset);
-
-       vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO));
-       if (!map->init) {
-               /* FIXME: remove constant below */
-               vlv_iosf_sb_write(dev_priv, port, pconf0, 0x2000CC00);
-               map->init = true;
-       }
-
-       tmp = 0x4 | value;
-       vlv_iosf_sb_write(dev_priv, port, padval, tmp);
-       vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO));
-}
-
-static void chv_exec_gpio(struct drm_i915_private *dev_priv,
-                         u8 gpio_source, u8 gpio_index, bool value)
-{
-       u16 cfg0, cfg1;
-       u16 family_num;
-       u8 port;
-
-       if (dev_priv->vbt.dsi.seq_version >= 3) {
-               if (gpio_index >= CHV_GPIO_IDX_START_SE) {
-                       /* XXX: it's unclear whether 255->57 is part of SE. */
-                       gpio_index -= CHV_GPIO_IDX_START_SE;
-                       port = CHV_IOSF_PORT_GPIO_SE;
-               } else if (gpio_index >= CHV_GPIO_IDX_START_SW) {
-                       gpio_index -= CHV_GPIO_IDX_START_SW;
-                       port = CHV_IOSF_PORT_GPIO_SW;
-               } else if (gpio_index >= CHV_GPIO_IDX_START_E) {
-                       gpio_index -= CHV_GPIO_IDX_START_E;
-                       port = CHV_IOSF_PORT_GPIO_E;
-               } else {
-                       port = CHV_IOSF_PORT_GPIO_N;
-               }
-       } else {
-               /* XXX: The spec is unclear about CHV GPIO on seq v2 */
-               if (gpio_source != 0) {
-                       DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source);
-                       return;
-               }
-
-               if (gpio_index >= CHV_GPIO_IDX_START_E) {
-                       DRM_DEBUG_KMS("invalid gpio index %u for GPIO N\n",
-                                     gpio_index);
-                       return;
-               }
-
-               port = CHV_IOSF_PORT_GPIO_N;
-       }
-
-       family_num = gpio_index / CHV_VBT_MAX_PINS_PER_FMLY;
-       gpio_index = gpio_index % CHV_VBT_MAX_PINS_PER_FMLY;
-
-       cfg0 = CHV_GPIO_PAD_CFG0(family_num, gpio_index);
-       cfg1 = CHV_GPIO_PAD_CFG1(family_num, gpio_index);
-
-       vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO));
-       vlv_iosf_sb_write(dev_priv, port, cfg1, 0);
-       vlv_iosf_sb_write(dev_priv, port, cfg0,
-                         CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO |
-                         CHV_GPIO_GPIOTXSTATE(value));
-       vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO));
-}
-
-static void bxt_exec_gpio(struct drm_i915_private *dev_priv,
-                         u8 gpio_source, u8 gpio_index, bool value)
-{
-       /* XXX: this table is a quick ugly hack. */
-       static struct gpio_desc *bxt_gpio_table[U8_MAX + 1];
-       struct gpio_desc *gpio_desc = bxt_gpio_table[gpio_index];
-
-       if (!gpio_desc) {
-               gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev,
-                                                NULL, gpio_index,
-                                                value ? GPIOD_OUT_LOW :
-                                                GPIOD_OUT_HIGH);
-
-               if (IS_ERR_OR_NULL(gpio_desc)) {
-                       DRM_ERROR("GPIO index %u request failed (%ld)\n",
-                                 gpio_index, PTR_ERR(gpio_desc));
-                       return;
-               }
-
-               bxt_gpio_table[gpio_index] = gpio_desc;
-       }
-
-       gpiod_set_value(gpio_desc, value);
-}
-
-static void icl_exec_gpio(struct drm_i915_private *dev_priv,
-                         u8 gpio_source, u8 gpio_index, bool value)
-{
-       DRM_DEBUG_KMS("Skipping ICL GPIO element execution\n");
-}
-
-static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
-{
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u8 gpio_source, gpio_index = 0, gpio_number;
-       bool value;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (dev_priv->vbt.dsi.seq_version >= 3)
-               gpio_index = *data++;
-
-       gpio_number = *data++;
-
-       /* gpio source in sequence v2 only */
-       if (dev_priv->vbt.dsi.seq_version == 2)
-               gpio_source = (*data >> 1) & 3;
-       else
-               gpio_source = 0;
-
-       /* pull up/down */
-       value = *data++ & 1;
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_exec_gpio(dev_priv, gpio_source, gpio_index, value);
-       else if (IS_VALLEYVIEW(dev_priv))
-               vlv_exec_gpio(dev_priv, gpio_source, gpio_number, value);
-       else if (IS_CHERRYVIEW(dev_priv))
-               chv_exec_gpio(dev_priv, gpio_source, gpio_number, value);
-       else
-               bxt_exec_gpio(dev_priv, gpio_source, gpio_index, value);
-
-       return data;
-}
-
-static const u8 *mipi_exec_i2c(struct intel_dsi *intel_dsi, const u8 *data)
-{
-       DRM_DEBUG_KMS("Skipping I2C element execution\n");
-
-       return data + *(data + 6) + 7;
-}
-
-static const u8 *mipi_exec_spi(struct intel_dsi *intel_dsi, const u8 *data)
-{
-       DRM_DEBUG_KMS("Skipping SPI element execution\n");
-
-       return data + *(data + 5) + 6;
-}
-
-static const u8 *mipi_exec_pmic(struct intel_dsi *intel_dsi, const u8 *data)
-{
-#ifdef CONFIG_PMIC_OPREGION
-       u32 value, mask, reg_address;
-       u16 i2c_address;
-       int ret;
-
-       /* byte 0 aka PMIC Flag is reserved */
-       i2c_address     = get_unaligned_le16(data + 1);
-       reg_address     = get_unaligned_le32(data + 3);
-       value           = get_unaligned_le32(data + 7);
-       mask            = get_unaligned_le32(data + 11);
-
-       ret = intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address,
-                                                       reg_address,
-                                                       value, mask);
-       if (ret)
-               DRM_ERROR("%s failed, error: %d\n", __func__, ret);
-#else
-       DRM_ERROR("Your hardware requires CONFIG_PMIC_OPREGION and it is not set\n");
-#endif
-
-       return data + 15;
-}
-
-typedef const u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi,
-                                       const u8 *data);
-static const fn_mipi_elem_exec exec_elem[] = {
-       [MIPI_SEQ_ELEM_SEND_PKT] = mipi_exec_send_packet,
-       [MIPI_SEQ_ELEM_DELAY] = mipi_exec_delay,
-       [MIPI_SEQ_ELEM_GPIO] = mipi_exec_gpio,
-       [MIPI_SEQ_ELEM_I2C] = mipi_exec_i2c,
-       [MIPI_SEQ_ELEM_SPI] = mipi_exec_spi,
-       [MIPI_SEQ_ELEM_PMIC] = mipi_exec_pmic,
-};
-
-/*
- * MIPI Sequence from VBT #53 parsing logic
- * We have already separated each seqence during bios parsing
- * Following is generic execution function for any sequence
- */
-
-static const char * const seq_name[] = {
-       [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
-       [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
-       [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
-       [MIPI_SEQ_DISPLAY_OFF]  = "MIPI_SEQ_DISPLAY_OFF",
-       [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
-       [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
-       [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
-       [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
-       [MIPI_SEQ_TEAR_OFF] = "MIPI_SEQ_TEAR_OFF",
-       [MIPI_SEQ_POWER_ON] = "MIPI_SEQ_POWER_ON",
-       [MIPI_SEQ_POWER_OFF] = "MIPI_SEQ_POWER_OFF",
-};
-
-static const char *sequence_name(enum mipi_seq seq_id)
-{
-       if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id])
-               return seq_name[seq_id];
-       else
-               return "(unknown)";
-}
-
-void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
-                                enum mipi_seq seq_id)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-       const u8 *data;
-       fn_mipi_elem_exec mipi_elem_exec;
-
-       if (WARN_ON(seq_id >= ARRAY_SIZE(dev_priv->vbt.dsi.sequence)))
-               return;
-
-       data = dev_priv->vbt.dsi.sequence[seq_id];
-       if (!data)
-               return;
-
-       WARN_ON(*data != seq_id);
-
-       DRM_DEBUG_KMS("Starting MIPI sequence %d - %s\n",
-                     seq_id, sequence_name(seq_id));
-
-       /* Skip Sequence Byte. */
-       data++;
-
-       /* Skip Size of Sequence. */
-       if (dev_priv->vbt.dsi.seq_version >= 3)
-               data += 4;
-
-       while (1) {
-               u8 operation_byte = *data++;
-               u8 operation_size = 0;
-
-               if (operation_byte == MIPI_SEQ_ELEM_END)
-                       break;
-
-               if (operation_byte < ARRAY_SIZE(exec_elem))
-                       mipi_elem_exec = exec_elem[operation_byte];
-               else
-                       mipi_elem_exec = NULL;
-
-               /* Size of Operation. */
-               if (dev_priv->vbt.dsi.seq_version >= 3)
-                       operation_size = *data++;
-
-               if (mipi_elem_exec) {
-                       const u8 *next = data + operation_size;
-
-                       data = mipi_elem_exec(intel_dsi, data);
-
-                       /* Consistency check if we have size. */
-                       if (operation_size && data != next) {
-                               DRM_ERROR("Inconsistent operation size\n");
-                               return;
-                       }
-               } else if (operation_size) {
-                       /* We have size, skip. */
-                       DRM_DEBUG_KMS("Unsupported MIPI operation byte %u\n",
-                                     operation_byte);
-                       data += operation_size;
-               } else {
-                       /* No size, can't skip without parsing. */
-                       DRM_ERROR("Unsupported MIPI operation byte %u\n",
-                                 operation_byte);
-                       return;
-               }
-       }
-}
-
-void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-
-       /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */
-       if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3)
-               return;
-
-       msleep(msec);
-}
-
-void intel_dsi_log_params(struct intel_dsi *intel_dsi)
-{
-       DRM_DEBUG_KMS("Pclk %d\n", intel_dsi->pclk);
-       DRM_DEBUG_KMS("Pixel overlap %d\n", intel_dsi->pixel_overlap);
-       DRM_DEBUG_KMS("Lane count %d\n", intel_dsi->lane_count);
-       DRM_DEBUG_KMS("DPHY param reg 0x%x\n", intel_dsi->dphy_reg);
-       DRM_DEBUG_KMS("Video mode format %s\n",
-                     intel_dsi->video_mode_format == VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE ?
-                     "non-burst with sync pulse" :
-                     intel_dsi->video_mode_format == VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS ?
-                     "non-burst with sync events" :
-                     intel_dsi->video_mode_format == VIDEO_MODE_BURST ?
-                     "burst" : "<unknown>");
-       DRM_DEBUG_KMS("Burst mode ratio %d\n", intel_dsi->burst_mode_ratio);
-       DRM_DEBUG_KMS("Reset timer %d\n", intel_dsi->rst_timer_val);
-       DRM_DEBUG_KMS("Eot %s\n", enableddisabled(intel_dsi->eotp_pkt));
-       DRM_DEBUG_KMS("Clockstop %s\n", enableddisabled(!intel_dsi->clock_stop));
-       DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video");
-       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-               DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n");
-       else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT)
-               DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n");
-       else
-               DRM_DEBUG_KMS("Dual link: NONE\n");
-       DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format);
-       DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div);
-       DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout);
-       DRM_DEBUG_KMS("Turnaround Timeout 0x%x\n", intel_dsi->turn_arnd_val);
-       DRM_DEBUG_KMS("Init Count 0x%x\n", intel_dsi->init_count);
-       DRM_DEBUG_KMS("HS to LP Count 0x%x\n", intel_dsi->hs_to_lp_count);
-       DRM_DEBUG_KMS("LP Byte Clock %d\n", intel_dsi->lp_byte_clk);
-       DRM_DEBUG_KMS("DBI BW Timer 0x%x\n", intel_dsi->bw_timer);
-       DRM_DEBUG_KMS("LP to HS Clock Count 0x%x\n", intel_dsi->clk_lp_to_hs_count);
-       DRM_DEBUG_KMS("HS to LP Clock Count 0x%x\n", intel_dsi->clk_hs_to_lp_count);
-       DRM_DEBUG_KMS("BTA %s\n",
-                       enableddisabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA)));
-}
-
-bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
-{
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
-       struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
-       struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
-       u16 burst_mode_ratio;
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1;
-       intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
-       intel_dsi->lane_count = mipi_config->lane_cnt + 1;
-       intel_dsi->pixel_format =
-                       pixel_format_from_register_bits(
-                               mipi_config->videomode_color_format << 7);
-
-       intel_dsi->dual_link = mipi_config->dual_link;
-       intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
-       intel_dsi->operation_mode = mipi_config->is_cmd_mode;
-       intel_dsi->video_mode_format = mipi_config->video_transfer_mode;
-       intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
-       intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout;
-       intel_dsi->hs_tx_timeout = mipi_config->hs_tx_timeout;
-       intel_dsi->turn_arnd_val = mipi_config->turn_around_timeout;
-       intel_dsi->rst_timer_val = mipi_config->device_reset_timer;
-       intel_dsi->init_count = mipi_config->master_init_timer;
-       intel_dsi->bw_timer = mipi_config->dbi_bw_timer;
-       intel_dsi->video_frmt_cfg_bits =
-               mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0;
-       intel_dsi->bgr_enabled = mipi_config->rgb_flip;
-
-       /* Starting point, adjusted depending on dual link and burst mode */
-       intel_dsi->pclk = mode->clock;
-
-       /* In dual link mode each port needs half of pixel clock */
-       if (intel_dsi->dual_link) {
-               intel_dsi->pclk /= 2;
-
-               /* we can enable pixel_overlap if needed by panel. In this
-                * case we need to increase the pixelclock for extra pixels
-                */
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
-                       intel_dsi->pclk += DIV_ROUND_UP(mode->vtotal * intel_dsi->pixel_overlap * 60, 1000);
-               }
-       }
-
-       /* Burst Mode Ratio
-        * Target ddr frequency from VBT / non burst ddr freq
-        * multiply by 100 to preserve remainder
-        */
-       if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
-               if (mipi_config->target_burst_mode_freq) {
-                       u32 bitrate = intel_dsi_bitrate(intel_dsi);
-
-                       /*
-                        * Sometimes the VBT contains a slightly lower clock,
-                        * then the bitrate we have calculated, in this case
-                        * just replace it with the calculated bitrate.
-                        */
-                       if (mipi_config->target_burst_mode_freq < bitrate &&
-                           intel_fuzzy_clock_check(
-                                       mipi_config->target_burst_mode_freq,
-                                       bitrate))
-                               mipi_config->target_burst_mode_freq = bitrate;
-
-                       if (mipi_config->target_burst_mode_freq < bitrate) {
-                               DRM_ERROR("Burst mode freq is less than computed\n");
-                               return false;
-                       }
-
-                       burst_mode_ratio = DIV_ROUND_UP(
-                               mipi_config->target_burst_mode_freq * 100,
-                               bitrate);
-
-                       intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100);
-               } else {
-                       DRM_ERROR("Burst mode target is not set\n");
-                       return false;
-               }
-       } else
-               burst_mode_ratio = 100;
-
-       intel_dsi->burst_mode_ratio = burst_mode_ratio;
-
-       /* delays in VBT are in unit of 100us, so need to convert
-        * here in ms
-        * Delay (100us) * 100 /1000 = Delay / 10 (ms) */
-       intel_dsi->backlight_off_delay = pps->bl_disable_delay / 10;
-       intel_dsi->backlight_on_delay = pps->bl_enable_delay / 10;
-       intel_dsi->panel_on_delay = pps->panel_on_delay / 10;
-       intel_dsi->panel_off_delay = pps->panel_off_delay / 10;
-       intel_dsi->panel_pwr_cycle_delay = pps->panel_power_cycle_delay / 10;
-
-       /* a regular driver would get the device in probe */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               mipi_dsi_attach(intel_dsi->dsi_hosts[port]->device);
-       }
-
-       return true;
-}
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
deleted file mode 100644 (file)
index 22666d2..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2007 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- */
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_connector.h"
-#include "intel_drv.h"
-#include "intel_dvo.h"
-#include "intel_dvo_dev.h"
-#include "intel_gmbus.h"
-#include "intel_panel.h"
-
-#define INTEL_DVO_CHIP_NONE    0
-#define INTEL_DVO_CHIP_LVDS    1
-#define INTEL_DVO_CHIP_TMDS    2
-#define INTEL_DVO_CHIP_TVOUT   4
-
-#define SIL164_ADDR    0x38
-#define CH7xxx_ADDR    0x76
-#define TFP410_ADDR    0x38
-#define NS2501_ADDR     0x38
-
-static const struct intel_dvo_device intel_dvo_devices[] = {
-       {
-               .type = INTEL_DVO_CHIP_TMDS,
-               .name = "sil164",
-               .dvo_reg = DVOC,
-               .dvo_srcdim_reg = DVOC_SRCDIM,
-               .slave_addr = SIL164_ADDR,
-               .dev_ops = &sil164_ops,
-       },
-       {
-               .type = INTEL_DVO_CHIP_TMDS,
-               .name = "ch7xxx",
-               .dvo_reg = DVOC,
-               .dvo_srcdim_reg = DVOC_SRCDIM,
-               .slave_addr = CH7xxx_ADDR,
-               .dev_ops = &ch7xxx_ops,
-       },
-       {
-               .type = INTEL_DVO_CHIP_TMDS,
-               .name = "ch7xxx",
-               .dvo_reg = DVOC,
-               .dvo_srcdim_reg = DVOC_SRCDIM,
-               .slave_addr = 0x75, /* For some ch7010 */
-               .dev_ops = &ch7xxx_ops,
-       },
-       {
-               .type = INTEL_DVO_CHIP_LVDS,
-               .name = "ivch",
-               .dvo_reg = DVOA,
-               .dvo_srcdim_reg = DVOA_SRCDIM,
-               .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
-               .dev_ops = &ivch_ops,
-       },
-       {
-               .type = INTEL_DVO_CHIP_TMDS,
-               .name = "tfp410",
-               .dvo_reg = DVOC,
-               .dvo_srcdim_reg = DVOC_SRCDIM,
-               .slave_addr = TFP410_ADDR,
-               .dev_ops = &tfp410_ops,
-       },
-       {
-               .type = INTEL_DVO_CHIP_LVDS,
-               .name = "ch7017",
-               .dvo_reg = DVOC,
-               .dvo_srcdim_reg = DVOC_SRCDIM,
-               .slave_addr = 0x75,
-               .gpio = GMBUS_PIN_DPB,
-               .dev_ops = &ch7017_ops,
-       },
-       {
-               .type = INTEL_DVO_CHIP_TMDS,
-               .name = "ns2501",
-               .dvo_reg = DVOB,
-               .dvo_srcdim_reg = DVOB_SRCDIM,
-               .slave_addr = NS2501_ADDR,
-               .dev_ops = &ns2501_ops,
-       }
-};
-
-struct intel_dvo {
-       struct intel_encoder base;
-
-       struct intel_dvo_device dev;
-
-       struct intel_connector *attached_connector;
-
-       bool panel_wants_dither;
-};
-
-static struct intel_dvo *enc_to_dvo(struct intel_encoder *encoder)
-{
-       return container_of(encoder, struct intel_dvo, base);
-}
-
-static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
-{
-       return enc_to_dvo(intel_attached_encoder(connector));
-}
-
-static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
-{
-       struct drm_device *dev = connector->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
-       u32 tmp;
-
-       tmp = I915_READ(intel_dvo->dev.dvo_reg);
-
-       if (!(tmp & DVO_ENABLE))
-               return false;
-
-       return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
-}
-
-static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
-                                  enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       u32 tmp;
-
-       tmp = I915_READ(intel_dvo->dev.dvo_reg);
-
-       *pipe = (tmp & DVO_PIPE_SEL_MASK) >> DVO_PIPE_SEL_SHIFT;
-
-       return tmp & DVO_ENABLE;
-}
-
-static void intel_dvo_get_config(struct intel_encoder *encoder,
-                                struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       u32 tmp, flags = 0;
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_DVO);
-
-       tmp = I915_READ(intel_dvo->dev.dvo_reg);
-       if (tmp & DVO_HSYNC_ACTIVE_HIGH)
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NHSYNC;
-       if (tmp & DVO_VSYNC_ACTIVE_HIGH)
-               flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NVSYNC;
-
-       pipe_config->base.adjusted_mode.flags |= flags;
-
-       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
-}
-
-static void intel_disable_dvo(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
-       u32 temp = I915_READ(dvo_reg);
-
-       intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
-       I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
-       I915_READ(dvo_reg);
-}
-
-static void intel_enable_dvo(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *pipe_config,
-                            const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
-       u32 temp = I915_READ(dvo_reg);
-
-       intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
-                                        &pipe_config->base.mode,
-                                        &pipe_config->base.adjusted_mode);
-
-       I915_WRITE(dvo_reg, temp | DVO_ENABLE);
-       I915_READ(dvo_reg);
-
-       intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
-}
-
-static enum drm_mode_status
-intel_dvo_mode_valid(struct drm_connector *connector,
-                    struct drm_display_mode *mode)
-{
-       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
-       const struct drm_display_mode *fixed_mode =
-               to_intel_connector(connector)->panel.fixed_mode;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-       int target_clock = mode->clock;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       /* XXX: Validate clock range */
-
-       if (fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-
-               target_clock = fixed_mode->clock;
-       }
-
-       if (target_clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
-}
-
-static int intel_dvo_compute_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config,
-                                   struct drm_connector_state *conn_state)
-{
-       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       const struct drm_display_mode *fixed_mode =
-               intel_dvo->attached_connector->panel.fixed_mode;
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-
-       /*
-        * If we have timings from the BIOS for the panel, put them in
-        * to the adjusted mode.  The CRTC will be set up for this mode,
-        * with the panel scaling set up to source from the H/VDisplay
-        * of the original mode.
-        */
-       if (fixed_mode)
-               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       return 0;
-}
-
-static void intel_dvo_pre_enable(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config,
-                                const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       int pipe = crtc->pipe;
-       u32 dvo_val;
-       i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
-       i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg;
-
-       /* Save the data order, since I don't know what it should be set to. */
-       dvo_val = I915_READ(dvo_reg) &
-                 (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
-       dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |
-                  DVO_BLANK_ACTIVE_HIGH;
-
-       dvo_val |= DVO_PIPE_SEL(pipe);
-       dvo_val |= DVO_PIPE_STALL;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-               dvo_val |= DVO_HSYNC_ACTIVE_HIGH;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-               dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
-
-       /*I915_WRITE(DVOB_SRCDIM,
-         (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
-         (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
-       I915_WRITE(dvo_srcdim_reg,
-                  (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
-                  (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
-       /*I915_WRITE(DVOB, dvo_val);*/
-       I915_WRITE(dvo_reg, dvo_val);
-}
-
-static enum drm_connector_status
-intel_dvo_detect(struct drm_connector *connector, bool force)
-{
-       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-       return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
-}
-
-static int intel_dvo_get_modes(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       const struct drm_display_mode *fixed_mode =
-               to_intel_connector(connector)->panel.fixed_mode;
-
-       /*
-        * We should probably have an i2c driver get_modes function for those
-        * devices which will have a fixed set of modes determined by the chip
-        * (TV-out, for example), but for now with just TMDS and LVDS,
-        * that's not the case.
-        */
-       intel_ddc_get_modes(connector,
-                           intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPC));
-       if (!list_empty(&connector->probed_modes))
-               return 1;
-
-       if (fixed_mode) {
-               struct drm_display_mode *mode;
-               mode = drm_mode_duplicate(connector->dev, fixed_mode);
-               if (mode) {
-                       drm_mode_probed_add(connector, mode);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static const struct drm_connector_funcs intel_dvo_connector_funcs = {
-       .detect = intel_dvo_detect,
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-};
-
-static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
-       .mode_valid = intel_dvo_mode_valid,
-       .get_modes = intel_dvo_get_modes,
-};
-
-static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
-{
-       struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder));
-
-       if (intel_dvo->dev.dev_ops->destroy)
-               intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
-
-       intel_encoder_destroy(encoder);
-}
-
-static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
-       .destroy = intel_dvo_enc_destroy,
-};
-
-/*
- * Attempts to get a fixed panel timing for LVDS (currently only the i830).
- *
- * Other chips with DVO LVDS will need to extend this to deal with the LVDS
- * chip being on DVOB/C and having multiple pipes.
- */
-static struct drm_display_mode *
-intel_dvo_get_current_mode(struct intel_encoder *encoder)
-{
-       struct drm_display_mode *mode;
-
-       mode = intel_encoder_current_mode(encoder);
-       if (mode) {
-               DRM_DEBUG_KMS("using current (BIOS) mode: ");
-               drm_mode_debug_printmodeline(mode);
-               mode->type |= DRM_MODE_TYPE_PREFERRED;
-       }
-
-       return mode;
-}
-
-static enum port intel_dvo_port(i915_reg_t dvo_reg)
-{
-       if (i915_mmio_reg_equal(dvo_reg, DVOA))
-               return PORT_A;
-       else if (i915_mmio_reg_equal(dvo_reg, DVOB))
-               return PORT_B;
-       else
-               return PORT_C;
-}
-
-void intel_dvo_init(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *intel_encoder;
-       struct intel_dvo *intel_dvo;
-       struct intel_connector *intel_connector;
-       int i;
-       int encoder_type = DRM_MODE_ENCODER_NONE;
-
-       intel_dvo = kzalloc(sizeof(*intel_dvo), GFP_KERNEL);
-       if (!intel_dvo)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_dvo);
-               return;
-       }
-
-       intel_dvo->attached_connector = intel_connector;
-
-       intel_encoder = &intel_dvo->base;
-
-       intel_encoder->disable = intel_disable_dvo;
-       intel_encoder->enable = intel_enable_dvo;
-       intel_encoder->get_hw_state = intel_dvo_get_hw_state;
-       intel_encoder->get_config = intel_dvo_get_config;
-       intel_encoder->compute_config = intel_dvo_compute_config;
-       intel_encoder->pre_enable = intel_dvo_pre_enable;
-       intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
-
-       /* Now, try to find a controller */
-       for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
-               struct drm_connector *connector = &intel_connector->base;
-               const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
-               struct i2c_adapter *i2c;
-               int gpio;
-               bool dvoinit;
-               enum pipe pipe;
-               u32 dpll[I915_MAX_PIPES];
-               enum port port;
-
-               /*
-                * Allow the I2C driver info to specify the GPIO to be used in
-                * special cases, but otherwise default to what's defined
-                * in the spec.
-                */
-               if (intel_gmbus_is_valid_pin(dev_priv, dvo->gpio))
-                       gpio = dvo->gpio;
-               else if (dvo->type == INTEL_DVO_CHIP_LVDS)
-                       gpio = GMBUS_PIN_SSC;
-               else
-                       gpio = GMBUS_PIN_DPB;
-
-               /*
-                * Set up the I2C bus necessary for the chip we're probing.
-                * It appears that everything is on GPIOE except for panels
-                * on i830 laptops, which are on GPIOB (DVOA).
-                */
-               i2c = intel_gmbus_get_adapter(dev_priv, gpio);
-
-               intel_dvo->dev = *dvo;
-
-               /*
-                * GMBUS NAK handling seems to be unstable, hence let the
-                * transmitter detection run in bit banging mode for now.
-                */
-               intel_gmbus_force_bit(i2c, true);
-
-               /*
-                * ns2501 requires the DVO 2x clock before it will
-                * respond to i2c accesses, so make sure we have
-                * have the clock enabled before we attempt to
-                * initialize the device.
-                */
-               for_each_pipe(dev_priv, pipe) {
-                       dpll[pipe] = I915_READ(DPLL(pipe));
-                       I915_WRITE(DPLL(pipe), dpll[pipe] | DPLL_DVO_2X_MODE);
-               }
-
-               dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c);
-
-               /* restore the DVO 2x clock state to original */
-               for_each_pipe(dev_priv, pipe) {
-                       I915_WRITE(DPLL(pipe), dpll[pipe]);
-               }
-
-               intel_gmbus_force_bit(i2c, false);
-
-               if (!dvoinit)
-                       continue;
-
-               port = intel_dvo_port(dvo->dvo_reg);
-               drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
-                                &intel_dvo_enc_funcs, encoder_type,
-                                "DVO %c", port_name(port));
-
-               intel_encoder->type = INTEL_OUTPUT_DVO;
-               intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
-               intel_encoder->port = port;
-               intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-
-               switch (dvo->type) {
-               case INTEL_DVO_CHIP_TMDS:
-                       intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
-                               (1 << INTEL_OUTPUT_DVO);
-                       drm_connector_init(&dev_priv->drm, connector,
-                                          &intel_dvo_connector_funcs,
-                                          DRM_MODE_CONNECTOR_DVII);
-                       encoder_type = DRM_MODE_ENCODER_TMDS;
-                       break;
-               case INTEL_DVO_CHIP_LVDS:
-                       intel_encoder->cloneable = 0;
-                       drm_connector_init(&dev_priv->drm, connector,
-                                          &intel_dvo_connector_funcs,
-                                          DRM_MODE_CONNECTOR_LVDS);
-                       encoder_type = DRM_MODE_ENCODER_LVDS;
-                       break;
-               }
-
-               drm_connector_helper_add(connector,
-                                        &intel_dvo_connector_helper_funcs);
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-               connector->interlace_allowed = false;
-               connector->doublescan_allowed = false;
-
-               intel_connector_attach_encoder(intel_connector, intel_encoder);
-               if (dvo->type == INTEL_DVO_CHIP_LVDS) {
-                       /*
-                        * For our LVDS chipsets, we should hopefully be able
-                        * to dig the fixed panel mode out of the BIOS data.
-                        * However, it's in a different format from the BIOS
-                        * data on chipsets with integrated LVDS (stored in AIM
-                        * headers, likely), so for now, just get the current
-                        * mode being output through DVO.
-                        */
-                       intel_panel_init(&intel_connector->panel,
-                                        intel_dvo_get_current_mode(intel_encoder),
-                                        NULL);
-                       intel_dvo->panel_wants_dither = true;
-               }
-
-               return;
-       }
-
-       kfree(intel_dvo);
-       kfree(intel_connector);
-}
diff --git a/drivers/gpu/drm/i915/intel_dvo.h b/drivers/gpu/drm/i915/intel_dvo.h
deleted file mode 100644 (file)
index 3ed0fdf..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_DVO_H__
-#define __INTEL_DVO_H__
-
-struct drm_i915_private;
-
-void intel_dvo_init(struct drm_i915_private *dev_priv);
-
-#endif /* __INTEL_DVO_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dvo_dev.h b/drivers/gpu/drm/i915/intel_dvo_dev.h
deleted file mode 100644 (file)
index 94a6ae1..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright © 2006 Eric Anholt
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- */
-
-#ifndef __INTEL_DVO_DEV_H__
-#define __INTEL_DVO_DEV_H__
-
-#include <linux/i2c.h>
-
-#include <drm/drm_crtc.h>
-
-#include "i915_reg.h"
-
-struct intel_dvo_device {
-       const char *name;
-       int type;
-       /* DVOA/B/C output register */
-       i915_reg_t dvo_reg;
-       i915_reg_t dvo_srcdim_reg;
-       /* GPIO register used for i2c bus to control this device */
-       u32 gpio;
-       int slave_addr;
-
-       const struct intel_dvo_dev_ops *dev_ops;
-       void *dev_priv;
-       struct i2c_adapter *i2c_bus;
-};
-
-struct intel_dvo_dev_ops {
-       /*
-        * Initialize the device at startup time.
-        * Returns NULL if the device does not exist.
-        */
-       bool (*init)(struct intel_dvo_device *dvo,
-                    struct i2c_adapter *i2cbus);
-
-       /*
-        * Called to allow the output a chance to create properties after the
-        * RandR objects have been created.
-        */
-       void (*create_resources)(struct intel_dvo_device *dvo);
-
-       /*
-        * Turn on/off output.
-        *
-        * Because none of our dvo drivers support an intermediate power levels,
-        * we don't expose this in the interfac.
-        */
-       void (*dpms)(struct intel_dvo_device *dvo, bool enable);
-
-       /*
-        * Callback for testing a video mode for a given output.
-        *
-        * This function should only check for cases where a mode can't
-        * be supported on the output specifically, and not represent
-        * generic CRTC limitations.
-        *
-        * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
-        */
-       int (*mode_valid)(struct intel_dvo_device *dvo,
-                         struct drm_display_mode *mode);
-
-       /*
-        * Callback for preparing mode changes on an output
-        */
-       void (*prepare)(struct intel_dvo_device *dvo);
-
-       /*
-        * Callback for committing mode changes on an output
-        */
-       void (*commit)(struct intel_dvo_device *dvo);
-
-       /*
-        * Callback for setting up a video mode after fixups have been made.
-        *
-        * This is only called while the output is disabled.  The dpms callback
-        * must be all that's necessary for the output, to turn the output on
-        * after this function is called.
-        */
-       void (*mode_set)(struct intel_dvo_device *dvo,
-                        const struct drm_display_mode *mode,
-                        const struct drm_display_mode *adjusted_mode);
-
-       /*
-        * Probe for a connected output, and return detect_status.
-        */
-       enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
-
-       /*
-        * Probe the current hw status, returning true if the connected output
-        * is active.
-        */
-       bool (*get_hw_state)(struct intel_dvo_device *dev);
-
-       /**
-        * Query the device for the modes it provides.
-        *
-        * This function may also update MonInfo, mm_width, and mm_height.
-        *
-        * \return singly-linked list of modes or NULL if no modes found.
-        */
-       struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
-
-       /**
-        * Clean up driver-specific bits of the output
-        */
-       void (*destroy) (struct intel_dvo_device *dvo);
-
-       /**
-        * Debugging hook to dump device registers to log file
-        */
-       void (*dump_regs)(struct intel_dvo_device *dvo);
-};
-
-extern const struct intel_dvo_dev_ops sil164_ops;
-extern const struct intel_dvo_dev_ops ch7xxx_ops;
-extern const struct intel_dvo_dev_ops ivch_ops;
-extern const struct intel_dvo_dev_ops tfp410_ops;
-extern const struct intel_dvo_dev_ops ch7017_ops;
-extern const struct intel_dvo_dev_ops ns2501_ops;
-
-#endif /* __INTEL_DVO_DEV_H__ */
index d6036b9ad16a2e5619e96f79d361b4b033cf27bd..44273c10cea5417377a89085ced804272344b6d3 100644 (file)
@@ -55,8 +55,9 @@
  * cancelled as soon as busyness is detected.
  */
 
+#include "display/intel_dp.h"
+
 #include "i915_drv.h"
-#include "intel_dp.h"
 #include "intel_drv.h"
 #include "intel_fbc.h"
 #include "intel_frontbuffer.h"
diff --git a/drivers/gpu/drm/i915/intel_gmbus.c b/drivers/gpu/drm/i915/intel_gmbus.c
deleted file mode 100644 (file)
index aa88e6e..0000000
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2008,2010 Intel Corporation
- *   Jesse Barnes <jesse.barnes@intel.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- *     Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include <linux/export.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/i2c.h>
-
-#include <drm/drm_hdcp.h>
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_gmbus.h"
-
-struct gmbus_pin {
-       const char *name;
-       enum i915_gpio gpio;
-};
-
-/* Map gmbus pin pairs to names and registers. */
-static const struct gmbus_pin gmbus_pins[] = {
-       [GMBUS_PIN_SSC] = { "ssc", GPIOB },
-       [GMBUS_PIN_VGADDC] = { "vga", GPIOA },
-       [GMBUS_PIN_PANEL] = { "panel", GPIOC },
-       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
-       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
-       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
-};
-
-static const struct gmbus_pin gmbus_pins_bdw[] = {
-       [GMBUS_PIN_VGADDC] = { "vga", GPIOA },
-       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
-       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
-       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
-};
-
-static const struct gmbus_pin gmbus_pins_skl[] = {
-       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
-       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
-       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
-};
-
-static const struct gmbus_pin gmbus_pins_bxt[] = {
-       [GMBUS_PIN_1_BXT] = { "dpb", GPIOB },
-       [GMBUS_PIN_2_BXT] = { "dpc", GPIOC },
-       [GMBUS_PIN_3_BXT] = { "misc", GPIOD },
-};
-
-static const struct gmbus_pin gmbus_pins_cnp[] = {
-       [GMBUS_PIN_1_BXT] = { "dpb", GPIOB },
-       [GMBUS_PIN_2_BXT] = { "dpc", GPIOC },
-       [GMBUS_PIN_3_BXT] = { "misc", GPIOD },
-       [GMBUS_PIN_4_CNP] = { "dpd", GPIOE },
-};
-
-static const struct gmbus_pin gmbus_pins_icp[] = {
-       [GMBUS_PIN_1_BXT] = { "dpa", GPIOB },
-       [GMBUS_PIN_2_BXT] = { "dpb", GPIOC },
-       [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ },
-       [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOK },
-       [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOL },
-       [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOM },
-};
-
-/* pin is expected to be valid */
-static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
-                                            unsigned int pin)
-{
-       if (HAS_PCH_ICP(dev_priv))
-               return &gmbus_pins_icp[pin];
-       else if (HAS_PCH_CNP(dev_priv))
-               return &gmbus_pins_cnp[pin];
-       else if (IS_GEN9_LP(dev_priv))
-               return &gmbus_pins_bxt[pin];
-       else if (IS_GEN9_BC(dev_priv))
-               return &gmbus_pins_skl[pin];
-       else if (IS_BROADWELL(dev_priv))
-               return &gmbus_pins_bdw[pin];
-       else
-               return &gmbus_pins[pin];
-}
-
-bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
-                             unsigned int pin)
-{
-       unsigned int size;
-
-       if (HAS_PCH_ICP(dev_priv))
-               size = ARRAY_SIZE(gmbus_pins_icp);
-       else if (HAS_PCH_CNP(dev_priv))
-               size = ARRAY_SIZE(gmbus_pins_cnp);
-       else if (IS_GEN9_LP(dev_priv))
-               size = ARRAY_SIZE(gmbus_pins_bxt);
-       else if (IS_GEN9_BC(dev_priv))
-               size = ARRAY_SIZE(gmbus_pins_skl);
-       else if (IS_BROADWELL(dev_priv))
-               size = ARRAY_SIZE(gmbus_pins_bdw);
-       else
-               size = ARRAY_SIZE(gmbus_pins);
-
-       return pin < size && get_gmbus_pin(dev_priv, pin)->name;
-}
-
-/* Intel GPIO access functions */
-
-#define I2C_RISEFALL_TIME 10
-
-static inline struct intel_gmbus *
-to_intel_gmbus(struct i2c_adapter *i2c)
-{
-       return container_of(i2c, struct intel_gmbus, adapter);
-}
-
-void
-intel_gmbus_reset(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE(GMBUS0, 0);
-       I915_WRITE(GMBUS4, 0);
-}
-
-static void pnv_gmbus_clock_gating(struct drm_i915_private *dev_priv,
-                                  bool enable)
-{
-       u32 val;
-
-       /* When using bit bashing for I2C, this bit needs to be set to 1 */
-       val = I915_READ(DSPCLK_GATE_D);
-       if (!enable)
-               val |= PNV_GMBUSUNIT_CLOCK_GATE_DISABLE;
-       else
-               val &= ~PNV_GMBUSUNIT_CLOCK_GATE_DISABLE;
-       I915_WRITE(DSPCLK_GATE_D, val);
-}
-
-static void pch_gmbus_clock_gating(struct drm_i915_private *dev_priv,
-                                  bool enable)
-{
-       u32 val;
-
-       val = I915_READ(SOUTH_DSPCLK_GATE_D);
-       if (!enable)
-               val |= PCH_GMBUSUNIT_CLOCK_GATE_DISABLE;
-       else
-               val &= ~PCH_GMBUSUNIT_CLOCK_GATE_DISABLE;
-       I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
-}
-
-static void bxt_gmbus_clock_gating(struct drm_i915_private *dev_priv,
-                                  bool enable)
-{
-       u32 val;
-
-       val = I915_READ(GEN9_CLKGATE_DIS_4);
-       if (!enable)
-               val |= BXT_GMBUS_GATING_DIS;
-       else
-               val &= ~BXT_GMBUS_GATING_DIS;
-       I915_WRITE(GEN9_CLKGATE_DIS_4, val);
-}
-
-static u32 get_reserved(struct intel_gmbus *bus)
-{
-       struct drm_i915_private *i915 = bus->dev_priv;
-       struct intel_uncore *uncore = &i915->uncore;
-       u32 reserved = 0;
-
-       /* On most chips, these bits must be preserved in software. */
-       if (!IS_I830(i915) && !IS_I845G(i915))
-               reserved = intel_uncore_read_notrace(uncore, bus->gpio_reg) &
-                          (GPIO_DATA_PULLUP_DISABLE |
-                           GPIO_CLOCK_PULLUP_DISABLE);
-
-       return reserved;
-}
-
-static int get_clock(void *data)
-{
-       struct intel_gmbus *bus = data;
-       struct intel_uncore *uncore = &bus->dev_priv->uncore;
-       u32 reserved = get_reserved(bus);
-
-       intel_uncore_write_notrace(uncore,
-                                  bus->gpio_reg,
-                                  reserved | GPIO_CLOCK_DIR_MASK);
-       intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved);
-
-       return (intel_uncore_read_notrace(uncore, bus->gpio_reg) &
-               GPIO_CLOCK_VAL_IN) != 0;
-}
-
-static int get_data(void *data)
-{
-       struct intel_gmbus *bus = data;
-       struct intel_uncore *uncore = &bus->dev_priv->uncore;
-       u32 reserved = get_reserved(bus);
-
-       intel_uncore_write_notrace(uncore,
-                                  bus->gpio_reg,
-                                  reserved | GPIO_DATA_DIR_MASK);
-       intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved);
-
-       return (intel_uncore_read_notrace(uncore, bus->gpio_reg) &
-               GPIO_DATA_VAL_IN) != 0;
-}
-
-static void set_clock(void *data, int state_high)
-{
-       struct intel_gmbus *bus = data;
-       struct intel_uncore *uncore = &bus->dev_priv->uncore;
-       u32 reserved = get_reserved(bus);
-       u32 clock_bits;
-
-       if (state_high)
-               clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
-       else
-               clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
-                            GPIO_CLOCK_VAL_MASK;
-
-       intel_uncore_write_notrace(uncore,
-                                  bus->gpio_reg,
-                                  reserved | clock_bits);
-       intel_uncore_posting_read(uncore, bus->gpio_reg);
-}
-
-static void set_data(void *data, int state_high)
-{
-       struct intel_gmbus *bus = data;
-       struct intel_uncore *uncore = &bus->dev_priv->uncore;
-       u32 reserved = get_reserved(bus);
-       u32 data_bits;
-
-       if (state_high)
-               data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
-       else
-               data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
-                       GPIO_DATA_VAL_MASK;
-
-       intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved | data_bits);
-       intel_uncore_posting_read(uncore, bus->gpio_reg);
-}
-
-static int
-intel_gpio_pre_xfer(struct i2c_adapter *adapter)
-{
-       struct intel_gmbus *bus = container_of(adapter,
-                                              struct intel_gmbus,
-                                              adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       intel_gmbus_reset(dev_priv);
-
-       if (IS_PINEVIEW(dev_priv))
-               pnv_gmbus_clock_gating(dev_priv, false);
-
-       set_data(bus, 1);
-       set_clock(bus, 1);
-       udelay(I2C_RISEFALL_TIME);
-       return 0;
-}
-
-static void
-intel_gpio_post_xfer(struct i2c_adapter *adapter)
-{
-       struct intel_gmbus *bus = container_of(adapter,
-                                              struct intel_gmbus,
-                                              adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       set_data(bus, 1);
-       set_clock(bus, 1);
-
-       if (IS_PINEVIEW(dev_priv))
-               pnv_gmbus_clock_gating(dev_priv, true);
-}
-
-static void
-intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
-{
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-       struct i2c_algo_bit_data *algo;
-
-       algo = &bus->bit_algo;
-
-       bus->gpio_reg = GPIO(get_gmbus_pin(dev_priv, pin)->gpio);
-       bus->adapter.algo_data = algo;
-       algo->setsda = set_data;
-       algo->setscl = set_clock;
-       algo->getsda = get_data;
-       algo->getscl = get_clock;
-       algo->pre_xfer = intel_gpio_pre_xfer;
-       algo->post_xfer = intel_gpio_post_xfer;
-       algo->udelay = I2C_RISEFALL_TIME;
-       algo->timeout = usecs_to_jiffies(2200);
-       algo->data = bus;
-}
-
-static int gmbus_wait(struct drm_i915_private *dev_priv, u32 status, u32 irq_en)
-{
-       DEFINE_WAIT(wait);
-       u32 gmbus2;
-       int ret;
-
-       /* Important: The hw handles only the first bit, so set only one! Since
-        * we also need to check for NAKs besides the hw ready/idle signal, we
-        * need to wake up periodically and check that ourselves.
-        */
-       if (!HAS_GMBUS_IRQ(dev_priv))
-               irq_en = 0;
-
-       add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
-       I915_WRITE_FW(GMBUS4, irq_en);
-
-       status |= GMBUS_SATOER;
-       ret = wait_for_us((gmbus2 = I915_READ_FW(GMBUS2)) & status, 2);
-       if (ret)
-               ret = wait_for((gmbus2 = I915_READ_FW(GMBUS2)) & status, 50);
-
-       I915_WRITE_FW(GMBUS4, 0);
-       remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
-
-       if (gmbus2 & GMBUS_SATOER)
-               return -ENXIO;
-
-       return ret;
-}
-
-static int
-gmbus_wait_idle(struct drm_i915_private *dev_priv)
-{
-       DEFINE_WAIT(wait);
-       u32 irq_enable;
-       int ret;
-
-       /* Important: The hw handles only the first bit, so set only one! */
-       irq_enable = 0;
-       if (HAS_GMBUS_IRQ(dev_priv))
-               irq_enable = GMBUS_IDLE_EN;
-
-       add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
-       I915_WRITE_FW(GMBUS4, irq_enable);
-
-       ret = intel_wait_for_register_fw(&dev_priv->uncore,
-                                        GMBUS2, GMBUS_ACTIVE, 0,
-                                        10);
-
-       I915_WRITE_FW(GMBUS4, 0);
-       remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
-
-       return ret;
-}
-
-static inline
-unsigned int gmbus_max_xfer_size(struct drm_i915_private *dev_priv)
-{
-       return INTEL_GEN(dev_priv) >= 9 ? GEN9_GMBUS_BYTE_COUNT_MAX :
-              GMBUS_BYTE_COUNT_MAX;
-}
-
-static int
-gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
-                     unsigned short addr, u8 *buf, unsigned int len,
-                     u32 gmbus0_reg, u32 gmbus1_index)
-{
-       unsigned int size = len;
-       bool burst_read = len > gmbus_max_xfer_size(dev_priv);
-       bool extra_byte_added = false;
-
-       if (burst_read) {
-               /*
-                * As per HW Spec, for 512Bytes need to read extra Byte and
-                * Ignore the extra byte read.
-                */
-               if (len == 512) {
-                       extra_byte_added = true;
-                       len++;
-               }
-               size = len % 256 + 256;
-               I915_WRITE_FW(GMBUS0, gmbus0_reg | GMBUS_BYTE_CNT_OVERRIDE);
-       }
-
-       I915_WRITE_FW(GMBUS1,
-                     gmbus1_index |
-                     GMBUS_CYCLE_WAIT |
-                     (size << GMBUS_BYTE_COUNT_SHIFT) |
-                     (addr << GMBUS_SLAVE_ADDR_SHIFT) |
-                     GMBUS_SLAVE_READ | GMBUS_SW_RDY);
-       while (len) {
-               int ret;
-               u32 val, loop = 0;
-
-               ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
-               if (ret)
-                       return ret;
-
-               val = I915_READ_FW(GMBUS3);
-               do {
-                       if (extra_byte_added && len == 1)
-                               break;
-
-                       *buf++ = val & 0xff;
-                       val >>= 8;
-               } while (--len && ++loop < 4);
-
-               if (burst_read && len == size - 4)
-                       /* Reset the override bit */
-                       I915_WRITE_FW(GMBUS0, gmbus0_reg);
-       }
-
-       return 0;
-}
-
-/*
- * HW spec says that 512Bytes in Burst read need special treatment.
- * But it doesn't talk about other multiple of 256Bytes. And couldn't locate
- * an I2C slave, which supports such a lengthy burst read too for experiments.
- *
- * So until things get clarified on HW support, to avoid the burst read length
- * in fold of 256Bytes except 512, max burst read length is fixed at 767Bytes.
- */
-#define INTEL_GMBUS_BURST_READ_MAX_LEN         767U
-
-static int
-gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
-               u32 gmbus0_reg, u32 gmbus1_index)
-{
-       u8 *buf = msg->buf;
-       unsigned int rx_size = msg->len;
-       unsigned int len;
-       int ret;
-
-       do {
-               if (HAS_GMBUS_BURST_READ(dev_priv))
-                       len = min(rx_size, INTEL_GMBUS_BURST_READ_MAX_LEN);
-               else
-                       len = min(rx_size, gmbus_max_xfer_size(dev_priv));
-
-               ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, buf, len,
-                                           gmbus0_reg, gmbus1_index);
-               if (ret)
-                       return ret;
-
-               rx_size -= len;
-               buf += len;
-       } while (rx_size != 0);
-
-       return 0;
-}
-
-static int
-gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
-                      unsigned short addr, u8 *buf, unsigned int len,
-                      u32 gmbus1_index)
-{
-       unsigned int chunk_size = len;
-       u32 val, loop;
-
-       val = loop = 0;
-       while (len && loop < 4) {
-               val |= *buf++ << (8 * loop++);
-               len -= 1;
-       }
-
-       I915_WRITE_FW(GMBUS3, val);
-       I915_WRITE_FW(GMBUS1,
-                     gmbus1_index | GMBUS_CYCLE_WAIT |
-                     (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
-                     (addr << GMBUS_SLAVE_ADDR_SHIFT) |
-                     GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
-       while (len) {
-               int ret;
-
-               val = loop = 0;
-               do {
-                       val |= *buf++ << (8 * loop);
-               } while (--len && ++loop < 4);
-
-               I915_WRITE_FW(GMBUS3, val);
-
-               ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static int
-gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
-                u32 gmbus1_index)
-{
-       u8 *buf = msg->buf;
-       unsigned int tx_size = msg->len;
-       unsigned int len;
-       int ret;
-
-       do {
-               len = min(tx_size, gmbus_max_xfer_size(dev_priv));
-
-               ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len,
-                                            gmbus1_index);
-               if (ret)
-                       return ret;
-
-               buf += len;
-               tx_size -= len;
-       } while (tx_size != 0);
-
-       return 0;
-}
-
-/*
- * The gmbus controller can combine a 1 or 2 byte write with another read/write
- * that immediately follows it by using an "INDEX" cycle.
- */
-static bool
-gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num)
-{
-       return (i + 1 < num &&
-               msgs[i].addr == msgs[i + 1].addr &&
-               !(msgs[i].flags & I2C_M_RD) &&
-               (msgs[i].len == 1 || msgs[i].len == 2) &&
-               msgs[i + 1].len > 0);
-}
-
-static int
-gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs,
-                u32 gmbus0_reg)
-{
-       u32 gmbus1_index = 0;
-       u32 gmbus5 = 0;
-       int ret;
-
-       if (msgs[0].len == 2)
-               gmbus5 = GMBUS_2BYTE_INDEX_EN |
-                        msgs[0].buf[1] | (msgs[0].buf[0] << 8);
-       if (msgs[0].len == 1)
-               gmbus1_index = GMBUS_CYCLE_INDEX |
-                              (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT);
-
-       /* GMBUS5 holds 16-bit index */
-       if (gmbus5)
-               I915_WRITE_FW(GMBUS5, gmbus5);
-
-       if (msgs[1].flags & I2C_M_RD)
-               ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus0_reg,
-                                     gmbus1_index);
-       else
-               ret = gmbus_xfer_write(dev_priv, &msgs[1], gmbus1_index);
-
-       /* Clear GMBUS5 after each index transfer */
-       if (gmbus5)
-               I915_WRITE_FW(GMBUS5, 0);
-
-       return ret;
-}
-
-static int
-do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
-             u32 gmbus0_source)
-{
-       struct intel_gmbus *bus = container_of(adapter,
-                                              struct intel_gmbus,
-                                              adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-       int i = 0, inc, try = 0;
-       int ret = 0;
-
-       /* Display WA #0868: skl,bxt,kbl,cfl,glk,cnl */
-       if (IS_GEN9_LP(dev_priv))
-               bxt_gmbus_clock_gating(dev_priv, false);
-       else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_CNP(dev_priv))
-               pch_gmbus_clock_gating(dev_priv, false);
-
-retry:
-       I915_WRITE_FW(GMBUS0, gmbus0_source | bus->reg0);
-
-       for (; i < num; i += inc) {
-               inc = 1;
-               if (gmbus_is_index_xfer(msgs, i, num)) {
-                       ret = gmbus_index_xfer(dev_priv, &msgs[i],
-                                              gmbus0_source | bus->reg0);
-                       inc = 2; /* an index transmission is two msgs */
-               } else if (msgs[i].flags & I2C_M_RD) {
-                       ret = gmbus_xfer_read(dev_priv, &msgs[i],
-                                             gmbus0_source | bus->reg0, 0);
-               } else {
-                       ret = gmbus_xfer_write(dev_priv, &msgs[i], 0);
-               }
-
-               if (!ret)
-                       ret = gmbus_wait(dev_priv,
-                                        GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
-               if (ret == -ETIMEDOUT)
-                       goto timeout;
-               else if (ret)
-                       goto clear_err;
-       }
-
-       /* Generate a STOP condition on the bus. Note that gmbus can't generata
-        * a STOP on the very first cycle. To simplify the code we
-        * unconditionally generate the STOP condition with an additional gmbus
-        * cycle. */
-       I915_WRITE_FW(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
-
-       /* Mark the GMBUS interface as disabled after waiting for idle.
-        * We will re-enable it at the start of the next xfer,
-        * till then let it sleep.
-        */
-       if (gmbus_wait_idle(dev_priv)) {
-               DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
-                        adapter->name);
-               ret = -ETIMEDOUT;
-       }
-       I915_WRITE_FW(GMBUS0, 0);
-       ret = ret ?: i;
-       goto out;
-
-clear_err:
-       /*
-        * Wait for bus to IDLE before clearing NAK.
-        * If we clear the NAK while bus is still active, then it will stay
-        * active and the next transaction may fail.
-        *
-        * If no ACK is received during the address phase of a transaction, the
-        * adapter must report -ENXIO. It is not clear what to return if no ACK
-        * is received at other times. But we have to be careful to not return
-        * spurious -ENXIO because that will prevent i2c and drm edid functions
-        * from retrying. So return -ENXIO only when gmbus properly quiescents -
-        * timing out seems to happen when there _is_ a ddc chip present, but
-        * it's slow responding and only answers on the 2nd retry.
-        */
-       ret = -ENXIO;
-       if (gmbus_wait_idle(dev_priv)) {
-               DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
-                             adapter->name);
-               ret = -ETIMEDOUT;
-       }
-
-       /* Toggle the Software Clear Interrupt bit. This has the effect
-        * of resetting the GMBUS controller and so clearing the
-        * BUS_ERROR raised by the slave's NAK.
-        */
-       I915_WRITE_FW(GMBUS1, GMBUS_SW_CLR_INT);
-       I915_WRITE_FW(GMBUS1, 0);
-       I915_WRITE_FW(GMBUS0, 0);
-
-       DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
-                        adapter->name, msgs[i].addr,
-                        (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
-
-       /*
-        * Passive adapters sometimes NAK the first probe. Retry the first
-        * message once on -ENXIO for GMBUS transfers; the bit banging algorithm
-        * has retries internally. See also the retry loop in
-        * drm_do_probe_ddc_edid, which bails out on the first -ENXIO.
-        */
-       if (ret == -ENXIO && i == 0 && try++ == 0) {
-               DRM_DEBUG_KMS("GMBUS [%s] NAK on first message, retry\n",
-                             adapter->name);
-               goto retry;
-       }
-
-       goto out;
-
-timeout:
-       DRM_DEBUG_KMS("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
-                     bus->adapter.name, bus->reg0 & 0xff);
-       I915_WRITE_FW(GMBUS0, 0);
-
-       /*
-        * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
-        * instead. Use EAGAIN to have i2c core retry.
-        */
-       ret = -EAGAIN;
-
-out:
-       /* Display WA #0868: skl,bxt,kbl,cfl,glk,cnl */
-       if (IS_GEN9_LP(dev_priv))
-               bxt_gmbus_clock_gating(dev_priv, true);
-       else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_CNP(dev_priv))
-               pch_gmbus_clock_gating(dev_priv, true);
-
-       return ret;
-}
-
-static int
-gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
-{
-       struct intel_gmbus *bus =
-               container_of(adapter, struct intel_gmbus, adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-       intel_wakeref_t wakeref;
-       int ret;
-
-       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
-
-       if (bus->force_bit) {
-               ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
-               if (ret < 0)
-                       bus->force_bit &= ~GMBUS_FORCE_BIT_RETRY;
-       } else {
-               ret = do_gmbus_xfer(adapter, msgs, num, 0);
-               if (ret == -EAGAIN)
-                       bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
-       }
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
-
-       return ret;
-}
-
-int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
-{
-       struct intel_gmbus *bus =
-               container_of(adapter, struct intel_gmbus, adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-       u8 cmd = DRM_HDCP_DDC_AKSV;
-       u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = DRM_HDCP_DDC_ADDR,
-                       .flags = 0,
-                       .len = sizeof(cmd),
-                       .buf = &cmd,
-               },
-               {
-                       .addr = DRM_HDCP_DDC_ADDR,
-                       .flags = 0,
-                       .len = sizeof(buf),
-                       .buf = buf,
-               }
-       };
-       intel_wakeref_t wakeref;
-       int ret;
-
-       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
-       mutex_lock(&dev_priv->gmbus_mutex);
-
-       /*
-        * In order to output Aksv to the receiver, use an indexed write to
-        * pass the i2c command, and tell GMBUS to use the HW-provided value
-        * instead of sourcing GMBUS3 for the data.
-        */
-       ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
-
-       mutex_unlock(&dev_priv->gmbus_mutex);
-       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
-
-       return ret;
-}
-
-static u32 gmbus_func(struct i2c_adapter *adapter)
-{
-       return i2c_bit_algo.functionality(adapter) &
-               (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
-               /* I2C_FUNC_10BIT_ADDR | */
-               I2C_FUNC_SMBUS_READ_BLOCK_DATA |
-               I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
-}
-
-static const struct i2c_algorithm gmbus_algorithm = {
-       .master_xfer    = gmbus_xfer,
-       .functionality  = gmbus_func
-};
-
-static void gmbus_lock_bus(struct i2c_adapter *adapter,
-                          unsigned int flags)
-{
-       struct intel_gmbus *bus = to_intel_gmbus(adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       mutex_lock(&dev_priv->gmbus_mutex);
-}
-
-static int gmbus_trylock_bus(struct i2c_adapter *adapter,
-                            unsigned int flags)
-{
-       struct intel_gmbus *bus = to_intel_gmbus(adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       return mutex_trylock(&dev_priv->gmbus_mutex);
-}
-
-static void gmbus_unlock_bus(struct i2c_adapter *adapter,
-                            unsigned int flags)
-{
-       struct intel_gmbus *bus = to_intel_gmbus(adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       mutex_unlock(&dev_priv->gmbus_mutex);
-}
-
-static const struct i2c_lock_operations gmbus_lock_ops = {
-       .lock_bus =    gmbus_lock_bus,
-       .trylock_bus = gmbus_trylock_bus,
-       .unlock_bus =  gmbus_unlock_bus,
-};
-
-/**
- * intel_gmbus_setup - instantiate all Intel i2c GMBuses
- * @dev_priv: i915 device private
- */
-int intel_gmbus_setup(struct drm_i915_private *dev_priv)
-{
-       struct pci_dev *pdev = dev_priv->drm.pdev;
-       struct intel_gmbus *bus;
-       unsigned int pin;
-       int ret;
-
-       if (!HAS_DISPLAY(dev_priv))
-               return 0;
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
-       else if (!HAS_GMCH(dev_priv))
-               /*
-                * Broxton uses the same PCH offsets for South Display Engine,
-                * even though it doesn't have a PCH.
-                */
-               dev_priv->gpio_mmio_base = PCH_DISPLAY_BASE;
-
-       mutex_init(&dev_priv->gmbus_mutex);
-       init_waitqueue_head(&dev_priv->gmbus_wait_queue);
-
-       for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
-               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
-                       continue;
-
-               bus = &dev_priv->gmbus[pin];
-
-               bus->adapter.owner = THIS_MODULE;
-               bus->adapter.class = I2C_CLASS_DDC;
-               snprintf(bus->adapter.name,
-                        sizeof(bus->adapter.name),
-                        "i915 gmbus %s",
-                        get_gmbus_pin(dev_priv, pin)->name);
-
-               bus->adapter.dev.parent = &pdev->dev;
-               bus->dev_priv = dev_priv;
-
-               bus->adapter.algo = &gmbus_algorithm;
-               bus->adapter.lock_ops = &gmbus_lock_ops;
-
-               /*
-                * We wish to retry with bit banging
-                * after a timed out GMBUS attempt.
-                */
-               bus->adapter.retries = 1;
-
-               /* By default use a conservative clock rate */
-               bus->reg0 = pin | GMBUS_RATE_100KHZ;
-
-               /* gmbus seems to be broken on i830 */
-               if (IS_I830(dev_priv))
-                       bus->force_bit = 1;
-
-               intel_gpio_setup(bus, pin);
-
-               ret = i2c_add_adapter(&bus->adapter);
-               if (ret)
-                       goto err;
-       }
-
-       intel_gmbus_reset(dev_priv);
-
-       return 0;
-
-err:
-       while (pin--) {
-               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
-                       continue;
-
-               bus = &dev_priv->gmbus[pin];
-               i2c_del_adapter(&bus->adapter);
-       }
-       return ret;
-}
-
-struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
-                                           unsigned int pin)
-{
-       if (WARN_ON(!intel_gmbus_is_valid_pin(dev_priv, pin)))
-               return NULL;
-
-       return &dev_priv->gmbus[pin].adapter;
-}
-
-void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
-{
-       struct intel_gmbus *bus = to_intel_gmbus(adapter);
-
-       bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | speed;
-}
-
-void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
-{
-       struct intel_gmbus *bus = to_intel_gmbus(adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       mutex_lock(&dev_priv->gmbus_mutex);
-
-       bus->force_bit += force_bit ? 1 : -1;
-       DRM_DEBUG_KMS("%sabling bit-banging on %s. force bit now %d\n",
-                     force_bit ? "en" : "dis", adapter->name,
-                     bus->force_bit);
-
-       mutex_unlock(&dev_priv->gmbus_mutex);
-}
-
-bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
-{
-       struct intel_gmbus *bus = to_intel_gmbus(adapter);
-
-       return bus->force_bit;
-}
-
-void intel_gmbus_teardown(struct drm_i915_private *dev_priv)
-{
-       struct intel_gmbus *bus;
-       unsigned int pin;
-
-       for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
-               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
-                       continue;
-
-               bus = &dev_priv->gmbus[pin];
-               i2c_del_adapter(&bus->adapter);
-       }
-}
diff --git a/drivers/gpu/drm/i915/intel_gmbus.h b/drivers/gpu/drm/i915/intel_gmbus.h
deleted file mode 100644 (file)
index d989085..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_GMBUS_H__
-#define __INTEL_GMBUS_H__
-
-#include <linux/types.h>
-
-struct drm_i915_private;
-struct i2c_adapter;
-
-int intel_gmbus_setup(struct drm_i915_private *dev_priv);
-void intel_gmbus_teardown(struct drm_i915_private *dev_priv);
-bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
-                             unsigned int pin);
-int intel_gmbus_output_aksv(struct i2c_adapter *adapter);
-
-struct i2c_adapter *
-intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
-void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
-void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
-bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter);
-void intel_gmbus_reset(struct drm_i915_private *dev_priv);
-
-#endif /* __INTEL_GMBUS_H__ */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
deleted file mode 100644 (file)
index 187a2b8..0000000
+++ /dev/null
@@ -1,3204 +0,0 @@
-/*
- * Copyright 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- *     Jesse Barnes <jesse.barnes@intel.com>
- */
-
-#include <linux/delay.h>
-#include <linux/hdmi.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_hdcp.h>
-#include <drm/drm_scdc_helper.h>
-#include <drm/i915_drm.h>
-#include <drm/intel_lpe_audio.h>
-
-#include "i915_debugfs.h"
-#include "i915_drv.h"
-#include "intel_atomic.h"
-#include "intel_audio.h"
-#include "intel_connector.h"
-#include "intel_ddi.h"
-#include "intel_dp.h"
-#include "intel_dpio_phy.h"
-#include "intel_drv.h"
-#include "intel_fifo_underrun.h"
-#include "intel_gmbus.h"
-#include "intel_hdcp.h"
-#include "intel_hdmi.h"
-#include "intel_hotplug.h"
-#include "intel_lspcon.h"
-#include "intel_sdvo.h"
-#include "intel_panel.h"
-#include "intel_sideband.h"
-
-static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
-{
-       return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
-}
-
-static void
-assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
-{
-       struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 enabled_bits;
-
-       enabled_bits = HAS_DDI(dev_priv) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
-
-       WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
-            "HDMI port enabled, expecting disabled\n");
-}
-
-static void
-assert_hdmi_transcoder_func_disabled(struct drm_i915_private *dev_priv,
-                                    enum transcoder cpu_transcoder)
-{
-       WARN(I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)) &
-            TRANS_DDI_FUNC_ENABLE,
-            "HDMI transcoder function enabled, expecting disabled\n");
-}
-
-struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
-{
-       struct intel_digital_port *intel_dig_port =
-               container_of(encoder, struct intel_digital_port, base.base);
-       return &intel_dig_port->hdmi;
-}
-
-static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
-{
-       return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base);
-}
-
-static u32 g4x_infoframe_index(unsigned int type)
-{
-       switch (type) {
-       case HDMI_PACKET_TYPE_GAMUT_METADATA:
-               return VIDEO_DIP_SELECT_GAMUT;
-       case HDMI_INFOFRAME_TYPE_AVI:
-               return VIDEO_DIP_SELECT_AVI;
-       case HDMI_INFOFRAME_TYPE_SPD:
-               return VIDEO_DIP_SELECT_SPD;
-       case HDMI_INFOFRAME_TYPE_VENDOR:
-               return VIDEO_DIP_SELECT_VENDOR;
-       default:
-               MISSING_CASE(type);
-               return 0;
-       }
-}
-
-static u32 g4x_infoframe_enable(unsigned int type)
-{
-       switch (type) {
-       case HDMI_PACKET_TYPE_GENERAL_CONTROL:
-               return VIDEO_DIP_ENABLE_GCP;
-       case HDMI_PACKET_TYPE_GAMUT_METADATA:
-               return VIDEO_DIP_ENABLE_GAMUT;
-       case DP_SDP_VSC:
-               return 0;
-       case HDMI_INFOFRAME_TYPE_AVI:
-               return VIDEO_DIP_ENABLE_AVI;
-       case HDMI_INFOFRAME_TYPE_SPD:
-               return VIDEO_DIP_ENABLE_SPD;
-       case HDMI_INFOFRAME_TYPE_VENDOR:
-               return VIDEO_DIP_ENABLE_VENDOR;
-       case HDMI_INFOFRAME_TYPE_DRM:
-               return 0;
-       default:
-               MISSING_CASE(type);
-               return 0;
-       }
-}
-
-static u32 hsw_infoframe_enable(unsigned int type)
-{
-       switch (type) {
-       case HDMI_PACKET_TYPE_GENERAL_CONTROL:
-               return VIDEO_DIP_ENABLE_GCP_HSW;
-       case HDMI_PACKET_TYPE_GAMUT_METADATA:
-               return VIDEO_DIP_ENABLE_GMP_HSW;
-       case DP_SDP_VSC:
-               return VIDEO_DIP_ENABLE_VSC_HSW;
-       case DP_SDP_PPS:
-               return VDIP_ENABLE_PPS;
-       case HDMI_INFOFRAME_TYPE_AVI:
-               return VIDEO_DIP_ENABLE_AVI_HSW;
-       case HDMI_INFOFRAME_TYPE_SPD:
-               return VIDEO_DIP_ENABLE_SPD_HSW;
-       case HDMI_INFOFRAME_TYPE_VENDOR:
-               return VIDEO_DIP_ENABLE_VS_HSW;
-       case HDMI_INFOFRAME_TYPE_DRM:
-               return VIDEO_DIP_ENABLE_DRM_GLK;
-       default:
-               MISSING_CASE(type);
-               return 0;
-       }
-}
-
-static i915_reg_t
-hsw_dip_data_reg(struct drm_i915_private *dev_priv,
-                enum transcoder cpu_transcoder,
-                unsigned int type,
-                int i)
-{
-       switch (type) {
-       case HDMI_PACKET_TYPE_GAMUT_METADATA:
-               return HSW_TVIDEO_DIP_GMP_DATA(cpu_transcoder, i);
-       case DP_SDP_VSC:
-               return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i);
-       case DP_SDP_PPS:
-               return ICL_VIDEO_DIP_PPS_DATA(cpu_transcoder, i);
-       case HDMI_INFOFRAME_TYPE_AVI:
-               return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder, i);
-       case HDMI_INFOFRAME_TYPE_SPD:
-               return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder, i);
-       case HDMI_INFOFRAME_TYPE_VENDOR:
-               return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
-       case HDMI_INFOFRAME_TYPE_DRM:
-               return GLK_TVIDEO_DIP_DRM_DATA(cpu_transcoder, i);
-       default:
-               MISSING_CASE(type);
-               return INVALID_MMIO_REG;
-       }
-}
-
-static int hsw_dip_data_size(unsigned int type)
-{
-       switch (type) {
-       case DP_SDP_VSC:
-               return VIDEO_DIP_VSC_DATA_SIZE;
-       case DP_SDP_PPS:
-               return VIDEO_DIP_PPS_DATA_SIZE;
-       default:
-               return VIDEO_DIP_DATA_SIZE;
-       }
-}
-
-static void g4x_write_infoframe(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *crtc_state,
-                               unsigned int type,
-                               const void *frame, ssize_t len)
-{
-       const u32 *data = frame;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val = I915_READ(VIDEO_DIP_CTL);
-       int i;
-
-       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       val &= ~g4x_infoframe_enable(type);
-
-       I915_WRITE(VIDEO_DIP_CTL, val);
-
-       for (i = 0; i < len; i += 4) {
-               I915_WRITE(VIDEO_DIP_DATA, *data);
-               data++;
-       }
-       /* Write every possible data byte to force correct ECC calculation. */
-       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
-               I915_WRITE(VIDEO_DIP_DATA, 0);
-
-       val |= g4x_infoframe_enable(type);
-       val &= ~VIDEO_DIP_FREQ_MASK;
-       val |= VIDEO_DIP_FREQ_VSYNC;
-
-       I915_WRITE(VIDEO_DIP_CTL, val);
-       POSTING_READ(VIDEO_DIP_CTL);
-}
-
-static void g4x_read_infoframe(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              unsigned int type,
-                              void *frame, ssize_t len)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val, *data = frame;
-       int i;
-
-       val = I915_READ(VIDEO_DIP_CTL);
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       I915_WRITE(VIDEO_DIP_CTL, val);
-
-       for (i = 0; i < len; i += 4)
-               *data++ = I915_READ(VIDEO_DIP_DATA);
-}
-
-static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val = I915_READ(VIDEO_DIP_CTL);
-
-       if ((val & VIDEO_DIP_ENABLE) == 0)
-               return 0;
-
-       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
-               return 0;
-
-       return val & (VIDEO_DIP_ENABLE_AVI |
-                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
-}
-
-static void ibx_write_infoframe(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *crtc_state,
-                               unsigned int type,
-                               const void *frame, ssize_t len)
-{
-       const u32 *data = frame;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
-       u32 val = I915_READ(reg);
-       int i;
-
-       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       val &= ~g4x_infoframe_enable(type);
-
-       I915_WRITE(reg, val);
-
-       for (i = 0; i < len; i += 4) {
-               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
-               data++;
-       }
-       /* Write every possible data byte to force correct ECC calculation. */
-       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
-               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
-
-       val |= g4x_infoframe_enable(type);
-       val &= ~VIDEO_DIP_FREQ_MASK;
-       val |= VIDEO_DIP_FREQ_VSYNC;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-}
-
-static void ibx_read_infoframe(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              unsigned int type,
-                              void *frame, ssize_t len)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       u32 val, *data = frame;
-       int i;
-
-       val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
-
-       for (i = 0; i < len; i += 4)
-               *data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
-}
-
-static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
-       i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
-       u32 val = I915_READ(reg);
-
-       if ((val & VIDEO_DIP_ENABLE) == 0)
-               return 0;
-
-       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
-               return 0;
-
-       return val & (VIDEO_DIP_ENABLE_AVI |
-                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                     VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-}
-
-static void cpt_write_infoframe(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *crtc_state,
-                               unsigned int type,
-                               const void *frame, ssize_t len)
-{
-       const u32 *data = frame;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
-       u32 val = I915_READ(reg);
-       int i;
-
-       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       /* The DIP control register spec says that we need to update the AVI
-        * infoframe without clearing its enable bit */
-       if (type != HDMI_INFOFRAME_TYPE_AVI)
-               val &= ~g4x_infoframe_enable(type);
-
-       I915_WRITE(reg, val);
-
-       for (i = 0; i < len; i += 4) {
-               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
-               data++;
-       }
-       /* Write every possible data byte to force correct ECC calculation. */
-       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
-               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
-
-       val |= g4x_infoframe_enable(type);
-       val &= ~VIDEO_DIP_FREQ_MASK;
-       val |= VIDEO_DIP_FREQ_VSYNC;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-}
-
-static void cpt_read_infoframe(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              unsigned int type,
-                              void *frame, ssize_t len)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       u32 val, *data = frame;
-       int i;
-
-       val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
-
-       for (i = 0; i < len; i += 4)
-               *data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
-}
-
-static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
-       u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
-
-       if ((val & VIDEO_DIP_ENABLE) == 0)
-               return 0;
-
-       return val & (VIDEO_DIP_ENABLE_AVI |
-                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                     VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-}
-
-static void vlv_write_infoframe(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *crtc_state,
-                               unsigned int type,
-                               const void *frame, ssize_t len)
-{
-       const u32 *data = frame;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
-       u32 val = I915_READ(reg);
-       int i;
-
-       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       val &= ~g4x_infoframe_enable(type);
-
-       I915_WRITE(reg, val);
-
-       for (i = 0; i < len; i += 4) {
-               I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
-               data++;
-       }
-       /* Write every possible data byte to force correct ECC calculation. */
-       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
-               I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
-
-       val |= g4x_infoframe_enable(type);
-       val &= ~VIDEO_DIP_FREQ_MASK;
-       val |= VIDEO_DIP_FREQ_VSYNC;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-}
-
-static void vlv_read_infoframe(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              unsigned int type,
-                              void *frame, ssize_t len)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       u32 val, *data = frame;
-       int i;
-
-       val = I915_READ(VLV_TVIDEO_DIP_CTL(crtc->pipe));
-
-       val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
-       val |= g4x_infoframe_index(type);
-
-       I915_WRITE(VLV_TVIDEO_DIP_CTL(crtc->pipe), val);
-
-       for (i = 0; i < len; i += 4)
-               *data++ = I915_READ(VLV_TVIDEO_DIP_DATA(crtc->pipe));
-}
-
-static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
-       u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
-
-       if ((val & VIDEO_DIP_ENABLE) == 0)
-               return 0;
-
-       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
-               return 0;
-
-       return val & (VIDEO_DIP_ENABLE_AVI |
-                     VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                     VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-}
-
-static void hsw_write_infoframe(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *crtc_state,
-                               unsigned int type,
-                               const void *frame, ssize_t len)
-{
-       const u32 *data = frame;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
-       int data_size;
-       int i;
-       u32 val = I915_READ(ctl_reg);
-
-       data_size = hsw_dip_data_size(type);
-
-       val &= ~hsw_infoframe_enable(type);
-       I915_WRITE(ctl_reg, val);
-
-       for (i = 0; i < len; i += 4) {
-               I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
-                                           type, i >> 2), *data);
-               data++;
-       }
-       /* Write every possible data byte to force correct ECC calculation. */
-       for (; i < data_size; i += 4)
-               I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
-                                           type, i >> 2), 0);
-
-       val |= hsw_infoframe_enable(type);
-       I915_WRITE(ctl_reg, val);
-       POSTING_READ(ctl_reg);
-}
-
-static void hsw_read_infoframe(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state,
-                              unsigned int type,
-                              void *frame, ssize_t len)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       u32 val, *data = frame;
-       int i;
-
-       val = I915_READ(HSW_TVIDEO_DIP_CTL(cpu_transcoder));
-
-       for (i = 0; i < len; i += 4)
-               *data++ = I915_READ(hsw_dip_data_reg(dev_priv, cpu_transcoder,
-                                                    type, i >> 2));
-}
-
-static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
-       u32 mask;
-
-       mask = (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
-               VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
-               VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
-
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               mask |= VIDEO_DIP_ENABLE_DRM_GLK;
-
-       return val & mask;
-}
-
-static const u8 infoframe_type_to_idx[] = {
-       HDMI_PACKET_TYPE_GENERAL_CONTROL,
-       HDMI_PACKET_TYPE_GAMUT_METADATA,
-       DP_SDP_VSC,
-       HDMI_INFOFRAME_TYPE_AVI,
-       HDMI_INFOFRAME_TYPE_SPD,
-       HDMI_INFOFRAME_TYPE_VENDOR,
-       HDMI_INFOFRAME_TYPE_DRM,
-};
-
-u32 intel_hdmi_infoframe_enable(unsigned int type)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
-               if (infoframe_type_to_idx[i] == type)
-                       return BIT(i);
-       }
-
-       return 0;
-}
-
-u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       u32 val, ret = 0;
-       int i;
-
-       val = dig_port->infoframes_enabled(encoder, crtc_state);
-
-       /* map from hardware bits to dip idx */
-       for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
-               unsigned int type = infoframe_type_to_idx[i];
-
-               if (HAS_DDI(dev_priv)) {
-                       if (val & hsw_infoframe_enable(type))
-                               ret |= BIT(i);
-               } else {
-                       if (val & g4x_infoframe_enable(type))
-                               ret |= BIT(i);
-               }
-       }
-
-       return ret;
-}
-
-/*
- * The data we write to the DIP data buffer registers is 1 byte bigger than the
- * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
- * at 0). It's also a byte used by DisplayPort so the same DIP registers can be
- * used for both technologies.
- *
- * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0
- * DW1:       DB3       | DB2 | DB1 | DB0
- * DW2:       DB7       | DB6 | DB5 | DB4
- * DW3: ...
- *
- * (HB is Header Byte, DB is Data Byte)
- *
- * The hdmi pack() functions don't know about that hardware specific hole so we
- * trick them by giving an offset into the buffer and moving back the header
- * bytes by one.
- */
-static void intel_write_infoframe(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 enum hdmi_infoframe_type type,
-                                 const union hdmi_infoframe *frame)
-{
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
-       u8 buffer[VIDEO_DIP_DATA_SIZE];
-       ssize_t len;
-
-       if ((crtc_state->infoframes.enable &
-            intel_hdmi_infoframe_enable(type)) == 0)
-               return;
-
-       if (WARN_ON(frame->any.type != type))
-               return;
-
-       /* see comment above for the reason for this offset */
-       len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1);
-       if (WARN_ON(len < 0))
-               return;
-
-       /* Insert the 'hole' (see big comment above) at position 3 */
-       memmove(&buffer[0], &buffer[1], 3);
-       buffer[3] = 0;
-       len++;
-
-       intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
-}
-
-void intel_read_infoframe(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *crtc_state,
-                         enum hdmi_infoframe_type type,
-                         union hdmi_infoframe *frame)
-{
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
-       u8 buffer[VIDEO_DIP_DATA_SIZE];
-       int ret;
-
-       if ((crtc_state->infoframes.enable &
-            intel_hdmi_infoframe_enable(type)) == 0)
-               return;
-
-       intel_dig_port->read_infoframe(encoder, crtc_state,
-                                      type, buffer, sizeof(buffer));
-
-       /* Fill the 'hole' (see big comment above) at position 3 */
-       memmove(&buffer[1], &buffer[0], 3);
-
-       /* see comment above for the reason for this offset */
-       ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1);
-       if (ret) {
-               DRM_DEBUG_KMS("Failed to unpack infoframe type 0x%02x\n", type);
-               return;
-       }
-
-       if (frame->any.type != type)
-               DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
-                             frame->any.type, type);
-}
-
-static bool
-intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
-                                struct intel_crtc_state *crtc_state,
-                                struct drm_connector_state *conn_state)
-{
-       struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       struct drm_connector *connector = conn_state->connector;
-       int ret;
-
-       if (!crtc_state->has_infoframe)
-               return true;
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
-
-       ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector,
-                                                      adjusted_mode);
-       if (ret)
-               return false;
-
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
-               frame->colorspace = HDMI_COLORSPACE_YUV420;
-       else if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
-               frame->colorspace = HDMI_COLORSPACE_YUV444;
-       else
-               frame->colorspace = HDMI_COLORSPACE_RGB;
-
-       drm_hdmi_avi_infoframe_colorspace(frame, conn_state);
-
-       drm_hdmi_avi_infoframe_quant_range(frame, connector,
-                                          adjusted_mode,
-                                          crtc_state->limited_color_range ?
-                                          HDMI_QUANTIZATION_RANGE_LIMITED :
-                                          HDMI_QUANTIZATION_RANGE_FULL);
-
-       drm_hdmi_avi_infoframe_content_type(frame, conn_state);
-
-       /* TODO: handle pixel repetition for YCBCR420 outputs */
-
-       ret = hdmi_avi_infoframe_check(frame);
-       if (WARN_ON(ret))
-               return false;
-
-       return true;
-}
-
-static bool
-intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
-                                struct intel_crtc_state *crtc_state,
-                                struct drm_connector_state *conn_state)
-{
-       struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd;
-       int ret;
-
-       if (!crtc_state->has_infoframe)
-               return true;
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD);
-
-       ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
-       if (WARN_ON(ret))
-               return false;
-
-       frame->sdi = HDMI_SPD_SDI_PC;
-
-       ret = hdmi_spd_infoframe_check(frame);
-       if (WARN_ON(ret))
-               return false;
-
-       return true;
-}
-
-static bool
-intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *crtc_state,
-                                 struct drm_connector_state *conn_state)
-{
-       struct hdmi_vendor_infoframe *frame =
-               &crtc_state->infoframes.hdmi.vendor.hdmi;
-       const struct drm_display_info *info =
-               &conn_state->connector->display_info;
-       int ret;
-
-       if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe)
-               return true;
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR);
-
-       ret = drm_hdmi_vendor_infoframe_from_display_mode(frame,
-                                                         conn_state->connector,
-                                                         &crtc_state->base.adjusted_mode);
-       if (WARN_ON(ret))
-               return false;
-
-       ret = hdmi_vendor_infoframe_check(frame);
-       if (WARN_ON(ret))
-               return false;
-
-       return true;
-}
-
-static bool
-intel_hdmi_compute_drm_infoframe(struct intel_encoder *encoder,
-                                struct intel_crtc_state *crtc_state,
-                                struct drm_connector_state *conn_state)
-{
-       struct hdmi_drm_infoframe *frame = &crtc_state->infoframes.drm.drm;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       int ret;
-
-       if (!(INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)))
-               return true;
-
-       if (!crtc_state->has_infoframe)
-               return true;
-
-       if (!conn_state->hdr_output_metadata)
-               return true;
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_DRM);
-
-       ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state);
-       if (ret < 0) {
-               DRM_DEBUG_KMS("couldn't set HDR metadata in infoframe\n");
-               return false;
-       }
-
-       ret = hdmi_drm_infoframe_check(frame);
-       if (WARN_ON(ret))
-               return false;
-
-       return true;
-}
-
-static void g4x_set_infoframes(struct intel_encoder *encoder,
-                              bool enable,
-                              const struct intel_crtc_state *crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
-       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
-       i915_reg_t reg = VIDEO_DIP_CTL;
-       u32 val = I915_READ(reg);
-       u32 port = VIDEO_DIP_PORT(encoder->port);
-
-       assert_hdmi_port_disabled(intel_hdmi);
-
-       /* If the registers were not initialized yet, they might be zeroes,
-        * which means we're selecting the AVI DIP and we're setting its
-        * frequency to once. This seems to really confuse the HW and make
-        * things stop working (the register spec says the AVI always needs to
-        * be sent every VSync). So here we avoid writing to the register more
-        * than we need and also explicitly select the AVI DIP and explicitly
-        * set its frequency to every VSync. Avoiding to write it twice seems to
-        * be enough to solve the problem, but being defensive shouldn't hurt us
-        * either. */
-       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
-
-       if (!enable) {
-               if (!(val & VIDEO_DIP_ENABLE))
-                       return;
-               if (port != (val & VIDEO_DIP_PORT_MASK)) {
-                       DRM_DEBUG_KMS("video DIP still enabled on port %c\n",
-                                     (val & VIDEO_DIP_PORT_MASK) >> 29);
-                       return;
-               }
-               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
-                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
-               I915_WRITE(reg, val);
-               POSTING_READ(reg);
-               return;
-       }
-
-       if (port != (val & VIDEO_DIP_PORT_MASK)) {
-               if (val & VIDEO_DIP_ENABLE) {
-                       DRM_DEBUG_KMS("video DIP already enabled on port %c\n",
-                                     (val & VIDEO_DIP_PORT_MASK) >> 29);
-                       return;
-               }
-               val &= ~VIDEO_DIP_PORT_MASK;
-               val |= port;
-       }
-
-       val |= VIDEO_DIP_ENABLE;
-       val &= ~(VIDEO_DIP_ENABLE_AVI |
-                VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_AVI,
-                             &crtc_state->infoframes.avi);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_SPD,
-                             &crtc_state->infoframes.spd);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_VENDOR,
-                             &crtc_state->infoframes.hdmi);
-}
-
-/*
- * Determine if default_phase=1 can be indicated in the GCP infoframe.
- *
- * From HDMI specification 1.4a:
- * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0
- * - The first pixel following each Video Data Period shall have a pixel packing phase of 0
- * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase
- * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing
- *   phase of 0
- */
-static bool gcp_default_phase_possible(int pipe_bpp,
-                                      const struct drm_display_mode *mode)
-{
-       unsigned int pixels_per_group;
-
-       switch (pipe_bpp) {
-       case 30:
-               /* 4 pixels in 5 clocks */
-               pixels_per_group = 4;
-               break;
-       case 36:
-               /* 2 pixels in 3 clocks */
-               pixels_per_group = 2;
-               break;
-       case 48:
-               /* 1 pixel in 2 clocks */
-               pixels_per_group = 1;
-               break;
-       default:
-               /* phase information not relevant for 8bpc */
-               return false;
-       }
-
-       return mode->crtc_hdisplay % pixels_per_group == 0 &&
-               mode->crtc_htotal % pixels_per_group == 0 &&
-               mode->crtc_hblank_start % pixels_per_group == 0 &&
-               mode->crtc_hblank_end % pixels_per_group == 0 &&
-               mode->crtc_hsync_start % pixels_per_group == 0 &&
-               mode->crtc_hsync_end % pixels_per_group == 0 &&
-               ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 ||
-                mode->crtc_htotal/2 % pixels_per_group == 0);
-}
-
-static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
-                                        const struct intel_crtc_state *crtc_state,
-                                        const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       i915_reg_t reg;
-
-       if ((crtc_state->infoframes.enable &
-            intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
-               return false;
-
-       if (HAS_DDI(dev_priv))
-               reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
-       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
-       else if (HAS_PCH_SPLIT(dev_priv))
-               reg = TVIDEO_DIP_GCP(crtc->pipe);
-       else
-               return false;
-
-       I915_WRITE(reg, crtc_state->infoframes.gcp);
-
-       return true;
-}
-
-void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
-                                  struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       i915_reg_t reg;
-
-       if ((crtc_state->infoframes.enable &
-            intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
-               return;
-
-       if (HAS_DDI(dev_priv))
-               reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
-       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
-       else if (HAS_PCH_SPLIT(dev_priv))
-               reg = TVIDEO_DIP_GCP(crtc->pipe);
-       else
-               return;
-
-       crtc_state->infoframes.gcp = I915_READ(reg);
-}
-
-static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
-                                            struct intel_crtc_state *crtc_state,
-                                            struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (IS_G4X(dev_priv) || !crtc_state->has_infoframe)
-               return;
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL);
-
-       /* Indicate color indication for deep color mode */
-       if (crtc_state->pipe_bpp > 24)
-               crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION;
-
-       /* Enable default_phase whenever the display mode is suitably aligned */
-       if (gcp_default_phase_possible(crtc_state->pipe_bpp,
-                                      &crtc_state->base.adjusted_mode))
-               crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE;
-}
-
-static void ibx_set_infoframes(struct intel_encoder *encoder,
-                              bool enable,
-                              const struct intel_crtc_state *crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
-       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
-       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
-       u32 val = I915_READ(reg);
-       u32 port = VIDEO_DIP_PORT(encoder->port);
-
-       assert_hdmi_port_disabled(intel_hdmi);
-
-       /* See the big comment in g4x_set_infoframes() */
-       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
-
-       if (!enable) {
-               if (!(val & VIDEO_DIP_ENABLE))
-                       return;
-               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
-                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                        VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-               I915_WRITE(reg, val);
-               POSTING_READ(reg);
-               return;
-       }
-
-       if (port != (val & VIDEO_DIP_PORT_MASK)) {
-               WARN(val & VIDEO_DIP_ENABLE,
-                    "DIP already enabled on port %c\n",
-                    (val & VIDEO_DIP_PORT_MASK) >> 29);
-               val &= ~VIDEO_DIP_PORT_MASK;
-               val |= port;
-       }
-
-       val |= VIDEO_DIP_ENABLE;
-       val &= ~(VIDEO_DIP_ENABLE_AVI |
-                VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-
-       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
-               val |= VIDEO_DIP_ENABLE_GCP;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_AVI,
-                             &crtc_state->infoframes.avi);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_SPD,
-                             &crtc_state->infoframes.spd);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_VENDOR,
-                             &crtc_state->infoframes.hdmi);
-}
-
-static void cpt_set_infoframes(struct intel_encoder *encoder,
-                              bool enable,
-                              const struct intel_crtc_state *crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
-       u32 val = I915_READ(reg);
-
-       assert_hdmi_port_disabled(intel_hdmi);
-
-       /* See the big comment in g4x_set_infoframes() */
-       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
-
-       if (!enable) {
-               if (!(val & VIDEO_DIP_ENABLE))
-                       return;
-               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
-                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                        VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-               I915_WRITE(reg, val);
-               POSTING_READ(reg);
-               return;
-       }
-
-       /* Set both together, unset both together: see the spec. */
-       val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
-       val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-
-       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
-               val |= VIDEO_DIP_ENABLE_GCP;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_AVI,
-                             &crtc_state->infoframes.avi);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_SPD,
-                             &crtc_state->infoframes.spd);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_VENDOR,
-                             &crtc_state->infoframes.hdmi);
-}
-
-static void vlv_set_infoframes(struct intel_encoder *encoder,
-                              bool enable,
-                              const struct intel_crtc_state *crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
-       u32 val = I915_READ(reg);
-       u32 port = VIDEO_DIP_PORT(encoder->port);
-
-       assert_hdmi_port_disabled(intel_hdmi);
-
-       /* See the big comment in g4x_set_infoframes() */
-       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
-
-       if (!enable) {
-               if (!(val & VIDEO_DIP_ENABLE))
-                       return;
-               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
-                        VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                        VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-               I915_WRITE(reg, val);
-               POSTING_READ(reg);
-               return;
-       }
-
-       if (port != (val & VIDEO_DIP_PORT_MASK)) {
-               WARN(val & VIDEO_DIP_ENABLE,
-                    "DIP already enabled on port %c\n",
-                    (val & VIDEO_DIP_PORT_MASK) >> 29);
-               val &= ~VIDEO_DIP_PORT_MASK;
-               val |= port;
-       }
-
-       val |= VIDEO_DIP_ENABLE;
-       val &= ~(VIDEO_DIP_ENABLE_AVI |
-                VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
-
-       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
-               val |= VIDEO_DIP_ENABLE_GCP;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_AVI,
-                             &crtc_state->infoframes.avi);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_SPD,
-                             &crtc_state->infoframes.spd);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_VENDOR,
-                             &crtc_state->infoframes.hdmi);
-}
-
-static void hsw_set_infoframes(struct intel_encoder *encoder,
-                              bool enable,
-                              const struct intel_crtc_state *crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
-       u32 val = I915_READ(reg);
-
-       assert_hdmi_transcoder_func_disabled(dev_priv,
-                                            crtc_state->cpu_transcoder);
-
-       val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
-                VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
-                VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW |
-                VIDEO_DIP_ENABLE_DRM_GLK);
-
-       if (!enable) {
-               I915_WRITE(reg, val);
-               POSTING_READ(reg);
-               return;
-       }
-
-       if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
-               val |= VIDEO_DIP_ENABLE_GCP_HSW;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_AVI,
-                             &crtc_state->infoframes.avi);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_SPD,
-                             &crtc_state->infoframes.spd);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_VENDOR,
-                             &crtc_state->infoframes.hdmi);
-       intel_write_infoframe(encoder, crtc_state,
-                             HDMI_INFOFRAME_TYPE_DRM,
-                             &crtc_state->infoframes.drm);
-}
-
-void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
-       struct i2c_adapter *adapter =
-               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
-
-       if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
-               return;
-
-       DRM_DEBUG_KMS("%s DP dual mode adaptor TMDS output\n",
-                     enable ? "Enabling" : "Disabling");
-
-       drm_dp_dual_mode_set_tmds_output(hdmi->dp_dual_mode.type,
-                                        adapter, enable);
-}
-
-static int intel_hdmi_hdcp_read(struct intel_digital_port *intel_dig_port,
-                               unsigned int offset, void *buffer, size_t size)
-{
-       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
-       struct drm_i915_private *dev_priv =
-               intel_dig_port->base.base.dev->dev_private;
-       struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
-                                                             hdmi->ddc_bus);
-       int ret;
-       u8 start = offset & 0xff;
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = DRM_HDCP_DDC_ADDR,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &start,
-               },
-               {
-                       .addr = DRM_HDCP_DDC_ADDR,
-                       .flags = I2C_M_RD,
-                       .len = size,
-                       .buf = buffer
-               }
-       };
-       ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
-       if (ret == ARRAY_SIZE(msgs))
-               return 0;
-       return ret >= 0 ? -EIO : ret;
-}
-
-static int intel_hdmi_hdcp_write(struct intel_digital_port *intel_dig_port,
-                                unsigned int offset, void *buffer, size_t size)
-{
-       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
-       struct drm_i915_private *dev_priv =
-               intel_dig_port->base.base.dev->dev_private;
-       struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
-                                                             hdmi->ddc_bus);
-       int ret;
-       u8 *write_buf;
-       struct i2c_msg msg;
-
-       write_buf = kzalloc(size + 1, GFP_KERNEL);
-       if (!write_buf)
-               return -ENOMEM;
-
-       write_buf[0] = offset & 0xff;
-       memcpy(&write_buf[1], buffer, size);
-
-       msg.addr = DRM_HDCP_DDC_ADDR;
-       msg.flags = 0,
-       msg.len = size + 1,
-       msg.buf = write_buf;
-
-       ret = i2c_transfer(adapter, &msg, 1);
-       if (ret == 1)
-               ret = 0;
-       else if (ret >= 0)
-               ret = -EIO;
-
-       kfree(write_buf);
-       return ret;
-}
-
-static
-int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
-                                 u8 *an)
-{
-       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
-       struct drm_i915_private *dev_priv =
-               intel_dig_port->base.base.dev->dev_private;
-       struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
-                                                             hdmi->ddc_bus);
-       int ret;
-
-       ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an,
-                                   DRM_HDCP_AN_LEN);
-       if (ret) {
-               DRM_DEBUG_KMS("Write An over DDC failed (%d)\n", ret);
-               return ret;
-       }
-
-       ret = intel_gmbus_output_aksv(adapter);
-       if (ret < 0) {
-               DRM_DEBUG_KMS("Failed to output aksv (%d)\n", ret);
-               return ret;
-       }
-       return 0;
-}
-
-static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
-                                    u8 *bksv)
-{
-       int ret;
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv,
-                                  DRM_HDCP_KSV_LEN);
-       if (ret)
-               DRM_DEBUG_KMS("Read Bksv over DDC failed (%d)\n", ret);
-       return ret;
-}
-
-static
-int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
-                                u8 *bstatus)
-{
-       int ret;
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS,
-                                  bstatus, DRM_HDCP_BSTATUS_LEN);
-       if (ret)
-               DRM_DEBUG_KMS("Read bstatus over DDC failed (%d)\n", ret);
-       return ret;
-}
-
-static
-int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
-                                    bool *repeater_present)
-{
-       int ret;
-       u8 val;
-
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
-       if (ret) {
-               DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
-               return ret;
-       }
-       *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
-       return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
-                                 u8 *ri_prime)
-{
-       int ret;
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME,
-                                  ri_prime, DRM_HDCP_RI_LEN);
-       if (ret)
-               DRM_DEBUG_KMS("Read Ri' over DDC failed (%d)\n", ret);
-       return ret;
-}
-
-static
-int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
-                                  bool *ksv_ready)
-{
-       int ret;
-       u8 val;
-
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
-       if (ret) {
-               DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
-               return ret;
-       }
-       *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
-       return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
-                                 int num_downstream, u8 *ksv_fifo)
-{
-       int ret;
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO,
-                                  ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
-       if (ret) {
-               DRM_DEBUG_KMS("Read ksv fifo over DDC failed (%d)\n", ret);
-               return ret;
-       }
-       return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
-                                     int i, u32 *part)
-{
-       int ret;
-
-       if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
-               return -EINVAL;
-
-       ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i),
-                                  part, DRM_HDCP_V_PRIME_PART_LEN);
-       if (ret)
-               DRM_DEBUG_KMS("Read V'[%d] over DDC failed (%d)\n", i, ret);
-       return ret;
-}
-
-static int kbl_repositioning_enc_en_signal(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
-       struct drm_crtc *crtc = connector->base.state->crtc;
-       struct intel_crtc *intel_crtc = container_of(crtc,
-                                                    struct intel_crtc, base);
-       u32 scanline;
-       int ret;
-
-       for (;;) {
-               scanline = I915_READ(PIPEDSL(intel_crtc->pipe));
-               if (scanline > 100 && scanline < 200)
-                       break;
-               usleep_range(25, 50);
-       }
-
-       ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, false);
-       if (ret) {
-               DRM_ERROR("Disable HDCP signalling failed (%d)\n", ret);
-               return ret;
-       }
-       ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, true);
-       if (ret) {
-               DRM_ERROR("Enable HDCP signalling failed (%d)\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static
-int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
-                                     bool enable)
-{
-       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
-       struct intel_connector *connector = hdmi->attached_connector;
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int ret;
-
-       if (!enable)
-               usleep_range(6, 60); /* Bspec says >= 6us */
-
-       ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, enable);
-       if (ret) {
-               DRM_ERROR("%s HDCP signalling failed (%d)\n",
-                         enable ? "Enable" : "Disable", ret);
-               return ret;
-       }
-
-       /*
-        * WA: To fix incorrect positioning of the window of
-        * opportunity and enc_en signalling in KABYLAKE.
-        */
-       if (IS_KABYLAKE(dev_priv) && enable)
-               return kbl_repositioning_enc_en_signal(connector);
-
-       return 0;
-}
-
-static
-bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port)
-{
-       struct drm_i915_private *dev_priv =
-               intel_dig_port->base.base.dev->dev_private;
-       enum port port = intel_dig_port->base.port;
-       int ret;
-       union {
-               u32 reg;
-               u8 shim[DRM_HDCP_RI_LEN];
-       } ri;
-
-       ret = intel_hdmi_hdcp_read_ri_prime(intel_dig_port, ri.shim);
-       if (ret)
-               return false;
-
-       I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg);
-
-       /* Wait for Ri prime match */
-       if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) &
-                    (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
-               DRM_ERROR("Ri' mismatch detected, link check failed (%x)\n",
-                         I915_READ(PORT_HDCP_STATUS(port)));
-               return false;
-       }
-       return true;
-}
-
-static struct hdcp2_hdmi_msg_data {
-       u8 msg_id;
-       u32 timeout;
-       u32 timeout2;
-       } hdcp2_msg_data[] = {
-               {HDCP_2_2_AKE_INIT, 0, 0},
-               {HDCP_2_2_AKE_SEND_CERT, HDCP_2_2_CERT_TIMEOUT_MS, 0},
-               {HDCP_2_2_AKE_NO_STORED_KM, 0, 0},
-               {HDCP_2_2_AKE_STORED_KM, 0, 0},
-               {HDCP_2_2_AKE_SEND_HPRIME, HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS,
-                               HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS},
-               {HDCP_2_2_AKE_SEND_PAIRING_INFO, HDCP_2_2_PAIRING_TIMEOUT_MS,
-                               0},
-               {HDCP_2_2_LC_INIT, 0, 0},
-               {HDCP_2_2_LC_SEND_LPRIME, HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS, 0},
-               {HDCP_2_2_SKE_SEND_EKS, 0, 0},
-               {HDCP_2_2_REP_SEND_RECVID_LIST,
-                               HDCP_2_2_RECVID_LIST_TIMEOUT_MS, 0},
-               {HDCP_2_2_REP_SEND_ACK, 0, 0},
-               {HDCP_2_2_REP_STREAM_MANAGE, 0, 0},
-               {HDCP_2_2_REP_STREAM_READY, HDCP_2_2_STREAM_READY_TIMEOUT_MS,
-                               0},
-       };
-
-static
-int intel_hdmi_hdcp2_read_rx_status(struct intel_digital_port *intel_dig_port,
-                                   u8 *rx_status)
-{
-       return intel_hdmi_hdcp_read(intel_dig_port,
-                                   HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET,
-                                   rx_status,
-                                   HDCP_2_2_HDMI_RXSTATUS_LEN);
-}
-
-static int get_hdcp2_msg_timeout(u8 msg_id, bool is_paired)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hdcp2_msg_data); i++)
-               if (hdcp2_msg_data[i].msg_id == msg_id &&
-                   (msg_id != HDCP_2_2_AKE_SEND_HPRIME || is_paired))
-                       return hdcp2_msg_data[i].timeout;
-               else if (hdcp2_msg_data[i].msg_id == msg_id)
-                       return hdcp2_msg_data[i].timeout2;
-
-       return -EINVAL;
-}
-
-static inline
-int hdcp2_detect_msg_availability(struct intel_digital_port *intel_digital_port,
-                                 u8 msg_id, bool *msg_ready,
-                                 ssize_t *msg_sz)
-{
-       u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
-       int ret;
-
-       ret = intel_hdmi_hdcp2_read_rx_status(intel_digital_port, rx_status);
-       if (ret < 0) {
-               DRM_DEBUG_KMS("rx_status read failed. Err %d\n", ret);
-               return ret;
-       }
-
-       *msg_sz = ((HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(rx_status[1]) << 8) |
-                 rx_status[0]);
-
-       if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST)
-               *msg_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]) &&
-                            *msg_sz);
-       else
-               *msg_ready = *msg_sz;
-
-       return 0;
-}
-
-static ssize_t
-intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port,
-                             u8 msg_id, bool paired)
-{
-       bool msg_ready = false;
-       int timeout, ret;
-       ssize_t msg_sz = 0;
-
-       timeout = get_hdcp2_msg_timeout(msg_id, paired);
-       if (timeout < 0)
-               return timeout;
-
-       ret = __wait_for(ret = hdcp2_detect_msg_availability(intel_dig_port,
-                                                            msg_id, &msg_ready,
-                                                            &msg_sz),
-                        !ret && msg_ready && msg_sz, timeout * 1000,
-                        1000, 5 * 1000);
-       if (ret)
-               DRM_DEBUG_KMS("msg_id: %d, ret: %d, timeout: %d\n",
-                             msg_id, ret, timeout);
-
-       return ret ? ret : msg_sz;
-}
-
-static
-int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *intel_dig_port,
-                              void *buf, size_t size)
-{
-       unsigned int offset;
-
-       offset = HDCP_2_2_HDMI_REG_WR_MSG_OFFSET;
-       return intel_hdmi_hdcp_write(intel_dig_port, offset, buf, size);
-}
-
-static
-int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *intel_dig_port,
-                             u8 msg_id, void *buf, size_t size)
-{
-       struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
-       struct intel_hdcp *hdcp = &hdmi->attached_connector->hdcp;
-       unsigned int offset;
-       ssize_t ret;
-
-       ret = intel_hdmi_hdcp2_wait_for_msg(intel_dig_port, msg_id,
-                                           hdcp->is_paired);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Available msg size should be equal to or lesser than the
-        * available buffer.
-        */
-       if (ret > size) {
-               DRM_DEBUG_KMS("msg_sz(%zd) is more than exp size(%zu)\n",
-                             ret, size);
-               return -1;
-       }
-
-       offset = HDCP_2_2_HDMI_REG_RD_MSG_OFFSET;
-       ret = intel_hdmi_hdcp_read(intel_dig_port, offset, buf, ret);
-       if (ret)
-               DRM_DEBUG_KMS("Failed to read msg_id: %d(%zd)\n", msg_id, ret);
-
-       return ret;
-}
-
-static
-int intel_hdmi_hdcp2_check_link(struct intel_digital_port *intel_dig_port)
-{
-       u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
-       int ret;
-
-       ret = intel_hdmi_hdcp2_read_rx_status(intel_dig_port, rx_status);
-       if (ret)
-               return ret;
-
-       /*
-        * Re-auth request and Link Integrity Failures are represented by
-        * same bit. i.e reauth_req.
-        */
-       if (HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(rx_status[1]))
-               ret = HDCP_REAUTH_REQUEST;
-       else if (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]))
-               ret = HDCP_TOPOLOGY_CHANGE;
-
-       return ret;
-}
-
-static
-int intel_hdmi_hdcp2_capable(struct intel_digital_port *intel_dig_port,
-                            bool *capable)
-{
-       u8 hdcp2_version;
-       int ret;
-
-       *capable = false;
-       ret = intel_hdmi_hdcp_read(intel_dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
-                                  &hdcp2_version, sizeof(hdcp2_version));
-       if (!ret && hdcp2_version & HDCP_2_2_HDMI_SUPPORT_MASK)
-               *capable = true;
-
-       return ret;
-}
-
-static inline
-enum hdcp_wired_protocol intel_hdmi_hdcp2_protocol(void)
-{
-       return HDCP_PROTOCOL_HDMI;
-}
-
-static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
-       .write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
-       .read_bksv = intel_hdmi_hdcp_read_bksv,
-       .read_bstatus = intel_hdmi_hdcp_read_bstatus,
-       .repeater_present = intel_hdmi_hdcp_repeater_present,
-       .read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
-       .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
-       .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
-       .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
-       .toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
-       .check_link = intel_hdmi_hdcp_check_link,
-       .write_2_2_msg = intel_hdmi_hdcp2_write_msg,
-       .read_2_2_msg = intel_hdmi_hdcp2_read_msg,
-       .check_2_2_link = intel_hdmi_hdcp2_check_link,
-       .hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
-       .protocol = HDCP_PROTOCOL_HDMI,
-};
-
-static void intel_hdmi_prepare(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *crtc_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
-       u32 hdmi_val;
-
-       intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
-
-       hdmi_val = SDVO_ENCODING_HDMI;
-       if (!HAS_PCH_SPLIT(dev_priv) && crtc_state->limited_color_range)
-               hdmi_val |= HDMI_COLOR_RANGE_16_235;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-               hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-               hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
-
-       if (crtc_state->pipe_bpp > 24)
-               hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
-       else
-               hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
-
-       if (crtc_state->has_hdmi_sink)
-               hdmi_val |= HDMI_MODE_SELECT_HDMI;
-
-       if (HAS_PCH_CPT(dev_priv))
-               hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe);
-       else if (IS_CHERRYVIEW(dev_priv))
-               hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe);
-       else
-               hdmi_val |= SDVO_PIPE_SEL(crtc->pipe);
-
-       I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
-       POSTING_READ(intel_hdmi->hdmi_reg);
-}
-
-static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
-                                   enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       intel_wakeref_t wakeref;
-       bool ret;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       ret = intel_sdvo_port_enabled(dev_priv, intel_hdmi->hdmi_reg, pipe);
-
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-
-       return ret;
-}
-
-static void intel_hdmi_get_config(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *pipe_config)
-{
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 tmp, flags = 0;
-       int dotclock;
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI);
-
-       tmp = I915_READ(intel_hdmi->hdmi_reg);
-
-       if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NHSYNC;
-
-       if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
-               flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NVSYNC;
-
-       if (tmp & HDMI_MODE_SELECT_HDMI)
-               pipe_config->has_hdmi_sink = true;
-
-       pipe_config->infoframes.enable |=
-               intel_hdmi_infoframes_enabled(encoder, pipe_config);
-
-       if (pipe_config->infoframes.enable)
-               pipe_config->has_infoframe = true;
-
-       if (tmp & HDMI_AUDIO_ENABLE)
-               pipe_config->has_audio = true;
-
-       if (!HAS_PCH_SPLIT(dev_priv) &&
-           tmp & HDMI_COLOR_RANGE_16_235)
-               pipe_config->limited_color_range = true;
-
-       pipe_config->base.adjusted_mode.flags |= flags;
-
-       if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
-               dotclock = pipe_config->port_clock * 2 / 3;
-       else
-               dotclock = pipe_config->port_clock;
-
-       if (pipe_config->pixel_multiplier)
-               dotclock /= pipe_config->pixel_multiplier;
-
-       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
-
-       pipe_config->lane_count = 4;
-
-       intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
-
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_AVI,
-                            &pipe_config->infoframes.avi);
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_SPD,
-                            &pipe_config->infoframes.spd);
-       intel_read_infoframe(encoder, pipe_config,
-                            HDMI_INFOFRAME_TYPE_VENDOR,
-                            &pipe_config->infoframes.hdmi);
-}
-
-static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
-                                   const struct intel_crtc_state *pipe_config,
-                                   const struct drm_connector_state *conn_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-
-       WARN_ON(!pipe_config->has_hdmi_sink);
-       DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
-                        pipe_name(crtc->pipe));
-       intel_audio_codec_enable(encoder, pipe_config, conn_state);
-}
-
-static void g4x_enable_hdmi(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *pipe_config,
-                           const struct drm_connector_state *conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       u32 temp;
-
-       temp = I915_READ(intel_hdmi->hdmi_reg);
-
-       temp |= SDVO_ENABLE;
-       if (pipe_config->has_audio)
-               temp |= HDMI_AUDIO_ENABLE;
-
-       I915_WRITE(intel_hdmi->hdmi_reg, temp);
-       POSTING_READ(intel_hdmi->hdmi_reg);
-
-       if (pipe_config->has_audio)
-               intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
-}
-
-static void ibx_enable_hdmi(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *pipe_config,
-                           const struct drm_connector_state *conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       u32 temp;
-
-       temp = I915_READ(intel_hdmi->hdmi_reg);
-
-       temp |= SDVO_ENABLE;
-       if (pipe_config->has_audio)
-               temp |= HDMI_AUDIO_ENABLE;
-
-       /*
-        * HW workaround, need to write this twice for issue
-        * that may result in first write getting masked.
-        */
-       I915_WRITE(intel_hdmi->hdmi_reg, temp);
-       POSTING_READ(intel_hdmi->hdmi_reg);
-       I915_WRITE(intel_hdmi->hdmi_reg, temp);
-       POSTING_READ(intel_hdmi->hdmi_reg);
-
-       /*
-        * HW workaround, need to toggle enable bit off and on
-        * for 12bpc with pixel repeat.
-        *
-        * FIXME: BSpec says this should be done at the end of
-        * of the modeset sequence, so not sure if this isn't too soon.
-        */
-       if (pipe_config->pipe_bpp > 24 &&
-           pipe_config->pixel_multiplier > 1) {
-               I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-
-               /*
-                * HW workaround, need to write this twice for issue
-                * that may result in first write getting masked.
-                */
-               I915_WRITE(intel_hdmi->hdmi_reg, temp);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-               I915_WRITE(intel_hdmi->hdmi_reg, temp);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-       }
-
-       if (pipe_config->has_audio)
-               intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
-}
-
-static void cpt_enable_hdmi(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *pipe_config,
-                           const struct drm_connector_state *conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       enum pipe pipe = crtc->pipe;
-       u32 temp;
-
-       temp = I915_READ(intel_hdmi->hdmi_reg);
-
-       temp |= SDVO_ENABLE;
-       if (pipe_config->has_audio)
-               temp |= HDMI_AUDIO_ENABLE;
-
-       /*
-        * WaEnableHDMI8bpcBefore12bpc:snb,ivb
-        *
-        * The procedure for 12bpc is as follows:
-        * 1. disable HDMI clock gating
-        * 2. enable HDMI with 8bpc
-        * 3. enable HDMI with 12bpc
-        * 4. enable HDMI clock gating
-        */
-
-       if (pipe_config->pipe_bpp > 24) {
-               I915_WRITE(TRANS_CHICKEN1(pipe),
-                          I915_READ(TRANS_CHICKEN1(pipe)) |
-                          TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
-
-               temp &= ~SDVO_COLOR_FORMAT_MASK;
-               temp |= SDVO_COLOR_FORMAT_8bpc;
-       }
-
-       I915_WRITE(intel_hdmi->hdmi_reg, temp);
-       POSTING_READ(intel_hdmi->hdmi_reg);
-
-       if (pipe_config->pipe_bpp > 24) {
-               temp &= ~SDVO_COLOR_FORMAT_MASK;
-               temp |= HDMI_COLOR_FORMAT_12bpc;
-
-               I915_WRITE(intel_hdmi->hdmi_reg, temp);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-
-               I915_WRITE(TRANS_CHICKEN1(pipe),
-                          I915_READ(TRANS_CHICKEN1(pipe)) &
-                          ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
-       }
-
-       if (pipe_config->has_audio)
-               intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
-}
-
-static void vlv_enable_hdmi(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *pipe_config,
-                           const struct drm_connector_state *conn_state)
-{
-}
-
-static void intel_disable_hdmi(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *old_crtc_state,
-                              const struct drm_connector_state *old_conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       struct intel_digital_port *intel_dig_port =
-               hdmi_to_dig_port(intel_hdmi);
-       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
-       u32 temp;
-
-       temp = I915_READ(intel_hdmi->hdmi_reg);
-
-       temp &= ~(SDVO_ENABLE | HDMI_AUDIO_ENABLE);
-       I915_WRITE(intel_hdmi->hdmi_reg, temp);
-       POSTING_READ(intel_hdmi->hdmi_reg);
-
-       /*
-        * HW workaround for IBX, we need to move the port
-        * to transcoder A after disabling it to allow the
-        * matching DP port to be enabled on transcoder A.
-        */
-       if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
-               /*
-                * We get CPU/PCH FIFO underruns on the other pipe when
-                * doing the workaround. Sweep them under the rug.
-                */
-               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-
-               temp &= ~SDVO_PIPE_SEL_MASK;
-               temp |= SDVO_ENABLE | SDVO_PIPE_SEL(PIPE_A);
-               /*
-                * HW workaround, need to write this twice for issue
-                * that may result in first write getting masked.
-                */
-               I915_WRITE(intel_hdmi->hdmi_reg, temp);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-               I915_WRITE(intel_hdmi->hdmi_reg, temp);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-
-               temp &= ~SDVO_ENABLE;
-               I915_WRITE(intel_hdmi->hdmi_reg, temp);
-               POSTING_READ(intel_hdmi->hdmi_reg);
-
-               intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
-               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-       }
-
-       intel_dig_port->set_infoframes(encoder,
-                                      false,
-                                      old_crtc_state, old_conn_state);
-
-       intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
-}
-
-static void g4x_disable_hdmi(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *old_crtc_state,
-                            const struct drm_connector_state *old_conn_state)
-{
-       if (old_crtc_state->has_audio)
-               intel_audio_codec_disable(encoder,
-                                         old_crtc_state, old_conn_state);
-
-       intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
-}
-
-static void pch_disable_hdmi(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *old_crtc_state,
-                            const struct drm_connector_state *old_conn_state)
-{
-       if (old_crtc_state->has_audio)
-               intel_audio_codec_disable(encoder,
-                                         old_crtc_state, old_conn_state);
-}
-
-static void pch_post_disable_hdmi(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *old_crtc_state,
-                                 const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
-}
-
-static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       const struct ddi_vbt_port_info *info =
-               &dev_priv->vbt.ddi_port_info[encoder->port];
-       int max_tmds_clock;
-
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               max_tmds_clock = 594000;
-       else if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv))
-               max_tmds_clock = 300000;
-       else if (INTEL_GEN(dev_priv) >= 5)
-               max_tmds_clock = 225000;
-       else
-               max_tmds_clock = 165000;
-
-       if (info->max_tmds_clock)
-               max_tmds_clock = min(max_tmds_clock, info->max_tmds_clock);
-
-       return max_tmds_clock;
-}
-
-static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
-                                bool respect_downstream_limits,
-                                bool force_dvi)
-{
-       struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base;
-       int max_tmds_clock = intel_hdmi_source_max_tmds_clock(encoder);
-
-       if (respect_downstream_limits) {
-               struct intel_connector *connector = hdmi->attached_connector;
-               const struct drm_display_info *info = &connector->base.display_info;
-
-               if (hdmi->dp_dual_mode.max_tmds_clock)
-                       max_tmds_clock = min(max_tmds_clock,
-                                            hdmi->dp_dual_mode.max_tmds_clock);
-
-               if (info->max_tmds_clock)
-                       max_tmds_clock = min(max_tmds_clock,
-                                            info->max_tmds_clock);
-               else if (!hdmi->has_hdmi_sink || force_dvi)
-                       max_tmds_clock = min(max_tmds_clock, 165000);
-       }
-
-       return max_tmds_clock;
-}
-
-static enum drm_mode_status
-hdmi_port_clock_valid(struct intel_hdmi *hdmi,
-                     int clock, bool respect_downstream_limits,
-                     bool force_dvi)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
-
-       if (clock < 25000)
-               return MODE_CLOCK_LOW;
-       if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits, force_dvi))
-               return MODE_CLOCK_HIGH;
-
-       /* BXT DPLL can't generate 223-240 MHz */
-       if (IS_GEN9_LP(dev_priv) && clock > 223333 && clock < 240000)
-               return MODE_CLOCK_RANGE;
-
-       /* CHV DPLL can't generate 216-240 MHz */
-       if (IS_CHERRYVIEW(dev_priv) && clock > 216000 && clock < 240000)
-               return MODE_CLOCK_RANGE;
-
-       return MODE_OK;
-}
-
-static enum drm_mode_status
-intel_hdmi_mode_valid(struct drm_connector *connector,
-                     struct drm_display_mode *mode)
-{
-       struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
-       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum drm_mode_status status;
-       int clock;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-       bool force_dvi =
-               READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       clock = mode->clock;
-
-       if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
-               clock *= 2;
-
-       if (clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
-               clock *= 2;
-
-       if (drm_mode_is_420_only(&connector->display_info, mode))
-               clock /= 2;
-
-       /* check if we can do 8bpc */
-       status = hdmi_port_clock_valid(hdmi, clock, true, force_dvi);
-
-       if (hdmi->has_hdmi_sink && !force_dvi) {
-               /* if we can't do 8bpc we may still be able to do 12bpc */
-               if (status != MODE_OK && !HAS_GMCH(dev_priv))
-                       status = hdmi_port_clock_valid(hdmi, clock * 3 / 2,
-                                                      true, force_dvi);
-
-               /* if we can't do 8,12bpc we may still be able to do 10bpc */
-               if (status != MODE_OK && INTEL_GEN(dev_priv) >= 11)
-                       status = hdmi_port_clock_valid(hdmi, clock * 5 / 4,
-                                                      true, force_dvi);
-       }
-
-       return status;
-}
-
-static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
-                                    int bpc)
-{
-       struct drm_i915_private *dev_priv =
-               to_i915(crtc_state->base.crtc->dev);
-       struct drm_atomic_state *state = crtc_state->base.state;
-       struct drm_connector_state *connector_state;
-       struct drm_connector *connector;
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       int i;
-
-       if (HAS_GMCH(dev_priv))
-               return false;
-
-       if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
-               return false;
-
-       if (crtc_state->pipe_bpp < bpc * 3)
-               return false;
-
-       if (!crtc_state->has_hdmi_sink)
-               return false;
-
-       /*
-        * HDMI deep color affects the clocks, so it's only possible
-        * when not cloning with other encoder types.
-        */
-       if (crtc_state->output_types != 1 << INTEL_OUTPUT_HDMI)
-               return false;
-
-       for_each_new_connector_in_state(state, connector, connector_state, i) {
-               const struct drm_display_info *info = &connector->display_info;
-
-               if (connector_state->crtc != crtc_state->base.crtc)
-                       continue;
-
-               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
-                       const struct drm_hdmi_info *hdmi = &info->hdmi;
-
-                       if (bpc == 12 && !(hdmi->y420_dc_modes &
-                                          DRM_EDID_YCBCR420_DC_36))
-                               return false;
-                       else if (bpc == 10 && !(hdmi->y420_dc_modes &
-                                               DRM_EDID_YCBCR420_DC_30))
-                               return false;
-               } else {
-                       if (bpc == 12 && !(info->edid_hdmi_dc_modes &
-                                          DRM_EDID_HDMI_DC_36))
-                               return false;
-                       else if (bpc == 10 && !(info->edid_hdmi_dc_modes &
-                                               DRM_EDID_HDMI_DC_30))
-                               return false;
-               }
-       }
-
-       /* Display WA #1139: glk */
-       if (bpc == 12 && IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) &&
-           adjusted_mode->htotal > 5460)
-               return false;
-
-       /* Display Wa_1405510057:icl */
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
-           bpc == 10 && INTEL_GEN(dev_priv) >= 11 &&
-           (adjusted_mode->crtc_hblank_end -
-            adjusted_mode->crtc_hblank_start) % 8 == 2)
-               return false;
-
-       return true;
-}
-
-static bool
-intel_hdmi_ycbcr420_config(struct drm_connector *connector,
-                          struct intel_crtc_state *config,
-                          int *clock_12bpc, int *clock_10bpc,
-                          int *clock_8bpc)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(config->base.crtc);
-
-       if (!connector->ycbcr_420_allowed) {
-               DRM_ERROR("Platform doesn't support YCBCR420 output\n");
-               return false;
-       }
-
-       /* YCBCR420 TMDS rate requirement is half the pixel clock */
-       config->port_clock /= 2;
-       *clock_12bpc /= 2;
-       *clock_10bpc /= 2;
-       *clock_8bpc /= 2;
-       config->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
-
-       /* YCBCR 420 output conversion needs a scaler */
-       if (skl_update_scaler_crtc(config)) {
-               DRM_DEBUG_KMS("Scaler allocation for output failed\n");
-               return false;
-       }
-
-       intel_pch_panel_fitting(intel_crtc, config,
-                               DRM_MODE_SCALE_FULLSCREEN);
-
-       return true;
-}
-
-int intel_hdmi_compute_config(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config,
-                             struct drm_connector_state *conn_state)
-{
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct drm_connector *connector = conn_state->connector;
-       struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
-       struct intel_digital_connector_state *intel_conn_state =
-               to_intel_digital_connector_state(conn_state);
-       int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
-       int clock_10bpc = clock_8bpc * 5 / 4;
-       int clock_12bpc = clock_8bpc * 3 / 2;
-       int desired_bpp;
-       bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-       pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
-
-       if (pipe_config->has_hdmi_sink)
-               pipe_config->has_infoframe = true;
-
-       if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
-               /* See CEA-861-E - 5.1 Default Encoding Parameters */
-               pipe_config->limited_color_range =
-                       pipe_config->has_hdmi_sink &&
-                       drm_default_rgb_quant_range(adjusted_mode) ==
-                       HDMI_QUANTIZATION_RANGE_LIMITED;
-       } else {
-               pipe_config->limited_color_range =
-                       intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED;
-       }
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
-               pipe_config->pixel_multiplier = 2;
-               clock_8bpc *= 2;
-               clock_10bpc *= 2;
-               clock_12bpc *= 2;
-       }
-
-       if (drm_mode_is_420_only(&connector->display_info, adjusted_mode)) {
-               if (!intel_hdmi_ycbcr420_config(connector, pipe_config,
-                                               &clock_12bpc, &clock_10bpc,
-                                               &clock_8bpc)) {
-                       DRM_ERROR("Can't support YCBCR420 output\n");
-                       return -EINVAL;
-               }
-       }
-
-       if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv))
-               pipe_config->has_pch_encoder = true;
-
-       if (pipe_config->has_hdmi_sink) {
-               if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
-                       pipe_config->has_audio = intel_hdmi->has_audio;
-               else
-                       pipe_config->has_audio =
-                               intel_conn_state->force_audio == HDMI_AUDIO_ON;
-       }
-
-       /*
-        * Note that g4x/vlv don't support 12bpc hdmi outputs. We also need
-        * to check that the higher clock still fits within limits.
-        */
-       if (hdmi_deep_color_possible(pipe_config, 12) &&
-           hdmi_port_clock_valid(intel_hdmi, clock_12bpc,
-                                 true, force_dvi) == MODE_OK) {
-               DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
-               desired_bpp = 12*3;
-
-               /* Need to adjust the port link by 1.5x for 12bpc. */
-               pipe_config->port_clock = clock_12bpc;
-       } else if (hdmi_deep_color_possible(pipe_config, 10) &&
-                  hdmi_port_clock_valid(intel_hdmi, clock_10bpc,
-                                        true, force_dvi) == MODE_OK) {
-               DRM_DEBUG_KMS("picking bpc to 10 for HDMI output\n");
-               desired_bpp = 10 * 3;
-
-               /* Need to adjust the port link by 1.25x for 10bpc. */
-               pipe_config->port_clock = clock_10bpc;
-       } else {
-               DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
-               desired_bpp = 8*3;
-
-               pipe_config->port_clock = clock_8bpc;
-       }
-
-       if (!pipe_config->bw_constrained) {
-               DRM_DEBUG_KMS("forcing pipe bpp to %i for HDMI\n", desired_bpp);
-               pipe_config->pipe_bpp = desired_bpp;
-       }
-
-       if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
-                                 false, force_dvi) != MODE_OK) {
-               DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
-               return -EINVAL;
-       }
-
-       /* Set user selected PAR to incoming mode's member */
-       adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
-
-       pipe_config->lane_count = 4;
-
-       if (scdc->scrambling.supported && (INTEL_GEN(dev_priv) >= 10 ||
-                                          IS_GEMINILAKE(dev_priv))) {
-               if (scdc->scrambling.low_rates)
-                       pipe_config->hdmi_scrambling = true;
-
-               if (pipe_config->port_clock > 340000) {
-                       pipe_config->hdmi_scrambling = true;
-                       pipe_config->hdmi_high_tmds_clock_ratio = true;
-               }
-       }
-
-       intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, conn_state);
-
-       if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) {
-               DRM_DEBUG_KMS("bad AVI infoframe\n");
-               return -EINVAL;
-       }
-
-       if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) {
-               DRM_DEBUG_KMS("bad SPD infoframe\n");
-               return -EINVAL;
-       }
-
-       if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) {
-               DRM_DEBUG_KMS("bad HDMI infoframe\n");
-               return -EINVAL;
-       }
-
-       if (!intel_hdmi_compute_drm_infoframe(encoder, pipe_config, conn_state)) {
-               DRM_DEBUG_KMS("bad DRM infoframe\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void
-intel_hdmi_unset_edid(struct drm_connector *connector)
-{
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-
-       intel_hdmi->has_hdmi_sink = false;
-       intel_hdmi->has_audio = false;
-
-       intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
-       intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
-
-       kfree(to_intel_connector(connector)->detect_edid);
-       to_intel_connector(connector)->detect_edid = NULL;
-}
-
-static void
-intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
-       enum port port = hdmi_to_dig_port(hdmi)->base.port;
-       struct i2c_adapter *adapter =
-               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
-       enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(adapter);
-
-       /*
-        * Type 1 DVI adaptors are not required to implement any
-        * registers, so we can't always detect their presence.
-        * Ideally we should be able to check the state of the
-        * CONFIG1 pin, but no such luck on our hardware.
-        *
-        * The only method left to us is to check the VBT to see
-        * if the port is a dual mode capable DP port. But let's
-        * only do that when we sucesfully read the EDID, to avoid
-        * confusing log messages about DP dual mode adaptors when
-        * there's nothing connected to the port.
-        */
-       if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
-               /* An overridden EDID imply that we want this port for testing.
-                * Make sure not to set limits for that port.
-                */
-               if (has_edid && !connector->override_edid &&
-                   intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
-                       DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n");
-                       type = DRM_DP_DUAL_MODE_TYPE1_DVI;
-               } else {
-                       type = DRM_DP_DUAL_MODE_NONE;
-               }
-       }
-
-       if (type == DRM_DP_DUAL_MODE_NONE)
-               return;
-
-       hdmi->dp_dual_mode.type = type;
-       hdmi->dp_dual_mode.max_tmds_clock =
-               drm_dp_dual_mode_max_tmds_clock(type, adapter);
-
-       DRM_DEBUG_KMS("DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n",
-                     drm_dp_get_dual_mode_type_name(type),
-                     hdmi->dp_dual_mode.max_tmds_clock);
-}
-
-static bool
-intel_hdmi_set_edid(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       intel_wakeref_t wakeref;
-       struct edid *edid;
-       bool connected = false;
-       struct i2c_adapter *i2c;
-
-       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
-
-       i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
-
-       edid = drm_get_edid(connector, i2c);
-
-       if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
-               DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
-               intel_gmbus_force_bit(i2c, true);
-               edid = drm_get_edid(connector, i2c);
-               intel_gmbus_force_bit(i2c, false);
-       }
-
-       intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
-
-       to_intel_connector(connector)->detect_edid = edid;
-       if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
-               intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
-               intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
-
-               connected = true;
-       }
-
-       cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid);
-
-       return connected;
-}
-
-static enum drm_connector_status
-intel_hdmi_detect(struct drm_connector *connector, bool force)
-{
-       enum drm_connector_status status = connector_status_disconnected;
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base;
-       intel_wakeref_t wakeref;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
-
-       if (INTEL_GEN(dev_priv) >= 11 &&
-           !intel_digital_port_connected(encoder))
-               goto out;
-
-       intel_hdmi_unset_edid(connector);
-
-       if (intel_hdmi_set_edid(connector))
-               status = connector_status_connected;
-
-out:
-       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
-
-       if (status != connector_status_connected)
-               cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier);
-
-       return status;
-}
-
-static void
-intel_hdmi_force(struct drm_connector *connector)
-{
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       intel_hdmi_unset_edid(connector);
-
-       if (connector->status != connector_status_connected)
-               return;
-
-       intel_hdmi_set_edid(connector);
-}
-
-static int intel_hdmi_get_modes(struct drm_connector *connector)
-{
-       struct edid *edid;
-
-       edid = to_intel_connector(connector)->detect_edid;
-       if (edid == NULL)
-               return 0;
-
-       return intel_connector_update_modes(connector, edid);
-}
-
-static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_digital_port *intel_dig_port =
-               enc_to_dig_port(&encoder->base);
-
-       intel_hdmi_prepare(encoder, pipe_config);
-
-       intel_dig_port->set_infoframes(encoder,
-                                      pipe_config->has_infoframe,
-                                      pipe_config, conn_state);
-}
-
-static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *pipe_config,
-                               const struct drm_connector_state *conn_state)
-{
-       struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       vlv_phy_pre_encoder_enable(encoder, pipe_config);
-
-       /* HDMI 1.0V-2dB */
-       vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
-                                0x2b247878);
-
-       dport->set_infoframes(encoder,
-                             pipe_config->has_infoframe,
-                             pipe_config, conn_state);
-
-       g4x_enable_hdmi(encoder, pipe_config, conn_state);
-
-       vlv_wait_port_ready(dev_priv, dport, 0x0);
-}
-
-static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
-                                   const struct intel_crtc_state *pipe_config,
-                                   const struct drm_connector_state *conn_state)
-{
-       intel_hdmi_prepare(encoder, pipe_config);
-
-       vlv_phy_pre_pll_enable(encoder, pipe_config);
-}
-
-static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
-                                   const struct intel_crtc_state *pipe_config,
-                                   const struct drm_connector_state *conn_state)
-{
-       intel_hdmi_prepare(encoder, pipe_config);
-
-       chv_phy_pre_pll_enable(encoder, pipe_config);
-}
-
-static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder,
-                                     const struct intel_crtc_state *old_crtc_state,
-                                     const struct drm_connector_state *old_conn_state)
-{
-       chv_phy_post_pll_disable(encoder, old_crtc_state);
-}
-
-static void vlv_hdmi_post_disable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *old_crtc_state,
-                                 const struct drm_connector_state *old_conn_state)
-{
-       /* Reset lanes to avoid HDMI flicker (VLV w/a) */
-       vlv_phy_reset_lanes(encoder, old_crtc_state);
-}
-
-static void chv_hdmi_post_disable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *old_crtc_state,
-                                 const struct drm_connector_state *old_conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       vlv_dpio_get(dev_priv);
-
-       /* Assert data lane reset */
-       chv_data_lane_soft_reset(encoder, old_crtc_state, true);
-
-       vlv_dpio_put(dev_priv);
-}
-
-static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *pipe_config,
-                               const struct drm_connector_state *conn_state)
-{
-       struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       chv_phy_pre_encoder_enable(encoder, pipe_config);
-
-       /* FIXME: Program the support xxx V-dB */
-       /* Use 800mV-0dB */
-       chv_set_phy_signal_level(encoder, 128, 102, false);
-
-       dport->set_infoframes(encoder,
-                             pipe_config->has_infoframe,
-                             pipe_config, conn_state);
-
-       g4x_enable_hdmi(encoder, pipe_config, conn_state);
-
-       vlv_wait_port_ready(dev_priv, dport, 0x0);
-
-       /* Second common lane will stay alive on its own now */
-       chv_phy_release_cl2_override(encoder);
-}
-
-static struct i2c_adapter *
-intel_hdmi_get_i2c_adapter(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-
-       return intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
-}
-
-static void intel_hdmi_create_i2c_symlink(struct drm_connector *connector)
-{
-       struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector);
-       struct kobject *i2c_kobj = &adapter->dev.kobj;
-       struct kobject *connector_kobj = &connector->kdev->kobj;
-       int ret;
-
-       ret = sysfs_create_link(connector_kobj, i2c_kobj, i2c_kobj->name);
-       if (ret)
-               DRM_ERROR("Failed to create i2c symlink (%d)\n", ret);
-}
-
-static void intel_hdmi_remove_i2c_symlink(struct drm_connector *connector)
-{
-       struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector);
-       struct kobject *i2c_kobj = &adapter->dev.kobj;
-       struct kobject *connector_kobj = &connector->kdev->kobj;
-
-       sysfs_remove_link(connector_kobj, i2c_kobj->name);
-}
-
-static int
-intel_hdmi_connector_register(struct drm_connector *connector)
-{
-       int ret;
-
-       ret = intel_connector_register(connector);
-       if (ret)
-               return ret;
-
-       i915_debugfs_connector_add(connector);
-
-       intel_hdmi_create_i2c_symlink(connector);
-
-       return ret;
-}
-
-static void intel_hdmi_destroy(struct drm_connector *connector)
-{
-       if (intel_attached_hdmi(connector)->cec_notifier)
-               cec_notifier_put(intel_attached_hdmi(connector)->cec_notifier);
-
-       intel_connector_destroy(connector);
-}
-
-static void intel_hdmi_connector_unregister(struct drm_connector *connector)
-{
-       intel_hdmi_remove_i2c_symlink(connector);
-
-       intel_connector_unregister(connector);
-}
-
-static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
-       .detect = intel_hdmi_detect,
-       .force = intel_hdmi_force,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .late_register = intel_hdmi_connector_register,
-       .early_unregister = intel_hdmi_connector_unregister,
-       .destroy = intel_hdmi_destroy,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
-       .get_modes = intel_hdmi_get_modes,
-       .mode_valid = intel_hdmi_mode_valid,
-       .atomic_check = intel_digital_connector_atomic_check,
-};
-
-static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
-       .destroy = intel_encoder_destroy,
-};
-
-static void
-intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_digital_port *intel_dig_port =
-                               hdmi_to_dig_port(intel_hdmi);
-
-       intel_attach_force_audio_property(connector);
-       intel_attach_broadcast_rgb_property(connector);
-       intel_attach_aspect_ratio_property(connector);
-
-       /*
-        * Attach Colorspace property for Non LSPCON based device
-        * ToDo: This needs to be extended for LSPCON implementation
-        * as well. Will be implemented separately.
-        */
-       if (!intel_dig_port->lspcon.active)
-               intel_attach_colorspace_property(connector);
-
-       drm_connector_attach_content_type_property(connector);
-       connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
-
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               drm_object_attach_property(&connector->base,
-                       connector->dev->mode_config.hdr_output_metadata_property, 0);
-
-       if (!HAS_GMCH(dev_priv))
-               drm_connector_attach_max_bpc_property(connector, 8, 12);
-}
-
-/*
- * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup
- * @encoder: intel_encoder
- * @connector: drm_connector
- * @high_tmds_clock_ratio = bool to indicate if the function needs to set
- *  or reset the high tmds clock ratio for scrambling
- * @scrambling: bool to Indicate if the function needs to set or reset
- *  sink scrambling
- *
- * This function handles scrambling on HDMI 2.0 capable sinks.
- * If required clock rate is > 340 Mhz && scrambling is supported by sink
- * it enables scrambling. This should be called before enabling the HDMI
- * 2.0 port, as the sink can choose to disable the scrambling if it doesn't
- * detect a scrambled clock within 100 ms.
- *
- * Returns:
- * True on success, false on failure.
- */
-bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
-                                      struct drm_connector *connector,
-                                      bool high_tmds_clock_ratio,
-                                      bool scrambling)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-       struct drm_scrambling *sink_scrambling =
-               &connector->display_info.hdmi.scdc.scrambling;
-       struct i2c_adapter *adapter =
-               intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
-
-       if (!sink_scrambling->supported)
-               return true;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n",
-                     connector->base.id, connector->name,
-                     yesno(scrambling), high_tmds_clock_ratio ? 40 : 10);
-
-       /* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */
-       return drm_scdc_set_high_tmds_clock_ratio(adapter,
-                                                 high_tmds_clock_ratio) &&
-               drm_scdc_set_scrambling(adapter, scrambling);
-}
-
-static u8 chv_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
-{
-       u8 ddc_pin;
-
-       switch (port) {
-       case PORT_B:
-               ddc_pin = GMBUS_PIN_DPB;
-               break;
-       case PORT_C:
-               ddc_pin = GMBUS_PIN_DPC;
-               break;
-       case PORT_D:
-               ddc_pin = GMBUS_PIN_DPD_CHV;
-               break;
-       default:
-               MISSING_CASE(port);
-               ddc_pin = GMBUS_PIN_DPB;
-               break;
-       }
-       return ddc_pin;
-}
-
-static u8 bxt_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
-{
-       u8 ddc_pin;
-
-       switch (port) {
-       case PORT_B:
-               ddc_pin = GMBUS_PIN_1_BXT;
-               break;
-       case PORT_C:
-               ddc_pin = GMBUS_PIN_2_BXT;
-               break;
-       default:
-               MISSING_CASE(port);
-               ddc_pin = GMBUS_PIN_1_BXT;
-               break;
-       }
-       return ddc_pin;
-}
-
-static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv,
-                             enum port port)
-{
-       u8 ddc_pin;
-
-       switch (port) {
-       case PORT_B:
-               ddc_pin = GMBUS_PIN_1_BXT;
-               break;
-       case PORT_C:
-               ddc_pin = GMBUS_PIN_2_BXT;
-               break;
-       case PORT_D:
-               ddc_pin = GMBUS_PIN_4_CNP;
-               break;
-       case PORT_F:
-               ddc_pin = GMBUS_PIN_3_BXT;
-               break;
-       default:
-               MISSING_CASE(port);
-               ddc_pin = GMBUS_PIN_1_BXT;
-               break;
-       }
-       return ddc_pin;
-}
-
-static u8 icl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
-{
-       u8 ddc_pin;
-
-       switch (port) {
-       case PORT_A:
-               ddc_pin = GMBUS_PIN_1_BXT;
-               break;
-       case PORT_B:
-               ddc_pin = GMBUS_PIN_2_BXT;
-               break;
-       case PORT_C:
-               ddc_pin = GMBUS_PIN_9_TC1_ICP;
-               break;
-       case PORT_D:
-               ddc_pin = GMBUS_PIN_10_TC2_ICP;
-               break;
-       case PORT_E:
-               ddc_pin = GMBUS_PIN_11_TC3_ICP;
-               break;
-       case PORT_F:
-               ddc_pin = GMBUS_PIN_12_TC4_ICP;
-               break;
-       default:
-               MISSING_CASE(port);
-               ddc_pin = GMBUS_PIN_2_BXT;
-               break;
-       }
-       return ddc_pin;
-}
-
-static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv,
-                             enum port port)
-{
-       u8 ddc_pin;
-
-       switch (port) {
-       case PORT_B:
-               ddc_pin = GMBUS_PIN_DPB;
-               break;
-       case PORT_C:
-               ddc_pin = GMBUS_PIN_DPC;
-               break;
-       case PORT_D:
-               ddc_pin = GMBUS_PIN_DPD;
-               break;
-       default:
-               MISSING_CASE(port);
-               ddc_pin = GMBUS_PIN_DPB;
-               break;
-       }
-       return ddc_pin;
-}
-
-static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
-                            enum port port)
-{
-       const struct ddi_vbt_port_info *info =
-               &dev_priv->vbt.ddi_port_info[port];
-       u8 ddc_pin;
-
-       if (info->alternate_ddc_pin) {
-               DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (VBT)\n",
-                             info->alternate_ddc_pin, port_name(port));
-               return info->alternate_ddc_pin;
-       }
-
-       if (HAS_PCH_ICP(dev_priv))
-               ddc_pin = icl_port_to_ddc_pin(dev_priv, port);
-       else if (HAS_PCH_CNP(dev_priv))
-               ddc_pin = cnp_port_to_ddc_pin(dev_priv, port);
-       else if (IS_GEN9_LP(dev_priv))
-               ddc_pin = bxt_port_to_ddc_pin(dev_priv, port);
-       else if (IS_CHERRYVIEW(dev_priv))
-               ddc_pin = chv_port_to_ddc_pin(dev_priv, port);
-       else
-               ddc_pin = g4x_port_to_ddc_pin(dev_priv, port);
-
-       DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (platform default)\n",
-                     ddc_pin, port_name(port));
-
-       return ddc_pin;
-}
-
-void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
-{
-       struct drm_i915_private *dev_priv =
-               to_i915(intel_dig_port->base.base.dev);
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               intel_dig_port->write_infoframe = vlv_write_infoframe;
-               intel_dig_port->read_infoframe = vlv_read_infoframe;
-               intel_dig_port->set_infoframes = vlv_set_infoframes;
-               intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
-       } else if (IS_G4X(dev_priv)) {
-               intel_dig_port->write_infoframe = g4x_write_infoframe;
-               intel_dig_port->read_infoframe = g4x_read_infoframe;
-               intel_dig_port->set_infoframes = g4x_set_infoframes;
-               intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
-       } else if (HAS_DDI(dev_priv)) {
-               if (intel_dig_port->lspcon.active) {
-                       intel_dig_port->write_infoframe = lspcon_write_infoframe;
-                       intel_dig_port->read_infoframe = lspcon_read_infoframe;
-                       intel_dig_port->set_infoframes = lspcon_set_infoframes;
-                       intel_dig_port->infoframes_enabled = lspcon_infoframes_enabled;
-               } else {
-                       intel_dig_port->write_infoframe = hsw_write_infoframe;
-                       intel_dig_port->read_infoframe = hsw_read_infoframe;
-                       intel_dig_port->set_infoframes = hsw_set_infoframes;
-                       intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
-               }
-       } else if (HAS_PCH_IBX(dev_priv)) {
-               intel_dig_port->write_infoframe = ibx_write_infoframe;
-               intel_dig_port->read_infoframe = ibx_read_infoframe;
-               intel_dig_port->set_infoframes = ibx_set_infoframes;
-               intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
-       } else {
-               intel_dig_port->write_infoframe = cpt_write_infoframe;
-               intel_dig_port->read_infoframe = cpt_read_infoframe;
-               intel_dig_port->set_infoframes = cpt_set_infoframes;
-               intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
-       }
-}
-
-void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
-                              struct intel_connector *intel_connector)
-{
-       struct drm_connector *connector = &intel_connector->base;
-       struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct drm_device *dev = intel_encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum port port = intel_encoder->port;
-
-       DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
-                     port_name(port));
-
-       if (WARN(intel_dig_port->max_lanes < 4,
-                "Not enough lanes (%d) for HDMI on port %c\n",
-                intel_dig_port->max_lanes, port_name(port)))
-               return;
-
-       drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
-                          DRM_MODE_CONNECTOR_HDMIA);
-       drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
-
-       connector->interlace_allowed = 1;
-       connector->doublescan_allowed = 0;
-       connector->stereo_allowed = 1;
-
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               connector->ycbcr_420_allowed = true;
-
-       intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(dev_priv, port);
-
-       if (WARN_ON(port == PORT_A))
-               return;
-       intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
-
-       if (HAS_DDI(dev_priv))
-               intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
-       else
-               intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       intel_hdmi_add_properties(intel_hdmi, connector);
-
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
-       intel_hdmi->attached_connector = intel_connector;
-
-       if (is_hdcp_supported(dev_priv, port)) {
-               int ret = intel_hdcp_init(intel_connector,
-                                         &intel_hdmi_hdcp_shim);
-               if (ret)
-                       DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
-       }
-
-       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
-        * 0xd.  Failure to do so will result in spurious interrupts being
-        * generated on the port when a cable is not attached.
-        */
-       if (IS_G45(dev_priv)) {
-               u32 temp = I915_READ(PEG_BAND_GAP_DATA);
-               I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
-       }
-
-       intel_hdmi->cec_notifier = cec_notifier_get_conn(dev->dev,
-                                                        port_identifier(port));
-       if (!intel_hdmi->cec_notifier)
-               DRM_DEBUG_KMS("CEC notifier get failed\n");
-}
-
-void intel_hdmi_init(struct drm_i915_private *dev_priv,
-                    i915_reg_t hdmi_reg, enum port port)
-{
-       struct intel_digital_port *intel_dig_port;
-       struct intel_encoder *intel_encoder;
-       struct intel_connector *intel_connector;
-
-       intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
-       if (!intel_dig_port)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_dig_port);
-               return;
-       }
-
-       intel_encoder = &intel_dig_port->base;
-
-       drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
-                        &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
-                        "HDMI %c", port_name(port));
-
-       intel_encoder->hotplug = intel_encoder_hotplug;
-       intel_encoder->compute_config = intel_hdmi_compute_config;
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               intel_encoder->disable = pch_disable_hdmi;
-               intel_encoder->post_disable = pch_post_disable_hdmi;
-       } else {
-               intel_encoder->disable = g4x_disable_hdmi;
-       }
-       intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
-       intel_encoder->get_config = intel_hdmi_get_config;
-       if (IS_CHERRYVIEW(dev_priv)) {
-               intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable;
-               intel_encoder->pre_enable = chv_hdmi_pre_enable;
-               intel_encoder->enable = vlv_enable_hdmi;
-               intel_encoder->post_disable = chv_hdmi_post_disable;
-               intel_encoder->post_pll_disable = chv_hdmi_post_pll_disable;
-       } else if (IS_VALLEYVIEW(dev_priv)) {
-               intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable;
-               intel_encoder->pre_enable = vlv_hdmi_pre_enable;
-               intel_encoder->enable = vlv_enable_hdmi;
-               intel_encoder->post_disable = vlv_hdmi_post_disable;
-       } else {
-               intel_encoder->pre_enable = intel_hdmi_pre_enable;
-               if (HAS_PCH_CPT(dev_priv))
-                       intel_encoder->enable = cpt_enable_hdmi;
-               else if (HAS_PCH_IBX(dev_priv))
-                       intel_encoder->enable = ibx_enable_hdmi;
-               else
-                       intel_encoder->enable = g4x_enable_hdmi;
-       }
-
-       intel_encoder->type = INTEL_OUTPUT_HDMI;
-       intel_encoder->power_domain = intel_port_to_power_domain(port);
-       intel_encoder->port = port;
-       if (IS_CHERRYVIEW(dev_priv)) {
-               if (port == PORT_D)
-                       intel_encoder->crtc_mask = 1 << 2;
-               else
-                       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       } else {
-               intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       }
-       intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
-       /*
-        * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
-        * to work on real hardware. And since g4x can send infoframes to
-        * only one port anyway, nothing is lost by allowing it.
-        */
-       if (IS_G4X(dev_priv))
-               intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
-
-       intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
-       intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
-       intel_dig_port->max_lanes = 4;
-
-       intel_infoframe_init(intel_dig_port);
-
-       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
-       intel_hdmi_init_connector(intel_dig_port, intel_connector);
-}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.h b/drivers/gpu/drm/i915/intel_hdmi.h
deleted file mode 100644 (file)
index 106c2e0..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_HDMI_H__
-#define __INTEL_HDMI_H__
-
-#include <linux/hdmi.h>
-#include <linux/types.h>
-
-#include <drm/i915_drm.h>
-
-#include "i915_reg.h"
-
-struct drm_connector;
-struct drm_encoder;
-struct drm_i915_private;
-struct intel_connector;
-struct intel_digital_port;
-struct intel_encoder;
-struct intel_crtc_state;
-struct intel_hdmi;
-struct drm_connector_state;
-union hdmi_infoframe;
-
-void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg,
-                    enum port port);
-void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
-                              struct intel_connector *intel_connector);
-struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
-int intel_hdmi_compute_config(struct intel_encoder *encoder,
-                             struct intel_crtc_state *pipe_config,
-                             struct drm_connector_state *conn_state);
-bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
-                                      struct drm_connector *connector,
-                                      bool high_tmds_clock_ratio,
-                                      bool scrambling);
-void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
-void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
-u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state);
-u32 intel_hdmi_infoframe_enable(unsigned int type);
-void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
-                                  struct intel_crtc_state *crtc_state);
-void intel_read_infoframe(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *crtc_state,
-                         enum hdmi_infoframe_type type,
-                         union hdmi_infoframe *frame);
-
-#endif /* __INTEL_HDMI_H__ */
diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c
deleted file mode 100644 (file)
index 7028d0c..0000000
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- *
- */
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_dp_dual_mode_helper.h>
-#include <drm/drm_edid.h>
-
-#include "intel_dp.h"
-#include "intel_drv.h"
-#include "intel_lspcon.h"
-
-/* LSPCON OUI Vendor ID(signatures) */
-#define LSPCON_VENDOR_PARADE_OUI 0x001CF8
-#define LSPCON_VENDOR_MCA_OUI 0x0060AD
-
-/* AUX addresses to write MCA AVI IF */
-#define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
-#define LSPCON_MCA_AVI_IF_CTRL 0x5DF
-#define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
-#define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
-
-/* AUX addresses to write Parade AVI IF */
-#define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
-#define LSPCON_PARADE_AVI_IF_CTRL 0x51E
-#define  LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
-#define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
-
-static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
-{
-       struct intel_digital_port *dig_port =
-               container_of(lspcon, struct intel_digital_port, lspcon);
-
-       return &dig_port->dp;
-}
-
-static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
-{
-       switch (mode) {
-       case DRM_LSPCON_MODE_PCON:
-               return "PCON";
-       case DRM_LSPCON_MODE_LS:
-               return "LS";
-       case DRM_LSPCON_MODE_INVALID:
-               return "INVALID";
-       default:
-               MISSING_CASE(mode);
-               return "INVALID";
-       }
-}
-
-static bool lspcon_detect_vendor(struct intel_lspcon *lspcon)
-{
-       struct intel_dp *dp = lspcon_to_intel_dp(lspcon);
-       struct drm_dp_dpcd_ident *ident;
-       u32 vendor_oui;
-
-       if (drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd))) {
-               DRM_ERROR("Can't read description\n");
-               return false;
-       }
-
-       ident = &dp->desc.ident;
-       vendor_oui = (ident->oui[0] << 16) | (ident->oui[1] << 8) |
-                     ident->oui[2];
-
-       switch (vendor_oui) {
-       case LSPCON_VENDOR_MCA_OUI:
-               lspcon->vendor = LSPCON_VENDOR_MCA;
-               DRM_DEBUG_KMS("Vendor: Mega Chips\n");
-               break;
-
-       case LSPCON_VENDOR_PARADE_OUI:
-               lspcon->vendor = LSPCON_VENDOR_PARADE;
-               DRM_DEBUG_KMS("Vendor: Parade Tech\n");
-               break;
-
-       default:
-               DRM_ERROR("Invalid/Unknown vendor OUI\n");
-               return false;
-       }
-
-       return true;
-}
-
-static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
-{
-       enum drm_lspcon_mode current_mode;
-       struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
-
-       if (drm_lspcon_get_mode(adapter, &current_mode)) {
-               DRM_DEBUG_KMS("Error reading LSPCON mode\n");
-               return DRM_LSPCON_MODE_INVALID;
-       }
-       return current_mode;
-}
-
-static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
-                                            enum drm_lspcon_mode mode)
-{
-       enum drm_lspcon_mode current_mode;
-
-       current_mode = lspcon_get_current_mode(lspcon);
-       if (current_mode == mode)
-               goto out;
-
-       DRM_DEBUG_KMS("Waiting for LSPCON mode %s to settle\n",
-                     lspcon_mode_name(mode));
-
-       wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, 400);
-       if (current_mode != mode)
-               DRM_ERROR("LSPCON mode hasn't settled\n");
-
-out:
-       DRM_DEBUG_KMS("Current LSPCON mode %s\n",
-                     lspcon_mode_name(current_mode));
-
-       return current_mode;
-}
-
-static int lspcon_change_mode(struct intel_lspcon *lspcon,
-                             enum drm_lspcon_mode mode)
-{
-       int err;
-       enum drm_lspcon_mode current_mode;
-       struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
-
-       err = drm_lspcon_get_mode(adapter, &current_mode);
-       if (err) {
-               DRM_ERROR("Error reading LSPCON mode\n");
-               return err;
-       }
-
-       if (current_mode == mode) {
-               DRM_DEBUG_KMS("Current mode = desired LSPCON mode\n");
-               return 0;
-       }
-
-       err = drm_lspcon_set_mode(adapter, mode);
-       if (err < 0) {
-               DRM_ERROR("LSPCON mode change failed\n");
-               return err;
-       }
-
-       lspcon->mode = mode;
-       DRM_DEBUG_KMS("LSPCON mode changed done\n");
-       return 0;
-}
-
-static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
-{
-       u8 rev;
-
-       if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV,
-                             &rev) != 1) {
-               DRM_DEBUG_KMS("Native AUX CH down\n");
-               return false;
-       }
-
-       DRM_DEBUG_KMS("Native AUX CH up, DPCD version: %d.%d\n",
-                     rev >> 4, rev & 0xf);
-
-       return true;
-}
-
-void lspcon_ycbcr420_config(struct drm_connector *connector,
-                           struct intel_crtc_state *crtc_state)
-{
-       const struct drm_display_info *info = &connector->display_info;
-       const struct drm_display_mode *adjusted_mode =
-                                       &crtc_state->base.adjusted_mode;
-
-       if (drm_mode_is_420_only(info, adjusted_mode) &&
-           connector->ycbcr_420_allowed) {
-               crtc_state->port_clock /= 2;
-               crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
-               crtc_state->lspcon_downsampling = true;
-       }
-}
-
-static bool lspcon_probe(struct intel_lspcon *lspcon)
-{
-       int retry;
-       enum drm_dp_dual_mode_type adaptor_type;
-       struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
-       enum drm_lspcon_mode expected_mode;
-
-       expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
-                       DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
-
-       /* Lets probe the adaptor and check its type */
-       for (retry = 0; retry < 6; retry++) {
-               if (retry)
-                       usleep_range(500, 1000);
-
-               adaptor_type = drm_dp_dual_mode_detect(adapter);
-               if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON)
-                       break;
-       }
-
-       if (adaptor_type != DRM_DP_DUAL_MODE_LSPCON) {
-               DRM_DEBUG_KMS("No LSPCON detected, found %s\n",
-                              drm_dp_get_dual_mode_type_name(adaptor_type));
-               return false;
-       }
-
-       /* Yay ... got a LSPCON device */
-       DRM_DEBUG_KMS("LSPCON detected\n");
-       lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
-
-       /*
-        * In the SW state machine, lets Put LSPCON in PCON mode only.
-        * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
-        * 2.0 sinks.
-        */
-       if (lspcon->mode != DRM_LSPCON_MODE_PCON) {
-               if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
-                       DRM_ERROR("LSPCON mode change to PCON failed\n");
-                       return false;
-               }
-       }
-       return true;
-}
-
-static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
-{
-       struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       unsigned long start = jiffies;
-
-       while (1) {
-               if (intel_digital_port_connected(&dig_port->base)) {
-                       DRM_DEBUG_KMS("LSPCON recovering in PCON mode after %u ms\n",
-                                     jiffies_to_msecs(jiffies - start));
-                       return;
-               }
-
-               if (time_after(jiffies, start + msecs_to_jiffies(1000)))
-                       break;
-
-               usleep_range(10000, 15000);
-       }
-
-       DRM_DEBUG_KMS("LSPCON DP descriptor mismatch after resume\n");
-}
-
-static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
-{
-       u8 avi_if_ctrl;
-       u8 retry;
-       ssize_t ret;
-
-       /* Check if LSPCON FW is ready for data */
-       for (retry = 0; retry < 5; retry++) {
-               if (retry)
-                       usleep_range(200, 300);
-
-               ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
-                                      &avi_if_ctrl, 1);
-               if (ret < 0) {
-                       DRM_ERROR("Failed to read AVI IF control\n");
-                       return false;
-               }
-
-               if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0)
-                       return true;
-       }
-
-       DRM_ERROR("Parade FW not ready to accept AVI IF\n");
-       return false;
-}
-
-static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
-                                                 u8 *avi_buf)
-{
-       u8 avi_if_ctrl;
-       u8 block_count = 0;
-       u8 *data;
-       u16 reg;
-       ssize_t ret;
-
-       while (block_count < 4) {
-               if (!lspcon_parade_fw_ready(aux)) {
-                       DRM_DEBUG_KMS("LSPCON FW not ready, block %d\n",
-                                     block_count);
-                       return false;
-               }
-
-               reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
-               data = avi_buf + block_count * 8;
-               ret = drm_dp_dpcd_write(aux, reg, data, 8);
-               if (ret < 0) {
-                       DRM_ERROR("Failed to write AVI IF block %d\n",
-                                 block_count);
-                       return false;
-               }
-
-               /*
-                * Once a block of data is written, we have to inform the FW
-                * about this by writing into avi infoframe control register:
-                * - set the kickoff bit[7] to 1
-                * - write the block no. to bits[1:0]
-                */
-               reg = LSPCON_PARADE_AVI_IF_CTRL;
-               avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
-               ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
-               if (ret < 0) {
-                       DRM_ERROR("Failed to update (0x%x), block %d\n",
-                                 reg, block_count);
-                       return false;
-               }
-
-               block_count++;
-       }
-
-       DRM_DEBUG_KMS("Wrote AVI IF blocks successfully\n");
-       return true;
-}
-
-static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
-                                              const u8 *frame,
-                                              ssize_t len)
-{
-       u8 avi_if[LSPCON_PARADE_AVI_IF_DATA_SIZE] = {1, };
-
-       /*
-        * Parade's frames contains 32 bytes of data, divided
-        * into 4 frames:
-        *      Token byte (first byte of first frame, must be non-zero)
-        *      HB0 to HB2       from AVI IF (3 bytes header)
-        *      PB0 to PB27 from AVI IF (28 bytes data)
-        * So it should look like this
-        *      first block: | <token> <HB0-HB2> <DB0-DB3> |
-        *      next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
-        */
-
-       if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
-               DRM_ERROR("Invalid length of infoframes\n");
-               return false;
-       }
-
-       memcpy(&avi_if[1], frame, len);
-
-       if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
-               DRM_DEBUG_KMS("Failed to write infoframe blocks\n");
-               return false;
-       }
-
-       return true;
-}
-
-static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
-                                           const u8 *buffer, ssize_t len)
-{
-       int ret;
-       u32 val = 0;
-       u32 retry;
-       u16 reg;
-       const u8 *data = buffer;
-
-       reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
-       while (val < len) {
-               /* DPCD write for AVI IF can fail on a slow FW day, so retry */
-               for (retry = 0; retry < 5; retry++) {
-                       ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
-                       if (ret == 1) {
-                               break;
-                       } else if (retry < 4) {
-                               mdelay(50);
-                               continue;
-                       } else {
-                               DRM_ERROR("DPCD write failed at:0x%x\n", reg);
-                               return false;
-                       }
-               }
-               val++; reg++; data++;
-       }
-
-       val = 0;
-       reg = LSPCON_MCA_AVI_IF_CTRL;
-       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
-       if (ret < 0) {
-               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
-               return false;
-       }
-
-       /* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
-       val &= ~LSPCON_MCA_AVI_IF_HANDLED;
-       val |= LSPCON_MCA_AVI_IF_KICKOFF;
-
-       ret = drm_dp_dpcd_write(aux, reg, &val, 1);
-       if (ret < 0) {
-               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
-               return false;
-       }
-
-       val = 0;
-       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
-       if (ret < 0) {
-               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
-               return false;
-       }
-
-       if (val == LSPCON_MCA_AVI_IF_HANDLED)
-               DRM_DEBUG_KMS("AVI IF handled by FW\n");
-
-       return true;
-}
-
-void lspcon_write_infoframe(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *crtc_state,
-                           unsigned int type,
-                           const void *frame, ssize_t len)
-{
-       bool ret;
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
-
-       /* LSPCON only needs AVI IF */
-       if (type != HDMI_INFOFRAME_TYPE_AVI)
-               return;
-
-       if (lspcon->vendor == LSPCON_VENDOR_MCA)
-               ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
-                                                     frame, len);
-       else
-               ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
-                                                        frame, len);
-
-       if (!ret) {
-               DRM_ERROR("Failed to write AVI infoframes\n");
-               return;
-       }
-
-       DRM_DEBUG_DRIVER("AVI infoframes updated successfully\n");
-}
-
-void lspcon_read_infoframe(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *crtc_state,
-                          unsigned int type,
-                          void *frame, ssize_t len)
-{
-       /* FIXME implement this */
-}
-
-void lspcon_set_infoframes(struct intel_encoder *encoder,
-                          bool enable,
-                          const struct intel_crtc_state *crtc_state,
-                          const struct drm_connector_state *conn_state)
-{
-       ssize_t ret;
-       union hdmi_infoframe frame;
-       u8 buf[VIDEO_DIP_DATA_SIZE];
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       struct intel_lspcon *lspcon = &dig_port->lspcon;
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-
-       if (!lspcon->active) {
-               DRM_ERROR("Writing infoframes while LSPCON disabled ?\n");
-               return;
-       }
-
-       /* FIXME precompute infoframes */
-
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-                                                      conn_state->connector,
-                                                      adjusted_mode);
-       if (ret < 0) {
-               DRM_ERROR("couldn't fill AVI infoframe\n");
-               return;
-       }
-
-       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
-               if (crtc_state->lspcon_downsampling)
-                       frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
-               else
-                       frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
-       } else {
-               frame.avi.colorspace = HDMI_COLORSPACE_RGB;
-       }
-
-       drm_hdmi_avi_infoframe_quant_range(&frame.avi,
-                                          conn_state->connector,
-                                          adjusted_mode,
-                                          crtc_state->limited_color_range ?
-                                          HDMI_QUANTIZATION_RANGE_LIMITED :
-                                          HDMI_QUANTIZATION_RANGE_FULL);
-
-       ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
-       if (ret < 0) {
-               DRM_ERROR("Failed to pack AVI IF\n");
-               return;
-       }
-
-       dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI,
-                                 buf, ret);
-}
-
-u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config)
-{
-       /* FIXME actually read this from the hw */
-       return enc_to_intel_lspcon(&encoder->base)->active;
-}
-
-void lspcon_resume(struct intel_lspcon *lspcon)
-{
-       enum drm_lspcon_mode expected_mode;
-
-       if (lspcon_wake_native_aux_ch(lspcon)) {
-               expected_mode = DRM_LSPCON_MODE_PCON;
-               lspcon_resume_in_pcon_wa(lspcon);
-       } else {
-               expected_mode = DRM_LSPCON_MODE_LS;
-       }
-
-       if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
-               return;
-
-       if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
-               DRM_ERROR("LSPCON resume failed\n");
-       else
-               DRM_DEBUG_KMS("LSPCON resume success\n");
-}
-
-void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
-{
-       lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
-}
-
-bool lspcon_init(struct intel_digital_port *intel_dig_port)
-{
-       struct intel_dp *dp = &intel_dig_port->dp;
-       struct intel_lspcon *lspcon = &intel_dig_port->lspcon;
-       struct drm_device *dev = intel_dig_port->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_connector *connector = &dp->attached_connector->base;
-
-       if (!HAS_LSPCON(dev_priv)) {
-               DRM_ERROR("LSPCON is not supported on this platform\n");
-               return false;
-       }
-
-       lspcon->active = false;
-       lspcon->mode = DRM_LSPCON_MODE_INVALID;
-
-       if (!lspcon_probe(lspcon)) {
-               DRM_ERROR("Failed to probe lspcon\n");
-               return false;
-       }
-
-       if (!intel_dp_read_dpcd(dp)) {
-               DRM_ERROR("LSPCON DPCD read failed\n");
-               return false;
-       }
-
-       if (!lspcon_detect_vendor(lspcon)) {
-               DRM_ERROR("LSPCON vendor detection failed\n");
-               return false;
-       }
-
-       connector->ycbcr_420_allowed = true;
-       lspcon->active = true;
-       DRM_DEBUG_KMS("Success: LSPCON init\n");
-       return true;
-}
diff --git a/drivers/gpu/drm/i915/intel_lspcon.h b/drivers/gpu/drm/i915/intel_lspcon.h
deleted file mode 100644 (file)
index 37cfddf..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_LSPCON_H__
-#define __INTEL_LSPCON_H__
-
-#include <linux/types.h>
-
-struct drm_connector;
-struct drm_connector_state;
-struct intel_crtc_state;
-struct intel_digital_port;
-struct intel_encoder;
-struct intel_lspcon;
-
-bool lspcon_init(struct intel_digital_port *intel_dig_port);
-void lspcon_resume(struct intel_lspcon *lspcon);
-void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
-void lspcon_write_infoframe(struct intel_encoder *encoder,
-                           const struct intel_crtc_state *crtc_state,
-                           unsigned int type,
-                           const void *buf, ssize_t len);
-void lspcon_read_infoframe(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *crtc_state,
-                          unsigned int type,
-                          void *frame, ssize_t len);
-void lspcon_set_infoframes(struct intel_encoder *encoder,
-                          bool enable,
-                          const struct intel_crtc_state *crtc_state,
-                          const struct drm_connector_state *conn_state);
-u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config);
-void lspcon_ycbcr420_config(struct drm_connector *connector,
-                           struct intel_crtc_state *crtc_state);
-
-#endif /* __INTEL_LSPCON_H__ */
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
deleted file mode 100644 (file)
index efefed6..0000000
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * Copyright © 2006-2007 Intel Corporation
- * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- *      Dave Airlie <airlied@linux.ie>
- *      Jesse Barnes <jesse.barnes@intel.com>
- */
-
-#include <acpi/button.h>
-#include <linux/acpi.h>
-#include <linux/dmi.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/vga_switcheroo.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_atomic.h"
-#include "intel_connector.h"
-#include "intel_drv.h"
-#include "intel_gmbus.h"
-#include "intel_lvds.h"
-#include "intel_panel.h"
-
-/* Private structure for the integrated LVDS support */
-struct intel_lvds_pps {
-       /* 100us units */
-       int t1_t2;
-       int t3;
-       int t4;
-       int t5;
-       int tx;
-
-       int divider;
-
-       int port;
-       bool powerdown_on_reset;
-};
-
-struct intel_lvds_encoder {
-       struct intel_encoder base;
-
-       bool is_dual_link;
-       i915_reg_t reg;
-       u32 a3_power;
-
-       struct intel_lvds_pps init_pps;
-       u32 init_lvds_val;
-
-       struct intel_connector *attached_connector;
-};
-
-static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
-{
-       return container_of(encoder, struct intel_lvds_encoder, base.base);
-}
-
-bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
-                            i915_reg_t lvds_reg, enum pipe *pipe)
-{
-       u32 val;
-
-       val = I915_READ(lvds_reg);
-
-       /* asserts want to know the pipe even if the port is disabled */
-       if (HAS_PCH_CPT(dev_priv))
-               *pipe = (val & LVDS_PIPE_SEL_MASK_CPT) >> LVDS_PIPE_SEL_SHIFT_CPT;
-       else
-               *pipe = (val & LVDS_PIPE_SEL_MASK) >> LVDS_PIPE_SEL_SHIFT;
-
-       return val & LVDS_PORT_EN;
-}
-
-static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
-                                   enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       intel_wakeref_t wakeref;
-       bool ret;
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       ret = intel_lvds_port_enabled(dev_priv, lvds_encoder->reg, pipe);
-
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-
-       return ret;
-}
-
-static void intel_lvds_get_config(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       u32 tmp, flags = 0;
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_LVDS);
-
-       tmp = I915_READ(lvds_encoder->reg);
-       if (tmp & LVDS_HSYNC_POLARITY)
-               flags |= DRM_MODE_FLAG_NHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       if (tmp & LVDS_VSYNC_POLARITY)
-               flags |= DRM_MODE_FLAG_NVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_PVSYNC;
-
-       pipe_config->base.adjusted_mode.flags |= flags;
-
-       if (INTEL_GEN(dev_priv) < 5)
-               pipe_config->gmch_pfit.lvds_border_bits =
-                       tmp & LVDS_BORDER_ENABLE;
-
-       /* gen2/3 store dither state in pfit control, needs to match */
-       if (INTEL_GEN(dev_priv) < 4) {
-               tmp = I915_READ(PFIT_CONTROL);
-
-               pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
-       }
-
-       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
-}
-
-static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv,
-                                       struct intel_lvds_pps *pps)
-{
-       u32 val;
-
-       pps->powerdown_on_reset = I915_READ(PP_CONTROL(0)) & PANEL_POWER_RESET;
-
-       val = I915_READ(PP_ON_DELAYS(0));
-       pps->port = REG_FIELD_GET(PANEL_PORT_SELECT_MASK, val);
-       pps->t1_t2 = REG_FIELD_GET(PANEL_POWER_UP_DELAY_MASK, val);
-       pps->t5 = REG_FIELD_GET(PANEL_LIGHT_ON_DELAY_MASK, val);
-
-       val = I915_READ(PP_OFF_DELAYS(0));
-       pps->t3 = REG_FIELD_GET(PANEL_POWER_DOWN_DELAY_MASK, val);
-       pps->tx = REG_FIELD_GET(PANEL_LIGHT_OFF_DELAY_MASK, val);
-
-       val = I915_READ(PP_DIVISOR(0));
-       pps->divider = REG_FIELD_GET(PP_REFERENCE_DIVIDER_MASK, val);
-       val = REG_FIELD_GET(PANEL_POWER_CYCLE_DELAY_MASK, val);
-       /*
-        * Remove the BSpec specified +1 (100ms) offset that accounts for a
-        * too short power-cycle delay due to the asynchronous programming of
-        * the register.
-        */
-       if (val)
-               val--;
-       /* Convert from 100ms to 100us units */
-       pps->t4 = val * 1000;
-
-       if (INTEL_GEN(dev_priv) <= 4 &&
-           pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) {
-               DRM_DEBUG_KMS("Panel power timings uninitialized, "
-                             "setting defaults\n");
-               /* Set T2 to 40ms and T5 to 200ms in 100 usec units */
-               pps->t1_t2 = 40 * 10;
-               pps->t5 = 200 * 10;
-               /* Set T3 to 35ms and Tx to 200ms in 100 usec units */
-               pps->t3 = 35 * 10;
-               pps->tx = 200 * 10;
-       }
-
-       DRM_DEBUG_DRIVER("LVDS PPS:t1+t2 %d t3 %d t4 %d t5 %d tx %d "
-                        "divider %d port %d powerdown_on_reset %d\n",
-                        pps->t1_t2, pps->t3, pps->t4, pps->t5, pps->tx,
-                        pps->divider, pps->port, pps->powerdown_on_reset);
-}
-
-static void intel_lvds_pps_init_hw(struct drm_i915_private *dev_priv,
-                                  struct intel_lvds_pps *pps)
-{
-       u32 val;
-
-       val = I915_READ(PP_CONTROL(0));
-       WARN_ON((val & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS);
-       if (pps->powerdown_on_reset)
-               val |= PANEL_POWER_RESET;
-       I915_WRITE(PP_CONTROL(0), val);
-
-       I915_WRITE(PP_ON_DELAYS(0),
-                  REG_FIELD_PREP(PANEL_PORT_SELECT_MASK, pps->port) |
-                  REG_FIELD_PREP(PANEL_POWER_UP_DELAY_MASK, pps->t1_t2) |
-                  REG_FIELD_PREP(PANEL_LIGHT_ON_DELAY_MASK, pps->t5));
-
-       I915_WRITE(PP_OFF_DELAYS(0),
-                  REG_FIELD_PREP(PANEL_POWER_DOWN_DELAY_MASK, pps->t3) |
-                  REG_FIELD_PREP(PANEL_LIGHT_OFF_DELAY_MASK, pps->tx));
-
-       I915_WRITE(PP_DIVISOR(0),
-                  REG_FIELD_PREP(PP_REFERENCE_DIVIDER_MASK, pps->divider) |
-                  REG_FIELD_PREP(PANEL_POWER_CYCLE_DELAY_MASK,
-                                 DIV_ROUND_UP(pps->t4, 1000) + 1));
-}
-
-static void intel_pre_enable_lvds(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *pipe_config,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       int pipe = crtc->pipe;
-       u32 temp;
-
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               assert_fdi_rx_pll_disabled(dev_priv, pipe);
-               assert_shared_dpll_disabled(dev_priv,
-                                           pipe_config->shared_dpll);
-       } else {
-               assert_pll_disabled(dev_priv, pipe);
-       }
-
-       intel_lvds_pps_init_hw(dev_priv, &lvds_encoder->init_pps);
-
-       temp = lvds_encoder->init_lvds_val;
-       temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
-
-       if (HAS_PCH_CPT(dev_priv)) {
-               temp &= ~LVDS_PIPE_SEL_MASK_CPT;
-               temp |= LVDS_PIPE_SEL_CPT(pipe);
-       } else {
-               temp &= ~LVDS_PIPE_SEL_MASK;
-               temp |= LVDS_PIPE_SEL(pipe);
-       }
-
-       /* set the corresponsding LVDS_BORDER bit */
-       temp &= ~LVDS_BORDER_ENABLE;
-       temp |= pipe_config->gmch_pfit.lvds_border_bits;
-
-       /*
-        * Set the B0-B3 data pairs corresponding to whether we're going to
-        * set the DPLLs for dual-channel mode or not.
-        */
-       if (lvds_encoder->is_dual_link)
-               temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
-       else
-               temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
-
-       /*
-        * It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
-        * appropriately here, but we need to look more thoroughly into how
-        * panels behave in the two modes. For now, let's just maintain the
-        * value we got from the BIOS.
-        */
-       temp &= ~LVDS_A3_POWER_MASK;
-       temp |= lvds_encoder->a3_power;
-
-       /*
-        * Set the dithering flag on LVDS as needed, note that there is no
-        * special lvds dither control bit on pch-split platforms, dithering is
-        * only controlled through the PIPECONF reg.
-        */
-       if (IS_GEN(dev_priv, 4)) {
-               /*
-                * Bspec wording suggests that LVDS port dithering only exists
-                * for 18bpp panels.
-                */
-               if (pipe_config->dither && pipe_config->pipe_bpp == 18)
-                       temp |= LVDS_ENABLE_DITHER;
-               else
-                       temp &= ~LVDS_ENABLE_DITHER;
-       }
-       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
-       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
-               temp |= LVDS_HSYNC_POLARITY;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
-               temp |= LVDS_VSYNC_POLARITY;
-
-       I915_WRITE(lvds_encoder->reg, temp);
-}
-
-/*
- * Sets the power state for the panel.
- */
-static void intel_enable_lvds(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config,
-                             const struct drm_connector_state *conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN);
-
-       I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) | PANEL_POWER_ON);
-       POSTING_READ(lvds_encoder->reg);
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   PP_STATUS(0), PP_ON, PP_ON, 5000))
-               DRM_ERROR("timed out waiting for panel to power on\n");
-
-       intel_panel_enable_backlight(pipe_config, conn_state);
-}
-
-static void intel_disable_lvds(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *old_crtc_state,
-                              const struct drm_connector_state *old_conn_state)
-{
-       struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) & ~PANEL_POWER_ON);
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   PP_STATUS(0), PP_ON, 0, 1000))
-               DRM_ERROR("timed out waiting for panel to power off\n");
-
-       I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN);
-       POSTING_READ(lvds_encoder->reg);
-}
-
-static void gmch_disable_lvds(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-
-{
-       intel_panel_disable_backlight(old_conn_state);
-
-       intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
-}
-
-static void pch_disable_lvds(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *old_crtc_state,
-                            const struct drm_connector_state *old_conn_state)
-{
-       intel_panel_disable_backlight(old_conn_state);
-}
-
-static void pch_post_disable_lvds(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *old_crtc_state,
-                                 const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
-}
-
-static enum drm_mode_status
-intel_lvds_mode_valid(struct drm_connector *connector,
-                     struct drm_display_mode *mode)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-       if (mode->hdisplay > fixed_mode->hdisplay)
-               return MODE_PANEL;
-       if (mode->vdisplay > fixed_mode->vdisplay)
-               return MODE_PANEL;
-       if (fixed_mode->clock > max_pixclk)
-               return MODE_CLOCK_HIGH;
-
-       return MODE_OK;
-}
-
-static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
-                                    struct intel_crtc_state *pipe_config,
-                                    struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
-       struct intel_lvds_encoder *lvds_encoder =
-               to_lvds_encoder(&intel_encoder->base);
-       struct intel_connector *intel_connector =
-               lvds_encoder->attached_connector;
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       unsigned int lvds_bpp;
-
-       /* Should never happen!! */
-       if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) {
-               DRM_ERROR("Can't support LVDS on pipe A\n");
-               return -EINVAL;
-       }
-
-       if (lvds_encoder->a3_power == LVDS_A3_POWER_UP)
-               lvds_bpp = 8*3;
-       else
-               lvds_bpp = 6*3;
-
-       if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) {
-               DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n",
-                             pipe_config->pipe_bpp, lvds_bpp);
-               pipe_config->pipe_bpp = lvds_bpp;
-       }
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       /*
-        * We have timings from the BIOS for the panel, put them in
-        * to the adjusted mode.  The CRTC will be set up for this mode,
-        * with the panel scaling set up to source from the H/VDisplay
-        * of the original mode.
-        */
-       intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
-                              adjusted_mode);
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               pipe_config->has_pch_encoder = true;
-
-               intel_pch_panel_fitting(intel_crtc, pipe_config,
-                                       conn_state->scaling_mode);
-       } else {
-               intel_gmch_panel_fitting(intel_crtc, pipe_config,
-                                        conn_state->scaling_mode);
-
-       }
-
-       /*
-        * XXX: It would be nice to support lower refresh rates on the
-        * panels to reduce power consumption, and perhaps match the
-        * user's requested refresh rate.
-        */
-
-       return 0;
-}
-
-static enum drm_connector_status
-intel_lvds_detect(struct drm_connector *connector, bool force)
-{
-       return connector_status_connected;
-}
-
-/*
- * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
- */
-static int intel_lvds_get_modes(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_device *dev = connector->dev;
-       struct drm_display_mode *mode;
-
-       /* use cached edid if we have one */
-       if (!IS_ERR_OR_NULL(intel_connector->edid))
-               return drm_add_edid_modes(connector, intel_connector->edid);
-
-       mode = drm_mode_duplicate(dev, intel_connector->panel.fixed_mode);
-       if (mode == NULL)
-               return 0;
-
-       drm_mode_probed_add(connector, mode);
-       return 1;
-}
-
-static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
-       .get_modes = intel_lvds_get_modes,
-       .mode_valid = intel_lvds_mode_valid,
-       .atomic_check = intel_digital_connector_atomic_check,
-};
-
-static const struct drm_connector_funcs intel_lvds_connector_funcs = {
-       .detect = intel_lvds_detect,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
-       .destroy = intel_encoder_destroy,
-};
-
-static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
-{
-       DRM_INFO("Skipping LVDS initialization for %s\n", id->ident);
-       return 1;
-}
-
-/* These systems claim to have LVDS, but really don't */
-static const struct dmi_system_id intel_no_lvds[] = {
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Apple Mac Mini (Core series)",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Apple Mac Mini (Core 2 series)",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "MSI IM-945GSE-A",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A9830IMS"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Dell Studio Hybrid",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Dell OptiPlex FX170",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex FX170"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "AOpen Mini PC",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "AOpen"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "AOpen Mini PC MP915",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
-                       DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "AOpen i915GMm-HFS",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
-                       DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-                .ident = "AOpen i45GMx-I",
-                .matches = {
-                        DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
-                        DMI_MATCH(DMI_BOARD_NAME, "i45GMx-I"),
-                },
-        },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Aopen i945GTt-VFA",
-               .matches = {
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Clientron U800",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "U800"),
-               },
-       },
-       {
-                .callback = intel_no_lvds_dmi_callback,
-                .ident = "Clientron E830",
-                .matches = {
-                        DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
-                        DMI_MATCH(DMI_PRODUCT_NAME, "E830"),
-                },
-        },
-        {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Asus EeeBox PC EB1007",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "EB1007"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Asus AT5NM10T-I",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                       DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Hewlett-Packard HP t5740",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, " t5740"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Hewlett-Packard t5745",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "hp t5745"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Hewlett-Packard st5747",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "hp st5747"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "MSI Wind Box DC500",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
-                       DMI_MATCH(DMI_BOARD_NAME, "MS-7469"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Gigabyte GA-D525TUD",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
-                       DMI_MATCH(DMI_BOARD_NAME, "D525TUD"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Supermicro X7SPA-H",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Fujitsu Esprimo Q900",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Intel D410PT",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
-                       DMI_MATCH(DMI_BOARD_NAME, "D410PT"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Intel D425KT",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
-                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D425KT"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Intel D510MO",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
-                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D510MO"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Intel D525MW",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
-                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
-               .ident = "Radiant P845",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "P845"),
-               },
-       },
-
-       { }     /* terminating entry */
-};
-
-static int intel_dual_link_lvds_callback(const struct dmi_system_id *id)
-{
-       DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident);
-       return 1;
-}
-
-static const struct dmi_system_id intel_dual_link_lvds[] = {
-       {
-               .callback = intel_dual_link_lvds_callback,
-               .ident = "Apple MacBook Pro 15\" (2010)",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"),
-               },
-       },
-       {
-               .callback = intel_dual_link_lvds_callback,
-               .ident = "Apple MacBook Pro 15\" (2011)",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
-               },
-       },
-       {
-               .callback = intel_dual_link_lvds_callback,
-               .ident = "Apple MacBook Pro 15\" (2012)",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"),
-               },
-       },
-       { }     /* terminating entry */
-};
-
-struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder;
-
-       for_each_intel_encoder(&dev_priv->drm, encoder) {
-               if (encoder->type == INTEL_OUTPUT_LVDS)
-                       return encoder;
-       }
-
-       return NULL;
-}
-
-bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder = intel_get_lvds_encoder(dev_priv);
-
-       return encoder && to_lvds_encoder(&encoder->base)->is_dual_link;
-}
-
-static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
-{
-       struct drm_device *dev = lvds_encoder->base.base.dev;
-       unsigned int val;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       /* use the module option value if specified */
-       if (i915_modparams.lvds_channel_mode > 0)
-               return i915_modparams.lvds_channel_mode == 2;
-
-       /* single channel LVDS is limited to 112 MHz */
-       if (lvds_encoder->attached_connector->panel.fixed_mode->clock > 112999)
-               return true;
-
-       if (dmi_check_system(intel_dual_link_lvds))
-               return true;
-
-       /*
-        * BIOS should set the proper LVDS register value at boot, but
-        * in reality, it doesn't set the value when the lid is closed;
-        * we need to check "the value to be set" in VBT when LVDS
-        * register is uninitialized.
-        */
-       val = I915_READ(lvds_encoder->reg);
-       if (HAS_PCH_CPT(dev_priv))
-               val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK_CPT);
-       else
-               val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK);
-       if (val == 0)
-               val = dev_priv->vbt.bios_lvds_val;
-
-       return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
-}
-
-/**
- * intel_lvds_init - setup LVDS connectors on this device
- * @dev_priv: i915 device
- *
- * Create the connector, register the LVDS DDC bus, and try to figure out what
- * modes we can display on the LVDS panel (if present).
- */
-void intel_lvds_init(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_lvds_encoder *lvds_encoder;
-       struct intel_encoder *intel_encoder;
-       struct intel_connector *intel_connector;
-       struct drm_connector *connector;
-       struct drm_encoder *encoder;
-       struct drm_display_mode *fixed_mode = NULL;
-       struct drm_display_mode *downclock_mode = NULL;
-       struct edid *edid;
-       i915_reg_t lvds_reg;
-       u32 lvds;
-       u8 pin;
-       u32 allowed_scalers;
-
-       /* Skip init on machines we know falsely report LVDS */
-       if (dmi_check_system(intel_no_lvds)) {
-               WARN(!dev_priv->vbt.int_lvds_support,
-                    "Useless DMI match. Internal LVDS support disabled by VBT\n");
-               return;
-       }
-
-       if (!dev_priv->vbt.int_lvds_support) {
-               DRM_DEBUG_KMS("Internal LVDS support disabled by VBT\n");
-               return;
-       }
-
-       if (HAS_PCH_SPLIT(dev_priv))
-               lvds_reg = PCH_LVDS;
-       else
-               lvds_reg = LVDS;
-
-       lvds = I915_READ(lvds_reg);
-
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               if ((lvds & LVDS_DETECTED) == 0)
-                       return;
-       }
-
-       pin = GMBUS_PIN_PANEL;
-       if (!intel_bios_is_lvds_present(dev_priv, &pin)) {
-               if ((lvds & LVDS_PORT_EN) == 0) {
-                       DRM_DEBUG_KMS("LVDS is not present in VBT\n");
-                       return;
-               }
-               DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled anyway\n");
-       }
-
-       lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL);
-       if (!lvds_encoder)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(lvds_encoder);
-               return;
-       }
-
-       lvds_encoder->attached_connector = intel_connector;
-
-       intel_encoder = &lvds_encoder->base;
-       encoder = &intel_encoder->base;
-       connector = &intel_connector->base;
-       drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
-                          DRM_MODE_CONNECTOR_LVDS);
-
-       drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
-                        DRM_MODE_ENCODER_LVDS, "LVDS");
-
-       intel_encoder->enable = intel_enable_lvds;
-       intel_encoder->pre_enable = intel_pre_enable_lvds;
-       intel_encoder->compute_config = intel_lvds_compute_config;
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               intel_encoder->disable = pch_disable_lvds;
-               intel_encoder->post_disable = pch_post_disable_lvds;
-       } else {
-               intel_encoder->disable = gmch_disable_lvds;
-       }
-       intel_encoder->get_hw_state = intel_lvds_get_hw_state;
-       intel_encoder->get_config = intel_lvds_get_config;
-       intel_encoder->update_pipe = intel_panel_update_backlight;
-       intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
-
-       intel_encoder->type = INTEL_OUTPUT_LVDS;
-       intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
-       intel_encoder->port = PORT_NONE;
-       intel_encoder->cloneable = 0;
-       if (HAS_PCH_SPLIT(dev_priv))
-               intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       else if (IS_GEN(dev_priv, 4))
-               intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       else
-               intel_encoder->crtc_mask = (1 << 1);
-
-       drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-       connector->interlace_allowed = false;
-       connector->doublescan_allowed = false;
-
-       lvds_encoder->reg = lvds_reg;
-
-       /* create the scaling mode property */
-       allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT);
-       allowed_scalers |= BIT(DRM_MODE_SCALE_FULLSCREEN);
-       allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
-       drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
-       connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
-
-       intel_lvds_pps_get_hw_state(dev_priv, &lvds_encoder->init_pps);
-       lvds_encoder->init_lvds_val = lvds;
-
-       /*
-        * LVDS discovery:
-        * 1) check for EDID on DDC
-        * 2) check for VBT data
-        * 3) check to see if LVDS is already on
-        *    if none of the above, no panel
-        */
-
-       /*
-        * Attempt to get the fixed panel mode from DDC.  Assume that the
-        * preferred mode is the right one.
-        */
-       mutex_lock(&dev->mode_config.mutex);
-       if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
-               edid = drm_get_edid_switcheroo(connector,
-                                   intel_gmbus_get_adapter(dev_priv, pin));
-       else
-               edid = drm_get_edid(connector,
-                                   intel_gmbus_get_adapter(dev_priv, pin));
-       if (edid) {
-               if (drm_add_edid_modes(connector, edid)) {
-                       drm_connector_update_edid_property(connector,
-                                                               edid);
-               } else {
-                       kfree(edid);
-                       edid = ERR_PTR(-EINVAL);
-               }
-       } else {
-               edid = ERR_PTR(-ENOENT);
-       }
-       intel_connector->edid = edid;
-
-       fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
-       if (fixed_mode)
-               goto out;
-
-       /* Failed to get EDID, what about VBT? */
-       fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
-       if (fixed_mode)
-               goto out;
-
-       /*
-        * If we didn't get EDID, try checking if the panel is already turned
-        * on.  If so, assume that whatever is currently programmed is the
-        * correct mode.
-        */
-       fixed_mode = intel_encoder_current_mode(intel_encoder);
-       if (fixed_mode) {
-               DRM_DEBUG_KMS("using current (BIOS) mode: ");
-               drm_mode_debug_printmodeline(fixed_mode);
-               fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
-       }
-
-       /* If we still don't have a mode after all that, give up. */
-       if (!fixed_mode)
-               goto failed;
-
-out:
-       mutex_unlock(&dev->mode_config.mutex);
-
-       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
-
-       lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
-       DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
-                     lvds_encoder->is_dual_link ? "dual" : "single");
-
-       lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK;
-
-       return;
-
-failed:
-       mutex_unlock(&dev->mode_config.mutex);
-
-       DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
-       drm_connector_cleanup(connector);
-       drm_encoder_cleanup(encoder);
-       kfree(lvds_encoder);
-       intel_connector_free(intel_connector);
-       return;
-}
diff --git a/drivers/gpu/drm/i915/intel_lvds.h b/drivers/gpu/drm/i915/intel_lvds.h
deleted file mode 100644 (file)
index bc9c8b8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_LVDS_H__
-#define __INTEL_LVDS_H__
-
-#include <linux/types.h>
-
-#include "i915_reg.h"
-
-enum pipe;
-struct drm_i915_private;
-
-bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
-                            i915_reg_t lvds_reg, enum pipe *pipe);
-void intel_lvds_init(struct drm_i915_private *dev_priv);
-struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv);
-bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv);
-
-#endif /* __INTEL_LVDS_H__ */
index 8fa1159d097fce38d92d9ac08bcdfc1d656914aa..82488127135108cf1f5feecb67805dd364c7873a 100644 (file)
 
 #include <drm/i915_drm.h>
 
+#include "display/intel_panel.h"
+
 #include "i915_drv.h"
 #include "intel_drv.h"
 #include "intel_opregion.h"
-#include "intel_panel.h"
 
 #define OPREGION_HEADER_OFFSET 0
 #define OPREGION_ACPI_OFFSET   0x100
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
deleted file mode 100644 (file)
index 39d7420..0000000
+++ /dev/null
@@ -1,2051 +0,0 @@
-/*
- * Copyright © 2006-2010 Intel Corporation
- * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- *      Dave Airlie <airlied@linux.ie>
- *      Jesse Barnes <jesse.barnes@intel.com>
- *      Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/moduleparam.h>
-#include <linux/pwm.h>
-
-#include "intel_connector.h"
-#include "intel_dp_aux_backlight.h"
-#include "intel_drv.h"
-#include "intel_dsi_dcs_backlight.h"
-#include "intel_panel.h"
-
-#define CRC_PMIC_PWM_PERIOD_NS 21333
-
-void
-intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
-                      struct drm_display_mode *adjusted_mode)
-{
-       drm_mode_copy(adjusted_mode, fixed_mode);
-
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-}
-
-static bool is_downclock_mode(const struct drm_display_mode *downclock_mode,
-                             const struct drm_display_mode *fixed_mode)
-{
-       return drm_mode_match(downclock_mode, fixed_mode,
-                             DRM_MODE_MATCH_TIMINGS |
-                             DRM_MODE_MATCH_FLAGS |
-                             DRM_MODE_MATCH_3D_FLAGS) &&
-               downclock_mode->clock < fixed_mode->clock;
-}
-
-struct drm_display_mode *
-intel_panel_edid_downclock_mode(struct intel_connector *connector,
-                               const struct drm_display_mode *fixed_mode)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       const struct drm_display_mode *scan, *best_mode = NULL;
-       struct drm_display_mode *downclock_mode;
-       int best_clock = fixed_mode->clock;
-
-       list_for_each_entry(scan, &connector->base.probed_modes, head) {
-               /*
-                * If one mode has the same resolution with the fixed_panel
-                * mode while they have the different refresh rate, it means
-                * that the reduced downclock is found. In such
-                * case we can set the different FPx0/1 to dynamically select
-                * between low and high frequency.
-                */
-               if (is_downclock_mode(scan, fixed_mode) &&
-                   scan->clock < best_clock) {
-                       /*
-                        * The downclock is already found. But we
-                        * expect to find the lower downclock.
-                        */
-                       best_clock = scan->clock;
-                       best_mode = scan;
-               }
-       }
-
-       if (!best_mode)
-               return NULL;
-
-       downclock_mode = drm_mode_duplicate(&dev_priv->drm, best_mode);
-       if (!downclock_mode)
-               return NULL;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using downclock mode from EDID: ",
-                     connector->base.base.id, connector->base.name);
-       drm_mode_debug_printmodeline(downclock_mode);
-
-       return downclock_mode;
-}
-
-struct drm_display_mode *
-intel_panel_edid_fixed_mode(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       const struct drm_display_mode *scan;
-       struct drm_display_mode *fixed_mode;
-
-       if (list_empty(&connector->base.probed_modes))
-               return NULL;
-
-       /* prefer fixed mode from EDID if available */
-       list_for_each_entry(scan, &connector->base.probed_modes, head) {
-               if ((scan->type & DRM_MODE_TYPE_PREFERRED) == 0)
-                       continue;
-
-               fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan);
-               if (!fixed_mode)
-                       return NULL;
-
-               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using preferred mode from EDID: ",
-                             connector->base.base.id, connector->base.name);
-               drm_mode_debug_printmodeline(fixed_mode);
-
-               return fixed_mode;
-       }
-
-       scan = list_first_entry(&connector->base.probed_modes,
-                               typeof(*scan), head);
-
-       fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan);
-       if (!fixed_mode)
-               return NULL;
-
-       fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using first mode from EDID: ",
-                     connector->base.base.id, connector->base.name);
-       drm_mode_debug_printmodeline(fixed_mode);
-
-       return fixed_mode;
-}
-
-struct drm_display_mode *
-intel_panel_vbt_fixed_mode(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct drm_display_info *info = &connector->base.display_info;
-       struct drm_display_mode *fixed_mode;
-
-       if (!dev_priv->vbt.lfp_lvds_vbt_mode)
-               return NULL;
-
-       fixed_mode = drm_mode_duplicate(&dev_priv->drm,
-                                       dev_priv->vbt.lfp_lvds_vbt_mode);
-       if (!fixed_mode)
-               return NULL;
-
-       fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using mode from VBT: ",
-                     connector->base.base.id, connector->base.name);
-       drm_mode_debug_printmodeline(fixed_mode);
-
-       info->width_mm = fixed_mode->width_mm;
-       info->height_mm = fixed_mode->height_mm;
-
-       return fixed_mode;
-}
-
-/* adjusted_mode has been preset to be the panel's fixed mode */
-void
-intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
-                       struct intel_crtc_state *pipe_config,
-                       int fitting_mode)
-{
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       int x = 0, y = 0, width = 0, height = 0;
-
-       /* Native modes don't need fitting */
-       if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
-           adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h &&
-           pipe_config->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
-               goto done;
-
-       switch (fitting_mode) {
-       case DRM_MODE_SCALE_CENTER:
-               width = pipe_config->pipe_src_w;
-               height = pipe_config->pipe_src_h;
-               x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
-               y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
-               break;
-
-       case DRM_MODE_SCALE_ASPECT:
-               /* Scale but preserve the aspect ratio */
-               {
-                       u32 scaled_width = adjusted_mode->crtc_hdisplay
-                               * pipe_config->pipe_src_h;
-                       u32 scaled_height = pipe_config->pipe_src_w
-                               * adjusted_mode->crtc_vdisplay;
-                       if (scaled_width > scaled_height) { /* pillar */
-                               width = scaled_height / pipe_config->pipe_src_h;
-                               if (width & 1)
-                                       width++;
-                               x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
-                               y = 0;
-                               height = adjusted_mode->crtc_vdisplay;
-                       } else if (scaled_width < scaled_height) { /* letter */
-                               height = scaled_width / pipe_config->pipe_src_w;
-                               if (height & 1)
-                                   height++;
-                               y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
-                               x = 0;
-                               width = adjusted_mode->crtc_hdisplay;
-                       } else {
-                               x = y = 0;
-                               width = adjusted_mode->crtc_hdisplay;
-                               height = adjusted_mode->crtc_vdisplay;
-                       }
-               }
-               break;
-
-       case DRM_MODE_SCALE_FULLSCREEN:
-               x = y = 0;
-               width = adjusted_mode->crtc_hdisplay;
-               height = adjusted_mode->crtc_vdisplay;
-               break;
-
-       default:
-               WARN(1, "bad panel fit mode: %d\n", fitting_mode);
-               return;
-       }
-
-done:
-       pipe_config->pch_pfit.pos = (x << 16) | y;
-       pipe_config->pch_pfit.size = (width << 16) | height;
-       pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
-}
-
-static void
-centre_horizontally(struct drm_display_mode *adjusted_mode,
-                   int width)
-{
-       u32 border, sync_pos, blank_width, sync_width;
-
-       /* keep the hsync and hblank widths constant */
-       sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
-       blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
-       sync_pos = (blank_width - sync_width + 1) / 2;
-
-       border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
-       border += border & 1; /* make the border even */
-
-       adjusted_mode->crtc_hdisplay = width;
-       adjusted_mode->crtc_hblank_start = width + border;
-       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
-
-       adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
-       adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
-}
-
-static void
-centre_vertically(struct drm_display_mode *adjusted_mode,
-                 int height)
-{
-       u32 border, sync_pos, blank_width, sync_width;
-
-       /* keep the vsync and vblank widths constant */
-       sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
-       blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
-       sync_pos = (blank_width - sync_width + 1) / 2;
-
-       border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
-
-       adjusted_mode->crtc_vdisplay = height;
-       adjusted_mode->crtc_vblank_start = height + border;
-       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
-
-       adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
-       adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
-}
-
-static inline u32 panel_fitter_scaling(u32 source, u32 target)
-{
-       /*
-        * Floating point operation is not supported. So the FACTOR
-        * is defined, which can avoid the floating point computation
-        * when calculating the panel ratio.
-        */
-#define ACCURACY 12
-#define FACTOR (1 << ACCURACY)
-       u32 ratio = source * FACTOR / target;
-       return (FACTOR * ratio + FACTOR/2) / FACTOR;
-}
-
-static void i965_scale_aspect(struct intel_crtc_state *pipe_config,
-                             u32 *pfit_control)
-{
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       u32 scaled_width = adjusted_mode->crtc_hdisplay *
-               pipe_config->pipe_src_h;
-       u32 scaled_height = pipe_config->pipe_src_w *
-               adjusted_mode->crtc_vdisplay;
-
-       /* 965+ is easy, it does everything in hw */
-       if (scaled_width > scaled_height)
-               *pfit_control |= PFIT_ENABLE |
-                       PFIT_SCALING_PILLAR;
-       else if (scaled_width < scaled_height)
-               *pfit_control |= PFIT_ENABLE |
-                       PFIT_SCALING_LETTER;
-       else if (adjusted_mode->crtc_hdisplay != pipe_config->pipe_src_w)
-               *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
-}
-
-static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
-                             u32 *pfit_control, u32 *pfit_pgm_ratios,
-                             u32 *border)
-{
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       u32 scaled_width = adjusted_mode->crtc_hdisplay *
-               pipe_config->pipe_src_h;
-       u32 scaled_height = pipe_config->pipe_src_w *
-               adjusted_mode->crtc_vdisplay;
-       u32 bits;
-
-       /*
-        * For earlier chips we have to calculate the scaling
-        * ratio by hand and program it into the
-        * PFIT_PGM_RATIO register
-        */
-       if (scaled_width > scaled_height) { /* pillar */
-               centre_horizontally(adjusted_mode,
-                                   scaled_height /
-                                   pipe_config->pipe_src_h);
-
-               *border = LVDS_BORDER_ENABLE;
-               if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay) {
-                       bits = panel_fitter_scaling(pipe_config->pipe_src_h,
-                                                   adjusted_mode->crtc_vdisplay);
-
-                       *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
-                                            bits << PFIT_VERT_SCALE_SHIFT);
-                       *pfit_control |= (PFIT_ENABLE |
-                                         VERT_INTERP_BILINEAR |
-                                         HORIZ_INTERP_BILINEAR);
-               }
-       } else if (scaled_width < scaled_height) { /* letter */
-               centre_vertically(adjusted_mode,
-                                 scaled_width /
-                                 pipe_config->pipe_src_w);
-
-               *border = LVDS_BORDER_ENABLE;
-               if (pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) {
-                       bits = panel_fitter_scaling(pipe_config->pipe_src_w,
-                                                   adjusted_mode->crtc_hdisplay);
-
-                       *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
-                                            bits << PFIT_VERT_SCALE_SHIFT);
-                       *pfit_control |= (PFIT_ENABLE |
-                                         VERT_INTERP_BILINEAR |
-                                         HORIZ_INTERP_BILINEAR);
-               }
-       } else {
-               /* Aspects match, Let hw scale both directions */
-               *pfit_control |= (PFIT_ENABLE |
-                                 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
-                                 VERT_INTERP_BILINEAR |
-                                 HORIZ_INTERP_BILINEAR);
-       }
-}
-
-void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
-                             struct intel_crtc_state *pipe_config,
-                             int fitting_mode)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-       u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-
-       /* Native modes don't need fitting */
-       if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
-           adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h)
-               goto out;
-
-       switch (fitting_mode) {
-       case DRM_MODE_SCALE_CENTER:
-               /*
-                * For centered modes, we have to calculate border widths &
-                * heights and modify the values programmed into the CRTC.
-                */
-               centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
-               centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
-               border = LVDS_BORDER_ENABLE;
-               break;
-       case DRM_MODE_SCALE_ASPECT:
-               /* Scale but preserve the aspect ratio */
-               if (INTEL_GEN(dev_priv) >= 4)
-                       i965_scale_aspect(pipe_config, &pfit_control);
-               else
-                       i9xx_scale_aspect(pipe_config, &pfit_control,
-                                         &pfit_pgm_ratios, &border);
-               break;
-       case DRM_MODE_SCALE_FULLSCREEN:
-               /*
-                * Full scaling, even if it changes the aspect ratio.
-                * Fortunately this is all done for us in hw.
-                */
-               if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay ||
-                   pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) {
-                       pfit_control |= PFIT_ENABLE;
-                       if (INTEL_GEN(dev_priv) >= 4)
-                               pfit_control |= PFIT_SCALING_AUTO;
-                       else
-                               pfit_control |= (VERT_AUTO_SCALE |
-                                                VERT_INTERP_BILINEAR |
-                                                HORIZ_AUTO_SCALE |
-                                                HORIZ_INTERP_BILINEAR);
-               }
-               break;
-       default:
-               WARN(1, "bad panel fit mode: %d\n", fitting_mode);
-               return;
-       }
-
-       /* 965+ wants fuzzy fitting */
-       /* FIXME: handle multiple panels by failing gracefully */
-       if (INTEL_GEN(dev_priv) >= 4)
-               pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
-                                PFIT_FILTER_FUZZY);
-
-out:
-       if ((pfit_control & PFIT_ENABLE) == 0) {
-               pfit_control = 0;
-               pfit_pgm_ratios = 0;
-       }
-
-       /* Make sure pre-965 set dither correctly for 18bpp panels. */
-       if (INTEL_GEN(dev_priv) < 4 && pipe_config->pipe_bpp == 18)
-               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-
-       pipe_config->gmch_pfit.control = pfit_control;
-       pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
-       pipe_config->gmch_pfit.lvds_border_bits = border;
-}
-
-/**
- * scale - scale values from one range to another
- * @source_val: value in range [@source_min..@source_max]
- * @source_min: minimum legal value for @source_val
- * @source_max: maximum legal value for @source_val
- * @target_min: corresponding target value for @source_min
- * @target_max: corresponding target value for @source_max
- *
- * Return @source_val in range [@source_min..@source_max] scaled to range
- * [@target_min..@target_max].
- */
-static u32 scale(u32 source_val,
-                u32 source_min, u32 source_max,
-                u32 target_min, u32 target_max)
-{
-       u64 target_val;
-
-       WARN_ON(source_min > source_max);
-       WARN_ON(target_min > target_max);
-
-       /* defensive */
-       source_val = clamp(source_val, source_min, source_max);
-
-       /* avoid overflows */
-       target_val = mul_u32_u32(source_val - source_min,
-                                target_max - target_min);
-       target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min);
-       target_val += target_min;
-
-       return target_val;
-}
-
-/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
-static inline u32 scale_user_to_hw(struct intel_connector *connector,
-                                  u32 user_level, u32 user_max)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       return scale(user_level, 0, user_max,
-                    panel->backlight.min, panel->backlight.max);
-}
-
-/* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
- * to [hw_min..hw_max]. */
-static inline u32 clamp_user_to_hw(struct intel_connector *connector,
-                                  u32 user_level, u32 user_max)
-{
-       struct intel_panel *panel = &connector->panel;
-       u32 hw_level;
-
-       hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
-       hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
-
-       return hw_level;
-}
-
-/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
-static inline u32 scale_hw_to_user(struct intel_connector *connector,
-                                  u32 hw_level, u32 user_max)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       return scale(hw_level, panel->backlight.min, panel->backlight.max,
-                    0, user_max);
-}
-
-static u32 intel_panel_compute_brightness(struct intel_connector *connector,
-                                         u32 val)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       if (i915_modparams.invert_brightness < 0)
-               return val;
-
-       if (i915_modparams.invert_brightness > 0 ||
-           dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
-               return panel->backlight.max - val + panel->backlight.min;
-       }
-
-       return val;
-}
-
-static u32 lpt_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
-}
-
-static u32 pch_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-}
-
-static u32 i9xx_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 val;
-
-       val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-       if (INTEL_GEN(dev_priv) < 4)
-               val >>= 1;
-
-       if (panel->backlight.combination_mode) {
-               u8 lbpc;
-
-               pci_read_config_byte(dev_priv->drm.pdev, LBPC, &lbpc);
-               val *= lbpc;
-       }
-
-       return val;
-}
-
-static u32 _vlv_get_backlight(struct drm_i915_private *dev_priv, enum pipe pipe)
-{
-       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
-               return 0;
-
-       return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
-}
-
-static u32 vlv_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum pipe pipe = intel_connector_get_pipe(connector);
-
-       return _vlv_get_backlight(dev_priv, pipe);
-}
-
-static u32 bxt_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       return I915_READ(BXT_BLC_PWM_DUTY(panel->backlight.controller));
-}
-
-static u32 pwm_get_backlight(struct intel_connector *connector)
-{
-       struct intel_panel *panel = &connector->panel;
-       int duty_ns;
-
-       duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-       return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
-}
-
-static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
-}
-
-static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       u32 tmp;
-
-       tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
-}
-
-static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 tmp, mask;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       if (panel->backlight.combination_mode) {
-               u8 lbpc;
-
-               lbpc = level * 0xfe / panel->backlight.max + 1;
-               level /= lbpc;
-               pci_write_config_byte(dev_priv->drm.pdev, LBPC, lbpc);
-       }
-
-       if (IS_GEN(dev_priv, 4)) {
-               mask = BACKLIGHT_DUTY_CYCLE_MASK;
-       } else {
-               level <<= 1;
-               mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
-       }
-
-       tmp = I915_READ(BLC_PWM_CTL) & ~mask;
-       I915_WRITE(BLC_PWM_CTL, tmp | level);
-}
-
-static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
-       u32 tmp;
-
-       tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
-}
-
-static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       I915_WRITE(BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
-}
-
-static void pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
-       int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
-
-       pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
-}
-
-static void
-intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
-
-       level = intel_panel_compute_brightness(connector, level);
-       panel->backlight.set(conn_state, level);
-}
-
-/* set backlight brightness to level in range [0..max], assuming hw min is
- * respected.
- */
-void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
-                                   u32 user_level, u32 user_max)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 hw_level;
-
-       /*
-        * Lack of crtc may occur during driver init because
-        * connection_mutex isn't held across the entire backlight
-        * setup + modeset readout, and the BIOS can issue the
-        * requests at any time.
-        */
-       if (!panel->backlight.present || !conn_state->crtc)
-               return;
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       WARN_ON(panel->backlight.max == 0);
-
-       hw_level = clamp_user_to_hw(connector, user_level, user_max);
-       panel->backlight.level = hw_level;
-
-       if (panel->backlight.device)
-               panel->backlight.device->props.brightness =
-                       scale_hw_to_user(connector,
-                                        panel->backlight.level,
-                                        panel->backlight.device->props.max_brightness);
-
-       if (panel->backlight.enabled)
-               intel_panel_actually_set_backlight(conn_state, hw_level);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       u32 tmp;
-
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-
-       /*
-        * Although we don't support or enable CPU PWM with LPT/SPT based
-        * systems, it may have been enabled prior to loading the
-        * driver. Disable to avoid warnings on LCPLL disable.
-        *
-        * This needs rework if we need to add support for CPU PWM on PCH split
-        * platforms.
-        */
-       tmp = I915_READ(BLC_PWM_CPU_CTL2);
-       if (tmp & BLM_PWM_ENABLE) {
-               DRM_DEBUG_KMS("cpu backlight was enabled, disabling\n");
-               I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
-       }
-
-       tmp = I915_READ(BLC_PWM_PCH_CTL1);
-       I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
-}
-
-static void pch_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       u32 tmp;
-
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-
-       tmp = I915_READ(BLC_PWM_CPU_CTL2);
-       I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
-
-       tmp = I915_READ(BLC_PWM_PCH_CTL1);
-       I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
-}
-
-static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-}
-
-static void i965_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
-       u32 tmp;
-
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-
-       tmp = I915_READ(BLC_PWM_CTL2);
-       I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
-}
-
-static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
-       u32 tmp;
-
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-
-       tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe));
-       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
-}
-
-static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 tmp, val;
-
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-
-       tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
-                       tmp & ~BXT_BLC_PWM_ENABLE);
-
-       if (panel->backlight.controller == 1) {
-               val = I915_READ(UTIL_PIN_CTL);
-               val &= ~UTIL_PIN_ENABLE;
-               I915_WRITE(UTIL_PIN_CTL, val);
-       }
-}
-
-static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 tmp;
-
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-
-       tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
-                  tmp & ~BXT_BLC_PWM_ENABLE);
-}
-
-static void pwm_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       /* Disable the backlight */
-       intel_panel_actually_set_backlight(old_conn_state, 0);
-       usleep_range(2000, 3000);
-       pwm_disable(panel->backlight.pwm);
-}
-
-void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       if (!panel->backlight.present)
-               return;
-
-       /*
-        * Do not disable backlight on the vga_switcheroo path. When switching
-        * away from i915, the other client may depend on i915 to handle the
-        * backlight. This will leave the backlight on unnecessarily when
-        * another client is not activated.
-        */
-       if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
-               DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
-               return;
-       }
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       if (panel->backlight.device)
-               panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
-       panel->backlight.enabled = false;
-       panel->backlight.disable(old_conn_state);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pch_ctl1, pch_ctl2, schicken;
-
-       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
-       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
-               DRM_DEBUG_KMS("pch backlight already enabled\n");
-               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
-               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
-       }
-
-       if (HAS_PCH_LPT(dev_priv)) {
-               schicken = I915_READ(SOUTH_CHICKEN2);
-               if (panel->backlight.alternate_pwm_increment)
-                       schicken |= LPT_PWM_GRANULARITY;
-               else
-                       schicken &= ~LPT_PWM_GRANULARITY;
-               I915_WRITE(SOUTH_CHICKEN2, schicken);
-       } else {
-               schicken = I915_READ(SOUTH_CHICKEN1);
-               if (panel->backlight.alternate_pwm_increment)
-                       schicken |= SPT_PWM_GRANULARITY;
-               else
-                       schicken &= ~SPT_PWM_GRANULARITY;
-               I915_WRITE(SOUTH_CHICKEN1, schicken);
-       }
-
-       pch_ctl2 = panel->backlight.max << 16;
-       I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
-
-       pch_ctl1 = 0;
-       if (panel->backlight.active_low_pwm)
-               pch_ctl1 |= BLM_PCH_POLARITY;
-
-       /* After LPT, override is the default. */
-       if (HAS_PCH_LPT(dev_priv))
-               pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
-
-       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
-       POSTING_READ(BLC_PWM_PCH_CTL1);
-       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
-
-       /* This won't stick until the above enable. */
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-}
-
-static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
-
-       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
-       if (cpu_ctl2 & BLM_PWM_ENABLE) {
-               DRM_DEBUG_KMS("cpu backlight already enabled\n");
-               cpu_ctl2 &= ~BLM_PWM_ENABLE;
-               I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
-       }
-
-       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
-       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
-               DRM_DEBUG_KMS("pch backlight already enabled\n");
-               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
-               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
-       }
-
-       if (cpu_transcoder == TRANSCODER_EDP)
-               cpu_ctl2 = BLM_TRANSCODER_EDP;
-       else
-               cpu_ctl2 = BLM_PIPE(cpu_transcoder);
-       I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
-       POSTING_READ(BLC_PWM_CPU_CTL2);
-       I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
-
-       /* This won't stick until the above enable. */
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-
-       pch_ctl2 = panel->backlight.max << 16;
-       I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
-
-       pch_ctl1 = 0;
-       if (panel->backlight.active_low_pwm)
-               pch_ctl1 |= BLM_PCH_POLARITY;
-
-       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
-       POSTING_READ(BLC_PWM_PCH_CTL1);
-       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
-}
-
-static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, freq;
-
-       ctl = I915_READ(BLC_PWM_CTL);
-       if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
-               DRM_DEBUG_KMS("backlight already enabled\n");
-               I915_WRITE(BLC_PWM_CTL, 0);
-       }
-
-       freq = panel->backlight.max;
-       if (panel->backlight.combination_mode)
-               freq /= 0xff;
-
-       ctl = freq << 17;
-       if (panel->backlight.combination_mode)
-               ctl |= BLM_LEGACY_MODE;
-       if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm)
-               ctl |= BLM_POLARITY_PNV;
-
-       I915_WRITE(BLC_PWM_CTL, ctl);
-       POSTING_READ(BLC_PWM_CTL);
-
-       /* XXX: combine this into above write? */
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-
-       /*
-        * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
-        * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
-        * that has backlight.
-        */
-       if (IS_GEN(dev_priv, 2))
-               I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
-}
-
-static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
-       u32 ctl, ctl2, freq;
-
-       ctl2 = I915_READ(BLC_PWM_CTL2);
-       if (ctl2 & BLM_PWM_ENABLE) {
-               DRM_DEBUG_KMS("backlight already enabled\n");
-               ctl2 &= ~BLM_PWM_ENABLE;
-               I915_WRITE(BLC_PWM_CTL2, ctl2);
-       }
-
-       freq = panel->backlight.max;
-       if (panel->backlight.combination_mode)
-               freq /= 0xff;
-
-       ctl = freq << 16;
-       I915_WRITE(BLC_PWM_CTL, ctl);
-
-       ctl2 = BLM_PIPE(pipe);
-       if (panel->backlight.combination_mode)
-               ctl2 |= BLM_COMBINATION_MODE;
-       if (panel->backlight.active_low_pwm)
-               ctl2 |= BLM_POLARITY_I965;
-       I915_WRITE(BLC_PWM_CTL2, ctl2);
-       POSTING_READ(BLC_PWM_CTL2);
-       I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
-
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-}
-
-static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
-       u32 ctl, ctl2;
-
-       ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
-       if (ctl2 & BLM_PWM_ENABLE) {
-               DRM_DEBUG_KMS("backlight already enabled\n");
-               ctl2 &= ~BLM_PWM_ENABLE;
-               I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
-       }
-
-       ctl = panel->backlight.max << 16;
-       I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl);
-
-       /* XXX: combine this into above write? */
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-
-       ctl2 = 0;
-       if (panel->backlight.active_low_pwm)
-               ctl2 |= BLM_POLARITY_I965;
-       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
-       POSTING_READ(VLV_BLC_PWM_CTL2(pipe));
-       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
-}
-
-static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
-       u32 pwm_ctl, val;
-
-       /* Controller 1 uses the utility pin. */
-       if (panel->backlight.controller == 1) {
-               val = I915_READ(UTIL_PIN_CTL);
-               if (val & UTIL_PIN_ENABLE) {
-                       DRM_DEBUG_KMS("util pin already enabled\n");
-                       val &= ~UTIL_PIN_ENABLE;
-                       I915_WRITE(UTIL_PIN_CTL, val);
-               }
-
-               val = 0;
-               if (panel->backlight.util_pin_active_low)
-                       val |= UTIL_PIN_POLARITY;
-               I915_WRITE(UTIL_PIN_CTL, val | UTIL_PIN_PIPE(pipe) |
-                               UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
-       }
-
-       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
-               DRM_DEBUG_KMS("backlight already enabled\n");
-               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
-               I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
-                               pwm_ctl);
-       }
-
-       I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller),
-                       panel->backlight.max);
-
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-
-       pwm_ctl = 0;
-       if (panel->backlight.active_low_pwm)
-               pwm_ctl |= BXT_BLC_PWM_POLARITY;
-
-       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
-       POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
-                       pwm_ctl | BXT_BLC_PWM_ENABLE);
-}
-
-static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pwm_ctl;
-
-       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
-               DRM_DEBUG_KMS("backlight already enabled\n");
-               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
-               I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
-                          pwm_ctl);
-       }
-
-       I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller),
-                  panel->backlight.max);
-
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-
-       pwm_ctl = 0;
-       if (panel->backlight.active_low_pwm)
-               pwm_ctl |= BXT_BLC_PWM_POLARITY;
-
-       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
-       POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-       I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
-                  pwm_ctl | BXT_BLC_PWM_ENABLE);
-}
-
-static void pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       pwm_enable(panel->backlight.pwm);
-       intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-}
-
-static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                          const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       if (panel->backlight.level <= panel->backlight.min) {
-               panel->backlight.level = panel->backlight.max;
-               if (panel->backlight.device)
-                       panel->backlight.device->props.brightness =
-                               scale_hw_to_user(connector,
-                                                panel->backlight.level,
-                                                panel->backlight.device->props.max_brightness);
-       }
-
-       panel->backlight.enable(crtc_state, conn_state);
-       panel->backlight.enabled = true;
-       if (panel->backlight.device)
-               panel->backlight.device->props.power = FB_BLANK_UNBLANK;
-}
-
-void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
-
-       if (!panel->backlight.present)
-               return;
-
-       DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       __intel_panel_enable_backlight(crtc_state, conn_state);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
-static u32 intel_panel_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 val = 0;
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       if (panel->backlight.enabled) {
-               val = panel->backlight.get(connector);
-               val = intel_panel_compute_brightness(connector, val);
-       }
-
-       mutex_unlock(&dev_priv->backlight_lock);
-
-       DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
-       return val;
-}
-
-/* set backlight brightness to level in range [0..max], scaling wrt hw min */
-static void intel_panel_set_backlight(const struct drm_connector_state *conn_state,
-                                     u32 user_level, u32 user_max)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 hw_level;
-
-       if (!panel->backlight.present)
-               return;
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       WARN_ON(panel->backlight.max == 0);
-
-       hw_level = scale_user_to_hw(connector, user_level, user_max);
-       panel->backlight.level = hw_level;
-
-       if (panel->backlight.enabled)
-               intel_panel_actually_set_backlight(conn_state, hw_level);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-static int intel_backlight_device_update_status(struct backlight_device *bd)
-{
-       struct intel_connector *connector = bl_get_data(bd);
-       struct intel_panel *panel = &connector->panel;
-       struct drm_device *dev = connector->base.dev;
-
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
-                     bd->props.brightness, bd->props.max_brightness);
-       intel_panel_set_backlight(connector->base.state, bd->props.brightness,
-                                 bd->props.max_brightness);
-
-       /*
-        * Allow flipping bl_power as a sub-state of enabled. Sadly the
-        * backlight class device does not make it easy to to differentiate
-        * between callbacks for brightness and bl_power, so our backlight_power
-        * callback needs to take this into account.
-        */
-       if (panel->backlight.enabled) {
-               if (panel->backlight.power) {
-                       bool enable = bd->props.power == FB_BLANK_UNBLANK &&
-                               bd->props.brightness != 0;
-                       panel->backlight.power(connector, enable);
-               }
-       } else {
-               bd->props.power = FB_BLANK_POWERDOWN;
-       }
-
-       drm_modeset_unlock(&dev->mode_config.connection_mutex);
-       return 0;
-}
-
-static int intel_backlight_device_get_brightness(struct backlight_device *bd)
-{
-       struct intel_connector *connector = bl_get_data(bd);
-       struct drm_device *dev = connector->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       intel_wakeref_t wakeref;
-       int ret = 0;
-
-       with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) {
-               u32 hw_level;
-
-               drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-
-               hw_level = intel_panel_get_backlight(connector);
-               ret = scale_hw_to_user(connector,
-                                      hw_level, bd->props.max_brightness);
-
-               drm_modeset_unlock(&dev->mode_config.connection_mutex);
-       }
-
-       return ret;
-}
-
-static const struct backlight_ops intel_backlight_device_ops = {
-       .update_status = intel_backlight_device_update_status,
-       .get_brightness = intel_backlight_device_get_brightness,
-};
-
-int intel_backlight_device_register(struct intel_connector *connector)
-{
-       struct intel_panel *panel = &connector->panel;
-       struct backlight_properties props;
-
-       if (WARN_ON(panel->backlight.device))
-               return -ENODEV;
-
-       if (!panel->backlight.present)
-               return 0;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       memset(&props, 0, sizeof(props));
-       props.type = BACKLIGHT_RAW;
-
-       /*
-        * Note: Everything should work even if the backlight device max
-        * presented to the userspace is arbitrarily chosen.
-        */
-       props.max_brightness = panel->backlight.max;
-       props.brightness = scale_hw_to_user(connector,
-                                           panel->backlight.level,
-                                           props.max_brightness);
-
-       if (panel->backlight.enabled)
-               props.power = FB_BLANK_UNBLANK;
-       else
-               props.power = FB_BLANK_POWERDOWN;
-
-       /*
-        * Note: using the same name independent of the connector prevents
-        * registration of multiple backlight devices in the driver.
-        */
-       panel->backlight.device =
-               backlight_device_register("intel_backlight",
-                                         connector->base.kdev,
-                                         connector,
-                                         &intel_backlight_device_ops, &props);
-
-       if (IS_ERR(panel->backlight.device)) {
-               DRM_ERROR("Failed to register backlight: %ld\n",
-                         PTR_ERR(panel->backlight.device));
-               panel->backlight.device = NULL;
-               return -ENODEV;
-       }
-
-       DRM_DEBUG_KMS("Connector %s backlight sysfs interface registered\n",
-                     connector->base.name);
-
-       return 0;
-}
-
-void intel_backlight_device_unregister(struct intel_connector *connector)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       if (panel->backlight.device) {
-               backlight_device_unregister(panel->backlight.device);
-               panel->backlight.device = NULL;
-       }
-}
-#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-
-/*
- * CNP: PWM clock frequency is 19.2 MHz or 24 MHz.
- *      PWM increment = 1
- */
-static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return DIV_ROUND_CLOSEST(KHz(dev_priv->rawclk_freq), pwm_freq_hz);
-}
-
-/*
- * BXT: PWM clock frequency = 19.2 MHz.
- */
-static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz);
-}
-
-/*
- * SPT: This value represents the period of the PWM stream in clock periods
- * multiplied by 16 (default increment) or 128 (alternate increment selected in
- * SCHICKEN_1 bit 0). PWM clock is 24 MHz.
- */
-static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct intel_panel *panel = &connector->panel;
-       u32 mul;
-
-       if (panel->backlight.alternate_pwm_increment)
-               mul = 128;
-       else
-               mul = 16;
-
-       return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul);
-}
-
-/*
- * LPT: This value represents the period of the PWM stream in clock periods
- * multiplied by 128 (default increment) or 16 (alternate increment, selected in
- * LPT SOUTH_CHICKEN2 register bit 5).
- */
-static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 mul, clock;
-
-       if (panel->backlight.alternate_pwm_increment)
-               mul = 16;
-       else
-               mul = 128;
-
-       if (HAS_PCH_LPT_H(dev_priv))
-               clock = MHz(135); /* LPT:H */
-       else
-               clock = MHz(24); /* LPT:LP */
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
-}
-
-/*
- * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH
- * display raw clocks multiplied by 128.
- */
-static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return DIV_ROUND_CLOSEST(KHz(dev_priv->rawclk_freq), pwm_freq_hz * 128);
-}
-
-/*
- * Gen2: This field determines the number of time base events (display core
- * clock frequency/32) in total for a complete cycle of modulated backlight
- * control.
- *
- * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock)
- * divided by 32.
- */
-static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int clock;
-
-       if (IS_PINEVIEW(dev_priv))
-               clock = KHz(dev_priv->rawclk_freq);
-       else
-               clock = KHz(dev_priv->cdclk.hw.cdclk);
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
-}
-
-/*
- * Gen4: This value represents the period of the PWM stream in display core
- * clocks ([DevCTG] HRAW clocks) multiplied by 128.
- *
- */
-static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int clock;
-
-       if (IS_G4X(dev_priv))
-               clock = KHz(dev_priv->rawclk_freq);
-       else
-               clock = KHz(dev_priv->cdclk.hw.cdclk);
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
-}
-
-/*
- * VLV: This value represents the period of the PWM stream in display core
- * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks
- * multiplied by 16. CHV uses a 19.2MHz S0IX clock.
- */
-static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int mul, clock;
-
-       if ((I915_READ(CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
-               if (IS_CHERRYVIEW(dev_priv))
-                       clock = KHz(19200);
-               else
-                       clock = MHz(25);
-               mul = 16;
-       } else {
-               clock = KHz(dev_priv->rawclk_freq);
-               mul = 128;
-       }
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
-}
-
-static u32 get_backlight_max_vbt(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-       u32 pwm;
-
-       if (!panel->backlight.hz_to_pwm) {
-               DRM_DEBUG_KMS("backlight frequency conversion not supported\n");
-               return 0;
-       }
-
-       if (pwm_freq_hz) {
-               DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n",
-                             pwm_freq_hz);
-       } else {
-               pwm_freq_hz = 200;
-               DRM_DEBUG_KMS("default backlight frequency %u Hz\n",
-                             pwm_freq_hz);
-       }
-
-       pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
-       if (!pwm) {
-               DRM_DEBUG_KMS("backlight frequency conversion failed\n");
-               return 0;
-       }
-
-       return pwm;
-}
-
-/*
- * Note: The setup hooks can't assume pipe is set!
- */
-static u32 get_backlight_min_vbt(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       int min;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       /*
-        * XXX: If the vbt value is 255, it makes min equal to max, which leads
-        * to problems. There are such machines out there. Either our
-        * interpretation is wrong or the vbt has bogus data. Or both. Safeguard
-        * against this by letting the minimum be at most (arbitrarily chosen)
-        * 25% of the max.
-        */
-       min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64);
-       if (min != dev_priv->vbt.backlight.min_brightness) {
-               DRM_DEBUG_KMS("clamping VBT min backlight %d/255 to %d/255\n",
-                             dev_priv->vbt.backlight.min_brightness, min);
-       }
-
-       /* vbt value is a coefficient in range [0..255] */
-       return scale(min, 0, 255, 0, panel->backlight.max);
-}
-
-static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
-       bool alt, cpu_mode;
-
-       if (HAS_PCH_LPT(dev_priv))
-               alt = I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
-       else
-               alt = I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
-       panel->backlight.alternate_pwm_increment = alt;
-
-       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
-       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
-
-       pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-       panel->backlight.max = pch_ctl2 >> 16;
-
-       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
-
-       if (!panel->backlight.max)
-               panel->backlight.max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       panel->backlight.enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
-
-       cpu_mode = panel->backlight.enabled && HAS_PCH_LPT(dev_priv) &&
-                  !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
-                  (cpu_ctl2 & BLM_PWM_ENABLE);
-       if (cpu_mode)
-               val = pch_get_backlight(connector);
-       else
-               val = lpt_get_backlight(connector);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       if (cpu_mode) {
-               DRM_DEBUG_KMS("CPU backlight register was enabled, switching to PCH override\n");
-
-               /* Write converted CPU PWM value to PCH override register */
-               lpt_set_backlight(connector->base.state, panel->backlight.level);
-               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
-
-               I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 & ~BLM_PWM_ENABLE);
-       }
-
-       return 0;
-}
-
-static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
-
-       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
-       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
-
-       pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-       panel->backlight.max = pch_ctl2 >> 16;
-
-       if (!panel->backlight.max)
-               panel->backlight.max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       val = pch_get_backlight(connector);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
-       panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
-               (pch_ctl1 & BLM_PCH_PWM_ENABLE);
-
-       return 0;
-}
-
-static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, val;
-
-       ctl = I915_READ(BLC_PWM_CTL);
-
-       if (IS_GEN(dev_priv, 2) || IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
-               panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
-
-       if (IS_PINEVIEW(dev_priv))
-               panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
-
-       panel->backlight.max = ctl >> 17;
-
-       if (!panel->backlight.max) {
-               panel->backlight.max = get_backlight_max_vbt(connector);
-               panel->backlight.max >>= 1;
-       }
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       if (panel->backlight.combination_mode)
-               panel->backlight.max *= 0xff;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       val = i9xx_get_backlight(connector);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       panel->backlight.enabled = val != 0;
-
-       return 0;
-}
-
-static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, ctl2, val;
-
-       ctl2 = I915_READ(BLC_PWM_CTL2);
-       panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
-       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
-
-       ctl = I915_READ(BLC_PWM_CTL);
-       panel->backlight.max = ctl >> 16;
-
-       if (!panel->backlight.max)
-               panel->backlight.max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       if (panel->backlight.combination_mode)
-               panel->backlight.max *= 0xff;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       val = i9xx_get_backlight(connector);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
-
-       return 0;
-}
-
-static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, ctl2, val;
-
-       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
-               return -ENODEV;
-
-       ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
-       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
-
-       ctl = I915_READ(VLV_BLC_PWM_CTL(pipe));
-       panel->backlight.max = ctl >> 16;
-
-       if (!panel->backlight.max)
-               panel->backlight.max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       val = _vlv_get_backlight(dev_priv, pipe);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
-
-       return 0;
-}
-
-static int
-bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pwm_ctl, val;
-
-       panel->backlight.controller = dev_priv->vbt.backlight.controller;
-
-       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-
-       /* Controller 1 uses the utility pin. */
-       if (panel->backlight.controller == 1) {
-               val = I915_READ(UTIL_PIN_CTL);
-               panel->backlight.util_pin_active_low =
-                                       val & UTIL_PIN_POLARITY;
-       }
-
-       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
-       panel->backlight.max =
-               I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller));
-
-       if (!panel->backlight.max)
-               panel->backlight.max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       val = bxt_get_backlight(connector);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
-
-       return 0;
-}
-
-static int
-cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pwm_ctl, val;
-
-       /*
-        * CNP has the BXT implementation of backlight, but with only one
-        * controller. TODO: ICP has multiple controllers but we only use
-        * controller 0 for now.
-        */
-       panel->backlight.controller = 0;
-
-       pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
-
-       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
-       panel->backlight.max =
-               I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller));
-
-       if (!panel->backlight.max)
-               panel->backlight.max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.max)
-               return -ENODEV;
-
-       panel->backlight.min = get_backlight_min_vbt(connector);
-
-       val = bxt_get_backlight(connector);
-       val = intel_panel_compute_brightness(connector, val);
-       panel->backlight.level = clamp(val, panel->backlight.min,
-                                      panel->backlight.max);
-
-       panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
-
-       return 0;
-}
-
-static int pwm_setup_backlight(struct intel_connector *connector,
-                              enum pipe pipe)
-{
-       struct drm_device *dev = connector->base.dev;
-       struct intel_panel *panel = &connector->panel;
-       int retval;
-
-       /* Get the PWM chip for backlight control */
-       panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight");
-       if (IS_ERR(panel->backlight.pwm)) {
-               DRM_ERROR("Failed to own the pwm chip\n");
-               panel->backlight.pwm = NULL;
-               return -ENODEV;
-       }
-
-       /*
-        * FIXME: pwm_apply_args() should be removed when switching to
-        * the atomic PWM API.
-        */
-       pwm_apply_args(panel->backlight.pwm);
-
-       retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS,
-                           CRC_PMIC_PWM_PERIOD_NS);
-       if (retval < 0) {
-               DRM_ERROR("Failed to configure the pwm chip\n");
-               pwm_put(panel->backlight.pwm);
-               panel->backlight.pwm = NULL;
-               return retval;
-       }
-
-       panel->backlight.min = 0; /* 0% */
-       panel->backlight.max = 100; /* 100% */
-       panel->backlight.level = DIV_ROUND_UP(
-                                pwm_get_duty_cycle(panel->backlight.pwm) * 100,
-                                CRC_PMIC_PWM_PERIOD_NS);
-       panel->backlight.enabled = panel->backlight.level != 0;
-
-       return 0;
-}
-
-void intel_panel_update_backlight(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       if (!panel->backlight.present)
-               return;
-
-       mutex_lock(&dev_priv->backlight_lock);
-       if (!panel->backlight.enabled)
-               __intel_panel_enable_backlight(crtc_state, conn_state);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_panel *panel = &intel_connector->panel;
-       int ret;
-
-       if (!dev_priv->vbt.backlight.present) {
-               if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
-                       DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n");
-               } else {
-                       DRM_DEBUG_KMS("no backlight present per VBT\n");
-                       return 0;
-               }
-       }
-
-       /* ensure intel_panel has been initialized first */
-       if (WARN_ON(!panel->backlight.setup))
-               return -ENODEV;
-
-       /* set level and max in panel struct */
-       mutex_lock(&dev_priv->backlight_lock);
-       ret = panel->backlight.setup(intel_connector, pipe);
-       mutex_unlock(&dev_priv->backlight_lock);
-
-       if (ret) {
-               DRM_DEBUG_KMS("failed to setup backlight for connector %s\n",
-                             connector->name);
-               return ret;
-       }
-
-       panel->backlight.present = true;
-
-       DRM_DEBUG_KMS("Connector %s backlight initialized, %s, brightness %u/%u\n",
-                     connector->name,
-                     enableddisabled(panel->backlight.enabled),
-                     panel->backlight.level, panel->backlight.max);
-
-       return 0;
-}
-
-static void intel_panel_destroy_backlight(struct intel_panel *panel)
-{
-       /* dispose of the pwm */
-       if (panel->backlight.pwm)
-               pwm_put(panel->backlight.pwm);
-
-       panel->backlight.present = false;
-}
-
-/* Set up chip specific backlight functions */
-static void
-intel_panel_init_backlight_funcs(struct intel_panel *panel)
-{
-       struct intel_connector *connector =
-               container_of(panel, struct intel_connector, panel);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
-           intel_dp_aux_init_backlight_funcs(connector) == 0)
-               return;
-
-       if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
-           intel_dsi_dcs_init_backlight_funcs(connector) == 0)
-               return;
-
-       if (IS_GEN9_LP(dev_priv)) {
-               panel->backlight.setup = bxt_setup_backlight;
-               panel->backlight.enable = bxt_enable_backlight;
-               panel->backlight.disable = bxt_disable_backlight;
-               panel->backlight.set = bxt_set_backlight;
-               panel->backlight.get = bxt_get_backlight;
-               panel->backlight.hz_to_pwm = bxt_hz_to_pwm;
-       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
-               panel->backlight.setup = cnp_setup_backlight;
-               panel->backlight.enable = cnp_enable_backlight;
-               panel->backlight.disable = cnp_disable_backlight;
-               panel->backlight.set = bxt_set_backlight;
-               panel->backlight.get = bxt_get_backlight;
-               panel->backlight.hz_to_pwm = cnp_hz_to_pwm;
-       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
-               panel->backlight.setup = lpt_setup_backlight;
-               panel->backlight.enable = lpt_enable_backlight;
-               panel->backlight.disable = lpt_disable_backlight;
-               panel->backlight.set = lpt_set_backlight;
-               panel->backlight.get = lpt_get_backlight;
-               if (HAS_PCH_LPT(dev_priv))
-                       panel->backlight.hz_to_pwm = lpt_hz_to_pwm;
-               else
-                       panel->backlight.hz_to_pwm = spt_hz_to_pwm;
-       } else if (HAS_PCH_SPLIT(dev_priv)) {
-               panel->backlight.setup = pch_setup_backlight;
-               panel->backlight.enable = pch_enable_backlight;
-               panel->backlight.disable = pch_disable_backlight;
-               panel->backlight.set = pch_set_backlight;
-               panel->backlight.get = pch_get_backlight;
-               panel->backlight.hz_to_pwm = pch_hz_to_pwm;
-       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
-                       panel->backlight.setup = pwm_setup_backlight;
-                       panel->backlight.enable = pwm_enable_backlight;
-                       panel->backlight.disable = pwm_disable_backlight;
-                       panel->backlight.set = pwm_set_backlight;
-                       panel->backlight.get = pwm_get_backlight;
-               } else {
-                       panel->backlight.setup = vlv_setup_backlight;
-                       panel->backlight.enable = vlv_enable_backlight;
-                       panel->backlight.disable = vlv_disable_backlight;
-                       panel->backlight.set = vlv_set_backlight;
-                       panel->backlight.get = vlv_get_backlight;
-                       panel->backlight.hz_to_pwm = vlv_hz_to_pwm;
-               }
-       } else if (IS_GEN(dev_priv, 4)) {
-               panel->backlight.setup = i965_setup_backlight;
-               panel->backlight.enable = i965_enable_backlight;
-               panel->backlight.disable = i965_disable_backlight;
-               panel->backlight.set = i9xx_set_backlight;
-               panel->backlight.get = i9xx_get_backlight;
-               panel->backlight.hz_to_pwm = i965_hz_to_pwm;
-       } else {
-               panel->backlight.setup = i9xx_setup_backlight;
-               panel->backlight.enable = i9xx_enable_backlight;
-               panel->backlight.disable = i9xx_disable_backlight;
-               panel->backlight.set = i9xx_set_backlight;
-               panel->backlight.get = i9xx_get_backlight;
-               panel->backlight.hz_to_pwm = i9xx_hz_to_pwm;
-       }
-}
-
-int intel_panel_init(struct intel_panel *panel,
-                    struct drm_display_mode *fixed_mode,
-                    struct drm_display_mode *downclock_mode)
-{
-       intel_panel_init_backlight_funcs(panel);
-
-       panel->fixed_mode = fixed_mode;
-       panel->downclock_mode = downclock_mode;
-
-       return 0;
-}
-
-void intel_panel_fini(struct intel_panel *panel)
-{
-       struct intel_connector *intel_connector =
-               container_of(panel, struct intel_connector, panel);
-
-       intel_panel_destroy_backlight(panel);
-
-       if (panel->fixed_mode)
-               drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
-
-       if (panel->downclock_mode)
-               drm_mode_destroy(intel_connector->base.dev,
-                               panel->downclock_mode);
-}
diff --git a/drivers/gpu/drm/i915/intel_panel.h b/drivers/gpu/drm/i915/intel_panel.h
deleted file mode 100644 (file)
index cedeea4..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_PANEL_H__
-#define __INTEL_PANEL_H__
-
-#include <linux/types.h>
-
-#include "intel_display.h"
-
-struct drm_connector;
-struct drm_connector_state;
-struct drm_display_mode;
-struct intel_connector;
-struct intel_crtc;
-struct intel_crtc_state;
-struct intel_encoder;
-struct intel_panel;
-
-int intel_panel_init(struct intel_panel *panel,
-                    struct drm_display_mode *fixed_mode,
-                    struct drm_display_mode *downclock_mode);
-void intel_panel_fini(struct intel_panel *panel);
-void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
-                           struct drm_display_mode *adjusted_mode);
-void intel_pch_panel_fitting(struct intel_crtc *crtc,
-                            struct intel_crtc_state *pipe_config,
-                            int fitting_mode);
-void intel_gmch_panel_fitting(struct intel_crtc *crtc,
-                             struct intel_crtc_state *pipe_config,
-                             int fitting_mode);
-void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
-                                   u32 level, u32 max);
-int intel_panel_setup_backlight(struct drm_connector *connector,
-                               enum pipe pipe);
-void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state);
-void intel_panel_update_backlight(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state);
-void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state);
-struct drm_display_mode *
-intel_panel_edid_downclock_mode(struct intel_connector *connector,
-                               const struct drm_display_mode *fixed_mode);
-struct drm_display_mode *
-intel_panel_edid_fixed_mode(struct intel_connector *connector);
-struct drm_display_mode *
-intel_panel_vbt_fixed_mode(struct intel_connector *connector);
-
-#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
-int intel_backlight_device_register(struct intel_connector *connector);
-void intel_backlight_device_unregister(struct intel_connector *connector);
-#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-static inline int intel_backlight_device_register(struct intel_connector *connector)
-{
-       return 0;
-}
-static inline void intel_backlight_device_unregister(struct intel_connector *connector)
-{
-}
-#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-
-#endif /* __INTEL_PANEL_H__ */
index 01ca502099df11af1e8c8a28513589cf090a8308..69709df4a648fe644fd92649952101138725e2ad 100644 (file)
@@ -23,8 +23,9 @@
 
 #include <drm/drm_atomic_helper.h>
 
+#include "display/intel_dp.h"
+
 #include "i915_drv.h"
-#include "intel_dp.h"
 #include "intel_drv.h"
 #include "intel_psr.h"
 #include "intel_sprite.h"
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
deleted file mode 100644 (file)
index 0860ae3..0000000
+++ /dev/null
@@ -1,3333 +0,0 @@
-/*
- * Copyright 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2007 Intel Corporation
- *   Jesse Barnes <jesse.barnes@intel.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- */
-
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_atomic.h"
-#include "intel_connector.h"
-#include "intel_drv.h"
-#include "intel_fifo_underrun.h"
-#include "intel_gmbus.h"
-#include "intel_hdmi.h"
-#include "intel_hotplug.h"
-#include "intel_panel.h"
-#include "intel_sdvo.h"
-#include "intel_sdvo_regs.h"
-
-#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)
-#define SDVO_RGB_MASK  (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)
-#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
-#define SDVO_TV_MASK   (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0)
-
-#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
-                       SDVO_TV_MASK)
-
-#define IS_TV(c)       (c->output_flag & SDVO_TV_MASK)
-#define IS_TMDS(c)     (c->output_flag & SDVO_TMDS_MASK)
-#define IS_LVDS(c)     (c->output_flag & SDVO_LVDS_MASK)
-#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
-#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK))
-
-
-static const char * const tv_format_names[] = {
-       "NTSC_M"   , "NTSC_J"  , "NTSC_443",
-       "PAL_B"    , "PAL_D"   , "PAL_G"   ,
-       "PAL_H"    , "PAL_I"   , "PAL_M"   ,
-       "PAL_N"    , "PAL_NC"  , "PAL_60"  ,
-       "SECAM_B"  , "SECAM_D" , "SECAM_G" ,
-       "SECAM_K"  , "SECAM_K1", "SECAM_L" ,
-       "SECAM_60"
-};
-
-#define TV_FORMAT_NUM  ARRAY_SIZE(tv_format_names)
-
-struct intel_sdvo {
-       struct intel_encoder base;
-
-       struct i2c_adapter *i2c;
-       u8 slave_addr;
-
-       struct i2c_adapter ddc;
-
-       /* Register for the SDVO device: SDVOB or SDVOC */
-       i915_reg_t sdvo_reg;
-
-       /* Active outputs controlled by this SDVO output */
-       u16 controlled_output;
-
-       /*
-        * Capabilities of the SDVO device returned by
-        * intel_sdvo_get_capabilities()
-        */
-       struct intel_sdvo_caps caps;
-
-       /* Pixel clock limitations reported by the SDVO device, in kHz */
-       int pixel_clock_min, pixel_clock_max;
-
-       /*
-       * For multiple function SDVO device,
-       * this is for current attached outputs.
-       */
-       u16 attached_output;
-
-       /*
-        * Hotplug activation bits for this device
-        */
-       u16 hotplug_active;
-
-       enum port port;
-
-       bool has_hdmi_monitor;
-       bool has_hdmi_audio;
-
-       /* DDC bus used by this SDVO encoder */
-       u8 ddc_bus;
-
-       /*
-        * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd
-        */
-       u8 dtd_sdvo_flags;
-};
-
-struct intel_sdvo_connector {
-       struct intel_connector base;
-
-       /* Mark the type of connector */
-       u16 output_flag;
-
-       /* This contains all current supported TV format */
-       u8 tv_format_supported[TV_FORMAT_NUM];
-       int   format_supported_num;
-       struct drm_property *tv_format;
-
-       /* add the property for the SDVO-TV */
-       struct drm_property *left;
-       struct drm_property *right;
-       struct drm_property *top;
-       struct drm_property *bottom;
-       struct drm_property *hpos;
-       struct drm_property *vpos;
-       struct drm_property *contrast;
-       struct drm_property *saturation;
-       struct drm_property *hue;
-       struct drm_property *sharpness;
-       struct drm_property *flicker_filter;
-       struct drm_property *flicker_filter_adaptive;
-       struct drm_property *flicker_filter_2d;
-       struct drm_property *tv_chroma_filter;
-       struct drm_property *tv_luma_filter;
-       struct drm_property *dot_crawl;
-
-       /* add the property for the SDVO-TV/LVDS */
-       struct drm_property *brightness;
-
-       /* this is to get the range of margin.*/
-       u32 max_hscan, max_vscan;
-
-       /**
-        * This is set if we treat the device as HDMI, instead of DVI.
-        */
-       bool is_hdmi;
-};
-
-struct intel_sdvo_connector_state {
-       /* base.base: tv.saturation/contrast/hue/brightness */
-       struct intel_digital_connector_state base;
-
-       struct {
-               unsigned overscan_h, overscan_v, hpos, vpos, sharpness;
-               unsigned flicker_filter, flicker_filter_2d, flicker_filter_adaptive;
-               unsigned chroma_filter, luma_filter, dot_crawl;
-       } tv;
-};
-
-static struct intel_sdvo *to_sdvo(struct intel_encoder *encoder)
-{
-       return container_of(encoder, struct intel_sdvo, base);
-}
-
-static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
-{
-       return to_sdvo(intel_attached_encoder(connector));
-}
-
-static struct intel_sdvo_connector *
-to_intel_sdvo_connector(struct drm_connector *connector)
-{
-       return container_of(connector, struct intel_sdvo_connector, base.base);
-}
-
-#define to_intel_sdvo_connector_state(conn_state) \
-       container_of((conn_state), struct intel_sdvo_connector_state, base.base)
-
-static bool
-intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags);
-static bool
-intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
-                             struct intel_sdvo_connector *intel_sdvo_connector,
-                             int type);
-static bool
-intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
-                                  struct intel_sdvo_connector *intel_sdvo_connector);
-
-/*
- * Writes the SDVOB or SDVOC with the given value, but always writes both
- * SDVOB and SDVOC to work around apparent hardware issues (according to
- * comments in the BIOS).
- */
-static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
-{
-       struct drm_device *dev = intel_sdvo->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 bval = val, cval = val;
-       int i;
-
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               I915_WRITE(intel_sdvo->sdvo_reg, val);
-               POSTING_READ(intel_sdvo->sdvo_reg);
-               /*
-                * HW workaround, need to write this twice for issue
-                * that may result in first write getting masked.
-                */
-               if (HAS_PCH_IBX(dev_priv)) {
-                       I915_WRITE(intel_sdvo->sdvo_reg, val);
-                       POSTING_READ(intel_sdvo->sdvo_reg);
-               }
-               return;
-       }
-
-       if (intel_sdvo->port == PORT_B)
-               cval = I915_READ(GEN3_SDVOC);
-       else
-               bval = I915_READ(GEN3_SDVOB);
-
-       /*
-        * Write the registers twice for luck. Sometimes,
-        * writing them only once doesn't appear to 'stick'.
-        * The BIOS does this too. Yay, magic
-        */
-       for (i = 0; i < 2; i++) {
-               I915_WRITE(GEN3_SDVOB, bval);
-               POSTING_READ(GEN3_SDVOB);
-
-               I915_WRITE(GEN3_SDVOC, cval);
-               POSTING_READ(GEN3_SDVOC);
-       }
-}
-
-static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
-{
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = intel_sdvo->slave_addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &addr,
-               },
-               {
-                       .addr = intel_sdvo->slave_addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = ch,
-               }
-       };
-       int ret;
-
-       if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
-               return true;
-
-       DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
-       return false;
-}
-
-#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
-/** Mapping of command numbers to names, for debug output */
-static const struct _sdvo_cmd_name {
-       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),
-
-       /* 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),
-
-       /* 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),
-};
-
-#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)
-{
-       int i, pos = 0;
-#define BUF_LEN 256
-       char buffer[BUF_LEN];
-
-#define BUF_PRINT(args...) \
-       pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args)
-
-
-       for (i = 0; i < args_len; i++) {
-               BUF_PRINT("%02X ", ((u8 *)args)[i]);
-       }
-       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)) {
-               BUF_PRINT("(%02X)", cmd);
-       }
-       BUG_ON(pos >= BUF_LEN - 1);
-#undef BUF_PRINT
-#undef BUF_LEN
-
-       DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer);
-}
-
-static const char * const cmd_status_names[] = {
-       "Power on",
-       "Success",
-       "Not supported",
-       "Invalid arg",
-       "Pending",
-       "Target not specified",
-       "Scaling not supported"
-};
-
-static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
-                                  const void *args, int args_len,
-                                  bool unlocked)
-{
-       u8 *buf, status;
-       struct i2c_msg *msgs;
-       int i, ret = true;
-
-       /* Would be simpler to allocate both in one go ? */
-       buf = kzalloc(args_len * 2 + 2, GFP_KERNEL);
-       if (!buf)
-               return false;
-
-       msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL);
-       if (!msgs) {
-               kfree(buf);
-               return false;
-       }
-
-       intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
-
-       for (i = 0; i < args_len; i++) {
-               msgs[i].addr = intel_sdvo->slave_addr;
-               msgs[i].flags = 0;
-               msgs[i].len = 2;
-               msgs[i].buf = buf + 2 *i;
-               buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
-               buf[2*i + 1] = ((u8*)args)[i];
-       }
-       msgs[i].addr = intel_sdvo->slave_addr;
-       msgs[i].flags = 0;
-       msgs[i].len = 2;
-       msgs[i].buf = buf + 2*i;
-       buf[2*i + 0] = SDVO_I2C_OPCODE;
-       buf[2*i + 1] = cmd;
-
-       /* the following two are to read the response */
-       status = SDVO_I2C_CMD_STATUS;
-       msgs[i+1].addr = intel_sdvo->slave_addr;
-       msgs[i+1].flags = 0;
-       msgs[i+1].len = 1;
-       msgs[i+1].buf = &status;
-
-       msgs[i+2].addr = intel_sdvo->slave_addr;
-       msgs[i+2].flags = I2C_M_RD;
-       msgs[i+2].len = 1;
-       msgs[i+2].buf = &status;
-
-       if (unlocked)
-               ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
-       else
-               ret = __i2c_transfer(intel_sdvo->i2c, msgs, i+3);
-       if (ret < 0) {
-               DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
-               ret = false;
-               goto out;
-       }
-       if (ret != i+3) {
-               /* failure in I2C transfer */
-               DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
-               ret = false;
-       }
-
-out:
-       kfree(msgs);
-       kfree(buf);
-       return ret;
-}
-
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
-                                const void *args, int args_len)
-{
-       return __intel_sdvo_write_cmd(intel_sdvo, cmd, args, args_len, true);
-}
-
-static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
-                                    void *response, int response_len)
-{
-       u8 retry = 15; /* 5 quick checks, followed by 10 long checks */
-       u8 status;
-       int i, pos = 0;
-#define BUF_LEN 256
-       char buffer[BUF_LEN];
-
-       buffer[0] = '\0';
-
-       /*
-        * The documentation states that all commands will be
-        * processed within 15µs, and that we need only poll
-        * the status byte a maximum of 3 times in order for the
-        * command to be complete.
-        *
-        * Check 5 times in case the hardware failed to read the docs.
-        *
-        * Also beware that the first response by many devices is to
-        * reply PENDING and stall for time. TVs are notorious for
-        * requiring longer than specified to complete their replies.
-        * Originally (in the DDX long ago), the delay was only ever 15ms
-        * with an additional delay of 30ms applied for TVs added later after
-        * many experiments. To accommodate both sets of delays, we do a
-        * sequence of slow checks if the device is falling behind and fails
-        * to reply within 5*15µs.
-        */
-       if (!intel_sdvo_read_byte(intel_sdvo,
-                                 SDVO_I2C_CMD_STATUS,
-                                 &status))
-               goto log_fail;
-
-       while ((status == SDVO_CMD_STATUS_PENDING ||
-               status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && --retry) {
-               if (retry < 10)
-                       msleep(15);
-               else
-                       udelay(15);
-
-               if (!intel_sdvo_read_byte(intel_sdvo,
-                                         SDVO_I2C_CMD_STATUS,
-                                         &status))
-                       goto log_fail;
-       }
-
-#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]);
-       else
-               BUF_PRINT("(??? %d)", status);
-
-       if (status != SDVO_CMD_STATUS_SUCCESS)
-               goto log_fail;
-
-       /* Read the command response */
-       for (i = 0; i < response_len; i++) {
-               if (!intel_sdvo_read_byte(intel_sdvo,
-                                         SDVO_I2C_RETURN_0 + i,
-                                         &((u8 *)response)[i]))
-                       goto log_fail;
-               BUF_PRINT(" %02X", ((u8 *)response)[i]);
-       }
-       BUG_ON(pos >= BUF_LEN - 1);
-#undef BUF_PRINT
-#undef BUF_LEN
-
-       DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer);
-       return true;
-
-log_fail:
-       DRM_DEBUG_KMS("%s: R: ... failed %s\n",
-                     SDVO_NAME(intel_sdvo), buffer);
-       return false;
-}
-
-static int intel_sdvo_get_pixel_multiplier(const struct drm_display_mode *adjusted_mode)
-{
-       if (adjusted_mode->crtc_clock >= 100000)
-               return 1;
-       else if (adjusted_mode->crtc_clock >= 50000)
-               return 2;
-       else
-               return 4;
-}
-
-static bool __intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
-                                               u8 ddc_bus)
-{
-       /* This must be the immediately preceding write before the i2c xfer */
-       return __intel_sdvo_write_cmd(intel_sdvo,
-                                     SDVO_CMD_SET_CONTROL_BUS_SWITCH,
-                                     &ddc_bus, 1, false);
-}
-
-static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
-{
-       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
-               return false;
-
-       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
-}
-
-static bool
-intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len)
-{
-       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0))
-               return false;
-
-       return intel_sdvo_read_response(intel_sdvo, value, len);
-}
-
-static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo)
-{
-       struct intel_sdvo_set_target_input_args targets = {0};
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_TARGET_INPUT,
-                                   &targets, sizeof(targets));
-}
-
-/*
- * Return whether each input is trained.
- *
- * This function is making an assumption about the layout of the response,
- * which should be checked against the docs.
- */
-static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2)
-{
-       struct intel_sdvo_get_trained_inputs_response response;
-
-       BUILD_BUG_ON(sizeof(response) != 1);
-       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS,
-                                 &response, sizeof(response)))
-               return false;
-
-       *input_1 = response.input0_trained;
-       *input_2 = response.input1_trained;
-       return true;
-}
-
-static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,
-                                         u16 outputs)
-{
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_ACTIVE_OUTPUTS,
-                                   &outputs, sizeof(outputs));
-}
-
-static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
-                                         u16 *outputs)
-{
-       return intel_sdvo_get_value(intel_sdvo,
-                                   SDVO_CMD_GET_ACTIVE_OUTPUTS,
-                                   outputs, sizeof(*outputs));
-}
-
-static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
-                                              int mode)
-{
-       u8 state = SDVO_ENCODER_STATE_ON;
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               state = SDVO_ENCODER_STATE_ON;
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-               state = SDVO_ENCODER_STATE_STANDBY;
-               break;
-       case DRM_MODE_DPMS_SUSPEND:
-               state = SDVO_ENCODER_STATE_SUSPEND;
-               break;
-       case DRM_MODE_DPMS_OFF:
-               state = SDVO_ENCODER_STATE_OFF;
-               break;
-       }
-
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state));
-}
-
-static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo,
-                                                  int *clock_min,
-                                                  int *clock_max)
-{
-       struct intel_sdvo_pixel_clock_range clocks;
-
-       BUILD_BUG_ON(sizeof(clocks) != 4);
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
-                                 &clocks, sizeof(clocks)))
-               return false;
-
-       /* Convert the values from units of 10 kHz to kHz. */
-       *clock_min = clocks.min * 10;
-       *clock_max = clocks.max * 10;
-       return true;
-}
-
-static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo,
-                                        u16 outputs)
-{
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_TARGET_OUTPUT,
-                                   &outputs, sizeof(outputs));
-}
-
-static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
-                                 struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
-               intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
-}
-
-static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
-                                 struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
-               intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
-}
-
-static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
-                                        struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_set_timing(intel_sdvo,
-                                    SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
-}
-
-static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,
-                                        struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_set_timing(intel_sdvo,
-                                    SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
-}
-
-static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
-                                       struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_get_timing(intel_sdvo,
-                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
-}
-
-static bool
-intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
-                                        struct intel_sdvo_connector *intel_sdvo_connector,
-                                        u16 clock,
-                                        u16 width,
-                                        u16 height)
-{
-       struct intel_sdvo_preferred_input_timing_args args;
-
-       memset(&args, 0, sizeof(args));
-       args.clock = clock;
-       args.width = width;
-       args.height = height;
-       args.interlace = 0;
-
-       if (IS_LVDS(intel_sdvo_connector)) {
-               const struct drm_display_mode *fixed_mode =
-                       intel_sdvo_connector->base.panel.fixed_mode;
-
-               if (fixed_mode->hdisplay != width ||
-                   fixed_mode->vdisplay != height)
-                       args.scaled = 1;
-       }
-
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
-                                   &args, sizeof(args));
-}
-
-static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo,
-                                                 struct intel_sdvo_dtd *dtd)
-{
-       BUILD_BUG_ON(sizeof(dtd->part1) != 8);
-       BUILD_BUG_ON(sizeof(dtd->part2) != 8);
-       return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
-                                   &dtd->part1, sizeof(dtd->part1)) &&
-               intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
-                                    &dtd->part2, sizeof(dtd->part2));
-}
-
-static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val)
-{
-       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
-}
-
-static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
-                                        const struct drm_display_mode *mode)
-{
-       u16 width, height;
-       u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
-       u16 h_sync_offset, v_sync_offset;
-       int mode_clock;
-
-       memset(dtd, 0, sizeof(*dtd));
-
-       width = mode->hdisplay;
-       height = mode->vdisplay;
-
-       /* do some mode translations */
-       h_blank_len = mode->htotal - mode->hdisplay;
-       h_sync_len = mode->hsync_end - mode->hsync_start;
-
-       v_blank_len = mode->vtotal - mode->vdisplay;
-       v_sync_len = mode->vsync_end - mode->vsync_start;
-
-       h_sync_offset = mode->hsync_start - mode->hdisplay;
-       v_sync_offset = mode->vsync_start - mode->vdisplay;
-
-       mode_clock = mode->clock;
-       mode_clock /= 10;
-       dtd->part1.clock = mode_clock;
-
-       dtd->part1.h_active = width & 0xff;
-       dtd->part1.h_blank = h_blank_len & 0xff;
-       dtd->part1.h_high = (((width >> 8) & 0xf) << 4) |
-               ((h_blank_len >> 8) & 0xf);
-       dtd->part1.v_active = height & 0xff;
-       dtd->part1.v_blank = v_blank_len & 0xff;
-       dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
-               ((v_blank_len >> 8) & 0xf);
-
-       dtd->part2.h_sync_off = h_sync_offset & 0xff;
-       dtd->part2.h_sync_width = h_sync_len & 0xff;
-       dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
-               (v_sync_len & 0xf);
-       dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
-               ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
-               ((v_sync_len & 0x30) >> 4);
-
-       dtd->part2.dtd_flags = 0x18;
-       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-               dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-               dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE;
-       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-               dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
-
-       dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
-}
-
-static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode,
-                                        const struct intel_sdvo_dtd *dtd)
-{
-       struct drm_display_mode mode = {};
-
-       mode.hdisplay = dtd->part1.h_active;
-       mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
-       mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
-       mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
-       mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
-       mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
-       mode.htotal = mode.hdisplay + dtd->part1.h_blank;
-       mode.htotal += (dtd->part1.h_high & 0xf) << 8;
-
-       mode.vdisplay = dtd->part1.v_active;
-       mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
-       mode.vsync_start = mode.vdisplay;
-       mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
-       mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
-       mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0;
-       mode.vsync_end = mode.vsync_start +
-               (dtd->part2.v_sync_off_width & 0xf);
-       mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
-       mode.vtotal = mode.vdisplay + dtd->part1.v_blank;
-       mode.vtotal += (dtd->part1.v_high & 0xf) << 8;
-
-       mode.clock = dtd->part1.clock * 10;
-
-       if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
-               mode.flags |= DRM_MODE_FLAG_INTERLACE;
-       if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
-               mode.flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               mode.flags |= DRM_MODE_FLAG_NHSYNC;
-       if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
-               mode.flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               mode.flags |= DRM_MODE_FLAG_NVSYNC;
-
-       drm_mode_set_crtcinfo(&mode, 0);
-
-       drm_mode_copy(pmode, &mode);
-}
-
-static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
-{
-       struct intel_sdvo_encode encode;
-
-       BUILD_BUG_ON(sizeof(encode) != 2);
-       return intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_SUPP_ENCODE,
-                                 &encode, sizeof(encode));
-}
-
-static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
-                                 u8 mode)
-{
-       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1);
-}
-
-static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo,
-                                      u8 mode)
-{
-       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
-}
-
-static bool intel_sdvo_set_audio_state(struct intel_sdvo *intel_sdvo,
-                                      u8 audio_state)
-{
-       return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_AUDIO_STAT,
-                                   &audio_state, 1);
-}
-
-#if 0
-static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
-{
-       int i, j;
-       u8 set_buf_index[2];
-       u8 av_split;
-       u8 buf_size;
-       u8 buf[48];
-       u8 *pos;
-
-       intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1);
-
-       for (i = 0; i <= av_split; i++) {
-               set_buf_index[0] = i; set_buf_index[1] = 0;
-               intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX,
-                                    set_buf_index, 2);
-               intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
-               intel_sdvo_read_response(encoder, &buf_size, 1);
-
-               pos = buf;
-               for (j = 0; j <= buf_size; j += 8) {
-                       intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA,
-                                            NULL, 0);
-                       intel_sdvo_read_response(encoder, pos, 8);
-                       pos += 8;
-               }
-       }
-}
-#endif
-
-static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
-                                      unsigned int if_index, u8 tx_rate,
-                                      const u8 *data, unsigned int length)
-{
-       u8 set_buf_index[2] = { if_index, 0 };
-       u8 hbuf_size, tmp[8];
-       int i;
-
-       if (!intel_sdvo_set_value(intel_sdvo,
-                                 SDVO_CMD_SET_HBUF_INDEX,
-                                 set_buf_index, 2))
-               return false;
-
-       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
-                                 &hbuf_size, 1))
-               return false;
-
-       /* Buffer size is 0 based, hooray! */
-       hbuf_size++;
-
-       DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
-                     if_index, length, hbuf_size);
-
-       if (hbuf_size < length)
-               return false;
-
-       for (i = 0; i < hbuf_size; i += 8) {
-               memset(tmp, 0, 8);
-               if (i < length)
-                       memcpy(tmp, data + i, min_t(unsigned, 8, length - i));
-
-               if (!intel_sdvo_set_value(intel_sdvo,
-                                         SDVO_CMD_SET_HBUF_DATA,
-                                         tmp, 8))
-                       return false;
-       }
-
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_HBUF_TXRATE,
-                                   &tx_rate, 1);
-}
-
-static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
-                                        unsigned int if_index,
-                                        u8 *data, unsigned int length)
-{
-       u8 set_buf_index[2] = { if_index, 0 };
-       u8 hbuf_size, tx_rate, av_split;
-       int i;
-
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_HBUF_AV_SPLIT,
-                                 &av_split, 1))
-               return -ENXIO;
-
-       if (av_split < if_index)
-               return 0;
-
-       if (!intel_sdvo_set_value(intel_sdvo,
-                                 SDVO_CMD_SET_HBUF_INDEX,
-                                 set_buf_index, 2))
-               return -ENXIO;
-
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_HBUF_TXRATE,
-                                 &tx_rate, 1))
-               return -ENXIO;
-
-       if (tx_rate == SDVO_HBUF_TX_DISABLED)
-               return 0;
-
-       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
-                                 &hbuf_size, 1))
-               return -ENXIO;
-
-       /* Buffer size is 0 based, hooray! */
-       hbuf_size++;
-
-       DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
-                     if_index, length, hbuf_size);
-
-       hbuf_size = min_t(unsigned int, length, hbuf_size);
-
-       for (i = 0; i < hbuf_size; i += 8) {
-               if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
-                       return -ENXIO;
-               if (!intel_sdvo_read_response(intel_sdvo, &data[i],
-                                             min_t(unsigned int, 8, hbuf_size - i)))
-                       return -ENXIO;
-       }
-
-       return hbuf_size;
-}
-
-static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
-                                            struct intel_crtc_state *crtc_state,
-                                            struct drm_connector_state *conn_state)
-{
-       struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       int ret;
-
-       if (!crtc_state->has_hdmi_sink)
-               return true;
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
-
-       ret = drm_hdmi_avi_infoframe_from_display_mode(frame,
-                                                      conn_state->connector,
-                                                      adjusted_mode);
-       if (ret)
-               return false;
-
-       drm_hdmi_avi_infoframe_quant_range(frame,
-                                          conn_state->connector,
-                                          adjusted_mode,
-                                          crtc_state->limited_color_range ?
-                                          HDMI_QUANTIZATION_RANGE_LIMITED :
-                                          HDMI_QUANTIZATION_RANGE_FULL);
-
-       ret = hdmi_avi_infoframe_check(frame);
-       if (WARN_ON(ret))
-               return false;
-
-       return true;
-}
-
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
-                                        const struct intel_crtc_state *crtc_state)
-{
-       u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
-       const union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
-       ssize_t len;
-
-       if ((crtc_state->infoframes.enable &
-            intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI)) == 0)
-               return true;
-
-       if (WARN_ON(frame->any.type != HDMI_INFOFRAME_TYPE_AVI))
-               return false;
-
-       len = hdmi_infoframe_pack_only(frame, sdvo_data, sizeof(sdvo_data));
-       if (WARN_ON(len < 0))
-               return false;
-
-       return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
-                                         SDVO_HBUF_TX_VSYNC,
-                                         sdvo_data, len);
-}
-
-static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
-                                        struct intel_crtc_state *crtc_state)
-{
-       u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
-       union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
-       ssize_t len;
-       int ret;
-
-       if (!crtc_state->has_hdmi_sink)
-               return;
-
-       len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
-                                       sdvo_data, sizeof(sdvo_data));
-       if (len < 0) {
-               DRM_DEBUG_KMS("failed to read AVI infoframe\n");
-               return;
-       } else if (len == 0) {
-               return;
-       }
-
-       crtc_state->infoframes.enable |=
-               intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
-
-       ret = hdmi_infoframe_unpack(frame, sdvo_data, len);
-       if (ret) {
-               DRM_DEBUG_KMS("Failed to unpack AVI infoframe\n");
-               return;
-       }
-
-       if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
-               DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
-                             frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
-}
-
-static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
-                                    const struct drm_connector_state *conn_state)
-{
-       struct intel_sdvo_tv_format format;
-       u32 format_map;
-
-       format_map = 1 << conn_state->tv.mode;
-       memset(&format, 0, sizeof(format));
-       memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map)));
-
-       BUILD_BUG_ON(sizeof(format) != 6);
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_TV_FORMAT,
-                                   &format, sizeof(format));
-}
-
-static bool
-intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
-                                       const struct drm_display_mode *mode)
-{
-       struct intel_sdvo_dtd output_dtd;
-
-       if (!intel_sdvo_set_target_output(intel_sdvo,
-                                         intel_sdvo->attached_output))
-               return false;
-
-       intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
-       if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
-               return false;
-
-       return true;
-}
-
-/*
- * Asks the sdvo controller for the preferred input mode given the output mode.
- * Unfortunately we have to set up the full output mode to do that.
- */
-static bool
-intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
-                                   struct intel_sdvo_connector *intel_sdvo_connector,
-                                   const struct drm_display_mode *mode,
-                                   struct drm_display_mode *adjusted_mode)
-{
-       struct intel_sdvo_dtd input_dtd;
-
-       /* Reset the input timing to the screen. Assume always input 0. */
-       if (!intel_sdvo_set_target_input(intel_sdvo))
-               return false;
-
-       if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,
-                                                     intel_sdvo_connector,
-                                                     mode->clock / 10,
-                                                     mode->hdisplay,
-                                                     mode->vdisplay))
-               return false;
-
-       if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-                                                  &input_dtd))
-               return false;
-
-       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-       intel_sdvo->dtd_sdvo_flags = input_dtd.part2.sdvo_flags;
-
-       return true;
-}
-
-static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
-{
-       unsigned dotclock = pipe_config->port_clock;
-       struct dpll *clock = &pipe_config->dpll;
-
-       /*
-        * SDVO TV has fixed PLL values depend on its clock range,
-        * this mirrors vbios setting.
-        */
-       if (dotclock >= 100000 && dotclock < 140500) {
-               clock->p1 = 2;
-               clock->p2 = 10;
-               clock->n = 3;
-               clock->m1 = 16;
-               clock->m2 = 8;
-       } else if (dotclock >= 140500 && dotclock <= 200000) {
-               clock->p1 = 1;
-               clock->p2 = 10;
-               clock->n = 6;
-               clock->m1 = 12;
-               clock->m2 = 8;
-       } else {
-               WARN(1, "SDVO TV clock out of range: %i\n", dotclock);
-       }
-
-       pipe_config->clock_set = true;
-}
-
-static int intel_sdvo_compute_config(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config,
-                                    struct drm_connector_state *conn_state)
-{
-       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-       struct intel_sdvo_connector_state *intel_sdvo_state =
-               to_intel_sdvo_connector_state(conn_state);
-       struct intel_sdvo_connector *intel_sdvo_connector =
-               to_intel_sdvo_connector(conn_state->connector);
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct drm_display_mode *mode = &pipe_config->base.mode;
-
-       DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
-       pipe_config->pipe_bpp = 8*3;
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       if (HAS_PCH_SPLIT(to_i915(encoder->base.dev)))
-               pipe_config->has_pch_encoder = true;
-
-       /*
-        * We need to construct preferred input timings based on our
-        * output timings.  To do that, we have to set the output
-        * timings, even though this isn't really the right place in
-        * the sequence to do it. Oh well.
-        */
-       if (IS_TV(intel_sdvo_connector)) {
-               if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
-                       return -EINVAL;
-
-               (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
-                                                          intel_sdvo_connector,
-                                                          mode,
-                                                          adjusted_mode);
-               pipe_config->sdvo_tv_clock = true;
-       } else if (IS_LVDS(intel_sdvo_connector)) {
-               if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
-                                                            intel_sdvo_connector->base.panel.fixed_mode))
-                       return -EINVAL;
-
-               (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
-                                                          intel_sdvo_connector,
-                                                          mode,
-                                                          adjusted_mode);
-       }
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       /*
-        * Make the CRTC code factor in the SDVO pixel multiplier.  The
-        * SDVO device will factor out the multiplier during mode_set.
-        */
-       pipe_config->pixel_multiplier =
-               intel_sdvo_get_pixel_multiplier(adjusted_mode);
-
-       if (intel_sdvo_state->base.force_audio != HDMI_AUDIO_OFF_DVI)
-               pipe_config->has_hdmi_sink = intel_sdvo->has_hdmi_monitor;
-
-       if (intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON ||
-           (intel_sdvo_state->base.force_audio == HDMI_AUDIO_AUTO && intel_sdvo->has_hdmi_audio))
-               pipe_config->has_audio = true;
-
-       if (intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
-               /*
-                * See CEA-861-E - 5.1 Default Encoding Parameters
-                *
-                * FIXME: This bit is only valid when using TMDS encoding and 8
-                * bit per color mode.
-                */
-               if (pipe_config->has_hdmi_sink &&
-                   drm_match_cea_mode(adjusted_mode) > 1)
-                       pipe_config->limited_color_range = true;
-       } else {
-               if (pipe_config->has_hdmi_sink &&
-                   intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED)
-                       pipe_config->limited_color_range = true;
-       }
-
-       /* Clock computation needs to happen after pixel multiplier. */
-       if (IS_TV(intel_sdvo_connector))
-               i9xx_adjust_sdvo_tv_clock(pipe_config);
-
-       /* Set user selected PAR to incoming mode's member */
-       if (intel_sdvo_connector->is_hdmi)
-               adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
-
-       if (!intel_sdvo_compute_avi_infoframe(intel_sdvo,
-                                             pipe_config, conn_state)) {
-               DRM_DEBUG_KMS("bad AVI infoframe\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-#define UPDATE_PROPERTY(input, NAME) \
-       do { \
-               val = input; \
-               intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_##NAME, &val, sizeof(val)); \
-       } while (0)
-
-static void intel_sdvo_update_props(struct intel_sdvo *intel_sdvo,
-                                   const struct intel_sdvo_connector_state *sdvo_state)
-{
-       const struct drm_connector_state *conn_state = &sdvo_state->base.base;
-       struct intel_sdvo_connector *intel_sdvo_conn =
-               to_intel_sdvo_connector(conn_state->connector);
-       u16 val;
-
-       if (intel_sdvo_conn->left)
-               UPDATE_PROPERTY(sdvo_state->tv.overscan_h, OVERSCAN_H);
-
-       if (intel_sdvo_conn->top)
-               UPDATE_PROPERTY(sdvo_state->tv.overscan_v, OVERSCAN_V);
-
-       if (intel_sdvo_conn->hpos)
-               UPDATE_PROPERTY(sdvo_state->tv.hpos, HPOS);
-
-       if (intel_sdvo_conn->vpos)
-               UPDATE_PROPERTY(sdvo_state->tv.vpos, VPOS);
-
-       if (intel_sdvo_conn->saturation)
-               UPDATE_PROPERTY(conn_state->tv.saturation, SATURATION);
-
-       if (intel_sdvo_conn->contrast)
-               UPDATE_PROPERTY(conn_state->tv.contrast, CONTRAST);
-
-       if (intel_sdvo_conn->hue)
-               UPDATE_PROPERTY(conn_state->tv.hue, HUE);
-
-       if (intel_sdvo_conn->brightness)
-               UPDATE_PROPERTY(conn_state->tv.brightness, BRIGHTNESS);
-
-       if (intel_sdvo_conn->sharpness)
-               UPDATE_PROPERTY(sdvo_state->tv.sharpness, SHARPNESS);
-
-       if (intel_sdvo_conn->flicker_filter)
-               UPDATE_PROPERTY(sdvo_state->tv.flicker_filter, FLICKER_FILTER);
-
-       if (intel_sdvo_conn->flicker_filter_2d)
-               UPDATE_PROPERTY(sdvo_state->tv.flicker_filter_2d, FLICKER_FILTER_2D);
-
-       if (intel_sdvo_conn->flicker_filter_adaptive)
-               UPDATE_PROPERTY(sdvo_state->tv.flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
-
-       if (intel_sdvo_conn->tv_chroma_filter)
-               UPDATE_PROPERTY(sdvo_state->tv.chroma_filter, TV_CHROMA_FILTER);
-
-       if (intel_sdvo_conn->tv_luma_filter)
-               UPDATE_PROPERTY(sdvo_state->tv.luma_filter, TV_LUMA_FILTER);
-
-       if (intel_sdvo_conn->dot_crawl)
-               UPDATE_PROPERTY(sdvo_state->tv.dot_crawl, DOT_CRAWL);
-
-#undef UPDATE_PROPERTY
-}
-
-static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
-       const struct intel_sdvo_connector_state *sdvo_state =
-               to_intel_sdvo_connector_state(conn_state);
-       const struct intel_sdvo_connector *intel_sdvo_connector =
-               to_intel_sdvo_connector(conn_state->connector);
-       const struct drm_display_mode *mode = &crtc_state->base.mode;
-       struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
-       u32 sdvox;
-       struct intel_sdvo_in_out_map in_out;
-       struct intel_sdvo_dtd input_dtd, output_dtd;
-       int rate;
-
-       intel_sdvo_update_props(intel_sdvo, sdvo_state);
-
-       /*
-        * First, set the input mapping for the first input to our controlled
-        * output. This is only correct if we're a single-input device, in
-        * which case the first input is the output from the appropriate SDVO
-        * channel on the motherboard.  In a two-input device, the first input
-        * will be SDVOB and the second SDVOC.
-        */
-       in_out.in0 = intel_sdvo->attached_output;
-       in_out.in1 = 0;
-
-       intel_sdvo_set_value(intel_sdvo,
-                            SDVO_CMD_SET_IN_OUT_MAP,
-                            &in_out, sizeof(in_out));
-
-       /* Set the output timings to the screen */
-       if (!intel_sdvo_set_target_output(intel_sdvo,
-                                         intel_sdvo->attached_output))
-               return;
-
-       /* lvds has a special fixed output timing. */
-       if (IS_LVDS(intel_sdvo_connector))
-               intel_sdvo_get_dtd_from_mode(&output_dtd,
-                                            intel_sdvo_connector->base.panel.fixed_mode);
-       else
-               intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
-       if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
-               DRM_INFO("Setting output timings on %s failed\n",
-                        SDVO_NAME(intel_sdvo));
-
-       /* Set the input timing to the screen. Assume always input 0. */
-       if (!intel_sdvo_set_target_input(intel_sdvo))
-               return;
-
-       if (crtc_state->has_hdmi_sink) {
-               intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
-               intel_sdvo_set_colorimetry(intel_sdvo,
-                                          SDVO_COLORIMETRY_RGB256);
-               intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state);
-       } else
-               intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
-
-       if (IS_TV(intel_sdvo_connector) &&
-           !intel_sdvo_set_tv_format(intel_sdvo, conn_state))
-               return;
-
-       intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-
-       if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector))
-               input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags;
-       if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
-               DRM_INFO("Setting input timings on %s failed\n",
-                        SDVO_NAME(intel_sdvo));
-
-       switch (crtc_state->pixel_multiplier) {
-       default:
-               WARN(1, "unknown pixel multiplier specified\n");
-               /* fall through */
-       case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
-       case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
-       case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
-       }
-       if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate))
-               return;
-
-       /* Set the SDVO control regs. */
-       if (INTEL_GEN(dev_priv) >= 4) {
-               /* The real mode polarity is set by the SDVO commands, using
-                * struct intel_sdvo_dtd. */
-               sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
-               if (!HAS_PCH_SPLIT(dev_priv) && crtc_state->limited_color_range)
-                       sdvox |= HDMI_COLOR_RANGE_16_235;
-               if (INTEL_GEN(dev_priv) < 5)
-                       sdvox |= SDVO_BORDER_ENABLE;
-       } else {
-               sdvox = I915_READ(intel_sdvo->sdvo_reg);
-               if (intel_sdvo->port == PORT_B)
-                       sdvox &= SDVOB_PRESERVE_MASK;
-               else
-                       sdvox &= SDVOC_PRESERVE_MASK;
-               sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
-       }
-
-       if (HAS_PCH_CPT(dev_priv))
-               sdvox |= SDVO_PIPE_SEL_CPT(crtc->pipe);
-       else
-               sdvox |= SDVO_PIPE_SEL(crtc->pipe);
-
-       if (INTEL_GEN(dev_priv) >= 4) {
-               /* done in crtc_mode_set as the dpll_md reg must be written early */
-       } else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
-                  IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
-               /* done in crtc_mode_set as it lives inside the dpll register */
-       } else {
-               sdvox |= (crtc_state->pixel_multiplier - 1)
-                       << SDVO_PORT_MULTIPLY_SHIFT;
-       }
-
-       if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL &&
-           INTEL_GEN(dev_priv) < 5)
-               sdvox |= SDVO_STALL_SELECT;
-       intel_sdvo_write_sdvox(intel_sdvo, sdvox);
-}
-
-static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
-{
-       struct intel_sdvo_connector *intel_sdvo_connector =
-               to_intel_sdvo_connector(&connector->base);
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
-       u16 active_outputs = 0;
-
-       intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
-
-       return active_outputs & intel_sdvo_connector->output_flag;
-}
-
-bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv,
-                            i915_reg_t sdvo_reg, enum pipe *pipe)
-{
-       u32 val;
-
-       val = I915_READ(sdvo_reg);
-
-       /* asserts want to know the pipe even if the port is disabled */
-       if (HAS_PCH_CPT(dev_priv))
-               *pipe = (val & SDVO_PIPE_SEL_MASK_CPT) >> SDVO_PIPE_SEL_SHIFT_CPT;
-       else if (IS_CHERRYVIEW(dev_priv))
-               *pipe = (val & SDVO_PIPE_SEL_MASK_CHV) >> SDVO_PIPE_SEL_SHIFT_CHV;
-       else
-               *pipe = (val & SDVO_PIPE_SEL_MASK) >> SDVO_PIPE_SEL_SHIFT;
-
-       return val & SDVO_ENABLE;
-}
-
-static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
-                                   enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-       u16 active_outputs = 0;
-       bool ret;
-
-       intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
-
-       ret = intel_sdvo_port_enabled(dev_priv, intel_sdvo->sdvo_reg, pipe);
-
-       return ret || active_outputs;
-}
-
-static void intel_sdvo_get_config(struct intel_encoder *encoder,
-                                 struct intel_crtc_state *pipe_config)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-       struct intel_sdvo_dtd dtd;
-       int encoder_pixel_multiplier = 0;
-       int dotclock;
-       u32 flags = 0, sdvox;
-       u8 val;
-       bool ret;
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_SDVO);
-
-       sdvox = I915_READ(intel_sdvo->sdvo_reg);
-
-       ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
-       if (!ret) {
-               /*
-                * Some sdvo encoders are not spec compliant and don't
-                * implement the mandatory get_timings function.
-                */
-               DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
-               pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS;
-       } else {
-               if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
-                       flags |= DRM_MODE_FLAG_PHSYNC;
-               else
-                       flags |= DRM_MODE_FLAG_NHSYNC;
-
-               if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
-                       flags |= DRM_MODE_FLAG_PVSYNC;
-               else
-                       flags |= DRM_MODE_FLAG_NVSYNC;
-       }
-
-       pipe_config->base.adjusted_mode.flags |= flags;
-
-       /*
-        * pixel multiplier readout is tricky: Only on i915g/gm it is stored in
-        * the sdvo port register, on all other platforms it is part of the dpll
-        * state. Since the general pipe state readout happens before the
-        * encoder->get_config we so already have a valid pixel multplier on all
-        * other platfroms.
-        */
-       if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
-               pipe_config->pixel_multiplier =
-                       ((sdvox & SDVO_PORT_MULTIPLY_MASK)
-                        >> SDVO_PORT_MULTIPLY_SHIFT) + 1;
-       }
-
-       dotclock = pipe_config->port_clock;
-
-       if (pipe_config->pixel_multiplier)
-               dotclock /= pipe_config->pixel_multiplier;
-
-       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
-
-       /* Cross check the port pixel multiplier with the sdvo encoder state. */
-       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
-                                &val, 1)) {
-               switch (val) {
-               case SDVO_CLOCK_RATE_MULT_1X:
-                       encoder_pixel_multiplier = 1;
-                       break;
-               case SDVO_CLOCK_RATE_MULT_2X:
-                       encoder_pixel_multiplier = 2;
-                       break;
-               case SDVO_CLOCK_RATE_MULT_4X:
-                       encoder_pixel_multiplier = 4;
-                       break;
-               }
-       }
-
-       WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
-            "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
-            pipe_config->pixel_multiplier, encoder_pixel_multiplier);
-
-       if (sdvox & HDMI_COLOR_RANGE_16_235)
-               pipe_config->limited_color_range = true;
-
-       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
-                                &val, 1)) {
-               u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT;
-
-               if ((val & mask) == mask)
-                       pipe_config->has_audio = true;
-       }
-
-       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
-                                &val, 1)) {
-               if (val == SDVO_ENCODE_HDMI)
-                       pipe_config->has_hdmi_sink = true;
-       }
-
-       intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
-}
-
-static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo)
-{
-       intel_sdvo_set_audio_state(intel_sdvo, 0);
-}
-
-static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo,
-                                   const struct intel_crtc_state *crtc_state,
-                                   const struct drm_connector_state *conn_state)
-{
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
-       struct drm_connector *connector = conn_state->connector;
-       u8 *eld = connector->eld;
-
-       eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
-
-       intel_sdvo_set_audio_state(intel_sdvo, 0);
-
-       intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD,
-                                  SDVO_HBUF_TX_DISABLED,
-                                  eld, drm_eld_size(eld));
-
-       intel_sdvo_set_audio_state(intel_sdvo, SDVO_AUDIO_ELD_VALID |
-                                  SDVO_AUDIO_PRESENCE_DETECT);
-}
-
-static void intel_disable_sdvo(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *old_crtc_state,
-                              const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
-       u32 temp;
-
-       if (old_crtc_state->has_audio)
-               intel_sdvo_disable_audio(intel_sdvo);
-
-       intel_sdvo_set_active_outputs(intel_sdvo, 0);
-       if (0)
-               intel_sdvo_set_encoder_power_state(intel_sdvo,
-                                                  DRM_MODE_DPMS_OFF);
-
-       temp = I915_READ(intel_sdvo->sdvo_reg);
-
-       temp &= ~SDVO_ENABLE;
-       intel_sdvo_write_sdvox(intel_sdvo, temp);
-
-       /*
-        * HW workaround for IBX, we need to move the port
-        * to transcoder A after disabling it to allow the
-        * matching DP port to be enabled on transcoder A.
-        */
-       if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
-               /*
-                * We get CPU/PCH FIFO underruns on the other pipe when
-                * doing the workaround. Sweep them under the rug.
-                */
-               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
-
-               temp &= ~SDVO_PIPE_SEL_MASK;
-               temp |= SDVO_ENABLE | SDVO_PIPE_SEL(PIPE_A);
-               intel_sdvo_write_sdvox(intel_sdvo, temp);
-
-               temp &= ~SDVO_ENABLE;
-               intel_sdvo_write_sdvox(intel_sdvo, temp);
-
-               intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
-               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
-       }
-}
-
-static void pch_disable_sdvo(struct intel_encoder *encoder,
-                            const struct intel_crtc_state *old_crtc_state,
-                            const struct drm_connector_state *old_conn_state)
-{
-}
-
-static void pch_post_disable_sdvo(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *old_crtc_state,
-                                 const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_sdvo(encoder, old_crtc_state, old_conn_state);
-}
-
-static void intel_enable_sdvo(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *pipe_config,
-                             const struct drm_connector_state *conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       u32 temp;
-       bool input1, input2;
-       int i;
-       bool success;
-
-       temp = I915_READ(intel_sdvo->sdvo_reg);
-       temp |= SDVO_ENABLE;
-       intel_sdvo_write_sdvox(intel_sdvo, temp);
-
-       for (i = 0; i < 2; i++)
-               intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
-
-       success = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
-       /*
-        * Warn if the device reported failure to sync.
-        *
-        * A lot of SDVO devices fail to notify of sync, but it's
-        * a given it the status is a success, we succeeded.
-        */
-       if (success && !input1) {
-               DRM_DEBUG_KMS("First %s output reported failure to "
-                               "sync\n", SDVO_NAME(intel_sdvo));
-       }
-
-       if (0)
-               intel_sdvo_set_encoder_power_state(intel_sdvo,
-                                                  DRM_MODE_DPMS_ON);
-       intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
-
-       if (pipe_config->has_audio)
-               intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state);
-}
-
-static enum drm_mode_status
-intel_sdvo_mode_valid(struct drm_connector *connector,
-                     struct drm_display_mode *mode)
-{
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-       struct intel_sdvo_connector *intel_sdvo_connector =
-               to_intel_sdvo_connector(connector);
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       if (intel_sdvo->pixel_clock_min > mode->clock)
-               return MODE_CLOCK_LOW;
-
-       if (intel_sdvo->pixel_clock_max < mode->clock)
-               return MODE_CLOCK_HIGH;
-
-       if (mode->clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       if (IS_LVDS(intel_sdvo_connector)) {
-               const struct drm_display_mode *fixed_mode =
-                       intel_sdvo_connector->base.panel.fixed_mode;
-
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-       }
-
-       return MODE_OK;
-}
-
-static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
-{
-       BUILD_BUG_ON(sizeof(*caps) != 8);
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_DEVICE_CAPS,
-                                 caps, sizeof(*caps)))
-               return false;
-
-       DRM_DEBUG_KMS("SDVO capabilities:\n"
-                     "  vendor_id: %d\n"
-                     "  device_id: %d\n"
-                     "  device_rev_id: %d\n"
-                     "  sdvo_version_major: %d\n"
-                     "  sdvo_version_minor: %d\n"
-                     "  sdvo_inputs_mask: %d\n"
-                     "  smooth_scaling: %d\n"
-                     "  sharp_scaling: %d\n"
-                     "  up_scaling: %d\n"
-                     "  down_scaling: %d\n"
-                     "  stall_support: %d\n"
-                     "  output_flags: %d\n",
-                     caps->vendor_id,
-                     caps->device_id,
-                     caps->device_rev_id,
-                     caps->sdvo_version_major,
-                     caps->sdvo_version_minor,
-                     caps->sdvo_inputs_mask,
-                     caps->smooth_scaling,
-                     caps->sharp_scaling,
-                     caps->up_scaling,
-                     caps->down_scaling,
-                     caps->stall_support,
-                     caps->output_flags);
-
-       return true;
-}
-
-static u16 intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_sdvo->base.base.dev);
-       u16 hotplug;
-
-       if (!I915_HAS_HOTPLUG(dev_priv))
-               return 0;
-
-       /*
-        * HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
-        * on the line.
-        */
-       if (IS_I945G(dev_priv) || IS_I945GM(dev_priv))
-               return 0;
-
-       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
-                                       &hotplug, sizeof(hotplug)))
-               return 0;
-
-       return hotplug;
-}
-
-static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
-{
-       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-
-       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
-                            &intel_sdvo->hotplug_active, 2);
-}
-
-static bool intel_sdvo_hotplug(struct intel_encoder *encoder,
-                              struct intel_connector *connector)
-{
-       intel_sdvo_enable_hotplug(encoder);
-
-       return intel_encoder_hotplug(encoder, connector);
-}
-
-static bool
-intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
-{
-       /* Is there more than one type of output? */
-       return hweight16(intel_sdvo->caps.output_flags) > 1;
-}
-
-static struct edid *
-intel_sdvo_get_edid(struct drm_connector *connector)
-{
-       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
-       return drm_get_edid(connector, &sdvo->ddc);
-}
-
-/* Mac mini hack -- use the same DDC as the analog connector */
-static struct edid *
-intel_sdvo_get_analog_edid(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-
-       return drm_get_edid(connector,
-                           intel_gmbus_get_adapter(dev_priv,
-                                                   dev_priv->vbt.crt_ddc_pin));
-}
-
-static enum drm_connector_status
-intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
-{
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-       struct intel_sdvo_connector *intel_sdvo_connector =
-               to_intel_sdvo_connector(connector);
-       enum drm_connector_status status;
-       struct edid *edid;
-
-       edid = intel_sdvo_get_edid(connector);
-
-       if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
-               u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
-
-               /*
-                * Don't use the 1 as the argument of DDC bus switch to get
-                * the EDID. It is used for SDVO SPD ROM.
-                */
-               for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
-                       intel_sdvo->ddc_bus = ddc;
-                       edid = intel_sdvo_get_edid(connector);
-                       if (edid)
-                               break;
-               }
-               /*
-                * If we found the EDID on the other bus,
-                * assume that is the correct DDC bus.
-                */
-               if (edid == NULL)
-                       intel_sdvo->ddc_bus = saved_ddc;
-       }
-
-       /*
-        * When there is no edid and no monitor is connected with VGA
-        * port, try to use the CRT ddc to read the EDID for DVI-connector.
-        */
-       if (edid == NULL)
-               edid = intel_sdvo_get_analog_edid(connector);
-
-       status = connector_status_unknown;
-       if (edid != NULL) {
-               /* DDC bus is shared, match EDID to connector type */
-               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
-                       status = connector_status_connected;
-                       if (intel_sdvo_connector->is_hdmi) {
-                               intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
-                               intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
-                       }
-               } else
-                       status = connector_status_disconnected;
-               kfree(edid);
-       }
-
-       return status;
-}
-
-static bool
-intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
-                                 struct edid *edid)
-{
-       bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
-       bool connector_is_digital = !!IS_DIGITAL(sdvo);
-
-       DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n",
-                     connector_is_digital, monitor_is_digital);
-       return connector_is_digital == monitor_is_digital;
-}
-
-static enum drm_connector_status
-intel_sdvo_detect(struct drm_connector *connector, bool force)
-{
-       u16 response;
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-       enum drm_connector_status ret;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_ATTACHED_DISPLAYS,
-                                 &response, 2))
-               return connector_status_unknown;
-
-       DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
-                     response & 0xff, response >> 8,
-                     intel_sdvo_connector->output_flag);
-
-       if (response == 0)
-               return connector_status_disconnected;
-
-       intel_sdvo->attached_output = response;
-
-       intel_sdvo->has_hdmi_monitor = false;
-       intel_sdvo->has_hdmi_audio = false;
-
-       if ((intel_sdvo_connector->output_flag & response) == 0)
-               ret = connector_status_disconnected;
-       else if (IS_TMDS(intel_sdvo_connector))
-               ret = intel_sdvo_tmds_sink_detect(connector);
-       else {
-               struct edid *edid;
-
-               /* if we have an edid check it matches the connection */
-               edid = intel_sdvo_get_edid(connector);
-               if (edid == NULL)
-                       edid = intel_sdvo_get_analog_edid(connector);
-               if (edid != NULL) {
-                       if (intel_sdvo_connector_matches_edid(intel_sdvo_connector,
-                                                             edid))
-                               ret = connector_status_connected;
-                       else
-                               ret = connector_status_disconnected;
-
-                       kfree(edid);
-               } else
-                       ret = connector_status_connected;
-       }
-
-       return ret;
-}
-
-static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
-{
-       struct edid *edid;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       /* set the bus switch and get the modes */
-       edid = intel_sdvo_get_edid(connector);
-
-       /*
-        * Mac mini hack.  On this device, the DVI-I connector shares one DDC
-        * link between analog and digital outputs. So, if the regular SDVO
-        * DDC fails, check to see if the analog output is disconnected, in
-        * which case we'll look there for the digital DDC data.
-        */
-       if (edid == NULL)
-               edid = intel_sdvo_get_analog_edid(connector);
-
-       if (edid != NULL) {
-               if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector),
-                                                     edid)) {
-                       drm_connector_update_edid_property(connector, edid);
-                       drm_add_edid_modes(connector, edid);
-               }
-
-               kfree(edid);
-       }
-}
-
-/*
- * Set of SDVO TV modes.
- * Note!  This is in reply order (see loop in get_tv_modes).
- * XXX: all 60Hz refresh?
- */
-static const struct drm_display_mode sdvo_tv_modes[] = {
-       { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
-                  416, 0, 200, 201, 232, 233, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
-                  416, 0, 240, 241, 272, 273, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
-                  496, 0, 300, 301, 332, 333, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
-                  736, 0, 350, 351, 382, 383, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
-                  736, 0, 400, 401, 432, 433, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
-                  736, 0, 480, 481, 512, 513, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
-                  800, 0, 480, 481, 512, 513, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
-                  800, 0, 576, 577, 608, 609, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
-                  816, 0, 350, 351, 382, 383, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
-                  816, 0, 400, 401, 432, 433, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
-                  816, 0, 480, 481, 512, 513, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
-                  816, 0, 540, 541, 572, 573, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
-                  816, 0, 576, 577, 608, 609, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
-                  864, 0, 576, 577, 608, 609, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
-                  896, 0, 600, 601, 632, 633, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
-                  928, 0, 624, 625, 656, 657, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
-                  1016, 0, 766, 767, 798, 799, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
-                  1120, 0, 768, 769, 800, 801, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
-                  1376, 0, 1024, 1025, 1056, 1057, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-};
-
-static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
-{
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-       const struct drm_connector_state *conn_state = connector->state;
-       struct intel_sdvo_sdtv_resolution_request tv_res;
-       u32 reply = 0, format_map = 0;
-       int i;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       /*
-        * Read the list of supported input resolutions for the selected TV
-        * format.
-        */
-       format_map = 1 << conn_state->tv.mode;
-       memcpy(&tv_res, &format_map,
-              min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));
-
-       if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output))
-               return;
-
-       BUILD_BUG_ON(sizeof(tv_res) != 3);
-       if (!intel_sdvo_write_cmd(intel_sdvo,
-                                 SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
-                                 &tv_res, sizeof(tv_res)))
-               return;
-       if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
-               if (reply & (1 << i)) {
-                       struct drm_display_mode *nmode;
-                       nmode = drm_mode_duplicate(connector->dev,
-                                                  &sdvo_tv_modes[i]);
-                       if (nmode)
-                               drm_mode_probed_add(connector, nmode);
-               }
-}
-
-static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
-{
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct drm_display_mode *newmode;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       /*
-        * Fetch modes from VBT. For SDVO prefer the VBT mode since some
-        * SDVO->LVDS transcoders can't cope with the EDID mode.
-        */
-       if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) {
-               newmode = drm_mode_duplicate(connector->dev,
-                                            dev_priv->vbt.sdvo_lvds_vbt_mode);
-               if (newmode != NULL) {
-                       /* Guarantee the mode is preferred */
-                       newmode->type = (DRM_MODE_TYPE_PREFERRED |
-                                        DRM_MODE_TYPE_DRIVER);
-                       drm_mode_probed_add(connector, newmode);
-               }
-       }
-
-       /*
-        * Attempt to get the mode list from DDC.
-        * Assume that the preferred modes are
-        * arranged in priority order.
-        */
-       intel_ddc_get_modes(connector, &intel_sdvo->ddc);
-}
-
-static int intel_sdvo_get_modes(struct drm_connector *connector)
-{
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-
-       if (IS_TV(intel_sdvo_connector))
-               intel_sdvo_get_tv_modes(connector);
-       else if (IS_LVDS(intel_sdvo_connector))
-               intel_sdvo_get_lvds_modes(connector);
-       else
-               intel_sdvo_get_ddc_modes(connector);
-
-       return !list_empty(&connector->probed_modes);
-}
-
-static int
-intel_sdvo_connector_atomic_get_property(struct drm_connector *connector,
-                                        const struct drm_connector_state *state,
-                                        struct drm_property *property,
-                                        u64 *val)
-{
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-       const struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state((void *)state);
-
-       if (property == intel_sdvo_connector->tv_format) {
-               int i;
-
-               for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
-                       if (state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) {
-                               *val = i;
-
-                               return 0;
-                       }
-
-               WARN_ON(1);
-               *val = 0;
-       } else if (property == intel_sdvo_connector->top ||
-                  property == intel_sdvo_connector->bottom)
-               *val = intel_sdvo_connector->max_vscan - sdvo_state->tv.overscan_v;
-       else if (property == intel_sdvo_connector->left ||
-                property == intel_sdvo_connector->right)
-               *val = intel_sdvo_connector->max_hscan - sdvo_state->tv.overscan_h;
-       else if (property == intel_sdvo_connector->hpos)
-               *val = sdvo_state->tv.hpos;
-       else if (property == intel_sdvo_connector->vpos)
-               *val = sdvo_state->tv.vpos;
-       else if (property == intel_sdvo_connector->saturation)
-               *val = state->tv.saturation;
-       else if (property == intel_sdvo_connector->contrast)
-               *val = state->tv.contrast;
-       else if (property == intel_sdvo_connector->hue)
-               *val = state->tv.hue;
-       else if (property == intel_sdvo_connector->brightness)
-               *val = state->tv.brightness;
-       else if (property == intel_sdvo_connector->sharpness)
-               *val = sdvo_state->tv.sharpness;
-       else if (property == intel_sdvo_connector->flicker_filter)
-               *val = sdvo_state->tv.flicker_filter;
-       else if (property == intel_sdvo_connector->flicker_filter_2d)
-               *val = sdvo_state->tv.flicker_filter_2d;
-       else if (property == intel_sdvo_connector->flicker_filter_adaptive)
-               *val = sdvo_state->tv.flicker_filter_adaptive;
-       else if (property == intel_sdvo_connector->tv_chroma_filter)
-               *val = sdvo_state->tv.chroma_filter;
-       else if (property == intel_sdvo_connector->tv_luma_filter)
-               *val = sdvo_state->tv.luma_filter;
-       else if (property == intel_sdvo_connector->dot_crawl)
-               *val = sdvo_state->tv.dot_crawl;
-       else
-               return intel_digital_connector_atomic_get_property(connector, state, property, val);
-
-       return 0;
-}
-
-static int
-intel_sdvo_connector_atomic_set_property(struct drm_connector *connector,
-                                        struct drm_connector_state *state,
-                                        struct drm_property *property,
-                                        u64 val)
-{
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-       struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(state);
-
-       if (property == intel_sdvo_connector->tv_format) {
-               state->tv.mode = intel_sdvo_connector->tv_format_supported[val];
-
-               if (state->crtc) {
-                       struct drm_crtc_state *crtc_state =
-                               drm_atomic_get_new_crtc_state(state->state, state->crtc);
-
-                       crtc_state->connectors_changed = true;
-               }
-       } else if (property == intel_sdvo_connector->top ||
-                  property == intel_sdvo_connector->bottom)
-               /* Cannot set these independent from each other */
-               sdvo_state->tv.overscan_v = intel_sdvo_connector->max_vscan - val;
-       else if (property == intel_sdvo_connector->left ||
-                property == intel_sdvo_connector->right)
-               /* Cannot set these independent from each other */
-               sdvo_state->tv.overscan_h = intel_sdvo_connector->max_hscan - val;
-       else if (property == intel_sdvo_connector->hpos)
-               sdvo_state->tv.hpos = val;
-       else if (property == intel_sdvo_connector->vpos)
-               sdvo_state->tv.vpos = val;
-       else if (property == intel_sdvo_connector->saturation)
-               state->tv.saturation = val;
-       else if (property == intel_sdvo_connector->contrast)
-               state->tv.contrast = val;
-       else if (property == intel_sdvo_connector->hue)
-               state->tv.hue = val;
-       else if (property == intel_sdvo_connector->brightness)
-               state->tv.brightness = val;
-       else if (property == intel_sdvo_connector->sharpness)
-               sdvo_state->tv.sharpness = val;
-       else if (property == intel_sdvo_connector->flicker_filter)
-               sdvo_state->tv.flicker_filter = val;
-       else if (property == intel_sdvo_connector->flicker_filter_2d)
-               sdvo_state->tv.flicker_filter_2d = val;
-       else if (property == intel_sdvo_connector->flicker_filter_adaptive)
-               sdvo_state->tv.flicker_filter_adaptive = val;
-       else if (property == intel_sdvo_connector->tv_chroma_filter)
-               sdvo_state->tv.chroma_filter = val;
-       else if (property == intel_sdvo_connector->tv_luma_filter)
-               sdvo_state->tv.luma_filter = val;
-       else if (property == intel_sdvo_connector->dot_crawl)
-               sdvo_state->tv.dot_crawl = val;
-       else
-               return intel_digital_connector_atomic_set_property(connector, state, property, val);
-
-       return 0;
-}
-
-static int
-intel_sdvo_connector_register(struct drm_connector *connector)
-{
-       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
-       int ret;
-
-       ret = intel_connector_register(connector);
-       if (ret)
-               return ret;
-
-       return sysfs_create_link(&connector->kdev->kobj,
-                                &sdvo->ddc.dev.kobj,
-                                sdvo->ddc.dev.kobj.name);
-}
-
-static void
-intel_sdvo_connector_unregister(struct drm_connector *connector)
-{
-       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
-
-       sysfs_remove_link(&connector->kdev->kobj,
-                         sdvo->ddc.dev.kobj.name);
-       intel_connector_unregister(connector);
-}
-
-static struct drm_connector_state *
-intel_sdvo_connector_duplicate_state(struct drm_connector *connector)
-{
-       struct intel_sdvo_connector_state *state;
-
-       state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
-       if (!state)
-               return NULL;
-
-       __drm_atomic_helper_connector_duplicate_state(connector, &state->base.base);
-       return &state->base.base;
-}
-
-static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
-       .detect = intel_sdvo_detect,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_sdvo_connector_atomic_get_property,
-       .atomic_set_property = intel_sdvo_connector_atomic_set_property,
-       .late_register = intel_sdvo_connector_register,
-       .early_unregister = intel_sdvo_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
-};
-
-static int intel_sdvo_atomic_check(struct drm_connector *conn,
-                                  struct drm_connector_state *new_conn_state)
-{
-       struct drm_atomic_state *state = new_conn_state->state;
-       struct drm_connector_state *old_conn_state =
-               drm_atomic_get_old_connector_state(state, conn);
-       struct intel_sdvo_connector_state *old_state =
-               to_intel_sdvo_connector_state(old_conn_state);
-       struct intel_sdvo_connector_state *new_state =
-               to_intel_sdvo_connector_state(new_conn_state);
-
-       if (new_conn_state->crtc &&
-           (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
-            memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
-               struct drm_crtc_state *crtc_state =
-                       drm_atomic_get_new_crtc_state(new_conn_state->state,
-                                                     new_conn_state->crtc);
-
-               crtc_state->connectors_changed = true;
-       }
-
-       return intel_digital_connector_atomic_check(conn, new_conn_state);
-}
-
-static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
-       .get_modes = intel_sdvo_get_modes,
-       .mode_valid = intel_sdvo_mode_valid,
-       .atomic_check = intel_sdvo_atomic_check,
-};
-
-static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
-{
-       struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder));
-
-       i2c_del_adapter(&intel_sdvo->ddc);
-       intel_encoder_destroy(encoder);
-}
-
-static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
-       .destroy = intel_sdvo_enc_destroy,
-};
-
-static void
-intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
-{
-       u16 mask = 0;
-       unsigned int num_bits;
-
-       /*
-        * Make a mask of outputs less than or equal to our own priority in the
-        * list.
-        */
-       switch (sdvo->controlled_output) {
-       case SDVO_OUTPUT_LVDS1:
-               mask |= SDVO_OUTPUT_LVDS1;
-               /* fall through */
-       case SDVO_OUTPUT_LVDS0:
-               mask |= SDVO_OUTPUT_LVDS0;
-               /* fall through */
-       case SDVO_OUTPUT_TMDS1:
-               mask |= SDVO_OUTPUT_TMDS1;
-               /* fall through */
-       case SDVO_OUTPUT_TMDS0:
-               mask |= SDVO_OUTPUT_TMDS0;
-               /* fall through */
-       case SDVO_OUTPUT_RGB1:
-               mask |= SDVO_OUTPUT_RGB1;
-               /* fall through */
-       case SDVO_OUTPUT_RGB0:
-               mask |= SDVO_OUTPUT_RGB0;
-               break;
-       }
-
-       /* Count bits to find what number we are in the priority list. */
-       mask &= sdvo->caps.output_flags;
-       num_bits = hweight16(mask);
-       /* If more than 3 outputs, default to DDC bus 3 for now. */
-       if (num_bits > 3)
-               num_bits = 3;
-
-       /* Corresponds to SDVO_CONTROL_BUS_DDCx */
-       sdvo->ddc_bus = 1 << num_bits;
-}
-
-/*
- * Choose the appropriate DDC bus for control bus switch command for this
- * SDVO output based on the controlled output.
- *
- * DDC bus number assignment is in a priority order of RGB outputs, then TMDS
- * outputs, then LVDS outputs.
- */
-static void
-intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
-                         struct intel_sdvo *sdvo)
-{
-       struct sdvo_device_mapping *mapping;
-
-       if (sdvo->port == PORT_B)
-               mapping = &dev_priv->vbt.sdvo_mappings[0];
-       else
-               mapping = &dev_priv->vbt.sdvo_mappings[1];
-
-       if (mapping->initialized)
-               sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4);
-       else
-               intel_sdvo_guess_ddc_bus(sdvo);
-}
-
-static void
-intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
-                         struct intel_sdvo *sdvo)
-{
-       struct sdvo_device_mapping *mapping;
-       u8 pin;
-
-       if (sdvo->port == PORT_B)
-               mapping = &dev_priv->vbt.sdvo_mappings[0];
-       else
-               mapping = &dev_priv->vbt.sdvo_mappings[1];
-
-       if (mapping->initialized &&
-           intel_gmbus_is_valid_pin(dev_priv, mapping->i2c_pin))
-               pin = mapping->i2c_pin;
-       else
-               pin = GMBUS_PIN_DPB;
-
-       sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
-
-       /*
-        * With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow
-        * our code totally fails once we start using gmbus. Hence fall back to
-        * bit banging for now.
-        */
-       intel_gmbus_force_bit(sdvo->i2c, true);
-}
-
-/* undo any changes intel_sdvo_select_i2c_bus() did to sdvo->i2c */
-static void
-intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo)
-{
-       intel_gmbus_force_bit(sdvo->i2c, false);
-}
-
-static bool
-intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
-{
-       return intel_sdvo_check_supp_encode(intel_sdvo);
-}
-
-static u8
-intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv,
-                         struct intel_sdvo *sdvo)
-{
-       struct sdvo_device_mapping *my_mapping, *other_mapping;
-
-       if (sdvo->port == PORT_B) {
-               my_mapping = &dev_priv->vbt.sdvo_mappings[0];
-               other_mapping = &dev_priv->vbt.sdvo_mappings[1];
-       } else {
-               my_mapping = &dev_priv->vbt.sdvo_mappings[1];
-               other_mapping = &dev_priv->vbt.sdvo_mappings[0];
-       }
-
-       /* If the BIOS described our SDVO device, take advantage of it. */
-       if (my_mapping->slave_addr)
-               return my_mapping->slave_addr;
-
-       /*
-        * If the BIOS only described a different SDVO device, use the
-        * address that it isn't using.
-        */
-       if (other_mapping->slave_addr) {
-               if (other_mapping->slave_addr == 0x70)
-                       return 0x72;
-               else
-                       return 0x70;
-       }
-
-       /*
-        * No SDVO device info is found for another DVO port,
-        * so use mapping assumption we had before BIOS parsing.
-        */
-       if (sdvo->port == PORT_B)
-               return 0x70;
-       else
-               return 0x72;
-}
-
-static int
-intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
-                         struct intel_sdvo *encoder)
-{
-       struct drm_connector *drm_connector;
-       int ret;
-
-       drm_connector = &connector->base.base;
-       ret = drm_connector_init(encoder->base.base.dev,
-                          drm_connector,
-                          &intel_sdvo_connector_funcs,
-                          connector->base.base.connector_type);
-       if (ret < 0)
-               return ret;
-
-       drm_connector_helper_add(drm_connector,
-                                &intel_sdvo_connector_helper_funcs);
-
-       connector->base.base.interlace_allowed = 1;
-       connector->base.base.doublescan_allowed = 0;
-       connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
-       connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
-
-       intel_connector_attach_encoder(&connector->base, &encoder->base);
-
-       return 0;
-}
-
-static void
-intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
-                              struct intel_sdvo_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.base.dev);
-
-       intel_attach_force_audio_property(&connector->base.base);
-       if (INTEL_GEN(dev_priv) >= 4 && IS_MOBILE(dev_priv)) {
-               intel_attach_broadcast_rgb_property(&connector->base.base);
-       }
-       intel_attach_aspect_ratio_property(&connector->base.base);
-       connector->base.base.state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
-}
-
-static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
-{
-       struct intel_sdvo_connector *sdvo_connector;
-       struct intel_sdvo_connector_state *conn_state;
-
-       sdvo_connector = kzalloc(sizeof(*sdvo_connector), GFP_KERNEL);
-       if (!sdvo_connector)
-               return NULL;
-
-       conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
-       if (!conn_state) {
-               kfree(sdvo_connector);
-               return NULL;
-       }
-
-       __drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
-                                           &conn_state->base.base);
-
-       return sdvo_connector;
-}
-
-static bool
-intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
-{
-       struct drm_encoder *encoder = &intel_sdvo->base.base;
-       struct drm_connector *connector;
-       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-       struct intel_connector *intel_connector;
-       struct intel_sdvo_connector *intel_sdvo_connector;
-
-       DRM_DEBUG_KMS("initialising DVI device %d\n", device);
-
-       intel_sdvo_connector = intel_sdvo_connector_alloc();
-       if (!intel_sdvo_connector)
-               return false;
-
-       if (device == 0) {
-               intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0;
-               intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
-       } else if (device == 1) {
-               intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1;
-               intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
-       }
-
-       intel_connector = &intel_sdvo_connector->base;
-       connector = &intel_connector->base;
-       if (intel_sdvo_get_hotplug_support(intel_sdvo) &
-               intel_sdvo_connector->output_flag) {
-               intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
-               /*
-                * Some SDVO devices have one-shot hotplug interrupts.
-                * Ensure that they get re-enabled when an interrupt happens.
-                */
-               intel_encoder->hotplug = intel_sdvo_hotplug;
-               intel_sdvo_enable_hotplug(intel_encoder);
-       } else {
-               intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
-       }
-       encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
-       connector->connector_type = DRM_MODE_CONNECTOR_DVID;
-
-       if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
-               connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
-               intel_sdvo_connector->is_hdmi = true;
-       }
-
-       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-               kfree(intel_sdvo_connector);
-               return false;
-       }
-
-       if (intel_sdvo_connector->is_hdmi)
-               intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
-
-       return true;
-}
-
-static bool
-intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
-{
-       struct drm_encoder *encoder = &intel_sdvo->base.base;
-       struct drm_connector *connector;
-       struct intel_connector *intel_connector;
-       struct intel_sdvo_connector *intel_sdvo_connector;
-
-       DRM_DEBUG_KMS("initialising TV type %d\n", type);
-
-       intel_sdvo_connector = intel_sdvo_connector_alloc();
-       if (!intel_sdvo_connector)
-               return false;
-
-       intel_connector = &intel_sdvo_connector->base;
-       connector = &intel_connector->base;
-       encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-       connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
-
-       intel_sdvo->controlled_output |= type;
-       intel_sdvo_connector->output_flag = type;
-
-       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-               kfree(intel_sdvo_connector);
-               return false;
-       }
-
-       if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
-               goto err;
-
-       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
-               goto err;
-
-       return true;
-
-err:
-       intel_connector_destroy(connector);
-       return false;
-}
-
-static bool
-intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
-{
-       struct drm_encoder *encoder = &intel_sdvo->base.base;
-       struct drm_connector *connector;
-       struct intel_connector *intel_connector;
-       struct intel_sdvo_connector *intel_sdvo_connector;
-
-       DRM_DEBUG_KMS("initialising analog device %d\n", device);
-
-       intel_sdvo_connector = intel_sdvo_connector_alloc();
-       if (!intel_sdvo_connector)
-               return false;
-
-       intel_connector = &intel_sdvo_connector->base;
-       connector = &intel_connector->base;
-       intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-       encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-       connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-
-       if (device == 0) {
-               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
-               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
-       } else if (device == 1) {
-               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
-               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
-       }
-
-       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-               kfree(intel_sdvo_connector);
-               return false;
-       }
-
-       return true;
-}
-
-static bool
-intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
-{
-       struct drm_encoder *encoder = &intel_sdvo->base.base;
-       struct drm_connector *connector;
-       struct intel_connector *intel_connector;
-       struct intel_sdvo_connector *intel_sdvo_connector;
-       struct drm_display_mode *mode;
-
-       DRM_DEBUG_KMS("initialising LVDS device %d\n", device);
-
-       intel_sdvo_connector = intel_sdvo_connector_alloc();
-       if (!intel_sdvo_connector)
-               return false;
-
-       intel_connector = &intel_sdvo_connector->base;
-       connector = &intel_connector->base;
-       encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-       connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-
-       if (device == 0) {
-               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
-               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
-       } else if (device == 1) {
-               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
-               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
-       }
-
-       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-               kfree(intel_sdvo_connector);
-               return false;
-       }
-
-       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
-               goto err;
-
-       intel_sdvo_get_lvds_modes(connector);
-
-       list_for_each_entry(mode, &connector->probed_modes, head) {
-               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
-                       struct drm_display_mode *fixed_mode =
-                               drm_mode_duplicate(connector->dev, mode);
-
-                       intel_panel_init(&intel_connector->panel,
-                                        fixed_mode, NULL);
-                       break;
-               }
-       }
-
-       if (!intel_connector->panel.fixed_mode)
-               goto err;
-
-       return true;
-
-err:
-       intel_connector_destroy(connector);
-       return false;
-}
-
-static bool
-intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags)
-{
-       /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
-
-       if (flags & SDVO_OUTPUT_TMDS0)
-               if (!intel_sdvo_dvi_init(intel_sdvo, 0))
-                       return false;
-
-       if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)
-               if (!intel_sdvo_dvi_init(intel_sdvo, 1))
-                       return false;
-
-       /* TV has no XXX1 function block */
-       if (flags & SDVO_OUTPUT_SVID0)
-               if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0))
-                       return false;
-
-       if (flags & SDVO_OUTPUT_CVBS0)
-               if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0))
-                       return false;
-
-       if (flags & SDVO_OUTPUT_YPRPB0)
-               if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0))
-                       return false;
-
-       if (flags & SDVO_OUTPUT_RGB0)
-               if (!intel_sdvo_analog_init(intel_sdvo, 0))
-                       return false;
-
-       if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)
-               if (!intel_sdvo_analog_init(intel_sdvo, 1))
-                       return false;
-
-       if (flags & SDVO_OUTPUT_LVDS0)
-               if (!intel_sdvo_lvds_init(intel_sdvo, 0))
-                       return false;
-
-       if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)
-               if (!intel_sdvo_lvds_init(intel_sdvo, 1))
-                       return false;
-
-       if ((flags & SDVO_OUTPUT_MASK) == 0) {
-               unsigned char bytes[2];
-
-               intel_sdvo->controlled_output = 0;
-               memcpy(bytes, &intel_sdvo->caps.output_flags, 2);
-               DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
-                             SDVO_NAME(intel_sdvo),
-                             bytes[0], bytes[1]);
-               return false;
-       }
-       intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-
-       return true;
-}
-
-static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
-{
-       struct drm_device *dev = intel_sdvo->base.base.dev;
-       struct drm_connector *connector, *tmp;
-
-       list_for_each_entry_safe(connector, tmp,
-                                &dev->mode_config.connector_list, head) {
-               if (intel_attached_encoder(connector) == &intel_sdvo->base) {
-                       drm_connector_unregister(connector);
-                       intel_connector_destroy(connector);
-               }
-       }
-}
-
-static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
-                                         struct intel_sdvo_connector *intel_sdvo_connector,
-                                         int type)
-{
-       struct drm_device *dev = intel_sdvo->base.base.dev;
-       struct intel_sdvo_tv_format format;
-       u32 format_map, i;
-
-       if (!intel_sdvo_set_target_output(intel_sdvo, type))
-               return false;
-
-       BUILD_BUG_ON(sizeof(format) != 6);
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
-                                 &format, sizeof(format)))
-               return false;
-
-       memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format)));
-
-       if (format_map == 0)
-               return false;
-
-       intel_sdvo_connector->format_supported_num = 0;
-       for (i = 0 ; i < TV_FORMAT_NUM; i++)
-               if (format_map & (1 << i))
-                       intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i;
-
-
-       intel_sdvo_connector->tv_format =
-                       drm_property_create(dev, DRM_MODE_PROP_ENUM,
-                                           "mode", intel_sdvo_connector->format_supported_num);
-       if (!intel_sdvo_connector->tv_format)
-               return false;
-
-       for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
-               drm_property_add_enum(intel_sdvo_connector->tv_format, i,
-                                     tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);
-
-       intel_sdvo_connector->base.base.state->tv.mode = intel_sdvo_connector->tv_format_supported[0];
-       drm_object_attach_property(&intel_sdvo_connector->base.base.base,
-                                  intel_sdvo_connector->tv_format, 0);
-       return true;
-
-}
-
-#define _ENHANCEMENT(state_assignment, name, NAME) do { \
-       if (enhancements.name) { \
-               if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \
-                   !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \
-                       return false; \
-               intel_sdvo_connector->name = \
-                       drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
-               if (!intel_sdvo_connector->name) return false; \
-               state_assignment = response; \
-               drm_object_attach_property(&connector->base, \
-                                          intel_sdvo_connector->name, 0); \
-               DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \
-                             data_value[0], data_value[1], response); \
-       } \
-} while (0)
-
-#define ENHANCEMENT(state, name, NAME) _ENHANCEMENT((state)->name, name, NAME)
-
-static bool
-intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
-                                     struct intel_sdvo_connector *intel_sdvo_connector,
-                                     struct intel_sdvo_enhancements_reply enhancements)
-{
-       struct drm_device *dev = intel_sdvo->base.base.dev;
-       struct drm_connector *connector = &intel_sdvo_connector->base.base;
-       struct drm_connector_state *conn_state = connector->state;
-       struct intel_sdvo_connector_state *sdvo_state =
-               to_intel_sdvo_connector_state(conn_state);
-       u16 response, data_value[2];
-
-       /* when horizontal overscan is supported, Add the left/right property */
-       if (enhancements.overscan_h) {
-               if (!intel_sdvo_get_value(intel_sdvo,
-                                         SDVO_CMD_GET_MAX_OVERSCAN_H,
-                                         &data_value, 4))
-                       return false;
-
-               if (!intel_sdvo_get_value(intel_sdvo,
-                                         SDVO_CMD_GET_OVERSCAN_H,
-                                         &response, 2))
-                       return false;
-
-               sdvo_state->tv.overscan_h = response;
-
-               intel_sdvo_connector->max_hscan = data_value[0];
-               intel_sdvo_connector->left =
-                       drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
-               if (!intel_sdvo_connector->left)
-                       return false;
-
-               drm_object_attach_property(&connector->base,
-                                          intel_sdvo_connector->left, 0);
-
-               intel_sdvo_connector->right =
-                       drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
-               if (!intel_sdvo_connector->right)
-                       return false;
-
-               drm_object_attach_property(&connector->base,
-                                             intel_sdvo_connector->right, 0);
-               DRM_DEBUG_KMS("h_overscan: max %d, "
-                             "default %d, current %d\n",
-                             data_value[0], data_value[1], response);
-       }
-
-       if (enhancements.overscan_v) {
-               if (!intel_sdvo_get_value(intel_sdvo,
-                                         SDVO_CMD_GET_MAX_OVERSCAN_V,
-                                         &data_value, 4))
-                       return false;
-
-               if (!intel_sdvo_get_value(intel_sdvo,
-                                         SDVO_CMD_GET_OVERSCAN_V,
-                                         &response, 2))
-                       return false;
-
-               sdvo_state->tv.overscan_v = response;
-
-               intel_sdvo_connector->max_vscan = data_value[0];
-               intel_sdvo_connector->top =
-                       drm_property_create_range(dev, 0,
-                                           "top_margin", 0, data_value[0]);
-               if (!intel_sdvo_connector->top)
-                       return false;
-
-               drm_object_attach_property(&connector->base,
-                                          intel_sdvo_connector->top, 0);
-
-               intel_sdvo_connector->bottom =
-                       drm_property_create_range(dev, 0,
-                                           "bottom_margin", 0, data_value[0]);
-               if (!intel_sdvo_connector->bottom)
-                       return false;
-
-               drm_object_attach_property(&connector->base,
-                                             intel_sdvo_connector->bottom, 0);
-               DRM_DEBUG_KMS("v_overscan: max %d, "
-                             "default %d, current %d\n",
-                             data_value[0], data_value[1], response);
-       }
-
-       ENHANCEMENT(&sdvo_state->tv, hpos, HPOS);
-       ENHANCEMENT(&sdvo_state->tv, vpos, VPOS);
-       ENHANCEMENT(&conn_state->tv, saturation, SATURATION);
-       ENHANCEMENT(&conn_state->tv, contrast, CONTRAST);
-       ENHANCEMENT(&conn_state->tv, hue, HUE);
-       ENHANCEMENT(&conn_state->tv, brightness, BRIGHTNESS);
-       ENHANCEMENT(&sdvo_state->tv, sharpness, SHARPNESS);
-       ENHANCEMENT(&sdvo_state->tv, flicker_filter, FLICKER_FILTER);
-       ENHANCEMENT(&sdvo_state->tv, flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
-       ENHANCEMENT(&sdvo_state->tv, flicker_filter_2d, FLICKER_FILTER_2D);
-       _ENHANCEMENT(sdvo_state->tv.chroma_filter, tv_chroma_filter, TV_CHROMA_FILTER);
-       _ENHANCEMENT(sdvo_state->tv.luma_filter, tv_luma_filter, TV_LUMA_FILTER);
-
-       if (enhancements.dot_crawl) {
-               if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2))
-                       return false;
-
-               sdvo_state->tv.dot_crawl = response & 0x1;
-               intel_sdvo_connector->dot_crawl =
-                       drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
-               if (!intel_sdvo_connector->dot_crawl)
-                       return false;
-
-               drm_object_attach_property(&connector->base,
-                                          intel_sdvo_connector->dot_crawl, 0);
-               DRM_DEBUG_KMS("dot crawl: current %d\n", response);
-       }
-
-       return true;
-}
-
-static bool
-intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
-                                       struct intel_sdvo_connector *intel_sdvo_connector,
-                                       struct intel_sdvo_enhancements_reply enhancements)
-{
-       struct drm_device *dev = intel_sdvo->base.base.dev;
-       struct drm_connector *connector = &intel_sdvo_connector->base.base;
-       u16 response, data_value[2];
-
-       ENHANCEMENT(&connector->state->tv, brightness, BRIGHTNESS);
-
-       return true;
-}
-#undef ENHANCEMENT
-#undef _ENHANCEMENT
-
-static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
-                                              struct intel_sdvo_connector *intel_sdvo_connector)
-{
-       union {
-               struct intel_sdvo_enhancements_reply reply;
-               u16 response;
-       } enhancements;
-
-       BUILD_BUG_ON(sizeof(enhancements) != 2);
-
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
-                                 &enhancements, sizeof(enhancements)) ||
-           enhancements.response == 0) {
-               DRM_DEBUG_KMS("No enhancement is supported\n");
-               return true;
-       }
-
-       if (IS_TV(intel_sdvo_connector))
-               return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply);
-       else if (IS_LVDS(intel_sdvo_connector))
-               return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
-       else
-               return true;
-}
-
-static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
-                                    struct i2c_msg *msgs,
-                                    int num)
-{
-       struct intel_sdvo *sdvo = adapter->algo_data;
-
-       if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
-               return -EIO;
-
-       return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
-}
-
-static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
-{
-       struct intel_sdvo *sdvo = adapter->algo_data;
-       return sdvo->i2c->algo->functionality(sdvo->i2c);
-}
-
-static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
-       .master_xfer    = intel_sdvo_ddc_proxy_xfer,
-       .functionality  = intel_sdvo_ddc_proxy_func
-};
-
-static void proxy_lock_bus(struct i2c_adapter *adapter,
-                          unsigned int flags)
-{
-       struct intel_sdvo *sdvo = adapter->algo_data;
-       sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags);
-}
-
-static int proxy_trylock_bus(struct i2c_adapter *adapter,
-                            unsigned int flags)
-{
-       struct intel_sdvo *sdvo = adapter->algo_data;
-       return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags);
-}
-
-static void proxy_unlock_bus(struct i2c_adapter *adapter,
-                            unsigned int flags)
-{
-       struct intel_sdvo *sdvo = adapter->algo_data;
-       sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags);
-}
-
-static const struct i2c_lock_operations proxy_lock_ops = {
-       .lock_bus =    proxy_lock_bus,
-       .trylock_bus = proxy_trylock_bus,
-       .unlock_bus =  proxy_unlock_bus,
-};
-
-static bool
-intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
-                         struct drm_i915_private *dev_priv)
-{
-       struct pci_dev *pdev = dev_priv->drm.pdev;
-
-       sdvo->ddc.owner = THIS_MODULE;
-       sdvo->ddc.class = I2C_CLASS_DDC;
-       snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
-       sdvo->ddc.dev.parent = &pdev->dev;
-       sdvo->ddc.algo_data = sdvo;
-       sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
-       sdvo->ddc.lock_ops = &proxy_lock_ops;
-
-       return i2c_add_adapter(&sdvo->ddc) == 0;
-}
-
-static void assert_sdvo_port_valid(const struct drm_i915_private *dev_priv,
-                                  enum port port)
-{
-       if (HAS_PCH_SPLIT(dev_priv))
-               WARN_ON(port != PORT_B);
-       else
-               WARN_ON(port != PORT_B && port != PORT_C);
-}
-
-bool intel_sdvo_init(struct drm_i915_private *dev_priv,
-                    i915_reg_t sdvo_reg, enum port port)
-{
-       struct intel_encoder *intel_encoder;
-       struct intel_sdvo *intel_sdvo;
-       int i;
-
-       assert_sdvo_port_valid(dev_priv, port);
-
-       intel_sdvo = kzalloc(sizeof(*intel_sdvo), GFP_KERNEL);
-       if (!intel_sdvo)
-               return false;
-
-       intel_sdvo->sdvo_reg = sdvo_reg;
-       intel_sdvo->port = port;
-       intel_sdvo->slave_addr =
-               intel_sdvo_get_slave_addr(dev_priv, intel_sdvo) >> 1;
-       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo);
-       if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev_priv))
-               goto err_i2c_bus;
-
-       /* encoder type will be decided later */
-       intel_encoder = &intel_sdvo->base;
-       intel_encoder->type = INTEL_OUTPUT_SDVO;
-       intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
-       intel_encoder->port = port;
-       drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
-                        &intel_sdvo_enc_funcs, 0,
-                        "SDVO %c", port_name(port));
-
-       /* Read the regs to test if we can talk to the device */
-       for (i = 0; i < 0x40; i++) {
-               u8 byte;
-
-               if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
-                       DRM_DEBUG_KMS("No SDVO device found on %s\n",
-                                     SDVO_NAME(intel_sdvo));
-                       goto err;
-               }
-       }
-
-       intel_encoder->compute_config = intel_sdvo_compute_config;
-       if (HAS_PCH_SPLIT(dev_priv)) {
-               intel_encoder->disable = pch_disable_sdvo;
-               intel_encoder->post_disable = pch_post_disable_sdvo;
-       } else {
-               intel_encoder->disable = intel_disable_sdvo;
-       }
-       intel_encoder->pre_enable = intel_sdvo_pre_enable;
-       intel_encoder->enable = intel_enable_sdvo;
-       intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
-       intel_encoder->get_config = intel_sdvo_get_config;
-
-       /* In default case sdvo lvds is false */
-       if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-               goto err;
-
-       if (intel_sdvo_output_setup(intel_sdvo,
-                                   intel_sdvo->caps.output_flags) != true) {
-               DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
-                             SDVO_NAME(intel_sdvo));
-               /* Output_setup can leave behind connectors! */
-               goto err_output;
-       }
-
-       /*
-        * Only enable the hotplug irq if we need it, to work around noisy
-        * hotplug lines.
-        */
-       if (intel_sdvo->hotplug_active) {
-               if (intel_sdvo->port == PORT_B)
-                       intel_encoder->hpd_pin = HPD_SDVO_B;
-               else
-                       intel_encoder->hpd_pin = HPD_SDVO_C;
-       }
-
-       /*
-        * Cloning SDVO with anything is often impossible, since the SDVO
-        * encoder can request a special input timing mode. And even if that's
-        * not the case we have evidence that cloning a plain unscaled mode with
-        * VGA doesn't really work. Furthermore the cloning flags are way too
-        * simplistic anyway to express such constraints, so just give up on
-        * cloning for SDVO encoders.
-        */
-       intel_sdvo->base.cloneable = 0;
-
-       intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo);
-
-       /* Set the input timing to the screen. Assume always input 0. */
-       if (!intel_sdvo_set_target_input(intel_sdvo))
-               goto err_output;
-
-       if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
-                                                   &intel_sdvo->pixel_clock_min,
-                                                   &intel_sdvo->pixel_clock_max))
-               goto err_output;
-
-       DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
-                       "clock range %dMHz - %dMHz, "
-                       "input 1: %c, input 2: %c, "
-                       "output 1: %c, output 2: %c\n",
-                       SDVO_NAME(intel_sdvo),
-                       intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
-                       intel_sdvo->caps.device_rev_id,
-                       intel_sdvo->pixel_clock_min / 1000,
-                       intel_sdvo->pixel_clock_max / 1000,
-                       (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
-                       (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
-                       /* check currently supported outputs */
-                       intel_sdvo->caps.output_flags &
-                       (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
-                       intel_sdvo->caps.output_flags &
-                       (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
-       return true;
-
-err_output:
-       intel_sdvo_output_cleanup(intel_sdvo);
-
-err:
-       drm_encoder_cleanup(&intel_encoder->base);
-       i2c_del_adapter(&intel_sdvo->ddc);
-err_i2c_bus:
-       intel_sdvo_unselect_i2c_bus(intel_sdvo);
-       kfree(intel_sdvo);
-
-       return false;
-}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.h b/drivers/gpu/drm/i915/intel_sdvo.h
deleted file mode 100644 (file)
index c9e05bc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_SDVO_H__
-#define __INTEL_SDVO_H__
-
-#include <linux/types.h>
-
-#include <drm/i915_drm.h>
-
-#include "i915_reg.h"
-
-struct drm_i915_private;
-enum pipe;
-
-bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv,
-                            i915_reg_t sdvo_reg, enum pipe *pipe);
-bool intel_sdvo_init(struct drm_i915_private *dev_priv,
-                    i915_reg_t reg, enum port port);
-
-#endif /* __INTEL_SDVO_H__ */
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h
deleted file mode 100644 (file)
index 13b9a8e..0000000
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * Copyright © 2006-2007 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Eric Anholt <eric@anholt.net>
- */
-
-#ifndef __INTEL_SDVO_REGS_H__
-#define __INTEL_SDVO_REGS_H__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-/*
- * SDVO command definitions and structures.
- */
-
-#define SDVO_OUTPUT_FIRST   (0)
-#define SDVO_OUTPUT_TMDS0   (1 << 0)
-#define SDVO_OUTPUT_RGB0    (1 << 1)
-#define SDVO_OUTPUT_CVBS0   (1 << 2)
-#define SDVO_OUTPUT_SVID0   (1 << 3)
-#define SDVO_OUTPUT_YPRPB0  (1 << 4)
-#define SDVO_OUTPUT_SCART0  (1 << 5)
-#define SDVO_OUTPUT_LVDS0   (1 << 6)
-#define SDVO_OUTPUT_TMDS1   (1 << 8)
-#define SDVO_OUTPUT_RGB1    (1 << 9)
-#define SDVO_OUTPUT_CVBS1   (1 << 10)
-#define SDVO_OUTPUT_SVID1   (1 << 11)
-#define SDVO_OUTPUT_YPRPB1  (1 << 12)
-#define SDVO_OUTPUT_SCART1  (1 << 13)
-#define SDVO_OUTPUT_LVDS1   (1 << 14)
-#define SDVO_OUTPUT_LAST    (14)
-
-struct intel_sdvo_caps {
-       u8 vendor_id;
-       u8 device_id;
-       u8 device_rev_id;
-       u8 sdvo_version_major;
-       u8 sdvo_version_minor;
-       unsigned int sdvo_inputs_mask:2;
-       unsigned int smooth_scaling:1;
-       unsigned int sharp_scaling:1;
-       unsigned int up_scaling:1;
-       unsigned int down_scaling:1;
-       unsigned int stall_support:1;
-       unsigned int pad:1;
-       u16 output_flags;
-} __packed;
-
-/* Note: SDVO detailed timing flags match EDID misc flags. */
-#define DTD_FLAG_HSYNC_POSITIVE (1 << 1)
-#define DTD_FLAG_VSYNC_POSITIVE (1 << 2)
-#define DTD_FLAG_INTERLACE     (1 << 7)
-
-/* This matches the EDID DTD structure, more or less */
-struct intel_sdvo_dtd {
-       struct {
-               u16 clock;      /* pixel clock, in 10kHz units */
-               u8 h_active;    /* lower 8 bits (pixels) */
-               u8 h_blank;     /* lower 8 bits (pixels) */
-               u8 h_high;      /* upper 4 bits each h_active, h_blank */
-               u8 v_active;    /* lower 8 bits (lines) */
-               u8 v_blank;     /* lower 8 bits (lines) */
-               u8 v_high;      /* upper 4 bits each v_active, v_blank */
-       } part1;
-
-       struct {
-               u8 h_sync_off;  /* lower 8 bits, from hblank start */
-               u8 h_sync_width;        /* lower 8 bits (pixels) */
-               /* lower 4 bits each vsync offset, vsync width */
-               u8 v_sync_off_width;
-               /*
-               * 2 high bits of hsync offset, 2 high bits of hsync width,
-               * bits 4-5 of vsync offset, and 2 high bits of vsync width.
-               */
-               u8 sync_off_width_high;
-               u8 dtd_flags;
-               u8 sdvo_flags;
-               /* bits 6-7 of vsync offset at bits 6-7 */
-               u8 v_sync_off_high;
-               u8 reserved;
-       } part2;
-} __packed;
-
-struct intel_sdvo_pixel_clock_range {
-       u16 min;        /* pixel clock, in 10kHz units */
-       u16 max;        /* pixel clock, in 10kHz units */
-} __packed;
-
-struct intel_sdvo_preferred_input_timing_args {
-       u16 clock;
-       u16 width;
-       u16 height;
-       u8      interlace:1;
-       u8      scaled:1;
-       u8      pad:6;
-} __packed;
-
-/* I2C registers for SDVO */
-#define SDVO_I2C_ARG_0                         0x07
-#define SDVO_I2C_ARG_1                         0x06
-#define SDVO_I2C_ARG_2                         0x05
-#define SDVO_I2C_ARG_3                         0x04
-#define SDVO_I2C_ARG_4                         0x03
-#define SDVO_I2C_ARG_5                         0x02
-#define SDVO_I2C_ARG_6                         0x01
-#define SDVO_I2C_ARG_7                         0x00
-#define SDVO_I2C_OPCODE                                0x08
-#define SDVO_I2C_CMD_STATUS                    0x09
-#define SDVO_I2C_RETURN_0                      0x0a
-#define SDVO_I2C_RETURN_1                      0x0b
-#define SDVO_I2C_RETURN_2                      0x0c
-#define SDVO_I2C_RETURN_3                      0x0d
-#define SDVO_I2C_RETURN_4                      0x0e
-#define SDVO_I2C_RETURN_5                      0x0f
-#define SDVO_I2C_RETURN_6                      0x10
-#define SDVO_I2C_RETURN_7                      0x11
-#define SDVO_I2C_VENDOR_BEGIN                  0x20
-
-/* Status results */
-#define SDVO_CMD_STATUS_POWER_ON               0x0
-#define SDVO_CMD_STATUS_SUCCESS                        0x1
-#define SDVO_CMD_STATUS_NOTSUPP                        0x2
-#define SDVO_CMD_STATUS_INVALID_ARG            0x3
-#define SDVO_CMD_STATUS_PENDING                        0x4
-#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED   0x5
-#define SDVO_CMD_STATUS_SCALING_NOT_SUPP       0x6
-
-/* SDVO commands, argument/result registers */
-
-#define SDVO_CMD_RESET                                 0x01
-
-/* Returns a struct intel_sdvo_caps */
-#define SDVO_CMD_GET_DEVICE_CAPS                       0x02
-
-#define SDVO_CMD_GET_FIRMWARE_REV                      0x86
-# define SDVO_DEVICE_FIRMWARE_MINOR                    SDVO_I2C_RETURN_0
-# define SDVO_DEVICE_FIRMWARE_MAJOR                    SDVO_I2C_RETURN_1
-# define SDVO_DEVICE_FIRMWARE_PATCH                    SDVO_I2C_RETURN_2
-
-/*
- * Reports which inputs are trained (managed to sync).
- *
- * Devices must have trained within 2 vsyncs of a mode change.
- */
-#define SDVO_CMD_GET_TRAINED_INPUTS                    0x03
-struct intel_sdvo_get_trained_inputs_response {
-       unsigned int input0_trained:1;
-       unsigned int input1_trained:1;
-       unsigned int pad:6;
-} __packed;
-
-/* Returns a struct intel_sdvo_output_flags of active outputs. */
-#define SDVO_CMD_GET_ACTIVE_OUTPUTS                    0x04
-
-/*
- * Sets the current set of active outputs.
- *
- * Takes a struct intel_sdvo_output_flags.  Must be preceded by a SET_IN_OUT_MAP
- * on multi-output devices.
- */
-#define SDVO_CMD_SET_ACTIVE_OUTPUTS                    0x05
-
-/*
- * Returns the current mapping of SDVO inputs to outputs on the device.
- *
- * Returns two struct intel_sdvo_output_flags structures.
- */
-#define SDVO_CMD_GET_IN_OUT_MAP                                0x06
-struct intel_sdvo_in_out_map {
-       u16 in0, in1;
-};
-
-/*
- * Sets the current mapping of SDVO inputs to outputs on the device.
- *
- * Takes two struct i380_sdvo_output_flags structures.
- */
-#define SDVO_CMD_SET_IN_OUT_MAP                                0x07
-
-/*
- * Returns a struct intel_sdvo_output_flags of attached displays.
- */
-#define SDVO_CMD_GET_ATTACHED_DISPLAYS                 0x0b
-
-/*
- * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging.
- */
-#define SDVO_CMD_GET_HOT_PLUG_SUPPORT                  0x0c
-
-/*
- * Takes a struct intel_sdvo_output_flags.
- */
-#define SDVO_CMD_SET_ACTIVE_HOT_PLUG                   0x0d
-
-/*
- * Returns a struct intel_sdvo_output_flags of displays with hot plug
- * interrupts enabled.
- */
-#define SDVO_CMD_GET_ACTIVE_HOT_PLUG                   0x0e
-
-#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE            0x0f
-struct intel_sdvo_get_interrupt_event_source_response {
-       u16 interrupt_status;
-       unsigned int ambient_light_interrupt:1;
-       unsigned int hdmi_audio_encrypt_change:1;
-       unsigned int pad:6;
-} __packed;
-
-/*
- * Selects which input is affected by future input commands.
- *
- * Commands affected include SET_INPUT_TIMINGS_PART[12],
- * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12],
- * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS.
- */
-#define SDVO_CMD_SET_TARGET_INPUT                      0x10
-struct intel_sdvo_set_target_input_args {
-       unsigned int target_1:1;
-       unsigned int pad:7;
-} __packed;
-
-/*
- * Takes a struct intel_sdvo_output_flags of which outputs are targeted by
- * future output commands.
- *
- * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12],
- * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE.
- */
-#define SDVO_CMD_SET_TARGET_OUTPUT                     0x11
-
-#define SDVO_CMD_GET_INPUT_TIMINGS_PART1               0x12
-#define SDVO_CMD_GET_INPUT_TIMINGS_PART2               0x13
-#define SDVO_CMD_SET_INPUT_TIMINGS_PART1               0x14
-#define SDVO_CMD_SET_INPUT_TIMINGS_PART2               0x15
-#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1              0x16
-#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2              0x17
-#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1              0x18
-#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2              0x19
-/* Part 1 */
-# define SDVO_DTD_CLOCK_LOW                            SDVO_I2C_ARG_0
-# define SDVO_DTD_CLOCK_HIGH                           SDVO_I2C_ARG_1
-# define SDVO_DTD_H_ACTIVE                             SDVO_I2C_ARG_2
-# define SDVO_DTD_H_BLANK                              SDVO_I2C_ARG_3
-# define SDVO_DTD_H_HIGH                               SDVO_I2C_ARG_4
-# define SDVO_DTD_V_ACTIVE                             SDVO_I2C_ARG_5
-# define SDVO_DTD_V_BLANK                              SDVO_I2C_ARG_6
-# define SDVO_DTD_V_HIGH                               SDVO_I2C_ARG_7
-/* Part 2 */
-# define SDVO_DTD_HSYNC_OFF                            SDVO_I2C_ARG_0
-# define SDVO_DTD_HSYNC_WIDTH                          SDVO_I2C_ARG_1
-# define SDVO_DTD_VSYNC_OFF_WIDTH                      SDVO_I2C_ARG_2
-# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH                  SDVO_I2C_ARG_3
-# define SDVO_DTD_DTD_FLAGS                            SDVO_I2C_ARG_4
-# define SDVO_DTD_DTD_FLAG_INTERLACED                          (1 << 7)
-# define SDVO_DTD_DTD_FLAG_STEREO_MASK                         (3 << 5)
-# define SDVO_DTD_DTD_FLAG_INPUT_MASK                          (3 << 3)
-# define SDVO_DTD_DTD_FLAG_SYNC_MASK                           (3 << 1)
-# define SDVO_DTD_SDVO_FLAS                            SDVO_I2C_ARG_5
-# define SDVO_DTD_SDVO_FLAG_STALL                              (1 << 7)
-# define SDVO_DTD_SDVO_FLAG_CENTERED                           (0 << 6)
-# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT                         (1 << 6)
-# define SDVO_DTD_SDVO_FLAG_SCALING_MASK                       (3 << 4)
-# define SDVO_DTD_SDVO_FLAG_SCALING_NONE                       (0 << 4)
-# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP                      (1 << 4)
-# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH                     (2 << 4)
-# define SDVO_DTD_VSYNC_OFF_HIGH                       SDVO_I2C_ARG_6
-
-/*
- * Generates a DTD based on the given width, height, and flags.
- *
- * This will be supported by any device supporting scaling or interlaced
- * modes.
- */
-#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING         0x1a
-# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW         SDVO_I2C_ARG_0
-# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH                SDVO_I2C_ARG_1
-# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW         SDVO_I2C_ARG_2
-# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH                SDVO_I2C_ARG_3
-# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW                SDVO_I2C_ARG_4
-# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH       SDVO_I2C_ARG_5
-# define SDVO_PREFERRED_INPUT_TIMING_FLAGS             SDVO_I2C_ARG_6
-# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED          (1 << 0)
-# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED              (1 << 1)
-
-#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1      0x1b
-#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2      0x1c
-
-/* Returns a struct intel_sdvo_pixel_clock_range */
-#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE           0x1d
-/* Returns a struct intel_sdvo_pixel_clock_range */
-#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE          0x1e
-
-/* Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */
-#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS                0x1f
-
-/* Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
-#define SDVO_CMD_GET_CLOCK_RATE_MULT                   0x20
-/* Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
-#define SDVO_CMD_SET_CLOCK_RATE_MULT                   0x21
-# define SDVO_CLOCK_RATE_MULT_1X                               (1 << 0)
-# define SDVO_CLOCK_RATE_MULT_2X                               (1 << 1)
-# define SDVO_CLOCK_RATE_MULT_4X                               (1 << 3)
-
-#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS              0x27
-/* 6 bytes of bit flags for TV formats shared by all TV format functions */
-struct intel_sdvo_tv_format {
-       unsigned int ntsc_m:1;
-       unsigned int ntsc_j:1;
-       unsigned int ntsc_443:1;
-       unsigned int pal_b:1;
-       unsigned int pal_d:1;
-       unsigned int pal_g:1;
-       unsigned int pal_h:1;
-       unsigned int pal_i:1;
-
-       unsigned int pal_m:1;
-       unsigned int pal_n:1;
-       unsigned int pal_nc:1;
-       unsigned int pal_60:1;
-       unsigned int secam_b:1;
-       unsigned int secam_d:1;
-       unsigned int secam_g:1;
-       unsigned int secam_k:1;
-
-       unsigned int secam_k1:1;
-       unsigned int secam_l:1;
-       unsigned int secam_60:1;
-       unsigned int hdtv_std_smpte_240m_1080i_59:1;
-       unsigned int hdtv_std_smpte_240m_1080i_60:1;
-       unsigned int hdtv_std_smpte_260m_1080i_59:1;
-       unsigned int hdtv_std_smpte_260m_1080i_60:1;
-       unsigned int hdtv_std_smpte_274m_1080i_50:1;
-
-       unsigned int hdtv_std_smpte_274m_1080i_59:1;
-       unsigned int hdtv_std_smpte_274m_1080i_60:1;
-       unsigned int hdtv_std_smpte_274m_1080p_23:1;
-       unsigned int hdtv_std_smpte_274m_1080p_24:1;
-       unsigned int hdtv_std_smpte_274m_1080p_25:1;
-       unsigned int hdtv_std_smpte_274m_1080p_29:1;
-       unsigned int hdtv_std_smpte_274m_1080p_30:1;
-       unsigned int hdtv_std_smpte_274m_1080p_50:1;
-
-       unsigned int hdtv_std_smpte_274m_1080p_59:1;
-       unsigned int hdtv_std_smpte_274m_1080p_60:1;
-       unsigned int hdtv_std_smpte_295m_1080i_50:1;
-       unsigned int hdtv_std_smpte_295m_1080p_50:1;
-       unsigned int hdtv_std_smpte_296m_720p_59:1;
-       unsigned int hdtv_std_smpte_296m_720p_60:1;
-       unsigned int hdtv_std_smpte_296m_720p_50:1;
-       unsigned int hdtv_std_smpte_293m_480p_59:1;
-
-       unsigned int hdtv_std_smpte_170m_480i_59:1;
-       unsigned int hdtv_std_iturbt601_576i_50:1;
-       unsigned int hdtv_std_iturbt601_576p_50:1;
-       unsigned int hdtv_std_eia_7702a_480i_60:1;
-       unsigned int hdtv_std_eia_7702a_480p_60:1;
-       unsigned int pad:3;
-} __packed;
-
-#define SDVO_CMD_GET_TV_FORMAT                         0x28
-
-#define SDVO_CMD_SET_TV_FORMAT                         0x29
-
-/* Returns the resolutiosn that can be used with the given TV format */
-#define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT           0x83
-struct intel_sdvo_sdtv_resolution_request {
-       unsigned int ntsc_m:1;
-       unsigned int ntsc_j:1;
-       unsigned int ntsc_443:1;
-       unsigned int pal_b:1;
-       unsigned int pal_d:1;
-       unsigned int pal_g:1;
-       unsigned int pal_h:1;
-       unsigned int pal_i:1;
-
-       unsigned int pal_m:1;
-       unsigned int pal_n:1;
-       unsigned int pal_nc:1;
-       unsigned int pal_60:1;
-       unsigned int secam_b:1;
-       unsigned int secam_d:1;
-       unsigned int secam_g:1;
-       unsigned int secam_k:1;
-
-       unsigned int secam_k1:1;
-       unsigned int secam_l:1;
-       unsigned int secam_60:1;
-       unsigned int pad:5;
-} __packed;
-
-struct intel_sdvo_sdtv_resolution_reply {
-       unsigned int res_320x200:1;
-       unsigned int res_320x240:1;
-       unsigned int res_400x300:1;
-       unsigned int res_640x350:1;
-       unsigned int res_640x400:1;
-       unsigned int res_640x480:1;
-       unsigned int res_704x480:1;
-       unsigned int res_704x576:1;
-
-       unsigned int res_720x350:1;
-       unsigned int res_720x400:1;
-       unsigned int res_720x480:1;
-       unsigned int res_720x540:1;
-       unsigned int res_720x576:1;
-       unsigned int res_768x576:1;
-       unsigned int res_800x600:1;
-       unsigned int res_832x624:1;
-
-       unsigned int res_920x766:1;
-       unsigned int res_1024x768:1;
-       unsigned int res_1280x1024:1;
-       unsigned int pad:5;
-} __packed;
-
-/* Get supported resolution with squire pixel aspect ratio that can be
-   scaled for the requested HDTV format */
-#define SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT            0x85
-
-struct intel_sdvo_hdtv_resolution_request {
-       unsigned int hdtv_std_smpte_240m_1080i_59:1;
-       unsigned int hdtv_std_smpte_240m_1080i_60:1;
-       unsigned int hdtv_std_smpte_260m_1080i_59:1;
-       unsigned int hdtv_std_smpte_260m_1080i_60:1;
-       unsigned int hdtv_std_smpte_274m_1080i_50:1;
-       unsigned int hdtv_std_smpte_274m_1080i_59:1;
-       unsigned int hdtv_std_smpte_274m_1080i_60:1;
-       unsigned int hdtv_std_smpte_274m_1080p_23:1;
-
-       unsigned int hdtv_std_smpte_274m_1080p_24:1;
-       unsigned int hdtv_std_smpte_274m_1080p_25:1;
-       unsigned int hdtv_std_smpte_274m_1080p_29:1;
-       unsigned int hdtv_std_smpte_274m_1080p_30:1;
-       unsigned int hdtv_std_smpte_274m_1080p_50:1;
-       unsigned int hdtv_std_smpte_274m_1080p_59:1;
-       unsigned int hdtv_std_smpte_274m_1080p_60:1;
-       unsigned int hdtv_std_smpte_295m_1080i_50:1;
-
-       unsigned int hdtv_std_smpte_295m_1080p_50:1;
-       unsigned int hdtv_std_smpte_296m_720p_59:1;
-       unsigned int hdtv_std_smpte_296m_720p_60:1;
-       unsigned int hdtv_std_smpte_296m_720p_50:1;
-       unsigned int hdtv_std_smpte_293m_480p_59:1;
-       unsigned int hdtv_std_smpte_170m_480i_59:1;
-       unsigned int hdtv_std_iturbt601_576i_50:1;
-       unsigned int hdtv_std_iturbt601_576p_50:1;
-
-       unsigned int hdtv_std_eia_7702a_480i_60:1;
-       unsigned int hdtv_std_eia_7702a_480p_60:1;
-       unsigned int pad:6;
-} __packed;
-
-struct intel_sdvo_hdtv_resolution_reply {
-       unsigned int res_640x480:1;
-       unsigned int res_800x600:1;
-       unsigned int res_1024x768:1;
-       unsigned int res_1280x960:1;
-       unsigned int res_1400x1050:1;
-       unsigned int res_1600x1200:1;
-       unsigned int res_1920x1440:1;
-       unsigned int res_2048x1536:1;
-
-       unsigned int res_2560x1920:1;
-       unsigned int res_3200x2400:1;
-       unsigned int res_3840x2880:1;
-       unsigned int pad1:5;
-
-       unsigned int res_848x480:1;
-       unsigned int res_1064x600:1;
-       unsigned int res_1280x720:1;
-       unsigned int res_1360x768:1;
-       unsigned int res_1704x960:1;
-       unsigned int res_1864x1050:1;
-       unsigned int res_1920x1080:1;
-       unsigned int res_2128x1200:1;
-
-       unsigned int res_2560x1400:1;
-       unsigned int res_2728x1536:1;
-       unsigned int res_3408x1920:1;
-       unsigned int res_4264x2400:1;
-       unsigned int res_5120x2880:1;
-       unsigned int pad2:3;
-
-       unsigned int res_768x480:1;
-       unsigned int res_960x600:1;
-       unsigned int res_1152x720:1;
-       unsigned int res_1124x768:1;
-       unsigned int res_1536x960:1;
-       unsigned int res_1680x1050:1;
-       unsigned int res_1728x1080:1;
-       unsigned int res_1920x1200:1;
-
-       unsigned int res_2304x1440:1;
-       unsigned int res_2456x1536:1;
-       unsigned int res_3072x1920:1;
-       unsigned int res_3840x2400:1;
-       unsigned int res_4608x2880:1;
-       unsigned int pad3:3;
-
-       unsigned int res_1280x1024:1;
-       unsigned int pad4:7;
-
-       unsigned int res_1280x768:1;
-       unsigned int pad5:7;
-} __packed;
-
-/* Get supported power state returns info for encoder and monitor, rely on
-   last SetTargetInput and SetTargetOutput calls */
-#define SDVO_CMD_GET_SUPPORTED_POWER_STATES            0x2a
-/* Get power state returns info for encoder and monitor, rely on last
-   SetTargetInput and SetTargetOutput calls */
-#define SDVO_CMD_GET_POWER_STATE                       0x2b
-#define SDVO_CMD_GET_ENCODER_POWER_STATE               0x2b
-#define SDVO_CMD_SET_ENCODER_POWER_STATE               0x2c
-# define SDVO_ENCODER_STATE_ON                                 (1 << 0)
-# define SDVO_ENCODER_STATE_STANDBY                            (1 << 1)
-# define SDVO_ENCODER_STATE_SUSPEND                            (1 << 2)
-# define SDVO_ENCODER_STATE_OFF                                        (1 << 3)
-# define SDVO_MONITOR_STATE_ON                                 (1 << 4)
-# define SDVO_MONITOR_STATE_STANDBY                            (1 << 5)
-# define SDVO_MONITOR_STATE_SUSPEND                            (1 << 6)
-# define SDVO_MONITOR_STATE_OFF                                        (1 << 7)
-
-#define SDVO_CMD_GET_MAX_PANEL_POWER_SEQUENCING                0x2d
-#define SDVO_CMD_GET_PANEL_POWER_SEQUENCING            0x2e
-#define SDVO_CMD_SET_PANEL_POWER_SEQUENCING            0x2f
-/*
- * The panel power sequencing parameters are in units of milliseconds.
- * The high fields are bits 8:9 of the 10-bit values.
- */
-struct sdvo_panel_power_sequencing {
-       u8 t0;
-       u8 t1;
-       u8 t2;
-       u8 t3;
-       u8 t4;
-
-       unsigned int t0_high:2;
-       unsigned int t1_high:2;
-       unsigned int t2_high:2;
-       unsigned int t3_high:2;
-
-       unsigned int t4_high:2;
-       unsigned int pad:6;
-} __packed;
-
-#define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL               0x30
-struct sdvo_max_backlight_reply {
-       u8 max_value;
-       u8 default_value;
-} __packed;
-
-#define SDVO_CMD_GET_BACKLIGHT_LEVEL                   0x31
-#define SDVO_CMD_SET_BACKLIGHT_LEVEL                   0x32
-
-#define SDVO_CMD_GET_AMBIENT_LIGHT                     0x33
-struct sdvo_get_ambient_light_reply {
-       u16 trip_low;
-       u16 trip_high;
-       u16 value;
-} __packed;
-#define SDVO_CMD_SET_AMBIENT_LIGHT                     0x34
-struct sdvo_set_ambient_light_reply {
-       u16 trip_low;
-       u16 trip_high;
-       unsigned int enable:1;
-       unsigned int pad:7;
-} __packed;
-
-/* Set display power state */
-#define SDVO_CMD_SET_DISPLAY_POWER_STATE               0x7d
-# define SDVO_DISPLAY_STATE_ON                         (1 << 0)
-# define SDVO_DISPLAY_STATE_STANDBY                    (1 << 1)
-# define SDVO_DISPLAY_STATE_SUSPEND                    (1 << 2)
-# define SDVO_DISPLAY_STATE_OFF                                (1 << 3)
-
-#define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS            0x84
-struct intel_sdvo_enhancements_reply {
-       unsigned int flicker_filter:1;
-       unsigned int flicker_filter_adaptive:1;
-       unsigned int flicker_filter_2d:1;
-       unsigned int saturation:1;
-       unsigned int hue:1;
-       unsigned int brightness:1;
-       unsigned int contrast:1;
-       unsigned int overscan_h:1;
-
-       unsigned int overscan_v:1;
-       unsigned int hpos:1;
-       unsigned int vpos:1;
-       unsigned int sharpness:1;
-       unsigned int dot_crawl:1;
-       unsigned int dither:1;
-       unsigned int tv_chroma_filter:1;
-       unsigned int tv_luma_filter:1;
-} __packed;
-
-/* Picture enhancement limits below are dependent on the current TV format,
- * and thus need to be queried and set after it.
- */
-#define SDVO_CMD_GET_MAX_FLICKER_FILTER                        0x4d
-#define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE       0x7b
-#define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D             0x52
-#define SDVO_CMD_GET_MAX_SATURATION                    0x55
-#define SDVO_CMD_GET_MAX_HUE                           0x58
-#define SDVO_CMD_GET_MAX_BRIGHTNESS                    0x5b
-#define SDVO_CMD_GET_MAX_CONTRAST                      0x5e
-#define SDVO_CMD_GET_MAX_OVERSCAN_H                    0x61
-#define SDVO_CMD_GET_MAX_OVERSCAN_V                    0x64
-#define SDVO_CMD_GET_MAX_HPOS                          0x67
-#define SDVO_CMD_GET_MAX_VPOS                          0x6a
-#define SDVO_CMD_GET_MAX_SHARPNESS                     0x6d
-#define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER              0x74
-#define SDVO_CMD_GET_MAX_TV_LUMA_FILTER                        0x77
-struct intel_sdvo_enhancement_limits_reply {
-       u16 max_value;
-       u16 default_value;
-} __packed;
-
-#define SDVO_CMD_GET_LVDS_PANEL_INFORMATION            0x7f
-#define SDVO_CMD_SET_LVDS_PANEL_INFORMATION            0x80
-# define SDVO_LVDS_COLOR_DEPTH_18                      (0 << 0)
-# define SDVO_LVDS_COLOR_DEPTH_24                      (1 << 0)
-# define SDVO_LVDS_CONNECTOR_SPWG                      (0 << 2)
-# define SDVO_LVDS_CONNECTOR_OPENLDI                   (1 << 2)
-# define SDVO_LVDS_SINGLE_CHANNEL                      (0 << 4)
-# define SDVO_LVDS_DUAL_CHANNEL                                (1 << 4)
-
-#define SDVO_CMD_GET_FLICKER_FILTER                    0x4e
-#define SDVO_CMD_SET_FLICKER_FILTER                    0x4f
-#define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE           0x50
-#define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE           0x51
-#define SDVO_CMD_GET_FLICKER_FILTER_2D                 0x53
-#define SDVO_CMD_SET_FLICKER_FILTER_2D                 0x54
-#define SDVO_CMD_GET_SATURATION                                0x56
-#define SDVO_CMD_SET_SATURATION                                0x57
-#define SDVO_CMD_GET_HUE                               0x59
-#define SDVO_CMD_SET_HUE                               0x5a
-#define SDVO_CMD_GET_BRIGHTNESS                                0x5c
-#define SDVO_CMD_SET_BRIGHTNESS                                0x5d
-#define SDVO_CMD_GET_CONTRAST                          0x5f
-#define SDVO_CMD_SET_CONTRAST                          0x60
-#define SDVO_CMD_GET_OVERSCAN_H                                0x62
-#define SDVO_CMD_SET_OVERSCAN_H                                0x63
-#define SDVO_CMD_GET_OVERSCAN_V                                0x65
-#define SDVO_CMD_SET_OVERSCAN_V                                0x66
-#define SDVO_CMD_GET_HPOS                              0x68
-#define SDVO_CMD_SET_HPOS                              0x69
-#define SDVO_CMD_GET_VPOS                              0x6b
-#define SDVO_CMD_SET_VPOS                              0x6c
-#define SDVO_CMD_GET_SHARPNESS                         0x6e
-#define SDVO_CMD_SET_SHARPNESS                         0x6f
-#define SDVO_CMD_GET_TV_CHROMA_FILTER                  0x75
-#define SDVO_CMD_SET_TV_CHROMA_FILTER                  0x76
-#define SDVO_CMD_GET_TV_LUMA_FILTER                    0x78
-#define SDVO_CMD_SET_TV_LUMA_FILTER                    0x79
-struct intel_sdvo_enhancements_arg {
-       u16 value;
-} __packed;
-
-#define SDVO_CMD_GET_DOT_CRAWL                         0x70
-#define SDVO_CMD_SET_DOT_CRAWL                         0x71
-# define SDVO_DOT_CRAWL_ON                                     (1 << 0)
-# define SDVO_DOT_CRAWL_DEFAULT_ON                             (1 << 1)
-
-#define SDVO_CMD_GET_DITHER                            0x72
-#define SDVO_CMD_SET_DITHER                            0x73
-# define SDVO_DITHER_ON                                                (1 << 0)
-# define SDVO_DITHER_DEFAULT_ON                                        (1 << 1)
-
-#define SDVO_CMD_SET_CONTROL_BUS_SWITCH                        0x7a
-# define SDVO_CONTROL_BUS_PROM                         (1 << 0)
-# define SDVO_CONTROL_BUS_DDC1                         (1 << 1)
-# define SDVO_CONTROL_BUS_DDC2                         (1 << 2)
-# define SDVO_CONTROL_BUS_DDC3                         (1 << 3)
-
-/* HDMI op codes */
-#define SDVO_CMD_GET_SUPP_ENCODE       0x9d
-#define SDVO_CMD_GET_ENCODE            0x9e
-#define SDVO_CMD_SET_ENCODE            0x9f
-  #define SDVO_ENCODE_DVI      0x0
-  #define SDVO_ENCODE_HDMI     0x1
-#define SDVO_CMD_SET_PIXEL_REPLI       0x8b
-#define SDVO_CMD_GET_PIXEL_REPLI       0x8c
-#define SDVO_CMD_GET_COLORIMETRY_CAP   0x8d
-#define SDVO_CMD_SET_COLORIMETRY       0x8e
-  #define SDVO_COLORIMETRY_RGB256   0x0
-  #define SDVO_COLORIMETRY_RGB220   0x1
-  #define SDVO_COLORIMETRY_YCrCb422 0x3
-  #define SDVO_COLORIMETRY_YCrCb444 0x4
-#define SDVO_CMD_GET_COLORIMETRY       0x8f
-#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90
-#define SDVO_CMD_SET_AUDIO_STAT                0x91
-#define SDVO_CMD_GET_AUDIO_STAT                0x92
-  #define SDVO_AUDIO_ELD_VALID         (1 << 0)
-  #define SDVO_AUDIO_PRESENCE_DETECT   (1 << 1)
-  #define SDVO_AUDIO_CP_READY          (1 << 2)
-#define SDVO_CMD_SET_HBUF_INDEX                0x93
-  #define SDVO_HBUF_INDEX_ELD          0
-  #define SDVO_HBUF_INDEX_AVI_IF       1
-#define SDVO_CMD_GET_HBUF_INDEX                0x94
-#define SDVO_CMD_GET_HBUF_INFO         0x95
-#define SDVO_CMD_SET_HBUF_AV_SPLIT     0x96
-#define SDVO_CMD_GET_HBUF_AV_SPLIT     0x97
-#define SDVO_CMD_SET_HBUF_DATA         0x98
-#define SDVO_CMD_GET_HBUF_DATA         0x99
-#define SDVO_CMD_SET_HBUF_TXRATE       0x9a
-#define SDVO_CMD_GET_HBUF_TXRATE       0x9b
-  #define SDVO_HBUF_TX_DISABLED        (0 << 6)
-  #define SDVO_HBUF_TX_ONCE    (2 << 6)
-  #define SDVO_HBUF_TX_VSYNC   (3 << 6)
-#define SDVO_CMD_GET_AUDIO_TX_INFO     0x9c
-#define SDVO_NEED_TO_STALL  (1 << 7)
-
-struct intel_sdvo_encode {
-       u8 dvi_rev;
-       u8 hdmi_rev;
-} __packed;
-
-#endif /* __INTEL_SDVO_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
deleted file mode 100644 (file)
index 5dc594e..0000000
+++ /dev/null
@@ -1,1991 +0,0 @@
-/*
- * Copyright © 2006-2008 Intel Corporation
- *   Jesse Barnes <jesse.barnes@intel.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-/** @file
- * Integrated TV-out support for the 915GM and 945GM.
- */
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_connector.h"
-#include "intel_drv.h"
-#include "intel_hotplug.h"
-#include "intel_tv.h"
-
-enum tv_margin {
-       TV_MARGIN_LEFT, TV_MARGIN_TOP,
-       TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
-};
-
-struct intel_tv {
-       struct intel_encoder base;
-
-       int type;
-};
-
-struct video_levels {
-       u16 blank, black;
-       u8 burst;
-};
-
-struct color_conversion {
-       u16 ry, gy, by, ay;
-       u16 ru, gu, bu, au;
-       u16 rv, gv, bv, av;
-};
-
-static const u32 filter_table[] = {
-       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
-       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
-       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
-       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
-       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
-       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
-       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
-       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
-       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
-       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
-       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
-       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
-       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
-       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
-       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
-       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
-       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
-       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
-       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
-       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
-       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
-       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
-       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
-       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
-       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
-       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
-       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
-       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
-       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
-       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
-       0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
-       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
-       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
-       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
-       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
-       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
-       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
-       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
-       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
-       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
-       0x28003100, 0x28002F00, 0x00003100, 0x36403000,
-       0x2D002CC0, 0x30003640, 0x2D0036C0,
-       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
-       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
-       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
-       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
-       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
-       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
-       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
-       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
-       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
-       0x28003100, 0x28002F00, 0x00003100,
-};
-
-/*
- * Color conversion values have 3 separate fixed point formats:
- *
- * 10 bit fields (ay, au)
- *   1.9 fixed point (b.bbbbbbbbb)
- * 11 bit fields (ry, by, ru, gu, gv)
- *   exp.mantissa (ee.mmmmmmmmm)
- *   ee = 00 = 10^-1 (0.mmmmmmmmm)
- *   ee = 01 = 10^-2 (0.0mmmmmmmmm)
- *   ee = 10 = 10^-3 (0.00mmmmmmmmm)
- *   ee = 11 = 10^-4 (0.000mmmmmmmmm)
- * 12 bit fields (gy, rv, bu)
- *   exp.mantissa (eee.mmmmmmmmm)
- *   eee = 000 = 10^-1 (0.mmmmmmmmm)
- *   eee = 001 = 10^-2 (0.0mmmmmmmmm)
- *   eee = 010 = 10^-3 (0.00mmmmmmmmm)
- *   eee = 011 = 10^-4 (0.000mmmmmmmmm)
- *   eee = 100 = reserved
- *   eee = 101 = reserved
- *   eee = 110 = reserved
- *   eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
- *
- * Saturation and contrast are 8 bits, with their own representation:
- * 8 bit field (saturation, contrast)
- *   exp.mantissa (ee.mmmmmm)
- *   ee = 00 = 10^-1 (0.mmmmmm)
- *   ee = 01 = 10^0 (m.mmmmm)
- *   ee = 10 = 10^1 (mm.mmmm)
- *   ee = 11 = 10^2 (mmm.mmm)
- *
- * Simple conversion function:
- *
- * static u32
- * float_to_csc_11(float f)
- * {
- *     u32 exp;
- *     u32 mant;
- *     u32 ret;
- *
- *     if (f < 0)
- *         f = -f;
- *
- *     if (f >= 1) {
- *         exp = 0x7;
- *        mant = 1 << 8;
- *     } else {
- *         for (exp = 0; exp < 3 && f < 0.5; exp++)
- *        f *= 2.0;
- *         mant = (f * (1 << 9) + 0.5);
- *         if (mant >= (1 << 9))
- *             mant = (1 << 9) - 1;
- *     }
- *     ret = (exp << 9) | mant;
- *     return ret;
- * }
- */
-
-/*
- * Behold, magic numbers!  If we plant them they might grow a big
- * s-video cable to the sky... or something.
- *
- * Pre-converted to appropriate hex value.
- */
-
-/*
- * PAL & NTSC values for composite & s-video connections
- */
-static const struct color_conversion ntsc_m_csc_composite = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
-       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
-       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
-};
-
-static const struct video_levels ntsc_m_levels_composite = {
-       .blank = 225, .black = 267, .burst = 113,
-};
-
-static const struct color_conversion ntsc_m_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
-       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
-       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
-};
-
-static const struct video_levels ntsc_m_levels_svideo = {
-       .blank = 266, .black = 316, .burst = 133,
-};
-
-static const struct color_conversion ntsc_j_csc_composite = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
-       .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
-       .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
-};
-
-static const struct video_levels ntsc_j_levels_composite = {
-       .blank = 225, .black = 225, .burst = 113,
-};
-
-static const struct color_conversion ntsc_j_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
-       .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
-       .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
-};
-
-static const struct video_levels ntsc_j_levels_svideo = {
-       .blank = 266, .black = 266, .burst = 133,
-};
-
-static const struct color_conversion pal_csc_composite = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
-       .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
-       .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
-};
-
-static const struct video_levels pal_levels_composite = {
-       .blank = 237, .black = 237, .burst = 118,
-};
-
-static const struct color_conversion pal_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
-       .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
-       .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
-};
-
-static const struct video_levels pal_levels_svideo = {
-       .blank = 280, .black = 280, .burst = 139,
-};
-
-static const struct color_conversion pal_m_csc_composite = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
-       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
-       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
-};
-
-static const struct video_levels pal_m_levels_composite = {
-       .blank = 225, .black = 267, .burst = 113,
-};
-
-static const struct color_conversion pal_m_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
-       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
-       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
-};
-
-static const struct video_levels pal_m_levels_svideo = {
-       .blank = 266, .black = 316, .burst = 133,
-};
-
-static const struct color_conversion pal_n_csc_composite = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
-       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
-       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
-};
-
-static const struct video_levels pal_n_levels_composite = {
-       .blank = 225, .black = 267, .burst = 118,
-};
-
-static const struct color_conversion pal_n_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
-       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
-       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
-};
-
-static const struct video_levels pal_n_levels_svideo = {
-       .blank = 266, .black = 316, .burst = 139,
-};
-
-/*
- * Component connections
- */
-static const struct color_conversion sdtv_csc_yprpb = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
-       .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
-       .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
-};
-
-static const struct color_conversion hdtv_csc_yprpb = {
-       .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
-       .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
-       .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
-};
-
-static const struct video_levels component_levels = {
-       .blank = 279, .black = 279, .burst = 0,
-};
-
-
-struct tv_mode {
-       const char *name;
-
-       u32 clock;
-       u16 refresh; /* in millihertz (for precision) */
-       u8 oversample;
-       u8 hsync_end;
-       u16 hblank_start, hblank_end, htotal;
-       bool progressive : 1, trilevel_sync : 1, component_only : 1;
-       u8 vsync_start_f1, vsync_start_f2, vsync_len;
-       bool veq_ena : 1;
-       u8 veq_start_f1, veq_start_f2, veq_len;
-       u8 vi_end_f1, vi_end_f2;
-       u16 nbr_end;
-       bool burst_ena : 1;
-       u8 hburst_start, hburst_len;
-       u8 vburst_start_f1;
-       u16 vburst_end_f1;
-       u8 vburst_start_f2;
-       u16 vburst_end_f2;
-       u8 vburst_start_f3;
-       u16 vburst_end_f3;
-       u8 vburst_start_f4;
-       u16 vburst_end_f4;
-       /*
-        * subcarrier programming
-        */
-       u16 dda2_size, dda3_size;
-       u8 dda1_inc;
-       u16 dda2_inc, dda3_inc;
-       u32 sc_reset;
-       bool pal_burst : 1;
-       /*
-        * blank/black levels
-        */
-       const struct video_levels *composite_levels, *svideo_levels;
-       const struct color_conversion *composite_color, *svideo_color;
-       const u32 *filter_table;
-};
-
-
-/*
- * Sub carrier DDA
- *
- *  I think this works as follows:
- *
- *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
- *
- * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
- *
- * So,
- *  dda1_ideal = subcarrier/pixel * 4096
- *  dda1_inc = floor (dda1_ideal)
- *  dda2 = dda1_ideal - dda1_inc
- *
- *  then pick a ratio for dda2 that gives the closest approximation. If
- *  you can't get close enough, you can play with dda3 as well. This
- *  seems likely to happen when dda2 is small as the jumps would be larger
- *
- * To invert this,
- *
- *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
- *
- * The constants below were all computed using a 107.520MHz clock
- */
-
-/*
- * Register programming values for TV modes.
- *
- * These values account for -1s required.
- */
-static const struct tv_mode tv_modes[] = {
-       {
-               .name           = "NTSC-M",
-               .clock          = 108000,
-               .refresh        = 59940,
-               .oversample     = 8,
-               .component_only = false,
-               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
-
-               .hsync_end      = 64,               .hblank_end         = 124,
-               .hblank_start   = 836,              .htotal             = 857,
-
-               .progressive    = false,            .trilevel_sync = false,
-
-               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
-               .vsync_len      = 6,
-
-               .veq_ena        = true,             .veq_start_f1       = 0,
-               .veq_start_f2   = 1,                .veq_len            = 18,
-
-               .vi_end_f1      = 20,               .vi_end_f2          = 21,
-               .nbr_end        = 240,
-
-               .burst_ena      = true,
-               .hburst_start   = 72,               .hburst_len         = 34,
-               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
-               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
-               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
-               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
-
-               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
-               .dda1_inc       =    135,
-               .dda2_inc       =  20800,           .dda2_size          =  27456,
-               .dda3_inc       =      0,           .dda3_size          =      0,
-               .sc_reset       = TV_SC_RESET_EVERY_4,
-               .pal_burst      = false,
-
-               .composite_levels = &ntsc_m_levels_composite,
-               .composite_color = &ntsc_m_csc_composite,
-               .svideo_levels  = &ntsc_m_levels_svideo,
-               .svideo_color = &ntsc_m_csc_svideo,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name           = "NTSC-443",
-               .clock          = 108000,
-               .refresh        = 59940,
-               .oversample     = 8,
-               .component_only = false,
-               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
-               .hsync_end      = 64,               .hblank_end         = 124,
-               .hblank_start   = 836,              .htotal             = 857,
-
-               .progressive    = false,            .trilevel_sync = false,
-
-               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
-               .vsync_len      = 6,
-
-               .veq_ena        = true,             .veq_start_f1       = 0,
-               .veq_start_f2   = 1,                .veq_len            = 18,
-
-               .vi_end_f1      = 20,               .vi_end_f2          = 21,
-               .nbr_end        = 240,
-
-               .burst_ena      = true,
-               .hburst_start   = 72,               .hburst_len         = 34,
-               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
-               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
-               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
-               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
-
-               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
-               .dda1_inc       =    168,
-               .dda2_inc       =   4093,       .dda2_size      =  27456,
-               .dda3_inc       =    310,       .dda3_size      =    525,
-               .sc_reset   = TV_SC_RESET_NEVER,
-               .pal_burst  = false,
-
-               .composite_levels = &ntsc_m_levels_composite,
-               .composite_color = &ntsc_m_csc_composite,
-               .svideo_levels  = &ntsc_m_levels_svideo,
-               .svideo_color = &ntsc_m_csc_svideo,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name           = "NTSC-J",
-               .clock          = 108000,
-               .refresh        = 59940,
-               .oversample     = 8,
-               .component_only = false,
-
-               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
-               .hsync_end      = 64,               .hblank_end         = 124,
-               .hblank_start = 836,        .htotal             = 857,
-
-               .progressive    = false,    .trilevel_sync = false,
-
-               .vsync_start_f1 = 6,        .vsync_start_f2     = 7,
-               .vsync_len      = 6,
-
-               .veq_ena      = true,       .veq_start_f1       = 0,
-               .veq_start_f2 = 1,          .veq_len            = 18,
-
-               .vi_end_f1      = 20,               .vi_end_f2          = 21,
-               .nbr_end        = 240,
-
-               .burst_ena      = true,
-               .hburst_start   = 72,               .hburst_len         = 34,
-               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
-               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
-               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
-               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
-
-               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
-               .dda1_inc       =    135,
-               .dda2_inc       =  20800,           .dda2_size          =  27456,
-               .dda3_inc       =      0,           .dda3_size          =      0,
-               .sc_reset       = TV_SC_RESET_EVERY_4,
-               .pal_burst      = false,
-
-               .composite_levels = &ntsc_j_levels_composite,
-               .composite_color = &ntsc_j_csc_composite,
-               .svideo_levels  = &ntsc_j_levels_svideo,
-               .svideo_color = &ntsc_j_csc_svideo,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name           = "PAL-M",
-               .clock          = 108000,
-               .refresh        = 59940,
-               .oversample     = 8,
-               .component_only = false,
-
-               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
-               .hsync_end      = 64,             .hblank_end           = 124,
-               .hblank_start = 836,      .htotal               = 857,
-
-               .progressive    = false,            .trilevel_sync = false,
-
-               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
-               .vsync_len      = 6,
-
-               .veq_ena        = true,             .veq_start_f1       = 0,
-               .veq_start_f2   = 1,                .veq_len            = 18,
-
-               .vi_end_f1      = 20,               .vi_end_f2          = 21,
-               .nbr_end        = 240,
-
-               .burst_ena      = true,
-               .hburst_start   = 72,               .hburst_len         = 34,
-               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
-               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
-               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
-               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
-
-               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
-               .dda1_inc       =    135,
-               .dda2_inc       =  16704,           .dda2_size          =  27456,
-               .dda3_inc       =      0,           .dda3_size          =      0,
-               .sc_reset       = TV_SC_RESET_EVERY_8,
-               .pal_burst  = true,
-
-               .composite_levels = &pal_m_levels_composite,
-               .composite_color = &pal_m_csc_composite,
-               .svideo_levels  = &pal_m_levels_svideo,
-               .svideo_color = &pal_m_csc_svideo,
-
-               .filter_table = filter_table,
-       },
-       {
-               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
-               .name       = "PAL-N",
-               .clock          = 108000,
-               .refresh        = 50000,
-               .oversample     = 8,
-               .component_only = false,
-
-               .hsync_end      = 64,               .hblank_end         = 128,
-               .hblank_start = 844,        .htotal             = 863,
-
-               .progressive  = false,    .trilevel_sync = false,
-
-
-               .vsync_start_f1 = 6,       .vsync_start_f2      = 7,
-               .vsync_len      = 6,
-
-               .veq_ena        = true,             .veq_start_f1       = 0,
-               .veq_start_f2   = 1,                .veq_len            = 18,
-
-               .vi_end_f1      = 24,               .vi_end_f2          = 25,
-               .nbr_end        = 286,
-
-               .burst_ena      = true,
-               .hburst_start = 73,         .hburst_len         = 34,
-               .vburst_start_f1 = 8,       .vburst_end_f1      = 285,
-               .vburst_start_f2 = 8,       .vburst_end_f2      = 286,
-               .vburst_start_f3 = 9,       .vburst_end_f3      = 286,
-               .vburst_start_f4 = 9,       .vburst_end_f4      = 285,
-
-
-               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
-               .dda1_inc       =    135,
-               .dda2_inc       =  23578,       .dda2_size      =  27648,
-               .dda3_inc       =    134,       .dda3_size      =    625,
-               .sc_reset   = TV_SC_RESET_EVERY_8,
-               .pal_burst  = true,
-
-               .composite_levels = &pal_n_levels_composite,
-               .composite_color = &pal_n_csc_composite,
-               .svideo_levels  = &pal_n_levels_svideo,
-               .svideo_color = &pal_n_csc_svideo,
-
-               .filter_table = filter_table,
-       },
-       {
-               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
-               .name       = "PAL",
-               .clock          = 108000,
-               .refresh        = 50000,
-               .oversample     = 8,
-               .component_only = false,
-
-               .hsync_end      = 64,               .hblank_end         = 142,
-               .hblank_start   = 844,      .htotal             = 863,
-
-               .progressive    = false,    .trilevel_sync = false,
-
-               .vsync_start_f1 = 5,        .vsync_start_f2     = 6,
-               .vsync_len      = 5,
-
-               .veq_ena        = true,     .veq_start_f1       = 0,
-               .veq_start_f2   = 1,        .veq_len            = 15,
-
-               .vi_end_f1      = 24,               .vi_end_f2          = 25,
-               .nbr_end        = 286,
-
-               .burst_ena      = true,
-               .hburst_start   = 73,               .hburst_len         = 32,
-               .vburst_start_f1 = 8,               .vburst_end_f1      = 285,
-               .vburst_start_f2 = 8,               .vburst_end_f2      = 286,
-               .vburst_start_f3 = 9,               .vburst_end_f3      = 286,
-               .vburst_start_f4 = 9,               .vburst_end_f4      = 285,
-
-               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
-               .dda1_inc       =    168,
-               .dda2_inc       =   4122,       .dda2_size      =  27648,
-               .dda3_inc       =     67,       .dda3_size      =    625,
-               .sc_reset   = TV_SC_RESET_EVERY_8,
-               .pal_burst  = true,
-
-               .composite_levels = &pal_levels_composite,
-               .composite_color = &pal_csc_composite,
-               .svideo_levels  = &pal_levels_svideo,
-               .svideo_color = &pal_csc_svideo,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name       = "480p",
-               .clock          = 108000,
-               .refresh        = 59940,
-               .oversample     = 4,
-               .component_only = true,
-
-               .hsync_end      = 64,               .hblank_end         = 122,
-               .hblank_start   = 842,              .htotal             = 857,
-
-               .progressive    = true,             .trilevel_sync = false,
-
-               .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
-               .vsync_len      = 12,
-
-               .veq_ena        = false,
-
-               .vi_end_f1      = 44,               .vi_end_f2          = 44,
-               .nbr_end        = 479,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name       = "576p",
-               .clock          = 108000,
-               .refresh        = 50000,
-               .oversample     = 4,
-               .component_only = true,
-
-               .hsync_end      = 64,               .hblank_end         = 139,
-               .hblank_start   = 859,              .htotal             = 863,
-
-               .progressive    = true,             .trilevel_sync = false,
-
-               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
-               .vsync_len      = 10,
-
-               .veq_ena        = false,
-
-               .vi_end_f1      = 48,               .vi_end_f2          = 48,
-               .nbr_end        = 575,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name       = "720p@60Hz",
-               .clock          = 148500,
-               .refresh        = 60000,
-               .oversample     = 2,
-               .component_only = true,
-
-               .hsync_end      = 80,               .hblank_end         = 300,
-               .hblank_start   = 1580,             .htotal             = 1649,
-
-               .progressive    = true,             .trilevel_sync = true,
-
-               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
-               .vsync_len      = 10,
-
-               .veq_ena        = false,
-
-               .vi_end_f1      = 29,               .vi_end_f2          = 29,
-               .nbr_end        = 719,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name       = "720p@50Hz",
-               .clock          = 148500,
-               .refresh        = 50000,
-               .oversample     = 2,
-               .component_only = true,
-
-               .hsync_end      = 80,               .hblank_end         = 300,
-               .hblank_start   = 1580,             .htotal             = 1979,
-
-               .progressive    = true,             .trilevel_sync = true,
-
-               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
-               .vsync_len      = 10,
-
-               .veq_ena        = false,
-
-               .vi_end_f1      = 29,               .vi_end_f2          = 29,
-               .nbr_end        = 719,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name       = "1080i@50Hz",
-               .clock          = 148500,
-               .refresh        = 50000,
-               .oversample     = 2,
-               .component_only = true,
-
-               .hsync_end      = 88,               .hblank_end         = 235,
-               .hblank_start   = 2155,             .htotal             = 2639,
-
-               .progressive    = false,          .trilevel_sync = true,
-
-               .vsync_start_f1 = 4,              .vsync_start_f2     = 5,
-               .vsync_len      = 10,
-
-               .veq_ena        = true,     .veq_start_f1       = 4,
-               .veq_start_f2   = 4,        .veq_len            = 10,
-
-
-               .vi_end_f1      = 21,           .vi_end_f2          = 22,
-               .nbr_end        = 539,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-       {
-               .name       = "1080i@60Hz",
-               .clock          = 148500,
-               .refresh        = 60000,
-               .oversample     = 2,
-               .component_only = true,
-
-               .hsync_end      = 88,               .hblank_end         = 235,
-               .hblank_start   = 2155,             .htotal             = 2199,
-
-               .progressive    = false,            .trilevel_sync = true,
-
-               .vsync_start_f1 = 4,               .vsync_start_f2     = 5,
-               .vsync_len      = 10,
-
-               .veq_ena        = true,             .veq_start_f1       = 4,
-               .veq_start_f2   = 4,                .veq_len            = 10,
-
-
-               .vi_end_f1      = 21,               .vi_end_f2          = 22,
-               .nbr_end        = 539,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-
-       {
-               .name       = "1080p@30Hz",
-               .clock          = 148500,
-               .refresh        = 30000,
-               .oversample     = 2,
-               .component_only = true,
-
-               .hsync_end      = 88,               .hblank_end         = 235,
-               .hblank_start   = 2155,             .htotal             = 2199,
-
-               .progressive    = true,             .trilevel_sync = true,
-
-               .vsync_start_f1 = 8,               .vsync_start_f2     = 8,
-               .vsync_len      = 10,
-
-               .veq_ena        = false,        .veq_start_f1   = 0,
-               .veq_start_f2   = 0,                .veq_len            = 0,
-
-               .vi_end_f1      = 44,               .vi_end_f2          = 44,
-               .nbr_end        = 1079,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-
-       {
-               .name       = "1080p@50Hz",
-               .clock          = 148500,
-               .refresh        = 50000,
-               .oversample     = 1,
-               .component_only = true,
-
-               .hsync_end      = 88,               .hblank_end         = 235,
-               .hblank_start   = 2155,             .htotal             = 2639,
-
-               .progressive    = true,             .trilevel_sync = true,
-
-               .vsync_start_f1 = 8,               .vsync_start_f2     = 8,
-               .vsync_len      = 10,
-
-               .veq_ena        = false,        .veq_start_f1   = 0,
-               .veq_start_f2   = 0,                .veq_len            = 0,
-
-               .vi_end_f1      = 44,               .vi_end_f2          = 44,
-               .nbr_end        = 1079,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-
-       {
-               .name       = "1080p@60Hz",
-               .clock          = 148500,
-               .refresh        = 60000,
-               .oversample     = 1,
-               .component_only = true,
-
-               .hsync_end      = 88,               .hblank_end         = 235,
-               .hblank_start   = 2155,             .htotal             = 2199,
-
-               .progressive    = true,             .trilevel_sync = true,
-
-               .vsync_start_f1 = 8,               .vsync_start_f2     = 8,
-               .vsync_len      = 10,
-
-               .veq_ena        = false,                    .veq_start_f1       = 0,
-               .veq_start_f2   = 0,                .veq_len            = 0,
-
-               .vi_end_f1      = 44,               .vi_end_f2          = 44,
-               .nbr_end        = 1079,
-
-               .burst_ena      = false,
-
-               .filter_table = filter_table,
-       },
-};
-
-struct intel_tv_connector_state {
-       struct drm_connector_state base;
-
-       /*
-        * May need to override the user margins for
-        * gen3 >1024 wide source vertical centering.
-        */
-       struct {
-               u16 top, bottom;
-       } margins;
-
-       bool bypass_vfilter;
-};
-
-#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
-
-static struct drm_connector_state *
-intel_tv_connector_duplicate_state(struct drm_connector *connector)
-{
-       struct intel_tv_connector_state *state;
-
-       state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
-       if (!state)
-               return NULL;
-
-       __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
-       return &state->base;
-}
-
-static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
-{
-       return container_of(encoder, struct intel_tv, base);
-}
-
-static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
-{
-       return enc_to_tv(intel_attached_encoder(connector));
-}
-
-static bool
-intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 tmp = I915_READ(TV_CTL);
-
-       *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
-
-       return tmp & TV_ENC_ENABLE;
-}
-
-static void
-intel_enable_tv(struct intel_encoder *encoder,
-               const struct intel_crtc_state *pipe_config,
-               const struct drm_connector_state *conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       /* Prevents vblank waits from timing out in intel_tv_detect_type() */
-       intel_wait_for_vblank(dev_priv,
-                             to_intel_crtc(pipe_config->base.crtc)->pipe);
-
-       I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
-}
-
-static void
-intel_disable_tv(struct intel_encoder *encoder,
-                const struct intel_crtc_state *old_crtc_state,
-                const struct drm_connector_state *old_conn_state)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
-}
-
-static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
-{
-       int format = conn_state->tv.mode;
-
-       return &tv_modes[format];
-}
-
-static enum drm_mode_status
-intel_tv_mode_valid(struct drm_connector *connector,
-                   struct drm_display_mode *mode)
-{
-       const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       if (mode->clock > max_dotclk)
-               return MODE_CLOCK_HIGH;
-
-       /* Ensure TV refresh is close to desired refresh */
-       if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
-                               < 1000)
-               return MODE_OK;
-
-       return MODE_CLOCK_RANGE;
-}
-
-static int
-intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
-{
-       if (tv_mode->progressive)
-               return tv_mode->nbr_end + 1;
-       else
-               return 2 * (tv_mode->nbr_end + 1);
-}
-
-static void
-intel_tv_mode_to_mode(struct drm_display_mode *mode,
-                     const struct tv_mode *tv_mode)
-{
-       mode->clock = tv_mode->clock /
-               (tv_mode->oversample >> !tv_mode->progressive);
-
-       /*
-        * tv_mode horizontal timings:
-        *
-        * hsync_end
-        *    | hblank_end
-        *    |    | hblank_start
-        *    |    |       | htotal
-        *    |     _______    |
-        *     ____/       \___
-        * \__/                \
-        */
-       mode->hdisplay =
-               tv_mode->hblank_start - tv_mode->hblank_end;
-       mode->hsync_start = mode->hdisplay +
-               tv_mode->htotal - tv_mode->hblank_start;
-       mode->hsync_end = mode->hsync_start +
-               tv_mode->hsync_end;
-       mode->htotal = tv_mode->htotal + 1;
-
-       /*
-        * tv_mode vertical timings:
-        *
-        * vsync_start
-        *    | vsync_end
-        *    |  | vi_end nbr_end
-        *    |  |    |       |
-        *    |  |     _______
-        * \__    ____/       \
-        *    \__/
-        */
-       mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
-       if (tv_mode->progressive) {
-               mode->vsync_start = mode->vdisplay +
-                       tv_mode->vsync_start_f1 + 1;
-               mode->vsync_end = mode->vsync_start +
-                       tv_mode->vsync_len;
-               mode->vtotal = mode->vdisplay +
-                       tv_mode->vi_end_f1 + 1;
-       } else {
-               mode->vsync_start = mode->vdisplay +
-                       tv_mode->vsync_start_f1 + 1 +
-                       tv_mode->vsync_start_f2 + 1;
-               mode->vsync_end = mode->vsync_start +
-                       2 * tv_mode->vsync_len;
-               mode->vtotal = mode->vdisplay +
-                       tv_mode->vi_end_f1 + 1 +
-                       tv_mode->vi_end_f2 + 1;
-       }
-
-       /* TV has it's own notion of sync and other mode flags, so clear them. */
-       mode->flags = 0;
-
-       mode->vrefresh = 0;
-       mode->vrefresh = drm_mode_vrefresh(mode);
-
-       snprintf(mode->name, sizeof(mode->name),
-                "%dx%d%c (%s)",
-                mode->hdisplay, mode->vdisplay,
-                tv_mode->progressive ? 'p' : 'i',
-                tv_mode->name);
-}
-
-static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
-                                     int hdisplay, int left_margin,
-                                     int right_margin)
-{
-       int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
-       int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
-       int new_htotal = mode->htotal * hdisplay /
-               (mode->hdisplay - left_margin - right_margin);
-
-       mode->clock = mode->clock * new_htotal / mode->htotal;
-
-       mode->hdisplay = hdisplay;
-       mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
-       mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
-       mode->htotal = new_htotal;
-}
-
-static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
-                                    int vdisplay, int top_margin,
-                                    int bottom_margin)
-{
-       int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
-       int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
-       int new_vtotal = mode->vtotal * vdisplay /
-               (mode->vdisplay - top_margin - bottom_margin);
-
-       mode->clock = mode->clock * new_vtotal / mode->vtotal;
-
-       mode->vdisplay = vdisplay;
-       mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
-       mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
-       mode->vtotal = new_vtotal;
-}
-
-static void
-intel_tv_get_config(struct intel_encoder *encoder,
-                   struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct drm_display_mode *adjusted_mode =
-               &pipe_config->base.adjusted_mode;
-       struct drm_display_mode mode = {};
-       u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
-       struct tv_mode tv_mode = {};
-       int hdisplay = adjusted_mode->crtc_hdisplay;
-       int vdisplay = adjusted_mode->crtc_vdisplay;
-       int xsize, ysize, xpos, ypos;
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
-
-       tv_ctl = I915_READ(TV_CTL);
-       hctl1 = I915_READ(TV_H_CTL_1);
-       hctl3 = I915_READ(TV_H_CTL_3);
-       vctl1 = I915_READ(TV_V_CTL_1);
-       vctl2 = I915_READ(TV_V_CTL_2);
-
-       tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
-       tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
-
-       tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
-       tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
-
-       tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
-       tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
-       tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
-
-       tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
-       tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
-       tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
-
-       tv_mode.clock = pipe_config->port_clock;
-
-       tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
-
-       switch (tv_ctl & TV_OVERSAMPLE_MASK) {
-       case TV_OVERSAMPLE_8X:
-               tv_mode.oversample = 8;
-               break;
-       case TV_OVERSAMPLE_4X:
-               tv_mode.oversample = 4;
-               break;
-       case TV_OVERSAMPLE_2X:
-               tv_mode.oversample = 2;
-               break;
-       default:
-               tv_mode.oversample = 1;
-               break;
-       }
-
-       tmp = I915_READ(TV_WIN_POS);
-       xpos = tmp >> 16;
-       ypos = tmp & 0xffff;
-
-       tmp = I915_READ(TV_WIN_SIZE);
-       xsize = tmp >> 16;
-       ysize = tmp & 0xffff;
-
-       intel_tv_mode_to_mode(&mode, &tv_mode);
-
-       DRM_DEBUG_KMS("TV mode:\n");
-       drm_mode_debug_printmodeline(&mode);
-
-       intel_tv_scale_mode_horiz(&mode, hdisplay,
-                                 xpos, mode.hdisplay - xsize - xpos);
-       intel_tv_scale_mode_vert(&mode, vdisplay,
-                                ypos, mode.vdisplay - ysize - ypos);
-
-       adjusted_mode->crtc_clock = mode.clock;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
-               adjusted_mode->crtc_clock /= 2;
-
-       /* pixel counter doesn't work on i965gm TV output */
-       if (IS_I965GM(dev_priv))
-               adjusted_mode->private_flags |=
-                       I915_MODE_FLAG_USE_SCANLINE_COUNTER;
-}
-
-static bool intel_tv_source_too_wide(struct drm_i915_private *dev_priv,
-                                    int hdisplay)
-{
-       return IS_GEN(dev_priv, 3) && hdisplay > 1024;
-}
-
-static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode,
-                                 const struct drm_connector_state *conn_state,
-                                 int vdisplay)
-{
-       return tv_mode->crtc_vdisplay -
-               conn_state->tv.margins.top -
-               conn_state->tv.margins.bottom !=
-               vdisplay;
-}
-
-static int
-intel_tv_compute_config(struct intel_encoder *encoder,
-                       struct intel_crtc_state *pipe_config,
-                       struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_tv_connector_state *tv_conn_state =
-               to_intel_tv_connector_state(conn_state);
-       const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
-       struct drm_display_mode *adjusted_mode =
-               &pipe_config->base.adjusted_mode;
-       int hdisplay = adjusted_mode->crtc_hdisplay;
-       int vdisplay = adjusted_mode->crtc_vdisplay;
-
-       if (!tv_mode)
-               return -EINVAL;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
-       pipe_config->pipe_bpp = 8*3;
-
-       pipe_config->port_clock = tv_mode->clock;
-
-       intel_tv_mode_to_mode(adjusted_mode, tv_mode);
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-
-       if (intel_tv_source_too_wide(dev_priv, hdisplay) ||
-           !intel_tv_vert_scaling(adjusted_mode, conn_state, vdisplay)) {
-               int extra, top, bottom;
-
-               extra = adjusted_mode->crtc_vdisplay - vdisplay;
-
-               if (extra < 0) {
-                       DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
-                       return -EINVAL;
-               }
-
-               /* Need to turn off the vertical filter and center the image */
-
-               /* Attempt to maintain the relative sizes of the margins */
-               top = conn_state->tv.margins.top;
-               bottom = conn_state->tv.margins.bottom;
-
-               if (top + bottom)
-                       top = extra * top / (top + bottom);
-               else
-                       top = extra / 2;
-               bottom = extra - top;
-
-               tv_conn_state->margins.top = top;
-               tv_conn_state->margins.bottom = bottom;
-
-               tv_conn_state->bypass_vfilter = true;
-
-               if (!tv_mode->progressive) {
-                       adjusted_mode->clock /= 2;
-                       adjusted_mode->crtc_clock /= 2;
-                       adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
-               }
-       } else {
-               tv_conn_state->margins.top = conn_state->tv.margins.top;
-               tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
-
-               tv_conn_state->bypass_vfilter = false;
-       }
-
-       DRM_DEBUG_KMS("TV mode:\n");
-       drm_mode_debug_printmodeline(adjusted_mode);
-
-       /*
-        * The pipe scanline counter behaviour looks as follows when
-        * using the TV encoder:
-        *
-        * time ->
-        *
-        * dsl=vtotal-1       |             |
-        *                   ||            ||
-        *               ___| |        ___| |
-        *              /     |       /     |
-        *             /      |      /      |
-        * dsl=0   ___/       |_____/       |
-        *        | | |  |  | |
-        *         ^ ^ ^   ^ ^
-        *         | | |   | pipe vblank/first part of tv vblank
-        *         | | |   bottom margin
-        *         | | active
-        *         | top margin
-        *         remainder of tv vblank
-        *
-        * When the TV encoder is used the pipe wants to run faster
-        * than expected rate. During the active portion the TV
-        * encoder stalls the pipe every few lines to keep it in
-        * check. When the TV encoder reaches the bottom margin the
-        * pipe simply stops. Once we reach the TV vblank the pipe is
-        * no longer stalled and it runs at the max rate (apparently
-        * oversample clock on gen3, cdclk on gen4). Once the pipe
-        * reaches the pipe vtotal the pipe stops for the remainder
-        * of the TV vblank/top margin. The pipe starts up again when
-        * the TV encoder exits the top margin.
-        *
-        * To avoid huge hassles for vblank timestamping we scale
-        * the pipe timings as if the pipe always runs at the average
-        * rate it maintains during the active period. This also
-        * gives us a reasonable guesstimate as to the pixel rate.
-        * Due to the variation in the actual pipe speed the scanline
-        * counter will give us slightly erroneous results during the
-        * TV vblank/margins. But since vtotal was selected such that
-        * it matches the average rate of the pipe during the active
-        * portion the error shouldn't cause any serious grief to
-        * vblank timestamps.
-        *
-        * For posterity here is the empirically derived formula
-        * that gives us the maximum length of the pipe vblank
-        * we can use without causing display corruption. Following
-        * this would allow us to have a ticking scanline counter
-        * everywhere except during the bottom margin (there the
-        * pipe always stops). Ie. this would eliminate the second
-        * flat portion of the above graph. However this would also
-        * complicate vblank timestamping as the pipe vtotal would
-        * no longer match the average rate the pipe runs at during
-        * the active portion. Hence following this formula seems
-        * more trouble that it's worth.
-        *
-        * if (IS_GEN(dev_priv, 4)) {
-        *      num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
-        *      den = tv_mode->clock;
-        * } else {
-        *      num = tv_mode->oversample >> !tv_mode->progressive;
-        *      den = 1;
-        * }
-        * max_pipe_vblank_len ~=
-        *      (num * tv_htotal * (tv_vblank_len + top_margin)) /
-        *      (den * pipe_htotal);
-        */
-       intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
-                                 conn_state->tv.margins.left,
-                                 conn_state->tv.margins.right);
-       intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
-                                tv_conn_state->margins.top,
-                                tv_conn_state->margins.bottom);
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-       adjusted_mode->name[0] = '\0';
-
-       /* pixel counter doesn't work on i965gm TV output */
-       if (IS_I965GM(dev_priv))
-               adjusted_mode->private_flags |=
-                       I915_MODE_FLAG_USE_SCANLINE_COUNTER;
-
-       return 0;
-}
-
-static void
-set_tv_mode_timings(struct drm_i915_private *dev_priv,
-                   const struct tv_mode *tv_mode,
-                   bool burst_ena)
-{
-       u32 hctl1, hctl2, hctl3;
-       u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
-
-       hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
-               (tv_mode->htotal << TV_HTOTAL_SHIFT);
-
-       hctl2 = (tv_mode->hburst_start << 16) |
-               (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
-
-       if (burst_ena)
-               hctl2 |= TV_BURST_ENA;
-
-       hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
-               (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
-
-       vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
-               (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
-               (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
-
-       vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
-               (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
-               (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
-
-       vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
-               (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
-               (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
-
-       if (tv_mode->veq_ena)
-               vctl3 |= TV_EQUAL_ENA;
-
-       vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
-               (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
-
-       vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
-               (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
-
-       vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
-               (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
-
-       vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
-               (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
-
-       I915_WRITE(TV_H_CTL_1, hctl1);
-       I915_WRITE(TV_H_CTL_2, hctl2);
-       I915_WRITE(TV_H_CTL_3, hctl3);
-       I915_WRITE(TV_V_CTL_1, vctl1);
-       I915_WRITE(TV_V_CTL_2, vctl2);
-       I915_WRITE(TV_V_CTL_3, vctl3);
-       I915_WRITE(TV_V_CTL_4, vctl4);
-       I915_WRITE(TV_V_CTL_5, vctl5);
-       I915_WRITE(TV_V_CTL_6, vctl6);
-       I915_WRITE(TV_V_CTL_7, vctl7);
-}
-
-static void set_color_conversion(struct drm_i915_private *dev_priv,
-                                const struct color_conversion *color_conversion)
-{
-       if (!color_conversion)
-               return;
-
-       I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
-                  color_conversion->gy);
-       I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
-                  color_conversion->ay);
-       I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
-                  color_conversion->gu);
-       I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
-                  color_conversion->au);
-       I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
-                  color_conversion->gv);
-       I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
-                  color_conversion->av);
-}
-
-static void intel_tv_pre_enable(struct intel_encoder *encoder,
-                               const struct intel_crtc_state *pipe_config,
-                               const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_tv *intel_tv = enc_to_tv(encoder);
-       const struct intel_tv_connector_state *tv_conn_state =
-               to_intel_tv_connector_state(conn_state);
-       const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
-       u32 tv_ctl, tv_filter_ctl;
-       u32 scctl1, scctl2, scctl3;
-       int i, j;
-       const struct video_levels *video_levels;
-       const struct color_conversion *color_conversion;
-       bool burst_ena;
-       int xpos, ypos;
-       unsigned int xsize, ysize;
-
-       if (!tv_mode)
-               return; /* can't happen (mode_prepare prevents this) */
-
-       tv_ctl = I915_READ(TV_CTL);
-       tv_ctl &= TV_CTL_SAVE;
-
-       switch (intel_tv->type) {
-       default:
-       case DRM_MODE_CONNECTOR_Unknown:
-       case DRM_MODE_CONNECTOR_Composite:
-               tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
-               video_levels = tv_mode->composite_levels;
-               color_conversion = tv_mode->composite_color;
-               burst_ena = tv_mode->burst_ena;
-               break;
-       case DRM_MODE_CONNECTOR_Component:
-               tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
-               video_levels = &component_levels;
-               if (tv_mode->burst_ena)
-                       color_conversion = &sdtv_csc_yprpb;
-               else
-                       color_conversion = &hdtv_csc_yprpb;
-               burst_ena = false;
-               break;
-       case DRM_MODE_CONNECTOR_SVIDEO:
-               tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
-               video_levels = tv_mode->svideo_levels;
-               color_conversion = tv_mode->svideo_color;
-               burst_ena = tv_mode->burst_ena;
-               break;
-       }
-
-       tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
-
-       switch (tv_mode->oversample) {
-       case 8:
-               tv_ctl |= TV_OVERSAMPLE_8X;
-               break;
-       case 4:
-               tv_ctl |= TV_OVERSAMPLE_4X;
-               break;
-       case 2:
-               tv_ctl |= TV_OVERSAMPLE_2X;
-               break;
-       default:
-               tv_ctl |= TV_OVERSAMPLE_NONE;
-               break;
-       }
-
-       if (tv_mode->progressive)
-               tv_ctl |= TV_PROGRESSIVE;
-       if (tv_mode->trilevel_sync)
-               tv_ctl |= TV_TRILEVEL_SYNC;
-       if (tv_mode->pal_burst)
-               tv_ctl |= TV_PAL_BURST;
-
-       scctl1 = 0;
-       if (tv_mode->dda1_inc)
-               scctl1 |= TV_SC_DDA1_EN;
-       if (tv_mode->dda2_inc)
-               scctl1 |= TV_SC_DDA2_EN;
-       if (tv_mode->dda3_inc)
-               scctl1 |= TV_SC_DDA3_EN;
-       scctl1 |= tv_mode->sc_reset;
-       if (video_levels)
-               scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
-       scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
-
-       scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
-               tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
-
-       scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
-               tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
-
-       /* Enable two fixes for the chips that need them. */
-       if (IS_I915GM(dev_priv))
-               tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
-
-       set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
-
-       I915_WRITE(TV_SC_CTL_1, scctl1);
-       I915_WRITE(TV_SC_CTL_2, scctl2);
-       I915_WRITE(TV_SC_CTL_3, scctl3);
-
-       set_color_conversion(dev_priv, color_conversion);
-
-       if (INTEL_GEN(dev_priv) >= 4)
-               I915_WRITE(TV_CLR_KNOBS, 0x00404000);
-       else
-               I915_WRITE(TV_CLR_KNOBS, 0x00606000);
-
-       if (video_levels)
-               I915_WRITE(TV_CLR_LEVEL,
-                          ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
-                           (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
-
-       assert_pipe_disabled(dev_priv, intel_crtc->pipe);
-
-       /* Filter ctl must be set before TV_WIN_SIZE */
-       tv_filter_ctl = TV_AUTO_SCALE;
-       if (tv_conn_state->bypass_vfilter)
-               tv_filter_ctl |= TV_V_FILTER_BYPASS;
-       I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
-
-       xsize = tv_mode->hblank_start - tv_mode->hblank_end;
-       ysize = intel_tv_mode_vdisplay(tv_mode);
-
-       xpos = conn_state->tv.margins.left;
-       ypos = tv_conn_state->margins.top;
-       xsize -= (conn_state->tv.margins.left +
-                 conn_state->tv.margins.right);
-       ysize -= (tv_conn_state->margins.top +
-                 tv_conn_state->margins.bottom);
-       I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
-       I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
-
-       j = 0;
-       for (i = 0; i < 60; i++)
-               I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
-       for (i = 0; i < 60; i++)
-               I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
-       for (i = 0; i < 43; i++)
-               I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
-       for (i = 0; i < 43; i++)
-               I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
-       I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
-       I915_WRITE(TV_CTL, tv_ctl);
-}
-
-static int
-intel_tv_detect_type(struct intel_tv *intel_tv,
-                     struct drm_connector *connector)
-{
-       struct drm_crtc *crtc = connector->state->crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 tv_ctl, save_tv_ctl;
-       u32 tv_dac, save_tv_dac;
-       int type;
-
-       /* Disable TV interrupts around load detect or we'll recurse */
-       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
-               spin_lock_irq(&dev_priv->irq_lock);
-               i915_disable_pipestat(dev_priv, 0,
-                                     PIPE_HOTPLUG_INTERRUPT_STATUS |
-                                     PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
-               spin_unlock_irq(&dev_priv->irq_lock);
-       }
-
-       save_tv_dac = tv_dac = I915_READ(TV_DAC);
-       save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
-
-       /* Poll for TV detection */
-       tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
-       tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-       tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
-
-       tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
-       tv_dac |= (TVDAC_STATE_CHG_EN |
-                  TVDAC_A_SENSE_CTL |
-                  TVDAC_B_SENSE_CTL |
-                  TVDAC_C_SENSE_CTL |
-                  DAC_CTL_OVERRIDE |
-                  DAC_A_0_7_V |
-                  DAC_B_0_7_V |
-                  DAC_C_0_7_V);
-
-
-       /*
-        * The TV sense state should be cleared to zero on cantiga platform. Otherwise
-        * the TV is misdetected. This is hardware requirement.
-        */
-       if (IS_GM45(dev_priv))
-               tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
-                           TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
-
-       I915_WRITE(TV_CTL, tv_ctl);
-       I915_WRITE(TV_DAC, tv_dac);
-       POSTING_READ(TV_DAC);
-
-       intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
-
-       type = -1;
-       tv_dac = I915_READ(TV_DAC);
-       DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
-       /*
-        *  A B C
-        *  0 1 1 Composite
-        *  1 0 X svideo
-        *  0 0 0 Component
-        */
-       if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
-               DRM_DEBUG_KMS("Detected Composite TV connection\n");
-               type = DRM_MODE_CONNECTOR_Composite;
-       } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
-               DRM_DEBUG_KMS("Detected S-Video TV connection\n");
-               type = DRM_MODE_CONNECTOR_SVIDEO;
-       } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
-               DRM_DEBUG_KMS("Detected Component TV connection\n");
-               type = DRM_MODE_CONNECTOR_Component;
-       } else {
-               DRM_DEBUG_KMS("Unrecognised TV connection\n");
-               type = -1;
-       }
-
-       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
-       I915_WRITE(TV_CTL, save_tv_ctl);
-       POSTING_READ(TV_CTL);
-
-       /* For unknown reasons the hw barfs if we don't do this vblank wait. */
-       intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
-
-       /* Restore interrupt config */
-       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
-               spin_lock_irq(&dev_priv->irq_lock);
-               i915_enable_pipestat(dev_priv, 0,
-                                    PIPE_HOTPLUG_INTERRUPT_STATUS |
-                                    PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
-               spin_unlock_irq(&dev_priv->irq_lock);
-       }
-
-       return type;
-}
-
-/*
- * Here we set accurate tv format according to connector type
- * i.e Component TV should not be assigned by NTSC or PAL
- */
-static void intel_tv_find_better_format(struct drm_connector *connector)
-{
-       struct intel_tv *intel_tv = intel_attached_tv(connector);
-       const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
-       int i;
-
-       /* Component supports everything so we can keep the current mode */
-       if (intel_tv->type == DRM_MODE_CONNECTOR_Component)
-               return;
-
-       /* If the current mode is fine don't change it */
-       if (!tv_mode->component_only)
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-               tv_mode = &tv_modes[i];
-
-               if (!tv_mode->component_only)
-                       break;
-       }
-
-       connector->state->tv.mode = i;
-}
-
-static int
-intel_tv_detect(struct drm_connector *connector,
-               struct drm_modeset_acquire_ctx *ctx,
-               bool force)
-{
-       struct intel_tv *intel_tv = intel_attached_tv(connector);
-       enum drm_connector_status status;
-       int type;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
-                     connector->base.id, connector->name,
-                     force);
-
-       if (force) {
-               struct intel_load_detect_pipe tmp;
-               int ret;
-
-               ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
-               if (ret < 0)
-                       return ret;
-
-               if (ret > 0) {
-                       type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(connector, &tmp, ctx);
-                       status = type < 0 ?
-                               connector_status_disconnected :
-                               connector_status_connected;
-               } else
-                       status = connector_status_unknown;
-
-               if (status == connector_status_connected) {
-                       intel_tv->type = type;
-                       intel_tv_find_better_format(connector);
-               }
-
-               return status;
-       } else
-               return connector->status;
-}
-
-static const struct input_res {
-       u16 w, h;
-} input_res_table[] = {
-       { 640, 480 },
-       { 800, 600 },
-       { 1024, 768 },
-       { 1280, 1024 },
-       { 848, 480 },
-       { 1280, 720 },
-       { 1920, 1080 },
-};
-
-/* Choose preferred mode according to line number of TV format */
-static bool
-intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
-                          const struct tv_mode *tv_mode)
-{
-       int vdisplay = intel_tv_mode_vdisplay(tv_mode);
-
-       /* prefer 480 line modes for all SD TV modes */
-       if (vdisplay <= 576)
-               vdisplay = 480;
-
-       return vdisplay == mode->vdisplay;
-}
-
-static void
-intel_tv_set_mode_type(struct drm_display_mode *mode,
-                      const struct tv_mode *tv_mode)
-{
-       mode->type = DRM_MODE_TYPE_DRIVER;
-
-       if (intel_tv_is_preferred_mode(mode, tv_mode))
-               mode->type |= DRM_MODE_TYPE_PREFERRED;
-}
-
-static int
-intel_tv_get_modes(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
-       int i, count = 0;
-
-       for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
-               const struct input_res *input = &input_res_table[i];
-               struct drm_display_mode *mode;
-
-               if (input->w > 1024 &&
-                   !tv_mode->progressive &&
-                   !tv_mode->component_only)
-                       continue;
-
-               /* no vertical scaling with wide sources on gen3 */
-               if (IS_GEN(dev_priv, 3) && input->w > 1024 &&
-                   input->h > intel_tv_mode_vdisplay(tv_mode))
-                       continue;
-
-               mode = drm_mode_create(connector->dev);
-               if (!mode)
-                       continue;
-
-               /*
-                * We take the TV mode and scale it to look
-                * like it had the expected h/vdisplay. This
-                * provides the most information to userspace
-                * about the actual timings of the mode. We
-                * do ignore the margins though.
-                */
-               intel_tv_mode_to_mode(mode, tv_mode);
-               if (count == 0) {
-                       DRM_DEBUG_KMS("TV mode:\n");
-                       drm_mode_debug_printmodeline(mode);
-               }
-               intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
-               intel_tv_scale_mode_vert(mode, input->h, 0, 0);
-               intel_tv_set_mode_type(mode, tv_mode);
-
-               drm_mode_set_name(mode);
-
-               drm_mode_probed_add(connector, mode);
-               count++;
-       }
-
-       return count;
-}
-
-static const struct drm_connector_funcs intel_tv_connector_funcs = {
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_tv_connector_duplicate_state,
-};
-
-static int intel_tv_atomic_check(struct drm_connector *connector,
-                                struct drm_connector_state *new_state)
-{
-       struct drm_crtc_state *new_crtc_state;
-       struct drm_connector_state *old_state;
-
-       if (!new_state->crtc)
-               return 0;
-
-       old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
-       new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
-
-       if (old_state->tv.mode != new_state->tv.mode ||
-           old_state->tv.margins.left != new_state->tv.margins.left ||
-           old_state->tv.margins.right != new_state->tv.margins.right ||
-           old_state->tv.margins.top != new_state->tv.margins.top ||
-           old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
-               /* Force a modeset. */
-
-               new_crtc_state->connectors_changed = true;
-       }
-
-       return 0;
-}
-
-static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
-       .detect_ctx = intel_tv_detect,
-       .mode_valid = intel_tv_mode_valid,
-       .get_modes = intel_tv_get_modes,
-       .atomic_check = intel_tv_atomic_check,
-};
-
-static const struct drm_encoder_funcs intel_tv_enc_funcs = {
-       .destroy = intel_encoder_destroy,
-};
-
-void
-intel_tv_init(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = &dev_priv->drm;
-       struct drm_connector *connector;
-       struct intel_tv *intel_tv;
-       struct intel_encoder *intel_encoder;
-       struct intel_connector *intel_connector;
-       u32 tv_dac_on, tv_dac_off, save_tv_dac;
-       const char *tv_format_names[ARRAY_SIZE(tv_modes)];
-       int i, initial_mode = 0;
-       struct drm_connector_state *state;
-
-       if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
-               return;
-
-       if (!intel_bios_is_tv_present(dev_priv)) {
-               DRM_DEBUG_KMS("Integrated TV is not present.\n");
-               return;
-       }
-
-       /*
-        * Sanity check the TV output by checking to see if the
-        * DAC register holds a value
-        */
-       save_tv_dac = I915_READ(TV_DAC);
-
-       I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
-       tv_dac_on = I915_READ(TV_DAC);
-
-       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
-       tv_dac_off = I915_READ(TV_DAC);
-
-       I915_WRITE(TV_DAC, save_tv_dac);
-
-       /*
-        * If the register does not hold the state change enable
-        * bit, (either as a 0 or a 1), assume it doesn't really
-        * exist
-        */
-       if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
-           (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
-               return;
-
-       intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
-       if (!intel_tv) {
-               return;
-       }
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_tv);
-               return;
-       }
-
-       intel_encoder = &intel_tv->base;
-       connector = &intel_connector->base;
-       state = connector->state;
-
-       /*
-        * The documentation, for the older chipsets at least, recommend
-        * using a polling method rather than hotplug detection for TVs.
-        * This is because in order to perform the hotplug detection, the PLLs
-        * for the TV must be kept alive increasing power drain and starving
-        * bandwidth from other encoders. Notably for instance, it causes
-        * pipe underruns on Crestline when this encoder is supposedly idle.
-        *
-        * More recent chipsets favour HDMI rather than integrated S-Video.
-        */
-       intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-
-       drm_connector_init(dev, connector, &intel_tv_connector_funcs,
-                          DRM_MODE_CONNECTOR_SVIDEO);
-
-       drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
-                        DRM_MODE_ENCODER_TVDAC, "TV");
-
-       intel_encoder->compute_config = intel_tv_compute_config;
-       intel_encoder->get_config = intel_tv_get_config;
-       intel_encoder->pre_enable = intel_tv_pre_enable;
-       intel_encoder->enable = intel_enable_tv;
-       intel_encoder->disable = intel_disable_tv;
-       intel_encoder->get_hw_state = intel_tv_get_hw_state;
-       intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
-
-       intel_encoder->type = INTEL_OUTPUT_TVOUT;
-       intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
-       intel_encoder->port = PORT_NONE;
-       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       intel_encoder->cloneable = 0;
-       intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
-       intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
-
-       /* BIOS margin values */
-       state->tv.margins.left = 54;
-       state->tv.margins.top = 36;
-       state->tv.margins.right = 46;
-       state->tv.margins.bottom = 37;
-
-       state->tv.mode = initial_mode;
-
-       drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
-       connector->interlace_allowed = false;
-       connector->doublescan_allowed = false;
-
-       /* Create TV properties then attach current values */
-       for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-               /* 1080p50/1080p60 not supported on gen3 */
-               if (IS_GEN(dev_priv, 3) &&
-                   tv_modes[i].oversample == 1)
-                       break;
-
-               tv_format_names[i] = tv_modes[i].name;
-       }
-       drm_mode_create_tv_properties(dev, i, tv_format_names);
-
-       drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
-                                  state->tv.mode);
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.tv_left_margin_property,
-                                  state->tv.margins.left);
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.tv_top_margin_property,
-                                  state->tv.margins.top);
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.tv_right_margin_property,
-                                  state->tv.margins.right);
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.tv_bottom_margin_property,
-                                  state->tv.margins.bottom);
-}
diff --git a/drivers/gpu/drm/i915/intel_tv.h b/drivers/gpu/drm/i915/intel_tv.h
deleted file mode 100644 (file)
index 4451857..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_TV_H__
-#define __INTEL_TV_H__
-
-struct drm_i915_private;
-
-void intel_tv_init(struct drm_i915_private *dev_priv);
-
-#endif /* __INTEL_TV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_vdsc.c b/drivers/gpu/drm/i915/intel_vdsc.c
deleted file mode 100644 (file)
index ffec807..0000000
+++ /dev/null
@@ -1,966 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2018 Intel Corporation
- *
- * Author: Gaurav K Singh <gaurav.k.singh@intel.com>
- *         Manasi Navare <manasi.d.navare@intel.com>
- */
-
-#include <drm/i915_drm.h>
-
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_vdsc.h"
-
-enum ROW_INDEX_BPP {
-       ROW_INDEX_6BPP = 0,
-       ROW_INDEX_8BPP,
-       ROW_INDEX_10BPP,
-       ROW_INDEX_12BPP,
-       ROW_INDEX_15BPP,
-       MAX_ROW_INDEX
-};
-
-enum COLUMN_INDEX_BPC {
-       COLUMN_INDEX_8BPC = 0,
-       COLUMN_INDEX_10BPC,
-       COLUMN_INDEX_12BPC,
-       COLUMN_INDEX_14BPC,
-       COLUMN_INDEX_16BPC,
-       MAX_COLUMN_INDEX
-};
-
-#define DSC_SUPPORTED_VERSION_MIN              1
-
-/* From DSC_v1.11 spec, rc_parameter_Set syntax element typically constant */
-static u16 rc_buf_thresh[] = {
-       896, 1792, 2688, 3584, 4480, 5376, 6272, 6720, 7168, 7616,
-       7744, 7872, 8000, 8064
-};
-
-struct rc_parameters {
-       u16 initial_xmit_delay;
-       u8 first_line_bpg_offset;
-       u16 initial_offset;
-       u8 flatness_min_qp;
-       u8 flatness_max_qp;
-       u8 rc_quant_incr_limit0;
-       u8 rc_quant_incr_limit1;
-       struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES];
-};
-
-/*
- * Selected Rate Control Related Parameter Recommended Values
- * from DSC_v1.11 spec & C Model release: DSC_model_20161212
- */
-static struct rc_parameters rc_params[][MAX_COLUMN_INDEX] = {
-{
-       /* 6BPP/8BPC */
-       { 768, 15, 6144, 3, 13, 11, 11, {
-               { 0, 4, 0 }, { 1, 6, -2 }, { 3, 8, -2 }, { 4, 8, -4 },
-               { 5, 9, -6 }, { 5, 9, -6 }, { 6, 9, -6 }, { 6, 10, -8 },
-               { 7, 11, -8 }, { 8, 12, -10 }, { 9, 12, -10 }, { 10, 12, -12 },
-               { 10, 12, -12 }, { 11, 12, -12 }, { 13, 14, -12 }
-               }
-       },
-       /* 6BPP/10BPC */
-       { 768, 15, 6144, 7, 17, 15, 15, {
-               { 0, 8, 0 }, { 3, 10, -2 }, { 7, 12, -2 }, { 8, 12, -4 },
-               { 9, 13, -6 }, { 9, 13, -6 }, { 10, 13, -6 }, { 10, 14, -8 },
-               { 11, 15, -8 }, { 12, 16, -10 }, { 13, 16, -10 },
-               { 14, 16, -12 }, { 14, 16, -12 }, { 15, 16, -12 },
-               { 17, 18, -12 }
-               }
-       },
-       /* 6BPP/12BPC */
-       { 768, 15, 6144, 11, 21, 19, 19, {
-               { 0, 12, 0 }, { 5, 14, -2 }, { 11, 16, -2 }, { 12, 16, -4 },
-               { 13, 17, -6 }, { 13, 17, -6 }, { 14, 17, -6 }, { 14, 18, -8 },
-               { 15, 19, -8 }, { 16, 20, -10 }, { 17, 20, -10 },
-               { 18, 20, -12 }, { 18, 20, -12 }, { 19, 20, -12 },
-               { 21, 22, -12 }
-               }
-       },
-       /* 6BPP/14BPC */
-       { 768, 15, 6144, 15, 25, 23, 27, {
-               { 0, 16, 0 }, { 7, 18, -2 }, { 15, 20, -2 }, { 16, 20, -4 },
-               { 17, 21, -6 }, { 17, 21, -6 }, { 18, 21, -6 }, { 18, 22, -8 },
-               { 19, 23, -8 }, { 20, 24, -10 }, { 21, 24, -10 },
-               { 22, 24, -12 }, { 22, 24, -12 }, { 23, 24, -12 },
-               { 25, 26, -12 }
-               }
-       },
-       /* 6BPP/16BPC */
-       { 768, 15, 6144, 19, 29, 27, 27, {
-               { 0, 20, 0 }, { 9, 22, -2 }, { 19, 24, -2 }, { 20, 24, -4 },
-               { 21, 25, -6 }, { 21, 25, -6 }, { 22, 25, -6 }, { 22, 26, -8 },
-               { 23, 27, -8 }, { 24, 28, -10 }, { 25, 28, -10 },
-               { 26, 28, -12 }, { 26, 28, -12 }, { 27, 28, -12 },
-               { 29, 30, -12 }
-               }
-       },
-},
-{
-       /* 8BPP/8BPC */
-       { 512, 12, 6144, 3, 12, 11, 11, {
-               { 0, 4, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
-               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
-               { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 }, { 5, 12, -12 },
-               { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
-               }
-       },
-       /* 8BPP/10BPC */
-       { 512, 12, 6144, 7, 16, 15, 15, {
-               { 0, 4, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 5, 10, -2 },
-               { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
-               { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
-               { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
-               }
-       },
-       /* 8BPP/12BPC */
-       { 512, 12, 6144, 11, 20, 19, 19, {
-               { 0, 12, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 9, 14, -2 },
-               { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
-               { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
-               { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
-               { 21, 23, -12 }
-               }
-       },
-       /* 8BPP/14BPC */
-       { 512, 12, 6144, 15, 24, 23, 23, {
-               { 0, 12, 0 }, { 5, 13, 0 }, { 11, 15, 0 }, { 12, 17, -2 },
-               { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
-               { 15, 21, -8 }, { 15, 22, -10 }, { 17, 22, -10 },
-               { 17, 23, -12 }, { 17, 23, -12 }, { 21, 24, -12 },
-               { 24, 25, -12 }
-               }
-       },
-       /* 8BPP/16BPC */
-       { 512, 12, 6144, 19, 28, 27, 27, {
-               { 0, 12, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 15, 20, -2 },
-               { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
-               { 19, 25, -8 }, { 19, 26, -10 }, { 21, 26, -10 },
-               { 21, 27, -12 }, { 21, 27, -12 }, { 25, 28, -12 },
-               { 28, 29, -12 }
-               }
-       },
-},
-{
-       /* 10BPP/8BPC */
-       { 410, 15, 5632, 3, 12, 11, 11, {
-               { 0, 3, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 2, 6, -2 },
-               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
-               { 3, 9, -8 }, { 3, 9, -10 }, { 5, 10, -10 }, { 5, 10, -10 },
-               { 5, 11, -12 }, { 7, 11, -12 }, { 11, 12, -12 }
-               }
-       },
-       /* 10BPP/10BPC */
-       { 410, 15, 5632, 7, 16, 15, 15, {
-               { 0, 7, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 6, 10, -2 },
-               { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
-               { 7, 13, -8 }, { 7, 13, -10 }, { 9, 14, -10 }, { 9, 14, -10 },
-               { 9, 15, -12 }, { 11, 15, -12 }, { 15, 16, -12 }
-               }
-       },
-       /* 10BPP/12BPC */
-       { 410, 15, 5632, 11, 20, 19, 19, {
-               { 0, 11, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 10, 14, -2 },
-               { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
-               { 11, 17, -8 }, { 11, 17, -10 }, { 13, 18, -10 },
-               { 13, 18, -10 }, { 13, 19, -12 }, { 15, 19, -12 },
-               { 19, 20, -12 }
-               }
-       },
-       /* 10BPP/14BPC */
-       { 410, 15, 5632, 15, 24, 23, 23, {
-               { 0, 11, 2 }, { 5, 13, 0 }, { 11, 15, 0 }, { 13, 18, -2 },
-               { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
-               { 15, 21, -8 }, { 15, 21, -10 }, { 17, 22, -10 },
-               { 17, 22, -10 }, { 17, 23, -12 }, { 19, 23, -12 },
-               { 23, 24, -12 }
-               }
-       },
-       /* 10BPP/16BPC */
-       { 410, 15, 5632, 19, 28, 27, 27, {
-               { 0, 11, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 16, 20, -2 },
-               { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
-               { 19, 25, -8 }, { 19, 25, -10 }, { 21, 26, -10 },
-               { 21, 26, -10 }, { 21, 27, -12 }, { 23, 27, -12 },
-               { 27, 28, -12 }
-               }
-       },
-},
-{
-       /* 12BPP/8BPC */
-       { 341, 15, 2048, 3, 12, 11, 11, {
-               { 0, 2, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
-               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
-               { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 },
-               { 5, 12, -12 }, { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
-               }
-       },
-       /* 12BPP/10BPC */
-       { 341, 15, 2048, 7, 16, 15, 15, {
-               { 0, 2, 2 }, { 2, 5, 0 }, { 3, 7, 0 }, { 4, 8, -2 },
-               { 6, 9, -4 }, { 7, 10, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
-               { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
-               { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
-               }
-       },
-       /* 12BPP/12BPC */
-       { 341, 15, 2048, 11, 20, 19, 19, {
-               { 0, 6, 2 }, { 4, 9, 0 }, { 7, 11, 0 }, { 8, 12, -2 },
-               { 10, 13, -4 }, { 11, 14, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
-               { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
-               { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
-               { 21, 23, -12 }
-               }
-       },
-       /* 12BPP/14BPC */
-       { 341, 15, 2048, 15, 24, 23, 23, {
-               { 0, 6, 2 }, { 7, 10, 0 }, { 9, 13, 0 }, { 11, 16, -2 },
-               { 14, 17, -4 }, { 15, 18, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
-               { 15, 20, -8 }, { 15, 21, -10 }, { 17, 21, -10 },
-               { 17, 21, -12 }, { 17, 21, -12 }, { 19, 22, -12 },
-               { 22, 23, -12 }
-               }
-       },
-       /* 12BPP/16BPC */
-       { 341, 15, 2048, 19, 28, 27, 27, {
-               { 0, 6, 2 }, { 6, 11, 0 }, { 11, 15, 0 }, { 14, 18, -2 },
-               { 18, 21, -4 }, { 19, 22, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
-               { 19, 24, -8 }, { 19, 25, -10 }, { 21, 25, -10 },
-               { 21, 25, -12 }, { 21, 25, -12 }, { 23, 26, -12 },
-               { 26, 27, -12 }
-               }
-       },
-},
-{
-       /* 15BPP/8BPC */
-       { 273, 15, 2048, 3, 12, 11, 11, {
-               { 0, 0, 10 }, { 0, 1, 8 }, { 0, 1, 6 }, { 0, 2, 4 },
-               { 1, 2, 2 }, { 1, 3, 0 }, { 1, 3, -2 }, { 2, 4, -4 },
-               { 2, 5, -6 }, { 3, 5, -8 }, { 4, 6, -10 }, { 4, 7, -10 },
-               { 5, 7, -12 }, { 7, 8, -12 }, { 8, 9, -12 }
-               }
-       },
-       /* 15BPP/10BPC */
-       { 273, 15, 2048, 7, 16, 15, 15, {
-               { 0, 2, 10 }, { 2, 5, 8 }, { 3, 5, 6 }, { 4, 6, 4 },
-               { 5, 6, 2 }, { 5, 7, 0 }, { 5, 7, -2 }, { 6, 8, -4 },
-               { 6, 9, -6 }, { 7, 9, -8 }, { 8, 10, -10 }, { 8, 11, -10 },
-               { 9, 11, -12 }, { 11, 12, -12 }, { 12, 13, -12 }
-               }
-       },
-       /* 15BPP/12BPC */
-       { 273, 15, 2048, 11, 20, 19, 19, {
-               { 0, 4, 10 }, { 2, 7, 8 }, { 4, 9, 6 }, { 6, 11, 4 },
-               { 9, 11, 2 }, { 9, 11, 0 }, { 9, 12, -2 }, { 10, 12, -4 },
-               { 11, 13, -6 }, { 11, 13, -8 }, { 12, 14, -10 },
-               { 13, 15, -10 }, { 13, 15, -12 }, { 15, 16, -12 },
-               { 16, 17, -12 }
-               }
-       },
-       /* 15BPP/14BPC */
-       { 273, 15, 2048, 15, 24, 23, 23, {
-               { 0, 4, 10 }, { 3, 8, 8 }, { 6, 11, 6 }, { 9, 14, 4 },
-               { 13, 15, 2 }, { 13, 15, 0 }, { 13, 16, -2 }, { 14, 16, -4 },
-               { 15, 17, -6 }, { 15, 17, -8 }, { 16, 18, -10 },
-               { 17, 19, -10 }, { 17, 19, -12 }, { 19, 20, -12 },
-               { 20, 21, -12 }
-               }
-       },
-       /* 15BPP/16BPC */
-       { 273, 15, 2048, 19, 28, 27, 27, {
-               { 0, 4, 10 }, { 4, 9, 8 }, { 8, 13, 6 }, { 12, 17, 4 },
-               { 17, 19, 2 }, { 17, 20, 0 }, { 17, 20, -2 }, { 18, 20, -4 },
-               { 19, 21, -6 }, { 19, 21, -8 }, { 20, 22, -10 },
-               { 21, 23, -10 }, { 21, 23, -12 }, { 23, 24, -12 },
-               { 24, 25, -12 }
-               }
-       }
-}
-
-};
-
-static int get_row_index_for_rc_params(u16 compressed_bpp)
-{
-       switch (compressed_bpp) {
-       case 6:
-               return ROW_INDEX_6BPP;
-       case 8:
-               return ROW_INDEX_8BPP;
-       case 10:
-               return ROW_INDEX_10BPP;
-       case 12:
-               return ROW_INDEX_12BPP;
-       case 15:
-               return ROW_INDEX_15BPP;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int get_column_index_for_rc_params(u8 bits_per_component)
-{
-       switch (bits_per_component) {
-       case 8:
-               return COLUMN_INDEX_8BPC;
-       case 10:
-               return COLUMN_INDEX_10BPC;
-       case 12:
-               return COLUMN_INDEX_12BPC;
-       case 14:
-               return COLUMN_INDEX_14BPC;
-       case 16:
-               return COLUMN_INDEX_16BPC;
-       default:
-               return -EINVAL;
-       }
-}
-
-int intel_dp_compute_dsc_params(struct intel_dp *intel_dp,
-                               struct intel_crtc_state *pipe_config)
-{
-       struct drm_dsc_config *vdsc_cfg = &pipe_config->dp_dsc_cfg;
-       u16 compressed_bpp = pipe_config->dsc_params.compressed_bpp;
-       u8 i = 0;
-       int row_index = 0;
-       int column_index = 0;
-       u8 line_buf_depth = 0;
-
-       vdsc_cfg->pic_width = pipe_config->base.adjusted_mode.crtc_hdisplay;
-       vdsc_cfg->pic_height = pipe_config->base.adjusted_mode.crtc_vdisplay;
-       vdsc_cfg->slice_width = DIV_ROUND_UP(vdsc_cfg->pic_width,
-                                            pipe_config->dsc_params.slice_count);
-       /*
-        * Slice Height of 8 works for all currently available panels. So start
-        * with that if pic_height is an integral multiple of 8.
-        * Eventually add logic to try multiple slice heights.
-        */
-       if (vdsc_cfg->pic_height % 8 == 0)
-               vdsc_cfg->slice_height = 8;
-       else if (vdsc_cfg->pic_height % 4 == 0)
-               vdsc_cfg->slice_height = 4;
-       else
-               vdsc_cfg->slice_height = 2;
-
-       /* Values filled from DSC Sink DPCD */
-       vdsc_cfg->dsc_version_major =
-               (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
-                DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT;
-       vdsc_cfg->dsc_version_minor =
-               min(DSC_SUPPORTED_VERSION_MIN,
-                   (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
-                    DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT);
-
-       vdsc_cfg->convert_rgb = intel_dp->dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] &
-               DP_DSC_RGB;
-
-       line_buf_depth = drm_dp_dsc_sink_line_buf_depth(intel_dp->dsc_dpcd);
-       if (!line_buf_depth) {
-               DRM_DEBUG_KMS("DSC Sink Line Buffer Depth invalid\n");
-               return -EINVAL;
-       }
-       if (vdsc_cfg->dsc_version_minor == 2)
-               vdsc_cfg->line_buf_depth = (line_buf_depth == DSC_1_2_MAX_LINEBUF_DEPTH_BITS) ?
-                       DSC_1_2_MAX_LINEBUF_DEPTH_VAL : line_buf_depth;
-       else
-               vdsc_cfg->line_buf_depth = (line_buf_depth > DSC_1_1_MAX_LINEBUF_DEPTH_BITS) ?
-                       DSC_1_1_MAX_LINEBUF_DEPTH_BITS : line_buf_depth;
-
-       /* Gen 11 does not support YCbCr */
-       vdsc_cfg->simple_422 = false;
-       /* Gen 11 does not support VBR */
-       vdsc_cfg->vbr_enable = false;
-       vdsc_cfg->block_pred_enable =
-                       intel_dp->dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] &
-               DP_DSC_BLK_PREDICTION_IS_SUPPORTED;
-
-       /* Gen 11 only supports integral values of bpp */
-       vdsc_cfg->bits_per_pixel = compressed_bpp << 4;
-       vdsc_cfg->bits_per_component = pipe_config->pipe_bpp / 3;
-
-       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
-               /*
-                * six 0s are appended to the lsb of each threshold value
-                * internally in h/w.
-                * Only 8 bits are allowed for programming RcBufThreshold
-                */
-               vdsc_cfg->rc_buf_thresh[i] = rc_buf_thresh[i] >> 6;
-       }
-
-       /*
-        * For 6bpp, RC Buffer threshold 12 and 13 need a different value
-        * as per C Model
-        */
-       if (compressed_bpp == 6) {
-               vdsc_cfg->rc_buf_thresh[12] = 0x7C;
-               vdsc_cfg->rc_buf_thresh[13] = 0x7D;
-       }
-
-       row_index = get_row_index_for_rc_params(compressed_bpp);
-       column_index =
-               get_column_index_for_rc_params(vdsc_cfg->bits_per_component);
-
-       if (row_index < 0 || column_index < 0)
-               return -EINVAL;
-
-       vdsc_cfg->first_line_bpg_offset =
-               rc_params[row_index][column_index].first_line_bpg_offset;
-       vdsc_cfg->initial_xmit_delay =
-               rc_params[row_index][column_index].initial_xmit_delay;
-       vdsc_cfg->initial_offset =
-               rc_params[row_index][column_index].initial_offset;
-       vdsc_cfg->flatness_min_qp =
-               rc_params[row_index][column_index].flatness_min_qp;
-       vdsc_cfg->flatness_max_qp =
-               rc_params[row_index][column_index].flatness_max_qp;
-       vdsc_cfg->rc_quant_incr_limit0 =
-               rc_params[row_index][column_index].rc_quant_incr_limit0;
-       vdsc_cfg->rc_quant_incr_limit1 =
-               rc_params[row_index][column_index].rc_quant_incr_limit1;
-
-       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
-               vdsc_cfg->rc_range_params[i].range_min_qp =
-                       rc_params[row_index][column_index].rc_range_params[i].range_min_qp;
-               vdsc_cfg->rc_range_params[i].range_max_qp =
-                       rc_params[row_index][column_index].rc_range_params[i].range_max_qp;
-               /*
-                * Range BPG Offset uses 2's complement and is only a 6 bits. So
-                * mask it to get only 6 bits.
-                */
-               vdsc_cfg->rc_range_params[i].range_bpg_offset =
-                       rc_params[row_index][column_index].rc_range_params[i].range_bpg_offset &
-                       DSC_RANGE_BPG_OFFSET_MASK;
-       }
-
-       /*
-        * BitsPerComponent value determines mux_word_size:
-        * When BitsPerComponent is 12bpc, muxWordSize will be equal to 64 bits
-        * When BitsPerComponent is 8 or 10bpc, muxWordSize will be equal to
-        * 48 bits
-        */
-       if (vdsc_cfg->bits_per_component == 8 ||
-           vdsc_cfg->bits_per_component == 10)
-               vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
-       else if (vdsc_cfg->bits_per_component == 12)
-               vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
-
-       /* RC_MODEL_SIZE is a constant across all configurations */
-       vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
-       /* InitialScaleValue is a 6 bit value with 3 fractional bits (U3.3) */
-       vdsc_cfg->initial_scale_value = (vdsc_cfg->rc_model_size << 3) /
-               (vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset);
-
-       return drm_dsc_compute_rc_parameters(vdsc_cfg);
-}
-
-enum intel_display_power_domain
-intel_dsc_power_domain(const struct intel_crtc_state *crtc_state)
-{
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-
-       /*
-        * On ICL VDSC/joining for eDP transcoder uses a separate power well PW2
-        * This requires POWER_DOMAIN_TRANSCODER_EDP_VDSC power domain.
-        * For any other transcoder, VDSC/joining uses the power well associated
-        * with the pipe/transcoder in use. Hence another reference on the
-        * transcoder power domain will suffice.
-        */
-       if (cpu_transcoder == TRANSCODER_EDP)
-               return POWER_DOMAIN_TRANSCODER_EDP_VDSC;
-       else
-               return POWER_DOMAIN_TRANSCODER(cpu_transcoder);
-}
-
-static void intel_configure_pps_for_dsc_encoder(struct intel_encoder *encoder,
-                                               const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       const struct drm_dsc_config *vdsc_cfg = &crtc_state->dp_dsc_cfg;
-       enum pipe pipe = crtc->pipe;
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       u32 pps_val = 0;
-       u32 rc_buf_thresh_dword[4];
-       u32 rc_range_params_dword[8];
-       u8 num_vdsc_instances = (crtc_state->dsc_params.dsc_split) ? 2 : 1;
-       int i = 0;
-
-       /* Populate PICTURE_PARAMETER_SET_0 registers */
-       pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor <<
-               DSC_VER_MIN_SHIFT |
-               vdsc_cfg->bits_per_component << DSC_BPC_SHIFT |
-               vdsc_cfg->line_buf_depth << DSC_LINE_BUF_DEPTH_SHIFT;
-       if (vdsc_cfg->block_pred_enable)
-               pps_val |= DSC_BLOCK_PREDICTION;
-       if (vdsc_cfg->convert_rgb)
-               pps_val |= DSC_COLOR_SPACE_CONVERSION;
-       if (vdsc_cfg->simple_422)
-               pps_val |= DSC_422_ENABLE;
-       if (vdsc_cfg->vbr_enable)
-               pps_val |= DSC_VBR_ENABLE;
-       DRM_INFO("PPS0 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_0, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_0, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_1 registers */
-       pps_val = 0;
-       pps_val |= DSC_BPP(vdsc_cfg->bits_per_pixel);
-       DRM_INFO("PPS1 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_1, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_1, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_2 registers */
-       pps_val = 0;
-       pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) |
-               DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances);
-       DRM_INFO("PPS2 = 0x%08x\n", pps_val);
-       if (encoder->type == INTEL_OUTPUT_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_2, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_2, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_3 registers */
-       pps_val = 0;
-       pps_val |= DSC_SLICE_HEIGHT(vdsc_cfg->slice_height) |
-               DSC_SLICE_WIDTH(vdsc_cfg->slice_width);
-       DRM_INFO("PPS3 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_3, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_3, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_4 registers */
-       pps_val = 0;
-       pps_val |= DSC_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) |
-               DSC_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay);
-       DRM_INFO("PPS4 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_4, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_4, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_5 registers */
-       pps_val = 0;
-       pps_val |= DSC_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) |
-               DSC_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval);
-       DRM_INFO("PPS5 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_5, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_5, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_6 registers */
-       pps_val = 0;
-       pps_val |= DSC_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) |
-               DSC_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) |
-               DSC_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) |
-               DSC_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp);
-       DRM_INFO("PPS6 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_6, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_6, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_7 registers */
-       pps_val = 0;
-       pps_val |= DSC_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) |
-               DSC_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset);
-       DRM_INFO("PPS7 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_7, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_7, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_8 registers */
-       pps_val = 0;
-       pps_val |= DSC_FINAL_OFFSET(vdsc_cfg->final_offset) |
-               DSC_INITIAL_OFFSET(vdsc_cfg->initial_offset);
-       DRM_INFO("PPS8 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_8, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_8, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_9 registers */
-       pps_val = 0;
-       pps_val |= DSC_RC_MODEL_SIZE(DSC_RC_MODEL_SIZE_CONST) |
-               DSC_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST);
-       DRM_INFO("PPS9 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_9, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_9, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe),
-                                  pps_val);
-       }
-
-       /* Populate PICTURE_PARAMETER_SET_10 registers */
-       pps_val = 0;
-       pps_val |= DSC_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) |
-               DSC_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) |
-               DSC_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) |
-               DSC_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST);
-       DRM_INFO("PPS10 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_10, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_10, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe),
-                                  pps_val);
-       }
-
-       /* Populate Picture parameter set 16 */
-       pps_val = 0;
-       pps_val |= DSC_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) |
-               DSC_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) /
-                                  vdsc_cfg->slice_width) |
-               DSC_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height /
-                                       vdsc_cfg->slice_height);
-       DRM_INFO("PPS16 = 0x%08x\n", pps_val);
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_16, pps_val);
-               /*
-                * If 2 VDSC instances are needed, configure PPS for second
-                * VDSC
-                */
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_16, pps_val);
-       } else {
-               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe), pps_val);
-               if (crtc_state->dsc_params.dsc_split)
-                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe),
-                                  pps_val);
-       }
-
-       /* Populate the RC_BUF_THRESH registers */
-       memset(rc_buf_thresh_dword, 0, sizeof(rc_buf_thresh_dword));
-       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
-               rc_buf_thresh_dword[i / 4] |=
-                       (u32)(vdsc_cfg->rc_buf_thresh[i] <<
-                             BITS_PER_BYTE * (i % 4));
-               DRM_INFO(" RC_BUF_THRESH%d = 0x%08x\n", i,
-                        rc_buf_thresh_dword[i / 4]);
-       }
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_RC_BUF_THRESH_0, rc_buf_thresh_dword[0]);
-               I915_WRITE(DSCA_RC_BUF_THRESH_0_UDW, rc_buf_thresh_dword[1]);
-               I915_WRITE(DSCA_RC_BUF_THRESH_1, rc_buf_thresh_dword[2]);
-               I915_WRITE(DSCA_RC_BUF_THRESH_1_UDW, rc_buf_thresh_dword[3]);
-               if (crtc_state->dsc_params.dsc_split) {
-                       I915_WRITE(DSCC_RC_BUF_THRESH_0,
-                                  rc_buf_thresh_dword[0]);
-                       I915_WRITE(DSCC_RC_BUF_THRESH_0_UDW,
-                                  rc_buf_thresh_dword[1]);
-                       I915_WRITE(DSCC_RC_BUF_THRESH_1,
-                                  rc_buf_thresh_dword[2]);
-                       I915_WRITE(DSCC_RC_BUF_THRESH_1_UDW,
-                                  rc_buf_thresh_dword[3]);
-               }
-       } else {
-               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_0(pipe),
-                          rc_buf_thresh_dword[0]);
-               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_0_UDW(pipe),
-                          rc_buf_thresh_dword[1]);
-               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_1(pipe),
-                          rc_buf_thresh_dword[2]);
-               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_1_UDW(pipe),
-                          rc_buf_thresh_dword[3]);
-               if (crtc_state->dsc_params.dsc_split) {
-                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_0(pipe),
-                                  rc_buf_thresh_dword[0]);
-                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_0_UDW(pipe),
-                                  rc_buf_thresh_dword[1]);
-                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_1(pipe),
-                                  rc_buf_thresh_dword[2]);
-                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_1_UDW(pipe),
-                                  rc_buf_thresh_dword[3]);
-               }
-       }
-
-       /* Populate the RC_RANGE_PARAMETERS registers */
-       memset(rc_range_params_dword, 0, sizeof(rc_range_params_dword));
-       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
-               rc_range_params_dword[i / 2] |=
-                       (u32)(((vdsc_cfg->rc_range_params[i].range_bpg_offset <<
-                               RC_BPG_OFFSET_SHIFT) |
-                              (vdsc_cfg->rc_range_params[i].range_max_qp <<
-                               RC_MAX_QP_SHIFT) |
-                              (vdsc_cfg->rc_range_params[i].range_min_qp <<
-                               RC_MIN_QP_SHIFT)) << 16 * (i % 2));
-               DRM_INFO(" RC_RANGE_PARAM_%d = 0x%08x\n", i,
-                        rc_range_params_dword[i / 2]);
-       }
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_0,
-                          rc_range_params_dword[0]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_0_UDW,
-                          rc_range_params_dword[1]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_1,
-                          rc_range_params_dword[2]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_1_UDW,
-                          rc_range_params_dword[3]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_2,
-                          rc_range_params_dword[4]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_2_UDW,
-                          rc_range_params_dword[5]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_3,
-                          rc_range_params_dword[6]);
-               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_3_UDW,
-                          rc_range_params_dword[7]);
-               if (crtc_state->dsc_params.dsc_split) {
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_0,
-                                  rc_range_params_dword[0]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_0_UDW,
-                                  rc_range_params_dword[1]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_1,
-                                  rc_range_params_dword[2]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_1_UDW,
-                                  rc_range_params_dword[3]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_2,
-                                  rc_range_params_dword[4]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_2_UDW,
-                                  rc_range_params_dword[5]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_3,
-                                  rc_range_params_dword[6]);
-                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_3_UDW,
-                                  rc_range_params_dword[7]);
-               }
-       } else {
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe),
-                          rc_range_params_dword[0]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe),
-                          rc_range_params_dword[1]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe),
-                          rc_range_params_dword[2]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe),
-                          rc_range_params_dword[3]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe),
-                          rc_range_params_dword[4]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe),
-                          rc_range_params_dword[5]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe),
-                          rc_range_params_dword[6]);
-               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe),
-                          rc_range_params_dword[7]);
-               if (crtc_state->dsc_params.dsc_split) {
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe),
-                                  rc_range_params_dword[0]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe),
-                                  rc_range_params_dword[1]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe),
-                                  rc_range_params_dword[2]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe),
-                                  rc_range_params_dword[3]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe),
-                                  rc_range_params_dword[4]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe),
-                                  rc_range_params_dword[5]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe),
-                                  rc_range_params_dword[6]);
-                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe),
-                                  rc_range_params_dword[7]);
-               }
-       }
-}
-
-static void intel_dp_write_dsc_pps_sdp(struct intel_encoder *encoder,
-                                      const struct intel_crtc_state *crtc_state)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       const struct drm_dsc_config *vdsc_cfg = &crtc_state->dp_dsc_cfg;
-       struct drm_dsc_pps_infoframe dp_dsc_pps_sdp;
-
-       /* Prepare DP SDP PPS header as per DP 1.4 spec, Table 2-123 */
-       drm_dsc_dp_pps_header_init(&dp_dsc_pps_sdp.pps_header);
-
-       /* Fill the PPS payload bytes as per DSC spec 1.2 Table 4-1 */
-       drm_dsc_pps_payload_pack(&dp_dsc_pps_sdp.pps_payload, vdsc_cfg);
-
-       intel_dig_port->write_infoframe(encoder, crtc_state,
-                                       DP_SDP_PPS, &dp_dsc_pps_sdp,
-                                       sizeof(dp_dsc_pps_sdp));
-}
-
-void intel_dsc_enable(struct intel_encoder *encoder,
-                     const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum pipe pipe = crtc->pipe;
-       i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
-       u32 dss_ctl1_val = 0;
-       u32 dss_ctl2_val = 0;
-
-       if (!crtc_state->dsc_params.compression_enable)
-               return;
-
-       /* Enable Power wells for VDSC/joining */
-       intel_display_power_get(dev_priv,
-                               intel_dsc_power_domain(crtc_state));
-
-       intel_configure_pps_for_dsc_encoder(encoder, crtc_state);
-
-       intel_dp_write_dsc_pps_sdp(encoder, crtc_state);
-
-       if (crtc_state->cpu_transcoder == TRANSCODER_EDP) {
-               dss_ctl1_reg = DSS_CTL1;
-               dss_ctl2_reg = DSS_CTL2;
-       } else {
-               dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
-               dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
-       }
-       dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE;
-       if (crtc_state->dsc_params.dsc_split) {
-               dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
-               dss_ctl1_val |= JOINER_ENABLE;
-       }
-       I915_WRITE(dss_ctl1_reg, dss_ctl1_val);
-       I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
-}
-
-void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum pipe pipe = crtc->pipe;
-       i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
-       u32 dss_ctl1_val = 0, dss_ctl2_val = 0;
-
-       if (!old_crtc_state->dsc_params.compression_enable)
-               return;
-
-       if (old_crtc_state->cpu_transcoder == TRANSCODER_EDP) {
-               dss_ctl1_reg = DSS_CTL1;
-               dss_ctl2_reg = DSS_CTL2;
-       } else {
-               dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
-               dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
-       }
-       dss_ctl1_val = I915_READ(dss_ctl1_reg);
-       if (dss_ctl1_val & JOINER_ENABLE)
-               dss_ctl1_val &= ~JOINER_ENABLE;
-       I915_WRITE(dss_ctl1_reg, dss_ctl1_val);
-
-       dss_ctl2_val = I915_READ(dss_ctl2_reg);
-       if (dss_ctl2_val & LEFT_BRANCH_VDSC_ENABLE ||
-           dss_ctl2_val & RIGHT_BRANCH_VDSC_ENABLE)
-               dss_ctl2_val &= ~(LEFT_BRANCH_VDSC_ENABLE |
-                                 RIGHT_BRANCH_VDSC_ENABLE);
-       I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
-
-       /* Disable Power wells for VDSC/joining */
-       intel_display_power_put_unchecked(dev_priv,
-                                         intel_dsc_power_domain(old_crtc_state));
-}
diff --git a/drivers/gpu/drm/i915/intel_vdsc.h b/drivers/gpu/drm/i915/intel_vdsc.h
deleted file mode 100644 (file)
index 90d3f60..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __INTEL_VDSC_H__
-#define __INTEL_VDSC_H__
-
-struct intel_encoder;
-struct intel_crtc_state;
-struct intel_dp;
-
-void intel_dsc_enable(struct intel_encoder *encoder,
-                     const struct intel_crtc_state *crtc_state);
-void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
-int intel_dp_compute_dsc_params(struct intel_dp *intel_dp,
-                               struct intel_crtc_state *pipe_config);
-enum intel_display_power_domain
-intel_dsc_power_domain(const struct intel_crtc_state *crtc_state);
-
-#endif /* __INTEL_VDSC_H__ */
diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c
deleted file mode 100644 (file)
index e272d82..0000000
+++ /dev/null
@@ -1,1996 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Jani Nikula <jani.nikula@intel.com>
- */
-
-#include <linux/gpio/consumer.h>
-#include <linux/slab.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_mipi_dsi.h>
-
-#include "i915_drv.h"
-#include "intel_atomic.h"
-#include "intel_connector.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_fifo_underrun.h"
-#include "intel_panel.h"
-#include "intel_sideband.h"
-
-/* return pixels in terms of txbyteclkhs */
-static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
-                      u16 burst_mode_ratio)
-{
-       return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp * burst_mode_ratio,
-                                        8 * 100), lane_count);
-}
-
-/* return pixels equvalent to txbyteclkhs */
-static u16 pixels_from_txbyteclkhs(u16 clk_hs, int bpp, int lane_count,
-                       u16 burst_mode_ratio)
-{
-       return DIV_ROUND_UP((clk_hs * lane_count * 8 * 100),
-                                               (bpp * burst_mode_ratio));
-}
-
-enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt)
-{
-       /* It just so happens the VBT matches register contents. */
-       switch (fmt) {
-       case VID_MODE_FORMAT_RGB888:
-               return MIPI_DSI_FMT_RGB888;
-       case VID_MODE_FORMAT_RGB666:
-               return MIPI_DSI_FMT_RGB666;
-       case VID_MODE_FORMAT_RGB666_PACKED:
-               return MIPI_DSI_FMT_RGB666_PACKED;
-       case VID_MODE_FORMAT_RGB565:
-               return MIPI_DSI_FMT_RGB565;
-       default:
-               MISSING_CASE(fmt);
-               return MIPI_DSI_FMT_RGB666;
-       }
-}
-
-void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
-{
-       struct drm_encoder *encoder = &intel_dsi->base.base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 mask;
-
-       mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
-               LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   MIPI_GEN_FIFO_STAT(port), mask, mask,
-                                   100))
-               DRM_ERROR("DPI FIFOs are not empty\n");
-}
-
-static void write_data(struct drm_i915_private *dev_priv,
-                      i915_reg_t reg,
-                      const u8 *data, u32 len)
-{
-       u32 i, j;
-
-       for (i = 0; i < len; i += 4) {
-               u32 val = 0;
-
-               for (j = 0; j < min_t(u32, len - i, 4); j++)
-                       val |= *data++ << 8 * j;
-
-               I915_WRITE(reg, val);
-       }
-}
-
-static void read_data(struct drm_i915_private *dev_priv,
-                     i915_reg_t reg,
-                     u8 *data, u32 len)
-{
-       u32 i, j;
-
-       for (i = 0; i < len; i += 4) {
-               u32 val = I915_READ(reg);
-
-               for (j = 0; j < min_t(u32, len - i, 4); j++)
-                       *data++ = val >> 8 * j;
-       }
-}
-
-static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host,
-                                      const struct mipi_dsi_msg *msg)
-{
-       struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
-       struct drm_device *dev = intel_dsi_host->intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum port port = intel_dsi_host->port;
-       struct mipi_dsi_packet packet;
-       ssize_t ret;
-       const u8 *header, *data;
-       i915_reg_t data_reg, ctrl_reg;
-       u32 data_mask, ctrl_mask;
-
-       ret = mipi_dsi_create_packet(&packet, msg);
-       if (ret < 0)
-               return ret;
-
-       header = packet.header;
-       data = packet.payload;
-
-       if (msg->flags & MIPI_DSI_MSG_USE_LPM) {
-               data_reg = MIPI_LP_GEN_DATA(port);
-               data_mask = LP_DATA_FIFO_FULL;
-               ctrl_reg = MIPI_LP_GEN_CTRL(port);
-               ctrl_mask = LP_CTRL_FIFO_FULL;
-       } else {
-               data_reg = MIPI_HS_GEN_DATA(port);
-               data_mask = HS_DATA_FIFO_FULL;
-               ctrl_reg = MIPI_HS_GEN_CTRL(port);
-               ctrl_mask = HS_CTRL_FIFO_FULL;
-       }
-
-       /* note: this is never true for reads */
-       if (packet.payload_length) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_GEN_FIFO_STAT(port),
-                                           data_mask, 0,
-                                           50))
-                       DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
-
-               write_data(dev_priv, data_reg, packet.payload,
-                          packet.payload_length);
-       }
-
-       if (msg->rx_len) {
-               I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
-       }
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   MIPI_GEN_FIFO_STAT(port),
-                                   ctrl_mask, 0,
-                                   50)) {
-               DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
-       }
-
-       I915_WRITE(ctrl_reg, header[2] << 16 | header[1] << 8 | header[0]);
-
-       /* ->rx_len is set only for reads */
-       if (msg->rx_len) {
-               data_mask = GEN_READ_DATA_AVAIL;
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_INTR_STAT(port),
-                                           data_mask, data_mask,
-                                           50))
-                       DRM_ERROR("Timeout waiting for read data.\n");
-
-               read_data(dev_priv, data_reg, msg->rx_buf, msg->rx_len);
-       }
-
-       /* XXX: fix for reads and writes */
-       return 4 + packet.payload_length;
-}
-
-static int intel_dsi_host_attach(struct mipi_dsi_host *host,
-                                struct mipi_dsi_device *dsi)
-{
-       return 0;
-}
-
-static int intel_dsi_host_detach(struct mipi_dsi_host *host,
-                                struct mipi_dsi_device *dsi)
-{
-       return 0;
-}
-
-static const struct mipi_dsi_host_ops intel_dsi_host_ops = {
-       .attach = intel_dsi_host_attach,
-       .detach = intel_dsi_host_detach,
-       .transfer = intel_dsi_host_transfer,
-};
-
-/*
- * send a video mode command
- *
- * XXX: commands with data in MIPI_DPI_DATA?
- */
-static int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs,
-                       enum port port)
-{
-       struct drm_encoder *encoder = &intel_dsi->base.base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 mask;
-
-       /* XXX: pipe, hs */
-       if (hs)
-               cmd &= ~DPI_LP_MODE;
-       else
-               cmd |= DPI_LP_MODE;
-
-       /* clear bit */
-       I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT);
-
-       /* XXX: old code skips write if control unchanged */
-       if (cmd == I915_READ(MIPI_DPI_CONTROL(port)))
-               DRM_DEBUG_KMS("Same special packet %02x twice in a row.\n", cmd);
-
-       I915_WRITE(MIPI_DPI_CONTROL(port), cmd);
-
-       mask = SPL_PKT_SENT_INTERRUPT;
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   MIPI_INTR_STAT(port), mask, mask,
-                                   100))
-               DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
-
-       return 0;
-}
-
-static void band_gap_reset(struct drm_i915_private *dev_priv)
-{
-       vlv_flisdsi_get(dev_priv);
-
-       vlv_flisdsi_write(dev_priv, 0x08, 0x0001);
-       vlv_flisdsi_write(dev_priv, 0x0F, 0x0005);
-       vlv_flisdsi_write(dev_priv, 0x0F, 0x0025);
-       udelay(150);
-       vlv_flisdsi_write(dev_priv, 0x0F, 0x0000);
-       vlv_flisdsi_write(dev_priv, 0x08, 0x0000);
-
-       vlv_flisdsi_put(dev_priv);
-}
-
-static int intel_dsi_compute_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config,
-                                   struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
-                                                  base);
-       struct intel_connector *intel_connector = intel_dsi->attached_connector;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       int ret;
-
-       DRM_DEBUG_KMS("\n");
-       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-
-       if (fixed_mode) {
-               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
-
-               if (HAS_GMCH(dev_priv))
-                       intel_gmch_panel_fitting(crtc, pipe_config,
-                                                conn_state->scaling_mode);
-               else
-                       intel_pch_panel_fitting(crtc, pipe_config,
-                                               conn_state->scaling_mode);
-       }
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return -EINVAL;
-
-       /* DSI uses short packets for sync events, so clear mode flags for DSI */
-       adjusted_mode->flags = 0;
-
-       if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB888)
-               pipe_config->pipe_bpp = 24;
-       else
-               pipe_config->pipe_bpp = 18;
-
-       if (IS_GEN9_LP(dev_priv)) {
-               /* Enable Frame time stamp based scanline reporting */
-               adjusted_mode->private_flags |=
-                       I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP;
-
-               /* Dual link goes to DSI transcoder A. */
-               if (intel_dsi->ports == BIT(PORT_C))
-                       pipe_config->cpu_transcoder = TRANSCODER_DSI_C;
-               else
-                       pipe_config->cpu_transcoder = TRANSCODER_DSI_A;
-
-               ret = bxt_dsi_pll_compute(encoder, pipe_config);
-               if (ret)
-                       return -EINVAL;
-       } else {
-               ret = vlv_dsi_pll_compute(encoder, pipe_config);
-               if (ret)
-                       return -EINVAL;
-       }
-
-       pipe_config->clock_set = true;
-
-       return 0;
-}
-
-static bool glk_dsi_enable_io(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-       bool cold_boot = false;
-
-       /* Set the MIPI mode
-        * If MIPI_Mode is off, then writing to LP_Wake bit is not reflecting.
-        * Power ON MIPI IO first and then write into IO reset and LP wake bits
-        */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(MIPI_CTRL(port));
-               I915_WRITE(MIPI_CTRL(port), tmp | GLK_MIPIIO_ENABLE);
-       }
-
-       /* Put the IO into reset */
-       tmp = I915_READ(MIPI_CTRL(PORT_A));
-       tmp &= ~GLK_MIPIIO_RESET_RELEASED;
-       I915_WRITE(MIPI_CTRL(PORT_A), tmp);
-
-       /* Program LP Wake */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(MIPI_CTRL(port));
-               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY))
-                       tmp &= ~GLK_LP_WAKE;
-               else
-                       tmp |= GLK_LP_WAKE;
-               I915_WRITE(MIPI_CTRL(port), tmp);
-       }
-
-       /* Wait for Pwr ACK */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_CTRL(port),
-                                           GLK_MIPIIO_PORT_POWERED,
-                                           GLK_MIPIIO_PORT_POWERED,
-                                           20))
-                       DRM_ERROR("MIPIO port is powergated\n");
-       }
-
-       /* Check for cold boot scenario */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               cold_boot |=
-                       !(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY);
-       }
-
-       return cold_boot;
-}
-
-static void glk_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       /* Wait for MIPI PHY status bit to set */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_CTRL(port),
-                                           GLK_PHY_STATUS_PORT_READY,
-                                           GLK_PHY_STATUS_PORT_READY,
-                                           20))
-                       DRM_ERROR("PHY is not ON\n");
-       }
-
-       /* Get IO out of reset */
-       val = I915_READ(MIPI_CTRL(PORT_A));
-       I915_WRITE(MIPI_CTRL(PORT_A), val | GLK_MIPIIO_RESET_RELEASED);
-
-       /* Get IO out of Low power state*/
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY)) {
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= DEVICE_READY;
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-                       usleep_range(10, 15);
-               } else {
-                       /* Enter ULPS */
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= (ULPS_STATE_ENTER | DEVICE_READY);
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-
-                       /* Wait for ULPS active */
-                       if (intel_wait_for_register(&dev_priv->uncore,
-                                                   MIPI_CTRL(port),
-                                                   GLK_ULPS_NOT_ACTIVE,
-                                                   0,
-                                                   20))
-                               DRM_ERROR("ULPS not active\n");
-
-                       /* Exit ULPS */
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= (ULPS_STATE_EXIT | DEVICE_READY);
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-
-                       /* Enter Normal Mode */
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= (ULPS_STATE_NORMAL_OPERATION | DEVICE_READY);
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-
-                       val = I915_READ(MIPI_CTRL(port));
-                       val &= ~GLK_LP_WAKE;
-                       I915_WRITE(MIPI_CTRL(port), val);
-               }
-       }
-
-       /* Wait for Stop state */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_CTRL(port),
-                                           GLK_DATA_LANE_STOP_STATE,
-                                           GLK_DATA_LANE_STOP_STATE,
-                                           20))
-                       DRM_ERROR("Date lane not in STOP state\n");
-       }
-
-       /* Wait for AFE LATCH */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           BXT_MIPI_PORT_CTRL(port),
-                                           AFE_LATCHOUT,
-                                           AFE_LATCHOUT,
-                                           20))
-                       DRM_ERROR("D-PHY not entering LP-11 state\n");
-       }
-}
-
-static void bxt_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* Enable MIPI PHY transparent latch */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val = I915_READ(BXT_MIPI_PORT_CTRL(port));
-               I915_WRITE(BXT_MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD);
-               usleep_range(2000, 2500);
-       }
-
-       /* Clear ULPS and set device ready */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val = I915_READ(MIPI_DEVICE_READY(port));
-               val &= ~ULPS_STATE_MASK;
-               I915_WRITE(MIPI_DEVICE_READY(port), val);
-               usleep_range(2000, 2500);
-               val |= DEVICE_READY;
-               I915_WRITE(MIPI_DEVICE_READY(port), val);
-       }
-}
-
-static void vlv_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       vlv_flisdsi_get(dev_priv);
-       /* program rcomp for compliance, reduce from 50 ohms to 45 ohms
-        * needed everytime after power gate */
-       vlv_flisdsi_write(dev_priv, 0x04, 0x0004);
-       vlv_flisdsi_put(dev_priv);
-
-       /* bandgap reset is needed after everytime we do power gate */
-       band_gap_reset(dev_priv);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-
-               I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER);
-               usleep_range(2500, 3000);
-
-               /* Enable MIPI PHY transparent latch
-                * Common bit for both MIPI Port A & MIPI Port C
-                * No similar bit in MIPI Port C reg
-                */
-               val = I915_READ(MIPI_PORT_CTRL(PORT_A));
-               I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD);
-               usleep_range(1000, 1500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT);
-               usleep_range(2500, 3000);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY);
-               usleep_range(2500, 3000);
-       }
-}
-
-static void intel_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (IS_GEMINILAKE(dev_priv))
-               glk_dsi_device_ready(encoder);
-       else if (IS_GEN9_LP(dev_priv))
-               bxt_dsi_device_ready(encoder);
-       else
-               vlv_dsi_device_ready(encoder);
-}
-
-static void glk_dsi_enter_low_power_mode(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       /* Enter ULPS */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val = I915_READ(MIPI_DEVICE_READY(port));
-               val &= ~ULPS_STATE_MASK;
-               val |= (ULPS_STATE_ENTER | DEVICE_READY);
-               I915_WRITE(MIPI_DEVICE_READY(port), val);
-       }
-
-       /* Wait for MIPI PHY status bit to unset */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_CTRL(port),
-                                           GLK_PHY_STATUS_PORT_READY, 0, 20))
-                       DRM_ERROR("PHY is not turning OFF\n");
-       }
-
-       /* Wait for Pwr ACK bit to unset */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_CTRL(port),
-                                           GLK_MIPIIO_PORT_POWERED, 0, 20))
-                       DRM_ERROR("MIPI IO Port is not powergated\n");
-       }
-}
-
-static void glk_dsi_disable_mipi_io(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-
-       /* Put the IO into reset */
-       tmp = I915_READ(MIPI_CTRL(PORT_A));
-       tmp &= ~GLK_MIPIIO_RESET_RELEASED;
-       I915_WRITE(MIPI_CTRL(PORT_A), tmp);
-
-       /* Wait for MIPI PHY status bit to unset */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(&dev_priv->uncore,
-                                           MIPI_CTRL(port),
-                                           GLK_PHY_STATUS_PORT_READY, 0, 20))
-                       DRM_ERROR("PHY is not turning OFF\n");
-       }
-
-       /* Clear MIPI mode */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(MIPI_CTRL(port));
-               tmp &= ~GLK_MIPIIO_ENABLE;
-               I915_WRITE(MIPI_CTRL(port), tmp);
-       }
-}
-
-static void glk_dsi_clear_device_ready(struct intel_encoder *encoder)
-{
-       glk_dsi_enter_low_power_mode(encoder);
-       glk_dsi_disable_mipi_io(encoder);
-}
-
-static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-       for_each_dsi_port(port, intel_dsi->ports) {
-               /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */
-               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A);
-               u32 val;
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
-                                                       ULPS_STATE_ENTER);
-               usleep_range(2000, 2500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
-                                                       ULPS_STATE_EXIT);
-               usleep_range(2000, 2500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
-                                                       ULPS_STATE_ENTER);
-               usleep_range(2000, 2500);
-
-               /*
-                * On VLV/CHV, wait till Clock lanes are in LP-00 state for MIPI
-                * Port A only. MIPI Port C has no similar bit for checking.
-                */
-               if ((IS_GEN9_LP(dev_priv) || port == PORT_A) &&
-                   intel_wait_for_register(&dev_priv->uncore,
-                                           port_ctrl, AFE_LATCHOUT, 0,
-                                           30))
-                       DRM_ERROR("DSI LP not going Low\n");
-
-               /* Disable MIPI PHY transparent latch */
-               val = I915_READ(port_ctrl);
-               I915_WRITE(port_ctrl, val & ~LP_OUTPUT_HOLD);
-               usleep_range(1000, 1500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
-               usleep_range(2000, 2500);
-       }
-}
-
-static void intel_dsi_port_enable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
-               u32 temp;
-               if (IS_GEN9_LP(dev_priv)) {
-                       for_each_dsi_port(port, intel_dsi->ports) {
-                               temp = I915_READ(MIPI_CTRL(port));
-                               temp &= ~BXT_PIXEL_OVERLAP_CNT_MASK |
-                                       intel_dsi->pixel_overlap <<
-                                       BXT_PIXEL_OVERLAP_CNT_SHIFT;
-                               I915_WRITE(MIPI_CTRL(port), temp);
-                       }
-               } else {
-                       temp = I915_READ(VLV_CHICKEN_3);
-                       temp &= ~PIXEL_OVERLAP_CNT_MASK |
-                                       intel_dsi->pixel_overlap <<
-                                       PIXEL_OVERLAP_CNT_SHIFT;
-                       I915_WRITE(VLV_CHICKEN_3, temp);
-               }
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
-               u32 temp;
-
-               temp = I915_READ(port_ctrl);
-
-               temp &= ~LANE_CONFIGURATION_MASK;
-               temp &= ~DUAL_LINK_MODE_MASK;
-
-               if (intel_dsi->ports == (BIT(PORT_A) | BIT(PORT_C))) {
-                       temp |= (intel_dsi->dual_link - 1)
-                                               << DUAL_LINK_MODE_SHIFT;
-                       if (IS_BROXTON(dev_priv))
-                               temp |= LANE_CONFIGURATION_DUAL_LINK_A;
-                       else
-                               temp |= crtc->pipe ?
-                                       LANE_CONFIGURATION_DUAL_LINK_B :
-                                       LANE_CONFIGURATION_DUAL_LINK_A;
-               }
-
-               if (intel_dsi->pixel_format != MIPI_DSI_FMT_RGB888)
-                       temp |= DITHERING_ENABLE;
-
-               /* assert ip_tg_enable signal */
-               I915_WRITE(port_ctrl, temp | DPI_ENABLE);
-               POSTING_READ(port_ctrl);
-       }
-}
-
-static void intel_dsi_port_disable(struct intel_encoder *encoder)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
-               u32 temp;
-
-               /* de-assert ip_tg_enable signal */
-               temp = I915_READ(port_ctrl);
-               I915_WRITE(port_ctrl, temp & ~DPI_ENABLE);
-               POSTING_READ(port_ctrl);
-       }
-}
-
-static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
-                             const struct intel_crtc_state *pipe_config);
-static void intel_dsi_unprepare(struct intel_encoder *encoder);
-
-/*
- * Panel enable/disable sequences from the VBT spec.
- *
- * Note the spec has AssertReset / DeassertReset swapped from their
- * usual naming. We use the normal names to avoid confusion (so below
- * they are swapped compared to the spec).
- *
- * Steps starting with MIPI refer to VBT sequences, note that for v2
- * VBTs several steps which have a VBT in v2 are expected to be handled
- * directly by the driver, by directly driving gpios for example.
- *
- * v2 video mode seq         v3 video mode seq         command mode seq
- * - power on                - MIPIPanelPowerOn        - power on
- * - wait t1+t2                                        - wait t1+t2
- * - MIPIDeassertResetPin    - MIPIDeassertResetPin    - MIPIDeassertResetPin
- * - io lines to lp-11       - io lines to lp-11       - io lines to lp-11
- * - MIPISendInitialDcsCmds  - MIPISendInitialDcsCmds  - MIPISendInitialDcsCmds
- *                                                     - MIPITearOn
- *                                                     - MIPIDisplayOn
- * - turn on DPI             - turn on DPI             - set pipe to dsr mode
- * - MIPIDisplayOn           - MIPIDisplayOn
- * - wait t5                                           - wait t5
- * - backlight on            - MIPIBacklightOn         - backlight on
- * ...                       ...                       ... issue mem cmds ...
- * - backlight off           - MIPIBacklightOff        - backlight off
- * - wait t6                                           - wait t6
- * - MIPIDisplayOff
- * - turn off DPI            - turn off DPI            - disable pipe dsr mode
- *                                                     - MIPITearOff
- *                           - MIPIDisplayOff          - MIPIDisplayOff
- * - io lines to lp-00       - io lines to lp-00       - io lines to lp-00
- * - MIPIAssertResetPin      - MIPIAssertResetPin      - MIPIAssertResetPin
- * - wait t3                                           - wait t3
- * - power off               - MIPIPanelPowerOff       - power off
- * - wait t4                                           - wait t4
- */
-
-/*
- * DSI port enable has to be done before pipe and plane enable, so we do it in
- * the pre_enable hook instead of the enable hook.
- */
-static void intel_dsi_pre_enable(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       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;
-       enum port port;
-       u32 val;
-       bool glk_cold_boot = false;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
-
-       /*
-        * The BIOS may leave the PLL in a wonky state where it doesn't
-        * lock. It needs to be fully powered down to fix it.
-        */
-       if (IS_GEN9_LP(dev_priv)) {
-               bxt_dsi_pll_disable(encoder);
-               bxt_dsi_pll_enable(encoder, pipe_config);
-       } else {
-               vlv_dsi_pll_disable(encoder);
-               vlv_dsi_pll_enable(encoder, pipe_config);
-       }
-
-       if (IS_BROXTON(dev_priv)) {
-               /* Add MIPI IO reset programming for modeset */
-               val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
-               I915_WRITE(BXT_P_CR_GT_DISP_PWRON,
-                                       val | MIPIO_RST_CTRL);
-
-               /* Power up DSI regulator */
-               I915_WRITE(BXT_P_DSI_REGULATOR_CFG, STAP_SELECT);
-               I915_WRITE(BXT_P_DSI_REGULATOR_TX_CTRL, 0);
-       }
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               u32 val;
-
-               /* Disable DPOunit clock gating, can stall pipe */
-               val = I915_READ(DSPCLK_GATE_D);
-               val |= DPOUNIT_CLOCK_GATE_DISABLE;
-               I915_WRITE(DSPCLK_GATE_D, val);
-       }
-
-       if (!IS_GEMINILAKE(dev_priv))
-               intel_dsi_prepare(encoder, pipe_config);
-
-       /* Power on, try both CRC pmic gpio and VBT */
-       if (intel_dsi->gpio_panel)
-               gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
-
-       /* Deassert reset */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
-
-       if (IS_GEMINILAKE(dev_priv)) {
-               glk_cold_boot = glk_dsi_enable_io(encoder);
-
-               /* Prepare port in cold boot(s3/s4) scenario */
-               if (glk_cold_boot)
-                       intel_dsi_prepare(encoder, pipe_config);
-       }
-
-       /* Put device in ready state (LP-11) */
-       intel_dsi_device_ready(encoder);
-
-       /* Prepare port in normal boot scenario */
-       if (IS_GEMINILAKE(dev_priv) && !glk_cold_boot)
-               intel_dsi_prepare(encoder, pipe_config);
-
-       /* Send initialization commands in LP mode */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
-
-       /* Enable port in pre-enable phase itself because as per hw team
-        * recommendation, port should be enabled befor plane & pipe */
-       if (is_cmd_mode(intel_dsi)) {
-               for_each_dsi_port(port, intel_dsi->ports)
-                       I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_TEAR_ON);
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
-       } else {
-               msleep(20); /* XXX */
-               for_each_dsi_port(port, intel_dsi->ports)
-                       dpi_send_cmd(intel_dsi, TURN_ON, false, port);
-               intel_dsi_msleep(intel_dsi, 100);
-
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
-
-               intel_dsi_port_enable(encoder, pipe_config);
-       }
-
-       intel_panel_enable_backlight(pipe_config, conn_state);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
-}
-
-/*
- * DSI port disable has to be done after pipe and plane disable, so we do it in
- * the post_disable hook.
- */
-static void intel_dsi_disable(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
-       intel_panel_disable_backlight(old_conn_state);
-
-       /*
-        * According to the spec we should send SHUTDOWN before
-        * MIPI_SEQ_DISPLAY_OFF only for v3+ VBTs, but field testing
-        * has shown that the v3 sequence works for v2 VBTs too
-        */
-       if (is_vid_mode(intel_dsi)) {
-               /* Send Shutdown command to the panel in LP mode */
-               for_each_dsi_port(port, intel_dsi->ports)
-                       dpi_send_cmd(intel_dsi, SHUTDOWN, false, port);
-               msleep(10);
-       }
-}
-
-static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (IS_GEMINILAKE(dev_priv))
-               glk_dsi_clear_device_ready(encoder);
-       else
-               vlv_dsi_clear_device_ready(encoder);
-}
-
-static void intel_dsi_post_disable(struct intel_encoder *encoder,
-                                  const struct intel_crtc_state *pipe_config,
-                                  const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (is_vid_mode(intel_dsi)) {
-               for_each_dsi_port(port, intel_dsi->ports)
-                       vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
-
-               intel_dsi_port_disable(encoder);
-               usleep_range(2000, 5000);
-       }
-
-       intel_dsi_unprepare(encoder);
-
-       /*
-        * if disable packets are sent before sending shutdown packet then in
-        * some next enable sequence send turn on packet error is observed
-        */
-       if (is_cmd_mode(intel_dsi))
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_TEAR_OFF);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
-
-       /* Transition to LP-00 */
-       intel_dsi_clear_device_ready(encoder);
-
-       if (IS_BROXTON(dev_priv)) {
-               /* Power down DSI regulator to save power */
-               I915_WRITE(BXT_P_DSI_REGULATOR_CFG, STAP_SELECT);
-               I915_WRITE(BXT_P_DSI_REGULATOR_TX_CTRL, HS_IO_CTRL_SELECT);
-
-               /* Add MIPI IO reset programming for modeset */
-               val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
-               I915_WRITE(BXT_P_CR_GT_DISP_PWRON,
-                               val & ~MIPIO_RST_CTRL);
-       }
-
-       if (IS_GEN9_LP(dev_priv)) {
-               bxt_dsi_pll_disable(encoder);
-       } else {
-               u32 val;
-
-               vlv_dsi_pll_disable(encoder);
-
-               val = I915_READ(DSPCLK_GATE_D);
-               val &= ~DPOUNIT_CLOCK_GATE_DISABLE;
-               I915_WRITE(DSPCLK_GATE_D, val);
-       }
-
-       /* Assert reset */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
-
-       /* Power off, try both CRC pmic gpio and VBT */
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
-       if (intel_dsi->gpio_panel)
-               gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0);
-
-       /*
-        * FIXME As we do with eDP, just make a note of the time here
-        * and perform the wait before the next panel power on.
-        */
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
-}
-
-static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
-                                  enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       intel_wakeref_t wakeref;
-       enum port port;
-       bool active = false;
-
-       DRM_DEBUG_KMS("\n");
-
-       wakeref = intel_display_power_get_if_enabled(dev_priv,
-                                                    encoder->power_domain);
-       if (!wakeref)
-               return false;
-
-       /*
-        * On Broxton the PLL needs to be enabled with a valid divider
-        * configuration, otherwise accessing DSI registers will hang the
-        * machine. See BSpec North Display Engine registers/MIPI[BXT].
-        */
-       if (IS_GEN9_LP(dev_priv) && !bxt_dsi_pll_is_enabled(dev_priv))
-               goto out_put_power;
-
-       /* XXX: this only works for one DSI output */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               i915_reg_t ctrl_reg = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
-               bool enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
-
-               /*
-                * Due to some hardware limitations on VLV/CHV, the DPI enable
-                * bit in port C control register does not get set. As a
-                * workaround, check pipe B conf instead.
-                */
-               if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-                   port == PORT_C)
-                       enabled = I915_READ(PIPECONF(PIPE_B)) & PIPECONF_ENABLE;
-
-               /* Try command mode if video mode not enabled */
-               if (!enabled) {
-                       u32 tmp = I915_READ(MIPI_DSI_FUNC_PRG(port));
-                       enabled = tmp & CMD_MODE_DATA_WIDTH_MASK;
-               }
-
-               if (!enabled)
-                       continue;
-
-               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY))
-                       continue;
-
-               if (IS_GEN9_LP(dev_priv)) {
-                       u32 tmp = I915_READ(MIPI_CTRL(port));
-                       tmp &= BXT_PIPE_SELECT_MASK;
-                       tmp >>= BXT_PIPE_SELECT_SHIFT;
-
-                       if (WARN_ON(tmp > PIPE_C))
-                               continue;
-
-                       *pipe = tmp;
-               } else {
-                       *pipe = port == PORT_A ? PIPE_A : PIPE_B;
-               }
-
-               active = true;
-               break;
-       }
-
-out_put_power:
-       intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
-
-       return active;
-}
-
-static void bxt_dsi_get_pipe_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_display_mode *adjusted_mode =
-                                       &pipe_config->base.adjusted_mode;
-       struct drm_display_mode *adjusted_mode_sw;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       unsigned int lane_count = intel_dsi->lane_count;
-       unsigned int bpp, fmt;
-       enum port port;
-       u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
-       u16 hfp_sw, hsync_sw, hbp_sw;
-       u16 crtc_htotal_sw, crtc_hsync_start_sw, crtc_hsync_end_sw,
-                               crtc_hblank_start_sw, crtc_hblank_end_sw;
-
-       /* FIXME: hw readout should not depend on SW state */
-       adjusted_mode_sw = &crtc->config->base.adjusted_mode;
-
-       /*
-        * Atleast one port is active as encoder->get_config called only if
-        * encoder->get_hw_state() returns true.
-        */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (I915_READ(BXT_MIPI_PORT_CTRL(port)) & DPI_ENABLE)
-                       break;
-       }
-
-       fmt = I915_READ(MIPI_DSI_FUNC_PRG(port)) & VID_MODE_FORMAT_MASK;
-       bpp = mipi_dsi_pixel_format_to_bpp(
-                       pixel_format_from_register_bits(fmt));
-
-       pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
-
-       /* Enable Frame time stamo based scanline reporting */
-       adjusted_mode->private_flags |=
-                       I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP;
-
-       /* In terms of pixels */
-       adjusted_mode->crtc_hdisplay =
-                               I915_READ(BXT_MIPI_TRANS_HACTIVE(port));
-       adjusted_mode->crtc_vdisplay =
-                               I915_READ(BXT_MIPI_TRANS_VACTIVE(port));
-       adjusted_mode->crtc_vtotal =
-                               I915_READ(BXT_MIPI_TRANS_VTOTAL(port));
-
-       hactive = adjusted_mode->crtc_hdisplay;
-       hfp = I915_READ(MIPI_HFP_COUNT(port));
-
-       /*
-        * Meaningful for video mode non-burst sync pulse mode only,
-        * can be zero for non-burst sync events and burst modes
-        */
-       hsync = I915_READ(MIPI_HSYNC_PADDING_COUNT(port));
-       hbp = I915_READ(MIPI_HBP_COUNT(port));
-
-       /* harizontal values are in terms of high speed byte clock */
-       hfp = pixels_from_txbyteclkhs(hfp, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hsync = pixels_from_txbyteclkhs(hsync, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hbp = pixels_from_txbyteclkhs(hbp, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-
-       if (intel_dsi->dual_link) {
-               hfp *= 2;
-               hsync *= 2;
-               hbp *= 2;
-       }
-
-       /* vertical values are in terms of lines */
-       vfp = I915_READ(MIPI_VFP_COUNT(port));
-       vsync = I915_READ(MIPI_VSYNC_PADDING_COUNT(port));
-       vbp = I915_READ(MIPI_VBP_COUNT(port));
-
-       adjusted_mode->crtc_htotal = hactive + hfp + hsync + hbp;
-       adjusted_mode->crtc_hsync_start = hfp + adjusted_mode->crtc_hdisplay;
-       adjusted_mode->crtc_hsync_end = hsync + adjusted_mode->crtc_hsync_start;
-       adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hdisplay;
-       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal;
-
-       adjusted_mode->crtc_vsync_start = vfp + adjusted_mode->crtc_vdisplay;
-       adjusted_mode->crtc_vsync_end = vsync + adjusted_mode->crtc_vsync_start;
-       adjusted_mode->crtc_vblank_start = adjusted_mode->crtc_vdisplay;
-       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal;
-
-       /*
-        * In BXT DSI there is no regs programmed with few horizontal timings
-        * in Pixels but txbyteclkhs.. So retrieval process adds some
-        * ROUND_UP ERRORS in the process of PIXELS<==>txbyteclkhs.
-        * Actually here for the given adjusted_mode, we are calculating the
-        * value programmed to the port and then back to the horizontal timing
-        * param in pixels. This is the expected value, including roundup errors
-        * And if that is same as retrieved value from port, then
-        * (HW state) adjusted_mode's horizontal timings are corrected to
-        * match with SW state to nullify the errors.
-        */
-       /* Calculating the value programmed to the Port register */
-       hfp_sw = adjusted_mode_sw->crtc_hsync_start -
-                                       adjusted_mode_sw->crtc_hdisplay;
-       hsync_sw = adjusted_mode_sw->crtc_hsync_end -
-                                       adjusted_mode_sw->crtc_hsync_start;
-       hbp_sw = adjusted_mode_sw->crtc_htotal -
-                                       adjusted_mode_sw->crtc_hsync_end;
-
-       if (intel_dsi->dual_link) {
-               hfp_sw /= 2;
-               hsync_sw /= 2;
-               hbp_sw /= 2;
-       }
-
-       hfp_sw = txbyteclkhs(hfp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hsync_sw = txbyteclkhs(hsync_sw, bpp, lane_count,
-                           intel_dsi->burst_mode_ratio);
-       hbp_sw = txbyteclkhs(hbp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-
-       /* Reverse calculating the adjusted mode parameters from port reg vals*/
-       hfp_sw = pixels_from_txbyteclkhs(hfp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hsync_sw = pixels_from_txbyteclkhs(hsync_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hbp_sw = pixels_from_txbyteclkhs(hbp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-
-       if (intel_dsi->dual_link) {
-               hfp_sw *= 2;
-               hsync_sw *= 2;
-               hbp_sw *= 2;
-       }
-
-       crtc_htotal_sw = adjusted_mode_sw->crtc_hdisplay + hfp_sw +
-                                                       hsync_sw + hbp_sw;
-       crtc_hsync_start_sw = hfp_sw + adjusted_mode_sw->crtc_hdisplay;
-       crtc_hsync_end_sw = hsync_sw + crtc_hsync_start_sw;
-       crtc_hblank_start_sw = adjusted_mode_sw->crtc_hdisplay;
-       crtc_hblank_end_sw = crtc_htotal_sw;
-
-       if (adjusted_mode->crtc_htotal == crtc_htotal_sw)
-               adjusted_mode->crtc_htotal = adjusted_mode_sw->crtc_htotal;
-
-       if (adjusted_mode->crtc_hsync_start == crtc_hsync_start_sw)
-               adjusted_mode->crtc_hsync_start =
-                                       adjusted_mode_sw->crtc_hsync_start;
-
-       if (adjusted_mode->crtc_hsync_end == crtc_hsync_end_sw)
-               adjusted_mode->crtc_hsync_end =
-                                       adjusted_mode_sw->crtc_hsync_end;
-
-       if (adjusted_mode->crtc_hblank_start == crtc_hblank_start_sw)
-               adjusted_mode->crtc_hblank_start =
-                                       adjusted_mode_sw->crtc_hblank_start;
-
-       if (adjusted_mode->crtc_hblank_end == crtc_hblank_end_sw)
-               adjusted_mode->crtc_hblank_end =
-                                       adjusted_mode_sw->crtc_hblank_end;
-}
-
-static void intel_dsi_get_config(struct intel_encoder *encoder,
-                                struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 pclk;
-       DRM_DEBUG_KMS("\n");
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
-
-       if (IS_GEN9_LP(dev_priv)) {
-               bxt_dsi_get_pipe_config(encoder, pipe_config);
-               pclk = bxt_dsi_get_pclk(encoder, pipe_config);
-       } else {
-               pclk = vlv_dsi_get_pclk(encoder, pipe_config);
-       }
-
-       if (pclk) {
-               pipe_config->base.adjusted_mode.crtc_clock = pclk;
-               pipe_config->port_clock = pclk;
-       }
-}
-
-/* return txclkesc cycles in terms of divider and duration in us */
-static u16 txclkesc(u32 divider, unsigned int us)
-{
-       switch (divider) {
-       case ESCAPE_CLOCK_DIVIDER_1:
-       default:
-               return 20 * us;
-       case ESCAPE_CLOCK_DIVIDER_2:
-               return 10 * us;
-       case ESCAPE_CLOCK_DIVIDER_4:
-               return 5 * us;
-       }
-}
-
-static void set_dsi_timings(struct drm_encoder *encoder,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-       enum port port;
-       unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-       unsigned int lane_count = intel_dsi->lane_count;
-
-       u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
-
-       hactive = adjusted_mode->crtc_hdisplay;
-       hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay;
-       hsync = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
-       hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end;
-
-       if (intel_dsi->dual_link) {
-               hactive /= 2;
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-                       hactive += intel_dsi->pixel_overlap;
-               hfp /= 2;
-               hsync /= 2;
-               hbp /= 2;
-       }
-
-       vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay;
-       vsync = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
-       vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end;
-
-       /* horizontal values are in terms of high speed byte clock */
-       hactive = txbyteclkhs(hactive, bpp, lane_count,
-                             intel_dsi->burst_mode_ratio);
-       hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio);
-       hsync = txbyteclkhs(hsync, bpp, lane_count,
-                           intel_dsi->burst_mode_ratio);
-       hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (IS_GEN9_LP(dev_priv)) {
-                       /*
-                        * Program hdisplay and vdisplay on MIPI transcoder.
-                        * This is different from calculated hactive and
-                        * vactive, as they are calculated per channel basis,
-                        * whereas these values should be based on resolution.
-                        */
-                       I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port),
-                                  adjusted_mode->crtc_hdisplay);
-                       I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port),
-                                  adjusted_mode->crtc_vdisplay);
-                       I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port),
-                                  adjusted_mode->crtc_vtotal);
-               }
-
-               I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
-               I915_WRITE(MIPI_HFP_COUNT(port), hfp);
-
-               /* meaningful for video mode non-burst sync pulse mode only,
-                * can be zero for non-burst sync events and burst modes */
-               I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync);
-               I915_WRITE(MIPI_HBP_COUNT(port), hbp);
-
-               /* vertical values are in terms of lines */
-               I915_WRITE(MIPI_VFP_COUNT(port), vfp);
-               I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync);
-               I915_WRITE(MIPI_VBP_COUNT(port), vbp);
-       }
-}
-
-static u32 pixel_format_to_reg(enum mipi_dsi_pixel_format fmt)
-{
-       switch (fmt) {
-       case MIPI_DSI_FMT_RGB888:
-               return VID_MODE_FORMAT_RGB888;
-       case MIPI_DSI_FMT_RGB666:
-               return VID_MODE_FORMAT_RGB666;
-       case MIPI_DSI_FMT_RGB666_PACKED:
-               return VID_MODE_FORMAT_RGB666_PACKED;
-       case MIPI_DSI_FMT_RGB565:
-               return VID_MODE_FORMAT_RGB565;
-       default:
-               MISSING_CASE(fmt);
-               return VID_MODE_FORMAT_RGB666;
-       }
-}
-
-static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
-                             const struct intel_crtc_state *pipe_config)
-{
-       struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       enum port port;
-       unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-       u32 val, tmp;
-       u16 mode_hdisplay;
-
-       DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
-
-       mode_hdisplay = adjusted_mode->crtc_hdisplay;
-
-       if (intel_dsi->dual_link) {
-               mode_hdisplay /= 2;
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-                       mode_hdisplay += intel_dsi->pixel_overlap;
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-                       /*
-                        * escape clock divider, 20MHz, shared for A and C.
-                        * device ready must be off when doing this! txclkesc?
-                        */
-                       tmp = I915_READ(MIPI_CTRL(PORT_A));
-                       tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
-                       I915_WRITE(MIPI_CTRL(PORT_A), tmp |
-                                       ESCAPE_CLOCK_DIVIDER_1);
-
-                       /* read request priority is per pipe */
-                       tmp = I915_READ(MIPI_CTRL(port));
-                       tmp &= ~READ_REQUEST_PRIORITY_MASK;
-                       I915_WRITE(MIPI_CTRL(port), tmp |
-                                       READ_REQUEST_PRIORITY_HIGH);
-               } else if (IS_GEN9_LP(dev_priv)) {
-                       enum pipe pipe = intel_crtc->pipe;
-
-                       tmp = I915_READ(MIPI_CTRL(port));
-                       tmp &= ~BXT_PIPE_SELECT_MASK;
-
-                       tmp |= BXT_PIPE_SELECT(pipe);
-                       I915_WRITE(MIPI_CTRL(port), tmp);
-               }
-
-               /* XXX: why here, why like this? handling in irq handler?! */
-               I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
-               I915_WRITE(MIPI_INTR_EN(port), 0xffffffff);
-
-               I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
-
-               I915_WRITE(MIPI_DPI_RESOLUTION(port),
-                       adjusted_mode->crtc_vdisplay << VERTICAL_ADDRESS_SHIFT |
-                       mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
-       }
-
-       set_dsi_timings(encoder, adjusted_mode);
-
-       val = intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT;
-       if (is_cmd_mode(intel_dsi)) {
-               val |= intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT;
-               val |= CMD_MODE_DATA_WIDTH_8_BIT; /* XXX */
-       } else {
-               val |= intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT;
-               val |= pixel_format_to_reg(intel_dsi->pixel_format);
-       }
-
-       tmp = 0;
-       if (intel_dsi->eotp_pkt == 0)
-               tmp |= EOT_DISABLE;
-       if (intel_dsi->clock_stop)
-               tmp |= CLOCKSTOP;
-
-       if (IS_GEN9_LP(dev_priv)) {
-               tmp |= BXT_DPHY_DEFEATURE_EN;
-               if (!is_cmd_mode(intel_dsi))
-                       tmp |= BXT_DEFEATURE_DPI_FIFO_CTR;
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
-
-               /* timeouts for recovery. one frame IIUC. if counter expires,
-                * EOT and stop state. */
-
-               /*
-                * In burst mode, value greater than one DPI line Time in byte
-                * clock (txbyteclkhs) To timeout this timer 1+ of the above
-                * said value is recommended.
-                *
-                * In non-burst mode, Value greater than one DPI frame time in
-                * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
-                * said value is recommended.
-                *
-                * In DBI only mode, value greater than one DBI frame time in
-                * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
-                * said value is recommended.
-                */
-
-               if (is_vid_mode(intel_dsi) &&
-                       intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
-                       I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
-                               txbyteclkhs(adjusted_mode->crtc_htotal, bpp,
-                                           intel_dsi->lane_count,
-                                           intel_dsi->burst_mode_ratio) + 1);
-               } else {
-                       I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
-                               txbyteclkhs(adjusted_mode->crtc_vtotal *
-                                           adjusted_mode->crtc_htotal,
-                                           bpp, intel_dsi->lane_count,
-                                           intel_dsi->burst_mode_ratio) + 1);
-               }
-               I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
-               I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
-                                               intel_dsi->turn_arnd_val);
-               I915_WRITE(MIPI_DEVICE_RESET_TIMER(port),
-                                               intel_dsi->rst_timer_val);
-
-               /* dphy stuff */
-
-               /* in terms of low power clock */
-               I915_WRITE(MIPI_INIT_COUNT(port),
-                               txclkesc(intel_dsi->escape_clk_div, 100));
-
-               if (IS_GEN9_LP(dev_priv) && (!intel_dsi->dual_link)) {
-                       /*
-                        * BXT spec says write MIPI_INIT_COUNT for
-                        * both the ports, even if only one is
-                        * getting used. So write the other port
-                        * if not in dual link mode.
-                        */
-                       I915_WRITE(MIPI_INIT_COUNT(port ==
-                                               PORT_A ? PORT_C : PORT_A),
-                                       intel_dsi->init_count);
-               }
-
-               /* recovery disables */
-               I915_WRITE(MIPI_EOT_DISABLE(port), tmp);
-
-               /* in terms of low power clock */
-               I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
-
-               /* in terms of txbyteclkhs. actual high to low switch +
-                * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
-                *
-                * XXX: write MIPI_STOP_STATE_STALL?
-                */
-               I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port),
-                                               intel_dsi->hs_to_lp_count);
-
-               /* XXX: low power clock equivalence in terms of byte clock.
-                * the number of byte clocks occupied in one low power clock.
-                * based on txbyteclkhs and txclkesc.
-                * txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL
-                * ) / 105.???
-                */
-               I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk);
-
-               if (IS_GEMINILAKE(dev_priv)) {
-                       I915_WRITE(MIPI_TLPX_TIME_COUNT(port),
-                                       intel_dsi->lp_byte_clk);
-                       /* Shadow of DPHY reg */
-                       I915_WRITE(MIPI_CLK_LANE_TIMING(port),
-                                       intel_dsi->dphy_reg);
-               }
-
-               /* the bw essential for transmitting 16 long packets containing
-                * 252 bytes meant for dcs write memory command is programmed in
-                * this register in terms of byte clocks. based on dsi transfer
-                * rate and the number of lanes configured the time taken to
-                * transmit 16 long packets in a dsi stream varies. */
-               I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer);
-
-               I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port),
-               intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
-               intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
-
-               if (is_vid_mode(intel_dsi))
-                       /* Some panels might have resolution which is not a
-                        * multiple of 64 like 1366 x 768. Enable RANDOM
-                        * resolution support for such panels by default */
-                       I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port),
-                               intel_dsi->video_frmt_cfg_bits |
-                               intel_dsi->video_mode_format |
-                               IP_TG_CONFIG |
-                               RANDOM_DPI_DISPLAY_RESOLUTION);
-       }
-}
-
-static void intel_dsi_unprepare(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       if (IS_GEMINILAKE(dev_priv))
-               return;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               /* Panel commands can be sent when clock is in LP11 */
-               I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
-
-               if (IS_GEN9_LP(dev_priv))
-                       bxt_dsi_reset_clocks(encoder, port);
-               else
-                       vlv_dsi_reset_clocks(encoder, port);
-               I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
-
-               val = I915_READ(MIPI_DSI_FUNC_PRG(port));
-               val &= ~VID_MODE_FORMAT_MASK;
-               I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
-       }
-}
-
-static void intel_dsi_encoder_destroy(struct drm_encoder *encoder)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-
-       /* dispose of the gpios */
-       if (intel_dsi->gpio_panel)
-               gpiod_put(intel_dsi->gpio_panel);
-
-       intel_encoder_destroy(encoder);
-}
-
-static const struct drm_encoder_funcs intel_dsi_funcs = {
-       .destroy = intel_dsi_encoder_destroy,
-};
-
-static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = {
-       .get_modes = intel_dsi_get_modes,
-       .mode_valid = intel_dsi_mode_valid,
-       .atomic_check = intel_digital_connector_atomic_check,
-};
-
-static const struct drm_connector_funcs intel_dsi_connector_funcs = {
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_connector_destroy,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static enum drm_panel_orientation
-vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_encoder *encoder = connector->encoder;
-       enum intel_display_power_domain power_domain;
-       enum drm_panel_orientation orientation;
-       struct intel_plane *plane;
-       struct intel_crtc *crtc;
-       intel_wakeref_t wakeref;
-       enum pipe pipe;
-       u32 val;
-
-       if (!encoder->get_hw_state(encoder, &pipe))
-               return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
-
-       crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
-       plane = to_intel_plane(crtc->base.primary);
-
-       power_domain = POWER_DOMAIN_PIPE(pipe);
-       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
-       if (!wakeref)
-               return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
-
-       val = I915_READ(DSPCNTR(plane->i9xx_plane));
-
-       if (!(val & DISPLAY_PLANE_ENABLE))
-               orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
-       else if (val & DISPPLANE_ROTATE_180)
-               orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
-       else
-               orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
-
-       intel_display_power_put(dev_priv, power_domain, wakeref);
-
-       return orientation;
-}
-
-static enum drm_panel_orientation
-vlv_dsi_get_panel_orientation(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum drm_panel_orientation orientation;
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               orientation = vlv_dsi_get_hw_panel_orientation(connector);
-               if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
-                       return orientation;
-       }
-
-       return intel_dsi_get_panel_orientation(connector);
-}
-
-static void intel_dsi_add_properties(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       if (connector->panel.fixed_mode) {
-               u32 allowed_scalers;
-
-               allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
-               if (!HAS_GMCH(dev_priv))
-                       allowed_scalers |= 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 =
-                       vlv_dsi_get_panel_orientation(connector);
-               drm_connector_init_panel_orientation_property(
-                               &connector->base,
-                               connector->panel.fixed_mode->hdisplay,
-                               connector->panel.fixed_mode->vdisplay);
-       }
-}
-
-#define NS_KHZ_RATIO           1000000
-
-#define PREPARE_CNT_MAX                0x3F
-#define EXIT_ZERO_CNT_MAX      0x3F
-#define CLK_ZERO_CNT_MAX       0xFF
-#define TRAIL_CNT_MAX          0x1F
-
-static void vlv_dphy_param_init(struct intel_dsi *intel_dsi)
-{
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
-       u32 tlpx_ns, extra_byte_count, tlpx_ui;
-       u32 ui_num, ui_den;
-       u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
-       u32 ths_prepare_ns, tclk_trail_ns;
-       u32 tclk_prepare_clkzero, ths_prepare_hszero;
-       u32 lp_to_hs_switch, hs_to_lp_switch;
-       u32 mul;
-
-       tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
-
-       switch (intel_dsi->lane_count) {
-       case 1:
-       case 2:
-               extra_byte_count = 2;
-               break;
-       case 3:
-               extra_byte_count = 4;
-               break;
-       case 4:
-       default:
-               extra_byte_count = 3;
-               break;
-       }
-
-       /* in Kbps */
-       ui_num = NS_KHZ_RATIO;
-       ui_den = intel_dsi_bitrate(intel_dsi);
-
-       tclk_prepare_clkzero = mipi_config->tclk_prepare_clkzero;
-       ths_prepare_hszero = mipi_config->ths_prepare_hszero;
-
-       /*
-        * B060
-        * LP byte clock = TLPX/ (8UI)
-        */
-       intel_dsi->lp_byte_clk = DIV_ROUND_UP(tlpx_ns * ui_den, 8 * ui_num);
-
-       /* DDR clock period = 2 * UI
-        * UI(sec) = 1/(bitrate * 10^3) (bitrate is in KHZ)
-        * UI(nsec) = 10^6 / bitrate
-        * DDR clock period (nsec) = 2 * UI = (2 * 10^6)/ bitrate
-        * DDR clock count  = ns_value / DDR clock period
-        *
-        * For GEMINILAKE dphy_param_reg will be programmed in terms of
-        * HS byte clock count for other platform in HS ddr clock count
-        */
-       mul = IS_GEMINILAKE(dev_priv) ? 8 : 2;
-       ths_prepare_ns = max(mipi_config->ths_prepare,
-                            mipi_config->tclk_prepare);
-
-       /* prepare count */
-       prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * ui_den, ui_num * mul);
-
-       if (prepare_cnt > PREPARE_CNT_MAX) {
-               DRM_DEBUG_KMS("prepare count too high %u\n", prepare_cnt);
-               prepare_cnt = PREPARE_CNT_MAX;
-       }
-
-       /* exit zero count */
-       exit_zero_cnt = DIV_ROUND_UP(
-                               (ths_prepare_hszero - ths_prepare_ns) * ui_den,
-                               ui_num * mul
-                               );
-
-       /*
-        * Exit zero is unified val ths_zero and ths_exit
-        * minimum value for ths_exit = 110ns
-        * min (exit_zero_cnt * 2) = 110/UI
-        * exit_zero_cnt = 55/UI
-        */
-       if (exit_zero_cnt < (55 * ui_den / ui_num) && (55 * ui_den) % ui_num)
-               exit_zero_cnt += 1;
-
-       if (exit_zero_cnt > EXIT_ZERO_CNT_MAX) {
-               DRM_DEBUG_KMS("exit zero count too high %u\n", exit_zero_cnt);
-               exit_zero_cnt = EXIT_ZERO_CNT_MAX;
-       }
-
-       /* clk zero count */
-       clk_zero_cnt = DIV_ROUND_UP(
-                               (tclk_prepare_clkzero - ths_prepare_ns)
-                               * ui_den, ui_num * mul);
-
-       if (clk_zero_cnt > CLK_ZERO_CNT_MAX) {
-               DRM_DEBUG_KMS("clock zero count too high %u\n", clk_zero_cnt);
-               clk_zero_cnt = CLK_ZERO_CNT_MAX;
-       }
-
-       /* trail count */
-       tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail);
-       trail_cnt = DIV_ROUND_UP(tclk_trail_ns * ui_den, ui_num * mul);
-
-       if (trail_cnt > TRAIL_CNT_MAX) {
-               DRM_DEBUG_KMS("trail count too high %u\n", trail_cnt);
-               trail_cnt = TRAIL_CNT_MAX;
-       }
-
-       /* B080 */
-       intel_dsi->dphy_reg = exit_zero_cnt << 24 | trail_cnt << 16 |
-                                               clk_zero_cnt << 8 | prepare_cnt;
-
-       /*
-        * LP to HS switch count = 4TLPX + PREP_COUNT * mul + EXIT_ZERO_COUNT *
-        *                                      mul + 10UI + Extra Byte Count
-        *
-        * HS to LP switch count = THS-TRAIL + 2TLPX + Extra Byte Count
-        * Extra Byte Count is calculated according to number of lanes.
-        * High Low Switch Count is the Max of LP to HS and
-        * HS to LP switch count
-        *
-        */
-       tlpx_ui = DIV_ROUND_UP(tlpx_ns * ui_den, ui_num);
-
-       /* B044 */
-       /* FIXME:
-        * The comment above does not match with the code */
-       lp_to_hs_switch = DIV_ROUND_UP(4 * tlpx_ui + prepare_cnt * mul +
-                                               exit_zero_cnt * mul + 10, 8);
-
-       hs_to_lp_switch = DIV_ROUND_UP(mipi_config->ths_trail + 2 * tlpx_ui, 8);
-
-       intel_dsi->hs_to_lp_count = max(lp_to_hs_switch, hs_to_lp_switch);
-       intel_dsi->hs_to_lp_count += extra_byte_count;
-
-       /* B088 */
-       /* LP -> HS for clock lanes
-        * LP clk sync + LP11 + LP01 + tclk_prepare + tclk_zero +
-        *                                              extra byte count
-        * 2TPLX + 1TLPX + 1 TPLX(in ns) + prepare_cnt * 2 + clk_zero_cnt *
-        *                                      2(in UI) + extra byte count
-        * In byteclks = (4TLPX + prepare_cnt * 2 + clk_zero_cnt *2 (in UI)) /
-        *                                      8 + extra byte count
-        */
-       intel_dsi->clk_lp_to_hs_count =
-               DIV_ROUND_UP(
-                       4 * tlpx_ui + prepare_cnt * 2 +
-                       clk_zero_cnt * 2,
-                       8);
-
-       intel_dsi->clk_lp_to_hs_count += extra_byte_count;
-
-       /* HS->LP for Clock Lanes
-        * Low Power clock synchronisations + 1Tx byteclk + tclk_trail +
-        *                                              Extra byte count
-        * 2TLPX + 8UI + (trail_count*2)(in UI) + Extra byte count
-        * In byteclks = (2*TLpx(in UI) + trail_count*2 +8)(in UI)/8 +
-        *                                              Extra byte count
-        */
-       intel_dsi->clk_hs_to_lp_count =
-               DIV_ROUND_UP(2 * tlpx_ui + trail_cnt * 2 + 8,
-                       8);
-       intel_dsi->clk_hs_to_lp_count += extra_byte_count;
-
-       intel_dsi_log_params(intel_dsi);
-}
-
-void vlv_dsi_init(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_dsi *intel_dsi;
-       struct intel_encoder *intel_encoder;
-       struct drm_encoder *encoder;
-       struct intel_connector *intel_connector;
-       struct drm_connector *connector;
-       struct drm_display_mode *current_mode, *fixed_mode;
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* There is no detection method for MIPI so rely on VBT */
-       if (!intel_bios_is_dsi_present(dev_priv, &port))
-               return;
-
-       if (IS_GEN9_LP(dev_priv))
-               dev_priv->mipi_mmio_base = BXT_MIPI_BASE;
-       else
-               dev_priv->mipi_mmio_base = VLV_MIPI_BASE;
-
-       intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
-       if (!intel_dsi)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_dsi);
-               return;
-       }
-
-       intel_encoder = &intel_dsi->base;
-       encoder = &intel_encoder->base;
-       intel_dsi->attached_connector = intel_connector;
-
-       connector = &intel_connector->base;
-
-       drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
-                        "DSI %c", port_name(port));
-
-       intel_encoder->compute_config = intel_dsi_compute_config;
-       intel_encoder->pre_enable = intel_dsi_pre_enable;
-       intel_encoder->disable = intel_dsi_disable;
-       intel_encoder->post_disable = intel_dsi_post_disable;
-       intel_encoder->get_hw_state = intel_dsi_get_hw_state;
-       intel_encoder->get_config = intel_dsi_get_config;
-       intel_encoder->update_pipe = intel_panel_update_backlight;
-
-       intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       intel_encoder->port = port;
-       intel_encoder->type = INTEL_OUTPUT_DSI;
-       intel_encoder->power_domain = POWER_DOMAIN_PORT_DSI;
-       intel_encoder->cloneable = 0;
-
-       /*
-        * On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI
-        * port C. BXT isn't limited like this.
-        */
-       if (IS_GEN9_LP(dev_priv))
-               intel_encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C);
-       else if (port == PORT_A)
-               intel_encoder->crtc_mask = BIT(PIPE_A);
-       else
-               intel_encoder->crtc_mask = BIT(PIPE_B);
-
-       if (dev_priv->vbt.dsi.config->dual_link)
-               intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C);
-       else
-               intel_dsi->ports = BIT(port);
-
-       intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports;
-       intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports;
-
-       /* Create a DSI host (and a device) for each port. */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               struct intel_dsi_host *host;
-
-               host = intel_dsi_host_init(intel_dsi, &intel_dsi_host_ops,
-                                          port);
-               if (!host)
-                       goto err;
-
-               intel_dsi->dsi_hosts[port] = host;
-       }
-
-       if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
-               DRM_DEBUG_KMS("no device found\n");
-               goto err;
-       }
-
-       /* Use clock read-back from current hw-state for fastboot */
-       current_mode = intel_encoder_current_mode(intel_encoder);
-       if (current_mode) {
-               DRM_DEBUG_KMS("Calculated pclk %d GOP %d\n",
-                             intel_dsi->pclk, current_mode->clock);
-               if (intel_fuzzy_clock_check(intel_dsi->pclk,
-                                           current_mode->clock)) {
-                       DRM_DEBUG_KMS("Using GOP pclk\n");
-                       intel_dsi->pclk = current_mode->clock;
-               }
-
-               kfree(current_mode);
-       }
-
-       vlv_dphy_param_init(intel_dsi);
-
-       /*
-        * In case of BYT with CRC PMIC, we need to use GPIO for
-        * Panel control.
-        */
-       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-           (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC)) {
-               intel_dsi->gpio_panel =
-                       gpiod_get(dev->dev, "panel", GPIOD_OUT_HIGH);
-
-               if (IS_ERR(intel_dsi->gpio_panel)) {
-                       DRM_ERROR("Failed to own gpio for panel control\n");
-                       intel_dsi->gpio_panel = NULL;
-               }
-       }
-
-       drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
-                          DRM_MODE_CONNECTOR_DSI);
-
-       drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs);
-
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/
-       connector->interlace_allowed = false;
-       connector->doublescan_allowed = false;
-
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
-
-       mutex_lock(&dev->mode_config.mutex);
-       fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
-       mutex_unlock(&dev->mode_config.mutex);
-
-       if (!fixed_mode) {
-               DRM_DEBUG_KMS("no fixed mode\n");
-               goto err_cleanup_connector;
-       }
-
-       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
-
-       intel_dsi_add_properties(intel_connector);
-
-       return;
-
-err_cleanup_connector:
-       drm_connector_cleanup(&intel_connector->base);
-err:
-       drm_encoder_cleanup(&intel_encoder->base);
-       kfree(intel_dsi);
-       kfree(intel_connector);
-}
diff --git a/drivers/gpu/drm/i915/vlv_dsi_pll.c b/drivers/gpu/drm/i915/vlv_dsi_pll.c
deleted file mode 100644 (file)
index 99cc3e2..0000000
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     Shobhit Kumar <shobhit.kumar@intel.com>
- *     Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com>
- */
-
-#include <linux/kernel.h>
-
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_sideband.h"
-
-static const u16 lfsr_converts[] = {
-       426, 469, 234, 373, 442, 221, 110, 311, 411,            /* 62 - 70 */
-       461, 486, 243, 377, 188, 350, 175, 343, 427, 213,       /* 71 - 80 */
-       106, 53, 282, 397, 454, 227, 113, 56, 284, 142,         /* 81 - 90 */
-       71, 35, 273, 136, 324, 418, 465, 488, 500, 506          /* 91 - 100 */
-};
-
-/* Get DSI clock from pixel clock */
-static u32 dsi_clk_from_pclk(u32 pclk, enum mipi_dsi_pixel_format fmt,
-                            int lane_count)
-{
-       u32 dsi_clk_khz;
-       u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt);
-
-       /* DSI data rate = pixel clock * bits per pixel / lane count
-          pixel clock is converted from KHz to Hz */
-       dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count);
-
-       return dsi_clk_khz;
-}
-
-static int dsi_calc_mnp(struct drm_i915_private *dev_priv,
-                       struct intel_crtc_state *config,
-                       int target_dsi_clk)
-{
-       unsigned int m_min, m_max, p_min = 2, p_max = 6;
-       unsigned int m, n, p;
-       unsigned int calc_m, calc_p;
-       int delta, ref_clk;
-
-       /* target_dsi_clk is expected in kHz */
-       if (target_dsi_clk < 300000 || target_dsi_clk > 1150000) {
-               DRM_ERROR("DSI CLK Out of Range\n");
-               return -ECHRNG;
-       }
-
-       if (IS_CHERRYVIEW(dev_priv)) {
-               ref_clk = 100000;
-               n = 4;
-               m_min = 70;
-               m_max = 96;
-       } else {
-               ref_clk = 25000;
-               n = 1;
-               m_min = 62;
-               m_max = 92;
-       }
-
-       calc_p = p_min;
-       calc_m = m_min;
-       delta = abs(target_dsi_clk - (m_min * ref_clk) / (p_min * n));
-
-       for (m = m_min; m <= m_max && delta; m++) {
-               for (p = p_min; p <= p_max && delta; p++) {
-                       /*
-                        * Find the optimal m and p divisors with minimal delta
-                        * +/- the required clock
-                        */
-                       int calc_dsi_clk = (m * ref_clk) / (p * n);
-                       int d = abs(target_dsi_clk - calc_dsi_clk);
-                       if (d < delta) {
-                               delta = d;
-                               calc_m = m;
-                               calc_p = p;
-                       }
-               }
-       }
-
-       /* register has log2(N1), this works fine for powers of two */
-       config->dsi_pll.ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2);
-       config->dsi_pll.div =
-               (ffs(n) - 1) << DSI_PLL_N1_DIV_SHIFT |
-               (u32)lfsr_converts[calc_m - 62] << DSI_PLL_M1_DIV_SHIFT;
-
-       return 0;
-}
-
-/*
- * XXX: The muxing and gating is hard coded for now. Need to add support for
- * sharing PLLs with two DSI outputs.
- */
-int vlv_dsi_pll_compute(struct intel_encoder *encoder,
-                       struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       int ret;
-       u32 dsi_clk;
-
-       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
-                                   intel_dsi->lane_count);
-
-       ret = dsi_calc_mnp(dev_priv, config, dsi_clk);
-       if (ret) {
-               DRM_DEBUG_KMS("dsi_calc_mnp failed\n");
-               return ret;
-       }
-
-       if (intel_dsi->ports & (1 << PORT_A))
-               config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
-
-       if (intel_dsi->ports & (1 << PORT_C))
-               config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
-
-       config->dsi_pll.ctrl |= DSI_PLL_VCO_EN;
-
-       DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
-                     config->dsi_pll.div, config->dsi_pll.ctrl);
-
-       return 0;
-}
-
-void vlv_dsi_pll_enable(struct intel_encoder *encoder,
-                       const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       DRM_DEBUG_KMS("\n");
-
-       vlv_cck_get(dev_priv);
-
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0);
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div);
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL,
-                     config->dsi_pll.ctrl & ~DSI_PLL_VCO_EN);
-
-       /* wait at least 0.5 us after ungating before enabling VCO,
-        * allow hrtimer subsystem optimization by relaxing timing
-        */
-       usleep_range(10, 50);
-
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl);
-
-       if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
-                                               DSI_PLL_LOCK, 20)) {
-
-               vlv_cck_put(dev_priv);
-               DRM_ERROR("DSI PLL lock failed\n");
-               return;
-       }
-       vlv_cck_put(dev_priv);
-
-       DRM_DEBUG_KMS("DSI PLL locked\n");
-}
-
-void vlv_dsi_pll_disable(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 tmp;
-
-       DRM_DEBUG_KMS("\n");
-
-       vlv_cck_get(dev_priv);
-
-       tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
-       tmp &= ~DSI_PLL_VCO_EN;
-       tmp |= DSI_PLL_LDO_GATE;
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
-
-       vlv_cck_put(dev_priv);
-}
-
-bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
-{
-       bool enabled;
-       u32 val;
-       u32 mask;
-
-       mask = BXT_DSI_PLL_DO_ENABLE | BXT_DSI_PLL_LOCKED;
-       val = I915_READ(BXT_DSI_PLL_ENABLE);
-       enabled = (val & mask) == mask;
-
-       if (!enabled)
-               return false;
-
-       /*
-        * Dividers must be programmed with valid values. As per BSEPC, for
-        * GEMINLAKE only PORT A divider values are checked while for BXT
-        * both divider values are validated. Check this here for
-        * paranoia, since BIOS is known to misconfigure PLLs in this way at
-        * times, and since accessing DSI registers with invalid dividers
-        * causes a system hang.
-        */
-       val = I915_READ(BXT_DSI_PLL_CTL);
-       if (IS_GEMINILAKE(dev_priv)) {
-               if (!(val & BXT_DSIA_16X_MASK)) {
-                       DRM_DEBUG_DRIVER("Invalid PLL divider (%08x)\n", val);
-                       enabled = false;
-               }
-       } else {
-               if (!(val & BXT_DSIA_16X_MASK) || !(val & BXT_DSIC_16X_MASK)) {
-                       DRM_DEBUG_DRIVER("Invalid PLL divider (%08x)\n", val);
-                       enabled = false;
-               }
-       }
-
-       return enabled;
-}
-
-void bxt_dsi_pll_disable(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       val = I915_READ(BXT_DSI_PLL_ENABLE);
-       val &= ~BXT_DSI_PLL_DO_ENABLE;
-       I915_WRITE(BXT_DSI_PLL_ENABLE, val);
-
-       /*
-        * PLL lock should deassert within 200us.
-        * Wait up to 1ms before timing out.
-        */
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   BXT_DSI_PLL_ENABLE,
-                                   BXT_DSI_PLL_LOCKED,
-                                   0,
-                                   1))
-               DRM_ERROR("Timeout waiting for PLL lock deassertion\n");
-}
-
-u32 vlv_dsi_get_pclk(struct intel_encoder *encoder,
-                    struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-       u32 dsi_clock, pclk;
-       u32 pll_ctl, pll_div;
-       u32 m = 0, p = 0, n;
-       int refclk = IS_CHERRYVIEW(dev_priv) ? 100000 : 25000;
-       int i;
-
-       DRM_DEBUG_KMS("\n");
-
-       vlv_cck_get(dev_priv);
-       pll_ctl = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
-       pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER);
-       vlv_cck_put(dev_priv);
-
-       config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK;
-       config->dsi_pll.div = pll_div;
-
-       /* mask out other bits and extract the P1 divisor */
-       pll_ctl &= DSI_PLL_P1_POST_DIV_MASK;
-       pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2);
-
-       /* N1 divisor */
-       n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT;
-       n = 1 << n; /* register has log2(N1) */
-
-       /* mask out the other bits and extract the M1 divisor */
-       pll_div &= DSI_PLL_M1_DIV_MASK;
-       pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT;
-
-       while (pll_ctl) {
-               pll_ctl = pll_ctl >> 1;
-               p++;
-       }
-       p--;
-
-       if (!p) {
-               DRM_ERROR("wrong P1 divisor\n");
-               return 0;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) {
-               if (lfsr_converts[i] == pll_div)
-                       break;
-       }
-
-       if (i == ARRAY_SIZE(lfsr_converts)) {
-               DRM_ERROR("wrong m_seed programmed\n");
-               return 0;
-       }
-
-       m = i + 62;
-
-       dsi_clock = (m * refclk) / (p * n);
-
-       pclk = DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, bpp);
-
-       return pclk;
-}
-
-u32 bxt_dsi_get_pclk(struct intel_encoder *encoder,
-                    struct intel_crtc_state *config)
-{
-       u32 pclk;
-       u32 dsi_clk;
-       u32 dsi_ratio;
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-
-       config->dsi_pll.ctrl = I915_READ(BXT_DSI_PLL_CTL);
-
-       dsi_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
-
-       dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2;
-
-       pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, bpp);
-
-       DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk);
-       return pclk;
-}
-
-void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
-{
-       u32 temp;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       temp = I915_READ(MIPI_CTRL(port));
-       temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
-       I915_WRITE(MIPI_CTRL(port), temp |
-                       intel_dsi->escape_clk_div <<
-                       ESCAPE_CLOCK_DIVIDER_SHIFT);
-}
-
-static void glk_dsi_program_esc_clock(struct drm_device *dev,
-                                  const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 dsi_rate = 0;
-       u32 pll_ratio = 0;
-       u32 ddr_clk = 0;
-       u32 div1_value = 0;
-       u32 div2_value = 0;
-       u32 txesc1_div = 0;
-       u32 txesc2_div = 0;
-
-       pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
-
-       dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
-
-       ddr_clk = dsi_rate / 2;
-
-       /* Variable divider value */
-       div1_value = DIV_ROUND_CLOSEST(ddr_clk, 20000);
-
-       /* Calculate TXESC1 divider */
-       if (div1_value <= 10)
-               txesc1_div = div1_value;
-       else if ((div1_value > 10) && (div1_value <= 20))
-               txesc1_div = DIV_ROUND_UP(div1_value, 2);
-       else if ((div1_value > 20) && (div1_value <= 30))
-               txesc1_div = DIV_ROUND_UP(div1_value, 4);
-       else if ((div1_value > 30) && (div1_value <= 40))
-               txesc1_div = DIV_ROUND_UP(div1_value, 6);
-       else if ((div1_value > 40) && (div1_value <= 50))
-               txesc1_div = DIV_ROUND_UP(div1_value, 8);
-       else
-               txesc1_div = 10;
-
-       /* Calculate TXESC2 divider */
-       div2_value = DIV_ROUND_UP(div1_value, txesc1_div);
-
-       if (div2_value < 10)
-               txesc2_div = div2_value;
-       else
-               txesc2_div = 10;
-
-       I915_WRITE(MIPIO_TXESC_CLK_DIV1, txesc1_div & GLK_TX_ESC_CLK_DIV1_MASK);
-       I915_WRITE(MIPIO_TXESC_CLK_DIV2, txesc2_div & GLK_TX_ESC_CLK_DIV2_MASK);
-}
-
-/* Program BXT Mipi clocks and dividers */
-static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port,
-                                  const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 tmp;
-       u32 dsi_rate = 0;
-       u32 pll_ratio = 0;
-       u32 rx_div;
-       u32 tx_div;
-       u32 rx_div_upper;
-       u32 rx_div_lower;
-       u32 mipi_8by3_divider;
-
-       /* Clear old configurations */
-       tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
-       tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
-       tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port));
-       tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port));
-       tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port));
-
-       /* Get the current DSI rate(actual) */
-       pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
-       dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
-
-       /*
-        * tx clock should be <= 20MHz and the div value must be
-        * subtracted by 1 as per bspec
-        */
-       tx_div = DIV_ROUND_UP(dsi_rate, 20000) - 1;
-       /*
-        * rx clock should be <= 150MHz and the div value must be
-        * subtracted by 1 as per bspec
-        */
-       rx_div = DIV_ROUND_UP(dsi_rate, 150000) - 1;
-
-       /*
-        * rx divider value needs to be updated in the
-        * two differnt bit fields in the register hence splitting the
-        * rx divider value accordingly
-        */
-       rx_div_lower = rx_div & RX_DIVIDER_BIT_1_2;
-       rx_div_upper = (rx_div & RX_DIVIDER_BIT_3_4) >> 2;
-
-       mipi_8by3_divider = 0x2;
-
-       tmp |= BXT_MIPI_8X_BY3_DIVIDER(port, mipi_8by3_divider);
-       tmp |= BXT_MIPI_TX_ESCLK_DIVIDER(port, tx_div);
-       tmp |= BXT_MIPI_RX_ESCLK_LOWER_DIVIDER(port, rx_div_lower);
-       tmp |= BXT_MIPI_RX_ESCLK_UPPER_DIVIDER(port, rx_div_upper);
-
-       I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
-}
-
-int bxt_dsi_pll_compute(struct intel_encoder *encoder,
-                       struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u8 dsi_ratio, dsi_ratio_min, dsi_ratio_max;
-       u32 dsi_clk;
-
-       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
-                                   intel_dsi->lane_count);
-
-       /*
-        * From clock diagram, to get PLL ratio divider, divide double of DSI
-        * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to
-        * round 'up' the result
-        */
-       dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ);
-
-       if (IS_BROXTON(dev_priv)) {
-               dsi_ratio_min = BXT_DSI_PLL_RATIO_MIN;
-               dsi_ratio_max = BXT_DSI_PLL_RATIO_MAX;
-       } else {
-               dsi_ratio_min = GLK_DSI_PLL_RATIO_MIN;
-               dsi_ratio_max = GLK_DSI_PLL_RATIO_MAX;
-       }
-
-       if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) {
-               DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n");
-               return -ECHRNG;
-       } else
-               DRM_DEBUG_KMS("DSI PLL calculation is Done!!\n");
-
-       /*
-        * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x
-        * Spec says both have to be programmed, even if one is not getting
-        * used. Configure MIPI_CLOCK_CTL dividers in modeset
-        */
-       config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2;
-
-       /* As per recommendation from hardware team,
-        * Prog PVD ratio =1 if dsi ratio <= 50
-        */
-       if (IS_BROXTON(dev_priv) && dsi_ratio <= 50)
-               config->dsi_pll.ctrl |= BXT_DSI_PLL_PVD_RATIO_1;
-
-       return 0;
-}
-
-void bxt_dsi_pll_enable(struct intel_encoder *encoder,
-                       const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* Configure PLL vales */
-       I915_WRITE(BXT_DSI_PLL_CTL, config->dsi_pll.ctrl);
-       POSTING_READ(BXT_DSI_PLL_CTL);
-
-       /* Program TX, RX, Dphy clocks */
-       if (IS_BROXTON(dev_priv)) {
-               for_each_dsi_port(port, intel_dsi->ports)
-                       bxt_dsi_program_clocks(encoder->base.dev, port, config);
-       } else {
-               glk_dsi_program_esc_clock(encoder->base.dev, config);
-       }
-
-       /* Enable DSI PLL */
-       val = I915_READ(BXT_DSI_PLL_ENABLE);
-       val |= BXT_DSI_PLL_DO_ENABLE;
-       I915_WRITE(BXT_DSI_PLL_ENABLE, val);
-
-       /* Timeout and fail if PLL not locked */
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   BXT_DSI_PLL_ENABLE,
-                                   BXT_DSI_PLL_LOCKED,
-                                   BXT_DSI_PLL_LOCKED,
-                                   1)) {
-               DRM_ERROR("Timed out waiting for DSI PLL to lock\n");
-               return;
-       }
-
-       DRM_DEBUG_KMS("DSI PLL locked\n");
-}
-
-void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
-{
-       u32 tmp;
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       /* Clear old configurations */
-       if (IS_BROXTON(dev_priv)) {
-               tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
-               tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
-               tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port));
-               tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port));
-               tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port));
-               I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
-       } else {
-               tmp = I915_READ(MIPIO_TXESC_CLK_DIV1);
-               tmp &= ~GLK_TX_ESC_CLK_DIV1_MASK;
-               I915_WRITE(MIPIO_TXESC_CLK_DIV1, tmp);
-
-               tmp = I915_READ(MIPIO_TXESC_CLK_DIV2);
-               tmp &= ~GLK_TX_ESC_CLK_DIV2_MASK;
-               I915_WRITE(MIPIO_TXESC_CLK_DIV2, tmp);
-       }
-       I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
-}