Merge tag 'drm-intel-next-2023-03-23' of git://anongit.freedesktop.org/drm/drm-intel...
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 24 Mar 2023 19:22:02 +0000 (20:22 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 24 Mar 2023 19:22:03 +0000 (20:22 +0100)
Core Changes:
- drm: Add SDP Error Detection Configuration Register (Arun)

Driver Changes:
- Meteor Lake enabling and fixes (RK, Jose, Madhumitha)
- Lock the fbdev obj before vma pin (Tejas)
- DSC fixes (Stanislav)
- Fixes and clean-up on opregion code (Imre)
- More wm/vblank stuff (Ville)
- More general display code organization (Jani)
- DP Fixes (Stanislav, Ville)
- Introduce flags to ignore long HPD and link training issues \
  for handling spurious issues on CI (Vinod)
- Plane cleanups and extra registers (Ville)
- Update audio keepalive clock values (Clint)
- Rename find_section to bdb_find_section (Maarten)
- DP SDP CRC16 for 128b132b link layer (Arun)
- Fix various issues with noarm register writes (Ville)
- Fix a few TypeC / MST issues (Imre)
- Create GSC submission targeting HDCP and PXP usages on MTL+ (Suraj)
- Enable HDCP2.x via GSC CS (Suraj)

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/ZBy56qc9C00tCLOY@intel.com
58 files changed:
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/hsw_ips.c
drivers/gpu/drm/i915/display/hsw_ips.h
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_atomic_plane.c
drivers/gpu/drm/i915/display/intel_atomic_plane.h
drivers/gpu/drm/i915/display/intel_audio.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_color.c
drivers/gpu/drm/i915/display/intel_color.h
drivers/gpu/drm/i915/display/intel_crtc.c
drivers/gpu/drm/i915/display/intel_cursor.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_ddi.h
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display.h
drivers/gpu/drm/i915/display/intel_display_core.h
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_display_debugfs.h
drivers/gpu/drm/i915/display/intel_display_power.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dmc.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp_aux.c
drivers/gpu/drm/i915/display/intel_dp_link_training.c
drivers/gpu/drm/i915/display/intel_dp_link_training.h
drivers/gpu/drm/i915/display/intel_fbdev.c
drivers/gpu/drm/i915/display/intel_fdi.c
drivers/gpu/drm/i915/display/intel_hdcp.c
drivers/gpu/drm/i915/display/intel_hdcp_gsc.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_hdcp_gsc.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_hotplug.c
drivers/gpu/drm/i915/display/intel_modeset_setup.c
drivers/gpu/drm/i915/display/intel_opregion.c
drivers/gpu/drm/i915/display/intel_opregion.h
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_psr.h
drivers/gpu/drm/i915/display/intel_sprite.c
drivers/gpu/drm/i915/display/intel_sprite_uapi.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_sprite_uapi.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_tc.c
drivers/gpu/drm/i915/display/intel_tc.h
drivers/gpu/drm/i915/display/intel_vblank.c
drivers/gpu/drm/i915/display/intel_vblank.h
drivers/gpu/drm/i915/display/skl_universal_plane.c
drivers/gpu/drm/i915/display/skl_watermark.c
drivers/gpu/drm/i915/display/vlv_dsi.c
drivers/gpu/drm/i915/gt/intel_gpu_commands.h
drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c [new file with mode: 0644]
drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_driver.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_gvt_mmio_table.c
drivers/misc/mei/hdcp/mei_hdcp.c
drivers/misc/mei/hdcp/mei_hdcp.h
include/drm/display/drm_dp.h
include/drm/i915_hdcp_interface.h [new file with mode: 0644]
include/drm/i915_mei_hdcp_interface.h [deleted file]

index 8e46f57e4569a5418122807e43c18b54bda222e6..057ef22fa9c6f99a2b7e39de0c728e039f9712b1 100644 (file)
@@ -195,6 +195,7 @@ i915-y += \
 i915-y += \
          gt/uc/intel_gsc_fw.o \
          gt/uc/intel_gsc_uc.o \
+         gt/uc/intel_gsc_uc_heci_cmd_submit.o\
          gt/uc/intel_guc.o \
          gt/uc/intel_guc_ads.o \
          gt/uc/intel_guc_capture.o \
@@ -255,6 +256,7 @@ i915-y += \
        display/intel_frontbuffer.o \
        display/intel_global_state.o \
        display/intel_hdcp.o \
+       display/intel_hdcp_gsc.o \
        display/intel_hotplug.o \
        display/intel_hti.o \
        display/intel_lpe_audio.o \
@@ -267,6 +269,7 @@ i915-y += \
        display/intel_psr.o \
        display/intel_quirks.o \
        display/intel_sprite.o \
+       display/intel_sprite_uapi.o \
        display/intel_tc.o \
        display/intel_vblank.o \
        display/intel_vga.o \
index 83aa3800245f9b2fa3add9aac683d63bf2eb5497..2910f5d0f3e2b6f1cc29bc04206864669f7ef879 100644 (file)
@@ -267,3 +267,40 @@ void hsw_ips_get_config(struct intel_crtc_state *crtc_state)
                crtc_state->ips_enabled = true;
        }
 }
+
+static int hsw_ips_debugfs_status_show(struct seq_file *m, void *unused)
+{
+       struct drm_i915_private *i915 = m->private;
+       intel_wakeref_t wakeref;
+
+       if (!HAS_IPS(i915))
+               return -ENODEV;
+
+       wakeref = intel_runtime_pm_get(&i915->runtime_pm);
+
+       seq_printf(m, "Enabled by kernel parameter: %s\n",
+                  str_yes_no(i915->params.enable_ips));
+
+       if (DISPLAY_VER(i915) >= 8) {
+               seq_puts(m, "Currently: unknown\n");
+       } else {
+               if (intel_de_read(i915, IPS_CTL) & IPS_ENABLE)
+                       seq_puts(m, "Currently: enabled\n");
+               else
+                       seq_puts(m, "Currently: disabled\n");
+       }
+
+       intel_runtime_pm_put(&i915->runtime_pm, wakeref);
+
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(hsw_ips_debugfs_status);
+
+void hsw_ips_debugfs_register(struct drm_i915_private *i915)
+{
+       struct drm_minor *minor = i915->drm.primary;
+
+       debugfs_create_file("i915_ips_status", 0444, minor->debugfs_root,
+                           i915, &hsw_ips_debugfs_status_fops);
+}
index 4564dee497d757cf0e0a38482f03b1694858c85e..7ed6061874f73def4fdae1778ca1f78a51a6dfbd 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 
+struct drm_i915_private;
 struct intel_atomic_state;
 struct intel_crtc;
 struct intel_crtc_state;
@@ -22,5 +23,6 @@ bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state);
 int hsw_ips_compute_config(struct intel_atomic_state *state,
                           struct intel_crtc *crtc);
 void hsw_ips_get_config(struct intel_crtc_state *crtc_state);
+void hsw_ips_debugfs_register(struct drm_i915_private *i915);
 
 #endif /* __HSW_IPS_H__ */
index 50dcaa8958546119cbd1443c0220ea16936f6618..4ff10b00ffbdb53dc464945aedb12c0aa73e6cfe 100644 (file)
@@ -1500,7 +1500,7 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
 
        gen11_dsi_get_timings(encoder, pipe_config);
        pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
-       pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
+       pipe_config->pipe_bpp = bdw_get_pipe_misc_bpp(crtc);
 
        /* Get the details on which TE should be enabled */
        if (is_cmd_mode(intel_dsi))
index 719a60e278f39c326a43bbba5d37a08e19dcd4e3..40de9f0f171b479b6623e2a4197c2a75f08961f6 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
 #include <drm/drm_fourcc.h>
 
 #include "i915_config.h"
@@ -42,7 +43,6 @@
 #include "intel_display_types.h"
 #include "intel_fb.h"
 #include "intel_fb_pin.h"
-#include "intel_sprite.h"
 #include "skl_scaler.h"
 #include "skl_watermark.h"
 
@@ -940,6 +940,64 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
        return 0;
 }
 
+int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
+{
+       struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+       const struct drm_framebuffer *fb = plane_state->hw.fb;
+       struct drm_rect *src = &plane_state->uapi.src;
+       u32 src_x, src_y, src_w, src_h, hsub, vsub;
+       bool rotated = drm_rotation_90_or_270(plane_state->hw.rotation);
+
+       /*
+        * FIXME hsub/vsub vs. block size is a mess. Pre-tgl CCS
+        * abuses hsub/vsub so we can't use them here. But as they
+        * are limited to 32bpp RGB formats we don't actually need
+        * to check anything.
+        */
+       if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+           fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS)
+               return 0;
+
+       /*
+        * Hardware doesn't handle subpixel coordinates.
+        * Adjust to (macro)pixel boundary, but be careful not to
+        * increase the source viewport size, because that could
+        * push the downscaling factor out of bounds.
+        */
+       src_x = src->x1 >> 16;
+       src_w = drm_rect_width(src) >> 16;
+       src_y = src->y1 >> 16;
+       src_h = drm_rect_height(src) >> 16;
+
+       drm_rect_init(src, src_x << 16, src_y << 16,
+                     src_w << 16, src_h << 16);
+
+       if (fb->format->format == DRM_FORMAT_RGB565 && rotated) {
+               hsub = 2;
+               vsub = 2;
+       } else {
+               hsub = fb->format->hsub;
+               vsub = fb->format->vsub;
+       }
+
+       if (rotated)
+               hsub = vsub = max(hsub, vsub);
+
+       if (src_x % hsub || src_w % hsub) {
+               drm_dbg_kms(&i915->drm, "src x/w (%u, %u) must be a multiple of %u (rotated: %s)\n",
+                           src_x, src_w, hsub, str_yes_no(rotated));
+               return -EINVAL;
+       }
+
+       if (src_y % vsub || src_h % vsub) {
+               drm_dbg_kms(&i915->drm, "src y/h (%u, %u) must be a multiple of %u (rotated: %s)\n",
+                           src_y, src_h, vsub, str_yes_no(rotated));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @_plane: drm plane to prepare for
index 74b6d3b169a72d8faa9dc60a428750b0b46a3107..191dad0efc8e6223d7e1700b598d64b050674ef7 100644 (file)
@@ -62,6 +62,7 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
                                      struct intel_crtc_state *crtc_state,
                                      int min_scale, int max_scale,
                                      bool can_position);
+int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);
 void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
                               struct intel_plane_state *plane_state);
 void intel_plane_helper_add(struct intel_plane *plane);
index 65151f5dcb151604958e9ff598d00c14abbb3092..3d5a9bbc6fde370fcb40a73b72a55766d677716c 100644 (file)
@@ -983,11 +983,7 @@ void intel_audio_cdclk_change_pre(struct drm_i915_private *i915)
 
 static void get_aud_ts_cdclk_m_n(int refclk, int cdclk, struct aud_ts_cdclk_m_n *aud_ts)
 {
-       if (refclk == 24000)
-               aud_ts->m = 12;
-       else
-               aud_ts->m = 15;
-
+       aud_ts->m = 60;
        aud_ts->n = cdclk * aud_ts->m / 24000;
 }
 
index e54febd34ca9d8ce5b799dde0ec3a4bfaa0b53f0..75e69dffc5e90ace3397a3c4b0e78b1168e2c89a 100644 (file)
@@ -141,8 +141,8 @@ struct bdb_block_entry {
 };
 
 static const void *
-find_section(struct drm_i915_private *i915,
-            enum bdb_block_id section_id)
+bdb_find_section(struct drm_i915_private *i915,
+                enum bdb_block_id section_id)
 {
        struct bdb_block_entry *entry;
 
@@ -201,7 +201,7 @@ static size_t lfp_data_min_size(struct drm_i915_private *i915)
        const struct bdb_lvds_lfp_data_ptrs *ptrs;
        size_t size;
 
-       ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
+       ptrs = bdb_find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
        if (!ptrs)
                return 0;
 
@@ -630,7 +630,7 @@ static int vbt_get_panel_type(struct drm_i915_private *i915,
 {
        const struct bdb_lvds_options *lvds_options;
 
-       lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
+       lvds_options = bdb_find_section(i915, BDB_LVDS_OPTIONS);
        if (!lvds_options)
                return -1;
 
@@ -671,11 +671,11 @@ static int pnpid_get_panel_type(struct drm_i915_private *i915,
 
        dump_pnp_id(i915, edid_id, "EDID");
 
-       ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
+       ptrs = bdb_find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
        if (!ptrs)
                return -1;
 
-       data = find_section(i915, BDB_LVDS_LFP_DATA);
+       data = bdb_find_section(i915, BDB_LVDS_LFP_DATA);
        if (!data)
                return -1;
 
@@ -791,7 +791,7 @@ parse_panel_options(struct drm_i915_private *i915,
        int panel_type = panel->vbt.panel_type;
        int drrs_mode;
 
-       lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
+       lvds_options = bdb_find_section(i915, BDB_LVDS_OPTIONS);
        if (!lvds_options)
                return;
 
@@ -881,11 +881,11 @@ parse_lfp_data(struct drm_i915_private *i915,
        const struct lvds_pnp_id *pnp_id;
        int panel_type = panel->vbt.panel_type;
 
-       ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
+       ptrs = bdb_find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
        if (!ptrs)
                return;
 
-       data = find_section(i915, BDB_LVDS_LFP_DATA);
+       data = bdb_find_section(i915, BDB_LVDS_LFP_DATA);
        if (!data)
                return;
 
@@ -932,7 +932,7 @@ parse_generic_dtd(struct drm_i915_private *i915,
        if (i915->display.vbt.version < 229)
                return;
 
-       generic_dtd = find_section(i915, BDB_GENERIC_DTD);
+       generic_dtd = bdb_find_section(i915, BDB_GENERIC_DTD);
        if (!generic_dtd)
                return;
 
@@ -1011,7 +1011,7 @@ parse_lfp_backlight(struct drm_i915_private *i915,
        int panel_type = panel->vbt.panel_type;
        u16 level;
 
-       backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT);
+       backlight_data = bdb_find_section(i915, BDB_LVDS_BACKLIGHT);
        if (!backlight_data)
                return;
 
@@ -1119,14 +1119,14 @@ parse_sdvo_panel_data(struct drm_i915_private *i915,
        if (index == -1) {
                const struct bdb_sdvo_lvds_options *sdvo_lvds_options;
 
-               sdvo_lvds_options = find_section(i915, BDB_SDVO_LVDS_OPTIONS);
+               sdvo_lvds_options = bdb_find_section(i915, BDB_SDVO_LVDS_OPTIONS);
                if (!sdvo_lvds_options)
                        return;
 
                index = sdvo_lvds_options->panel_type;
        }
 
-       dtds = find_section(i915, BDB_SDVO_PANEL_DTDS);
+       dtds = bdb_find_section(i915, BDB_SDVO_PANEL_DTDS);
        if (!dtds)
                return;
 
@@ -1162,7 +1162,7 @@ parse_general_features(struct drm_i915_private *i915)
 {
        const struct bdb_general_features *general;
 
-       general = find_section(i915, BDB_GENERAL_FEATURES);
+       general = bdb_find_section(i915, BDB_GENERAL_FEATURES);
        if (!general)
                return;
 
@@ -1285,7 +1285,7 @@ parse_driver_features(struct drm_i915_private *i915)
 {
        const struct bdb_driver_features *driver;
 
-       driver = find_section(i915, BDB_DRIVER_FEATURES);
+       driver = bdb_find_section(i915, BDB_DRIVER_FEATURES);
        if (!driver)
                return;
 
@@ -1322,7 +1322,7 @@ parse_panel_driver_features(struct drm_i915_private *i915,
 {
        const struct bdb_driver_features *driver;
 
-       driver = find_section(i915, BDB_DRIVER_FEATURES);
+       driver = bdb_find_section(i915, BDB_DRIVER_FEATURES);
        if (!driver)
                return;
 
@@ -1362,7 +1362,7 @@ parse_power_conservation_features(struct drm_i915_private *i915,
        if (i915->display.vbt.version < 228)
                return;
 
-       power = find_section(i915, BDB_LFP_POWER);
+       power = bdb_find_section(i915, BDB_LFP_POWER);
        if (!power)
                return;
 
@@ -1402,7 +1402,7 @@ parse_edp(struct drm_i915_private *i915,
        const struct edp_fast_link_params *edp_link_params;
        int panel_type = panel->vbt.panel_type;
 
-       edp = find_section(i915, BDB_EDP);
+       edp = bdb_find_section(i915, BDB_EDP);
        if (!edp)
                return;
 
@@ -1532,7 +1532,7 @@ parse_psr(struct drm_i915_private *i915,
        const struct psr_table *psr_table;
        int panel_type = panel->vbt.panel_type;
 
-       psr = find_section(i915, BDB_PSR);
+       psr = bdb_find_section(i915, BDB_PSR);
        if (!psr) {
                drm_dbg_kms(&i915->drm, "No PSR BDB found.\n");
                return;
@@ -1693,7 +1693,7 @@ parse_mipi_config(struct drm_i915_private *i915,
        /* Parse #52 for panel index used from panel_type already
         * parsed
         */
-       start = find_section(i915, BDB_MIPI_CONFIG);
+       start = bdb_find_section(i915, BDB_MIPI_CONFIG);
        if (!start) {
                drm_dbg_kms(&i915->drm, "No MIPI config BDB found");
                return;
@@ -2005,7 +2005,7 @@ parse_mipi_sequence(struct drm_i915_private *i915,
        if (panel->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID)
                return;
 
-       sequence = find_section(i915, BDB_MIPI_SEQUENCE);
+       sequence = bdb_find_section(i915, BDB_MIPI_SEQUENCE);
        if (!sequence) {
                drm_dbg_kms(&i915->drm,
                            "No MIPI Sequence found, parsing complete\n");
@@ -2086,7 +2086,7 @@ parse_compression_parameters(struct drm_i915_private *i915)
        if (i915->display.vbt.version < 198)
                return;
 
-       params = find_section(i915, BDB_COMPRESSION_PARAMETERS);
+       params = bdb_find_section(i915, BDB_COMPRESSION_PARAMETERS);
        if (params) {
                /* Sanity checks */
                if (params->entry_size != sizeof(params->data[0])) {
@@ -2792,7 +2792,7 @@ parse_general_definitions(struct drm_i915_private *i915)
        u16 block_size;
        int bus_pin;
 
-       defs = find_section(i915, BDB_GENERAL_DEFINITIONS);
+       defs = bdb_find_section(i915, BDB_GENERAL_DEFINITIONS);
        if (!defs) {
                drm_dbg_kms(&i915->drm,
                            "No general definition block is found, no devices defined.\n");
index a6dd0859823315126ceff7db4696472b7dba62c3..36aac88143ac1936fe469d7424841d3606729a66 100644 (file)
@@ -46,6 +46,11 @@ struct intel_color_funcs {
         * registers involved with the same commit.
         */
        void (*color_commit_arm)(const struct intel_crtc_state *crtc_state);
+       /*
+        * Perform any extra tasks needed after all the
+        * double buffered registers have been latched.
+        */
+       void (*color_post_update)(const struct intel_crtc_state *crtc_state);
        /*
         * Load LUTs (and other single buffered color management
         * registers). Will (hopefully) be called during the vblank
@@ -614,9 +619,33 @@ static void ilk_lut_12p4_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
 
 static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state)
 {
+       /*
+        * Despite Wa_1406463849, ICL no longer suffers from the SKL
+        * DC5/PSR CSC black screen issue (see skl_color_commit_noarm()).
+        * Possibly due to the extra sticky CSC arming
+        * (see icl_color_post_update()).
+        *
+        * On TGL+ all CSC arming issues have been properly fixed.
+        */
        icl_load_csc_matrix(crtc_state);
 }
 
+static void skl_color_commit_noarm(const struct intel_crtc_state *crtc_state)
+{
+       /*
+        * Possibly related to display WA #1184, SKL CSC loses the latched
+        * CSC coeff/offset register values if the CSC registers are disarmed
+        * between DC5 exit and PSR exit. This will cause the plane(s) to
+        * output all black (until CSC_MODE is rearmed and properly latched).
+        * Once PSR exit (and proper register latching) has occurred the
+        * danger is over. Thus when PSR is enabled the CSC coeff/offset
+        * register programming will be peformed from skl_color_commit_arm()
+        * which is called after PSR exit.
+        */
+       if (!crtc_state->has_psr)
+               ilk_load_csc_matrix(crtc_state);
+}
+
 static void ilk_color_commit_noarm(const struct intel_crtc_state *crtc_state)
 {
        ilk_load_csc_matrix(crtc_state);
@@ -659,6 +688,9 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state)
        enum pipe pipe = crtc->pipe;
        u32 val = 0;
 
+       if (crtc_state->has_psr)
+               ilk_load_csc_matrix(crtc_state);
+
        /*
         * We don't (yet) allow userspace to control the pipe background color,
         * so force it to black, but apply pipe gamma and CSC appropriately
@@ -677,6 +709,47 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state)
                          crtc_state->csc_mode);
 }
 
+static void icl_color_commit_arm(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+
+       /*
+        * We don't (yet) allow userspace to control the pipe background color,
+        * so force it to black.
+        */
+       intel_de_write(i915, SKL_BOTTOM_COLOR(pipe), 0);
+
+       intel_de_write(i915, GAMMA_MODE(crtc->pipe),
+                      crtc_state->gamma_mode);
+
+       intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe),
+                         crtc_state->csc_mode);
+}
+
+static void icl_color_post_update(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+
+       /*
+        * Despite Wa_1406463849, ICL CSC is no longer disarmed by
+        * coeff/offset register *writes*. Instead, once CSC_MODE
+        * is armed it stays armed, even after it has been latched.
+        * Afterwards the coeff/offset registers become effectively
+        * self-arming. That self-arming must be disabled before the
+        * next icl_color_commit_noarm() tries to write the next set
+        * of coeff/offset registers. Fortunately register *reads*
+        * do still disarm the CSC. Naturally this must not be done
+        * until the previously written CSC registers have actually
+        * been latched.
+        *
+        * TGL+ no longer need this workaround.
+        */
+       intel_de_read_fw(i915, PIPE_CSC_PREOFF_HI(crtc->pipe));
+}
+
 static struct drm_property_blob *
 create_linear_lut(struct drm_i915_private *i915, int lut_size)
 {
@@ -1376,6 +1449,14 @@ void intel_color_commit_arm(const struct intel_crtc_state *crtc_state)
        i915->display.funcs.color->color_commit_arm(crtc_state);
 }
 
+void intel_color_post_update(const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+       if (i915->display.funcs.color->color_post_update)
+               i915->display.funcs.color->color_post_update(crtc_state);
+}
+
 void intel_color_prepare_commit(struct intel_crtc_state *crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -3072,10 +3153,20 @@ static const struct intel_color_funcs i9xx_color_funcs = {
        .lut_equal = i9xx_lut_equal,
 };
 
+static const struct intel_color_funcs tgl_color_funcs = {
+       .color_check = icl_color_check,
+       .color_commit_noarm = icl_color_commit_noarm,
+       .color_commit_arm = icl_color_commit_arm,
+       .load_luts = icl_load_luts,
+       .read_luts = icl_read_luts,
+       .lut_equal = icl_lut_equal,
+};
+
 static const struct intel_color_funcs icl_color_funcs = {
        .color_check = icl_color_check,
        .color_commit_noarm = icl_color_commit_noarm,
-       .color_commit_arm = skl_color_commit_arm,
+       .color_commit_arm = icl_color_commit_arm,
+       .color_post_update = icl_color_post_update,
        .load_luts = icl_load_luts,
        .read_luts = icl_read_luts,
        .lut_equal = icl_lut_equal,
@@ -3083,7 +3174,7 @@ static const struct intel_color_funcs icl_color_funcs = {
 
 static const struct intel_color_funcs glk_color_funcs = {
        .color_check = glk_color_check,
-       .color_commit_noarm = ilk_color_commit_noarm,
+       .color_commit_noarm = skl_color_commit_noarm,
        .color_commit_arm = skl_color_commit_arm,
        .load_luts = glk_load_luts,
        .read_luts = glk_read_luts,
@@ -3092,7 +3183,7 @@ static const struct intel_color_funcs glk_color_funcs = {
 
 static const struct intel_color_funcs skl_color_funcs = {
        .color_check = ivb_color_check,
-       .color_commit_noarm = ilk_color_commit_noarm,
+       .color_commit_noarm = skl_color_commit_noarm,
        .color_commit_arm = skl_color_commit_arm,
        .load_luts = bdw_load_luts,
        .read_luts = bdw_read_luts,
@@ -3188,7 +3279,9 @@ void intel_color_init_hooks(struct drm_i915_private *i915)
                else
                        i915->display.funcs.color = &i9xx_color_funcs;
        } else {
-               if (DISPLAY_VER(i915) >= 11)
+               if (DISPLAY_VER(i915) >= 12)
+                       i915->display.funcs.color = &tgl_color_funcs;
+               else if (DISPLAY_VER(i915) == 11)
                        i915->display.funcs.color = &icl_color_funcs;
                else if (DISPLAY_VER(i915) == 10)
                        i915->display.funcs.color = &glk_color_funcs;
index d620b5b1e2a6ebdc68e98d16c65b3ccaa7e84c09..8002492be709096aec9169c4e89483d8ccac112f 100644 (file)
@@ -21,6 +21,7 @@ void intel_color_prepare_commit(struct intel_crtc_state *crtc_state);
 void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state);
 void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state);
 void intel_color_commit_arm(const struct intel_crtc_state *crtc_state);
+void intel_color_post_update(const struct intel_crtc_state *crtc_state);
 void intel_color_load_luts(const struct intel_crtc_state *crtc_state);
 void intel_color_get_config(struct intel_crtc_state *crtc_state);
 bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state,
index b79a8834559f6a426857cf7dcad88c76be460803..ed45a693485480e63c6541f6d492ed5caf7c040c 100644 (file)
@@ -212,7 +212,7 @@ static void intel_crtc_destroy(struct drm_crtc *_crtc)
 
 static int intel_crtc_late_register(struct drm_crtc *crtc)
 {
-       intel_crtc_debugfs_add(crtc);
+       intel_crtc_debugfs_add(to_intel_crtc(crtc));
        return 0;
 }
 
@@ -686,6 +686,14 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
         */
        intel_vrr_send_push(new_crtc_state);
 
+       /*
+        * Seamless M/N update may need to update frame timings.
+        *
+        * FIXME Should be synchronized with the start of vblank somehow...
+        */
+       if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state))
+               intel_crtc_update_active_timings(new_crtc_state);
+
        local_irq_enable();
 
        if (intel_vgpu_active(dev_priv))
index c3173c0c2068756022d12b7412686e99b6eb043f..31bef04273779e0aa9b5811f8e0569227a6c9972 100644 (file)
@@ -21,7 +21,6 @@
 #include "intel_fb_pin.h"
 #include "intel_frontbuffer.h"
 #include "intel_psr.h"
-#include "intel_sprite.h"
 #include "skl_watermark.h"
 
 /* Cursor formats */
index 0950bcfea4c0b3b6bfafa5e7dd75950f4ef0fa13..73240cf78c8bf3b7298c5762b21275bdea93a6c8 100644 (file)
@@ -65,7 +65,6 @@
 #include "intel_psr.h"
 #include "intel_quirks.h"
 #include "intel_snps_phy.h"
-#include "intel_sprite.h"
 #include "intel_tc.h"
 #include "intel_vdsc.h"
 #include "intel_vdsc_regs.h"
@@ -2520,6 +2519,10 @@ static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state,
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 
+       if (HAS_DP20(dev_priv))
+               intel_dp_128b132b_sdp_crc16(enc_to_intel_dp(encoder),
+                                           crtc_state);
+
        if (DISPLAY_VER(dev_priv) >= 12)
                tgl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state);
        else
@@ -2618,8 +2621,7 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,
 
        if (intel_crtc_has_dp_encoder(crtc_state))
                intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state),
-                            DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK,
-                            DP_TP_CTL_LINK_TRAIN_PAT1);
+                            DP_TP_CTL_ENABLE, 0);
 
        /* Disable FEC in DP Sink */
        intel_ddi_disable_fec_state(encoder, crtc_state);
@@ -3140,8 +3142,7 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
                        wait = true;
                }
 
-               dp_tp_ctl &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
-               dp_tp_ctl |= DP_TP_CTL_LINK_TRAIN_PAT1;
+               dp_tp_ctl &= ~DP_TP_CTL_ENABLE;
                intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl);
                intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
 
@@ -3543,6 +3544,37 @@ static void icl_ddi_combo_get_config(struct intel_encoder *encoder,
        intel_ddi_get_config(encoder, crtc_state);
 }
 
+static bool icl_ddi_tc_pll_is_tbt(const struct intel_shared_dpll *pll)
+{
+       return pll->info->id == DPLL_ID_ICL_TBTPLL;
+}
+
+static enum icl_port_dpll_id
+icl_ddi_tc_port_pll_type(struct intel_encoder *encoder,
+                        const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+
+       if (drm_WARN_ON(&i915->drm, !pll))
+               return ICL_PORT_DPLL_DEFAULT;
+
+       if (icl_ddi_tc_pll_is_tbt(pll))
+               return ICL_PORT_DPLL_DEFAULT;
+       else
+               return ICL_PORT_DPLL_MG_PHY;
+}
+
+enum icl_port_dpll_id
+intel_ddi_port_pll_type(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *crtc_state)
+{
+       if (!encoder->port_pll_type)
+               return ICL_PORT_DPLL_DEFAULT;
+
+       return encoder->port_pll_type(encoder, crtc_state);
+}
+
 static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
                                 struct intel_crtc_state *crtc_state,
                                 struct intel_shared_dpll *pll)
@@ -3555,7 +3587,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
        if (drm_WARN_ON(&i915->drm, !pll))
                return;
 
-       if (pll->info->id == DPLL_ID_ICL_TBTPLL)
+       if (icl_ddi_tc_pll_is_tbt(pll))
                port_dpll_id = ICL_PORT_DPLL_DEFAULT;
        else
                port_dpll_id = ICL_PORT_DPLL_MG_PHY;
@@ -3568,7 +3600,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
 
        icl_set_active_port_dpll(crtc_state, port_dpll_id);
 
-       if (crtc_state->shared_dpll->info->id == DPLL_ID_ICL_TBTPLL)
+       if (icl_ddi_tc_pll_is_tbt(crtc_state->shared_dpll))
                crtc_state->port_clock = icl_calc_tbt_pll_link(i915, encoder->port);
        else
                crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll,
@@ -3610,7 +3642,8 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder,
        enum phy phy = intel_port_to_phy(i915, encoder->port);
 
        if (intel_phy_is_tc(i915, phy))
-               intel_tc_port_sanitize_mode(enc_to_dig_port(encoder));
+               intel_tc_port_sanitize_mode(enc_to_dig_port(encoder),
+                                           crtc_state);
 
        if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))
                intel_dp_sync_state(encoder, crtc_state);
@@ -4404,6 +4437,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
                        encoder->enable_clock = jsl_ddi_tc_enable_clock;
                        encoder->disable_clock = jsl_ddi_tc_disable_clock;
                        encoder->is_clock_enabled = jsl_ddi_tc_is_clock_enabled;
+                       encoder->port_pll_type = icl_ddi_tc_port_pll_type;
                        encoder->get_config = icl_ddi_combo_get_config;
                } else {
                        encoder->enable_clock = icl_ddi_combo_enable_clock;
@@ -4416,6 +4450,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
                        encoder->enable_clock = icl_ddi_tc_enable_clock;
                        encoder->disable_clock = icl_ddi_tc_disable_clock;
                        encoder->is_clock_enabled = icl_ddi_tc_is_clock_enabled;
+                       encoder->port_pll_type = icl_ddi_tc_port_pll_type;
                        encoder->get_config = icl_ddi_tc_get_config;
                } else {
                        encoder->enable_clock = icl_ddi_combo_enable_clock;
@@ -4496,6 +4531,16 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
                        !intel_bios_encoder_supports_typec_usb(devdata) &&
                        !intel_bios_encoder_supports_tbt(devdata);
 
+               if (!is_legacy && init_hdmi) {
+                       is_legacy = !init_dp;
+
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "VBT says port %c is non-legacy TC and has HDMI (with DP: %s), assume it's %s\n",
+                                   port_name(port),
+                                   str_yes_no(init_dp),
+                                   is_legacy ? "legacy" : "non-legacy");
+               }
+
                intel_tc_port_init(dig_port, is_legacy);
 
                encoder->update_prepare = intel_ddi_update_prepare;
index 361f6874dde535d3f05ce98641d19da00be46eb5..c85e74ae68e4d1420fffc4284e5e2e02984da6c5 100644 (file)
@@ -40,6 +40,9 @@ void hsw_ddi_enable_clock(struct intel_encoder *encoder,
                          const struct intel_crtc_state *crtc_state);
 void hsw_ddi_disable_clock(struct intel_encoder *encoder);
 bool hsw_ddi_is_clock_enabled(struct intel_encoder *encoder);
+enum icl_port_dpll_id
+intel_ddi_port_pll_type(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *crtc_state);
 void hsw_ddi_get_config(struct intel_encoder *encoder,
                        struct intel_crtc_state *crtc_state);
 struct intel_shared_dpll *icl_ddi_combo_get_pll(struct intel_encoder *encoder);
index edbcb1273ca2880c0cd5dabd9c0ae9cdd37f55c0..5a386c7c0bc92aa1dcc93a1715c30d0a5e06ae5f 100644 (file)
 #include "intel_quirks.h"
 #include "intel_sdvo.h"
 #include "intel_snps_phy.h"
-#include "intel_sprite.h"
 #include "intel_tc.h"
 #include "intel_tv.h"
 #include "intel_vblank.h"
 static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state);
 static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state);
 static void hsw_set_transconf(const struct intel_crtc_state *crtc_state);
-static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state);
+static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state);
 static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
 
 /* returns HPLL frequency in kHz */
@@ -1116,6 +1115,9 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
        if (needs_cursorclk_wa(old_crtc_state) &&
            !needs_cursorclk_wa(new_crtc_state))
                icl_wa_cursorclkgating(dev_priv, pipe, false);
+
+       if (intel_crtc_needs_color_update(new_crtc_state))
+               intel_color_post_update(new_crtc_state);
 }
 
 static void intel_crtc_enable_flip_done(struct intel_atomic_state *state,
@@ -1793,7 +1795,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
 
        intel_set_pipe_src_size(new_crtc_state);
        if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
-               bdw_set_pipemisc(new_crtc_state);
+               bdw_set_pipe_misc(new_crtc_state);
 
        if (!intel_crtc_is_bigjoiner_slave(new_crtc_state) &&
            !transcoder_is_dsi(cpu_transcoder))
@@ -2139,6 +2141,8 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state,
 
        intel_set_pipe_src_size(new_crtc_state);
 
+       intel_de_write(dev_priv, VLV_PIPE_MSA_MISC(pipe), 0);
+
        if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
                intel_de_write(dev_priv, CHV_BLEND(pipe), CHV_BLEND_LEGACY);
                intel_de_write(dev_priv, CHV_CANVAS(pipe), 0);
@@ -3074,20 +3078,20 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
 }
 
 static enum intel_output_format
-bdw_get_pipemisc_output_format(struct intel_crtc *crtc)
+bdw_get_pipe_misc_output_format(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        u32 tmp;
 
-       tmp = intel_de_read(dev_priv, PIPEMISC(crtc->pipe));
+       tmp = intel_de_read(dev_priv, PIPE_MISC(crtc->pipe));
 
-       if (tmp & PIPEMISC_YUV420_ENABLE) {
+       if (tmp & PIPE_MISC_YUV420_ENABLE) {
                /* We support 4:2:0 in full blend mode only */
                drm_WARN_ON(&dev_priv->drm,
-                           (tmp & PIPEMISC_YUV420_MODE_FULL_BLEND) == 0);
+                           (tmp & PIPE_MISC_YUV420_MODE_FULL_BLEND) == 0);
 
                return INTEL_OUTPUT_FORMAT_YCBCR420;
-       } else if (tmp & PIPEMISC_OUTPUT_COLORSPACE_YUV) {
+       } else if (tmp & PIPE_MISC_OUTPUT_COLORSPACE_YUV) {
                return INTEL_OUTPUT_FORMAT_YCBCR444;
        } else {
                return INTEL_OUTPUT_FORMAT_RGB;
@@ -3330,7 +3334,7 @@ static void hsw_set_transconf(const struct intel_crtc_state *crtc_state)
        intel_de_posting_read(dev_priv, TRANSCONF(cpu_transcoder));
 }
 
-static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state)
+static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -3338,18 +3342,18 @@ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state)
 
        switch (crtc_state->pipe_bpp) {
        case 18:
-               val |= PIPEMISC_BPC_6;
+               val |= PIPE_MISC_BPC_6;
                break;
        case 24:
-               val |= PIPEMISC_BPC_8;
+               val |= PIPE_MISC_BPC_8;
                break;
        case 30:
-               val |= PIPEMISC_BPC_10;
+               val |= PIPE_MISC_BPC_10;
                break;
        case 36:
                /* Port output 12BPC defined for ADLP+ */
                if (DISPLAY_VER(dev_priv) > 12)
-                       val |= PIPEMISC_BPC_12_ADLP;
+                       val |= PIPE_MISC_BPC_12_ADLP;
                break;
        default:
                MISSING_CASE(crtc_state->pipe_bpp);
@@ -3357,38 +3361,38 @@ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state)
        }
 
        if (crtc_state->dither)
-               val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
+               val |= PIPE_MISC_DITHER_ENABLE | PIPE_MISC_DITHER_TYPE_SP;
 
        if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
            crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
-               val |= PIPEMISC_OUTPUT_COLORSPACE_YUV;
+               val |= PIPE_MISC_OUTPUT_COLORSPACE_YUV;
 
        if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
-               val |= PIPEMISC_YUV420_ENABLE |
-                       PIPEMISC_YUV420_MODE_FULL_BLEND;
+               val |= PIPE_MISC_YUV420_ENABLE |
+                       PIPE_MISC_YUV420_MODE_FULL_BLEND;
 
        if (DISPLAY_VER(dev_priv) >= 11 && is_hdr_mode(crtc_state))
-               val |= PIPEMISC_HDR_MODE_PRECISION;
+               val |= PIPE_MISC_HDR_MODE_PRECISION;
 
        if (DISPLAY_VER(dev_priv) >= 12)
-               val |= PIPEMISC_PIXEL_ROUNDING_TRUNC;
+               val |= PIPE_MISC_PIXEL_ROUNDING_TRUNC;
 
-       intel_de_write(dev_priv, PIPEMISC(crtc->pipe), val);
+       intel_de_write(dev_priv, PIPE_MISC(crtc->pipe), val);
 }
 
-int bdw_get_pipemisc_bpp(struct intel_crtc *crtc)
+int bdw_get_pipe_misc_bpp(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        u32 tmp;
 
-       tmp = intel_de_read(dev_priv, PIPEMISC(crtc->pipe));
+       tmp = intel_de_read(dev_priv, PIPE_MISC(crtc->pipe));
 
-       switch (tmp & PIPEMISC_BPC_MASK) {
-       case PIPEMISC_BPC_6:
+       switch (tmp & PIPE_MISC_BPC_MASK) {
+       case PIPE_MISC_BPC_6:
                return 18;
-       case PIPEMISC_BPC_8:
+       case PIPE_MISC_BPC_8:
                return 24;
-       case PIPEMISC_BPC_10:
+       case PIPE_MISC_BPC_10:
                return 30;
        /*
         * PORT OUTPUT 12 BPC defined for ADLP+.
@@ -3400,7 +3404,7 @@ int bdw_get_pipemisc_bpp(struct intel_crtc *crtc)
         * on older platforms, need to find a workaround for 12 BPC
         * MIPI DSI HW readout.
         */
-       case PIPEMISC_BPC_12_ADLP:
+       case PIPE_MISC_BPC_12_ADLP:
                if (DISPLAY_VER(dev_priv) > 12)
                        return 36;
                fallthrough;
@@ -3981,7 +3985,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
                        pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        } else {
                pipe_config->output_format =
-                       bdw_get_pipemisc_output_format(crtc);
+                       bdw_get_pipe_misc_output_format(crtc);
        }
 
        pipe_config->gamma_mode = intel_de_read(dev_priv,
@@ -5079,6 +5083,7 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
         * only fields that are know to not cause problems are preserved. */
 
        saved_state->uapi = crtc_state->uapi;
+       saved_state->inherited = crtc_state->inherited;
        saved_state->scaler_state = crtc_state->scaler_state;
        saved_state->shared_dpll = crtc_state->shared_dpll;
        saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
@@ -5904,68 +5909,6 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state,
        return 0;
 }
 
-void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct drm_display_mode adjusted_mode;
-
-       drm_mode_init(&adjusted_mode, &crtc_state->hw.adjusted_mode);
-
-       if (crtc_state->vrr.enable) {
-               adjusted_mode.crtc_vtotal = crtc_state->vrr.vmax;
-               adjusted_mode.crtc_vblank_end = crtc_state->vrr.vmax;
-               adjusted_mode.crtc_vblank_start = intel_vrr_vmin_vblank_start(crtc_state);
-               crtc->vmax_vblank_start = intel_vrr_vmax_vblank_start(crtc_state);
-       }
-
-       drm_calc_timestamping_constants(&crtc->base, &adjusted_mode);
-
-       crtc->mode_flags = crtc_state->mode_flags;
-
-       /*
-        * The scanline counter increments at the leading edge of hsync.
-        *
-        * On most platforms it starts counting from vtotal-1 on the
-        * first active line. That means the scanline counter value is
-        * always one less than what we would expect. Ie. just after
-        * start of vblank, which also occurs at start of hsync (on the
-        * last active line), the scanline counter will read vblank_start-1.
-        *
-        * On gen2 the scanline counter starts counting from 1 instead
-        * of vtotal-1, so we have to subtract one (or rather add vtotal-1
-        * to keep the value positive), instead of adding one.
-        *
-        * On HSW+ the behaviour of the scanline counter depends on the output
-        * type. For DP ports it behaves like most other platforms, but on HDMI
-        * there's an extra 1 line difference. So we need to add two instead of
-        * one to the value.
-        *
-        * On VLV/CHV DSI the scanline counter would appear to increment
-        * approx. 1/3 of a scanline before start of vblank. Unfortunately
-        * that means we can't tell whether we're in vblank or not while
-        * we're on that particular line. We must still set scanline_offset
-        * to 1 so that the vblank timestamps come out correct when we query
-        * the scanline counter from within the vblank interrupt handler.
-        * However if queried just before the start of vblank we'll get an
-        * answer that's slightly in the future.
-        */
-       if (DISPLAY_VER(dev_priv) == 2) {
-               int vtotal;
-
-               vtotal = adjusted_mode.crtc_vtotal;
-               if (adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
-                       vtotal /= 2;
-
-               crtc->scanline_offset = vtotal - 1;
-       } else if (HAS_DDI(dev_priv) &&
-                  intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
-               crtc->scanline_offset = 2;
-       } else {
-               crtc->scanline_offset = 1;
-       }
-}
-
 /*
  * This implements the workaround described in the "notes" section of the mode
  * set sequence documentation. When going from no pipes or single pipe to
@@ -6970,7 +6913,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state,
                        intel_color_commit_arm(new_crtc_state);
 
                if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
-                       bdw_set_pipemisc(new_crtc_state);
+                       bdw_set_pipe_misc(new_crtc_state);
 
                if (intel_crtc_needs_fastset(new_crtc_state))
                        intel_pipe_fastset(old_crtc_state, new_crtc_state);
@@ -7046,6 +6989,8 @@ static void intel_update_crtc(struct intel_atomic_state *state,
 
        intel_fbc_update(state, crtc);
 
+       drm_WARN_ON(&i915->drm, !intel_display_power_is_enabled(i915, POWER_DOMAIN_DC_OFF));
+
        if (!modeset &&
            intel_crtc_needs_color_update(new_crtc_state))
                intel_color_commit_noarm(new_crtc_state);
@@ -7413,8 +7358,28 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
        drm_atomic_helper_wait_for_dependencies(&state->base);
        drm_dp_mst_atomic_wait_for_dependencies(&state->base);
 
-       if (state->modeset)
-               wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
+       /*
+        * During full modesets we write a lot of registers, wait
+        * for PLLs, etc. Doing that while DC states are enabled
+        * is not a good idea.
+        *
+        * During fastsets and other updates we also need to
+        * disable DC states due to the following scenario:
+        * 1. DC5 exit and PSR exit happen
+        * 2. Some or all _noarm() registers are written
+        * 3. Due to some long delay PSR is re-entered
+        * 4. DC5 entry -> DMC saves the already written new
+        *    _noarm() registers and the old not yet written
+        *    _arm() registers
+        * 5. DC5 exit -> DMC restores a mixture of old and
+        *    new register values and arms the update
+        * 6. PSR exit -> hardware latches a mixture of old and
+        *    new register values -> corrupted frame, or worse
+        * 7. New _arm() registers are finally written
+        * 8. Hardware finally latches a complete set of new
+        *    register values, and subsequent frames will be OK again
+        */
+       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_DC_OFF);
 
        intel_atomic_prepare_plane_clear_colors(state);
 
@@ -7563,8 +7528,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
                 * the culprit.
                 */
                intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore);
-               intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET, wakeref);
        }
+       intel_display_power_put(dev_priv, POWER_DOMAIN_DC_OFF, wakeref);
        intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);
 
        /*
@@ -8886,14 +8851,14 @@ void intel_display_driver_register(struct drm_i915_private *i915)
        if (!HAS_DISPLAY(i915))
                return;
 
-       intel_display_debugfs_register(i915);
-
        /* Must be done after probing outputs */
        intel_opregion_register(i915);
        intel_acpi_video_register(i915);
 
        intel_audio_init(i915);
 
+       intel_display_debugfs_register(i915);
+
        /*
         * Some ports require correctly set-up hpd registers for
         * detection to work properly (leading to ghost connected
index 50285fb4fcf598cfb3cb1e71ddea057216ef4b38..596fd3ec19838f47d8e94bccfca4176034d9b688 100644 (file)
@@ -422,7 +422,6 @@ bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state);
 bool intel_pipe_config_compare(const struct intel_crtc_state *current_config,
                               const struct intel_crtc_state *pipe_config,
                               bool fastset);
-void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state);
 
 void intel_plane_destroy(struct drm_plane *plane);
 void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state);
@@ -511,7 +510,7 @@ void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
                                  struct intel_crtc_state *crtc_state);
 void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
 
-int bdw_get_pipemisc_bpp(struct intel_crtc *crtc);
+int bdw_get_pipe_misc_bpp(struct intel_crtc *crtc);
 unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state);
 
 bool intel_plane_uses_fence(const struct intel_plane_state *plane_state);
index fdab7bb93a7d6efb209a4ae5aae9d61db49ac7a9..0b5509f268a7b5c1385e4dca2cab71d8da6e80be 100644 (file)
@@ -183,6 +183,17 @@ struct intel_hotplug {
         * blocked behind the non-DP one.
         */
        struct workqueue_struct *dp_wq;
+
+       /*
+        * Flag to track if long HPDs need not to be processed
+        *
+        * Some panels generate long HPDs while keep connected to the port.
+        * This can cause issues with CI tests results. In CI systems we
+        * don't expect to disconnect the panels and could ignore the long
+        * HPDs generated from the faulty panels. This flag can be used as
+        * cue to ignore the long HPDs and can be set / unset using debugfs.
+        */
+       bool ignore_long_hpd;
 };
 
 struct intel_vbt_data {
@@ -384,9 +395,15 @@ struct intel_display {
        } gmbus;
 
        struct {
-               struct i915_hdcp_comp_master *master;
+               struct i915_hdcp_master *master;
                bool comp_added;
 
+               /*
+                * HDCP message struct for allocation of memory which can be
+                * reused when sending message to gsc cs.
+                * this is only populated post Meteorlake
+                */
+               struct intel_hdcp_gsc_message *hdcp_message;
                /* Mutex to protect the above hdcp component related values. */
                struct mutex comp_mutex;
        } hdcp;
index 1e654ddd0815c56d747f21712f725ba1e460e541..cc502627255845edda5140fa06b7a1cc24450dc3 100644 (file)
@@ -8,6 +8,7 @@
 #include <drm/drm_debugfs.h>
 #include <drm/drm_fourcc.h>
 
+#include "hsw_ips.h"
 #include "i915_debugfs.h"
 #include "i915_irq.h"
 #include "i915_reg.h"
@@ -48,33 +49,6 @@ static int i915_frontbuffer_tracking(struct seq_file *m, void *unused)
        return 0;
 }
 
