Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  intel_cmtg.c  Sprache: unbekannt

 
// SPDX-License-Identifier: MIT
/*
 * Copyright (C) 2025 Intel Corporation
 */


#include <linux/string_choices.h>
#include <linux/types.h>

#include <drm/drm_device.h>
#include <drm/drm_print.h>

#include "intel_cmtg.h"
#include "intel_cmtg_regs.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_device.h"
#include "intel_display_power.h"
#include "intel_display_regs.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.
 */


/*
 * We describe here only the minimum data required to allow us to properly
 * disable the CMTG if necessary.
 */

struct intel_cmtg_config {
 bool cmtg_a_enable;
 /*
  * Xe2_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;
};

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 void intel_cmtg_dump_config(struct intel_display *display,
       struct intel_cmtg_config *cmtg_config)
{
 drm_dbg_kms(display->drm,
      "CMTG readout: CMTG A: %s, CMTG B: %s, Transcoder A secondary: %s, Transcoder B secondary: %s\n",
      str_enabled_disabled(cmtg_config->cmtg_a_enable),
      intel_cmtg_has_cmtg_b(display) ? str_enabled_disabled(cmtg_config->cmtg_b_enable) : "n/a",
      str_yes_no(cmtg_config->trans_a_secondary),
      str_yes_no(cmtg_config->trans_b_secondary));
}

static bool intel_cmtg_transcoder_is_secondary(struct intel_display *display,
            enum transcoder trans)
{
 enum intel_display_power_domain power_domain;
 intel_wakeref_t wakeref;
 u32 val = 0;

 if (!HAS_TRANSCODER(display, trans))
  return false;

 power_domain = POWER_DOMAIN_TRANSCODER(trans);

 with_intel_display_power_if_enabled(display, power_domain, wakeref)
  val = intel_de_read(display, TRANS_DDI_FUNC_CTL2(display, trans));

 return val & CMTG_SECONDARY_MODE;
}

static void intel_cmtg_get_config(struct intel_display *display,
      struct intel_cmtg_config *cmtg_config)
{
 u32 val;

 val = intel_de_read(display, TRANS_CMTG_CTL_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);
  cmtg_config->cmtg_b_enable = val & CMTG_ENABLE;
 }

 cmtg_config->trans_a_secondary = intel_cmtg_transcoder_is_secondary(display, TRANSCODER_A);
 cmtg_config->trans_b_secondary = intel_cmtg_transcoder_is_secondary(display, TRANSCODER_B);
}

static bool intel_cmtg_disable_requires_modeset(struct intel_display *display,
      struct intel_cmtg_config *cmtg_config)
{
 if (DISPLAY_VER(display) >= 20)
  return false;

 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)
{
 u32 clk_sel_clr = 0;
 u32 clk_sel_set = 0;

 if (cmtg_config->trans_a_secondary)
  intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(display, TRANSCODER_A),
        CMTG_SECONDARY_MODE, 0);

 if (cmtg_config->trans_b_secondary)
  intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(display, TRANSCODER_B),
        CMTG_SECONDARY_MODE, 0);

 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);
  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);
  clk_sel_clr |= CMTG_CLK_SEL_B_MASK;
  clk_sel_set |= CMTG_CLK_SEL_B_DISABLED;
 }

 if (intel_cmtg_has_clock_sel(display) && clk_sel_clr)
  intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, clk_sel_set);
}

/*
 * Read out CMTG configuration and, on platforms that allow disabling it without
 * a modeset, do it.
 *
 * This function must be called before any port PLL is disabled in the general
 * sanitization process, because we need whatever port PLL that is providing the
 * clock for CMTG to be on before accessing CMTG registers.
 */

void intel_cmtg_sanitize(struct intel_display *display)
{
 struct intel_cmtg_config cmtg_config = {};

 if (!HAS_CMTG(display))
  return;

 intel_cmtg_get_config(display, &cmtg_config);
 intel_cmtg_dump_config(display, &cmtg_config);

 /*
  * FIXME: The driver is not prepared to handle cases where a modeset is
  * required for disabling the CMTG: we need a proper way of tracking
  * CMTG state and do the right syncronization with respect to triggering
  * the modeset as part of the disable sequence.
 */

 if (intel_cmtg_disable_requires_modeset(display, &cmtg_config))
  return;

 intel_cmtg_disable(display, &cmtg_config);
}

Messung V0.5 in Prozent
C=97 H=91 G=93

[Dauer der Verarbeitung: 0.11 Sekunden, vorverarbeitet 2026-10-12]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1127926
#Domains=1947682