squashed CMTG changes for DC3CO CI run.

Signed-off-by: Animesh Manna <[email protected]>
Signed-off-by: Dibin Moolakadan Subrahmanian 
<[email protected]>
---
 drivers/gpu/drm/i915/display/intel_cmtg.c     | 360 +++++++++++++++++-
 drivers/gpu/drm/i915/display/intel_cmtg.h     |  17 +
 .../gpu/drm/i915/display/intel_cmtg_regs.h    |  24 +-
 drivers/gpu/drm/i915/display/intel_cx0_phy.c  |   5 +
 drivers/gpu/drm/i915/display/intel_display.c  |  23 +-
 .../drm/i915/display/intel_display_device.c   |  14 +
 .../drm/i915/display/intel_display_device.h   |   2 +-
 .../gpu/drm/i915/display/intel_display_irq.c  |  12 +
 .../drm/i915/display/intel_display_limits.h   |   2 +
 .../drm/i915/display/intel_display_power.c    |  17 +
 .../drm/i915/display/intel_display_power.h    |   2 +
 .../gpu/drm/i915/display/intel_display_regs.h |   6 +
 .../drm/i915/display/intel_display_types.h    |   4 +
 drivers/gpu/drm/i915/display/intel_vrr.c      |   5 +
 14 files changed, 481 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.c 
b/drivers/gpu/drm/i915/display/intel_cmtg.c
index e1fdc6fe9762..058b9d32dcfc 100644
--- a/drivers/gpu/drm/i915/display/intel_cmtg.c
+++ b/drivers/gpu/drm/i915/display/intel_cmtg.c
@@ -4,7 +4,6 @@
  */
 
 #include <linux/string_choices.h>
-#include <linux/types.h>
 
 #include <drm/drm_device.h>
 #include <drm/drm_print.h>
@@ -14,8 +13,12 @@
 #include "intel_crtc.h"
 #include "intel_de.h"
 #include "intel_display_device.h"
+#include "intel_display_irq.h"
 #include "intel_display_power.h"
 #include "intel_display_regs.h"