-static int i915_ips_status(struct seq_file *m, void *unused)
-{
-       struct drm_i915_private *dev_priv = node_to_i915(m->private);
-       intel_wakeref_t wakeref;
-
-       if (!HAS_IPS(dev_priv))
-               return -ENODEV;
-
-       wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
-
-       seq_printf(m, "Enabled by kernel parameter: %s\n",
-                  str_yes_no(dev_priv->params.enable_ips));
-
-       if (DISPLAY_VER(dev_priv) >= 8) {
-               seq_puts(m, "Currently: unknown\n");
-       } else {
-               if (intel_de_read(dev_priv, IPS_CTL) & IPS_ENABLE)
-                       seq_puts(m, "Currently: enabled\n");
-               else
-                       seq_puts(m, "Currently: disabled\n");
-       }
-
-       intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
-
-       return 0;
-}
-
 static int i915_sr_status(struct seq_file *m, void *unused)
 {
        struct drm_i915_private *dev_priv = node_to_i915(m->private);
@@ -168,269 +142,6 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static int i915_psr_sink_status_show(struct seq_file *m, void *data)
-{
-       u8 val;
-       static const char * const sink_status[] = {
-               "inactive",
-               "transition to active, capture and display",
-               "active, display from RFB",
-               "active, capture and display on sink device timings",
-               "transition to inactive, capture and display, timing re-sync",
-               "reserved",
-               "reserved",
-               "sink internal error",
-       };
-       struct drm_connector *connector = m->private;
-       struct intel_dp *intel_dp =
-               intel_attached_dp(to_intel_connector(connector));
-       int ret;
-
-       if (!CAN_PSR(intel_dp)) {
-               seq_puts(m, "PSR Unsupported\n");
-               return -ENODEV;
-       }
-
-       if (connector->status != connector_status_connected)
-               return -ENODEV;
-
-       ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val);
-
-       if (ret == 1) {
-               const char *str = "unknown";
-
-               val &= DP_PSR_SINK_STATE_MASK;
-               if (val < ARRAY_SIZE(sink_status))
-                       str = sink_status[val];
-               seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, str);
-       } else {
-               return ret;
-       }
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status);
-
-static void
-psr_source_status(struct intel_dp *intel_dp, struct seq_file *m)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       const char *status = "unknown";
-       u32 val, status_val;
-
-       if (intel_dp->psr.psr2_enabled) {
-               static const char * const live_status[] = {
-                       "IDLE",
-                       "CAPTURE",
-                       "CAPTURE_FS",
-                       "SLEEP",
-                       "BUFON_FW",
-                       "ML_UP",
-                       "SU_STANDBY",
-                       "FAST_SLEEP",
-                       "DEEP_SLEEP",
-                       "BUF_ON",
-                       "TG_ON"
-               };
-               val = intel_de_read(dev_priv,
-                                   EDP_PSR2_STATUS(intel_dp->psr.transcoder));
-               status_val = REG_FIELD_GET(EDP_PSR2_STATUS_STATE_MASK, val);
-               if (status_val < ARRAY_SIZE(live_status))
-                       status = live_status[status_val];
-       } else {
-               static const char * const live_status[] = {
-                       "IDLE",
-                       "SRDONACK",
-                       "SRDENT",
-                       "BUFOFF",
-                       "BUFON",
-                       "AUXACK",
-                       "SRDOFFACK",
-                       "SRDENT_ON",
-               };
-               val = intel_de_read(dev_priv,
-                                   EDP_PSR_STATUS(intel_dp->psr.transcoder));
-               status_val = (val & EDP_PSR_STATUS_STATE_MASK) >>
-                             EDP_PSR_STATUS_STATE_SHIFT;
-               if (status_val < ARRAY_SIZE(live_status))
-                       status = live_status[status_val];
-       }
-
-       seq_printf(m, "Source PSR status: %s [0x%08x]\n", status, val);
-}
-
-static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_psr *psr = &intel_dp->psr;
-       intel_wakeref_t wakeref;
-       const char *status;
-       bool enabled;
-       u32 val;
-
-       seq_printf(m, "Sink support: %s", str_yes_no(psr->sink_support));
-       if (psr->sink_support)
-               seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]);
-       seq_puts(m, "\n");
-
-       if (!psr->sink_support)
-               return 0;
-
-       wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
-       mutex_lock(&psr->lock);
-
-       if (psr->enabled)
-               status = psr->psr2_enabled ? "PSR2 enabled" : "PSR1 enabled";
-       else
-               status = "disabled";
-       seq_printf(m, "PSR mode: %s\n", status);
-
-       if (!psr->enabled) {
-               seq_printf(m, "PSR sink not reliable: %s\n",
-                          str_yes_no(psr->sink_not_reliable));
-
-               goto unlock;
-       }
-
-       if (psr->psr2_enabled) {
-               val = intel_de_read(dev_priv,
-                                   EDP_PSR2_CTL(intel_dp->psr.transcoder));
-               enabled = val & EDP_PSR2_ENABLE;
-       } else {
-               val = intel_de_read(dev_priv,
-                                   EDP_PSR_CTL(intel_dp->psr.transcoder));
-               enabled = val & EDP_PSR_ENABLE;
-       }
-       seq_printf(m, "Source PSR ctl: %s [0x%08x]\n",
-                  str_enabled_disabled(enabled), val);
-       psr_source_status(intel_dp, m);
-       seq_printf(m, "Busy frontbuffer bits: 0x%08x\n",
-                  psr->busy_frontbuffer_bits);
-
-       /*
-        * SKL+ Perf counter is reset to 0 everytime DC state is entered
-        */
-       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
-               val = intel_de_read(dev_priv,
-                                   EDP_PSR_PERF_CNT(intel_dp->psr.transcoder));
-               val &= EDP_PSR_PERF_CNT_MASK;
-               seq_printf(m, "Performance counter: %u\n", val);
-       }
-
-       if (psr->debug & I915_PSR_DEBUG_IRQ) {
-               seq_printf(m, "Last attempted entry at: %lld\n",
-                          psr->last_entry_attempt);
-               seq_printf(m, "Last exit at: %lld\n", psr->last_exit);
-       }
-
-       if (psr->psr2_enabled) {
-               u32 su_frames_val[3];
-               int frame;
-
-               /*
-                * Reading all 3 registers before hand to minimize crossing a
-                * frame boundary between register reads
-                */
-               for (frame = 0; frame < PSR2_SU_STATUS_FRAMES; frame += 3) {
-                       val = intel_de_read(dev_priv,
-                                           PSR2_SU_STATUS(intel_dp->psr.transcoder, frame));
-                       su_frames_val[frame / 3] = val;
-               }
-
-               seq_puts(m, "Frame:\tPSR2 SU blocks:\n");
-
-               for (frame = 0; frame < PSR2_SU_STATUS_FRAMES; frame++) {
-                       u32 su_blocks;
-
-                       su_blocks = su_frames_val[frame / 3] &
-                                   PSR2_SU_STATUS_MASK(frame);
-                       su_blocks = su_blocks >> PSR2_SU_STATUS_SHIFT(frame);
-                       seq_printf(m, "%d\t%d\n", frame, su_blocks);
-               }
-
-               seq_printf(m, "PSR2 selective fetch: %s\n",
-                          str_enabled_disabled(psr->psr2_sel_fetch_enabled));
-       }
-
-unlock:
-       mutex_unlock(&psr->lock);
-       intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
-
-       return 0;
-}
-
-static int i915_edp_psr_status(struct seq_file *m, void *data)
-{
-       struct drm_i915_private *dev_priv = node_to_i915(m->private);
-       struct intel_dp *intel_dp = NULL;
-       struct intel_encoder *encoder;
-
-       if (!HAS_PSR(dev_priv))
-               return -ENODEV;
-
-       /* Find the first EDP which supports PSR */
-       for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
-               intel_dp = enc_to_intel_dp(encoder);
-               break;
-       }
-
-       if (!intel_dp)
-               return -ENODEV;
-
-       return intel_psr_status(m, intel_dp);
-}
-
-static int
-i915_edp_psr_debug_set(void *data, u64 val)
-{
-       struct drm_i915_private *dev_priv = data;
-       struct intel_encoder *encoder;
-       intel_wakeref_t wakeref;
-       int ret = -ENODEV;
-
-       if (!HAS_PSR(dev_priv))
-               return ret;
-
-       for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-               drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val);
-
-               wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
-
-               // TODO: split to each transcoder's PSR debug state
-               ret = intel_psr_debug_set(intel_dp, val);
-
-               intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
-       }
-
-       return ret;
-}
-
-static int
-i915_edp_psr_debug_get(void *data, u64 *val)
-{
-       struct drm_i915_private *dev_priv = data;
-       struct intel_encoder *encoder;
-
-       if (!HAS_PSR(dev_priv))
-               return -ENODEV;
-
-       for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-               // TODO: split to each transcoder's PSR debug state
-               *val = READ_ONCE(intel_dp->psr.debug);
-               return 0;
-       }
-
-       return -ENODEV;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops,
-                       i915_edp_psr_debug_get, i915_edp_psr_debug_set,
-                       "%llu\n");
-
 static int i915_power_domain_info(struct seq_file *m, void *unused)
 {
        struct drm_i915_private *i915 = node_to_i915(m->private);
@@ -831,10 +542,10 @@ static const struct file_operations crtc_updates_fops = {
        .write = crtc_updates_write
 };
 
-static void crtc_updates_add(struct drm_crtc *crtc)
+static void crtc_updates_add(struct intel_crtc *crtc)
 {
-       debugfs_create_file("i915_update_info", 0644, crtc->debugfs_entry,
-                           to_intel_crtc(crtc), &crtc_updates_fops);
+       debugfs_create_file("i915_update_info", 0644, crtc->base.debugfs_entry,
+                           crtc, &crtc_updates_fops);
 }
 
 #else
@@ -844,7 +555,7 @@ static void crtc_updates_info(struct seq_file *m,
 {
 }
 
-static void crtc_updates_add(struct drm_crtc *crtc)
+static void crtc_updates_add(struct intel_crtc *crtc)
 {
 }
 #endif
@@ -1342,12 +1053,10 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
 
 static const struct drm_info_list intel_display_debugfs_list[] = {
        {"i915_frontbuffer_tracking", i915_frontbuffer_tracking, 0},
-       {"i915_ips_status", i915_ips_status, 0},
        {"i915_sr_status", i915_sr_status, 0},
        {"i915_opregion", i915_opregion, 0},
        {"i915_vbt", i915_vbt, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
-       {"i915_edp_psr_status", i915_edp_psr_status, 0},
        {"i915_power_domain_info", i915_power_domain_info, 0},
        {"i915_display_info", i915_display_info, 0},
        {"i915_shared_dplls_info", i915_shared_dplls_info, 0},
@@ -1364,7 +1073,6 @@ static const struct {
        {"i915_dp_test_data", &i915_displayport_test_data_fops},
        {"i915_dp_test_type", &i915_displayport_test_type_fops},
        {"i915_dp_test_active", &i915_displayport_test_active_fops},
-       {"i915_edp_psr_debug", &i915_edp_psr_debug_fops},
 };
 
 void intel_display_debugfs_register(struct drm_i915_private *i915)
@@ -1384,9 +1092,11 @@ void intel_display_debugfs_register(struct drm_i915_private *i915)
                                 ARRAY_SIZE(intel_display_debugfs_list),
                                 minor->debugfs_root, minor);
 
+       hsw_ips_debugfs_register(i915);
        intel_dmc_debugfs_register(i915);
        intel_fbc_debugfs_register(i915);
        intel_hpd_debugfs_register(i915);
+       intel_psr_debugfs_register(i915);
        intel_wm_debugfs_register(i915);
 }
 
@@ -1439,16 +1149,6 @@ out:
 }
 DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability);
 
