mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-01 23:46:45 +00:00

A number of files have unnecessary i915_reg.h includes. Drop them. Reviewed-by: Michał Grzelak <michal.grzelak@intel.com> Link: https://lore.kernel.org/r/7c4002322f4d8132fd2eaa1a4d688539cdd043c3.1749469962.git.jani.nikula@intel.com Signed-off-by: Jani Nikula <jani.nikula@intel.com>
189 lines
5.9 KiB
C
189 lines
5.9 KiB
C
// 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);
|
|
}
|