drm/i915/cmtg: Add CMTG interrupt handling

Add support for the CMTG vblank interrupt, which is delivered
through the DE port interrupt block. Enable/disable the interrupt
via the DE port IMR around CMTG enable/disable, and dispatch the
CMTG_VBLANK_{A,B} bits to the corresponding pipe vblank handler in
the gen8 DE IRQ handler.

Wired up for DISPLAY_VER 35. The CMTG interrupt is not enabled via
IER today because CMTG is brought up together with the eDP
transcoder; this can be revisited later.

v2:
- Use consistent DC3co check as used in earlier patches. [Uma]
- Use else-if instead of separate if block. [Uma]
- Merge mask and unmask function as it is similar. [Uma]
- Modify DISPLAY_VER() check. [Uma]

v3:
- Enable only vblank interrupt. [Dibin]

v4:
- Keep irq related code to intel_display_irq.c. [Jani, Uma]

Signed-off-by: Animesh Manna <animesh.manna@intel.com>
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Link: https://patch.msgid.link/20260615200339.885190-23-animesh.manna@intel.com
This commit is contained in:
Animesh Manna 2026-06-16 01:33:39 +05:30
parent f9360ef054
commit 481fe84b73
4 changed files with 46 additions and 1 deletions

View File

@ -14,6 +14,7 @@
#include "intel_de.h"
#include "intel_display.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"
@ -177,7 +178,7 @@ void intel_cmtg_disable(const struct intel_crtc_state *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;
u32 clk_sel_clr = 0, interrupt_mask = 0;
if (!crtc->cmtg.enabled)
return;
@ -210,6 +211,13 @@ void intel_cmtg_disable(const struct intel_crtc_state *crtc_state)
intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, 0);
drm_dbg_kms(display->drm, "CMTG: %s disabled\n", transcoder_name(cpu_transcoder));
if (cpu_transcoder == TRANSCODER_A)
interrupt_mask = CMTG_VBLANK_A;
else if (cpu_transcoder == TRANSCODER_B)
interrupt_mask = CMTG_VBLANK_B;
intel_display_irq_port_interrupt_mask(display, interrupt_mask, true);
}
/*
@ -355,11 +363,25 @@ static 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;
u32 interrupt_mask = 0;
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));
/*
* TODO: Currently cmtg is enabled along with eDP transcoder so cmtg
* interrupt is not enabled through IER, need to do some fine
* tuning in future.
*/
if (cpu_transcoder == TRANSCODER_A)
interrupt_mask = CMTG_VBLANK_A;
else if (cpu_transcoder == TRANSCODER_B)
interrupt_mask = CMTG_VBLANK_B;
intel_display_irq_port_interrupt_mask(display, interrupt_mask, false);
}
/* Bspec: 75253 */

View File

@ -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) {
intel_handle_vblank(display, PIPE_A);
found = true;
}
if (iir & CMTG_VBLANK_B) {
intel_handle_vblank(display, PIPE_B);
found = true;
}
}
if (DISPLAY_VER(display) >= 11) {
u32 te_trigger = iir & (DSI0_TE | DSI1_TE);
@ -2666,3 +2678,10 @@ void intel_display_irq_snapshot_print(const struct intel_display_irq_snapshot *s
drm_printf(p, "DERRMR: 0x%08x\n", snapshot->derrmr);
drm_printf(p, "ERR_INT: 0x%08x\n", snapshot->err_int);
}
void intel_display_irq_port_interrupt_mask(struct intel_display *display, u32 bits, bool mask)
{
spin_lock_irq(&display->irq.lock);
bdw_update_port_irq(display, bits, mask ? 0 : bits);
spin_unlock_irq(&display->irq.lock);
}

View File

@ -82,4 +82,6 @@ void i915gm_irq_cstate_wa(struct intel_display *display, bool enable);
struct intel_display_irq_snapshot *intel_display_irq_snapshot_capture(struct intel_display *display);
void intel_display_irq_snapshot_print(const struct intel_display_irq_snapshot *snapshot, struct drm_printer *p);
void intel_display_irq_port_interrupt_mask(struct intel_display *display, u32 bits, bool mask);
#endif /* __INTEL_DISPLAY_IRQ_H__ */

View File

@ -1458,6 +1458,8 @@
#define GEN9_AUX_CHANNEL_B (1 << 25)
#define DSI1_TE (1 << 24)
#define DSI0_TE (1 << 23)
#define CMTG_VBLANK_B (1 << 17)
#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) | \