-static int i915_psr_status_show(struct seq_file *m, void *data)
-{
-       struct drm_connector *connector = m->private;
-       struct intel_dp *intel_dp =
-               intel_attached_dp(to_intel_connector(connector));
-
-       return intel_psr_status(m, intel_dp);
-}
-DEFINE_SHOW_ATTRIBUTE(i915_psr_status);
-
 static int i915_lpsp_capability_show(struct seq_file *m, void *data)
 {
        struct drm_connector *connector = m->private;
@@ -1666,7 +1366,7 @@ static const struct file_operations i915_dsc_bpc_fops = {
  */
 static int i915_current_bpc_show(struct seq_file *m, void *data)
 {
-       struct intel_crtc *crtc = to_intel_crtc(m->private);
+       struct intel_crtc *crtc = m->private;
        struct intel_crtc_state *crtc_state;
        int ret;
 
@@ -1683,6 +1383,17 @@ static int i915_current_bpc_show(struct seq_file *m, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(i915_current_bpc);
 
+/* Pipe may differ from crtc index if pipes are fused off */
+static int intel_crtc_pipe_show(struct seq_file *m, void *unused)
+{
+       struct intel_crtc *crtc = m->private;
+
+       seq_printf(m, "%c\n", pipe_name(crtc->pipe));
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(intel_crtc_pipe);
+
 /**
  * intel_connector_debugfs_add - add i915 specific connector debugfs files
  * @connector: pointer to a registered drm_connector
@@ -1701,19 +1412,11 @@ void intel_connector_debugfs_add(struct intel_connector *intel_connector)
                return;
 
        intel_drrs_connector_debugfs_add(intel_connector);
+       intel_psr_connector_debugfs_add(intel_connector);
 
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
                debugfs_create_file("i915_panel_timings", S_IRUGO, root,
                                    connector, &i915_panel_fops);
-               debugfs_create_file("i915_psr_sink_status", S_IRUGO, root,
-                                   connector, &i915_psr_sink_status_fops);
-       }
-
-       if (HAS_PSR(dev_priv) &&
-           connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
-               debugfs_create_file("i915_psr_status", 0444, root,
-                                   connector, &i915_psr_status_fops);
-       }
 
        if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
            connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
@@ -1748,15 +1451,19 @@ void intel_connector_debugfs_add(struct intel_connector *intel_connector)
  *
  * Failure to add debugfs entries should generally be ignored.
  */
-void intel_crtc_debugfs_add(struct drm_crtc *crtc)
+void intel_crtc_debugfs_add(struct intel_crtc *crtc)
 {
-       if (!crtc->debugfs_entry)
+       struct dentry *root = crtc->base.debugfs_entry;
+
+       if (!root)
                return;
 
        crtc_updates_add(crtc);
-       intel_drrs_crtc_debugfs_add(to_intel_crtc(crtc));
-       intel_fbc_crtc_debugfs_add(to_intel_crtc(crtc));
+       intel_drrs_crtc_debugfs_add(crtc);
+       intel_fbc_crtc_debugfs_add(crtc);
 
-       debugfs_create_file("i915_current_bpc", 0444, crtc->debugfs_entry, crtc,
+       debugfs_create_file("i915_current_bpc", 0444, root, crtc,
                            &i915_current_bpc_fops);
+       debugfs_create_file("i915_pipe", 0444, root, crtc,
+                           &intel_crtc_pipe_fops);
 }
index d3a79c07c384b657d99f37fe21977e51596cffca..e1f479b7acd16e2c17800790dde179027b8bc0dd 100644 (file)
@@ -6,18 +6,18 @@
 #ifndef __INTEL_DISPLAY_DEBUGFS_H__
 #define __INTEL_DISPLAY_DEBUGFS_H__
 
-struct drm_crtc;
 struct drm_i915_private;
 struct intel_connector;
+struct intel_crtc;
 
 #ifdef CONFIG_DEBUG_FS
 void intel_display_debugfs_register(struct drm_i915_private *i915);
 void intel_connector_debugfs_add(struct intel_connector *connector);
-void intel_crtc_debugfs_add(struct drm_crtc *crtc);
+void intel_crtc_debugfs_add(struct intel_crtc *crtc);
 #else
 static inline void intel_display_debugfs_register(struct drm_i915_private *i915) {}
 static inline void intel_connector_debugfs_add(struct intel_connector *connector) {}
-static inline void intel_crtc_debugfs_add(struct drm_crtc *crtc) {}
+static inline void intel_crtc_debugfs_add(struct intel_crtc *crtc) {}
 #endif
 
 #endif /* __INTEL_DISPLAY_DEBUGFS_H__ */
index f085ae9711508db1bf67ceae60bb275db0bd0536..f86060195987cb9dab91701bd9d1ef44569ea6ae 100644 (file)
@@ -1625,6 +1625,10 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
        intel_power_well_enable(dev_priv, well);
        mutex_unlock(&power_domains->lock);
 
+       if (DISPLAY_VER(dev_priv) == 14)
+               intel_de_rmw(dev_priv, DC_STATE_EN,
+                            HOLD_PHY_PG1_LATCH | HOLD_PHY_CLKREQ_PG1_LATCH, 0);
+
        /* 4. Enable CDCLK. */
        intel_cdclk_init_hw(dev_priv);
 
@@ -1678,6 +1682,10 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
        /* 3. Disable CD clock */
        intel_cdclk_uninit_hw(dev_priv);
 
+       if (DISPLAY_VER(dev_priv) == 14)
+               intel_de_rmw(dev_priv, DC_STATE_EN, 0,
+                            HOLD_PHY_PG1_LATCH | HOLD_PHY_CLKREQ_PG1_LATCH);
+
        /*
         * 4. Disable Power Well 1 (PG1).
         *    The AUX IO power wells are toggled on demand, so they are already
index c32bfba06ca1f21a4d661fbfba000b92d463cdb3..ab146b5b68bd5a7ef7f82aa35b484ac784ea01ea 100644 (file)
@@ -43,7 +43,7 @@
 #include <drm/drm_rect.h>
 #include <drm/drm_vblank.h>
 #include <drm/drm_vblank_work.h>
-#include <drm/i915_mei_hdcp_interface.h>
+#include <drm/i915_hdcp_interface.h>
 #include <media/cec-notifier.h>
 
 #include "i915_vma.h"
@@ -255,6 +255,11 @@ struct intel_encoder {
         * Returns whether the port clock is enabled or not.
         */
        bool (*is_clock_enabled)(struct intel_encoder *encoder);
+       /*
+        * Returns the PLL type the port uses.
+        */
+       enum icl_port_dpll_id (*port_pll_type)(struct intel_encoder *encoder,
+                                              const struct intel_crtc_state *crtc_state);
        const struct intel_ddi_buf_trans *(*get_buf_trans)(struct intel_encoder *encoder,
                                                           const struct intel_crtc_state *crtc_state,
                                                           int *n_entries);
@@ -1783,6 +1788,7 @@ struct intel_digital_port {
        bool tc_legacy_port:1;
        char tc_port_name[8];
        enum tc_port_mode tc_mode;
+       enum tc_port_mode tc_init_mode;
        enum phy_fia tc_phy_fia;
        u8 tc_phy_fia_idx;
 
index 6b162f77340e627ea47d101172e2e3d3dd53f974..8a88de67ff0a98f5b1350213d4471d987628f856 100644 (file)
@@ -89,10 +89,13 @@ static struct intel_dmc *i915_to_dmc(struct drm_i915_private *i915)
        __stringify(major) "_"                  \
        __stringify(minor) ".bin"
 
+#define XELPDP_DMC_MAX_FW_SIZE         0x7000
 #define DISPLAY_VER13_DMC_MAX_FW_SIZE  0x20000
-
 #define DISPLAY_VER12_DMC_MAX_FW_SIZE  ICL_DMC_MAX_FW_SIZE
 
+#define MTL_DMC_PATH                   DMC_PATH(mtl)
+MODULE_FIRMWARE(MTL_DMC_PATH);
+
 #define DG2_DMC_PATH                   DMC_LEGACY_PATH(dg2, 2, 08)
 MODULE_FIRMWARE(DG2_DMC_PATH);
 
@@ -424,15 +427,12 @@ static void disable_all_event_handlers(struct drm_i915_private *i915)
        }
 }
 
-static void pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
+static void adlp_pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
 {
        enum pipe pipe;
 
-       if (DISPLAY_VER(i915) < 13)
-               return;
-
        /*
-        * Wa_16015201720:adl-p,dg2, mtl
+        * Wa_16015201720:adl-p,dg2
         * The WA requires clock gating to be disabled all the time
         * for pipe A and B.
         * For pipe C and D clock gating needs to be disabled only
@@ -448,6 +448,25 @@ static void pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
                                     PIPEDMC_GATING_DIS, 0);
 }
 
+static void mtl_pipedmc_clock_gating_wa(struct drm_i915_private *i915)
+{
+       /*
+        * Wa_16015201720
+        * The WA requires clock gating to be disabled all the time
+        * for pipe A and B.
+        */
+       intel_de_rmw(i915, GEN9_CLKGATE_DIS_0, 0,
+                    MTL_PIPEDMC_GATING_DIS_A | MTL_PIPEDMC_GATING_DIS_B);
+}
+
+static void pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
+{
+       if (DISPLAY_VER(i915) >= 14 && enable)
+               mtl_pipedmc_clock_gating_wa(i915);
+       else if (DISPLAY_VER(i915) == 13)
+               adlp_pipedmc_clock_gating_wa(i915, enable);
+}
+
 void intel_dmc_enable_pipe(struct drm_i915_private *i915, enum pipe pipe)
 {
        enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe);
@@ -979,7 +998,10 @@ void intel_dmc_init(struct drm_i915_private *i915)
 
        INIT_WORK(&dmc->work, dmc_load_work_fn);
 
-       if (IS_DG2(i915)) {
+       if (IS_METEORLAKE(i915)) {
+               dmc->fw_path = MTL_DMC_PATH;
+               dmc->max_fw_size = XELPDP_DMC_MAX_FW_SIZE;
+       } else if (IS_DG2(i915)) {
                dmc->fw_path = DG2_DMC_PATH;
                dmc->max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE;
        } else if (IS_ALDERLAKE_P(i915)) {
index aee93b0d810e3180d832ac6567484a26d48dd17c..da1c00ee92fbbc75538b72a5c5418f6c495aa7a7 100644 (file)
@@ -687,6 +687,12 @@ u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 p
        /* From XE_LPD onwards we support from bpc upto uncompressed bpp-1 BPPs */
        if (DISPLAY_VER(i915) >= 13) {
                bits_per_pixel = min(bits_per_pixel, pipe_bpp - 1);
+
+               /*
+                * According to BSpec, 27 is the max DSC output bpp,
+                * 8 is the min DSC output bpp
+                */
+               bits_per_pixel = clamp_t(u32, bits_per_pixel, 8, 27);
        } else {
                /* Find the nearest match in the array of known BPPs from VESA */
                for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
@@ -716,9 +722,19 @@ u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
         * (LinkSymbolClock)* 8 * (TimeSlots / 64)
         * for SST -> TimeSlots is 64(i.e all TimeSlots that are available)
         * for MST -> TimeSlots has to be calculated, based on mode requirements
+        *
+        * Due to FEC overhead, the available bw is reduced to 97.2261%.
+        * To support the given mode:
+        * Bandwidth required should be <= Available link Bandwidth * FEC Overhead
+        * =>ModeClock * bits_per_pixel <= Available Link Bandwidth * FEC Overhead
+        * =>bits_per_pixel <= Available link Bandwidth * FEC Overhead / ModeClock
+        * =>bits_per_pixel <= (NumberOfLanes * LinkSymbolClock) * 8 (TimeSlots / 64) /
+        *                     (ModeClock / FEC Overhead)
+        * =>bits_per_pixel <= (NumberOfLanes * LinkSymbolClock * TimeSlots) /
+        *                     (ModeClock / FEC Overhead * 8)
         */
-       bits_per_pixel = DIV_ROUND_UP((link_clock * lane_count) * timeslots,
-                                     intel_dp_mode_to_fec_clock(mode_clock) * 8);
+       bits_per_pixel = ((link_clock * lane_count) * timeslots) /
+                        (intel_dp_mode_to_fec_clock(mode_clock) * 8);
 
        drm_dbg_kms(&i915->drm, "Max link bpp is %u for %u timeslots "
                                "total bw %u pixel clock %u\n",
@@ -771,6 +787,13 @@ u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
                min_slice_count = DIV_ROUND_UP(mode_clock,
                                               DP_DSC_MAX_ENC_THROUGHPUT_1);
 
+       /*
+        * Due to some DSC engine BW limitations, we need to enable second
+        * slice and VDSC engine, whenever we approach close enough to max CDCLK
+        */
+       if (mode_clock >= ((i915->display.cdclk.max_cdclk_freq * 85) / 100))
+               min_slice_count = max_t(u8, min_slice_count, 2);
+
        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_dbg_kms(&i915->drm,
@@ -1597,16 +1620,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
         * is greater than the maximum Cdclock and if slice count is even
         * then we need to use 2 VDSC instances.
         */
-       if (adjusted_mode->crtc_clock > dev_priv->display.cdclk.max_cdclk_freq ||
-           pipe_config->bigjoiner_pipes) {
-               if (pipe_config->dsc.slice_count > 1) {
-                       pipe_config->dsc.dsc_split = true;
-               } else {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "Cannot split stream to use 2 VDSC instances\n");
-                       return -EINVAL;
-               }
-       }
+       if (pipe_config->bigjoiner_pipes || pipe_config->dsc.slice_count > 1)
+               pipe_config->dsc.dsc_split = true;
 
        ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config);
        if (ret < 0) {
index 96967e21c94c2c9c813d81273fdfad9613eb653f..eb07dc5d8709906da245593939c060fb98a82c5f 100644 (file)
@@ -205,8 +205,19 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
        for (i = 0; i < ARRAY_SIZE(ch_data); i++)
                ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
 
-       if (is_tc_port)
+       if (is_tc_port) {
                intel_tc_port_lock(dig_port);
+               /*
+                * Abort transfers on a disconnected port as required by
+                * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX
+                * timeouts that would otherwise happen.
+                * TODO: abort the transfer on non-TC ports as well.
+                */
+               if (!intel_tc_port_connected_locked(&dig_port->base)) {
+                       ret = -ENXIO;
+                       goto out_unlock;
+               }
+       }
 
        aux_domain = intel_aux_power_domain(dig_port);
 
@@ -367,7 +378,7 @@ out:
 
        intel_pps_unlock(intel_dp, pps_wakeref);
        intel_display_power_put_async(i915, aux_domain, aux_wakeref);
-
+out_unlock:
        if (is_tc_port)
                intel_tc_port_unlock(dig_port);
 
index 3d3efcf02011e7d4b89ff2b82ee0cab6256a5c40..d638054c74ac182cf9d05414a197f9b2857175cc 100644 (file)
@@ -1379,10 +1379,6 @@ intel_dp_128b132b_lane_cds(struct intel_dp *intel_dp,
                }
        }
 
-       /* FIXME: Should DP_TRAINING_PATTERN_DISABLE be written first? */
-       if (intel_dp->set_idle_link_train)
-               intel_dp->set_idle_link_train(intel_dp, crtc_state);
-
        return true;
 }
 
@@ -1433,7 +1429,11 @@ intel_dp_128b132b_link_train(struct intel_dp *intel_dp,
 void intel_dp_start_link_train(struct intel_dp *intel_dp,
                               const struct intel_crtc_state *crtc_state)
 {
+       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+       struct intel_connector *connector = intel_dp->attached_connector;
+       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
        bool passed;
+
        /*
         * TODO: Reiniting LTTPRs here won't be needed once proper connector
         * HW state readout is added.
@@ -1451,6 +1451,46 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp,
        else
                passed = intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count);
 
+       /*
+        * Ignore the link failure in CI
+        *
+        * In fixed enviroments like CI, sometimes unexpected long HPDs are
+        * generated by the displays. If ignore_long_hpd flag is set, such long
+        * HPDs are ignored. And probably as a consequence of these ignored
+        * long HPDs, subsequent link trainings are failed resulting into CI
+        * execution failures.
+        *
+        * For test cases which rely on the link training or processing of HPDs
+        * ignore_long_hpd flag can unset from the testcase.
+        */
+       if (!passed && i915->display.hotplug.ignore_long_hpd) {
+               drm_dbg_kms(&i915->drm,
+                           "[CONNECTOR:%d:%s][ENCODER:%d:%s] Ignore the link failure\n",
+                           connector->base.base.id, connector->base.name,
+                           encoder->base.base.id, encoder->base.name);
+               return;
+       }
+
        if (!passed)
                intel_dp_schedule_fallback_link_training(intel_dp, crtc_state);
 }
+
+void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
+                                const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+
+       /*
+        * VIDEO_DIP_CTL register bit 31 should be set to '0' to not
+        * disable SDP CRC. This is applicable for Display version 13.
+        * Default value of bit 31 is '0' hence discarding the write
+        * TODO: Corrective actions on SDP corruption yet to be defined
+        */
+       if (intel_dp_is_uhbr(crtc_state))
+               /* DP v2.0 SCR on SDP CRC16 for 128b/132b Link Layer */
+               drm_dp_dpcd_writeb(&intel_dp->aux,
+                                  DP_SDP_ERROR_DETECTION_CONFIGURATION,
+                                  DP_SDP_CRC16_128B132B_EN);
+
+       drm_dbg_kms(&i915->drm, "DP2.0 SDP CRC16 for 128b/132b enabled\n");
+}
index 7fa1c0833096ffc740f3c87f58bede8536fed84c..2c8f2775891b0f37ec9d46813bcb48f301d5db0c 100644 (file)
@@ -39,4 +39,6 @@ static inline u8 intel_dp_training_pattern_symbol(u8 pattern)
        return pattern & ~DP_LINK_SCRAMBLING_DISABLE;
 }
 
+void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
+                                const struct intel_crtc_state *crtc_state);
 #endif /* __INTEL_DP_LINK_TRAINING_H__ */
index 3659350061a7da0f0866047af3bc1ab35ce0d436..673bcdfb7ff6d36cf5f991a065c9c8a2f216e264 100644 (file)
@@ -210,6 +210,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
        bool prealloc = false;
        void __iomem *vaddr;
        struct drm_i915_gem_object *obj;
+       struct i915_gem_ww_ctx ww;
        int ret;
 
        mutex_lock(&ifbdev->hpd_lock);
@@ -283,13 +284,24 @@ static int intelfb_create(struct drm_fb_helper *helper,
                info->fix.smem_len = vma->size;
        }
 
-       vaddr = i915_vma_pin_iomap(vma);
-       if (IS_ERR(vaddr)) {
-               drm_err(&dev_priv->drm,
-                       "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr);
-               ret = PTR_ERR(vaddr);
-               goto out_unpin;
+       for_i915_gem_ww(&ww, ret, false) {
+               ret = i915_gem_object_lock(vma->obj, &ww);
+
+               if (ret)
+                       continue;
+
+               vaddr = i915_vma_pin_iomap(vma);
+               if (IS_ERR(vaddr)) {
+                       drm_err(&dev_priv->drm,
+                               "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr);
+                       ret = PTR_ERR(vaddr);
+                       continue;
+               }
        }
+
+       if (ret)
+               goto out_unpin;
+
        info->screen_base = vaddr;
        info->screen_size = vma->size;
 
index f55b4893c00f133c3d51825a5c26f74cf9ecabbc..c08c26a321b33d73cea857f3c62a8b8c6088b907 100644 (file)
@@ -845,9 +845,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder,
                intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E));
 
                /* Disable DP_TP_CTL and FDI_RX_CTL and retry */
-               intel_de_rmw(dev_priv, DP_TP_CTL(PORT_E),
-                            DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK,
-                            DP_TP_CTL_LINK_TRAIN_PAT1);
+               intel_de_rmw(dev_priv, DP_TP_CTL(PORT_E), DP_TP_CTL_ENABLE, 0);
                intel_de_posting_read(dev_priv, DP_TP_CTL(PORT_E));
 
                intel_wait_ddi_buf_idle(dev_priv, PORT_E);
index 2984d2810e42cca64fb3ea3a02028cb31bf7e857..650232c4892b183800fa86adbe518e964cc0c29b 100644 (file)
@@ -23,6 +23,7 @@
 #include "intel_display_power_well.h"
 #include "intel_display_types.h"
 #include "intel_hdcp.h"
+#include "intel_hdcp_gsc.h"
 #include "intel_hdcp_regs.h"
 #include "intel_pcode.h"
 
@@ -203,13 +204,20 @@ bool intel_hdcp2_capable(struct intel_connector *connector)
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        struct intel_hdcp *hdcp = &connector->hdcp;
+       struct intel_gt *gt = dev_priv->media_gt;
+       struct intel_gsc_uc *gsc = &gt->uc.gsc;
        bool capable = false;
 
        /* I915 support for HDCP2.2 */
        if (!hdcp->hdcp2_supported)
                return false;
 
-       /* MEI interface is solid */
+       /* If MTL+ make sure gsc is loaded and proxy is setup */
+       if (intel_hdcp_gsc_cs_required(dev_priv))
+               if (!intel_uc_fw_is_running(&gsc->fw))
+                       return false;
+
+       /* MEI/GSC interface is solid depending on which is used */
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
        if (!dev_priv->display.hdcp.comp_added ||  !dev_priv->display.hdcp.master) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
@@ -1142,18 +1150,18 @@ hdcp2_prepare_ake_init(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->initiate_hdcp2_session(comp->mei_dev, data, ake_data);
+       ret = arbiter->ops->initiate_hdcp2_session(arbiter->hdcp_dev, data, ake_data);
        if (ret)
                drm_dbg_kms(&dev_priv->drm, "Prepare_ake_init failed. %d\n",
                            ret);
@@ -1172,18 +1180,18 @@ hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->verify_receiver_cert_prepare_km(comp->mei_dev, data,
+       ret = arbiter->ops->verify_receiver_cert_prepare_km(arbiter->hdcp_dev, data,
                                                         rx_cert, paired,
                                                         ek_pub_km, msg_sz);
        if (ret < 0)
@@ -1200,18 +1208,18 @@ static int hdcp2_verify_hprime(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->verify_hprime(comp->mei_dev, data, rx_hprime);
+       ret = arbiter->ops->verify_hprime(arbiter->hdcp_dev, data, rx_hprime);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Verify hprime failed. %d\n", ret);
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
@@ -1226,18 +1234,18 @@ hdcp2_store_pairing_info(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->store_pairing_info(comp->mei_dev, data, pairing_info);
+       ret = arbiter->ops->store_pairing_info(arbiter->hdcp_dev, data, pairing_info);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Store pairing info failed. %d\n",
                            ret);
@@ -1253,18 +1261,18 @@ hdcp2_prepare_lc_init(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->initiate_locality_check(comp->mei_dev, data, lc_init);
+       ret = arbiter->ops->initiate_locality_check(arbiter->hdcp_dev, data, lc_init);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Prepare lc_init failed. %d\n",
                            ret);
@@ -1280,18 +1288,18 @@ hdcp2_verify_lprime(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->verify_lprime(comp->mei_dev, data, rx_lprime);
+       ret = arbiter->ops->verify_lprime(arbiter->hdcp_dev, data, rx_lprime);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Verify L_Prime failed. %d\n",
                            ret);
@@ -1306,18 +1314,18 @@ static int hdcp2_prepare_skey(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->get_session_key(comp->mei_dev, data, ske_data);
+       ret = arbiter->ops->get_session_key(arbiter->hdcp_dev, data, ske_data);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Get session key failed. %d\n",
                            ret);
@@ -1335,20 +1343,21 @@ hdcp2_verify_rep_topology_prepare_ack(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->repeater_check_flow_prepare_ack(comp->mei_dev, data,
-                                                        rep_topology,
-                                                        rep_send_ack);
+       ret = arbiter->ops->repeater_check_flow_prepare_ack(arbiter->hdcp_dev,
+                                                           data,
+                                                           rep_topology,
+                                                           rep_send_ack);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm,
                            "Verify rep topology failed. %d\n", ret);
@@ -1364,18 +1373,18 @@ hdcp2_verify_mprime(struct intel_connector *connector,
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->verify_mprime(comp->mei_dev, data, stream_ready);
+       ret = arbiter->ops->verify_mprime(arbiter->hdcp_dev, data, stream_ready);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Verify mprime failed. %d\n", ret);
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
@@ -1388,18 +1397,18 @@ static int hdcp2_authenticate_port(struct intel_connector *connector)
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->enable_hdcp_authentication(comp->mei_dev, data);
+       ret = arbiter->ops->enable_hdcp_authentication(arbiter->hdcp_dev, data);
        if (ret < 0)
                drm_dbg_kms(&dev_priv->drm, "Enable hdcp auth failed. %d\n",
                            ret);
@@ -1408,22 +1417,22 @@ static int hdcp2_authenticate_port(struct intel_connector *connector)
        return ret;
 }
 
-static int hdcp2_close_mei_session(struct intel_connector *connector)
+static int hdcp2_close_session(struct intel_connector *connector)
 {
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct i915_hdcp_comp_master *comp;
+       struct i915_hdcp_master *arbiter;
        int ret;
 
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       comp = dev_priv->display.hdcp.master;
+       arbiter = dev_priv->display.hdcp.master;
 
-       if (!comp || !comp->ops) {
+       if (!arbiter || !arbiter->ops) {
                mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
                return -EINVAL;
        }
 
-       ret = comp->ops->close_hdcp_session(comp->mei_dev,
+       ret = arbiter->ops->close_hdcp_session(arbiter->hdcp_dev,
                                             &dig_port->hdcp_port_data);
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
 
@@ -1432,7 +1441,7 @@ static int hdcp2_close_mei_session(struct intel_connector *connector)
 
 static int hdcp2_deauthenticate_port(struct intel_connector *connector)
 {
-       return hdcp2_close_mei_session(connector);
+       return hdcp2_close_session(connector);
 }
 
 /* Authentication flow starts from here */
@@ -2142,8 +2151,8 @@ static int i915_hdcp_component_bind(struct device *i915_kdev,
 
        drm_dbg(&dev_priv->drm, "I915 HDCP comp bind\n");
        mutex_lock(&dev_priv->display.hdcp.comp_mutex);
-       dev_priv->display.hdcp.master = (struct i915_hdcp_comp_master *)data;
-       dev_priv->display.hdcp.master->mei_dev = mei_kdev;
+       dev_priv->display.hdcp.master = (struct i915_hdcp_master *)data;
+       dev_priv->display.hdcp.master->hdcp_dev = mei_kdev;
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
 
        return 0;
@@ -2160,30 +2169,30 @@ static void i915_hdcp_component_unbind(struct device *i915_kdev,
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
 }
 
-static const struct component_ops i915_hdcp_component_ops = {
+static const struct component_ops i915_hdcp_ops = {
        .bind   = i915_hdcp_component_bind,
        .unbind = i915_hdcp_component_unbind,
 };
 
-static enum mei_fw_ddi intel_get_mei_fw_ddi_index(enum port port)
+static enum hdcp_ddi intel_get_hdcp_ddi_index(enum port port)
 {
        switch (port) {
        case PORT_A:
-               return MEI_DDI_A;
+               return HDCP_DDI_A;
        case PORT_B ... PORT_F:
-               return (enum mei_fw_ddi)port;
+               return (enum hdcp_ddi)port;
        default:
-               return MEI_DDI_INVALID_PORT;
+               return HDCP_DDI_INVALID_PORT;
        }
 }
 
-static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
+static enum hdcp_transcoder intel_get_hdcp_transcoder(enum transcoder cpu_transcoder)
 {
        switch (cpu_transcoder) {
        case TRANSCODER_A ... TRANSCODER_D:
-               return (enum mei_fw_tc)(cpu_transcoder | 0x10);
+               return (enum hdcp_transcoder)(cpu_transcoder | 0x10);
        default: /* eDP, DSI TRANSCODERS are non HDCP capable */
-               return MEI_INVALID_TRANSCODER;
+               return HDCP_INVALID_TRANSCODER;
        }
 }
 
@@ -2197,20 +2206,20 @@ static int initialize_hdcp_port_data(struct intel_connector *connector,
        enum port port = dig_port->base.port;
 
        if (DISPLAY_VER(dev_priv) < 12)
-               data->fw_ddi = intel_get_mei_fw_ddi_index(port);
+               data->hdcp_ddi = intel_get_hdcp_ddi_index(port);
        else
                /*
-                * As per ME FW API expectation, for GEN 12+, fw_ddi is filled
+                * As per ME FW API expectation, for GEN 12+, hdcp_ddi is filled
                 * with zero(INVALID PORT index).
                 */
-               data->fw_ddi = MEI_DDI_INVALID_PORT;
+               data->hdcp_ddi = HDCP_DDI_INVALID_PORT;
 
        /*
-        * As associated transcoder is set and modified at modeset, here fw_tc
+        * As associated transcoder is set and modified at modeset, here hdcp_transcoder
         * is initialized to zero (invalid transcoder index). This will be
         * retained for <Gen12 forever.
         */
-       data->fw_tc = MEI_INVALID_TRANSCODER;
+       data->hdcp_transcoder = HDCP_INVALID_TRANSCODER;
 
        data->port_type = (u8)HDCP_PORT_TYPE_INTEGRATED;
        data->protocol = (u8)shim->protocol;
@@ -2232,6 +2241,9 @@ static int initialize_hdcp_port_data(struct intel_connector *connector,
 
 static bool is_hdcp2_supported(struct drm_i915_private *dev_priv)
 {
+       if (intel_hdcp_gsc_cs_required(dev_priv))
+               return true;
+
        if (!IS_ENABLED(CONFIG_INTEL_MEI_HDCP))
                return false;
 
@@ -2253,10 +2265,14 @@ void intel_hdcp_component_init(struct drm_i915_private *dev_priv)
 
        dev_priv->display.hdcp.comp_added = true;
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
-       ret = component_add_typed(dev_priv->drm.dev, &i915_hdcp_component_ops,
-                                 I915_COMPONENT_HDCP);
+       if (intel_hdcp_gsc_cs_required(dev_priv))
+               ret = intel_hdcp_gsc_init(dev_priv);
+       else
+               ret = component_add_typed(dev_priv->drm.dev, &i915_hdcp_ops,
+                                         I915_COMPONENT_HDCP);
+
        if (ret < 0) {
-               drm_dbg_kms(&dev_priv->drm, "Failed at component add(%d)\n",
+               drm_dbg_kms(&dev_priv->drm, "Failed at fw component add(%d)\n",
                            ret);
                mutex_lock(&dev_priv->display.hdcp.comp_mutex);
                dev_priv->display.hdcp.comp_added = false;
@@ -2347,7 +2363,8 @@ int intel_hdcp_enable(struct intel_connector *connector,
        }
 
        if (DISPLAY_VER(dev_priv) >= 12)
-               dig_port->hdcp_port_data.fw_tc = intel_get_mei_fw_tc(hdcp->cpu_transcoder);
+               dig_port->hdcp_port_data.hdcp_transcoder =
+                       intel_get_hdcp_transcoder(hdcp->cpu_transcoder);
 
        /*
         * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
@@ -2482,7 +2499,10 @@ void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
        dev_priv->display.hdcp.comp_added = false;
        mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
 
-       component_del(dev_priv->drm.dev, &i915_hdcp_component_ops);
+       if (intel_hdcp_gsc_cs_required(dev_priv))
+               intel_hdcp_gsc_fini(dev_priv);
+       else
+               component_del(dev_priv->drm.dev, &i915_hdcp_ops);
 }
 
 void intel_hdcp_cleanup(struct intel_connector *connector)
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c
new file mode 100644 (file)
index 0000000..7e52aea
--- /dev/null
@@ -0,0 +1,831 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2023, Intel Corporation.
+ */
+
+#include <drm/i915_hdcp_interface.h>
+
+#include "display/intel_hdcp_gsc.h"
+#include "gem/i915_gem_region.h"
+#include "gt/uc/intel_gsc_uc_heci_cmd_submit.h"
+#include "i915_drv.h"
+#include "i915_utils.h"
+
+bool intel_hdcp_gsc_cs_required(struct drm_i915_private *i915)
+{
+       return DISPLAY_VER(i915) >= 14;
+}
+
+static int
+gsc_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data,
+                         struct hdcp2_ake_init *ake_data)
+{
+       struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } };
+       struct wired_cmd_initiate_hdcp2_session_out
+                                               session_init_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !ake_data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       session_init_in.header.api_version = HDCP_API_VERSION;
+       session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION;
+       session_init_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       session_init_in.header.buffer_len =
+                               WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN;
+
+       session_init_in.port.integrated_port_type = data->port_type;
+       session_init_in.port.physical_port = (u8)data->hdcp_ddi;
+       session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+       session_init_in.protocol = data->protocol;
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_init_in,
+                                      sizeof(session_init_in),
+                                      (u8 *)&session_init_out,
+                                      sizeof(session_init_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (session_init_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n",
+                           WIRED_INITIATE_HDCP2_SESSION,
+                           session_init_out.header.status);
+               return -EIO;
+       }
+
+       ake_data->msg_id = HDCP_2_2_AKE_INIT;
+       ake_data->tx_caps = session_init_out.tx_caps;
+       memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN);
+
+       return 0;
+}
+
+static int
+gsc_hdcp_verify_receiver_cert_prepare_km(struct device *dev,
+                                        struct hdcp_port_data *data,
+                                        struct hdcp2_ake_send_cert *rx_cert,
+                                        bool *km_stored,
+                                        struct hdcp2_ake_no_stored_km
+                                                               *ek_pub_km,
+                                        size_t *msg_sz)
+{
+       struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } };
+       struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       verify_rxcert_in.header.api_version = HDCP_API_VERSION;
+       verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT;
+       verify_rxcert_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       verify_rxcert_in.header.buffer_len =
+                               WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN;
+
+       verify_rxcert_in.port.integrated_port_type = data->port_type;
+       verify_rxcert_in.port.physical_port = (u8)data->hdcp_ddi;
+       verify_rxcert_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       verify_rxcert_in.cert_rx = rx_cert->cert_rx;
+       memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN);
+       memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN);
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_rxcert_in,
+                                      sizeof(verify_rxcert_in),
+                                      (u8 *)&verify_rxcert_out,
+                                      sizeof(verify_rxcert_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed: %zd\n", byte);
+               return byte;
+       }
+
+       if (verify_rxcert_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n",
+                           WIRED_VERIFY_RECEIVER_CERT,
+                           verify_rxcert_out.header.status);
+               return -EIO;
+       }
+
+       *km_stored = !!verify_rxcert_out.km_stored;
+       if (verify_rxcert_out.km_stored) {
+               ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM;
+               *msg_sz = sizeof(struct hdcp2_ake_stored_km);
+       } else {
+               ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM;
+               *msg_sz = sizeof(struct hdcp2_ake_no_stored_km);
+       }
+
+       memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff,
+              sizeof(verify_rxcert_out.ekm_buff));
+
+       return 0;
+}
+
+static int
+gsc_hdcp_verify_hprime(struct device *dev, struct hdcp_port_data *data,
+                      struct hdcp2_ake_send_hprime *rx_hprime)
+{
+       struct wired_cmd_ake_send_hprime_in send_hprime_in = { { 0 } };
+       struct wired_cmd_ake_send_hprime_out send_hprime_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !rx_hprime)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       send_hprime_in.header.api_version = HDCP_API_VERSION;
+       send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME;
+       send_hprime_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN;
+
+       send_hprime_in.port.integrated_port_type = data->port_type;
+       send_hprime_in.port.physical_port = (u8)data->hdcp_ddi;
+       send_hprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       memcpy(send_hprime_in.h_prime, rx_hprime->h_prime,
+              HDCP_2_2_H_PRIME_LEN);
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&send_hprime_in,
+                                      sizeof(send_hprime_in),
+                                      (u8 *)&send_hprime_out,
+                                      sizeof(send_hprime_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (send_hprime_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n",
+                           WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+gsc_hdcp_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
+                           struct hdcp2_ake_send_pairing_info *pairing_info)
+{
+       struct wired_cmd_ake_send_pairing_info_in pairing_info_in = { { 0 } };
+       struct wired_cmd_ake_send_pairing_info_out pairing_info_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !pairing_info)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       pairing_info_in.header.api_version = HDCP_API_VERSION;
+       pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO;
+       pairing_info_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       pairing_info_in.header.buffer_len =
+                                       WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN;
+
+       pairing_info_in.port.integrated_port_type = data->port_type;
+       pairing_info_in.port.physical_port = (u8)data->hdcp_ddi;
+       pairing_info_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km,
+              HDCP_2_2_E_KH_KM_LEN);
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&pairing_info_in,
+                                      sizeof(pairing_info_in),
+                                      (u8 *)&pairing_info_out,
+                                      sizeof(pairing_info_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (pairing_info_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. Status: 0x%X\n",
+                           WIRED_AKE_SEND_PAIRING_INFO,
+                           pairing_info_out.header.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+gsc_hdcp_initiate_locality_check(struct device *dev,
+                                struct hdcp_port_data *data,
+                                struct hdcp2_lc_init *lc_init_data)
+{
+       struct wired_cmd_init_locality_check_in lc_init_in = { { 0 } };
+       struct wired_cmd_init_locality_check_out lc_init_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !lc_init_data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       lc_init_in.header.api_version = HDCP_API_VERSION;
+       lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK;
+       lc_init_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN;
+
+       lc_init_in.port.integrated_port_type = data->port_type;
+       lc_init_in.port.physical_port = (u8)data->hdcp_ddi;
+       lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&lc_init_in, sizeof(lc_init_in),
+                                      (u8 *)&lc_init_out, sizeof(lc_init_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (lc_init_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. status: 0x%X\n",
+                           WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status);
+               return -EIO;
+       }
+
+       lc_init_data->msg_id = HDCP_2_2_LC_INIT;
+       memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN);
+
+       return 0;
+}
+
+static int
+gsc_hdcp_verify_lprime(struct device *dev, struct hdcp_port_data *data,
+                      struct hdcp2_lc_send_lprime *rx_lprime)
+{
+       struct wired_cmd_validate_locality_in verify_lprime_in = { { 0 } };
+       struct wired_cmd_validate_locality_out verify_lprime_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !rx_lprime)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       verify_lprime_in.header.api_version = HDCP_API_VERSION;
+       verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY;
+       verify_lprime_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       verify_lprime_in.header.buffer_len =
+                                       WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN;
+
+       verify_lprime_in.port.integrated_port_type = data->port_type;
+       verify_lprime_in.port.physical_port = (u8)data->hdcp_ddi;
+       verify_lprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime,
+              HDCP_2_2_L_PRIME_LEN);
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_lprime_in,
+                                      sizeof(verify_lprime_in),
+                                      (u8 *)&verify_lprime_out,
+                                      sizeof(verify_lprime_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (verify_lprime_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n",
+                           WIRED_VALIDATE_LOCALITY,
+                           verify_lprime_out.header.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int gsc_hdcp_get_session_key(struct device *dev,
+                                   struct hdcp_port_data *data,
+                                   struct hdcp2_ske_send_eks *ske_data)
+{
+       struct wired_cmd_get_session_key_in get_skey_in = { { 0 } };
+       struct wired_cmd_get_session_key_out get_skey_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data || !ske_data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       get_skey_in.header.api_version = HDCP_API_VERSION;
+       get_skey_in.header.command_id = WIRED_GET_SESSION_KEY;
+       get_skey_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN;
+
+       get_skey_in.port.integrated_port_type = data->port_type;
+       get_skey_in.port.physical_port = (u8)data->hdcp_ddi;
+       get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&get_skey_in, sizeof(get_skey_in),
+                                      (u8 *)&get_skey_out, sizeof(get_skey_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (get_skey_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n",
+                           WIRED_GET_SESSION_KEY, get_skey_out.header.status);
+               return -EIO;
+       }
+
+       ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS;
+       memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks,
+              HDCP_2_2_E_DKEY_KS_LEN);
+       memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN);
+
+       return 0;
+}
+
+static int
+gsc_hdcp_repeater_check_flow_prepare_ack(struct device *dev,
+                                        struct hdcp_port_data *data,
+                                        struct hdcp2_rep_send_receiverid_list
+                                                       *rep_topology,
+                                        struct hdcp2_rep_send_ack
+                                                       *rep_send_ack)
+{
+       struct wired_cmd_verify_repeater_in verify_repeater_in = { { 0 } };
+       struct wired_cmd_verify_repeater_out verify_repeater_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !rep_topology || !rep_send_ack || !data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       verify_repeater_in.header.api_version = HDCP_API_VERSION;
+       verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER;
+       verify_repeater_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       verify_repeater_in.header.buffer_len =
+                                       WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN;
+
+       verify_repeater_in.port.integrated_port_type = data->port_type;
+       verify_repeater_in.port.physical_port = (u8)data->hdcp_ddi;
+       verify_repeater_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       memcpy(verify_repeater_in.rx_info, rep_topology->rx_info,
+              HDCP_2_2_RXINFO_LEN);
+       memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v,
+              HDCP_2_2_SEQ_NUM_LEN);
+       memcpy(verify_repeater_in.v_prime, rep_topology->v_prime,
+              HDCP_2_2_V_PRIME_HALF_LEN);
+       memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids,
+              HDCP_2_2_RECEIVER_IDS_MAX_LEN);
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_repeater_in,
+                                      sizeof(verify_repeater_in),
+                                      (u8 *)&verify_repeater_out,
+                                      sizeof(verify_repeater_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (verify_repeater_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n",
+                           WIRED_VERIFY_REPEATER,
+                           verify_repeater_out.header.status);
+               return -EIO;
+       }
+
+       memcpy(rep_send_ack->v, verify_repeater_out.v,
+              HDCP_2_2_V_PRIME_HALF_LEN);
+       rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK;
+
+       return 0;
+}
+
+static int gsc_hdcp_verify_mprime(struct device *dev,
+                                 struct hdcp_port_data *data,
+                                 struct hdcp2_rep_stream_ready *stream_ready)
+{
+       struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in;
+       struct wired_cmd_repeater_auth_stream_req_out
+                                       verify_mprime_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+       size_t cmd_size;
+
+       if (!dev || !stream_ready || !data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       cmd_size = struct_size(verify_mprime_in, streams, data->k);
+       if (cmd_size == SIZE_MAX)
+               return -EINVAL;
+
+       verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL);
+       if (!verify_mprime_in)
+               return -ENOMEM;
+
+       verify_mprime_in->header.api_version = HDCP_API_VERSION;
+       verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ;
+       verify_mprime_in->header.status = FW_HDCP_STATUS_SUCCESS;
+       verify_mprime_in->header.buffer_len = cmd_size  - sizeof(verify_mprime_in->header);
+
+       verify_mprime_in->port.integrated_port_type = data->port_type;
+       verify_mprime_in->port.physical_port = (u8)data->hdcp_ddi;
+       verify_mprime_in->port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN);
+       drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m);
+
+       memcpy(verify_mprime_in->streams, data->streams,
+              array_size(data->k, sizeof(*data->streams)));
+
+       verify_mprime_in->k = cpu_to_be16(data->k);
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)verify_mprime_in, cmd_size,
+                                      (u8 *)&verify_mprime_out,
+                                      sizeof(verify_mprime_out));
+       kfree(verify_mprime_in);
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (verify_mprime_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n",
+                           WIRED_REPEATER_AUTH_STREAM_REQ,
+                           verify_mprime_out.header.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int gsc_hdcp_enable_authentication(struct device *dev,
+                                         struct hdcp_port_data *data)
+{
+       struct wired_cmd_enable_auth_in enable_auth_in = { { 0 } };
+       struct wired_cmd_enable_auth_out enable_auth_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       enable_auth_in.header.api_version = HDCP_API_VERSION;
+       enable_auth_in.header.command_id = WIRED_ENABLE_AUTH;
+       enable_auth_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN;
+
+       enable_auth_in.port.integrated_port_type = data->port_type;
+       enable_auth_in.port.physical_port = (u8)data->hdcp_ddi;
+       enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+       enable_auth_in.stream_type = data->streams[0].stream_type;
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&enable_auth_in,
+                                      sizeof(enable_auth_in),
+                                      (u8 *)&enable_auth_out,
+                                      sizeof(enable_auth_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (enable_auth_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n",
+                           WIRED_ENABLE_AUTH, enable_auth_out.header.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+gsc_hdcp_close_session(struct device *dev, struct hdcp_port_data *data)
+{
+       struct wired_cmd_close_session_in session_close_in = { { 0 } };
+       struct wired_cmd_close_session_out session_close_out = { { 0 } };
+       struct drm_i915_private *i915;
+       ssize_t byte;
+
+       if (!dev || !data)
+               return -EINVAL;
+
+       i915 = kdev_to_i915(dev);
+       if (!i915) {
+               dev_err(dev, "DRM not initialized, aborting HDCP.\n");
+               return -ENODEV;
+       }
+
+       session_close_in.header.api_version = HDCP_API_VERSION;
+       session_close_in.header.command_id = WIRED_CLOSE_SESSION;
+       session_close_in.header.status = FW_HDCP_STATUS_SUCCESS;
+       session_close_in.header.buffer_len =
+                               WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN;
+
+       session_close_in.port.integrated_port_type = data->port_type;
+       session_close_in.port.physical_port = (u8)data->hdcp_ddi;
+       session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
+
+       byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_close_in,
+                                      sizeof(session_close_in),
+                                      (u8 *)&session_close_out,
+                                      sizeof(session_close_out));
+       if (byte < 0) {
+               drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
+               return byte;
+       }
+
+       if (session_close_out.header.status != FW_HDCP_STATUS_SUCCESS) {
+               drm_dbg_kms(&i915->drm, "Session Close Failed. status: 0x%X\n",
+                           session_close_out.header.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static const struct i915_hdcp_ops gsc_hdcp_ops = {
+       .initiate_hdcp2_session = gsc_hdcp_initiate_session,
+       .verify_receiver_cert_prepare_km =
+                               gsc_hdcp_verify_receiver_cert_prepare_km,
+       .verify_hprime = gsc_hdcp_verify_hprime,
+       .store_pairing_info = gsc_hdcp_store_pairing_info,
+       .initiate_locality_check = gsc_hdcp_initiate_locality_check,
+       .verify_lprime = gsc_hdcp_verify_lprime,
+       .get_session_key = gsc_hdcp_get_session_key,
+       .repeater_check_flow_prepare_ack =
+                               gsc_hdcp_repeater_check_flow_prepare_ack,
+       .verify_mprime = gsc_hdcp_verify_mprime,
+       .enable_hdcp_authentication = gsc_hdcp_enable_authentication,
+       .close_hdcp_session = gsc_hdcp_close_session,
+};
+
+/*This function helps allocate memory for the command that we will send to gsc cs */
+static int intel_hdcp_gsc_initialize_message(struct drm_i915_private *i915,
+                                            struct intel_hdcp_gsc_message *hdcp_message)
+{
+       struct intel_gt *gt = i915->media_gt;
+       struct drm_i915_gem_object *obj = NULL;
+       struct i915_vma *vma = NULL;
+       void *cmd;
+       int err;
+
+       /* allocate object of one page for HDCP command memory and store it */
+       obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
+
+       if (IS_ERR(obj)) {
+               drm_err(&i915->drm, "Failed to allocate HDCP streaming command!\n");
+               return PTR_ERR(obj);
+       }
+
+       cmd = i915_gem_object_pin_map_unlocked(obj, i915_coherent_map_type(i915, obj, true));
+       if (IS_ERR(cmd)) {
+               drm_err(&i915->drm, "Failed to map gsc message page!\n");
+               err = PTR_ERR(cmd);
+               goto out_unpin;
+       }
+
+       vma = i915_vma_instance(obj, &gt->ggtt->vm, NULL);
+       if (IS_ERR(vma)) {
+               err = PTR_ERR(vma);
+               goto out_unmap;
+       }
+
+       err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
+       if (err)
+               goto out_unmap;
+
+       memset(cmd, 0, obj->base.size);
+
+       hdcp_message->hdcp_cmd = cmd;
+       hdcp_message->vma = vma;
+
+       return 0;
+
+out_unmap:
+       i915_gem_object_unpin_map(obj);
+out_unpin:
+       i915_gem_object_put(obj);
+       return err;
+}
+
+static int intel_hdcp_gsc_hdcp2_init(struct drm_i915_private *i915)
+{
+       struct intel_hdcp_gsc_message *hdcp_message;
+       int ret;
+
+       hdcp_message = kzalloc(sizeof(*hdcp_message), GFP_KERNEL);
+
+       if (!hdcp_message)
+               return -ENOMEM;
+
+       /*
+        * NOTE: No need to lock the comp mutex here as it is already
+        * going to be taken before this function called
+        */
+       i915->display.hdcp.hdcp_message = hdcp_message;
+       ret = intel_hdcp_gsc_initialize_message(i915, hdcp_message);
+
+       if (ret)
+               drm_err(&i915->drm, "Could not initialize hdcp_message\n");
+
+       return ret;
+}
+
+static void intel_hdcp_gsc_free_message(struct drm_i915_private *i915)
+{
+       struct intel_hdcp_gsc_message *hdcp_message =
+                                       i915->display.hdcp.hdcp_message;
+
+       i915_vma_unpin_and_release(&hdcp_message->vma, I915_VMA_RELEASE_MAP);
+       kfree(hdcp_message);
+}
+
+int intel_hdcp_gsc_init(struct drm_i915_private *i915)
+{
+       struct i915_hdcp_master *data;
+       int ret;
+
+       data = kzalloc(sizeof(struct i915_hdcp_master), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       mutex_lock(&i915->display.hdcp.comp_mutex);
+       i915->display.hdcp.master = data;
+       i915->display.hdcp.master->hdcp_dev = i915->drm.dev;
+       i915->display.hdcp.master->ops = &gsc_hdcp_ops;
+       ret = intel_hdcp_gsc_hdcp2_init(i915);
+       mutex_unlock(&i915->display.hdcp.comp_mutex);
+
+       return ret;
+}
+
+void intel_hdcp_gsc_fini(struct drm_i915_private *i915)
+{
+       intel_hdcp_gsc_free_message(i915);
+       kfree(i915->display.hdcp.master);
+}
+
+static int intel_gsc_send_sync(struct drm_i915_private *i915,
+                              struct intel_gsc_mtl_header *header, u64 addr,
+                              size_t msg_out_len)
+{
+       struct intel_gt *gt = i915->media_gt;
+       int ret;
+
+       header->flags = 0;
+       ret = intel_gsc_uc_heci_cmd_submit_packet(&gt->uc.gsc, addr,
+                                                 header->message_size,
+                                                 addr,
+                                                 msg_out_len + sizeof(*header));
+       if (ret) {
+               drm_err(&i915->drm, "failed to send gsc HDCP msg (%d)\n", ret);
+               return ret;
+       }
+
+       /*
+        * Checking validity marker for memory sanity
+        */
+       if (header->validity_marker != GSC_HECI_VALIDITY_MARKER) {
+               drm_err(&i915->drm, "invalid validity marker\n");
+               return -EINVAL;
+       }
+
+       if (header->status != 0) {
+               drm_err(&i915->drm, "header status indicates error %d\n",
+                       header->status);
+               return -EINVAL;
+       }
+
+       if (header->flags & GSC_OUTFLAG_MSG_PENDING)
+               return -EAGAIN;
+
+       return 0;
+}
+
+/*
+ * This function can now be used for sending requests and will also handle
+ * receipt of reply messages hence no different function of message retrieval
+ * is required. We will initialize intel_hdcp_gsc_message structure then add
+ * gsc cs memory header as stated in specs after which the normal HDCP payload
+ * will follow
+ */
+ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in,
+                               size_t msg_in_len, u8 *msg_out,
+                               size_t msg_out_len)
+{
+       struct intel_gt *gt = i915->media_gt;
+       struct intel_gsc_mtl_header *header;
+       const size_t max_msg_size = PAGE_SIZE - sizeof(*header);
+       struct intel_hdcp_gsc_message *hdcp_message;
+       u64 addr, host_session_id;
+       u32 reply_size, msg_size;
+       int ret, tries = 0;
+
+       if (!intel_uc_uses_gsc_uc(&gt->uc))
+               return -ENODEV;
+
+       if (msg_in_len > max_msg_size || msg_out_len > max_msg_size)
+               return -ENOSPC;
+
+       hdcp_message = i915->display.hdcp.hdcp_message;
+       header = hdcp_message->hdcp_cmd;
+       addr = i915_ggtt_offset(hdcp_message->vma);
+
+       msg_size = msg_in_len + sizeof(*header);
+       memset(header, 0, msg_size);
+       get_random_bytes(&host_session_id, sizeof(u64));
+       intel_gsc_uc_heci_cmd_emit_mtl_header(header, HECI_MEADDRESS_HDCP,
+                                             msg_size, host_session_id);
+       memcpy(hdcp_message->hdcp_cmd + sizeof(*header), msg_in, msg_in_len);
+
+       /*
+        * Keep sending request in case the pending bit is set no need to add
+        * message handle as we are using same address hence loc. of header is
+        * same and it will contain the message handle. we will send the message
+        * 20 times each message 50 ms apart
+        */
+       do {
+               ret = intel_gsc_send_sync(i915, header, addr, msg_out_len);
+
+               /* Only try again if gsc says so */
+               if (ret != -EAGAIN)
+                       break;
+
+               msleep(50);
+
+       } while (++tries < 20);
+
+       if (ret)
+               goto err;
+
+       /* we use the same mem for the reply, so header is in the same loc */
+       reply_size = header->message_size - sizeof(*header);
+       if (reply_size > msg_out_len) {
+               drm_warn(&i915->drm, "caller with insufficient HDCP reply size %u (%d)\n",
+                        reply_size, (u32)msg_out_len);
+               reply_size = msg_out_len;
+       } else if (reply_size != msg_out_len) {
+               drm_dbg_kms(&i915->drm, "caller unexpected HCDP reply size %u (%d)\n",
+                           reply_size, (u32)msg_out_len);
+       }
+
+       memcpy(msg_out, hdcp_message->hdcp_cmd + sizeof(*header), msg_out_len);
+
+err:
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h
new file mode 100644 (file)
index 0000000..5cc9fd2
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_HDCP_GSC_H__
+#define __INTEL_HDCP_GSC_H__
+
+#include <linux/err.h>
+#include <linux/types.h>
+
+struct drm_i915_private;
+
+struct intel_hdcp_gsc_message {
+       struct i915_vma *vma;
+       void *hdcp_cmd;
+};
+
+bool intel_hdcp_gsc_cs_required(struct drm_i915_private *i915);
+ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in,
+                               size_t msg_in_len, u8 *msg_out,
+                               size_t msg_out_len);
+int intel_hdcp_gsc_init(struct drm_i915_private *i915);
+void intel_hdcp_gsc_fini(struct drm_i915_private *i915);
+
+#endif /* __INTEL_HDCP_GCS_H__ */
index 907ab7526cb47858b3357078ecb3f8c1122d10d3..b12900446828acf5871d044e6f56095394bb1f5e 100644 (file)
@@ -389,6 +389,13 @@ static void i915_hotplug_work_func(struct work_struct *work)
 
        spin_unlock_irq(&dev_priv->irq_lock);
 
+       /* Skip calling encode hotplug handlers if ignore long HPD set*/
+       if (dev_priv->display.hotplug.ignore_long_hpd) {
+               drm_dbg_kms(&dev_priv->drm, "Ignore HPD flag on - skip encoder hotplug handlers\n");
+               mutex_unlock(&dev_priv->drm.mode_config.mutex);
+               return;
+       }
+
        drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
        for_each_intel_connector_iter(connector, &conn_iter) {
                enum hpd_pin pin;
@@ -940,4 +947,6 @@ void intel_hpd_debugfs_register(struct drm_i915_private *i915)
                            i915, &i915_hpd_storm_ctl_fops);
        debugfs_create_file("i915_hpd_short_storm_ctl", 0644, minor->debugfs_root,
                            i915, &i915_hpd_short_storm_ctl_fops);
+       debugfs_create_bool("i915_ignore_long_hpd", 0644, minor->debugfs_root,
+                           &i915->display.hotplug.ignore_long_hpd);
 }
index 1d0c9e247c425b5a5832f3732b2c10741aee0e45..4558d02641fe1745a167700ca7f3a5edd25c8c5f 100644 (file)
@@ -26,6 +26,7 @@
 #include "intel_fifo_underrun.h"
 #include "intel_modeset_setup.h"
 #include "intel_pch_display.h"
+#include "intel_vblank.h"
 #include "intel_wm.h"
 #include "skl_watermark.h"
 
index b8dce0576512aab714d340e1a0e851f810102ca7..b7973a05d022d741f8d3286a2e120283360d89ca 100644 (file)
@@ -1159,13 +1159,10 @@ void intel_opregion_register(struct drm_i915_private *i915)
        intel_opregion_resume(i915);
 }
 
-void intel_opregion_resume(struct drm_i915_private *i915)
+static void intel_opregion_resume_display(struct drm_i915_private *i915)
 {
        struct intel_opregion *opregion = &i915->display.opregion;
 
-       if (!opregion->header)
-               return;
-
        if (opregion->acpi) {
                intel_didl_outputs(i915);
                intel_setup_cadls(i915);
@@ -1186,18 +1183,24 @@ void intel_opregion_resume(struct drm_i915_private *i915)
 
        /* Some platforms abuse the _DSM to enable MUX */
        intel_dsm_get_bios_data_funcs_supported(i915);
-
-       intel_opregion_notify_adapter(i915, PCI_D0);
 }
 
-void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state)
+void intel_opregion_resume(struct drm_i915_private *i915)
 {
        struct intel_opregion *opregion = &i915->display.opregion;
 
        if (!opregion->header)
                return;
 
-       intel_opregion_notify_adapter(i915, state);
+       if (HAS_DISPLAY(i915))
+               intel_opregion_resume_display(i915);
+
+       intel_opregion_notify_adapter(i915, PCI_D0);
+}
+
+static void intel_opregion_suspend_display(struct drm_i915_private *i915)
+{
+       struct intel_opregion *opregion = &i915->display.opregion;
 
        if (opregion->asle)
                opregion->asle->ardy = ASLE_ARDY_NOT_READY;
@@ -1208,6 +1211,19 @@ void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state)
                opregion->acpi->drdy = 0;
 }
 
+void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state)
+{
+       struct intel_opregion *opregion = &i915->display.opregion;
+
+       if (!opregion->header)
+               return;
+
+       intel_opregion_notify_adapter(i915, state);
+
+       if (HAS_DISPLAY(i915))
+               intel_opregion_suspend_display(i915);
+}
+
 void intel_opregion_unregister(struct drm_i915_private *i915)
 {
        struct intel_opregion *opregion = &i915->display.opregion;
@@ -1221,6 +1237,14 @@ void intel_opregion_unregister(struct drm_i915_private *i915)
                unregister_acpi_notifier(&opregion->acpi_notifier);
                opregion->acpi_notifier.notifier_call = NULL;
        }
+}
+
+void intel_opregion_cleanup(struct drm_i915_private *i915)
+{
+       struct intel_opregion *opregion = &i915->display.opregion;
+
+       if (!opregion->header)
+               return;
 
        /* just clear all opregion memory pointers now */
        memunmap(opregion->header);
index d02e6696a050e12dec491bd2674bdbda88f3cf28..fd2ea8ef0fa2093e9cfc7578f830f4c89eb8bd16 100644 (file)
@@ -60,6 +60,7 @@ struct intel_opregion {
 #ifdef CONFIG_ACPI
 
 int intel_opregion_setup(struct drm_i915_private *dev_priv);
+void intel_opregion_cleanup(struct drm_i915_private *i915);
 
 void intel_opregion_register(struct drm_i915_private *dev_priv);
 void intel_opregion_unregister(struct drm_i915_private *dev_priv);
@@ -85,6 +86,10 @@ static inline int intel_opregion_setup(struct drm_i915_private *dev_priv)
        return 0;
 }
 
+static inline void intel_opregion_cleanup(struct drm_i915_private *i915)
+{
+}
+
 static inline void intel_opregion_register(struct drm_i915_private *dev_priv)
 {
 }
index 44610b20cd293b25fd8cb87f31319f8dfb1c627e..31084d95711d12904a3d0d4520aa15572579f6d8 100644 (file)
@@ -2644,3 +2644,302 @@ void intel_psr_unlock(const struct intel_crtc_state *crtc_state)
                break;
        }
 }
+
+static void
+psr_source_status(struct intel_dp *intel_dp, struct seq_file *m)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       const char *status = "unknown";
+       u32 val, status_val;
+
+       if (intel_dp->psr.psr2_enabled) {
+               static const char * const live_status[] = {
+                       "IDLE",
+                       "CAPTURE",
+                       "CAPTURE_FS",
+                       "SLEEP",
+                       "BUFON_FW",
+                       "ML_UP",
+                       "SU_STANDBY",
+                       "FAST_SLEEP",
+                       "DEEP_SLEEP",
+                       "BUF_ON",
+                       "TG_ON"
+               };
+               val = intel_de_read(dev_priv,
+                                   EDP_PSR2_STATUS(intel_dp->psr.transcoder));
+               status_val = REG_FIELD_GET(EDP_PSR2_STATUS_STATE_MASK, val);
+               if (status_val < ARRAY_SIZE(live_status))
+                       status = live_status[status_val];
+       } else {
+               static const char * const live_status[] = {
+                       "IDLE",
+                       "SRDONACK",
+                       "SRDENT",
+                       "BUFOFF",
+                       "BUFON",
+                       "AUXACK",
+                       "SRDOFFACK",
+                       "SRDENT_ON",
+               };
+               val = intel_de_read(dev_priv,
+                                   EDP_PSR_STATUS(intel_dp->psr.transcoder));
+               status_val = (val & EDP_PSR_STATUS_STATE_MASK) >>
+                             EDP_PSR_STATUS_STATE_SHIFT;
+               if (status_val < ARRAY_SIZE(live_status))
+                       status = live_status[status_val];
+       }
+
+       seq_printf(m, "Source PSR status: %s [0x%08x]\n", status, val);
+}
+
+static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_psr *psr = &intel_dp->psr;
+       intel_wakeref_t wakeref;
+       const char *status;
+       bool enabled;
+       u32 val;
+
+       seq_printf(m, "Sink support: %s", str_yes_no(psr->sink_support));
+       if (psr->sink_support)
+               seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]);
+       seq_puts(m, "\n");
+
+       if (!psr->sink_support)
+               return 0;
+
+       wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
+       mutex_lock(&psr->lock);
+
+       if (psr->enabled)
+               status = psr->psr2_enabled ? "PSR2 enabled" : "PSR1 enabled";
+       else
+               status = "disabled";
+       seq_printf(m, "PSR mode: %s\n", status);
+
+       if (!psr->enabled) {
+               seq_printf(m, "PSR sink not reliable: %s\n",
+                          str_yes_no(psr->sink_not_reliable));
+
+               goto unlock;
+       }
+
+       if (psr->psr2_enabled) {
+               val = intel_de_read(dev_priv,
+                                   EDP_PSR2_CTL(intel_dp->psr.transcoder));
+               enabled = val & EDP_PSR2_ENABLE;
+       } else {
+               val = intel_de_read(dev_priv,
+                                   EDP_PSR_CTL(intel_dp->psr.transcoder));
+               enabled = val & EDP_PSR_ENABLE;
+       }
+       seq_printf(m, "Source PSR ctl: %s [0x%08x]\n",
+                  str_enabled_disabled(enabled), val);
+       psr_source_status(intel_dp, m);
+       seq_printf(m, "Busy frontbuffer bits: 0x%08x\n",
+                  psr->busy_frontbuffer_bits);
+
+       /*
+        * SKL+ Perf counter is reset to 0 everytime DC state is entered
+        */
+       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+               val = intel_de_read(dev_priv,
+                                   EDP_PSR_PERF_CNT(intel_dp->psr.transcoder));
+               val &= EDP_PSR_PERF_CNT_MASK;
+               seq_printf(m, "Performance counter: %u\n", val);
+       }
+
+       if (psr->debug & I915_PSR_DEBUG_IRQ) {
+               seq_printf(m, "Last attempted entry at: %lld\n",
+                          psr->last_entry_attempt);
+               seq_printf(m, "Last exit at: %lld\n", psr->last_exit);
+       }
+
+       if (psr->psr2_enabled) {
+               u32 su_frames_val[3];
+               int frame;
+
+               /*
+                * Reading all 3 registers before hand to minimize crossing a
+                * frame boundary between register reads
+                */
+               for (frame = 0; frame < PSR2_SU_STATUS_FRAMES; frame += 3) {
+                       val = intel_de_read(dev_priv,
+                                           PSR2_SU_STATUS(intel_dp->psr.transcoder, frame));
+                       su_frames_val[frame / 3] = val;
+               }
+
+               seq_puts(m, "Frame:\tPSR2 SU blocks:\n");
+
+               for (frame = 0; frame < PSR2_SU_STATUS_FRAMES; frame++) {
+                       u32 su_blocks;
+
+                       su_blocks = su_frames_val[frame / 3] &
+                                   PSR2_SU_STATUS_MASK(frame);
+                       su_blocks = su_blocks >> PSR2_SU_STATUS_SHIFT(frame);
+                       seq_printf(m, "%d\t%d\n", frame, su_blocks);
+               }
+
+               seq_printf(m, "PSR2 selective fetch: %s\n",
+                          str_enabled_disabled(psr->psr2_sel_fetch_enabled));
+       }
+
+unlock:
+       mutex_unlock(&psr->lock);
+       intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
+
+       return 0;
+}
+
+static int i915_edp_psr_status_show(struct seq_file *m, void *data)
+{
+       struct drm_i915_private *dev_priv = m->private;
+       struct intel_dp *intel_dp = NULL;
+       struct intel_encoder *encoder;
+
+       if (!HAS_PSR(dev_priv))
+               return -ENODEV;
+
+       /* Find the first EDP which supports PSR */
+       for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
+               intel_dp = enc_to_intel_dp(encoder);
+               break;
+       }
+
+       if (!intel_dp)
+               return -ENODEV;
+
+       return intel_psr_status(m, intel_dp);
+}
+DEFINE_SHOW_ATTRIBUTE(i915_edp_psr_status);
+
+static int
+i915_edp_psr_debug_set(void *data, u64 val)
+{
+       struct drm_i915_private *dev_priv = data;
+       struct intel_encoder *encoder;
+       intel_wakeref_t wakeref;
+       int ret = -ENODEV;
+
+       if (!HAS_PSR(dev_priv))
+               return ret;
+
+       for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+               drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val);
+
+               wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
+
+               // TODO: split to each transcoder's PSR debug state
+               ret = intel_psr_debug_set(intel_dp, val);
+
+               intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
+       }
+
+       return ret;
+}
+
+static int
+i915_edp_psr_debug_get(void *data, u64 *val)
+{
+       struct drm_i915_private *dev_priv = data;
+       struct intel_encoder *encoder;
+
+       if (!HAS_PSR(dev_priv))
+               return -ENODEV;
+
+       for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+               // TODO: split to each transcoder's PSR debug state
+               *val = READ_ONCE(intel_dp->psr.debug);
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops,
+                       i915_edp_psr_debug_get, i915_edp_psr_debug_set,
+                       "%llu\n");
+
+void intel_psr_debugfs_register(struct drm_i915_private *i915)
+{
+       struct drm_minor *minor = i915->drm.primary;
+
+       debugfs_create_file("i915_edp_psr_debug", 0644, minor->debugfs_root,
+                           i915, &i915_edp_psr_debug_fops);
+
+       debugfs_create_file("i915_edp_psr_status", 0444, minor->debugfs_root,
+                           i915, &i915_edp_psr_status_fops);
+}
+
+static int i915_psr_sink_status_show(struct seq_file *m, void *data)
+{
+       struct intel_connector *connector = m->private;
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       static const char * const sink_status[] = {
+               "inactive",
+               "transition to active, capture and display",
+               "active, display from RFB",
+               "active, capture and display on sink device timings",
+               "transition to inactive, capture and display, timing re-sync",
+               "reserved",
+               "reserved",
+               "sink internal error",
+       };
+       const char *str;
+       int ret;
+       u8 val;
+
+       if (!CAN_PSR(intel_dp)) {
+               seq_puts(m, "PSR Unsupported\n");
+               return -ENODEV;
+       }
+
+       if (connector->base.status != connector_status_connected)
+               return -ENODEV;
+
+       ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val);
+       if (ret != 1)
+               return ret < 0 ? ret : -EIO;
+
+       val &= DP_PSR_SINK_STATE_MASK;
+       if (val < ARRAY_SIZE(sink_status))
+               str = sink_status[val];
+       else
+               str = "unknown";
+
+       seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, str);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status);
+
+static int i915_psr_status_show(struct seq_file *m, void *data)
+{
+       struct intel_connector *connector = m->private;
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+
+       return intel_psr_status(m, intel_dp);
+}
+DEFINE_SHOW_ATTRIBUTE(i915_psr_status);
+
+void intel_psr_connector_debugfs_add(struct intel_connector *connector)
+{
+       struct drm_i915_private *i915 = to_i915(connector->base.dev);
+       struct dentry *root = connector->base.debugfs_entry;
+
+       if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
+               return;
+
+       debugfs_create_file("i915_psr_sink_status", 0444, root,
+                           connector, &i915_psr_sink_status_fops);
+
+       if (HAS_PSR(i915))
+               debugfs_create_file("i915_psr_status", 0444, root,
+                                   connector, &i915_psr_status_fops);
+}
index 7a38a9e7fa5bea3b9ead841f41f66cf64f3d7470..0b95e8aa615f20a566f5410fe513e0aa3beae5f7 100644 (file)
@@ -13,6 +13,7 @@ struct drm_connector;
 struct drm_connector_state;
 struct drm_i915_private;
 struct intel_atomic_state;
