From: Animesh Manna <[email protected]> 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 | 361 +++++++++++++++++- 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, 482 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..c1f4fa50f688 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,302 @@ 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; + int i; + 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, i) { + 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 757a78c75bbf..209a92f8ff15 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" @@ -1614,6 +1615,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) @@ -1769,6 +1771,11 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, struct intel_crtc *pipe_crtc; int i; + 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. @@ -2753,6 +2760,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) @@ -2814,6 +2823,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); } @@ -6653,9 +6663,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); @@ -6856,6 +6868,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, @@ -7533,6 +7552,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 899a38c0a7b7..f7f670dd5900 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 751e6b7d4a29..637d547831c0 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 d616d5d09cbe..b43d4146a78a 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; @@ -183,6 +184,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 f44be5c689ae..924f0b90d560 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1572,6 +1572,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 1b09992ce9fd..1260ceb7958e 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" @@ -334,6 +335,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 @@ -932,6 +935,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
