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