+struct intel_connector;
 struct intel_crtc;
 struct intel_crtc_state;
 struct intel_dp;
@@ -61,5 +62,7 @@ void intel_psr_resume(struct intel_dp *intel_dp);
 
 void intel_psr_lock(const struct intel_crtc_state *crtc_state);
 void intel_psr_unlock(const struct intel_crtc_state *crtc_state);
+void intel_psr_connector_debugfs_add(struct intel_connector *connector);
+void intel_psr_debugfs_register(struct drm_i915_private *i915);
 
 #endif /* __INTEL_PSR_H__ */
index a16e56a60c305d2882bc64f23d996c1eef82e384..25034bbf14456b11f535ac47629b8714a4c5a812 100644 (file)
 
 #include <linux/string_helpers.h>
 
-#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_blend.h>
 #include <drm/drm_color_mgmt.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_damage_helper.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_rect.h>
 
 #include "i915_drv.h"
 #include "i915_reg.h"
-#include "i915_vgpu.h"
 #include "i9xx_plane.h"
 #include "intel_atomic_plane.h"
-#include "intel_crtc.h"
 #include "intel_de.h"
 #include "intel_display_types.h"
 #include "intel_fb.h"
-#include "intel_frontbuffer.h"
 #include "intel_sprite.h"
-#include "intel_vrr.h"
-
-int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
-{
-       struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
-       const struct drm_framebuffer *fb = plane_state->hw.fb;
-       struct drm_rect *src = &plane_state->uapi.src;
-       u32 src_x, src_y, src_w, src_h, hsub, vsub;
-       bool rotated = drm_rotation_90_or_270(plane_state->hw.rotation);
-
-       /*
-        * FIXME hsub/vsub vs. block size is a mess. Pre-tgl CCS
-        * abuses hsub/vsub so we can't use them here. But as they
-        * are limited to 32bpp RGB formats we don't actually need
-        * to check anything.
-        */
-       if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-           fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS)
-               return 0;
-
-       /*
-        * Hardware doesn't handle subpixel coordinates.
-        * Adjust to (macro)pixel boundary, but be careful not to
-        * increase the source viewport size, because that could
-        * push the downscaling factor out of bounds.
-        */
-       src_x = src->x1 >> 16;
-       src_w = drm_rect_width(src) >> 16;
-       src_y = src->y1 >> 16;
-       src_h = drm_rect_height(src) >> 16;
-
-       drm_rect_init(src, src_x << 16, src_y << 16,
-                     src_w << 16, src_h << 16);
-
-       if (fb->format->format == DRM_FORMAT_RGB565 && rotated) {
-               hsub = 2;
-               vsub = 2;
-       } else {
-               hsub = fb->format->hsub;
-               vsub = fb->format->vsub;
-       }
-
-       if (rotated)
-               hsub = vsub = max(hsub, vsub);
-
-       if (src_x % hsub || src_w % hsub) {
-               drm_dbg_kms(&i915->drm, "src x/w (%u, %u) must be a multiple of %u (rotated: %s)\n",
-                           src_x, src_w, hsub, str_yes_no(rotated));
-               return -EINVAL;
-       }
-
-       if (src_y % vsub || src_h % vsub) {
-               drm_dbg_kms(&i915->drm, "src y/h (%u, %u) must be a multiple of %u (rotated: %s)\n",
-                           src_y, src_h, vsub, str_yes_no(rotated));
-               return -EINVAL;
-       }
-
-       return 0;
-}
 
 static void i9xx_plane_linear_gamma(u16 gamma[8])
 {
@@ -1449,124 +1384,6 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state,
        return 0;
 }
 