+#include "intel_display_types.h"
+#include "intel_psr_regs.h"
+#include "intel_vrr_regs.h"
 
 /**
  * DOC: Common Primary Timing Generator (CMTG)
@@ -81,6 +84,18 @@ static void intel_cmtg_dump_config(struct intel_display 
*display,
                    str_yes_no(cmtg_config->trans_b_secondary));
 }
 
+static inline enum transcoder to_cmtg_transcoder(enum transcoder 
cpu_transcoder)
+{
+       switch (cpu_transcoder) {
+       case TRANSCODER_A:
+               return TRANSCODER_CMTG0;
+       case TRANSCODER_B:
+               return TRANSCODER_CMTG1;
+       default:
+               return INVALID_TRANSCODER;
+       }
+}
+
 static bool intel_cmtg_transcoder_is_secondary(struct intel_display *display,
                                               enum transcoder trans)
 {
@@ -103,11 +118,11 @@ static void intel_cmtg_get_config(struct intel_display 
*display,
 {
        u32 val;
 
-       val = intel_de_read(display, TRANS_CMTG_CTL_A);
+       val = intel_de_read(display, TRANS_CMTG_CTL(TRANSCODER_A));
        cmtg_config->cmtg_a_enable = val & CMTG_ENABLE;
 
        if (intel_cmtg_has_cmtg_b(display)) {
-               val = intel_de_read(display, TRANS_CMTG_CTL_B);
+               val = intel_de_read(display, TRANS_CMTG_CTL(TRANSCODER_B));
                cmtg_config->cmtg_b_enable = val & CMTG_ENABLE;
        }
 
@@ -124,8 +139,8 @@ static bool intel_cmtg_disable_requires_modeset(struct 
intel_display *display,
        return cmtg_config->trans_a_secondary || cmtg_config->trans_b_secondary;
 }
 
-static void intel_cmtg_disable(struct intel_display *display,
-                              struct intel_cmtg_config *cmtg_config)
+static void intel_cmtg_disable_all(struct intel_display *display,
+                                  struct intel_cmtg_config *cmtg_config)
 {
        u32 clk_sel_clr = 0;
        u32 clk_sel_set = 0;
@@ -140,14 +155,14 @@ static void intel_cmtg_disable(struct intel_display 
*display,
 
        if (cmtg_config->cmtg_a_enable) {
                drm_dbg_kms(display->drm, "Disabling CMTG A\n");
-               intel_de_rmw(display, TRANS_CMTG_CTL_A, CMTG_ENABLE, 0);
+               intel_de_rmw(display, TRANS_CMTG_CTL(TRANSCODER_A), 
CMTG_ENABLE, 0);
                clk_sel_clr |= CMTG_CLK_SEL_A_MASK;
                clk_sel_set |= CMTG_CLK_SEL_A_DISABLED;
        }
 
        if (cmtg_config->cmtg_b_enable) {
                drm_dbg_kms(display->drm, "Disabling CMTG B\n");
-               intel_de_rmw(display, TRANS_CMTG_CTL_B, CMTG_ENABLE, 0);
+               intel_de_rmw(display, TRANS_CMTG_CTL(TRANSCODER_B), 
CMTG_ENABLE, 0);
                clk_sel_clr |= CMTG_CLK_SEL_B_MASK;
                clk_sel_set |= CMTG_CLK_SEL_B_DISABLED;
        }
@@ -156,6 +171,39 @@ static void intel_cmtg_disable(struct intel_display 
*display,
                intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, clk_sel_set);
 }
 
+void intel_cmtg_disable(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       enum transcoder cmtg_transcoder = 
to_cmtg_transcoder(crtc_state->cpu_transcoder);
+       u32 clk_sel_clr = 0;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       crtc->cmtg.enabled = false;
+       intel_de_rmw(display, TRANS_VRR_CTL(display, cmtg_transcoder),
+                    VRR_CTL_VRR_ENABLE | VRR_CTL_FLIP_LINE_EN, 0);
+
+       intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(display, cpu_transcoder),
+                    CMTG_SECONDARY_MODE, 0);
+       intel_de_rmw(display, CMTG_SCANLINE_GB1(cpu_transcoder), 
CMTG_HW_GB_ENABLE, 0);
+
+       intel_de_rmw(display, TRANS_CMTG_CTL(cpu_transcoder), CMTG_ENABLE, 0);
+
+       if (intel_de_wait_for_clear_ms(display, TRANS_CMTG_CTL(cpu_transcoder), 
CMTG_STATE, 50)) {
+               drm_WARN(display->drm, 1, "CMTG: %s disable timeout\n",
+                        transcoder_name(cpu_transcoder));
+               return;
+       }
+
+       clk_sel_clr = cpu_transcoder == TRANSCODER_A ? CMTG_CLK_SEL_A_MASK : 
CMTG_CLK_SEL_B_MASK;
+       intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, 0);
+
+       drm_dbg_kms(display->drm, "CMTG: %s disabled\n", 
transcoder_name(cpu_transcoder));
+}
+
 /*
  * Read out CMTG configuration and, on platforms that allow disabling it 
without
  * a modeset, do it.
@@ -183,5 +231,301 @@ void intel_cmtg_sanitize(struct intel_display *display)
        if (intel_cmtg_disable_requires_modeset(display, &cmtg_config))
                return;
 
-       intel_cmtg_disable(display, &cmtg_config);
+       intel_cmtg_disable_all(display, &cmtg_config);
+}
+
+bool intel_cmtg_is_allowed(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+       if ((cpu_transcoder == TRANSCODER_A || cpu_transcoder == TRANSCODER_B) 
&&
+           DISPLAY_VER(display) == 35 && intel_crtc_has_type(crtc_state, 
INTEL_OUTPUT_EDP))
+               return true;
+
+       return false;
+}
+
+void intel_cmtg_set_clk_select(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 clk_sel_clr = 0;
+       u32 clk_sel_set = 0;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       if (cpu_transcoder == TRANSCODER_A) {
+               clk_sel_clr = CMTG_CLK_SEL_A_MASK;
+               clk_sel_set = CMTG_CLK_SELECT_PHYA_ENABLE;
+       } else if (cpu_transcoder == TRANSCODER_B) {
+               clk_sel_clr = CMTG_CLK_SEL_B_MASK;
+               clk_sel_set = CMTG_CLK_SELECT_PHYB_ENABLE;
+       }
+
+       if (clk_sel_set)
+               intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, clk_sel_set);
+}
+
+void intel_cmtg_set_timings(const struct intel_crtc_state *crtc_state, bool 
lrr)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       const struct drm_display_mode *adjusted_mode = 
&crtc_state->hw.adjusted_mode;
+       enum transcoder cmtg_transcoder = 
to_cmtg_transcoder(crtc_state->cpu_transcoder);
+       u32 crtc_vdisplay, crtc_vtotal, crtc_vblank_start, crtc_vblank_end;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       crtc_vdisplay = adjusted_mode->crtc_vdisplay;
+
+       /*
+        * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal
+        * bits are not required. Since the support for these bits is going to
+        * be deprecated in upcoming platforms, avoid writing these bits for the
+        * platforms that do not use legacy Timing Generator.
+        */
+       crtc_vtotal = 1;
+
+       /*
+        * VBLANK_START not used by hw, just clear it
+        * to make it stand out in register dumps.
+        */
+       crtc_vblank_start = 1;
+
+       crtc_vblank_end = adjusted_mode->crtc_vblank_end;
+
+       if (lrr) {
+               intel_de_write(display, TRANS_SET_CONTEXT_LATENCY(display, 
cmtg_transcoder),
+                              crtc_state->set_context_latency);
+               intel_de_write(display, TRANS_VBLANK(display, cmtg_transcoder),
+                              VBLANK_START(crtc_vblank_start - 1) |
+                              VBLANK_END(crtc_vblank_end - 1));
+               intel_de_write(display, TRANS_VTOTAL(display, cmtg_transcoder),
+                              VACTIVE(crtc_vdisplay - 1) |
+                              VTOTAL(crtc_vtotal - 1));
+               return;
+       }
+
+       intel_de_write(display, TRANS_HTOTAL(display, cmtg_transcoder),
+                      HACTIVE(adjusted_mode->crtc_hdisplay - 1) |
+                      HTOTAL(adjusted_mode->crtc_htotal - 1));
+       intel_de_write(display, TRANS_HBLANK(display, cmtg_transcoder),
+                      HBLANK_START(adjusted_mode->crtc_hblank_start - 1) |
+                      HBLANK_END(adjusted_mode->crtc_hblank_end - 1));
+       intel_de_write(display, TRANS_HSYNC(display, cmtg_transcoder),
+                      HSYNC_START(adjusted_mode->crtc_hsync_start - 1) |
+                      HSYNC_END(adjusted_mode->crtc_hsync_end - 1));
+       intel_de_write(display, TRANS_VTOTAL(display, cmtg_transcoder),
+                      VACTIVE(crtc_vdisplay - 1) |
+                      VTOTAL(crtc_vtotal - 1));
+       intel_de_write(display, TRANS_VBLANK(display, cmtg_transcoder),
+                      VBLANK_START(crtc_vblank_start - 1) |
+                      VBLANK_END(crtc_vblank_end - 1));
+       intel_de_write(display, TRANS_VSYNC(display, cmtg_transcoder),
+                      VSYNC_START(adjusted_mode->crtc_vsync_start - 1) |
+                      VSYNC_END(adjusted_mode->crtc_vsync_end - 1));
+       intel_de_write(display, TRANS_SET_CONTEXT_LATENCY(display, 
cmtg_transcoder),
+                      crtc_state->set_context_latency);
+}
+
+void intel_cmtg_set_vrr_timings(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cmtg_transcoder = 
to_cmtg_transcoder(crtc_state->cpu_transcoder);
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       intel_de_write(display, TRANS_VRR_VMIN(display, cmtg_transcoder), 
crtc_state->vrr.vmin - 1);
+       intel_de_write(display, TRANS_VRR_VMAX(display, cmtg_transcoder), 
crtc_state->vrr.vmax - 1);
+       intel_de_write(display, TRANS_VRR_FLIPLINE(display, cmtg_transcoder),
+                      crtc_state->vrr.flipline - 1);
+}
+
+void intel_cmtg_set_vrr_ctl(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cmtg_transcoder = 
to_cmtg_transcoder(crtc_state->cpu_transcoder);
+       u32 vrr_ctl;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       vrr_ctl = VRR_CTL_VRR_ENABLE | VRR_CTL_FLIP_LINE_EN |
+                 XELPD_VRR_CTL_VRR_GUARDBAND(crtc_state->vrr.guardband);
+
+       /* TODO: The code below may need to be revisited once CMRR is enabled */
+       if (crtc_state->cmrr.enable)
+               vrr_ctl |= VRR_CTL_CMRR_ENABLE;
+
+       intel_de_write(display, TRANS_VRR_CTL(display, cmtg_transcoder), 
vrr_ctl);
+}
+
+void intel_cmtg_set_m_n(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cmtg_transcoder = 
to_cmtg_transcoder(crtc_state->cpu_transcoder);
+       const struct intel_link_m_n *m_n = &crtc_state->dp_m_n;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       intel_de_write(display, PIPE_LINK_M1(display, cmtg_transcoder), 
m_n->link_m);
+       intel_de_write(display, PIPE_LINK_N1(display, cmtg_transcoder), 
m_n->link_n);
+}
+
+void intel_cmtg_enable_sync(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 cmtg_ctl;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       cmtg_ctl = CMTG_SYNC_TO_PORT | CMTG_ENABLE;
+
+       intel_de_rmw(display, TRANS_CMTG_CTL(cpu_transcoder), 0, cmtg_ctl);
+       if (intel_de_wait_for_clear_ms(display, TRANS_CMTG_CTL(cpu_transcoder),
+                                      CMTG_SYNC_TO_PORT, 50)) {
+               drm_WARN(display->drm, 1, "CMTG: %s enable timeout\n",
+                        transcoder_name(cpu_transcoder));
+       }
+}
+
+void intel_cmtg_enable_ddi(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(display, cpu_transcoder), 0, 
CMTG_SECONDARY_MODE);
+       intel_de_rmw(display, CMTG_SCANLINE_GB1(cpu_transcoder), 0, 
CMTG_HW_GB_ENABLE);
+
+       crtc->cmtg.enabled = true;
+       drm_dbg_kms(display->drm, "CMTG: %s enabled\n", 
transcoder_name(cpu_transcoder));
+}
+
+static void intel_cmtg_mask_interrupt(const struct intel_crtc_state 
*crtc_state, bool mask)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 interrupt_mask = 0;
+
+       if (cpu_transcoder == TRANSCODER_A)
+               interrupt_mask = CMTG_VBLANK_A | CMTG_DELAYED_VBLANK_A | 
CMTG_VSYNC_A;
+       else if (cpu_transcoder == TRANSCODER_B)
+               interrupt_mask = CMTG_VBLANK_B | CMTG_DELAYED_VBLANK_B | 
CMTG_VSYNC_B;
+
+       if (mask)
+               bdw_update_port_irq(display, interrupt_mask, 0);
+       else
+               bdw_update_port_irq(display, interrupt_mask, interrupt_mask);
+}
+
+void intel_cmtg_enable_interrupt(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       spin_lock_irq(&display->irq.lock);
+       intel_cmtg_mask_interrupt(crtc_state, false);
+       spin_unlock_irq(&display->irq.lock);
+}
+
+void intel_cmtg_disable_interrupt(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       spin_lock_irq(&display->irq.lock);
+       intel_cmtg_mask_interrupt(crtc_state, true);
+       spin_unlock_irq(&display->irq.lock);
+}
+
+#define DC3CO_ENTRY_LATENCY    55
+#define DC3CO_EXIT_LATENCY     40
+
+void intel_cmtg_set_hwgb(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 breakeven_gb;
+       u32 dc5_exit_latency;
+       u32 line_time_us = 75;
+       u32 val;
+
+       if (!intel_cmtg_is_allowed(crtc_state))
+               return;
+
+       if (crtc_state->linetime)
+               line_time_us = DIV_ROUND_UP(crtc_state->linetime, 8);
+
+       /* Break Even Guardband - DC3co Entry Latency / linetime */
+       breakeven_gb = DIV_ROUND_UP(DC3CO_ENTRY_LATENCY, line_time_us);
+
+       /* DC5 Exit Latency - DC3co Exit Latency / linetime */
+       dc5_exit_latency = DIV_ROUND_UP(DC3CO_EXIT_LATENCY, line_time_us);
+
+       val = REG_FIELD_PREP(CMTG_HW_GB_BREAKEVEN_MASK, breakeven_gb) |
+             REG_FIELD_PREP(CMTG_HW_GB_DC5_EXIT_LATENCY_MASK, 
dc5_exit_latency) |
+             REG_FIELD_PREP(CMTG_HW_GB_UP_LW_BG_DIFF_MASK, 1);
+
+       intel_de_write(display, CMTG_HW_GB(cpu_transcoder), val);
+}
+
+bool intel_cmtg_program(struct intel_atomic_state *state)
+{
+       struct intel_display *display = to_intel_display(state);
+       struct intel_crtc *crtc;
+       struct intel_crtc_state *new_crtc_state;
+       bool dc3co_to_dc6 = 
intel_display_power_get_and_reset_dc3co_to_dc6(display);
+
+       for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state) {
+               bool modeset = intel_crtc_needs_modeset(new_crtc_state);
+
+               if ((modeset || dc3co_to_dc6) &&
+                   new_crtc_state->hw.active && !crtc->cmtg.enabled) {
+                       u32 psr2_status;
+                       enum transcoder cpu_transcoder = 
new_crtc_state->cpu_transcoder;
+                       /*
+                        * CMTG & DC3CO should not be enabled when transcoder 
in PSR2 deep sleep.
+                        * Return for first failure as more than one active 
crctc is not a
+                        * valid configuration.
+                        * FIXME: Check if this check can be decoupled from 
CMTG.
+                        */
+                       psr2_status = intel_de_read(display,
+                                                   EDP_PSR2_STATUS(display, 
cpu_transcoder));
+                       if (psr2_status & EDP_PSR2_STATUS_STATE_DEEP_SLEEP) {
+                               drm_dbg_kms(display->drm,
+                                           "PSR2 is in deep sleep on %s, 
skipping CMTG enable\n",
+                                           transcoder_name(cpu_transcoder));
+                               return false;
+                       }
+
+                       if (dc3co_to_dc6) {
+                               intel_cmtg_set_clk_select(new_crtc_state);
+                               intel_cmtg_set_timings(new_crtc_state, false);
+                               intel_cmtg_set_vrr_timings(new_crtc_state);
+                               intel_cmtg_set_vrr_ctl(new_crtc_state);
+                               intel_cmtg_set_m_n(new_crtc_state);
+                       }
+
+                       intel_cmtg_enable_sync(new_crtc_state);
+                       intel_cmtg_set_hwgb(new_crtc_state);
+                       intel_cmtg_enable_ddi(new_crtc_state);
+                       intel_cmtg_enable_interrupt(new_crtc_state);
+               }
+       }
+       /* return success , unless indicated otherwise */
+       return true;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.h 
b/drivers/gpu/drm/i915/display/intel_cmtg.h
index ba62199adaa2..3c6eec1174dd 100644
--- a/drivers/gpu/drm/i915/display/intel_cmtg.h
+++ b/drivers/gpu/drm/i915/display/intel_cmtg.h
@@ -6,8 +6,25 @@
 #ifndef __INTEL_CMTG_H__
 #define __INTEL_CMTG_H__
 
