On Tue, 2024-12-31 at 10:08 -0300, Gustavo Sousa wrote: > Quoting Hogander, Jouni (2024-12-31 08:23:58-03:00) > > On Tue, 2024-12-24 at 13:53 -0300, Gustavo Sousa wrote: > > > The CMTG is a timing generator that runs in parallel with > > > transcoders > > > timing generators and can be used as a reference for > > > synchronization. > > > > > > On PTL (display Xe3_LPD), we have observed that we are inheriting > > > from > > > GOP a display configuration with the CMTG enabled. Because our > > > driver > > > doesn't currently implement any CMTG sequences, the CMTG ends up > > > still > > > enabled after our driver takes over. > > > > > > We need to make sure that the CMTG is not enabled if we are not > > > going > > > to > > > use it. For that, let's add a partial implementation in our > > > driver > > > that > > > only cares about disabling the CMTG if it was found enabled > > > during > > > initial hardware readout. In the future, we can also implement > > > sequences > > > for enabling CMTG if that becomes a needed feature. > > > > > > For completeness, we do not only cover Xe3_LPD but also all > > > previous > > > display IPs that provide the CMTG. > > > > > > v2: > > > - DG2 does not have the CMTG. Update HAS_CMTG() accordingly. > > > - Update logic to force disabling of CMTG only for initial > > > commit. > > > v3: > > > - Add missing changes for v2 that were staged but not committed. > > > > > > Signed-off-by: Gustavo Sousa <gustavo.sousa@xxxxxxxxx> > > > --- > > > drivers/gpu/drm/i915/Makefile | 1 + > > > drivers/gpu/drm/i915/display/intel_cmtg.c | 311 > > > ++++++++++++++++++ > > > drivers/gpu/drm/i915/display/intel_cmtg.h | 38 +++ > > > .../gpu/drm/i915/display/intel_cmtg_regs.h | 21 ++ > > > drivers/gpu/drm/i915/display/intel_display.c | 11 + > > > .../gpu/drm/i915/display/intel_display_core.h | 4 + > > > .../drm/i915/display/intel_display_device.h | 1 + > > > .../drm/i915/display/intel_display_driver.c | 5 + > > > .../drm/i915/display/intel_modeset_setup.c | 5 + > > > drivers/gpu/drm/i915/i915_reg.h | 1 + > > > drivers/gpu/drm/xe/Makefile | 1 + > > > 11 files changed, 399 insertions(+) > > > create mode 100644 drivers/gpu/drm/i915/display/intel_cmtg.c > > > create mode 100644 drivers/gpu/drm/i915/display/intel_cmtg.h > > > create mode 100644 > > > drivers/gpu/drm/i915/display/intel_cmtg_regs.h > > > > > > diff --git a/drivers/gpu/drm/i915/Makefile > > > b/drivers/gpu/drm/i915/Makefile > > > index 3dda9f0eda82..7e7414453765 100644 > > > --- a/drivers/gpu/drm/i915/Makefile > > > +++ b/drivers/gpu/drm/i915/Makefile > > > @@ -231,6 +231,7 @@ i915-y += \ > > > display/intel_bo.o \ > > > display/intel_bw.o \ > > > display/intel_cdclk.o \ > > > + display/intel_cmtg.o \ > > > display/intel_color.o \ > > > display/intel_combo_phy.o \ > > > display/intel_connector.o \ > > > diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.c > > > b/drivers/gpu/drm/i915/display/intel_cmtg.c > > > new file mode 100644 > > > index 000000000000..27491497f515 > > > --- /dev/null > > > +++ b/drivers/gpu/drm/i915/display/intel_cmtg.c > > > @@ -0,0 +1,311 @@ > > > +// SPDX-License-Identifier: MIT > > > +/* > > > + * Copyright (C) 2024 Intel Corporation > > > + */ > > > + > > > +#include <linux/string.h> > > > +#include <linux/string_choices.h> > > > +#include <linux/types.h> > > > + > > > +#include "i915_drv.h" > > > +#include "i915_reg.h" > > > +#include "intel_crtc.h" > > > +#include "intel_de.h" > > > +#include "intel_cmtg.h" > > > +#include "intel_cmtg_regs.h" > > > +#include "intel_display_device.h" > > > +#include "intel_display_types.h" > > > + > > > +/** > > > + * DOC: Common Primary Timing Generator (CMTG) > > > + * > > > + * The CMTG is a timing generator that runs in parallel to > > > transcoders timing > > > + * generators (TG) to provide a synchronization mechanism where > > > CMTG > > > acts as > > > + * primary and transcoders TGs act as secondary to the CMTG. The > > > CMTG outputs > > > + * its TG start and frame sync signals to the transcoders that > > > are > > > configured > > > + * as secondary, which use those signals to synchronize their > > > own > > > timing with > > > + * the CMTG's. > > > + * > > > + * The CMTG can be used only with eDP or MIPI command mode and > > > supports the > > > + * following use cases: > > > + * > > > + * - Dual eDP: The CMTG can be used to keep two eDP TGs in sync > > > when > > > on a > > > + * dual eDP configuration (with or without PSR/PSR2 enabled). > > > + * > > > + * - Single eDP as secondary: It is also possible to use a > > > single > > > eDP > > > + * configuration with the transcoder TG as secondary to the > > > CMTG. > > > That would > > > + * allow a flow that would not require a modeset on the > > > existing > > > eDP when a > > > + * new eDP is added for a dual eDP configuration with CMTG. > > > + * > > > + * - DC6v: In DC6v, the transcoder might be off but the CMTG > > > keeps > > > running to > > > + * maintain frame timings. When exiting DC6v, the transcoder > > > TG > > > then is > > > + * synced back the CMTG. > > > + * > > > + * Currently, the driver does not use the CMTG, but we need to > > > make > > > sure that > > > + * we disable it in case we inherit a display configuration with > > > it > > > enabled. > > > + */ > > > + > > > +static struct intel_global_state * > > > +intel_cmtg_duplicate_state(struct intel_global_obj *obj) > > > +{ > > > + struct intel_cmtg_state *cmtg_state = > > > to_intel_cmtg_state(obj->state); > > > + > > > + cmtg_state = kmemdup(cmtg_state, sizeof(*cmtg_state), > > > GFP_KERNEL); > > > + if (!cmtg_state) > > > + return NULL; > > > + > > > + return &cmtg_state->base; > > > +} > > > + > > > +static void intel_cmtg_destroy_state(struct intel_global_obj > > > *obj, > > > + struct intel_global_state > > > *state) > > > +{ > > > + kfree(state); > > > +} > > > + > > > +static const struct intel_global_state_funcs > > > intel_cmtg_state_funcs > > > = { > > > + .atomic_duplicate_state = intel_cmtg_duplicate_state, > > > + .atomic_destroy_state = intel_cmtg_destroy_state, > > > +}; > > > + > > > +static bool intel_cmtg_has_cmtg_b(struct intel_display *display) > > > +{ > > > + return DISPLAY_VER(display) >= 20; > > > +} > > > + > > > +static bool intel_cmtg_has_clock_sel(struct intel_display > > > *display) > > > +{ > > > + return DISPLAY_VER(display) >= 14; > > > +} > > > + > > > +static bool intel_cmtg_requires_modeset(struct intel_display > > > *display) > > > +{ > > > + return DISPLAY_VER(display) < 20; > > > +} > > > + > > > +static void intel_cmtg_dump_state(struct intel_display *display, > > > + struct intel_cmtg_state > > > *cmtg_state) > > > +{ > > > + if (intel_cmtg_has_cmtg_b(display)) > > > + drm_dbg_kms(display->drm, > > > + "CMTG state readout: CMTG A: %s, > > > CMTG B: > > > %s, transcoder A secondary: %s, transcoder B secondary: %s\n", > > > + str_enabled_disabled(cmtg_state- > > > > cmtg_a_enable), > > > + str_enabled_disabled(cmtg_state- > > > > cmtg_b_enable), > > > + str_yes_no(cmtg_state- > > > > trans_a_secondary), > > > + str_yes_no(cmtg_state- > > > > trans_b_secondary)); > > > + else > > > + drm_dbg_kms(display->drm, > > > + "CMTG state readout: %s, Transcoder > > > A > > > secondary: %s, Transcoder B secondary: %s\n", > > > + str_enabled_disabled(cmtg_state- > > > > cmtg_a_enable), > > > + str_yes_no(cmtg_state- > > > > trans_a_secondary), > > > + str_yes_no(cmtg_state- > > > > trans_b_secondary)); > > > +} > > > + > > > +int intel_cmtg_init(struct intel_display *display) > > > +{ > > > + struct drm_i915_private *i915 = to_i915(display->drm); > > > + struct intel_cmtg_state *cmtg_state; > > > + > > > + cmtg_state = kzalloc(sizeof(*cmtg_state), GFP_KERNEL); > > > + if (!cmtg_state) > > > + return -ENOMEM; > > > + > > > + intel_atomic_global_obj_init(i915, &display->cmtg.obj, > > > + &cmtg_state->base, > > > + &intel_cmtg_state_funcs); > > > + > > > + return 0; > > > +} > > > + > > > +void intel_cmtg_readout_state(struct intel_display *display, > > > + struct intel_cmtg_state > > > *cmtg_state) > > > +{ > > > + struct drm_i915_private *i915 = to_i915(display->drm); > > > + u32 val; > > > + > > > + if (!HAS_CMTG(display)) > > > + return; > > > + > > > + val = intel_de_read(display, TRANS_CMTG_CTL_A); > > > + cmtg_state->cmtg_a_enable = val & CMTG_ENABLE; > > > + > > > + if (intel_cmtg_has_cmtg_b(display)) { > > > + val = intel_de_read(display, TRANS_CMTG_CTL_B); > > > + cmtg_state->cmtg_b_enable = val & CMTG_ENABLE; > > > + } > > > + > > > + if (intel_crtc_for_pipe(display, PIPE_A)) { > > > + val = intel_de_read(display, > > > TRANS_DDI_FUNC_CTL2(i915, TRANSCODER_A)); > > > + cmtg_state->trans_a_secondary = val & > > > CMTG_SECONDARY_MODE; > > > + } > > > + > > > + if (intel_crtc_for_pipe(display, PIPE_B)) { > > > + val = intel_de_read(display, > > > TRANS_DDI_FUNC_CTL2(i915, TRANSCODER_B)); > > > + cmtg_state->trans_b_secondary = val & > > > CMTG_SECONDARY_MODE; > > > + } > > > + > > > + intel_cmtg_dump_state(display, cmtg_state); > > > +} > > > + > > > +static struct intel_cmtg_state * > > > +intel_atomic_get_cmtg_state(struct intel_atomic_state *state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + struct intel_global_state *obj_state = > > > + intel_atomic_get_global_obj_state(state, > > > + &display- > > > > cmtg.obj); > > > + > > > + if (IS_ERR(obj_state)) > > > + return ERR_CAST(obj_state); > > > + > > > + return to_intel_cmtg_state(obj_state); > > > +} > > > + > > > +static struct intel_cmtg_state * > > > +intel_atomic_get_old_cmtg_state(struct intel_atomic_state > > > *state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + struct intel_global_state *obj_state = > > > + intel_atomic_get_old_global_obj_state(state, > > > + &display- > > > > cmtg.obj); > > > + > > > + if (!obj_state) > > > + return NULL; > > > + > > > + return to_intel_cmtg_state(obj_state); > > > +} > > > + > > > +static struct intel_cmtg_state * > > > +intel_atomic_get_new_cmtg_state(struct intel_atomic_state > > > *state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + struct intel_global_state *obj_state = > > > + intel_atomic_get_new_global_obj_state(state, > > > + &display- > > > > cmtg.obj); > > > + > > > + if (!obj_state) > > > + return NULL; > > > + > > > + return to_intel_cmtg_state(obj_state); > > > +} > > > + > > > +static bool intel_cmtg_state_changed(struct intel_cmtg_state > > > *old_cmtg_state, > > > + struct intel_cmtg_state > > > *new_cmtg_state) > > > +{ > > > + if (!new_cmtg_state) > > > + return false; > > > + > > > + return old_cmtg_state->cmtg_a_enable != new_cmtg_state- > > > > cmtg_a_enable || > > > + old_cmtg_state->cmtg_b_enable != new_cmtg_state- > > > > cmtg_b_enable || > > > + old_cmtg_state->trans_a_secondary != > > > new_cmtg_state- > > > > trans_a_secondary || > > > + old_cmtg_state->trans_b_secondary != > > > new_cmtg_state- > > > > trans_b_secondary; > > > +} > > > + > > > +static int intel_cmtg_check_modeset(struct intel_atomic_state > > > *state, > > > + struct intel_cmtg_state > > > *old_cmtg_state, > > > + struct intel_cmtg_state > > > *new_cmtg_state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + u8 pipe_mask; > > > + > > > + if (!intel_cmtg_requires_modeset(display)) > > > + return 0; > > > + > > > + pipe_mask = 0; > > > + > > > + if (old_cmtg_state->trans_a_secondary != new_cmtg_state- > > > > trans_a_secondary) > > > + pipe_mask |= BIT(PIPE_A); > > > + > > > + if (old_cmtg_state->trans_b_secondary != new_cmtg_state- > > > > trans_b_secondary) > > > + pipe_mask |= BIT(PIPE_B); > > > > On PTL this would mean we are always doing full modeset on boot? Is > > No. Because of intel_cmtg_requires_modeset(), we only go through this > if > we are on a display prior to Xe2_LPD (LNL's display). So, for PTL, a > modeset will not be required. > > > full modeset really required when disabling CTMG? Bspec says: > > > > "Switching between the local timing generator within the eDP and > > the > > CMTG will require a modeset." > > This is from the BSpec for pre-LNL displays (i.e. pre-Xe2_LPD). The > BSpec for LNL and PTL does not impose this restriction. > > > > > Are we really using CTMG or is it just enabled? > > The setup from GOP is using the CMTG with Pipe A. Ok, thank you for the clarification. BR, Jouni Högander > > -- > Gustavo Sousa > > > > > BR, > > > > Jouni Högander > > > > > + > > > + if (!pipe_mask) > > > + return 0; > > > + > > > + return intel_modeset_pipes_in_mask_early(state, > > > "updating > > > CMTG config", pipe_mask); > > > +} > > > + > > > +int intel_cmtg_force_disabled(struct intel_atomic_state *state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + struct intel_cmtg_state *new_cmtg_state; > > > + > > > + if (!HAS_CMTG(display)) > > > + return 0; > > > + > > > + new_cmtg_state = intel_atomic_get_cmtg_state(state); > > > + if (IS_ERR(new_cmtg_state)) > > > + return PTR_ERR(new_cmtg_state); > > > + > > > + new_cmtg_state->cmtg_a_enable = false; > > > + new_cmtg_state->cmtg_b_enable = false; > > > + new_cmtg_state->trans_a_secondary = false; > > > + new_cmtg_state->trans_b_secondary = false; > > > + return 0; > > > +} > > > + > > > +int intel_cmtg_atomic_check(struct intel_atomic_state *state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + struct intel_cmtg_state *old_cmtg_state; > > > + struct intel_cmtg_state *new_cmtg_state; > > > + int ret; > > > + > > > + if (!HAS_CMTG(display)) > > > + return 0; > > > + > > > + old_cmtg_state = intel_atomic_get_old_cmtg_state(state); > > > + new_cmtg_state = intel_atomic_get_new_cmtg_state(state); > > > + if (!intel_cmtg_state_changed(old_cmtg_state, > > > new_cmtg_state)) > > > + return 0; > > > + > > > + ret = intel_cmtg_check_modeset(state, old_cmtg_state, > > > new_cmtg_state); > > > + if (ret) > > > + return ret; > > > + > > > + return > > > intel_atomic_serialize_global_state(&new_cmtg_state- > > > > base); > > > +} > > > + > > > +/* > > > + * Access to CMTG registers require the PHY PLL that provides > > > its > > > clock to be > > > + * running (which is configured via CMTG_CLK_SEL). As such, this > > > function needs > > > + * to be called before intel_commit_modeset_disables() to ensure > > > that the PHY > > > + * PLL is still enabled when doing this. > > > + */ > > > +void intel_cmtg_disable(struct intel_atomic_state *state) > > > +{ > > > + struct intel_display *display = to_intel_display(state); > > > + struct drm_i915_private *i915 = to_i915(display->drm); > > > + struct intel_cmtg_state *old_cmtg_state; > > > + struct intel_cmtg_state *new_cmtg_state; > > > + > > > + if (!HAS_CMTG(display)) > > > + return; > > > + > > > + old_cmtg_state = intel_atomic_get_old_cmtg_state(state); > > > + new_cmtg_state = intel_atomic_get_new_cmtg_state(state); > > > + if (!intel_cmtg_state_changed(old_cmtg_state, > > > new_cmtg_state)) > > > + return; > > > + > > > + drm_info(display->drm, "Disabling CMTG\n"); > > > + > > > + intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(i915, > > > TRANSCODER_A), CMTG_SECONDARY_MODE, 0); > > > + intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(i915, > > > TRANSCODER_B), CMTG_SECONDARY_MODE, 0); > > > + > > > + intel_de_rmw(display, TRANS_CMTG_CTL_A, CMTG_ENABLE, 0); > > > + > > > + if (intel_cmtg_has_cmtg_b(display)) > > > + intel_de_rmw(display, TRANS_CMTG_CTL_B, > > > CMTG_ENABLE, > > > 0); > > > + > > > + if (intel_cmtg_has_clock_sel(display)) { > > > + u32 clk_sel_clr = CMTG_CLK_SEL_A_MASK; > > > + u32 clk_sel_set = CMTG_CLK_SEL_A_DISABLED; > > > + > > > + if (intel_cmtg_has_cmtg_b(display)) { > > > + clk_sel_clr |= CMTG_CLK_SEL_B_MASK; > > > + clk_sel_set |= CMTG_CLK_SEL_B_DISABLED; > > > + } > > > + > > > + intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, > > > clk_sel_set); > > > + } > > > +} > > > diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.h > > > b/drivers/gpu/drm/i915/display/intel_cmtg.h > > > new file mode 100644 > > > index 000000000000..4dfd31906d81 > > > --- /dev/null > > > +++ b/drivers/gpu/drm/i915/display/intel_cmtg.h > > > @@ -0,0 +1,38 @@ > > > +/* SPDX-License-Identifier: MIT */ > > > +/* > > > + * Copyright (C) 2024 Intel Corporation > > > + */ > > > + > > > +#ifndef __INTEL_CMTG_H__ > > > +#define __INTEL_CMTG_H__ > > > + > > > +#include "intel_display_core.h" > > > +#include "intel_global_state.h" > > > + > > > +/* > > > + * We describe here only the minimum state required to allow us > > > to > > > properly > > > + * disable the CMTG if necessary. > > > + */ > > > +struct intel_cmtg_state { > > > + struct intel_global_state base; > > > + > > > + bool cmtg_a_enable; > > > + /* > > > + * Xe3_LPD adds a second CMTG that can be used for dual > > > eDP > > > async mode. > > > + */ > > > + bool cmtg_b_enable; > > > + bool trans_a_secondary; > > > + bool trans_b_secondary; > > > +}; > > > + > > > +#define to_intel_cmtg_state(global_state) \ > > > + container_of_const((global_state), struct > > > intel_cmtg_state, > > > base) > > > + > > > +int intel_cmtg_init(struct intel_display *display); > > > +void intel_cmtg_readout_state(struct intel_display *display, > > > + struct intel_cmtg_state > > > *cmtg_state); > > > +int intel_cmtg_force_disabled(struct intel_atomic_state *state); > > > +int intel_cmtg_atomic_check(struct intel_atomic_state *state); > > > +void intel_cmtg_disable(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 > > > new file mode 100644 > > > index 000000000000..082f96cad284 > > > --- /dev/null > > > +++ b/drivers/gpu/drm/i915/display/intel_cmtg_regs.h > > > @@ -0,0 +1,21 @@ > > > +/* SPDX-License-Identifier: MIT */ > > > +/* > > > + * Copyright (C) 2024 Intel Corporation > > > + */ > > > + > > > +#ifndef __INTEL_CMTG_REGS_H__ > > > +#define __INTEL_CMTG_REGS_H__ > > > + > > > +#include "i915_reg_defs.h" > > > + > > > +#define CMTG_CLK_SEL _MMIO(0x46160) > > > +#define CMTG_CLK_SEL_A_MASK REG_GENMASK(31, 29) > > > +#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_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 CMTG_ENABLE REG_BIT(31) > > > + > > > +#endif /* __INTEL_CMTG_REGS_H__ */ > > > diff --git a/drivers/gpu/drm/i915/display/intel_display.c > > > b/drivers/gpu/drm/i915/display/intel_display.c > > > index 4271da219b41..098985ad7ad4 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_display.c > > > +++ b/drivers/gpu/drm/i915/display/intel_display.c > > > @@ -62,6 +62,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" > > > @@ -6828,6 +6829,10 @@ int intel_atomic_check(struct drm_device > > > *dev, > > > if (ret) > > > goto fail; > > > > > > + ret = intel_cmtg_atomic_check(state); > > > + if (ret) > > > + goto fail; > > > + > > > for_each_new_intel_crtc_in_state(state, crtc, > > > new_crtc_state, i) { > > > if (!intel_crtc_needs_modeset(new_crtc_state)) > > > continue; > > > @@ -7757,6 +7762,8 @@ static void intel_atomic_commit_tail(struct > > > intel_atomic_state *state) > > > > > > intel_modeset_get_crtc_power_domains(new_crt > > > c_state, &put_domains[crtc->pipe]); > > > } > > > > > > + intel_cmtg_disable(state); > > > + > > > intel_commit_modeset_disables(state); > > > > > > intel_dp_tunnel_atomic_alloc_bw(state); > > > @@ -8582,6 +8589,10 @@ int intel_initial_commit(struct drm_device > > > *dev) > > > } > > > } > > > > > > + ret = > > > intel_cmtg_force_disabled(to_intel_atomic_state(state)); > > > + if (ret) > > > + goto out; > > > + > > > ret = drm_atomic_commit(state); > > > > > > out: > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h > > > b/drivers/gpu/drm/i915/display/intel_display_core.h > > > index 554870d2494b..d0b039114e2d 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_display_core.h > > > +++ b/drivers/gpu/drm/i915/display/intel_display_core.h > > > @@ -354,6 +354,10 @@ struct intel_display { > > > unsigned int skl_preferred_vco_freq; > > > } cdclk; > > > > > > + struct { > > > + struct intel_global_obj obj; > > > + } cmtg; > > > + > > > struct { > > > struct drm_property_blob > > > *glk_linear_degamma_lut; > > > } color; > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h > > > b/drivers/gpu/drm/i915/display/intel_display_device.h > > > index 9a333d9e6601..a126247eb6b8 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_display_device.h > > > +++ b/drivers/gpu/drm/i915/display/intel_display_device.h > > > @@ -145,6 +145,7 @@ struct intel_display_platforms { > > > #define HAS_BIGJOINER(__display) (DISPLAY_VER(__display) > > > >= > > > 11 && HAS_DSC(__display)) > > > #define HAS_CDCLK_CRAWL(__display) > > > (DISPLAY_INFO(__display)- > > > > has_cdclk_crawl) > > > #define HAS_CDCLK_SQUASH(__display) > > > (DISPLAY_INFO(__display)- > > > > has_cdclk_squash) > > > +#define HAS_CMTG(__display) (!(__display)- > > > >platform.dg2 > > > && DISPLAY_VER(__display) >= 13) > > > #define HAS_CUR_FBC(__display) > > > (!HAS_GMCH(__display) && > > > IS_DISPLAY_VER(__display, 7, 13)) > > > #define HAS_D12_PLANE_MINIMIZATION(__display) > > > ((__display)- > > > > platform.rocketlake || (__display)->platform.alderlake_s) > > > #define > > > HAS_DBUF_OVERLAP_DETECTION(__display) > > > (DISPLAY_RUNTIME_INFO(__display)->has_dbuf_overlap_detection) > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c > > > b/drivers/gpu/drm/i915/display/intel_display_driver.c > > > index 497b4a1f045f..3e1483814e8d 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_display_driver.c > > > +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c > > > @@ -25,6 +25,7 @@ > > > #include "intel_bios.h" > > > #include "intel_bw.h" > > > #include "intel_cdclk.h" > > > +#include "intel_cmtg.h" > > > #include "intel_color.h" > > > #include "intel_crtc.h" > > > #include "intel_display_debugfs.h" > > > @@ -269,6 +270,10 @@ int intel_display_driver_probe_noirq(struct > > > intel_display *display) > > > if (ret) > > > goto cleanup_vga_client_pw_domain_dmc; > > > > > > + ret = intel_cmtg_init(display); > > > + if (ret) > > > + goto cleanup_vga_client_pw_domain_dmc; > > > + > > > intel_init_quirks(display); > > > > > > intel_fbc_init(display); > > > diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c > > > b/drivers/gpu/drm/i915/display/intel_modeset_setup.c > > > index 9db30db428f7..737a43916ac5 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c > > > +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c > > > @@ -15,6 +15,7 @@ > > > #include "i9xx_wm.h" > > > #include "intel_atomic.h" > > > #include "intel_bw.h" > > > +#include "intel_cmtg.h" > > > #include "intel_color.h" > > > #include "intel_crtc.h" > > > #include "intel_crtc_state_dump.h" > > > @@ -702,6 +703,8 @@ static void > > > intel_modeset_readout_hw_state(struct > > > drm_i915_private *i915) > > > struct intel_display *display = &i915->display; > > > struct intel_cdclk_state *cdclk_state = > > > to_intel_cdclk_state(i915- > > > >display.cdclk.obj.state); > > > + struct intel_cmtg_state *cmtg_state = > > > + to_intel_cmtg_state(display->cmtg.obj.state); > > > struct intel_dbuf_state *dbuf_state = > > > to_intel_dbuf_state(i915- > > > >display.dbuf.obj.state); > > > struct intel_pmdemand_state *pmdemand_state = > > > @@ -906,6 +909,8 @@ static void > > > intel_modeset_readout_hw_state(struct > > > drm_i915_private *i915) > > > } > > > > > > intel_pmdemand_init_pmdemand_params(i915, > > > pmdemand_state); > > > + > > > + intel_cmtg_readout_state(display, cmtg_state); > > > } > > > > > > static void > > > diff --git a/drivers/gpu/drm/i915/i915_reg.h > > > b/drivers/gpu/drm/i915/i915_reg.h > > > index 765e6c0528fb..b34bccfb1ccc 100644 > > > --- a/drivers/gpu/drm/i915/i915_reg.h > > > +++ b/drivers/gpu/drm/i915/i915_reg.h > > > @@ -3565,6 +3565,7 @@ enum skl_power_gate { > > > #define _TRANS_DDI_FUNC_CTL2_DSI1 0x6bc04 > > > #define TRANS_DDI_FUNC_CTL2(dev_priv, > > > tran) _MMIO_TRANS2(dev_priv, tran, _TRANS_DDI_FUNC_CTL2_A) > > > #define PORT_SYNC_MODE_ENABLE REG_BIT(4) > > > +#define CMTG_SECONDARY_MODE REG_BIT(3) > > > #define PORT_SYNC_MODE_MASTER_SELECT_MASK REG_GENMASK(2, > > > 0) > > > #define > > > PORT_SYNC_MODE_MASTER_SELECT(x) > > > REG_FIELD_PREP(PORT_SYNC_MODE_MASTER_SELECT_MASK,(x)) > > > > > > diff --git a/drivers/gpu/drm/xe/Makefile > > > b/drivers/gpu/drm/xe/Makefile > > > index 5c97ad6ed738..cd0e25fce14b 100644 > > > --- a/drivers/gpu/drm/xe/Makefile > > > +++ b/drivers/gpu/drm/xe/Makefile > > > @@ -199,6 +199,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ > > > i915-display/intel_bios.o \ > > > i915-display/intel_bw.o \ > > > i915-display/intel_cdclk.o \ > > > + i915-display/intel_cmtg.o \ > > > i915-display/intel_color.o \ > > > i915-display/intel_combo_phy.o \ > > > i915-display/intel_connector.o \ > >