-static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv)
-{
-       return DISPLAY_VER(dev_priv) >= 9;
-}
-
-static void intel_plane_set_ckey(struct intel_plane_state *plane_state,
-                                const struct drm_intel_sprite_colorkey *set)
-{
-       struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
-       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-
-       *key = *set;
-
-       /*
-        * We want src key enabled on the
-        * sprite and not on the primary.
-        */
-       if (plane->id == PLANE_PRIMARY &&
-           set->flags & I915_SET_COLORKEY_SOURCE)
-               key->flags = 0;
-
-       /*
-        * On SKL+ we want dst key enabled on
-        * the primary and not on the sprite.
-        */
-       if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_PRIMARY &&
-           set->flags & I915_SET_COLORKEY_DESTINATION)
-               key->flags = 0;
-}
-
-int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_intel_sprite_colorkey *set = data;
-       struct drm_plane *plane;
-       struct drm_plane_state *plane_state;
-       struct drm_atomic_state *state;
-       struct drm_modeset_acquire_ctx ctx;
-       int ret = 0;
-
-       /* ignore the pointless "none" flag */
-       set->flags &= ~I915_SET_COLORKEY_NONE;
-
-       if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
-               return -EINVAL;
-
-       /* Make sure we don't try to enable both src & dest simultaneously */
-       if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
-               return -EINVAL;
-
-       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-           set->flags & I915_SET_COLORKEY_DESTINATION)
-               return -EINVAL;
-
-       plane = drm_plane_find(dev, file_priv, set->plane_id);
-       if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
-               return -ENOENT;
-
-       /*
-        * SKL+ only plane 2 can do destination keying against plane 1.
-        * Also multiple planes can't do destination keying on the same
-        * pipe simultaneously.
-        */
-       if (DISPLAY_VER(dev_priv) >= 9 &&
-           to_intel_plane(plane)->id >= PLANE_SPRITE1 &&
-           set->flags & I915_SET_COLORKEY_DESTINATION)
-               return -EINVAL;
-
-       drm_modeset_acquire_init(&ctx, 0);
-
-       state = drm_atomic_state_alloc(plane->dev);
-       if (!state) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       state->acquire_ctx = &ctx;
-
-       while (1) {
-               plane_state = drm_atomic_get_plane_state(state, plane);
-               ret = PTR_ERR_OR_ZERO(plane_state);
-               if (!ret)
-                       intel_plane_set_ckey(to_intel_plane_state(plane_state), set);
-
-               /*
-                * On some platforms we have to configure
-                * the dst colorkey on the primary plane.
-                */
-               if (!ret && has_dst_key_in_primary_plane(dev_priv)) {
-                       struct intel_crtc *crtc =
-                               intel_crtc_for_pipe(dev_priv,
-                                                   to_intel_plane(plane)->pipe);
-
-                       plane_state = drm_atomic_get_plane_state(state,
-                                                                crtc->base.primary);
-                       ret = PTR_ERR_OR_ZERO(plane_state);
-                       if (!ret)
-                               intel_plane_set_ckey(to_intel_plane_state(plane_state), set);
-               }
-
-               if (!ret)
-                       ret = drm_atomic_commit(state);
-
-               if (ret != -EDEADLK)
-                       break;
-
-               drm_atomic_state_clear(state);
-               drm_modeset_backoff(&ctx);
-       }
-
-       drm_atomic_state_put(state);
-out:
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-       return ret;
-}
-
 static const u32 g4x_sprite_formats[] = {
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_YUYV,
diff --git a/drivers/gpu/drm/i915/display/intel_sprite_uapi.c b/drivers/gpu/drm/i915/display/intel_sprite_uapi.c
new file mode 100644 (file)
index 0000000..70a3910
--- /dev/null
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "intel_crtc.h"
+#include "intel_display_types.h"
+#include "intel_sprite_uapi.h"
+
+static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv)
+{
+       return DISPLAY_VER(dev_priv) >= 9;
+}
+
+static void intel_plane_set_ckey(struct intel_plane_state *plane_state,
+                                const struct drm_intel_sprite_colorkey *set)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
+
+       *key = *set;
+
+       /*
+        * We want src key enabled on the
+        * sprite and not on the primary.
+        */
+       if (plane->id == PLANE_PRIMARY &&
+           set->flags & I915_SET_COLORKEY_SOURCE)
+               key->flags = 0;
+
+       /*
+        * On SKL+ we want dst key enabled on
+        * the primary and not on the sprite.
+        */
+       if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_PRIMARY &&
+           set->flags & I915_SET_COLORKEY_DESTINATION)
+               key->flags = 0;
+}
+
+int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_intel_sprite_colorkey *set = data;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
+       struct drm_atomic_state *state;
+       struct drm_modeset_acquire_ctx ctx;
+       int ret = 0;
+
+       /* ignore the pointless "none" flag */
+       set->flags &= ~I915_SET_COLORKEY_NONE;
+
+       if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
+               return -EINVAL;
+
+       /* Make sure we don't try to enable both src & dest simultaneously */
+       if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
+               return -EINVAL;
+
+       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
+           set->flags & I915_SET_COLORKEY_DESTINATION)
+               return -EINVAL;
+
+       plane = drm_plane_find(dev, file_priv, set->plane_id);
+       if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
+               return -ENOENT;
+
+       /*
+        * SKL+ only plane 2 can do destination keying against plane 1.
+        * Also multiple planes can't do destination keying on the same
+        * pipe simultaneously.
+        */
+       if (DISPLAY_VER(dev_priv) >= 9 &&
+           to_intel_plane(plane)->id >= PLANE_SPRITE1 &&
+           set->flags & I915_SET_COLORKEY_DESTINATION)
+               return -EINVAL;
+
+       drm_modeset_acquire_init(&ctx, 0);
+
+       state = drm_atomic_state_alloc(plane->dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       state->acquire_ctx = &ctx;
+
+       while (1) {
+               plane_state = drm_atomic_get_plane_state(state, plane);
+               ret = PTR_ERR_OR_ZERO(plane_state);
+               if (!ret)
+                       intel_plane_set_ckey(to_intel_plane_state(plane_state), set);
+
+               /*
+                * On some platforms we have to configure
+                * the dst colorkey on the primary plane.
+                */
+               if (!ret && has_dst_key_in_primary_plane(dev_priv)) {
+                       struct intel_crtc *crtc =
+                               intel_crtc_for_pipe(dev_priv,
+                                                   to_intel_plane(plane)->pipe);
+
+                       plane_state = drm_atomic_get_plane_state(state,
+                                                                crtc->base.primary);
+                       ret = PTR_ERR_OR_ZERO(plane_state);
+                       if (!ret)
+                               intel_plane_set_ckey(to_intel_plane_state(plane_state), set);
+               }
+
+               if (!ret)
+                       ret = drm_atomic_commit(state);
+
+               if (ret != -EDEADLK)
+                       break;
+
+               drm_atomic_state_clear(state);
+               drm_modeset_backoff(&ctx);
+       }
+
+       drm_atomic_state_put(state);
+out:
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_sprite_uapi.h b/drivers/gpu/drm/i915/display/intel_sprite_uapi.h
new file mode 100644 (file)
index 0000000..3eb5002
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_SPRITE_UAPI_H__
+#define __INTEL_SPRITE_UAPI_H__
+
+struct drm_device;
+struct drm_file;
+
+int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+
+#endif /* __INTEL_SPRITE_UAPI_H__ */
index f45328712bff1bd582dc8bf4ad2c825923c4cee9..bd8c9df5f98fedac98d217de83db5198986ff0c2 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "i915_drv.h"
 #include "i915_reg.h"
+#include "intel_ddi.h"
 #include "intel_de.h"
 #include "intel_display.h"
 #include "intel_display_power_map.h"
@@ -118,6 +119,24 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port)
        drm_WARN_ON(&i915->drm, !enabled);
 }
 
+static enum intel_display_power_domain
+tc_port_power_domain(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
+
+       return POWER_DOMAIN_PORT_DDI_LANES_TC1 + tc_port - TC_PORT_1;
+}
+
+static void
+assert_tc_port_power_enabled(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+
+       drm_WARN_ON(&i915->drm,
+                   !intel_display_power_is_enabled(i915, tc_port_power_domain(dig_port)));
+}
+
 u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
@@ -418,9 +437,9 @@ static bool icl_tc_phy_is_owned(struct intel_digital_port *dig_port)
        val = intel_de_read(i915, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia));
        if (val == 0xffffffff) {
                drm_dbg_kms(&i915->drm,
-                           "Port %s: PHY in TCCOLD, assume safe mode\n",
+                           "Port %s: PHY in TCCOLD, assume not owned\n",
                            dig_port->tc_port_name);
-               return true;
+               return false;
        }
 
        return val & DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx);
@@ -464,7 +483,8 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port,
        u32 live_status_mask;
        int max_lanes;
 
-       if (!tc_phy_status_complete(dig_port)) {
+       if (!tc_phy_status_complete(dig_port) &&
+           !drm_WARN_ON(&i915->drm, dig_port->tc_legacy_port)) {
                drm_dbg_kms(&i915->drm, "Port %s: PHY not ready\n",
                            dig_port->tc_port_name);
                goto out_set_tbt_alt_mode;
@@ -539,62 +559,171 @@ static void icl_tc_phy_disconnect(struct intel_digital_port *dig_port)
        }
 }
 
-static bool icl_tc_phy_is_connected(struct intel_digital_port *dig_port)
+static bool tc_phy_is_ready_and_owned(struct intel_digital_port *dig_port,
+                                     bool phy_is_ready, bool phy_is_owned)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
 
-       if (!tc_phy_status_complete(dig_port)) {
-               drm_dbg_kms(&i915->drm, "Port %s: PHY status not complete\n",
-                           dig_port->tc_port_name);
-               return dig_port->tc_mode == TC_PORT_TBT_ALT;
-       }
+       drm_WARN_ON(&i915->drm, phy_is_owned && !phy_is_ready);
+
+       return phy_is_ready && phy_is_owned;
+}
 
-       /* On ADL-P the PHY complete flag is set in TBT mode as well. */
-       if (IS_ALDERLAKE_P(i915) && dig_port->tc_mode == TC_PORT_TBT_ALT)
-               return true;
+static bool tc_phy_is_connected(struct intel_digital_port *dig_port,
+                               enum icl_port_dpll_id port_pll_type)
+{
+       struct intel_encoder *encoder = &dig_port->base;
+       struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       bool phy_is_ready = tc_phy_status_complete(dig_port);
+       bool phy_is_owned = tc_phy_is_owned(dig_port);
+       bool is_connected;
 
-       if (!tc_phy_is_owned(dig_port)) {
-               drm_dbg_kms(&i915->drm, "Port %s: PHY not owned\n",
-                           dig_port->tc_port_name);
+       if (tc_phy_is_ready_and_owned(dig_port, phy_is_ready, phy_is_owned))
+               is_connected = port_pll_type == ICL_PORT_DPLL_MG_PHY;
+       else
+               is_connected = port_pll_type == ICL_PORT_DPLL_DEFAULT;
 
-               return false;
+       drm_dbg_kms(&i915->drm,
+                   "Port %s: PHY connected: %s (ready: %s, owned: %s, pll_type: %s)\n",
+                   dig_port->tc_port_name,
+                   str_yes_no(is_connected),
+                   str_yes_no(phy_is_ready),
+                   str_yes_no(phy_is_owned),
+                   port_pll_type == ICL_PORT_DPLL_DEFAULT ? "tbt" : "non-tbt");
+
+       return is_connected;
+}
+
+static void tc_phy_wait_for_ready(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+
+       if (wait_for(tc_phy_status_complete(dig_port), 100))
+               drm_err(&i915->drm, "Port %s: timeout waiting for PHY ready\n",
+                       dig_port->tc_port_name);
+}
+
+static enum tc_port_mode
+hpd_mask_to_tc_mode(u32 live_status_mask)
+{
+       if (live_status_mask)
+               return fls(live_status_mask) - 1;
+
+       return TC_PORT_DISCONNECTED;
+}
+
+static enum tc_port_mode
+tc_phy_hpd_live_mode(struct intel_digital_port *dig_port)
+{
+       u32 live_status_mask = tc_port_live_status_mask(dig_port);
+
+       return hpd_mask_to_tc_mode(live_status_mask);
+}
+
+static enum tc_port_mode
+get_tc_mode_in_phy_owned_state(struct intel_digital_port *dig_port,
+                              enum tc_port_mode live_mode)
+{
+       switch (live_mode) {
+       case TC_PORT_LEGACY:
+       case TC_PORT_DP_ALT:
+               return live_mode;
+       default:
+               MISSING_CASE(live_mode);
+               fallthrough;
+       case TC_PORT_TBT_ALT:
+       case TC_PORT_DISCONNECTED:
+               if (dig_port->tc_legacy_port)
+                       return TC_PORT_LEGACY;
+               else
+                       return TC_PORT_DP_ALT;
        }
+}
 
-       return dig_port->tc_mode == TC_PORT_DP_ALT ||
-              dig_port->tc_mode == TC_PORT_LEGACY;
+static enum tc_port_mode
+get_tc_mode_in_phy_not_owned_state(struct intel_digital_port *dig_port,
+                                  enum tc_port_mode live_mode)
+{
+       switch (live_mode) {
+       case TC_PORT_LEGACY:
+               return TC_PORT_DISCONNECTED;
+       case TC_PORT_DP_ALT:
+       case TC_PORT_TBT_ALT:
+               return TC_PORT_TBT_ALT;
+       default:
+               MISSING_CASE(live_mode);
+               fallthrough;
+       case TC_PORT_DISCONNECTED:
+               if (dig_port->tc_legacy_port)
+                       return TC_PORT_DISCONNECTED;
+               else
+                       return TC_PORT_TBT_ALT;
+       }
 }
 
 static enum tc_port_mode
 intel_tc_port_get_current_mode(struct intel_digital_port *dig_port)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-       u32 live_status_mask = tc_port_live_status_mask(dig_port);
+       enum tc_port_mode live_mode = tc_phy_hpd_live_mode(dig_port);
+       bool phy_is_ready;
+       bool phy_is_owned;
        enum tc_port_mode mode;
 
-       if (!tc_phy_is_owned(dig_port) ||
-           drm_WARN_ON(&i915->drm, !tc_phy_status_complete(dig_port)))
-               return TC_PORT_TBT_ALT;
+       /*
+        * For legacy ports the IOM firmware initializes the PHY during boot-up
+        * and system resume whether or not a sink is connected. Wait here for
+        * the initialization to get ready.
+        */
+       if (dig_port->tc_legacy_port)
+               tc_phy_wait_for_ready(dig_port);
 
-       mode = dig_port->tc_legacy_port ? TC_PORT_LEGACY : TC_PORT_DP_ALT;
-       if (live_status_mask) {
-               enum tc_port_mode live_mode = fls(live_status_mask) - 1;
+       phy_is_ready = tc_phy_status_complete(dig_port);
+       phy_is_owned = tc_phy_is_owned(dig_port);
 
-               if (!drm_WARN_ON(&i915->drm, live_mode == TC_PORT_TBT_ALT))
-                       mode = live_mode;
+       if (!tc_phy_is_ready_and_owned(dig_port, phy_is_ready, phy_is_owned)) {
+               mode = get_tc_mode_in_phy_not_owned_state(dig_port, live_mode);
+       } else {
+               drm_WARN_ON(&i915->drm, live_mode == TC_PORT_TBT_ALT);
+               mode = get_tc_mode_in_phy_owned_state(dig_port, live_mode);
        }
 
+       drm_dbg_kms(&i915->drm,
+                   "Port %s: PHY mode: %s (ready: %s, owned: %s, HPD: %s)\n",
+                   dig_port->tc_port_name,
+                   tc_port_mode_name(mode),
+                   str_yes_no(phy_is_ready),
+                   str_yes_no(phy_is_owned),
+                   tc_port_mode_name(live_mode));
+
        return mode;
 }
 
+static enum tc_port_mode default_tc_mode(struct intel_digital_port *dig_port)
+{
+       if (dig_port->tc_legacy_port)
+               return TC_PORT_LEGACY;
+
+       return TC_PORT_TBT_ALT;
+}
+
+static enum tc_port_mode
+hpd_mask_to_target_mode(struct intel_digital_port *dig_port, u32 live_status_mask)
+{
+       enum tc_port_mode mode = hpd_mask_to_tc_mode(live_status_mask);
+
+       if (mode != TC_PORT_DISCONNECTED)
+               return mode;
+
+       return default_tc_mode(dig_port);
+}
+
 static enum tc_port_mode
 intel_tc_port_get_target_mode(struct intel_digital_port *dig_port)
 {
        u32 live_status_mask = tc_port_live_status_mask(dig_port);
 
-       if (live_status_mask)
-               return fls(live_status_mask) - 1;
-
-       return TC_PORT_TBT_ALT;
+       return hpd_mask_to_target_mode(dig_port, live_status_mask);
 }
 
 static void intel_tc_port_reset_mode(struct intel_digital_port *dig_port,
@@ -660,11 +789,24 @@ static void intel_tc_port_update_mode(struct intel_digital_port *dig_port,
        tc_cold_unblock(dig_port, domain, wref);
 }
 
-static void
-intel_tc_port_link_init_refcount(struct intel_digital_port *dig_port,
-                                int refcount)
+static void __intel_tc_port_get_link(struct intel_digital_port *dig_port)
+{
+       dig_port->tc_link_refcount++;
+}
+
+static void __intel_tc_port_put_link(struct intel_digital_port *dig_port)
+{
+       dig_port->tc_link_refcount--;
+}
+
+static bool tc_port_is_enabled(struct intel_digital_port *dig_port)
 {
-       dig_port->tc_link_refcount = refcount;
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+
+       assert_tc_port_power_enabled(dig_port);
+
+       return intel_de_read(i915, DDI_BUF_CTL(dig_port->base.port)) &
+              DDI_BUF_CTL_ENABLE;
 }
 
 /**
@@ -679,6 +821,7 @@ void intel_tc_port_init_mode(struct intel_digital_port *dig_port)
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
        intel_wakeref_t tc_cold_wref;
        enum intel_display_power_domain domain;
+       bool update_mode = false;
 
        mutex_lock(&dig_port->tc_lock);
 
@@ -689,63 +832,105 @@ void intel_tc_port_init_mode(struct intel_digital_port *dig_port)
        tc_cold_wref = tc_cold_block(dig_port, &domain);
 
        dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
+       /*
+        * Save the initial mode for the state check in
+        * intel_tc_port_sanitize_mode().
+        */
+       dig_port->tc_init_mode = dig_port->tc_mode;
+       if (dig_port->tc_mode != TC_PORT_DISCONNECTED)
+               dig_port->tc_lock_wakeref =
+                       tc_cold_block(dig_port, &dig_port->tc_lock_power_domain);
+
+       /*
+        * The PHY needs to be connected for AUX to work during HW readout and
+        * MST topology resume, but the PHY mode can only be changed if the
+        * port is disabled.
+        *
+        * An exception is the case where BIOS leaves the PHY incorrectly
+        * disconnected on an enabled legacy port. Work around that by
+        * connecting the PHY even though the port is enabled. This doesn't
+        * cause a problem as the PHY ownership state is ignored by the
+        * IOM/TCSS firmware (only display can own the PHY in that case).
+        */
+       if (!tc_port_is_enabled(dig_port)) {
+               update_mode = true;
+       } else if (dig_port->tc_mode == TC_PORT_DISCONNECTED) {
+               drm_WARN_ON(&i915->drm, !dig_port->tc_legacy_port);
+               drm_err(&i915->drm,
+                       "Port %s: PHY disconnected on enabled port, connecting it\n",
+                       dig_port->tc_port_name);
+               update_mode = true;
+       }
+
+       if (update_mode)
+               intel_tc_port_update_mode(dig_port, 1, false);
+
        /* Prevent changing dig_port->tc_mode until intel_tc_port_sanitize_mode() is called. */
-       intel_tc_port_link_init_refcount(dig_port, 1);
-       dig_port->tc_lock_wakeref = tc_cold_block(dig_port, &dig_port->tc_lock_power_domain);
+       __intel_tc_port_get_link(dig_port);
 
        tc_cold_unblock(dig_port, domain, tc_cold_wref);
 
-       drm_dbg_kms(&i915->drm, "Port %s: init mode (%s)\n",
-                   dig_port->tc_port_name,
-                   tc_port_mode_name(dig_port->tc_mode));
-
        mutex_unlock(&dig_port->tc_lock);
 }
 
+static bool tc_port_has_active_links(struct intel_digital_port *dig_port,
+                                    const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       enum icl_port_dpll_id pll_type = ICL_PORT_DPLL_DEFAULT;
+       int active_links = 0;
+
+       if (dig_port->dp.is_mst) {
+               /* TODO: get the PLL type for MST, once HW readout is done for it. */
+               active_links = intel_dp_mst_encoder_active_links(dig_port);
+       } else if (crtc_state && crtc_state->hw.active) {
+               pll_type = intel_ddi_port_pll_type(&dig_port->base, crtc_state);
+               active_links = 1;
+       }
+
+       if (active_links && !tc_phy_is_connected(dig_port, pll_type))
+               drm_err(&i915->drm,
+                       "Port %s: PHY disconnected with %d active link(s)\n",
+                       dig_port->tc_port_name, active_links);
+
+       return active_links;
+}
+
 /**
  * intel_tc_port_sanitize_mode: Sanitize the given port's TypeC mode
  * @dig_port: digital port
+ * @crtc_state: atomic state of CRTC connected to @dig_port
  *
  * Sanitize @dig_port's TypeC mode wrt. the encoder's state right after driver
  * loading and system resume:
  * If the encoder is enabled keep the TypeC mode/PHY connected state locked until
  * the encoder is disabled.
  * If the encoder is disabled make sure the PHY is disconnected.
+ * @crtc_state is valid if @dig_port is enabled, NULL otherwise.
  */
-void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port)
+void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port,
+                                const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-       struct intel_encoder *encoder = &dig_port->base;
-       int active_links = 0;
 
        mutex_lock(&dig_port->tc_lock);
 
-       if (dig_port->dp.is_mst)
-               active_links = intel_dp_mst_encoder_active_links(dig_port);
-       else if (encoder->base.crtc)
-               active_links = to_intel_crtc(encoder->base.crtc)->active;
-
        drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount != 1);
-       intel_tc_port_link_init_refcount(dig_port, active_links);
-
-       if (active_links) {
-               if (!icl_tc_phy_is_connected(dig_port))
-                       drm_dbg_kms(&i915->drm,
-                                   "Port %s: PHY disconnected with %d active link(s)\n",
-                                   dig_port->tc_port_name, active_links);
-       } else {
+       if (!tc_port_has_active_links(dig_port, crtc_state)) {
                /*
                 * TBT-alt is the default mode in any case the PHY ownership is not
                 * held (regardless of the sink's connected live state), so
                 * we'll just switch to disconnected mode from it here without
                 * a note.
                 */
-               if (dig_port->tc_mode != TC_PORT_TBT_ALT)
+               if (dig_port->tc_init_mode != TC_PORT_TBT_ALT &&
+                   dig_port->tc_init_mode != TC_PORT_DISCONNECTED)
                        drm_dbg_kms(&i915->drm,
                                    "Port %s: PHY left in %s mode on disabled port, disconnecting it\n",
                                    dig_port->tc_port_name,
-                                   tc_port_mode_name(dig_port->tc_mode));
+                                   tc_port_mode_name(dig_port->tc_init_mode));
                icl_tc_phy_disconnect(dig_port);
+               __intel_tc_port_put_link(dig_port);
 
                tc_cold_unblock(dig_port, dig_port->tc_lock_power_domain,
                                fetch_and_zero(&dig_port->tc_lock_wakeref));
@@ -768,16 +953,23 @@ void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port)
  * connected ports are usable, and avoids exposing to the users objects they
  * can't really use.
  */