+#include <linux/types.h>
+
+struct intel_atomic_state;
 struct intel_display;
+struct intel_crtc_state;
 
+void intel_cmtg_disable(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_enable_ddi(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_enable_sync(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_set_m_n(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_set_vrr_timings(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_set_vrr_ctl(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_set_timings(const struct intel_crtc_state *crtc_state, bool 
lrr);
+void intel_cmtg_set_clk_select(const struct intel_crtc_state *crtc_state);
 void intel_cmtg_sanitize(struct intel_display *display);
+bool intel_cmtg_is_allowed(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_enable_interrupt(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_disable_interrupt(const struct intel_crtc_state *crtc_state);
+void intel_cmtg_set_hwgb(const struct intel_crtc_state *crtc_state);
+bool intel_cmtg_program(struct intel_atomic_state *state);
 
 #endif /* __INTEL_CMTG_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_cmtg_regs.h 
b/drivers/gpu/drm/i915/display/intel_cmtg_regs.h
index 945a35578284..18dcb665df04 100644
--- a/drivers/gpu/drm/i915/display/intel_cmtg_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_cmtg_regs.h
@@ -10,12 +10,32 @@
 
 #define CMTG_CLK_SEL                   _MMIO(0x46160)
 #define CMTG_CLK_SEL_A_MASK            REG_GENMASK(31, 29)
+#define CMTG_CLK_SELECT_PHYA_ENABLE    REG_FIELD_PREP(CMTG_CLK_SEL_A_MASK, 0x4)
 #define CMTG_CLK_SEL_A_DISABLED                
REG_FIELD_PREP(CMTG_CLK_SEL_A_MASK, 0)
 #define CMTG_CLK_SEL_B_MASK            REG_GENMASK(15, 13)
+#define CMTG_CLK_SELECT_PHYB_ENABLE    REG_FIELD_PREP(CMTG_CLK_SEL_B_MASK, 0x6)
 #define CMTG_CLK_SEL_B_DISABLED                
REG_FIELD_PREP(CMTG_CLK_SEL_B_MASK, 0)
 
-#define TRANS_CMTG_CTL_A               _MMIO(0x6fa88)
-#define TRANS_CMTG_CTL_B               _MMIO(0x6fb88)
+#define _TRANS_CMTG_CTL_A              0x6fa88
+#define _TRANS_CMTG_CTL_B              0x6fb88
+#define TRANS_CMTG_CTL(trans)          _MMIO_TRANS((trans), \
+                                                   _TRANS_CMTG_CTL_A, 
_TRANS_CMTG_CTL_B)
 #define  CMTG_ENABLE                   REG_BIT(31)
+#define  CMTG_SYNC_TO_PORT             REG_BIT(29)
+#define  CMTG_STATE                    REG_BIT(23)
+
+#define _CMTG_HW_GB_A                          0x6fa8c
+#define _CMTG_HW_GB_B                          0x6fb8c
+#define CMTG_HW_GB(trans)                      _MMIO_TRANS((trans), \
+                                                           _CMTG_HW_GB_A, 
_CMTG_HW_GB_B)
+#define CMTG_HW_GB_BREAKEVEN_MASK              REG_GENMASK(11, 0)
+#define CMTG_HW_GB_DC5_EXIT_LATENCY_MASK       REG_GENMASK(27, 16)
+#define CMTG_HW_GB_UP_LW_BG_DIFF_MASK          REG_GENMASK(31, 28)
+
+#define _CMTG_SCANLINE_GB1_A           0x456A0
+#define _CMTG_SCANLINE_GB1_B           0x456C0
+#define CMTG_SCANLINE_GB1(trans)       _MMIO_TRANS((trans), \
+                                                   _CMTG_SCANLINE_GB1_A, 
_CMTG_SCANLINE_GB1_B)
+#define  CMTG_HW_GB_ENABLE             REG_BIT(31)
 
 #endif /* __INTEL_CMTG_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c 
b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index 24a51ab21b55..acf48a25b1d6 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -9,6 +9,7 @@
 #include <drm/drm_print.h>
 
 #include "intel_alpm.h"
+#include "intel_cmtg.h"
 #include "intel_cx0_phy.h"
 #include "intel_cx0_phy_regs.h"
 #include "intel_display_regs.h"
@@ -3418,10 +3419,14 @@ void intel_mtl_pll_enable(struct intel_encoder *encoder,
 void intel_mtl_pll_enable_clock(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state)
 {
+       struct intel_display *display = to_intel_display(encoder);
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 
        if (intel_tc_port_in_tbt_alt_mode(dig_port))
                intel_mtl_tbt_pll_enable_clock(encoder, crtc_state->port_clock);
+
+       if (HAS_LT_PHY(display))
+               intel_cmtg_set_clk_select(crtc_state);
 }
 
 /*
diff --git a/drivers/gpu/drm/i915/display/intel_display.c 
b/drivers/gpu/drm/i915/display/intel_display.c
index 3d91495905e8..2fdda8d554b9 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -60,6 +60,7 @@
 #include "intel_bw.h"
 #include "intel_cdclk.h"
 #include "intel_clock_gating.h"
+#include "intel_cmtg.h"
 #include "intel_color.h"
 #include "intel_crt.h"
 #include "intel_crtc.h"
@@ -1635,6 +1636,7 @@ static void hsw_configure_cpu_transcoder(const struct 
intel_crtc_state *crtc_sta
                                               &crtc_state->dp_m2_n2);
        }
 
+       intel_cmtg_set_m_n(crtc_state);
        intel_set_transcoder_timings(crtc_state);
 
        if (cpu_transcoder != TRANSCODER_EDP)
@@ -1788,6 +1790,11 @@ static void hsw_crtc_disable(struct intel_atomic_state 
*state,
                intel_atomic_get_old_crtc_state(state, crtc);
        struct intel_crtc *pipe_crtc;
 
+       if (crtc->cmtg.enabled) {
+               intel_cmtg_set_clk_select(old_crtc_state);
+               intel_cmtg_disable(old_crtc_state);
+       }
+
        /*
         * FIXME collapse everything to one hook.
         * Need care with mst->ddi interactions.
@@ -2772,6 +2779,8 @@ static void intel_set_transcoder_timings(const struct 
intel_crtc_state *crtc_sta
                intel_de_write(display, DP_MIN_HBLANK_CTL(cpu_transcoder),
                               crtc_state->min_hblank);
        }
+
+       intel_cmtg_set_timings(crtc_state, false);
 }
 
 static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state 
*crtc_state)
@@ -2833,6 +2842,7 @@ static void intel_set_transcoder_timings_lrr(const struct 
intel_crtc_state *crtc
                       VACTIVE(crtc_vdisplay - 1) |
                       VTOTAL(crtc_vtotal - 1));
 
+       intel_cmtg_set_timings(crtc_state, true);
        intel_vrr_set_fixed_rr_timings(crtc_state);
        intel_vrr_transcoder_enable(crtc_state);
 }
@@ -6666,9 +6676,11 @@ static void intel_pipe_fastset(const struct 
intel_crtc_state *old_crtc_state,
            display->platform.broadwell || display->platform.haswell)
                hsw_set_linetime_wm(new_crtc_state);
 
-       if (new_crtc_state->update_m_n)
+       if (new_crtc_state->update_m_n) {
                intel_cpu_transcoder_set_m1_n1(crtc, 
new_crtc_state->cpu_transcoder,
                                               &new_crtc_state->dp_m_n);
+               intel_cmtg_set_m_n(new_crtc_state);
+       }
 
        if (new_crtc_state->update_lrr)
                intel_set_transcoder_timings_lrr(new_crtc_state);
@@ -6869,6 +6881,13 @@ static void intel_update_crtc(struct intel_atomic_state 
*state,
        if (intel_crtc_needs_fastset(new_crtc_state) &&
            old_crtc_state->inherited)
                intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
+
+       if (crtc->cmtg.enabled && (intel_crtc_vrr_enabling(state, crtc) ||
+                                  !intel_cmtg_is_allowed(new_crtc_state))) {
+               intel_cmtg_set_clk_select(new_crtc_state);
+               intel_cmtg_disable(new_crtc_state);
+               intel_cmtg_disable_interrupt(new_crtc_state);
+       }
 }
 
 static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
@@ -7538,6 +7557,8 @@ static void intel_atomic_commit_tail(struct 
intel_atomic_state *state)
        /* FIXME probably need to sequence this properly */
        intel_program_dpkgc_latency(state);
 
+       intel_cmtg_program(state);
+
        intel_wait_for_vblank_workers(state);
 
        /* FIXME: We should call drm_atomic_helper_commit_hw_done() here
diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c 
b/drivers/gpu/drm/i915/display/intel_display_device.c
index 69a9f782935c..f17fc2c68472 100644
--- a/drivers/gpu/drm/i915/display/intel_display_device.c
+++ b/drivers/gpu/drm/i915/display/intel_display_device.c
@@ -101,6 +101,8 @@ static const struct intel_display_device_info no_display = 
{};
 #define TRANSCODER_EDP_OFFSET 0x6f000
 #define TRANSCODER_DSI0_OFFSET 0x6b000
 #define TRANSCODER_DSI1_OFFSET 0x6b800
+#define TRANSCODER_CMTG0_OFFSET 0x6F000
+#define TRANSCODER_CMTG1_OFFSET 0x6F100
 
 #define CURSOR_A_OFFSET 0x70080
 #define CURSOR_B_OFFSET 0x700c0
@@ -1352,6 +1354,18 @@ static const struct intel_display_device_info 
xe2_lpd_display = {
                BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B) |
                BIT(INTEL_FBC_C) | BIT(INTEL_FBC_D),
        .__runtime_defaults.has_dbuf_overlap_detection = true,
+       .trans_offsets = {
+               [TRANSCODER_A] = TRANSCODER_A_OFFSET,
+               [TRANSCODER_B] = TRANSCODER_B_OFFSET,
+               [TRANSCODER_C] = TRANSCODER_C_OFFSET,
+               [TRANSCODER_D] = TRANSCODER_D_OFFSET,
+               [TRANSCODER_CMTG0] = TRANSCODER_CMTG0_OFFSET,
+               [TRANSCODER_CMTG1] = TRANSCODER_CMTG1_OFFSET,
+       },
+       .__runtime_defaults.cpu_transcoder_mask =
+               BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
+               BIT(TRANSCODER_C) | BIT(TRANSCODER_D) |
+               BIT(TRANSCODER_CMTG0) | BIT(TRANSCODER_CMTG1),
 };
 
 static const struct intel_display_device_info wcl_display = {
diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h 
b/drivers/gpu/drm/i915/display/intel_display_device.h
index 12e5a522a299..acb9ca87dda7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_device.h
+++ b/drivers/gpu/drm/i915/display/intel_display_device.h
@@ -292,7 +292,7 @@ struct intel_display_runtime_info {
        u32 rawclk_freq;
 
        u8 pipe_mask;
-       u8 cpu_transcoder_mask;
+       u16 cpu_transcoder_mask;
        u16 port_mask;
 
        u8 num_sprites[I915_MAX_PIPES];
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c 
b/drivers/gpu/drm/i915/display/intel_display_irq.c
index 4a821b0674fd..d849a633ce44 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -1469,6 +1469,18 @@ static void gen8_de_irq_handler(struct intel_display 
*display, u32 master_ctl)
                                found = true;
                        }
 
+                       if (DISPLAY_VER(display) == 35) {
+                               if (iir & (CMTG_VBLANK_A | CMTG_VSYNC_A | 
CMTG_DELAYED_VBLANK_A)) {
+                                       intel_handle_vblank(display, PIPE_A);
+                                       found = true;
+                               }
+
+                               if (iir & (CMTG_VBLANK_B | CMTG_VSYNC_B | 
CMTG_DELAYED_VBLANK_B)) {
+                                       intel_handle_vblank(display, PIPE_B);
+                                       found = true;
+                               }
+                       }
+
                        if (DISPLAY_VER(display) >= 11) {
                                u32 te_trigger = iir & (DSI0_TE | DSI1_TE);
 
diff --git a/drivers/gpu/drm/i915/display/intel_display_limits.h 
b/drivers/gpu/drm/i915/display/intel_display_limits.h
index 453f7b720815..ea89473c177f 100644
--- a/drivers/gpu/drm/i915/display/intel_display_limits.h
+++ b/drivers/gpu/drm/i915/display/intel_display_limits.h
@@ -45,6 +45,8 @@ enum transcoder {
        TRANSCODER_DSI_1,
        TRANSCODER_DSI_A = TRANSCODER_DSI_0,    /* legacy DSI */
        TRANSCODER_DSI_C = TRANSCODER_DSI_1,    /* legacy DSI */
+       TRANSCODER_CMTG0,
+       TRANSCODER_CMTG1,
 
        I915_MAX_TRANSCODERS
 };
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c 
b/drivers/gpu/drm/i915/display/intel_display_power.c
index b2dcfeedbd2c..ccd5d847b2fb 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -285,6 +285,19 @@ sanitize_target_dc_state(struct intel_display *display,
        return target_dc_state;
 }
 
+bool intel_display_power_get_and_reset_dc3co_to_dc6(struct intel_display 
*display)
+{
+       struct i915_power_domains *power_domains = &display->power.domains;
+       bool ret;
+
+       mutex_lock(&power_domains->lock);
+       ret = power_domains->dc3co_to_dc6;
+       power_domains->dc3co_to_dc6 = false;
+       mutex_unlock(&power_domains->lock);
+
+       return ret;
+}
+
 /**
  * intel_display_power_set_target_dc_state - Set target dc state.
  * @display: display device
@@ -320,6 +333,10 @@ void intel_display_power_set_target_dc_state(struct 
intel_display *display,
        if (!dc_off_enabled)
                intel_power_well_enable(display, power_well);
 
+       if (power_domains->target_dc_state == DC_STATE_EN_DC3CO &&
+           state == DC_STATE_EN_UPTO_DC6)
+               power_domains->dc3co_to_dc6 = true;
+
        power_domains->target_dc_state = state;
 
        if (!dc_off_enabled)
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h 
b/drivers/gpu/drm/i915/display/intel_display_power.h
index a43fab19e530..41419acabdc6 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -138,6 +138,7 @@ struct i915_power_domains {
         */
        bool initializing;
        bool display_core_suspended;
+       bool dc3co_to_dc6;
        int power_well_count;
 
        u32 dc_state;
@@ -181,6 +182,7 @@ void intel_display_power_suspend_late(struct intel_display 
*display, bool s2idle
 void intel_display_power_resume_early(struct intel_display *display);
 void intel_display_power_suspend(struct intel_display *display);
 void intel_display_power_resume(struct intel_display *display);
+bool intel_display_power_get_and_reset_dc3co_to_dc6(struct intel_display 
*display);
 void intel_display_power_set_target_dc_state(struct intel_display *display,
                                             u32 state);
 u32 intel_display_power_get_current_dc_state(struct intel_display *display);
diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h 
b/drivers/gpu/drm/i915/display/intel_display_regs.h
index 4321f8b529da..f38dcd9b6c48 100644
--- a/drivers/gpu/drm/i915/display/intel_display_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_display_regs.h
@@ -1458,6 +1458,12 @@
 #define  GEN9_AUX_CHANNEL_B            (1 << 25)
 #define  DSI1_TE                       (1 << 24)
 #define  DSI0_TE                       (1 << 23)
+#define  CMTG_VSYNC_B                  (1 << 19)
+#define  CMTG_DELAYED_VBLANK_B         (1 << 18)
+#define  CMTG_VBLANK_B                 (1 << 17)
+#define  CMTG_VSYNC_A                  (1 << 16)
+#define  CMTG_DELAYED_VBLANK_A         (1 << 15)
+#define  CMTG_VBLANK_A                 (1 << 14)
 #define  GEN8_DE_PORT_HOTPLUG(hpd_pin) REG_BIT(3 + _HPD_PIN_DDI(hpd_pin))
 #define  BXT_DE_PORT_HOTPLUG_MASK      (GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) | \
                                         GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) | \
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 13ce37a71b68..c1ca3fa6be0c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1573,6 +1573,10 @@ struct intel_crtc {
 #endif
 
        bool vblank_psr_notify;
+
+       struct {
+               bool enabled;
+       } cmtg;
 };
 
 struct intel_plane_error {
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c 
b/drivers/gpu/drm/i915/display/intel_vrr.c
index e03b5daac5be..825d5fba9bca 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -7,6 +7,7 @@
 #include <drm/drm_print.h>
 
 #include "intel_alpm.h"
+#include "intel_cmtg.h"
 #include "intel_crtc.h"
 #include "intel_de.h"
 #include "intel_display_regs.h"
@@ -332,6 +333,8 @@ void intel_vrr_set_fixed_rr_timings(const struct 
intel_crtc_state *crtc_state)
                       intel_vrr_fixed_rr_hw_vmax(crtc_state) - 1);
        intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder),
                       intel_vrr_fixed_rr_hw_flipline(crtc_state) - 1);
+
+       intel_cmtg_set_vrr_timings(crtc_state);
 }
 
 static
@@ -930,6 +933,8 @@ static void intel_vrr_tg_enable(const struct 
intel_crtc_state *crtc_state,
                vrr_ctl |= VRR_CTL_CMRR_ENABLE;
 
        intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), 
vrr_ctl);
+
+       intel_cmtg_set_vrr_ctl(crtc_state);
 }
 
 static void intel_vrr_tg_disable(const struct intel_crtc_state *old_crtc_state)
-- 
2.43.0

Reply via email to