+bool intel_tc_port_connected_locked(struct intel_encoder *encoder)
+{
+       struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+
+       drm_WARN_ON(&i915->drm, !intel_tc_port_ref_held(dig_port));
+
+       return tc_port_live_status_mask(dig_port) & BIT(dig_port->tc_mode);
+}
+
 bool intel_tc_port_connected(struct intel_encoder *encoder)
 {
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
        bool is_connected;
 
        intel_tc_port_lock(dig_port);
-
-       is_connected = tc_port_live_status_mask(dig_port) &
-                      BIT(dig_port->tc_mode);
-
+       is_connected = intel_tc_port_connected_locked(encoder);
        intel_tc_port_unlock(dig_port);
 
        return is_connected;
@@ -857,14 +1049,14 @@ void intel_tc_port_get_link(struct intel_digital_port *dig_port,
                            int required_lanes)
 {
        __intel_tc_port_lock(dig_port, required_lanes);
-       dig_port->tc_link_refcount++;
+       __intel_tc_port_get_link(dig_port);
        intel_tc_port_unlock(dig_port);
 }
 
 void intel_tc_port_put_link(struct intel_digital_port *dig_port)
 {
        intel_tc_port_lock(dig_port);
-       --dig_port->tc_link_refcount;
+       __intel_tc_port_put_link(dig_port);
        intel_tc_port_unlock(dig_port);
 
        /*
index d54082e2d5e8d75ea4a22929a525670961322d3f..79667d977508cfb99438586e87283113408d0ce3 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mutex.h>
 #include <linux/types.h>
 
+struct intel_crtc_state;
 struct intel_digital_port;
 struct intel_encoder;
 
@@ -17,6 +18,7 @@ bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port);
 bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port);
 
 bool intel_tc_port_connected(struct intel_encoder *encoder);
+bool intel_tc_port_connected_locked(struct intel_encoder *encoder);
 
 u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port);
 u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port);
@@ -25,7 +27,8 @@ void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
                                      int required_lanes);
 
 void intel_tc_port_init_mode(struct intel_digital_port *dig_port);
-void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port);
+void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port,
+                                const struct intel_crtc_state *crtc_state);
 void intel_tc_port_lock(struct intel_digital_port *dig_port);
 void intel_tc_port_unlock(struct intel_digital_port *dig_port);
 void intel_tc_port_flush_work(struct intel_digital_port *dig_port);
index 571f5dda1e66b65090eb6e155b16d8fd473770d1..f8bf9810527de8a1e10d542c8f6459233cc8807b 100644 (file)
@@ -8,6 +8,7 @@
 #include "intel_de.h"
 #include "intel_display_types.h"
 #include "intel_vblank.h"
+#include "intel_vrr.h"
 
 /*
  * This timing diagram depicts the video signal in and
@@ -439,3 +440,94 @@ void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
 {
        wait_for_pipe_scanline_moving(crtc, true);
 }
+
+static int intel_crtc_scanline_offset(const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+       const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+
+       /*
+        * The scanline counter increments at the leading edge of hsync.
+        *
+        * On most platforms it starts counting from vtotal-1 on the
+        * first active line. That means the scanline counter value is
+        * always one less than what we would expect. Ie. just after
+        * start of vblank, which also occurs at start of hsync (on the
+        * last active line), the scanline counter will read vblank_start-1.
+        *
+        * On gen2 the scanline counter starts counting from 1 instead
+        * of vtotal-1, so we have to subtract one (or rather add vtotal-1
+        * to keep the value positive), instead of adding one.
+        *
+        * On HSW+ the behaviour of the scanline counter depends on the output
+        * type. For DP ports it behaves like most other platforms, but on HDMI
+        * there's an extra 1 line difference. So we need to add two instead of
+        * one to the value.
+        *
+        * On VLV/CHV DSI the scanline counter would appear to increment
+        * approx. 1/3 of a scanline before start of vblank. Unfortunately
+        * that means we can't tell whether we're in vblank or not while
+        * we're on that particular line. We must still set scanline_offset
+        * to 1 so that the vblank timestamps come out correct when we query
+        * the scanline counter from within the vblank interrupt handler.
+        * However if queried just before the start of vblank we'll get an
+        * answer that's slightly in the future.
+        */
+       if (DISPLAY_VER(i915) == 2) {
+               int vtotal;
+
+               vtotal = adjusted_mode->crtc_vtotal;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       vtotal /= 2;
+
+               return vtotal - 1;
+       } else if (HAS_DDI(i915) && intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+               return 2;
+       } else {
+               return 1;
+       }
+}
+
+void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       struct drm_display_mode adjusted_mode;
+       int vmax_vblank_start = 0;
+       unsigned long irqflags;
+
+       drm_mode_init(&adjusted_mode, &crtc_state->hw.adjusted_mode);
+
+       if (crtc_state->vrr.enable) {
+               adjusted_mode.crtc_vtotal = crtc_state->vrr.vmax;
+               adjusted_mode.crtc_vblank_end = crtc_state->vrr.vmax;
+               adjusted_mode.crtc_vblank_start = intel_vrr_vmin_vblank_start(crtc_state);
+               vmax_vblank_start = intel_vrr_vmax_vblank_start(crtc_state);
+       }
+
+       /*
+        * Belts and suspenders locking to guarantee everyone sees 100%
+        * consistent state during fastset seamless refresh rate changes.
+        *
+        * vblank_time_lock takes care of all drm_vblank.c stuff, and
+        * uncore.lock takes care of __intel_get_crtc_scanline() which
+        * may get called elsewhere as well.
+        *
+        * TODO maybe just protect everything (including
+        * __intel_get_crtc_scanline()) with vblank_time_lock?
+        * Need to audit everything to make sure it's safe.
+        */
+       spin_lock_irqsave(&i915->drm.vblank_time_lock, irqflags);
+       spin_lock(&i915->uncore.lock);
+
+       drm_calc_timestamping_constants(&crtc->base, &adjusted_mode);
+
+       crtc->vmax_vblank_start = vmax_vblank_start;
+
+       crtc->mode_flags = crtc_state->mode_flags;
+
+       crtc->scanline_offset = intel_crtc_scanline_offset(crtc_state);
+
+       spin_unlock(&i915->uncore.lock);
+       spin_unlock_irqrestore(&i915->drm.vblank_time_lock, irqflags);
+}
index c9fea2c2a99073a8bceef0f871c273dc9baba4bf..0884db7e76ae04966151205b3fb4153a8100f4eb 100644 (file)
@@ -11,6 +11,7 @@
 
 struct drm_crtc;
 struct intel_crtc;
+struct intel_crtc_state;
 
 u32 i915_get_vblank_counter(struct drm_crtc *crtc);
 u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
@@ -19,5 +20,6 @@ bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
 int intel_get_crtc_scanline(struct intel_crtc *crtc);
 void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc);
 void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc);
+void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state);
 
 #endif /* __INTEL_VBLANK_H__ */
index ce55b8f09301ba50436251bb14d2d5918c3d2716..fd0065a46ec5f7e017900c2df3bb180974bbafc9 100644 (file)
@@ -17,7 +17,6 @@
 #include "intel_fb.h"
 #include "intel_fbc.h"
 #include "intel_psr.h"
-#include "intel_sprite.h"
 #include "skl_scaler.h"
 #include "skl_universal_plane.h"
 #include "skl_watermark.h"
index f0af997d2a23d509c35919587793141eab8b3eae..50a9a6adbe323557a5aa73cde098ecf7f3f8d957 100644 (file)
@@ -12,6 +12,7 @@
 #include "intel_atomic.h"
 #include "intel_atomic_plane.h"
 #include "intel_bw.h"
+#include "intel_crtc.h"
 #include "intel_de.h"
 #include "intel_display.h"
 #include "intel_display_power.h"
@@ -704,6 +705,28 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
                                 const struct skl_wm_level *result_prev,
                                 struct skl_wm_level *result /* out */);
 
+static unsigned int skl_wm_latency(struct drm_i915_private *i915, int level,
+                                  const struct skl_wm_params *wp)
+{
+       unsigned int latency = i915->display.wm.skl_latency[level];
+
+       if (latency == 0)
+               return 0;
+
+       /*
+        * WaIncreaseLatencyIPCEnabled: kbl,cfl
+        * Display WA #1141: kbl,cfl
+        */
+       if ((IS_KABYLAKE(i915) || IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) &&
+           skl_watermark_ipc_enabled(i915))
+               latency += 4;
+
+       if (skl_needs_memory_bw_wa(i915) && wp && wp->x_tiled)
+               latency += 15;
+
+       return latency;
+}
+
 static unsigned int
 skl_cursor_allocation(const struct intel_crtc_state *crtc_state,
                      int num_active)
@@ -723,7 +746,7 @@ skl_cursor_allocation(const struct intel_crtc_state *crtc_state,
        drm_WARN_ON(&i915->drm, ret);
 
        for (level = 0; level < i915->display.wm.num_levels; level++) {
-               unsigned int latency = i915->display.wm.skl_latency[level];
+               unsigned int latency = skl_wm_latency(i915, level, &wp);
 
                skl_compute_plane_wm(crtc_state, plane, level, latency, &wp, &wm, &wm);
                if (wm.min_ddb_alloc == U16_MAX)
@@ -1839,17 +1862,6 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
                return;
        }
 
-       /*
-        * WaIncreaseLatencyIPCEnabled: kbl,cfl
-        * Display WA #1141: kbl,cfl
-        */
-       if ((IS_KABYLAKE(i915) || IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) &&
-           skl_watermark_ipc_enabled(i915))
-               latency += 4;
-
-       if (skl_needs_memory_bw_wa(i915) && wp->x_tiled)
-               latency += 15;
-
        method1 = skl_wm_method1(i915, wp->plane_pixel_rate,
                                 wp->cpp, latency, wp->dbuf_block_size);
        method2 = skl_wm_method2(wp->plane_pixel_rate,
@@ -1976,7 +1988,7 @@ skl_compute_wm_levels(const struct intel_crtc_state *crtc_state,
 
        for (level = 0; level < i915->display.wm.num_levels; level++) {
                struct skl_wm_level *result = &levels[level];
-               unsigned int latency = i915->display.wm.skl_latency[level];
+               unsigned int latency = skl_wm_latency(i915, level, wm_params);
 
                skl_compute_plane_wm(crtc_state, plane, level, latency,
                                     wm_params, result_prev, result);
@@ -1996,7 +2008,8 @@ static void tgl_compute_sagv_wm(const struct intel_crtc_state *crtc_state,
        unsigned int latency = 0;
 
        if (i915->display.sagv.block_time_us)
-               latency = i915->display.sagv.block_time_us + i915->display.wm.skl_latency[0];
+               latency = i915->display.sagv.block_time_us +
+                       skl_wm_latency(i915, 0, wm_params);
 
        skl_compute_plane_wm(crtc_state, plane, 0, latency,
                             wm_params, &levels[0],
@@ -2188,6 +2201,119 @@ static int icl_build_plane_wm(struct intel_crtc_state *crtc_state,
        return 0;
 }
 
+static bool
+skl_is_vblank_too_short(const struct intel_crtc_state *crtc_state,
+                       int wm0_lines, int latency)
+{
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->hw.adjusted_mode;
+
+       /* FIXME missing scaler and DSC pre-fill time */
+       return crtc_state->framestart_delay +
+               intel_usecs_to_scanlines(adjusted_mode, latency) +
+               wm0_lines >
+               adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vblank_start;
+}
+
+static int skl_max_wm0_lines(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       enum plane_id plane_id;
+       int wm0_lines = 0;
+
+       for_each_plane_id_on_crtc(crtc, plane_id) {
+               const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+
+               /* FIXME what about !skl_wm_has_lines() platforms? */
+               wm0_lines = max_t(int, wm0_lines, wm->wm[0].lines);
+       }
+
+       return wm0_lines;
+}
+
+static int skl_max_wm_level_for_vblank(struct intel_crtc_state *crtc_state,
+                                      int wm0_lines)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       int level;
+
+       for (level = i915->display.wm.num_levels - 1; level >= 0; level--) {
+               int latency;
+
+               /* FIXME should we care about the latency w/a's? */
+               latency = skl_wm_latency(i915, level, NULL);
+               if (latency == 0)
+                       continue;
+
+               /* FIXME is it correct to use 0 latency for wm0 here? */
+               if (level == 0)
+                       latency = 0;
+
+               if (!skl_is_vblank_too_short(crtc_state, wm0_lines, latency))
+                       return level;
+       }
+
+       return -EINVAL;
+}
+
+static int skl_wm_check_vblank(struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       int wm0_lines, level;
+
+       if (!crtc_state->hw.active)
+               return 0;
+
+       wm0_lines = skl_max_wm0_lines(crtc_state);
+
+       level = skl_max_wm_level_for_vblank(crtc_state, wm0_lines);
+       if (level < 0)
+               return level;
+
+       /*
+        * FIXME PSR needs to toggle LATENCY_REPORTING_REMOVED_PIPE_*
+        * based on whether we're limited by the vblank duration.
+        *
+        * FIXME also related to skl+ w/a 1136 (also unimplemented as of
+        * now) perhaps?
+        */
+
+       for (level++; level < i915->display.wm.num_levels; level++) {
+               enum plane_id plane_id;
+
+               for_each_plane_id_on_crtc(crtc, plane_id) {
+                       struct skl_plane_wm *wm =
+                               &crtc_state->wm.skl.optimal.planes[plane_id];
+
+                       /*
+                        * FIXME just clear enable or flag the entire
+                        * thing as bad via min_ddb_alloc=U16_MAX?
+                        */
+                       wm->wm[level].enable = false;
+                       wm->uv_wm[level].enable = false;
+               }
+       }
+
+       if (DISPLAY_VER(i915) >= 12 &&
+           i915->display.sagv.block_time_us &&
+           skl_is_vblank_too_short(crtc_state, wm0_lines,
+                                   i915->display.sagv.block_time_us)) {
+               enum plane_id plane_id;
+
+               for_each_plane_id_on_crtc(crtc, plane_id) {
+                       struct skl_plane_wm *wm =
+                               &crtc_state->wm.skl.optimal.planes[plane_id];
+
+                       wm->sagv.wm0.enable = false;
+                       wm->sagv.trans_wm.enable = false;
+               }
+       }
+
+       return 0;
+}
+
 static int skl_build_pipe_wm(struct intel_atomic_state *state,
                             struct intel_crtc *crtc)
 {
@@ -2217,7 +2343,7 @@ static int skl_build_pipe_wm(struct intel_atomic_state *state,
 
        crtc_state->wm.skl.optimal = crtc_state->wm.skl.raw;
 
-       return 0;
+       return skl_wm_check_vblank(crtc_state);
 }
 
 static void skl_ddb_entry_write(struct drm_i915_private *i915,
index 8d2e6e151ba0ed752f819b7dd16d03d39365c5f6..028965ab442dc3f101b5ad3d81b5232dc31539cf 100644 (file)
@@ -1072,7 +1072,7 @@ static void bxt_dsi_get_pipe_config(struct intel_encoder *encoder,
        bpp = mipi_dsi_pixel_format_to_bpp(
                        pixel_format_from_register_bits(fmt));
 
-       pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
+       pipe_config->pipe_bpp = bdw_get_pipe_misc_bpp(crtc);
 
        /* Enable Frame time stamo based scanline reporting */
        pipe_config->mode_flags |=
index e10507fa71ce6389926790e3256c460e50e0368c..5d143e2a8db03ea60a509a2a7afb649638542720 100644 (file)
 #define GSC_FW_LOAD GSC_INSTR(1, 0, 2)
 #define   HECI1_FW_LIMIT_VALID (1 << 31)
 
+#define GSC_HECI_CMD_PKT GSC_INSTR(0, 0, 6)
+
 /*
  * Used to convert any address to canonical form.
  * Starting from gen8, some commands (e.g. STATE_BASE_ADDRESS,
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c
new file mode 100644 (file)
index 0000000..ea0da06
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "gt/intel_engine_pm.h"
+#include "gt/intel_gpu_commands.h"
+#include "gt/intel_gt.h"
+#include "gt/intel_ring.h"
+#include "intel_gsc_uc_heci_cmd_submit.h"
+
+struct gsc_heci_pkt {
+       u64 addr_in;
+       u32 size_in;
+       u64 addr_out;
+       u32 size_out;
+};
+
+static int emit_gsc_heci_pkt(struct i915_request *rq, struct gsc_heci_pkt *pkt)
+{
+       u32 *cs;
+
+       cs = intel_ring_begin(rq, 8);
+       if (IS_ERR(cs))
+               return PTR_ERR(cs);
+
+       *cs++ = GSC_HECI_CMD_PKT;
+       *cs++ = lower_32_bits(pkt->addr_in);
+       *cs++ = upper_32_bits(pkt->addr_in);
+       *cs++ = pkt->size_in;
+       *cs++ = lower_32_bits(pkt->addr_out);
+       *cs++ = upper_32_bits(pkt->addr_out);
+       *cs++ = pkt->size_out;
+       *cs++ = 0;
+
+       intel_ring_advance(rq, cs);
+
+       return 0;
+}
+
+int intel_gsc_uc_heci_cmd_submit_packet(struct intel_gsc_uc *gsc, u64 addr_in,
+                                       u32 size_in, u64 addr_out,
+                                       u32 size_out)
+{
+       struct intel_context *ce = gsc->ce;
+       struct i915_request *rq;
+       struct gsc_heci_pkt pkt = {
+       .addr_in = addr_in,
+       .size_in = size_in,
+       .addr_out = addr_out,
+       .size_out = size_out
+       };
+       int err;
+
+       if (!ce)
+               return -ENODEV;
+
+       rq = i915_request_create(ce);
+       if (IS_ERR(rq))
+               return PTR_ERR(rq);
+
+       if (ce->engine->emit_init_breadcrumb) {
+               err = ce->engine->emit_init_breadcrumb(rq);
+               if (err)
+                       goto out_rq;
+       }
+
+       err = emit_gsc_heci_pkt(rq, &pkt);
+
+       if (err)
+               goto out_rq;
+
+       err = ce->engine->emit_flush(rq, 0);
+
+out_rq:
+       i915_request_get(rq);
+
+       if (unlikely(err))
+               i915_request_set_error_once(rq, err);
+
+       i915_request_add(rq);
+
+       if (!err && i915_request_wait(rq, 0, msecs_to_jiffies(500)) < 0)
+               err = -ETIME;
+
+       i915_request_put(rq);
+
+       if (err)
+               drm_err(&gsc_uc_to_gt(gsc)->i915->drm,
+                       "Request submission for GSC heci cmd failed (%d)\n",
+                       err);
+
+       return err;
+}
+
+void intel_gsc_uc_heci_cmd_emit_mtl_header(struct intel_gsc_mtl_header *header,
+                                          u8 heci_client_id, u32 message_size,
+                                          u64 host_session_id)
+{
+       host_session_id &= ~HOST_SESSION_MASK;
+       if (heci_client_id == HECI_MEADDRESS_PXP)
+               host_session_id |= HOST_SESSION_PXP_SINGLE;
+
+       header->validity_marker = GSC_HECI_VALIDITY_MARKER;
+       header->heci_client_id = heci_client_id;
+       header->host_session_handle = host_session_id;
+       header->header_version = MTL_GSC_HEADER_VERSION;
+       header->message_size = message_size;
+}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h
new file mode 100644 (file)
index 0000000..3d56ae5
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _INTEL_GSC_UC_HECI_CMD_SUBMIT_H_
+#define _INTEL_GSC_UC_HECI_CMD_SUBMIT_H_
+
+#include <linux/types.h>
+
+struct intel_gsc_uc;
+struct intel_gsc_mtl_header {
+       u32 validity_marker;
+#define GSC_HECI_VALIDITY_MARKER 0xA578875A
+
+       u8 heci_client_id;
+#define HECI_MEADDRESS_PXP 17
+#define HECI_MEADDRESS_HDCP 18
+
+       u8 reserved1;
+
+       u16 header_version;
+#define MTL_GSC_HEADER_VERSION 1
+
+       /*
+        * FW allows host to decide host_session handle
+        * as it sees fit.
+        * For intertracebility reserving select bits(60-63)
+        * to differentiate caller-target subsystem
+        * 0000 - HDCP
+        * 0001 - PXP Single Session
+        */
+       u64 host_session_handle;
+#define HOST_SESSION_MASK      REG_GENMASK64(63, 60)
+#define HOST_SESSION_PXP_SINGLE BIT_ULL(60)
+       u64 gsc_message_handle;
+
+       u32 message_size; /* lower 20 bits only, upper 12 are reserved */
+
+       /*
+        * Flags mask:
+        * Bit 0: Pending
+        * Bit 1: Session Cleanup;
+        * Bits 2-15: Flags
+        * Bits 16-31: Extension Size
+        * According to internal spec flags are either input or output
+        * we distinguish the flags using OUTFLAG or INFLAG
+        */
+       u32 flags;
+#define GSC_OUTFLAG_MSG_PENDING        1
+
+       u32 status;
+} __packed;
+
+int intel_gsc_uc_heci_cmd_submit_packet(struct intel_gsc_uc *gsc,
+                                       u64 addr_in, u32 size_in,
+                                       u64 addr_out, u32 size_out);
+void intel_gsc_uc_heci_cmd_emit_mtl_header(struct intel_gsc_mtl_header *header,
+                                          u8 heci_client_id, u32 message_size,
+                                          u64 host_session_id);
+#endif
index a53fd339e2cc94ec65bce55422ae8b61ac71d0cc..da249337c23bdd5934bf9e97722df3b9e66bf9b0 100644 (file)
@@ -535,7 +535,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
 
        ret = i915_pcode_init(dev_priv);
        if (ret)
-               goto err_msi;
+               goto err_opregion;
 
        /*
         * Fill the dram structure to get the system dram info. This will be
@@ -556,6 +556,8 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
 
        return 0;
 
+err_opregion:
+       intel_opregion_cleanup(dev_priv);
 err_msi:
        if (pdev->msi_enabled)
                pci_disable_msi(pdev);
@@ -581,6 +583,8 @@ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv)
 
        i915_perf_fini(dev_priv);
 
+       intel_opregion_cleanup(dev_priv);
+
        if (pdev->msi_enabled)
                pci_disable_msi(pdev);
 
index 34b7d2ac33fb0c6e7a135568882ddda181bf3852..d22ffd7a32dc4961f1fdfab876dc4983d90de4d8 100644 (file)
  * GEN9 clock gating regs
  */
 #define GEN9_CLKGATE_DIS_0             _MMIO(0x46530)
-#define   DARBF_GATING_DIS             (1 << 27)
-#define   PWM2_GATING_DIS              (1 << 14)
-#define   PWM1_GATING_DIS              (1 << 13)
+#define   DARBF_GATING_DIS             REG_BIT(27)
+#define   MTL_PIPEDMC_GATING_DIS_A     REG_BIT(15)
+#define   MTL_PIPEDMC_GATING_DIS_B     REG_BIT(14)
+#define   PWM2_GATING_DIS              REG_BIT(14)
+#define   PWM1_GATING_DIS              REG_BIT(13)
 
 #define GEN9_CLKGATE_DIS_3             _MMIO(0x46538)
 #define   TGL_VRH_GATING_DIS           REG_BIT(31)
 
 #define _PIPE_MISC_A                   0x70030
 #define _PIPE_MISC_B                   0x71030
-#define   PIPEMISC_YUV420_ENABLE               REG_BIT(27) /* glk+ */
-#define   PIPEMISC_YUV420_MODE_FULL_BLEND      REG_BIT(26) /* glk+ */
-#define   PIPEMISC_HDR_MODE_PRECISION          REG_BIT(23) /* icl+ */
-#define   PIPEMISC_OUTPUT_COLORSPACE_YUV       REG_BIT(11)
-#define   PIPEMISC_PIXEL_ROUNDING_TRUNC                REG_BIT(8) /* tgl+ */
+#define   PIPE_MISC_YUV420_ENABLE              REG_BIT(27) /* glk+ */
+#define   PIPE_MISC_YUV420_MODE_FULL_BLEND     REG_BIT(26) /* glk+ */
+#define   PIPE_MISC_HDR_MODE_PRECISION         REG_BIT(23) /* icl+ */
+#define   PIPE_MISC_OUTPUT_COLORSPACE_YUV      REG_BIT(11)
+#define   PIPE_MISC_PIXEL_ROUNDING_TRUNC               REG_BIT(8) /* tgl+ */
 /*
  * For Display < 13, Bits 5-7 of PIPE MISC represent DITHER BPC with
  * valid values of: 6, 8, 10 BPC.
  * ADLP+, the bits 5-7 represent PORT OUTPUT BPC with valid values of:
  * 6, 8, 10, 12 BPC.
  */
-#define   PIPEMISC_BPC_MASK                    REG_GENMASK(7, 5)
-#define   PIPEMISC_BPC_8                       REG_FIELD_PREP(PIPEMISC_BPC_MASK, 0)
-#define   PIPEMISC_BPC_10                      REG_FIELD_PREP(PIPEMISC_BPC_MASK, 1)
-#define   PIPEMISC_BPC_6                       REG_FIELD_PREP(PIPEMISC_BPC_MASK, 2)
-#define   PIPEMISC_BPC_12_ADLP                 REG_FIELD_PREP(PIPEMISC_BPC_MASK, 4) /* adlp+ */
-#define   PIPEMISC_DITHER_ENABLE               REG_BIT(4)
-#define   PIPEMISC_DITHER_TYPE_MASK            REG_GENMASK(3, 2)
-#define   PIPEMISC_DITHER_TYPE_SP              REG_FIELD_PREP(PIPEMISC_DITHER_TYPE_MASK, 0)
-#define   PIPEMISC_DITHER_TYPE_ST1             REG_FIELD_PREP(PIPEMISC_DITHER_TYPE_MASK, 1)
-#define   PIPEMISC_DITHER_TYPE_ST2             REG_FIELD_PREP(PIPEMISC_DITHER_TYPE_MASK, 2)
-#define   PIPEMISC_DITHER_TYPE_TEMP            REG_FIELD_PREP(PIPEMISC_DITHER_TYPE_MASK, 3)
-#define PIPEMISC(pipe)                 _MMIO_PIPE2(pipe, _PIPE_MISC_A)
+#define   PIPE_MISC_BPC_MASK                   REG_GENMASK(7, 5)
+#define   PIPE_MISC_BPC_8                      REG_FIELD_PREP(PIPE_MISC_BPC_MASK, 0)
+#define   PIPE_MISC_BPC_10                     REG_FIELD_PREP(PIPE_MISC_BPC_MASK, 1)
+#define   PIPE_MISC_BPC_6                      REG_FIELD_PREP(PIPE_MISC_BPC_MASK, 2)
+#define   PIPE_MISC_BPC_12_ADLP                        REG_FIELD_PREP(PIPE_MISC_BPC_MASK, 4) /* adlp+ */
+#define   PIPE_MISC_DITHER_ENABLE              REG_BIT(4)
+#define   PIPE_MISC_DITHER_TYPE_MASK           REG_GENMASK(3, 2)
+#define   PIPE_MISC_DITHER_TYPE_SP             REG_FIELD_PREP(PIPE_MISC_DITHER_TYPE_MASK, 0)
+#define   PIPE_MISC_DITHER_TYPE_ST1            REG_FIELD_PREP(PIPE_MISC_DITHER_TYPE_MASK, 1)
+#define   PIPE_MISC_DITHER_TYPE_ST2            REG_FIELD_PREP(PIPE_MISC_DITHER_TYPE_MASK, 2)
+#define   PIPE_MISC_DITHER_TYPE_TEMP           REG_FIELD_PREP(PIPE_MISC_DITHER_TYPE_MASK, 3)
+#define PIPE_MISC(pipe)                        _MMIO_PIPE(pipe, _PIPE_MISC_A, _PIPE_MISC_B)
 
 #define _PIPE_MISC2_A                                  0x7002C
 #define _PIPE_MISC2_B                                  0x7102C
 #define   PIPE_MISC2_BUBBLE_COUNTER_MASK       REG_GENMASK(31, 24)
 #define   PIPE_MISC2_BUBBLE_COUNTER_SCALER_EN  REG_FIELD_PREP(PIPE_MISC2_BUBBLE_COUNTER_MASK, 80)
 #define   PIPE_MISC2_BUBBLE_COUNTER_SCALER_DIS REG_FIELD_PREP(PIPE_MISC2_BUBBLE_COUNTER_MASK, 20)
-#define PIPE_MISC2(pipe)                                       _MMIO_PIPE2(pipe, _PIPE_MISC2_A)
+#define   PIPE_MISC2_FLIP_INFO_PLANE_SEL_MASK          REG_GENMASK(2, 0) /* tgl+ */
+#define   PIPE_MISC2_FLIP_INFO_PLANE_SEL(plane_id)     REG_FIELD_PREP(PIPE_MISC2_FLIP_INFO_PLANE_SEL_MASK, (plane_id))
+#define PIPE_MISC2(pipe)               _MMIO_PIPE(pipe, _PIPE_MISC2_A, _PIPE_MISC2_B)
 
 /* Skylake+ pipe bottom (background) color */
 #define _SKL_BOTTOM_COLOR_A            0x70034
 #define   SP_CONST_ALPHA_ENABLE                REG_BIT(31)
 #define   SP_CONST_ALPHA_MASK          REG_GENMASK(7, 0)
 #define   SP_CONST_ALPHA(alpha)                REG_FIELD_PREP(SP_CONST_ALPHA_MASK, (alpha))
+#define _SPASURFLIVE           (VLV_DISPLAY_BASE + 0x721ac)
 #define _SPACLRC0              (VLV_DISPLAY_BASE + 0x721d0)
 #define   SP_CONTRAST_MASK             REG_GENMASK(26, 18)
 #define   SP_CONTRAST(x)               REG_FIELD_PREP(SP_CONTRAST_MASK, (x)) /* u3.6 */
 #define _SPBKEYMAXVAL          (VLV_DISPLAY_BASE + 0x722a0)
 #define _SPBTILEOFF            (VLV_DISPLAY_BASE + 0x722a4)
 #define _SPBCONSTALPHA         (VLV_DISPLAY_BASE + 0x722a8)
+#define _SPBSURFLIVE           (VLV_DISPLAY_BASE + 0x722ac)
 #define _SPBCLRC0              (VLV_DISPLAY_BASE + 0x722d0)
 #define _SPBCLRC1              (VLV_DISPLAY_BASE + 0x722d4)
 #define _SPBGAMC               (VLV_DISPLAY_BASE + 0x722e0)
 #define SPKEYMAXVAL(pipe, plane_id)    _MMIO_VLV_SPR((pipe), (plane_id), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
 #define SPTILEOFF(pipe, plane_id)      _MMIO_VLV_SPR((pipe), (plane_id), _SPATILEOFF, _SPBTILEOFF)
 #define SPCONSTALPHA(pipe, plane_id)   _MMIO_VLV_SPR((pipe), (plane_id), _SPACONSTALPHA, _SPBCONSTALPHA)
+#define SPSURFLIVE(pipe, plane_id)     _MMIO_VLV_SPR((pipe), (plane_id), _SPASURFLIVE, _SPBSURFLIVE)
 #define SPCLRC0(pipe, plane_id)                _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC0, _SPBCLRC0)
 #define SPCLRC1(pipe, plane_id)                _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC1, _SPBCLRC1)
 #define SPGAMC(pipe, plane_id, i)      _MMIO(_VLV_SPR((pipe), (plane_id), _SPAGAMC, _SPBGAMC) + (5 - (i)) * 4) /* 6 x u0.10 */
 #define _PLANE_KEYVAL_2_A                      0x70294
 #define _PLANE_KEYMSK_1_A                      0x70198
 #define _PLANE_KEYMSK_2_A                      0x70298
-#define  PLANE_KEYMSK_ALPHA_ENABLE             (1 << 31)
+#define   PLANE_KEYMSK_ALPHA_ENABLE            REG_BIT(31)
 #define _PLANE_KEYMAX_1_A                      0x701a0
 #define _PLANE_KEYMAX_2_A                      0x702a0
-#define  PLANE_KEYMAX_ALPHA(a)                 ((a) << 24)
+#define   PLANE_KEYMAX_ALPHA_MASK              REG_GENMASK(31, 24)
+#define   PLANE_KEYMAX_ALPHA(a)                        REG_FIELD_PREP(PLANE_KEYMAX_ALPHA_MASK, (a))
+#define _PLANE_SURFLIVE_1_A                    0x701ac
+#define _PLANE_SURFLIVE_2_A                    0x702ac
 #define _PLANE_CC_VAL_1_A                      0x701b4
 #define _PLANE_CC_VAL_2_A                      0x702b4
 #define _PLANE_AUX_DIST_1_A                    0x701c0
 #define PLANE_KEYMAX(pipe, plane)      \
        _MMIO_PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe))
 
+#define _PLANE_SURFLIVE_1_B                    0x711ac
+#define _PLANE_SURFLIVE_2_B                    0x712ac
+#define _PLANE_SURFLIVE_1(pipe)        _PIPE(pipe, _PLANE_SURFLIVE_1_A, _PLANE_SURFLIVE_1_B)
+#define _PLANE_SURFLIVE_2(pipe)        _PIPE(pipe, _PLANE_SURFLIVE_2_A, _PLANE_SURFLIVE_2_B)
+#define PLANE_SURFLIVE(pipe, plane)    \
+       _MMIO_PLANE(plane, _PLANE_SURFLIVE_1(pipe), _PLANE_SURFLIVE_2(pipe))
+
 #define _PLANE_BUF_CFG_1_B                     0x7127c
 #define _PLANE_BUF_CFG_2_B                     0x7137c
 /* skl+: 10 bits, icl+ 11 bits, adlp+ 12 bits */
@@ -7232,6 +7249,8 @@ enum skl_power_gate {
 #define  DC_STATE_DISABLE              0
 #define  DC_STATE_EN_DC3CO             REG_BIT(30)
 #define  DC_STATE_DC3CO_STATUS         REG_BIT(29)
+#define  HOLD_PHY_CLKREQ_PG1_LATCH     REG_BIT(21)
+#define  HOLD_PHY_PG1_LATCH            REG_BIT(20)
 #define  DC_STATE_EN_UPTO_DC5          (1 << 0)
 #define  DC_STATE_EN_DC9               (1 << 3)
 #define  DC_STATE_EN_UPTO_DC6          (2 << 0)
@@ -7541,9 +7560,29 @@ enum skl_power_gate {
 #define  GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_SHIFT  12
 #define  GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_MASK   (0xf << 12)
 
+/* g4x+, except vlv/chv! */
 #define _PIPE_FRMTMSTMP_A              0x70048
+#define _PIPE_FRMTMSTMP_B              0x71048
 #define PIPE_FRMTMSTMP(pipe)           \
-                       _MMIO_PIPE2(pipe, _PIPE_FRMTMSTMP_A)
+       _MMIO_PIPE(pipe, _PIPE_FRMTMSTMP_A, _PIPE_FRMTMSTMP_B)
+
+/* g4x+, except vlv/chv! */
+#define _PIPE_FLIPTMSTMP_A             0x7004C
+#define _PIPE_FLIPTMSTMP_B             0x7104C
+#define PIPE_FLIPTMSTMP(pipe)          \
+       _MMIO_PIPE(pipe, _PIPE_FLIPTMSTMP_A, _PIPE_FLIPTMSTMP_B)
+
+/* tgl+ */
+#define _PIPE_FLIPDONETMSTMP_A         0x70054
+#define _PIPE_FLIPDONETMSTMP_B         0x71054
+#define PIPE_FLIPDONETIMSTMP(pipe)     \
+       _MMIO_PIPE(pipe, _PIPE_FLIPDONETMSTMP_A, _PIPE_FLIPDONETMSTMP_B)
+
+#define _VLV_PIPE_MSA_MISC_A                   0x70048
+#define VLV_PIPE_MSA_MISC(pipe)                \
+                       _MMIO_PIPE2(pipe, _VLV_PIPE_MSA_MISC_A)
+#define   VLV_MSA_MISC1_HW_ENABLE                      REG_BIT(31)
+#define   VLV_MSA_MISC1_SW_S3D_MASK                    REG_GENMASK(2, 0) /* MSA MISC1 3:1 */
 
 #define GGC                            _MMIO(0x108040)
 #define   GMS_MASK                     REG_GENMASK(15, 8)
index 2b3fe469b3601a40a8492ec9fc91aa443278282e..091743e32e178c379ddb8f2a447bac571aab424f 100644 (file)
@@ -789,9 +789,9 @@ static int iterate_bdw_plus_mmio(struct intel_gvt_mmio_table_iter *iter)
        MMIO_RING_D(RING_REG);
 #undef RING_REG
 
-       MMIO_D(PIPEMISC(PIPE_A));
-       MMIO_D(PIPEMISC(PIPE_B));
-       MMIO_D(PIPEMISC(PIPE_C));
+       MMIO_D(PIPE_MISC(PIPE_A));
+       MMIO_D(PIPE_MISC(PIPE_B));
+       MMIO_D(PIPE_MISC(PIPE_C));
        MMIO_D(_MMIO(0x1c1d0));
        MMIO_D(GEN6_MBCUNIT_SNPCR);
        MMIO_D(GEN7_MISCCPCTL);
index e0dcd5c114db164ccf58dc218af0a4aa0a6e0cf4..7728fe6854762ec72d93e21c596c73cec3814ac1 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/component.h>
 #include <drm/drm_connector.h>
 #include <drm/i915_component.h>
-#include <drm/i915_mei_hdcp_interface.h>
+#include <drm/i915_hdcp_interface.h>
 
 #include "mei_hdcp.h"
 
@@ -52,13 +52,13 @@ mei_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data,
 
        session_init_in.header.api_version = HDCP_API_VERSION;
        session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION;
-       session_init_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       session_init_in.header.status = FW_HDCP_STATUS_SUCCESS;
        session_init_in.header.buffer_len =
                                WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN;
 
        session_init_in.port.integrated_port_type = data->port_type;
-       session_init_in.port.physical_port = (u8)data->fw_ddi;
-       session_init_in.port.attached_transcoder = (u8)data->fw_tc;
+       session_init_in.port.physical_port = (u8)data->hdcp_ddi;
+       session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
        session_init_in.protocol = data->protocol;
 
        byte = mei_cldev_send(cldev, (u8 *)&session_init_in,
@@ -75,7 +75,7 @@ mei_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data,
                return byte;
        }
 
-       if (session_init_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (session_init_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
                        WIRED_INITIATE_HDCP2_SESSION,
                        session_init_out.header.status);
@@ -122,13 +122,13 @@ mei_hdcp_verify_receiver_cert_prepare_km(struct device *dev,
 
        verify_rxcert_in.header.api_version = HDCP_API_VERSION;
        verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT;
-       verify_rxcert_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       verify_rxcert_in.header.status = FW_HDCP_STATUS_SUCCESS;
        verify_rxcert_in.header.buffer_len =
                                WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN;
 
        verify_rxcert_in.port.integrated_port_type = data->port_type;
-       verify_rxcert_in.port.physical_port = (u8)data->fw_ddi;
-       verify_rxcert_in.port.attached_transcoder = (u8)data->fw_tc;
+       verify_rxcert_in.port.physical_port = (u8)data->hdcp_ddi;
+       verify_rxcert_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        verify_rxcert_in.cert_rx = rx_cert->cert_rx;
        memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN);
@@ -148,7 +148,7 @@ mei_hdcp_verify_receiver_cert_prepare_km(struct device *dev,
                return byte;
        }
 
-       if (verify_rxcert_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (verify_rxcert_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
                        WIRED_VERIFY_RECEIVER_CERT,
                        verify_rxcert_out.header.status);
@@ -194,12 +194,12 @@ mei_hdcp_verify_hprime(struct device *dev, struct hdcp_port_data *data,
 
        send_hprime_in.header.api_version = HDCP_API_VERSION;
        send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME;
-       send_hprime_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       send_hprime_in.header.status = FW_HDCP_STATUS_SUCCESS;
        send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN;
 
        send_hprime_in.port.integrated_port_type = data->port_type;
-       send_hprime_in.port.physical_port = (u8)data->fw_ddi;
-       send_hprime_in.port.attached_transcoder = (u8)data->fw_tc;
+       send_hprime_in.port.physical_port = (u8)data->hdcp_ddi;
+       send_hprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        memcpy(send_hprime_in.h_prime, rx_hprime->h_prime,
               HDCP_2_2_H_PRIME_LEN);
@@ -218,7 +218,7 @@ mei_hdcp_verify_hprime(struct device *dev, struct hdcp_port_data *data,
                return byte;
        }
 
-       if (send_hprime_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (send_hprime_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
                        WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status);
                return -EIO;
@@ -251,13 +251,13 @@ mei_hdcp_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
 
        pairing_info_in.header.api_version = HDCP_API_VERSION;
        pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO;
-       pairing_info_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       pairing_info_in.header.status = FW_HDCP_STATUS_SUCCESS;
        pairing_info_in.header.buffer_len =
                                        WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN;
 
        pairing_info_in.port.integrated_port_type = data->port_type;
-       pairing_info_in.port.physical_port = (u8)data->fw_ddi;
-       pairing_info_in.port.attached_transcoder = (u8)data->fw_tc;
+       pairing_info_in.port.physical_port = (u8)data->hdcp_ddi;
+       pairing_info_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km,
               HDCP_2_2_E_KH_KM_LEN);
@@ -276,7 +276,7 @@ mei_hdcp_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
                return byte;
        }
 
-       if (pairing_info_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (pairing_info_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X failed. Status: 0x%X\n",
                        WIRED_AKE_SEND_PAIRING_INFO,
                        pairing_info_out.header.status);
@@ -311,12 +311,12 @@ mei_hdcp_initiate_locality_check(struct device *dev,
 
        lc_init_in.header.api_version = HDCP_API_VERSION;
        lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK;
-       lc_init_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       lc_init_in.header.status = FW_HDCP_STATUS_SUCCESS;
        lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN;
 
        lc_init_in.port.integrated_port_type = data->port_type;
-       lc_init_in.port.physical_port = (u8)data->fw_ddi;
-       lc_init_in.port.attached_transcoder = (u8)data->fw_tc;
+       lc_init_in.port.physical_port = (u8)data->hdcp_ddi;
+       lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        byte = mei_cldev_send(cldev, (u8 *)&lc_init_in, sizeof(lc_init_in));
        if (byte < 0) {
@@ -330,7 +330,7 @@ mei_hdcp_initiate_locality_check(struct device *dev,
                return byte;
        }
 
-       if (lc_init_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (lc_init_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X Failed. status: 0x%X\n",
                        WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status);
                return -EIO;
@@ -366,13 +366,13 @@ mei_hdcp_verify_lprime(struct device *dev, struct hdcp_port_data *data,
 
        verify_lprime_in.header.api_version = HDCP_API_VERSION;
        verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY;
-       verify_lprime_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       verify_lprime_in.header.status = FW_HDCP_STATUS_SUCCESS;
        verify_lprime_in.header.buffer_len =
                                        WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN;
 
        verify_lprime_in.port.integrated_port_type = data->port_type;
-       verify_lprime_in.port.physical_port = (u8)data->fw_ddi;
-       verify_lprime_in.port.attached_transcoder = (u8)data->fw_tc;
+       verify_lprime_in.port.physical_port = (u8)data->hdcp_ddi;
+       verify_lprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime,
               HDCP_2_2_L_PRIME_LEN);
@@ -391,7 +391,7 @@ mei_hdcp_verify_lprime(struct device *dev, struct hdcp_port_data *data,
                return byte;
        }
 
-       if (verify_lprime_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (verify_lprime_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
                        WIRED_VALIDATE_LOCALITY,
                        verify_lprime_out.header.status);
@@ -425,12 +425,12 @@ static int mei_hdcp_get_session_key(struct device *dev,
 
        get_skey_in.header.api_version = HDCP_API_VERSION;
        get_skey_in.header.command_id = WIRED_GET_SESSION_KEY;
-       get_skey_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       get_skey_in.header.status = FW_HDCP_STATUS_SUCCESS;
        get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN;
 
        get_skey_in.port.integrated_port_type = data->port_type;
-       get_skey_in.port.physical_port = (u8)data->fw_ddi;
-       get_skey_in.port.attached_transcoder = (u8)data->fw_tc;
+       get_skey_in.port.physical_port = (u8)data->hdcp_ddi;
+       get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        byte = mei_cldev_send(cldev, (u8 *)&get_skey_in, sizeof(get_skey_in));
        if (byte < 0) {
@@ -445,7 +445,7 @@ static int mei_hdcp_get_session_key(struct device *dev,
                return byte;
        }
 
-       if (get_skey_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (get_skey_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
                        WIRED_GET_SESSION_KEY, get_skey_out.header.status);
                return -EIO;
@@ -489,13 +489,13 @@ mei_hdcp_repeater_check_flow_prepare_ack(struct device *dev,
 
        verify_repeater_in.header.api_version = HDCP_API_VERSION;
        verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER;
-       verify_repeater_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       verify_repeater_in.header.status = FW_HDCP_STATUS_SUCCESS;
        verify_repeater_in.header.buffer_len =
                                        WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN;
 
        verify_repeater_in.port.integrated_port_type = data->port_type;
-       verify_repeater_in.port.physical_port = (u8)data->fw_ddi;
-       verify_repeater_in.port.attached_transcoder = (u8)data->fw_tc;
+       verify_repeater_in.port.physical_port = (u8)data->hdcp_ddi;
+       verify_repeater_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        memcpy(verify_repeater_in.rx_info, rep_topology->rx_info,
               HDCP_2_2_RXINFO_LEN);
@@ -520,7 +520,7 @@ mei_hdcp_repeater_check_flow_prepare_ack(struct device *dev,
                return byte;
        }
 
-       if (verify_repeater_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (verify_repeater_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
                        WIRED_VERIFY_REPEATER,
                        verify_repeater_out.header.status);
@@ -568,12 +568,12 @@ static int mei_hdcp_verify_mprime(struct device *dev,
 
        verify_mprime_in->header.api_version = HDCP_API_VERSION;
        verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ;
-       verify_mprime_in->header.status = ME_HDCP_STATUS_SUCCESS;
+       verify_mprime_in->header.status = FW_HDCP_STATUS_SUCCESS;
        verify_mprime_in->header.buffer_len = cmd_size  - sizeof(verify_mprime_in->header);
 
        verify_mprime_in->port.integrated_port_type = data->port_type;
-       verify_mprime_in->port.physical_port = (u8)data->fw_ddi;
-       verify_mprime_in->port.attached_transcoder = (u8)data->fw_tc;
+       verify_mprime_in->port.physical_port = (u8)data->hdcp_ddi;
+       verify_mprime_in->port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN);
        drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m);
@@ -597,7 +597,7 @@ static int mei_hdcp_verify_mprime(struct device *dev,
                return byte;
        }
 
-       if (verify_mprime_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (verify_mprime_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
                        WIRED_REPEATER_AUTH_STREAM_REQ,
                        verify_mprime_out.header.status);
@@ -630,12 +630,12 @@ static int mei_hdcp_enable_authentication(struct device *dev,
 
        enable_auth_in.header.api_version = HDCP_API_VERSION;
        enable_auth_in.header.command_id = WIRED_ENABLE_AUTH;
-       enable_auth_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       enable_auth_in.header.status = FW_HDCP_STATUS_SUCCESS;
        enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN;
 
        enable_auth_in.port.integrated_port_type = data->port_type;
-       enable_auth_in.port.physical_port = (u8)data->fw_ddi;
-       enable_auth_in.port.attached_transcoder = (u8)data->fw_tc;
+       enable_auth_in.port.physical_port = (u8)data->hdcp_ddi;
+       enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
        enable_auth_in.stream_type = data->streams[0].stream_type;
 
        byte = mei_cldev_send(cldev, (u8 *)&enable_auth_in,
@@ -652,7 +652,7 @@ static int mei_hdcp_enable_authentication(struct device *dev,
                return byte;
        }
 
-       if (enable_auth_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (enable_auth_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
                        WIRED_ENABLE_AUTH, enable_auth_out.header.status);
                return -EIO;
@@ -684,13 +684,13 @@ mei_hdcp_close_session(struct device *dev, struct hdcp_port_data *data)
 
        session_close_in.header.api_version = HDCP_API_VERSION;
        session_close_in.header.command_id = WIRED_CLOSE_SESSION;
-       session_close_in.header.status = ME_HDCP_STATUS_SUCCESS;
+       session_close_in.header.status = FW_HDCP_STATUS_SUCCESS;
        session_close_in.header.buffer_len =
                                WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN;
 
        session_close_in.port.integrated_port_type = data->port_type;
-       session_close_in.port.physical_port = (u8)data->fw_ddi;
-       session_close_in.port.attached_transcoder = (u8)data->fw_tc;
+       session_close_in.port.physical_port = (u8)data->hdcp_ddi;
+       session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
 
        byte = mei_cldev_send(cldev, (u8 *)&session_close_in,
                              sizeof(session_close_in));
@@ -706,7 +706,7 @@ mei_hdcp_close_session(struct device *dev, struct hdcp_port_data *data)
                return byte;
        }
 
-       if (session_close_out.header.status != ME_HDCP_STATUS_SUCCESS) {
+       if (session_close_out.header.status != FW_HDCP_STATUS_SUCCESS) {
                dev_dbg(dev, "Session Close Failed. status: 0x%X\n",
                        session_close_out.header.status);
                return -EIO;
@@ -715,7 +715,7 @@ mei_hdcp_close_session(struct device *dev, struct hdcp_port_data *data)
        return 0;
 }
 
-static const struct i915_hdcp_component_ops mei_hdcp_ops = {
+static const struct i915_hdcp_ops mei_hdcp_ops = {
        .owner = THIS_MODULE,
        .initiate_hdcp2_session = mei_hdcp_initiate_session,
        .verify_receiver_cert_prepare_km =
@@ -735,13 +735,12 @@ static const struct i915_hdcp_component_ops mei_hdcp_ops = {
 static int mei_component_master_bind(struct device *dev)
 {
        struct mei_cl_device *cldev = to_mei_cl_device(dev);
-       struct i915_hdcp_comp_master *comp_master =
-                                               mei_cldev_get_drvdata(cldev);
+       struct i915_hdcp_master *comp_master = mei_cldev_get_drvdata(cldev);
        int ret;
 
        dev_dbg(dev, "%s\n", __func__);
        comp_master->ops = &mei_hdcp_ops;
-       comp_master->mei_dev = dev;
+       comp_master->hdcp_dev = dev;
        ret = component_bind_all(dev, comp_master);
        if (ret < 0)
                return ret;
@@ -752,8 +751,7 @@ static int mei_component_master_bind(struct device *dev)
 static void mei_component_master_unbind(struct device *dev)
 {
        struct mei_cl_device *cldev = to_mei_cl_device(dev);
-       struct i915_hdcp_comp_master *comp_master =
-                                               mei_cldev_get_drvdata(cldev);
+       struct i915_hdcp_master *comp_master = mei_cldev_get_drvdata(cldev);
 
        dev_dbg(dev, "%s\n", __func__);
        component_unbind_all(dev, comp_master);
@@ -801,7 +799,7 @@ static int mei_hdcp_component_match(struct device *dev, int subcomponent,
 static int mei_hdcp_probe(struct mei_cl_device *cldev,
                          const struct mei_cl_device_id *id)
 {
-       struct i915_hdcp_comp_master *comp_master;
+       struct i915_hdcp_master *comp_master;
        struct component_match *master_match;
        int ret;
 
@@ -846,8 +844,7 @@ enable_err_exit:
 
 static void mei_hdcp_remove(struct mei_cl_device *cldev)
 {
-       struct i915_hdcp_comp_master *comp_master =
-                                               mei_cldev_get_drvdata(cldev);
+       struct i915_hdcp_master *comp_master = mei_cldev_get_drvdata(cldev);
        int ret;
 
        component_master_del(&cldev->dev, &mei_component_master_ops);
index ca09c8f83d6b921046c9202a52003ac71fc05b9c..0683d83ec17a4c0dfcc22ebe43f0e69363ab12a8 100644 (file)
 
 #include <drm/display/drm_hdcp.h>
 
-/* me_hdcp_status: Enumeration of all HDCP Status Codes */
-enum me_hdcp_status {
-       ME_HDCP_STATUS_SUCCESS                  = 0x0000,
-
-       /* WiDi Generic Status Codes */
-       ME_HDCP_STATUS_INTERNAL_ERROR           = 0x1000,
-       ME_HDCP_STATUS_UNKNOWN_ERROR            = 0x1001,
-       ME_HDCP_STATUS_INCORRECT_API_VERSION    = 0x1002,
-       ME_HDCP_STATUS_INVALID_FUNCTION         = 0x1003,
-       ME_HDCP_STATUS_INVALID_BUFFER_LENGTH    = 0x1004,
-       ME_HDCP_STATUS_INVALID_PARAMS           = 0x1005,
-       ME_HDCP_STATUS_AUTHENTICATION_FAILED    = 0x1006,
-
-       /* WiDi Status Codes */
-       ME_HDCP_INVALID_SESSION_STATE           = 0x6000,
-       ME_HDCP_SRM_FRAGMENT_UNEXPECTED         = 0x6001,
-       ME_HDCP_SRM_INVALID_LENGTH              = 0x6002,
-       ME_HDCP_SRM_FRAGMENT_OFFSET_INVALID     = 0x6003,
-       ME_HDCP_SRM_VERIFICATION_FAILED         = 0x6004,
-       ME_HDCP_SRM_VERSION_TOO_OLD             = 0x6005,
-       ME_HDCP_RX_CERT_VERIFICATION_FAILED     = 0x6006,
-       ME_HDCP_RX_REVOKED                      = 0x6007,
-       ME_HDCP_H_VERIFICATION_FAILED           = 0x6008,
-       ME_HDCP_REPEATER_CHECK_UNEXPECTED       = 0x6009,
-       ME_HDCP_TOPOLOGY_MAX_EXCEEDED           = 0x600A,
-       ME_HDCP_V_VERIFICATION_FAILED           = 0x600B,
-       ME_HDCP_L_VERIFICATION_FAILED           = 0x600C,
-       ME_HDCP_STREAM_KEY_ALLOC_FAILED         = 0x600D,
-       ME_HDCP_BASE_KEY_RESET_FAILED           = 0x600E,
-       ME_HDCP_NONCE_GENERATION_FAILED         = 0x600F,
-       ME_HDCP_STATUS_INVALID_E_KEY_STATE      = 0x6010,
-       ME_HDCP_STATUS_INVALID_CS_ICV           = 0x6011,
-       ME_HDCP_STATUS_INVALID_KB_KEY_STATE     = 0x6012,
-       ME_HDCP_STATUS_INVALID_PAVP_MODE_ICV    = 0x6013,
-       ME_HDCP_STATUS_INVALID_PAVP_MODE        = 0x6014,
-       ME_HDCP_STATUS_LC_MAX_ATTEMPTS          = 0x6015,
-
-       /* New status for HDCP 2.1 */
-       ME_HDCP_STATUS_MISMATCH_IN_M            = 0x6016,
-
-       /* New status code for HDCP 2.2 Rx */
-       ME_HDCP_STATUS_RX_PROV_NOT_ALLOWED      = 0x6017,
-       ME_HDCP_STATUS_RX_PROV_WRONG_SUBJECT    = 0x6018,
-       ME_HDCP_RX_NEEDS_PROVISIONING           = 0x6019,
-       ME_HDCP_BKSV_ICV_AUTH_FAILED            = 0x6020,
-       ME_HDCP_STATUS_INVALID_STREAM_ID        = 0x6021,
-       ME_HDCP_STATUS_CHAIN_NOT_INITIALIZED    = 0x6022,
-       ME_HDCP_FAIL_NOT_EXPECTED               = 0x6023,
-       ME_HDCP_FAIL_HDCP_OFF                   = 0x6024,
-       ME_HDCP_FAIL_INVALID_PAVP_MEMORY_MODE   = 0x6025,
-       ME_HDCP_FAIL_AES_ECB_FAILURE            = 0x6026,
-       ME_HDCP_FEATURE_NOT_SUPPORTED           = 0x6027,
-       ME_HDCP_DMA_READ_ERROR                  = 0x6028,
-       ME_HDCP_DMA_WRITE_ERROR                 = 0x6029,
-       ME_HDCP_FAIL_INVALID_PACKET_SIZE        = 0x6030,
-       ME_HDCP_H264_PARSING_ERROR              = 0x6031,
-       ME_HDCP_HDCP2_ERRATA_VIDEO_VIOLATION    = 0x6032,
-       ME_HDCP_HDCP2_ERRATA_AUDIO_VIOLATION    = 0x6033,
-       ME_HDCP_TX_ACTIVE_ERROR                 = 0x6034,
-       ME_HDCP_MODE_CHANGE_ERROR               = 0x6035,
-       ME_HDCP_STREAM_TYPE_ERROR               = 0x6036,
-       ME_HDCP_STREAM_MANAGE_NOT_POSSIBLE      = 0x6037,
-
-       ME_HDCP_STATUS_PORT_INVALID_COMMAND     = 0x6038,
-       ME_HDCP_STATUS_UNSUPPORTED_PROTOCOL     = 0x6039,
-       ME_HDCP_STATUS_INVALID_PORT_INDEX       = 0x603a,
-       ME_HDCP_STATUS_TX_AUTH_NEEDED           = 0x603b,
-       ME_HDCP_STATUS_NOT_INTEGRATED_PORT      = 0x603c,
-       ME_HDCP_STATUS_SESSION_MAX_REACHED      = 0x603d,
-
-       /* hdcp capable bit is not set in rx_caps(error is unique to DP) */
-       ME_HDCP_STATUS_NOT_HDCP_CAPABLE         = 0x6041,
-
-       ME_HDCP_STATUS_INVALID_STREAM_COUNT     = 0x6042,
-};
-
-#define HDCP_API_VERSION                               0x00010000
-
-#define HDCP_M_LEN                                     16
-#define HDCP_KH_LEN                                    16
-
-/* Payload Buffer size(Excluding Header) for CMDs and corresponding response */
-/* Wired_Tx_AKE  */
-#define        WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN     (4 + 1)
-#define        WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_OUT    (4 + 8 + 3)
-
-#define        WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN       (4 + 522 + 8 + 3)
-#define        WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_MIN_OUT  (4 + 1 + 3 + 16 + 16)
-#define        WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_MAX_OUT  (4 + 1 + 3 + 128)
-
-#define        WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN            (4 + 32)
-#define        WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_OUT           (4)
-
-#define        WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN          (4 + 16)
-#define        WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_OUT         (4)
-
-#define        WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN              (4)
-#define        WIRED_CMD_BUF_LEN_CLOSE_SESSION_OUT             (4)
-
-/* Wired_Tx_LC */
-#define        WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN        (4)
-#define        WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_OUT       (4 + 8)
-
-#define        WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN          (4 + 32)
-#define        WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_OUT         (4)
-
-/* Wired_Tx_SKE */
-#define        WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN            (4)
-#define        WIRED_CMD_BUF_LEN_GET_SESSION_KEY_OUT           (4 + 16 + 8)
-
-/* Wired_Tx_SKE */
-#define        WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN                (4 + 1)
-#define        WIRED_CMD_BUF_LEN_ENABLE_AUTH_OUT               (4)
-
-/* Wired_Tx_Repeater */
-#define        WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN            (4 + 2 + 3 + 16 + 155)
-#define        WIRED_CMD_BUF_LEN_VERIFY_REPEATER_OUT           (4 + 1 + 16)
-
-#define        WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN       (4 + 3 + \
-                                                               32 + 2 + 2)
-
-#define        WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_OUT          (4)
-
-/* hdcp_command_id: Enumeration of all WIRED HDCP Command IDs */
-enum hdcp_command_id {
-       _WIDI_COMMAND_BASE              = 0x00030000,
-       WIDI_INITIATE_HDCP2_SESSION     = _WIDI_COMMAND_BASE,
-       HDCP_GET_SRM_STATUS,
-       HDCP_SEND_SRM_FRAGMENT,
-
-       /* The wired HDCP Tx commands */
-       _WIRED_COMMAND_BASE             = 0x00031000,
-       WIRED_INITIATE_HDCP2_SESSION    = _WIRED_COMMAND_BASE,
-       WIRED_VERIFY_RECEIVER_CERT,
-       WIRED_AKE_SEND_HPRIME,
-       WIRED_AKE_SEND_PAIRING_INFO,
-       WIRED_INIT_LOCALITY_CHECK,
-       WIRED_VALIDATE_LOCALITY,
-       WIRED_GET_SESSION_KEY,
-       WIRED_ENABLE_AUTH,
-       WIRED_VERIFY_REPEATER,
-       WIRED_REPEATER_AUTH_STREAM_REQ,
-       WIRED_CLOSE_SESSION,
-
-       _WIRED_COMMANDS_COUNT,
-};
-
-union encrypted_buff {
-       u8              e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN];
-       u8              e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN];
-       struct {
-               u8      e_kh_km[HDCP_KH_LEN];
-               u8      m[HDCP_M_LEN];
-       } __packed;
-};
-
-/* HDCP HECI message header. All header values are little endian. */
-struct hdcp_cmd_header {
-       u32                     api_version;
-       u32                     command_id;
-       enum me_hdcp_status     status;
-       /* Length of the HECI message (excluding the header) */
-       u32                     buffer_len;
-} __packed;
-
-/* Empty command request or response. No data follows the header. */
-struct hdcp_cmd_no_data {
-       struct hdcp_cmd_header header;
-} __packed;
-
-/* Uniquely identifies the hdcp port being addressed for a given command. */
-struct hdcp_port_id {
-       u8      integrated_port_type;
-       /* physical_port is used until Gen11.5. Must be zero for Gen11.5+ */
-       u8      physical_port;
-       /* attached_transcoder is for Gen11.5+. Set to zero for <Gen11.5 */
-       u8      attached_transcoder;
-       u8      reserved;
-} __packed;
-
-/*
- * Data structures for integrated wired HDCP2 Tx in
- * support of the AKE protocol
- */
-/* HECI struct for integrated wired HDCP Tx session initiation. */
-struct wired_cmd_initiate_hdcp2_session_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      protocol; /* for HDMI vs DP */
-} __packed;
-
-struct wired_cmd_initiate_hdcp2_session_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      r_tx[HDCP_2_2_RTX_LEN];
-       struct hdcp2_tx_caps    tx_caps;
-} __packed;
-
-/* HECI struct for ending an integrated wired HDCP Tx session. */
-struct wired_cmd_close_session_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-struct wired_cmd_close_session_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-/* HECI struct for integrated wired HDCP Tx Rx Cert verification. */
-struct wired_cmd_verify_receiver_cert_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       struct hdcp2_cert_rx    cert_rx;
-       u8                      r_rx[HDCP_2_2_RRX_LEN];
-       u8                      rx_caps[HDCP_2_2_RXCAPS_LEN];
-} __packed;
-
-struct wired_cmd_verify_receiver_cert_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      km_stored;
-       u8                      reserved[3];
-       union encrypted_buff    ekm_buff;
-} __packed;
-
-/* HECI struct for verification of Rx's Hprime in a HDCP Tx session */
-struct wired_cmd_ake_send_hprime_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      h_prime[HDCP_2_2_H_PRIME_LEN];
-} __packed;
-
-struct wired_cmd_ake_send_hprime_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-/*
- * HECI struct for sending in AKE pairing data generated by the Rx in an
- * integrated wired HDCP Tx session.
- */
-struct wired_cmd_ake_send_pairing_info_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      e_kh_km[HDCP_2_2_E_KH_KM_LEN];
-} __packed;
-
-struct wired_cmd_ake_send_pairing_info_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-/* Data structures for integrated wired HDCP2 Tx in support of the LC protocol*/
-/*
- * HECI struct for initiating locality check with an
- * integrated wired HDCP Tx session.
- */
-struct wired_cmd_init_locality_check_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-struct wired_cmd_init_locality_check_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      r_n[HDCP_2_2_RN_LEN];
-} __packed;
-
-/*
- * HECI struct for validating an Rx's LPrime value in an
- * integrated wired HDCP Tx session.
- */
-struct wired_cmd_validate_locality_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      l_prime[HDCP_2_2_L_PRIME_LEN];
-} __packed;
-
-struct wired_cmd_validate_locality_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-/*
- * Data structures for integrated wired HDCP2 Tx in support of the
- * SKE protocol
- */
-/* HECI struct for creating session key */
-struct wired_cmd_get_session_key_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-struct wired_cmd_get_session_key_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN];
-       u8                      r_iv[HDCP_2_2_RIV_LEN];
-} __packed;
-
-/* HECI struct for the Tx enable authentication command */
-struct wired_cmd_enable_auth_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      stream_type;
-} __packed;
-
-struct wired_cmd_enable_auth_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
-
-/*
- * Data structures for integrated wired HDCP2 Tx in support of
- * the repeater protocols
- */
-/*
- * HECI struct for verifying the downstream repeater's HDCP topology in an
- * integrated wired HDCP Tx session.
- */
-struct wired_cmd_verify_repeater_in {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      rx_info[HDCP_2_2_RXINFO_LEN];
-       u8                      seq_num_v[HDCP_2_2_SEQ_NUM_LEN];
-       u8                      v_prime[HDCP_2_2_V_PRIME_HALF_LEN];
-       u8                      receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN];
-} __packed;
-
-struct wired_cmd_verify_repeater_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-       u8                      content_type_supported;
-       u8                      v[HDCP_2_2_V_PRIME_HALF_LEN];
-} __packed;
-
-/*
- * HECI struct in support of stream management in an
- * integrated wired HDCP Tx session.
- */
-struct wired_cmd_repeater_auth_stream_req_in {
-       struct hdcp_cmd_header          header;
-       struct hdcp_port_id             port;
-       u8                              seq_num_m[HDCP_2_2_SEQ_NUM_LEN];
-       u8                              m_prime[HDCP_2_2_MPRIME_LEN];
-       __be16                          k;
-       struct hdcp2_streamid_type      streams[];
-} __packed;
-
-struct wired_cmd_repeater_auth_stream_req_out {
-       struct hdcp_cmd_header  header;
-       struct hdcp_port_id     port;
-} __packed;
 #endif /* __MEI_HDCP_H__ */
index 632376c291db6be80da07263a07dbb5fa18379e9..358db4a9f167adc2b710d9e7411a68ee1b2e256b 100644 (file)
 # define DP_FEC_LANE_2_SELECT              (2 << 4)
 # define DP_FEC_LANE_3_SELECT              (3 << 4)
 
+#define DP_SDP_ERROR_DETECTION_CONFIGURATION   0x121   /* DP 2.0 E11 */
+#define DP_SDP_CRC16_128B132B_EN               BIT(0)
+
 #define DP_AUX_FRAME_SYNC_VALUE                    0x15c   /* eDP 1.4 */
 # define DP_AUX_FRAME_SYNC_VALID           (1 << 0)
 
diff --git a/include/drm/i915_hdcp_interface.h b/include/drm/i915_hdcp_interface.h
new file mode 100644 (file)
index 0000000..2059b06
--- /dev/null
@@ -0,0 +1,539 @@
+/* SPDX-License-Identifier: (GPL-2.0+) */
+/*
+ * Copyright © 2017-2019 Intel Corporation
+ *
+ * Authors:
+ * Ramalingam C <ramalingam.c@intel.com>
+ */
+
+#ifndef _I915_HDCP_INTERFACE_H_
+#define _I915_HDCP_INTERFACE_H_
+
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <drm/display/drm_hdcp.h>
+
+/**
+ * enum hdcp_port_type - HDCP port implementation type defined by ME/GSC FW
+ * @HDCP_PORT_TYPE_INVALID: Invalid hdcp port type
+ * @HDCP_PORT_TYPE_INTEGRATED: In-Host HDCP2.x port
+ * @HDCP_PORT_TYPE_LSPCON: HDCP2.2 discrete wired Tx port with LSPCON
+ *                        (HDMI 2.0) solution
+ * @HDCP_PORT_TYPE_CPDP: HDCP2.2 discrete wired Tx port using the CPDP (DP 1.3)
+ *                      solution
+ */
+enum hdcp_port_type {
+       HDCP_PORT_TYPE_INVALID,
+       HDCP_PORT_TYPE_INTEGRATED,
+       HDCP_PORT_TYPE_LSPCON,
+       HDCP_PORT_TYPE_CPDP
+};
+
+/**
+ * enum hdcp_wired_protocol - HDCP adaptation used on the port
+ * @HDCP_PROTOCOL_INVALID: Invalid HDCP adaptation protocol
+ * @HDCP_PROTOCOL_HDMI: HDMI adaptation of HDCP used on the port
+ * @HDCP_PROTOCOL_DP: DP adaptation of HDCP used on the port
+ */
+enum hdcp_wired_protocol {
+       HDCP_PROTOCOL_INVALID,
+       HDCP_PROTOCOL_HDMI,
+       HDCP_PROTOCOL_DP
+};
+
+enum hdcp_ddi {
+       HDCP_DDI_INVALID_PORT = 0x0,
+
+       HDCP_DDI_B = 1,
+       HDCP_DDI_C,
+       HDCP_DDI_D,
+       HDCP_DDI_E,
+       HDCP_DDI_F,
+       HDCP_DDI_A = 7,
+       HDCP_DDI_RANGE_END = HDCP_DDI_A,
+};
+
+/**
+ * enum hdcp_tc - ME/GSC Firmware defined index for transcoders
+ * @HDCP_INVALID_TRANSCODER: Index for Invalid transcoder
+ * @HDCP_TRANSCODER_EDP: Index for EDP Transcoder
+ * @HDCP_TRANSCODER_DSI0: Index for DSI0 Transcoder
+ * @HDCP_TRANSCODER_DSI1: Index for DSI1 Transcoder
+ * @HDCP_TRANSCODER_A: Index for Transcoder A
+ * @HDCP_TRANSCODER_B: Index for Transcoder B
+ * @HDCP_TRANSCODER_C: Index for Transcoder C
+ * @HDCP_TRANSCODER_D: Index for Transcoder D
+ */
+enum hdcp_transcoder {
+       HDCP_INVALID_TRANSCODER = 0x00,
+       HDCP_TRANSCODER_EDP,
+       HDCP_TRANSCODER_DSI0,
+       HDCP_TRANSCODER_DSI1,
+       HDCP_TRANSCODER_A = 0x10,
+       HDCP_TRANSCODER_B,
+       HDCP_TRANSCODER_C,
+       HDCP_TRANSCODER_D
+};
+
+/**
+ * struct hdcp_port_data - intel specific HDCP port data
+ * @hdcp_ddi: ddi index as per ME/GSC FW
+ * @hdcp_transcoder: transcoder index as per ME/GSC FW
+ * @port_type: HDCP port type as per ME/GSC FW classification
+ * @protocol: HDCP adaptation as per ME/GSC FW
+ * @k: No of streams transmitted on a port. Only on DP MST this is != 1
+ * @seq_num_m: Count of RepeaterAuth_Stream_Manage msg propagated.
+ *            Initialized to 0 on AKE_INIT. Incremented after every successful
+ *            transmission of RepeaterAuth_Stream_Manage message. When it rolls
+ *            over re-Auth has to be triggered.
+ * @streams: struct hdcp2_streamid_type[k]. Defines the type and id for the
+ *          streams
+ */
+struct hdcp_port_data {
+       enum hdcp_ddi hdcp_ddi;
+       enum hdcp_transcoder hdcp_transcoder;
+       u8 port_type;
+       u8 protocol;
+       u16 k;
+       u32 seq_num_m;
+       struct hdcp2_streamid_type *streams;
+};
+
+/**
+ * struct i915_hdcp_ops- ops for HDCP2.2 services.
+ * @owner: Module providing the ops
+ * @initiate_hdcp2_session: Initiate a Wired HDCP2.2 Tx Session.
+ *                         And Prepare AKE_Init.
+ * @verify_receiver_cert_prepare_km: Verify the Receiver Certificate
+ *                                  AKE_Send_Cert and prepare
+                                    AKE_Stored_Km/AKE_No_Stored_Km
+ * @verify_hprime: Verify AKE_Send_H_prime
+ * @store_pairing_info: Store pairing info received
+ * @initiate_locality_check: Prepare LC_Init
+ * @verify_lprime: Verify lprime
+ * @get_session_key: Prepare SKE_Send_Eks
+ * @repeater_check_flow_prepare_ack: Validate the Downstream topology
+ *                                  and prepare rep_ack
+ * @verify_mprime: Verify mprime
+ * @enable_hdcp_authentication:  Mark a port as authenticated.
+ * @close_hdcp_session: Close the Wired HDCP Tx session per port.
+ *                     This also disables the authenticated state of the port.
+ */
+struct i915_hdcp_ops {
+       /**
+        * @owner: hdcp module
+        */
+       struct module *owner;
+
+       int (*initiate_hdcp2_session)(struct device *dev,
+                                     struct hdcp_port_data *data,
+                                     struct hdcp2_ake_init *ake_data);
+       int (*verify_receiver_cert_prepare_km)(struct device *dev,
+                                              struct hdcp_port_data *data,
+                                              struct hdcp2_ake_send_cert
+                                                               *rx_cert,
+                                              bool *km_stored,
+                                              struct hdcp2_ake_no_stored_km
+                                                               *ek_pub_km,
+                                              size_t *msg_sz);
+       int (*verify_hprime)(struct device *dev,
+                            struct hdcp_port_data *data,
+                            struct hdcp2_ake_send_hprime *rx_hprime);
+       int (*store_pairing_info)(struct device *dev,
+                                 struct hdcp_port_data *data,
+                                 struct hdcp2_ake_send_pairing_info
+                                                               *pairing_info);
+       int (*initiate_locality_check)(struct device *dev,
+                                      struct hdcp_port_data *data,
+                                      struct hdcp2_lc_init *lc_init_data);
+       int (*verify_lprime)(struct device *dev,
+                            struct hdcp_port_data *data,
+                            struct hdcp2_lc_send_lprime *rx_lprime);
+       int (*get_session_key)(struct device *dev,
+                              struct hdcp_port_data *data,
+                              struct hdcp2_ske_send_eks *ske_data);
+       int (*repeater_check_flow_prepare_ack)(struct device *dev,
+                                              struct hdcp_port_data *data,
+                                              struct hdcp2_rep_send_receiverid_list
+                                                               *rep_topology,
+                                              struct hdcp2_rep_send_ack
+                                                               *rep_send_ack);
+       int (*verify_mprime)(struct device *dev,
+                            struct hdcp_port_data *data,
+                            struct hdcp2_rep_stream_ready *stream_ready);
+       int (*enable_hdcp_authentication)(struct device *dev,
+                                         struct hdcp_port_data *data);
+       int (*close_hdcp_session)(struct device *dev,
+                                 struct hdcp_port_data *data);
+};
+
+/**
+ * struct i915_hdcp_master - Used for communication between i915
+ * and hdcp drivers for the HDCP2.2 services
+ * @hdcp_dev: device that provide the HDCP2.2 service from MEI Bus.
+ * @hdcp_ops: Ops implemented by hdcp driver or intel_hdcp_gsc , used by i915 driver.
+ */
+struct i915_hdcp_master {
+       struct device *hdcp_dev;
+       const struct i915_hdcp_ops *ops;
+
+       /* To protect the above members. */
+       struct mutex mutex;
+};
+
+/* fw_hdcp_status: Enumeration of all HDCP Status Codes */
+enum fw_hdcp_status {
+       FW_HDCP_STATUS_SUCCESS                  = 0x0000,
+
+       /* WiDi Generic Status Codes */
+       FW_HDCP_STATUS_INTERNAL_ERROR           = 0x1000,
+       FW_HDCP_STATUS_UNKNOWN_ERROR            = 0x1001,
+       FW_HDCP_STATUS_INCORRECT_API_VERSION    = 0x1002,
+       FW_HDCP_STATUS_INVALID_FUNCTION         = 0x1003,
+       FW_HDCP_STATUS_INVALID_BUFFER_LENGTH    = 0x1004,
+       FW_HDCP_STATUS_INVALID_PARAMS           = 0x1005,
+       FW_HDCP_STATUS_AUTHENTICATION_FAILED    = 0x1006,
+
+       /* WiDi Status Codes */
+       FW_HDCP_INVALID_SESSION_STATE           = 0x6000,
+       FW_HDCP_SRM_FRAGMENT_UNEXPECTED         = 0x6001,
+       FW_HDCP_SRM_INVALID_LENGTH              = 0x6002,
+       FW_HDCP_SRM_FRAGMENT_OFFSET_INVALID     = 0x6003,
+       FW_HDCP_SRM_VERIFICATION_FAILED         = 0x6004,
+       FW_HDCP_SRM_VERSION_TOO_OLD             = 0x6005,
+       FW_HDCP_RX_CERT_VERIFICATION_FAILED     = 0x6006,
+       FW_HDCP_RX_REVOKED                      = 0x6007,
+       FW_HDCP_H_VERIFICATION_FAILED           = 0x6008,
+       FW_HDCP_REPEATER_CHECK_UNEXPECTED       = 0x6009,
+       FW_HDCP_TOPOLOGY_MAX_EXCEEDED           = 0x600A,
+       FW_HDCP_V_VERIFICATION_FAILED           = 0x600B,
+       FW_HDCP_L_VERIFICATION_FAILED           = 0x600C,
+       FW_HDCP_STREAM_KEY_ALLOC_FAILED         = 0x600D,
+       FW_HDCP_BASE_KEY_RESET_FAILED           = 0x600E,
+       FW_HDCP_NONCE_GENERATION_FAILED         = 0x600F,
+       FW_HDCP_STATUS_INVALID_E_KEY_STATE      = 0x6010,
+       FW_HDCP_STATUS_INVALID_CS_ICV           = 0x6011,
+       FW_HDCP_STATUS_INVALID_KB_KEY_STATE     = 0x6012,
+       FW_HDCP_STATUS_INVALID_PAVP_MODE_ICV    = 0x6013,
+       FW_HDCP_STATUS_INVALID_PAVP_MODE        = 0x6014,
+       FW_HDCP_STATUS_LC_MAX_ATTEMPTS          = 0x6015,
+
+       /* New status for HDCP 2.1 */
+       FW_HDCP_STATUS_MISMATCH_IN_M            = 0x6016,
+
+       /* New status code for HDCP 2.2 Rx */
+       FW_HDCP_STATUS_RX_PROV_NOT_ALLOWED      = 0x6017,
+       FW_HDCP_STATUS_RX_PROV_WRONG_SUBJECT    = 0x6018,
+       FW_HDCP_RX_NEEDS_PROVISIONING           = 0x6019,
+       FW_HDCP_BKSV_ICV_AUTH_FAILED            = 0x6020,
+       FW_HDCP_STATUS_INVALID_STREAM_ID        = 0x6021,
+       FW_HDCP_STATUS_CHAIN_NOT_INITIALIZED    = 0x6022,
+       FW_HDCP_FAIL_NOT_EXPECTED               = 0x6023,
+       FW_HDCP_FAIL_HDCP_OFF                   = 0x6024,
+       FW_HDCP_FAIL_INVALID_PAVP_MEMORY_MODE   = 0x6025,
+       FW_HDCP_FAIL_AES_ECB_FAILURE            = 0x6026,
+       FW_HDCP_FEATURE_NOT_SUPPORTED           = 0x6027,
+       FW_HDCP_DMA_READ_ERROR                  = 0x6028,
+       FW_HDCP_DMA_WRITE_ERROR                 = 0x6029,
+       FW_HDCP_FAIL_INVALID_PACKET_SIZE        = 0x6030,
+       FW_HDCP_H264_PARSING_ERROR              = 0x6031,
+       FW_HDCP_HDCP2_ERRATA_VIDEO_VIOLATION    = 0x6032,
+       FW_HDCP_HDCP2_ERRATA_AUDIO_VIOLATION    = 0x6033,
+       FW_HDCP_TX_ACTIVE_ERROR                 = 0x6034,
+       FW_HDCP_MODE_CHANGE_ERROR               = 0x6035,
+       FW_HDCP_STREAM_TYPE_ERROR               = 0x6036,
+       FW_HDCP_STREAM_MANAGE_NOT_POSSIBLE      = 0x6037,
+
+       FW_HDCP_STATUS_PORT_INVALID_COMMAND     = 0x6038,
+       FW_HDCP_STATUS_UNSUPPORTED_PROTOCOL     = 0x6039,
+       FW_HDCP_STATUS_INVALID_PORT_INDEX       = 0x603a,
+       FW_HDCP_STATUS_TX_AUTH_NEEDED           = 0x603b,
+       FW_HDCP_STATUS_NOT_INTEGRATED_PORT      = 0x603c,
+       FW_HDCP_STATUS_SESSION_MAX_REACHED      = 0x603d,
+
+       /* hdcp capable bit is not set in rx_caps(error is unique to DP) */
+       FW_HDCP_STATUS_NOT_HDCP_CAPABLE         = 0x6041,
+
+       FW_HDCP_STATUS_INVALID_STREAM_COUNT     = 0x6042,
+};
+
+#define HDCP_API_VERSION                               0x00010000
+
+#define HDCP_M_LEN                                     16
+#define HDCP_KH_LEN                                    16
+
+/* Payload Buffer size(Excluding Header) for CMDs and corresponding response */
+/* Wired_Tx_AKE  */
+#define        WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN     (4 + 1)
+#define        WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_OUT    (4 + 8 + 3)
+
+#define        WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN       (4 + 522 + 8 + 3)
+#define        WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_MIN_OUT  (4 + 1 + 3 + 16 + 16)
+#define        WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_MAX_OUT  (4 + 1 + 3 + 128)
+
+#define        WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN            (4 + 32)
+#define        WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_OUT           (4)
+
+#define        WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN          (4 + 16)
+#define        WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_OUT         (4)
+
+#define        WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN              (4)
+#define        WIRED_CMD_BUF_LEN_CLOSE_SESSION_OUT             (4)
+
+/* Wired_Tx_LC */
+#define        WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN        (4)
+#define        WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_OUT       (4 + 8)
+
+#define        WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN          (4 + 32)
+#define        WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_OUT         (4)
+
+/* Wired_Tx_SKE */
+#define        WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN            (4)
+#define        WIRED_CMD_BUF_LEN_GET_SESSION_KEY_OUT           (4 + 16 + 8)
+
+/* Wired_Tx_SKE */
+#define        WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN                (4 + 1)
+#define        WIRED_CMD_BUF_LEN_ENABLE_AUTH_OUT               (4)
+
+/* Wired_Tx_Repeater */
+#define        WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN            (4 + 2 + 3 + 16 + 155)
+#define        WIRED_CMD_BUF_LEN_VERIFY_REPEATER_OUT           (4 + 1 + 16)
+
+#define        WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN       (4 + 3 + \
+                                                               32 + 2 + 2)
+
+#define        WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_OUT          (4)
+
+/* hdcp_command_id: Enumeration of all WIRED HDCP Command IDs */
+enum hdcp_command_id {
+       _WIDI_COMMAND_BASE              = 0x00030000,
+       WIDI_INITIATE_HDCP2_SESSION     = _WIDI_COMMAND_BASE,
+       HDCP_GET_SRM_STATUS,
+       HDCP_SEND_SRM_FRAGMENT,
+
+       /* The wired HDCP Tx commands */
+       _WIRED_COMMAND_BASE             = 0x00031000,
+       WIRED_INITIATE_HDCP2_SESSION    = _WIRED_COMMAND_BASE,
+       WIRED_VERIFY_RECEIVER_CERT,
+       WIRED_AKE_SEND_HPRIME,
+       WIRED_AKE_SEND_PAIRING_INFO,
+       WIRED_INIT_LOCALITY_CHECK,
+       WIRED_VALIDATE_LOCALITY,
+       WIRED_GET_SESSION_KEY,
+       WIRED_ENABLE_AUTH,
+       WIRED_VERIFY_REPEATER,
+       WIRED_REPEATER_AUTH_STREAM_REQ,
+       WIRED_CLOSE_SESSION,
+
+       _WIRED_COMMANDS_COUNT,
+};
+
+union encrypted_buff {
+       u8              e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN];
+       u8              e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN];
+       struct {
+               u8      e_kh_km[HDCP_KH_LEN];
+               u8      m[HDCP_M_LEN];
+       } __packed;
+};
+
+/* HDCP HECI message header. All header values are little endian. */
+struct hdcp_cmd_header {
+       u32                     api_version;
+       u32                     command_id;
+       enum fw_hdcp_status     status;
+       /* Length of the HECI message (excluding the header) */
+       u32                     buffer_len;
+} __packed;
+
+/* Empty command request or response. No data follows the header. */
+struct hdcp_cmd_no_data {
+       struct hdcp_cmd_header header;
+} __packed;
+
+/* Uniquely identifies the hdcp port being addressed for a given command. */
+struct hdcp_port_id {
+       u8      integrated_port_type;
+       /* physical_port is used until Gen11.5. Must be zero for Gen11.5+ */
+       u8      physical_port;
+       /* attached_transcoder is for Gen11.5+. Set to zero for <Gen11.5 */
+       u8      attached_transcoder;
+       u8      reserved;
+} __packed;
+
+/*
+ * Data structures for integrated wired HDCP2 Tx in
+ * support of the AKE protocol
+ */
+/* HECI struct for integrated wired HDCP Tx session initiation. */
+struct wired_cmd_initiate_hdcp2_session_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      protocol; /* for HDMI vs DP */
+} __packed;
+
+struct wired_cmd_initiate_hdcp2_session_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      r_tx[HDCP_2_2_RTX_LEN];
+       struct hdcp2_tx_caps    tx_caps;
+} __packed;
+
+/* HECI struct for ending an integrated wired HDCP Tx session. */
+struct wired_cmd_close_session_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+struct wired_cmd_close_session_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+/* HECI struct for integrated wired HDCP Tx Rx Cert verification. */
+struct wired_cmd_verify_receiver_cert_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       struct hdcp2_cert_rx    cert_rx;
+       u8                      r_rx[HDCP_2_2_RRX_LEN];
+       u8                      rx_caps[HDCP_2_2_RXCAPS_LEN];
+} __packed;
+
+struct wired_cmd_verify_receiver_cert_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      km_stored;
+       u8                      reserved[3];
+       union encrypted_buff    ekm_buff;
+} __packed;
+
+/* HECI struct for verification of Rx's Hprime in a HDCP Tx session */
+struct wired_cmd_ake_send_hprime_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      h_prime[HDCP_2_2_H_PRIME_LEN];
+} __packed;
+
+struct wired_cmd_ake_send_hprime_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+/*
+ * HECI struct for sending in AKE pairing data generated by the Rx in an
+ * integrated wired HDCP Tx session.
+ */
+struct wired_cmd_ake_send_pairing_info_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      e_kh_km[HDCP_2_2_E_KH_KM_LEN];
+} __packed;
+
+struct wired_cmd_ake_send_pairing_info_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+/* Data structures for integrated wired HDCP2 Tx in support of the LC protocol*/
+/*
+ * HECI struct for initiating locality check with an
+ * integrated wired HDCP Tx session.
+ */
+struct wired_cmd_init_locality_check_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+struct wired_cmd_init_locality_check_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      r_n[HDCP_2_2_RN_LEN];
+} __packed;
+
+/*
+ * HECI struct for validating an Rx's LPrime value in an
+ * integrated wired HDCP Tx session.
+ */
+struct wired_cmd_validate_locality_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      l_prime[HDCP_2_2_L_PRIME_LEN];
+} __packed;
+
+struct wired_cmd_validate_locality_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+/*
+ * Data structures for integrated wired HDCP2 Tx in support of the
+ * SKE protocol
+ */
+/* HECI struct for creating session key */
+struct wired_cmd_get_session_key_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+struct wired_cmd_get_session_key_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN];
+       u8                      r_iv[HDCP_2_2_RIV_LEN];
+} __packed;
+
+/* HECI struct for the Tx enable authentication command */
+struct wired_cmd_enable_auth_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      stream_type;
+} __packed;
+
+struct wired_cmd_enable_auth_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+/*
+ * Data structures for integrated wired HDCP2 Tx in support of
+ * the repeater protocols
+ */
+/*
+ * HECI struct for verifying the downstream repeater's HDCP topology in an
+ * integrated wired HDCP Tx session.
+ */
+struct wired_cmd_verify_repeater_in {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      rx_info[HDCP_2_2_RXINFO_LEN];
+       u8                      seq_num_v[HDCP_2_2_SEQ_NUM_LEN];
+       u8                      v_prime[HDCP_2_2_V_PRIME_HALF_LEN];
+       u8                      receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN];
+} __packed;
+
+struct wired_cmd_verify_repeater_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+       u8                      content_type_supported;
+       u8                      v[HDCP_2_2_V_PRIME_HALF_LEN];
+} __packed;
+
+/*
+ * HECI struct in support of stream management in an
+ * integrated wired HDCP Tx session.
+ */
+struct wired_cmd_repeater_auth_stream_req_in {
+       struct hdcp_cmd_header          header;
+       struct hdcp_port_id             port;
+       u8                              seq_num_m[HDCP_2_2_SEQ_NUM_LEN];
+       u8                              m_prime[HDCP_2_2_MPRIME_LEN];
+       __be16                          k;
+       struct hdcp2_streamid_type      streams[];
+} __packed;
+
+struct wired_cmd_repeater_auth_stream_req_out {
+       struct hdcp_cmd_header  header;
+       struct hdcp_port_id     port;
+} __packed;
+
+#endif /* _I915_HDCP_INTERFACE_H_ */
diff --git a/include/drm/i915_mei_hdcp_interface.h b/include/drm/i915_mei_hdcp_interface.h
deleted file mode 100644 (file)
index f441cbc..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+) */
-/*
- * Copyright © 2017-2019 Intel Corporation
- *
- * Authors:
- * Ramalingam C <ramalingam.c@intel.com>
- */
-
-#ifndef _I915_MEI_HDCP_INTERFACE_H_
-#define _I915_MEI_HDCP_INTERFACE_H_
-
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <drm/display/drm_hdcp.h>
-
-/**
- * enum hdcp_port_type - HDCP port implementation type defined by ME FW
- * @HDCP_PORT_TYPE_INVALID: Invalid hdcp port type
- * @HDCP_PORT_TYPE_INTEGRATED: In-Host HDCP2.x port
- * @HDCP_PORT_TYPE_LSPCON: HDCP2.2 discrete wired Tx port with LSPCON
- *                        (HDMI 2.0) solution
- * @HDCP_PORT_TYPE_CPDP: HDCP2.2 discrete wired Tx port using the CPDP (DP 1.3)
- *                      solution
- */
-enum hdcp_port_type {
-       HDCP_PORT_TYPE_INVALID,
-       HDCP_PORT_TYPE_INTEGRATED,
-       HDCP_PORT_TYPE_LSPCON,
-       HDCP_PORT_TYPE_CPDP
-};
-
-/**
- * enum hdcp_wired_protocol - HDCP adaptation used on the port
- * @HDCP_PROTOCOL_INVALID: Invalid HDCP adaptation protocol
- * @HDCP_PROTOCOL_HDMI: HDMI adaptation of HDCP used on the port
- * @HDCP_PROTOCOL_DP: DP adaptation of HDCP used on the port
- */
-enum hdcp_wired_protocol {
-       HDCP_PROTOCOL_INVALID,
-       HDCP_PROTOCOL_HDMI,
-       HDCP_PROTOCOL_DP
-};
-
-enum mei_fw_ddi {
-       MEI_DDI_INVALID_PORT = 0x0,
-
-       MEI_DDI_B = 1,
-       MEI_DDI_C,
-       MEI_DDI_D,
-       MEI_DDI_E,
-       MEI_DDI_F,
-       MEI_DDI_A = 7,
-       MEI_DDI_RANGE_END = MEI_DDI_A,
-};
-
-/**
- * enum mei_fw_tc - ME Firmware defined index for transcoders
- * @MEI_INVALID_TRANSCODER: Index for Invalid transcoder
- * @MEI_TRANSCODER_EDP: Index for EDP Transcoder
- * @MEI_TRANSCODER_DSI0: Index for DSI0 Transcoder
- * @MEI_TRANSCODER_DSI1: Index for DSI1 Transcoder
- * @MEI_TRANSCODER_A: Index for Transcoder A
- * @MEI_TRANSCODER_B: Index for Transcoder B
- * @MEI_TRANSCODER_C: Index for Transcoder C
- * @MEI_TRANSCODER_D: Index for Transcoder D
- */
-enum mei_fw_tc {
-       MEI_INVALID_TRANSCODER = 0x00,
-       MEI_TRANSCODER_EDP,
-       MEI_TRANSCODER_DSI0,
-       MEI_TRANSCODER_DSI1,
-       MEI_TRANSCODER_A = 0x10,
-       MEI_TRANSCODER_B,
-       MEI_TRANSCODER_C,
-       MEI_TRANSCODER_D
-};
-
-/**
- * struct hdcp_port_data - intel specific HDCP port data
- * @fw_ddi: ddi index as per ME FW
- * @fw_tc: transcoder index as per ME FW
- * @port_type: HDCP port type as per ME FW classification
- * @protocol: HDCP adaptation as per ME FW
- * @k: No of streams transmitted on a port. Only on DP MST this is != 1
- * @seq_num_m: Count of RepeaterAuth_Stream_Manage msg propagated.
- *            Initialized to 0 on AKE_INIT. Incremented after every successful
- *            transmission of RepeaterAuth_Stream_Manage message. When it rolls
- *            over re-Auth has to be triggered.
- * @streams: struct hdcp2_streamid_type[k]. Defines the type and id for the
- *          streams
- */
-struct hdcp_port_data {
-       enum mei_fw_ddi fw_ddi;
-       enum mei_fw_tc fw_tc;
-       u8 port_type;
-       u8 protocol;
-       u16 k;
-       u32 seq_num_m;
-       struct hdcp2_streamid_type *streams;
-};
-
-/**
- * struct i915_hdcp_component_ops- ops for HDCP2.2 services.
- * @owner: Module providing the ops
- * @initiate_hdcp2_session: Initiate a Wired HDCP2.2 Tx Session.
- *                         And Prepare AKE_Init.
- * @verify_receiver_cert_prepare_km: Verify the Receiver Certificate
- *                                  AKE_Send_Cert and prepare
-                                    AKE_Stored_Km/AKE_No_Stored_Km
- * @verify_hprime: Verify AKE_Send_H_prime
- * @store_pairing_info: Store pairing info received
- * @initiate_locality_check: Prepare LC_Init
- * @verify_lprime: Verify lprime
- * @get_session_key: Prepare SKE_Send_Eks
- * @repeater_check_flow_prepare_ack: Validate the Downstream topology
- *                                  and prepare rep_ack
- * @verify_mprime: Verify mprime
- * @enable_hdcp_authentication:  Mark a port as authenticated.
- * @close_hdcp_session: Close the Wired HDCP Tx session per port.
- *                     This also disables the authenticated state of the port.
- */
-struct i915_hdcp_component_ops {
-       /**
-        * @owner: mei_hdcp module
-        */
-       struct module *owner;
-
-       int (*initiate_hdcp2_session)(struct device *dev,
-                                     struct hdcp_port_data *data,
-                                     struct hdcp2_ake_init *ake_data);
-       int (*verify_receiver_cert_prepare_km)(struct device *dev,
-                                              struct hdcp_port_data *data,
-                                              struct hdcp2_ake_send_cert
-                                                               *rx_cert,
-                                              bool *km_stored,
-                                              struct hdcp2_ake_no_stored_km
-                                                               *ek_pub_km,
-                                              size_t *msg_sz);
-       int (*verify_hprime)(struct device *dev,
-                            struct hdcp_port_data *data,
-                            struct hdcp2_ake_send_hprime *rx_hprime);
-       int (*store_pairing_info)(struct device *dev,
-                                 struct hdcp_port_data *data,
-                                 struct hdcp2_ake_send_pairing_info
-                                                               *pairing_info);
-       int (*initiate_locality_check)(struct device *dev,
-                                      struct hdcp_port_data *data,
-                                      struct hdcp2_lc_init *lc_init_data);
-       int (*verify_lprime)(struct device *dev,
-                            struct hdcp_port_data *data,
-                            struct hdcp2_lc_send_lprime *rx_lprime);
-       int (*get_session_key)(struct device *dev,
-                              struct hdcp_port_data *data,
-                              struct hdcp2_ske_send_eks *ske_data);
-       int (*repeater_check_flow_prepare_ack)(struct device *dev,
-                                              struct hdcp_port_data *data,
-                                              struct hdcp2_rep_send_receiverid_list
-                                                               *rep_topology,
-                                              struct hdcp2_rep_send_ack
-                                                               *rep_send_ack);
-       int (*verify_mprime)(struct device *dev,
-                            struct hdcp_port_data *data,
-                            struct hdcp2_rep_stream_ready *stream_ready);
-       int (*enable_hdcp_authentication)(struct device *dev,
-                                         struct hdcp_port_data *data);
-       int (*close_hdcp_session)(struct device *dev,
-                                 struct hdcp_port_data *data);
-};
-
-/**
- * struct i915_hdcp_component_master - Used for communication between i915
- * and mei_hdcp drivers for the HDCP2.2 services
- * @mei_dev: device that provide the HDCP2.2 service from MEI Bus.
- * @hdcp_ops: Ops implemented by mei_hdcp driver, used by i915 driver.
- */
-struct i915_hdcp_comp_master {
-       struct device *mei_dev;
-       const struct i915_hdcp_component_ops *ops;
-
-       /* To protect the above members. */
-       struct mutex mutex;
-};
-
-#endif /* _I915_MEI_HDCP_INTERFACE_H_ */