Merge tag 'drm-intel-next-2023-01-27' of git://anongit.freedesktop.org/drm/drm-intel into drm-next

drm/i915 feature pull #2 v6.3:

Features and functionality:
- Enable HF-EEODB by switching HDMI, DP and LVDS to use struct drm_edid (Jani)
- Start using unversioned DMC firmware paths for new platforms (Gustavo)

Refactoring and cleanups:
- ELD refactor: Stop using hardware buffer, precompute ELD, and wire up ELD in
  the state checker (Ville)
- Use generics for debugfs device parameters (Jani)
- DSB refactoring and fixes (Ville)
- Header refactoring, add new intel_display_limits.h (Jani)
- Split out GMCH code to a new file (Jani)
- Split out vblank code to a new file (Jani)
- i915_drv.h and struct drm_i915_private cleanups (Jani)
- Simplify FBC and DRRS debug attributes (Deepak R Varma)
- Remove some single-use macros (Rodrigo)

Fixes:
- Fix scaler limits for display versions 12 and 13 (Luca)
- Fix plane source size check for zero height (Drew Davenport)
- Implement PSR2 selective fetch workaround (Jouni)
- Expand a PSR workaound to more platforms and pipes (Jouni)
- Expand an HDMI infoframe workaround to all MTL steppings (Jouni)
- Enable PIPEDMC whenever its corresponding pipe is enabled (Imre)

Merges:
- Backmerge drm-next (Jani)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/87tu0c44gv.fsf@intel.com
This commit is contained in:
Dave Airlie 2023-01-30 13:35:56 +10:00
commit 49ed9f39c8
98 changed files with 1825 additions and 1504 deletions

View file

@ -63,6 +63,7 @@ i915-y += i915_driver.o \
# core peripheral code
i915-y += \
soc/intel_dram.o \
soc/intel_gmch.o \
soc/intel_pch.o
# core library code
@ -266,6 +267,7 @@ i915-y += \
display/intel_quirks.o \
display/intel_sprite.o \
display/intel_tc.o \
display/intel_vblank.o \
display/intel_vga.o \
display/i9xx_plane.o \
display/skl_scaler.o \

View file

@ -398,6 +398,8 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
if (intel_dp_is_edp(intel_dp))
intel_edp_fixup_vbt_bpp(encoder, pipe_config->pipe_bpp);
intel_audio_codec_get_config(encoder, pipe_config);
}
static void

View file

@ -155,6 +155,8 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
intel_read_infoframe(encoder, pipe_config,
HDMI_INFOFRAME_TYPE_VENDOR,
&pipe_config->infoframes.hdmi);
intel_audio_codec_get_config(encoder, pipe_config);
}
static void g4x_hdmi_enable_port(struct intel_encoder *encoder,

View file

@ -2054,7 +2054,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
goto err;
}
intel_panel_init(intel_connector);
intel_panel_init(intel_connector, NULL);
intel_backlight_setup(intel_connector, INVALID_PIPE);

View file

@ -36,6 +36,7 @@
#include "gt/intel_rps.h"
#include "i915_config.h"
#include "intel_atomic_plane.h"
#include "intel_cdclk.h"
#include "intel_display_trace.h"

View file

@ -71,6 +71,8 @@ struct intel_audio_funcs {
void (*audio_codec_disable)(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state);
void (*audio_codec_get_config)(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state);
};
/* DP N/M table */
@ -314,6 +316,27 @@ static int g4x_eld_buffer_size(struct drm_i915_private *i915)
return REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp);
}
static void g4x_audio_codec_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
u32 *eld = (u32 *)crtc_state->eld;
int eld_buffer_size, len, i;
u32 tmp;
tmp = intel_de_read(i915, G4X_AUD_CNTL_ST);
if ((tmp & G4X_ELD_VALID) == 0)
return;
intel_de_rmw(i915, G4X_AUD_CNTL_ST, G4X_ELD_ADDRESS_MASK, 0);
eld_buffer_size = g4x_eld_buffer_size(i915);
len = min_t(int, sizeof(crtc_state->eld) / 4, eld_buffer_size);
for (i = 0; i < len; i++)
eld[i] = intel_de_read(i915, G4X_HDMIW_HDMIEDID);
}
static void g4x_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
@ -335,8 +358,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
const u32 *eld = (const u32 *)connector->eld;
const u32 *eld = (const u32 *)crtc_state->eld;
int eld_buffer_size, len, i;
intel_crtc_wait_for_next_vblank(crtc);
@ -345,7 +367,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK, 0);
eld_buffer_size = g4x_eld_buffer_size(i915);
len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
len = min(drm_eld_size(crtc_state->eld) / 4, eld_buffer_size);
for (i = 0; i < len; i++)
intel_de_write(i915, G4X_HDMIW_HDMIEDID, eld[i]);
@ -459,17 +481,6 @@ hsw_audio_config_update(struct intel_encoder *encoder,
hsw_hdmi_audio_config_update(encoder, crtc_state);
}
/* ELD buffer size in dwords */
static int hsw_eld_buffer_size(struct drm_i915_private *i915,
enum transcoder cpu_transcoder)
{
u32 tmp;
tmp = intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder));
return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp);
}
static void hsw_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
@ -618,10 +629,7 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
const u32 *eld = (const u32 *)connector->eld;
int eld_buffer_size, len, i;
mutex_lock(&i915->display.audio.mutex);
@ -639,25 +647,10 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
AUDIO_ELD_VALID(cpu_transcoder), 0);
/* Reset ELD address */
intel_de_rmw(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder),
IBX_ELD_ADDRESS_MASK, 0);
eld_buffer_size = hsw_eld_buffer_size(i915, cpu_transcoder);
len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
for (i = 0; i < len; i++)
intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), eld[i]);
for (; i < eld_buffer_size; i++)
intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), 0);
drm_WARN_ON(&i915->drm,
(intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)) &
IBX_ELD_ADDRESS_MASK) != 0);
/* ELD valid */
intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
0, AUDIO_ELD_VALID(cpu_transcoder));
/*
* The audio componenent is used to convey the ELD
* instead using of the hardware ELD buffer.
*/
/* Enable timestamps */
hsw_audio_config_update(encoder, crtc_state);
@ -665,47 +658,33 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
mutex_unlock(&i915->display.audio.mutex);
}
struct ilk_audio_regs {
struct ibx_audio_regs {
i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
};
static void ilk_audio_regs_init(struct drm_i915_private *i915,
static void ibx_audio_regs_init(struct drm_i915_private *i915,
enum pipe pipe,
struct ilk_audio_regs *regs)
struct ibx_audio_regs *regs)
{
if (HAS_PCH_IBX(i915)) {
regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
regs->aud_config = IBX_AUD_CFG(pipe);
regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
} else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
regs->hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
regs->aud_config = VLV_AUD_CFG(pipe);
regs->aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
regs->aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
} else {
} else if (HAS_PCH_CPT(i915)) {
regs->hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
regs->aud_config = CPT_AUD_CFG(pipe);
regs->aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
regs->aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
} else if (HAS_PCH_IBX(i915)) {
regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
regs->aud_config = IBX_AUD_CFG(pipe);
regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
}
}
/* ELD buffer size in dwords */
static int ilk_eld_buffer_size(struct drm_i915_private *i915,
enum pipe pipe)
{
struct ilk_audio_regs regs;
u32 tmp;
ilk_audio_regs_init(i915, pipe, &regs);
tmp = intel_de_read(i915, regs.aud_cntl_st);
return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp);
}
static void ilk_audio_codec_disable(struct intel_encoder *encoder,
static void ibx_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
@ -713,12 +692,12 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
struct ilk_audio_regs regs;
struct ibx_audio_regs regs;
if (drm_WARN_ON(&i915->drm, port == PORT_A))
return;
ilk_audio_regs_init(i915, pipe, &regs);
ibx_audio_regs_init(i915, pipe, &regs);
mutex_lock(&i915->display.audio.mutex);
@ -741,25 +720,22 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder,
intel_crtc_wait_for_next_vblank(crtc);
}
static void ilk_audio_codec_enable(struct intel_encoder *encoder,
static void ibx_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
const u32 *eld = (const u32 *)connector->eld;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
int eld_buffer_size, len, i;
struct ilk_audio_regs regs;
struct ibx_audio_regs regs;
if (drm_WARN_ON(&i915->drm, port == PORT_A))
return;
intel_crtc_wait_for_next_vblank(crtc);
ilk_audio_regs_init(i915, pipe, &regs);
ibx_audio_regs_init(i915, pipe, &regs);
mutex_lock(&i915->display.audio.mutex);
@ -767,24 +743,10 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder,
intel_de_rmw(i915, regs.aud_cntrl_st2,
IBX_ELD_VALID(port), 0);
/* Reset ELD address */
intel_de_rmw(i915, regs.aud_cntl_st,
IBX_ELD_ADDRESS_MASK, 0);
eld_buffer_size = ilk_eld_buffer_size(i915, pipe);
len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
for (i = 0; i < len; i++)
intel_de_write(i915, regs.hdmiw_hdmiedid, eld[i]);
for (; i < eld_buffer_size; i++)
intel_de_write(i915, regs.hdmiw_hdmiedid, 0);
drm_WARN_ON(&i915->drm,
(intel_de_read(i915, regs.aud_cntl_st) & IBX_ELD_ADDRESS_MASK) != 0);
/* ELD valid */
intel_de_rmw(i915, regs.aud_cntrl_st2,
0, IBX_ELD_VALID(port));
/*
* The audio componenent is used to convey the ELD
* instead using of the hardware ELD buffer.
*/
/* Enable timestamps */
intel_de_rmw(i915, regs.aud_config,
@ -809,6 +771,30 @@ void intel_audio_sdp_split_update(struct intel_encoder *encoder,
crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0);
}
bool intel_audio_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct drm_connector *connector = conn_state->connector;
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
if (!connector->eld[0]) {
drm_dbg_kms(&i915->drm,
"Bogus ELD on [CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
return false;
}
BUILD_BUG_ON(sizeof(crtc_state->eld) != sizeof(connector->eld));
memcpy(crtc_state->eld, connector->eld, sizeof(crtc_state->eld));
crtc_state->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
return true;
}
/**
* intel_audio_codec_enable - Enable the audio codec for HD audio
* @encoder: encoder on which to enable audio
@ -825,27 +811,19 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
struct intel_connector *connector = to_intel_connector(conn_state->connector);
struct intel_audio_state *audio_state;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
if (!crtc_state->has_audio)
return;
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n",
connector->base.id, connector->name,
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on [CRTC:%d:%s], %u bytes ELD\n",
connector->base.base.id, connector->base.name,
encoder->base.base.id, encoder->base.name,
pipe_name(pipe), drm_eld_size(connector->eld));
/* FIXME precompute the ELD in .compute_config() */
if (!connector->eld[0])
drm_dbg_kms(&i915->drm,
"Bogus ELD on [CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
crtc->base.base.id, crtc->base.name,
drm_eld_size(crtc_state->eld));
if (i915->display.funcs.audio)
i915->display.funcs.audio->audio_codec_enable(encoder,
@ -853,10 +831,13 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
conn_state);
mutex_lock(&i915->display.audio.mutex);
encoder->audio_connector = connector;
/* referred in audio callbacks */
i915->display.audio.encoder_map[pipe] = encoder;
audio_state = &i915->display.audio.state[pipe];
audio_state->encoder = encoder;
BUILD_BUG_ON(sizeof(audio_state->eld) != sizeof(crtc_state->eld));
memcpy(audio_state->eld, crtc_state->eld, sizeof(audio_state->eld));
mutex_unlock(&i915->display.audio.mutex);
if (acomp && acomp->base.audio_ops &&
@ -868,7 +849,7 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
(int)port, (int)pipe);
}
intel_lpe_audio_notify(i915, pipe, port, connector->eld,
intel_lpe_audio_notify(i915, pipe, port, crtc_state->eld,
crtc_state->port_clock,
intel_crtc_has_dp_encoder(crtc_state));
}
@ -889,16 +870,18 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_connector *connector = old_conn_state->connector;
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
struct intel_audio_state *audio_state;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
if (!old_crtc_state->has_audio)
return;
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n",
connector->base.id, connector->name,
encoder->base.base.id, encoder->base.name, pipe_name(pipe));
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on [CRTC:%d:%s]\n",
connector->base.base.id, connector->base.name,
encoder->base.base.id, encoder->base.name,
crtc->base.base.id, crtc->base.name);
if (i915->display.funcs.audio)
i915->display.funcs.audio->audio_codec_disable(encoder,
@ -906,8 +889,12 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
old_conn_state);
mutex_lock(&i915->display.audio.mutex);
encoder->audio_connector = NULL;
i915->display.audio.encoder_map[pipe] = NULL;
audio_state = &i915->display.audio.state[pipe];
audio_state->encoder = NULL;
memset(audio_state->eld, 0, sizeof(audio_state->eld));
mutex_unlock(&i915->display.audio.mutex);
if (acomp && acomp->base.audio_ops &&
@ -922,19 +909,52 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
intel_lpe_audio_notify(i915, pipe, port, NULL, 0, false);
}
static void intel_acomp_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct intel_audio_state *audio_state;
enum pipe pipe = crtc->pipe;
mutex_lock(&i915->display.audio.mutex);
audio_state = &i915->display.audio.state[pipe];
if (audio_state->encoder)
memcpy(crtc_state->eld, audio_state->eld, sizeof(audio_state->eld));
mutex_unlock(&i915->display.audio.mutex);
}
void intel_audio_codec_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
if (!crtc_state->has_audio)
return;
if (i915->display.funcs.audio)
i915->display.funcs.audio->audio_codec_get_config(encoder, crtc_state);
}
static const struct intel_audio_funcs g4x_audio_funcs = {
.audio_codec_enable = g4x_audio_codec_enable,
.audio_codec_disable = g4x_audio_codec_disable,
.audio_codec_get_config = g4x_audio_codec_get_config,
};
static const struct intel_audio_funcs ilk_audio_funcs = {
.audio_codec_enable = ilk_audio_codec_enable,
.audio_codec_disable = ilk_audio_codec_disable,
static const struct intel_audio_funcs ibx_audio_funcs = {
.audio_codec_enable = ibx_audio_codec_enable,
.audio_codec_disable = ibx_audio_codec_disable,
.audio_codec_get_config = intel_acomp_get_config,
};
static const struct intel_audio_funcs hsw_audio_funcs = {
.audio_codec_enable = hsw_audio_codec_enable,
.audio_codec_disable = hsw_audio_codec_disable,
.audio_codec_get_config = intel_acomp_get_config,
};
/**
@ -945,12 +965,11 @@ void intel_audio_hooks_init(struct drm_i915_private *i915)
{
if (IS_G4X(i915))
i915->display.funcs.audio = &g4x_audio_funcs;
else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
i915->display.funcs.audio = &ilk_audio_funcs;
else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915) ||
HAS_PCH_CPT(i915) || HAS_PCH_IBX(i915))
i915->display.funcs.audio = &ibx_audio_funcs;
else if (IS_HASWELL(i915) || DISPLAY_VER(i915) >= 8)
i915->display.funcs.audio = &hsw_audio_funcs;
else if (HAS_PCH_SPLIT(i915))
i915->display.funcs.audio = &ilk_audio_funcs;
}
struct aud_ts_cdclk_m_n {
@ -1128,35 +1147,32 @@ static int i915_audio_component_get_cdclk_freq(struct device *kdev)
}
/*
* get the intel_encoder according to the parameter port and pipe
* intel_encoder is saved by the index of pipe
* MST & (pipe >= 0): return the audio.encoder_map[pipe],
* get the intel audio state according to the parameter port and pipe
* MST & (pipe >= 0): return the audio.state[pipe].encoder],
* when port is matched
* MST & (pipe < 0): this is invalid
* Non-MST & (pipe >= 0): only pipe = 0 (the first device entry)
* will get the right intel_encoder with port matched
* Non-MST & (pipe < 0): get the right intel_encoder with port matched
*/
static struct intel_encoder *get_saved_enc(struct drm_i915_private *i915,
int port, int pipe)
static struct intel_audio_state *find_audio_state(struct drm_i915_private *i915,
int port, int pipe)
{
/* MST */
if (pipe >= 0) {
struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
if (drm_WARN_ON(&i915->drm,
pipe >= ARRAY_SIZE(i915->display.audio.encoder_map)))
pipe >= ARRAY_SIZE(i915->display.audio.state)))
return NULL;
encoder = i915->display.audio.encoder_map[pipe];
/*
* when bootup, audio driver may not know it is
* MST or not. So it will poll all the port & pipe
* combinations
*/
audio_state = &i915->display.audio.state[pipe];
encoder = audio_state->encoder;
if (encoder && encoder->port == port &&
encoder->type == INTEL_OUTPUT_DP_MST)
return encoder;
return audio_state;
}
/* Non-MST */
@ -1164,13 +1180,15 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *i915,
return NULL;
for_each_pipe(i915, pipe) {
struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
encoder = i915->display.audio.encoder_map[pipe];
audio_state = &i915->display.audio.state[pipe];
encoder = audio_state->encoder;
if (encoder && encoder->port == port &&
encoder->type != INTEL_OUTPUT_DP_MST)
return encoder;
return audio_state;
}
return NULL;
@ -1181,6 +1199,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
{
struct drm_i915_private *i915 = kdev_to_i915(kdev);
struct i915_audio_component *acomp = i915->display.audio.component;
const struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
struct intel_crtc *crtc;
unsigned long cookie;
@ -1192,20 +1211,22 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
cookie = i915_audio_component_get_power(kdev);
mutex_lock(&i915->display.audio.mutex);
/* 1. get the pipe */
encoder = get_saved_enc(i915, port, pipe);
if (!encoder || !encoder->base.crtc) {
drm_dbg_kms(&i915->drm, "Not valid for port %c\n",
port_name(port));
audio_state = find_audio_state(i915, port, pipe);
if (!audio_state) {
drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port));
err = -ENODEV;
goto unlock;
}
encoder = audio_state->encoder;
/* FIXME stop using the legacy crtc pointer */
crtc = to_intel_crtc(encoder->base.crtc);
/* port must be valid now, otherwise the pipe will be invalid */
acomp->aud_sample_rate[port] = rate;
/* FIXME get rid of the crtc->config stuff */
hsw_audio_config_update(encoder, crtc->config);
unlock:
@ -1219,24 +1240,22 @@ static int i915_audio_component_get_eld(struct device *kdev, int port,
unsigned char *buf, int max_bytes)
{
struct drm_i915_private *i915 = kdev_to_i915(kdev);
struct intel_encoder *intel_encoder;
const u8 *eld;
int ret = -EINVAL;
const struct intel_audio_state *audio_state;
int ret = 0;
mutex_lock(&i915->display.audio.mutex);
intel_encoder = get_saved_enc(i915, port, pipe);
if (!intel_encoder) {
drm_dbg_kms(&i915->drm, "Not valid for port %c\n",
port_name(port));
audio_state = find_audio_state(i915, port, pipe);
if (!audio_state) {
drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port));
mutex_unlock(&i915->display.audio.mutex);
return ret;
return -EINVAL;
}
ret = 0;
*enabled = intel_encoder->audio_connector != NULL;
*enabled = audio_state->encoder != NULL;
if (*enabled) {
eld = intel_encoder->audio_connector->eld;
const u8 *eld = audio_state->eld;
ret = drm_eld_size(eld);
memcpy(buf, eld, min(max_bytes, ret));
}

View file

@ -6,18 +6,25 @@
#ifndef __INTEL_AUDIO_H__
#define __INTEL_AUDIO_H__
#include <linux/types.h>
struct drm_connector_state;
struct drm_i915_private;
struct intel_crtc_state;
struct intel_encoder;
void intel_audio_hooks_init(struct drm_i915_private *dev_priv);
bool intel_audio_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
void intel_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state);
void intel_audio_codec_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state);
void intel_audio_cdclk_change_pre(struct drm_i915_private *dev_priv);
void intel_audio_cdclk_change_post(struct drm_i915_private *dev_priv);
void intel_audio_init(struct drm_i915_private *dev_priv);

View file

@ -25,16 +25,15 @@
*
*/
#include <drm/drm_edid.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_dsc_helper.h>
#include "display/intel_display.h"
#include "display/intel_display_types.h"
#include "display/intel_gmbus.h"
#include <drm/drm_edid.h>
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_gmbus.h"
#define _INTEL_BIOS_PRIVATE
#include "intel_vbt_defs.h"
@ -620,14 +619,14 @@ static void dump_pnp_id(struct drm_i915_private *i915,
static int opregion_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid, bool use_fallback)
const struct drm_edid *drm_edid, bool use_fallback)
{
return intel_opregion_get_panel_type(i915);
}
static int vbt_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid, bool use_fallback)
const struct drm_edid *drm_edid, bool use_fallback)
{
const struct bdb_lvds_options *lvds_options;
@ -652,12 +651,13 @@ static int vbt_get_panel_type(struct drm_i915_private *i915,
static int pnpid_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid, bool use_fallback)
const struct drm_edid *drm_edid, bool use_fallback)
{
const struct bdb_lvds_lfp_data *data;
const struct bdb_lvds_lfp_data_ptrs *ptrs;
const struct lvds_pnp_id *edid_id;
struct lvds_pnp_id edid_id_nodate;
const struct edid *edid = drm_edid_raw(drm_edid); /* FIXME */
int i, best = -1;
if (!edid)
@ -701,7 +701,7 @@ static int pnpid_get_panel_type(struct drm_i915_private *i915,
static int fallback_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid, bool use_fallback)
const struct drm_edid *drm_edid, bool use_fallback)
{
return use_fallback ? 0 : -1;
}
@ -715,13 +715,13 @@ enum panel_type {
static int get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid, bool use_fallback)
const struct drm_edid *drm_edid, bool use_fallback)
{
struct {
const char *name;
int (*get_panel_type)(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid, bool use_fallback);
const struct drm_edid *drm_edid, bool use_fallback);
int panel_type;
} panel_types[] = {
[PANEL_TYPE_OPREGION] = {
@ -745,7 +745,7 @@ static int get_panel_type(struct drm_i915_private *i915,
for (i = 0; i < ARRAY_SIZE(panel_types); i++) {
panel_types[i].panel_type = panel_types[i].get_panel_type(i915, devdata,
edid, use_fallback);
drm_edid, use_fallback);
drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf &&
panel_types[i].panel_type != 0xff);
@ -3187,7 +3187,7 @@ void intel_bios_init(struct drm_i915_private *i915)
static void intel_bios_init_panel(struct drm_i915_private *i915,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid,
const struct drm_edid *drm_edid,
bool use_fallback)
{
/* already have it? */
@ -3197,7 +3197,7 @@ static void intel_bios_init_panel(struct drm_i915_private *i915,
}
panel->vbt.panel_type = get_panel_type(i915, devdata,
edid, use_fallback);
drm_edid, use_fallback);
if (panel->vbt.panel_type < 0) {
drm_WARN_ON(&i915->drm, use_fallback);
return;
@ -3228,9 +3228,9 @@ void intel_bios_init_panel_early(struct drm_i915_private *i915,
void intel_bios_init_panel_late(struct drm_i915_private *i915,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid)
const struct drm_edid *drm_edid)
{
intel_bios_init_panel(i915, panel, devdata, edid, true);
intel_bios_init_panel(i915, panel, devdata, drm_edid, true);
}
/**

View file

@ -32,8 +32,8 @@
#include <linux/types.h>
struct drm_edid;
struct drm_i915_private;
struct edid;
struct intel_bios_encoder_data;
struct intel_crtc_state;
struct intel_encoder;
@ -238,7 +238,7 @@ void intel_bios_init_panel_early(struct drm_i915_private *dev_priv,
void intel_bios_init_panel_late(struct drm_i915_private *dev_priv,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid);
const struct drm_edid *drm_edid);
void intel_bios_fini_panel(struct intel_panel *panel);
void intel_bios_driver_remove(struct drm_i915_private *dev_priv);
bool intel_bios_is_valid_vbt(const void *buf, size_t size);

View file

@ -8,7 +8,7 @@
#include <drm/drm_atomic.h>
#include "intel_display.h"
#include "intel_display_limits.h"
#include "intel_display_power.h"
#include "intel_global_state.h"

View file

@ -8,7 +8,7 @@
#include <linux/types.h>
#include "intel_display.h"
#include "intel_display_limits.h"
#include "intel_global_state.h"
struct drm_i915_private;

View file

@ -847,17 +847,6 @@ static void ilk_lut_write(const struct intel_crtc_state *crtc_state,
intel_de_write_fw(i915, reg, val);
}
static void ilk_lut_write_indexed(const struct intel_crtc_state *crtc_state,
i915_reg_t reg, u32 val)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
if (crtc_state->dsb)
intel_dsb_indexed_reg_write(crtc_state->dsb, reg, val);
else
intel_de_write_fw(i915, reg, val);
}
static void ilk_load_lut_8(const struct intel_crtc_state *crtc_state,
const struct drm_property_blob *blob)
{
@ -962,8 +951,8 @@ static void bdw_load_lut_10(const struct intel_crtc_state *crtc_state,
prec_index);
for (i = 0; i < lut_size; i++)
ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_10(&lut[i]));
ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_10(&lut[i]));
/*
* Reset the index, otherwise it prevents the legacy palette to be
@ -1093,13 +1082,13 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state,
* ToDo: Extend to max 7.0. Enable 32 bit input value
* as compared to just 16 to achieve this.
*/
ilk_lut_write_indexed(crtc_state, PRE_CSC_GAMC_DATA(pipe),
lut[i].green);
ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe),
lut[i].green);
}
/* Clamp values > 1.0. */
while (i++ < glk_degamma_lut_size(i915))
ilk_lut_write_indexed(crtc_state, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe), 0);
}
@ -1165,10 +1154,10 @@ icl_program_gamma_superfine_segment(const struct intel_crtc_state *crtc_state)
for (i = 0; i < 9; i++) {
const struct drm_color_lut *entry = &lut[i];
ilk_lut_write_indexed(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
ilk_lut_12p4_ldw(entry));
ilk_lut_write_indexed(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
ilk_lut_12p4_udw(entry));
ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
ilk_lut_12p4_ldw(entry));
ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
ilk_lut_12p4_udw(entry));
}
ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
@ -1204,10 +1193,10 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
for (i = 1; i < 257; i++) {
entry = &lut[i * 8];
ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_ldw(entry));
ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_udw(entry));
ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_ldw(entry));
ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_udw(entry));
}
/*
@ -1225,10 +1214,10 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
for (i = 0; i < 256; i++) {
entry = &lut[i * 8 * 128];
ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_ldw(entry));
ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_udw(entry));
ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_ldw(entry));
ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
ilk_lut_12p4_udw(entry));
}
ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
@ -1391,7 +1380,7 @@ void intel_color_prepare_commit(struct intel_crtc_state *crtc_state)
/* FIXME DSB has issues loading LUTs, disable it for now */
return;
crtc_state->dsb = intel_dsb_prepare(crtc);
crtc_state->dsb = intel_dsb_prepare(crtc, 1024);
}
void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state)

View file

@ -95,13 +95,10 @@ void intel_connector_destroy(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
kfree(intel_connector->detect_edid);
drm_edid_free(intel_connector->detect_edid);
intel_hdcp_cleanup(intel_connector);
if (!IS_ERR_OR_NULL(intel_connector->edid))
kfree(intel_connector->edid);
intel_panel_fini(intel_connector);
drm_connector_cleanup(connector);

View file

@ -28,6 +28,7 @@
#include "intel_pipe_crc.h"
#include "intel_psr.h"
#include "intel_sprite.h"
#include "intel_vblank.h"
#include "intel_vrr.h"
#include "skl_universal_plane.h"

View file

@ -3,6 +3,8 @@
* Copyright © 2022 Intel Corporation
*/
#include <drm/drm_edid.h>
#include "i915_drv.h"
#include "intel_crtc_state_dump.h"
#include "intel_display_types.h"
@ -56,6 +58,17 @@ intel_dump_dp_vsc_sdp(struct drm_i915_private *i915,
drm_dp_vsc_sdp_log(KERN_DEBUG, i915->drm.dev, vsc);
}
static void
intel_dump_buffer(struct drm_i915_private *i915,
const char *prefix, const u8 *buf, size_t len)
{
if (!drm_debug_enabled(DRM_UT_KMS))
return;
print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_NONE,
16, 0, buf, len, false);
}
#define OUTPUT_TYPE(x) [INTEL_OUTPUT_ ## x] = #x
static const char * const output_type_str[] = {
@ -236,6 +249,10 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config,
intel_hdmi_infoframe_enable(DP_SDP_VSC))
intel_dump_dp_vsc_sdp(i915, &pipe_config->infoframes.vsc);
if (pipe_config->has_audio)
intel_dump_buffer(i915, "ELD: ", pipe_config->eld,
drm_eld_size(pipe_config->eld));
drm_dbg_kms(&i915->drm, "vrr: %s, vmin: %d, vmax: %d, pipeline full: %d, guardband: %d flipline: %d, vmin vblank: %d, vmax vblank: %d\n",
str_yes_no(pipe_config->vrr.enable),
pipe_config->vrr.vmin, pipe_config->vrr.vmax,

View file

@ -3496,6 +3496,8 @@ static void intel_ddi_get_config(struct intel_encoder *encoder,
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
intel_psr_get_config(encoder, pipe_config);
intel_audio_codec_get_config(encoder, pipe_config);
}
void intel_ddi_get_clock(struct intel_encoder *encoder,
@ -4323,7 +4325,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
}
if (intel_phy_is_snps(dev_priv, phy) &&
dev_priv->snps_phy_failed_calibration & BIT(phy)) {
dev_priv->display.snps.phy_failed_calibration & BIT(phy)) {
drm_dbg_kms(&dev_priv->drm,
"SNPS PHY %c failed to calibrate, proceeding anyway\n",
phy_name(phy));

View file

@ -22,6 +22,13 @@ intel_de_read8(struct drm_i915_private *i915, i915_reg_t reg)
return intel_uncore_read8(&i915->uncore, reg);
}
static inline u64
intel_de_read64_2x32(struct drm_i915_private *i915,
i915_reg_t lower_reg, i915_reg_t upper_reg)
{
return intel_uncore_read64_2x32(&i915->uncore, lower_reg, upper_reg);
}
static inline void
intel_de_posting_read(struct drm_i915_private *i915, i915_reg_t reg)
{

View file

@ -24,15 +24,15 @@
* Eric Anholt <eric@anholt.net>
*/
#include <acpi/video.h>
#include <linux/dma-resv.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-resv.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/vga_switcheroo.h>
#include <acpi/video.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic.h>
@ -45,28 +45,6 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
#include "display/intel_audio.h"
#include "display/intel_crt.h"
#include "display/intel_ddi.h"
#include "display/intel_display_debugfs.h"
#include "display/intel_display_power.h"
#include "display/intel_dp.h"
#include "display/intel_dp_mst.h"
#include "display/intel_dpll.h"
#include "display/intel_dpll_mgr.h"
#include "display/intel_drrs.h"
#include "display/intel_dsi.h"
#include "display/intel_dvo.h"
#include "display/intel_fb.h"
#include "display/intel_gmbus.h"
#include "display/intel_hdmi.h"
#include "display/intel_lvds.h"
#include "display/intel_sdvo.h"
#include "display/intel_snps_phy.h"
#include "display/intel_tv.h"
#include "display/intel_vdsc.h"
#include "display/intel_vrr.h"
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_object.h"
@ -76,31 +54,48 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_utils.h"
#include "i9xx_plane.h"
#include "icl_dsi.h"
#include "intel_acpi.h"
#include "intel_atomic.h"
#include "intel_atomic_plane.h"
#include "intel_audio.h"
#include "intel_bw.h"
#include "intel_cdclk.h"
#include "intel_color.h"
#include "intel_crt.h"
#include "intel_crtc.h"
#include "intel_crtc_state_dump.h"
#include "intel_ddi.h"
#include "intel_de.h"
#include "intel_display_debugfs.h"
#include "intel_display_power.h"
#include "intel_display_types.h"
#include "intel_dmc.h"
#include "intel_dp.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_dpll_mgr.h"
#include "intel_dpt.h"
#include "intel_drrs.h"
#include "intel_dsi.h"
#include "intel_dvo.h"
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_fbdev.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
#include "intel_frontbuffer.h"
#include "intel_gmbus.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
#include "intel_hti.h"
#include "intel_modeset_verify.h"
#include "intel_lvds.h"
#include "intel_modeset_setup.h"
#include "intel_modeset_verify.h"
#include "intel_overlay.h"
#include "intel_panel.h"
#include "intel_pch_display.h"
@ -112,10 +107,15 @@
#include "intel_pps.h"
#include "intel_psr.h"
#include "intel_quirks.h"
#include "intel_sdvo.h"
#include "intel_snps_phy.h"
#include "intel_sprite.h"
#include "intel_tc.h"
#include "intel_tv.h"
#include "intel_vblank.h"
#include "intel_vdsc.h"
#include "intel_vga.h"
#include "i9xx_plane.h"
#include "intel_vrr.h"
#include "skl_scaler.h"
#include "skl_universal_plane.h"
#include "skl_watermark.h"
@ -385,41 +385,6 @@ struct intel_crtc *intel_master_crtc(const struct intel_crtc_state *crtc_state)
return to_intel_crtc(crtc_state->uapi.crtc);
}
static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
i915_reg_t reg = PIPEDSL(pipe);
u32 line1, line2;
line1 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
msleep(5);
line2 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
return line1 != line2;
}
static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
/* Wait for the display line to settle/start moving */
if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100))
drm_err(&dev_priv->drm,
"pipe %c scanline %s wait timed out\n",
pipe_name(pipe), str_on_off(state));
}
static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc)
{
wait_for_pipe_scanline_moving(crtc, false);
}
static void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
{
wait_for_pipe_scanline_moving(crtc, true);
}
static void
intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state)
{
@ -1095,22 +1060,6 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
return encoder;
}
static void cpt_verify_modeset(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
i915_reg_t dslreg = PIPEDSL(pipe);
u32 temp;
temp = intel_de_read(dev_priv, dslreg);
udelay(500);
if (wait_for(intel_de_read(dev_priv, dslreg) != temp, 5)) {
if (wait_for(intel_de_read(dev_priv, dslreg) != temp, 5))
drm_err(&dev_priv->drm,
"mode set failed: pipe %c stuck\n",
pipe_name(pipe));
}
}
static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@ -1805,7 +1754,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state,
intel_encoders_enable(state, crtc);
if (HAS_PCH_CPT(dev_priv))
cpt_verify_modeset(dev_priv, pipe);
intel_wait_for_pipe_scanline_moving(crtc);
/*
* Must wait for vblank to avoid spurious PCH FIFO underruns.
@ -1918,6 +1867,8 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (drm_WARN_ON(&dev_priv->drm, crtc->active))
return;
intel_dmc_enable_pipe(dev_priv, crtc->pipe);
if (!new_crtc_state->bigjoiner_pipes) {
intel_encoders_pre_pll_enable(state, crtc);
@ -2053,6 +2004,7 @@ static void hsw_crtc_disable(struct intel_atomic_state *state,
{
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
/*
* FIXME collapse everything to one hook.
@ -2062,6 +2014,8 @@ static void hsw_crtc_disable(struct intel_atomic_state *state,
intel_encoders_disable(state, crtc);
intel_encoders_post_disable(state, crtc);
}
intel_dmc_disable_pipe(i915, crtc->pipe);
}
static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state)
@ -3292,7 +3246,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
if (DISPLAY_VER(dev_priv) >= 4) {
/* No way to read it out on pipes B and C */
if (IS_CHERRYVIEW(dev_priv) && crtc->pipe != PIPE_A)
tmp = dev_priv->chv_dpll_md[crtc->pipe];
tmp = dev_priv->display.state.chv_dpll_md[crtc->pipe];
else
tmp = intel_de_read(dev_priv, DPLL_MD(crtc->pipe));
pipe_config->pixel_multiplier =
@ -5429,6 +5383,12 @@ intel_compare_dp_vsc_sdp(const struct drm_dp_vsc_sdp *a,
return memcmp(a, b, sizeof(*a)) == 0;
}
static bool
intel_compare_buffer(const u8 *a, const u8 *b, size_t len)
{
return memcmp(a, b, len) == 0;
}
static void
pipe_config_infoframe_mismatch(struct drm_i915_private *dev_priv,
bool fastset, const char *name,
@ -5479,6 +5439,30 @@ pipe_config_dp_vsc_sdp_mismatch(struct drm_i915_private *dev_priv,
}
}
static void
pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
bool fastset, const char *name,
const u8 *a, const u8 *b, size_t len)
{
if (fastset) {
if (!drm_debug_enabled(DRM_UT_KMS))
return;
drm_dbg_kms(&dev_priv->drm,
"fastset mismatch in %s buffer\n", name);
print_hex_dump(KERN_DEBUG, "expected: ", DUMP_PREFIX_NONE,
16, 0, a, len, false);
print_hex_dump(KERN_DEBUG, "found: ", DUMP_PREFIX_NONE,
16, 0, b, len, false);
} else {
drm_err(&dev_priv->drm, "mismatch in %s buffer\n", name);
print_hex_dump(KERN_ERR, "expected: ", DUMP_PREFIX_NONE,
16, 0, a, len, false);
print_hex_dump(KERN_ERR, "found: ", DUMP_PREFIX_NONE,
16, 0, b, len, false);
}
}
static void __printf(4, 5)
pipe_config_mismatch(bool fastset, const struct intel_crtc *crtc,
const char *name, const char *format, ...)
@ -5677,6 +5661,18 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
} \
} while (0)
#define PIPE_CONF_CHECK_BUFFER(name, len) do { \
BUILD_BUG_ON(sizeof(current_config->name) != (len)); \
BUILD_BUG_ON(sizeof(pipe_config->name) != (len)); \
if (!intel_compare_buffer(current_config->name, pipe_config->name, (len))) { \
pipe_config_buffer_mismatch(dev_priv, fastset, __stringify(name), \
current_config->name, \
pipe_config->name, \
(len)); \
ret = false; \
} \
} while (0)
#define PIPE_CONF_CHECK_COLOR_LUT(lut, is_pre_csc_lut) do { \
if (current_config->gamma_mode == pipe_config->gamma_mode && \
!intel_color_lut_equal(current_config, \
@ -5748,6 +5744,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(fec_enable);
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES);
PIPE_CONF_CHECK_X(gmch_pfit.control);
/* pfit ratios are autocomputed by the hw on gen4+ */

View file

@ -28,6 +28,7 @@
#include <drm/drm_util.h>
#include "i915_reg_defs.h"
#include "intel_display_limits.h"
enum drm_scaling_filter;
struct dpll;
@ -62,51 +63,9 @@ struct intel_remapped_info;
struct intel_rotation_info;
struct pci_dev;
/*
* Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the
* rest have consecutive values and match the enum values of transcoders
* with a 1:1 transcoder -> pipe mapping.
*/
enum pipe {
INVALID_PIPE = -1,
PIPE_A = 0,
PIPE_B,
PIPE_C,
PIPE_D,
_PIPE_EDP,
I915_MAX_PIPES = _PIPE_EDP
};
#define pipe_name(p) ((p) + 'A')
enum transcoder {
INVALID_TRANSCODER = -1,
/*
* The following transcoders have a 1:1 transcoder -> pipe mapping,
* keep their values fixed: the code assumes that TRANSCODER_A=0, the
* rest have consecutive values and match the enum values of the pipes
* they map to.
*/
TRANSCODER_A = PIPE_A,
TRANSCODER_B = PIPE_B,
TRANSCODER_C = PIPE_C,
TRANSCODER_D = PIPE_D,
/*
* The following transcoders can map to any pipe, their enum value
* doesn't need to stay fixed.
*/
TRANSCODER_EDP,
TRANSCODER_DSI_0,
TRANSCODER_DSI_1,
TRANSCODER_DSI_A = TRANSCODER_DSI_0, /* legacy DSI */
TRANSCODER_DSI_C = TRANSCODER_DSI_1, /* legacy DSI */
I915_MAX_TRANSCODERS
};
static inline const char *transcoder_name(enum transcoder transcoder)
{
switch (transcoder) {
@ -147,29 +106,6 @@ enum i9xx_plane_id {
#define plane_name(p) ((p) + 'A')
#define sprite_name(p, s) ((p) * RUNTIME_INFO(dev_priv)->num_sprites[(p)] + (s) + 'A')
/*
* Per-pipe plane identifier.
* I915_MAX_PLANES in the enum below is the maximum (across all platforms)
* number of planes per CRTC. Not all platforms really have this many planes,
* which means some arrays of size I915_MAX_PLANES may have unused entries
* between the topmost sprite plane and the cursor plane.
*
* This is expected to be passed to various register macros
* (eg. PLANE_CTL(), PS_PLANE_SEL(), etc.) so adjust with care.
*/
enum plane_id {
PLANE_PRIMARY,
PLANE_SPRITE0,
PLANE_SPRITE1,
PLANE_SPRITE2,
PLANE_SPRITE3,
PLANE_SPRITE4,
PLANE_SPRITE5,
PLANE_CURSOR,
I915_MAX_PLANES,
};
#define for_each_plane_id_on_crtc(__crtc, __p) \
for ((__p) = PLANE_PRIMARY; (__p) < I915_MAX_PLANES; (__p)++) \
for_each_if((__crtc)->plane_ids_mask & BIT(__p))
@ -182,34 +118,6 @@ enum plane_id {
for_each_dbuf_slice((__dev_priv), (__slice)) \
for_each_if((__mask) & BIT(__slice))
enum port {
PORT_NONE = -1,
PORT_A = 0,
PORT_B,
PORT_C,
PORT_D,
PORT_E,
PORT_F,
PORT_G,
PORT_H,
PORT_I,
/* tgl+ */
PORT_TC1 = PORT_D,
PORT_TC2,
PORT_TC3,
PORT_TC4,
PORT_TC5,
PORT_TC6,
/* XE_LPD repositions D/E offsets and bitfields */
PORT_D_XELPD = PORT_TC5,
PORT_E_XELPD,
I915_MAX_PORTS
};
#define port_name(p) ((p) + 'A')
/*
@ -312,27 +220,6 @@ enum phy_fia {
FIA3,
};
enum hpd_pin {
HPD_NONE = 0,
HPD_TV = HPD_NONE, /* TV is known to be unreliable */
HPD_CRT,
HPD_SDVO_B,
HPD_SDVO_C,
HPD_PORT_A,
HPD_PORT_B,
HPD_PORT_C,
HPD_PORT_D,
HPD_PORT_E,
HPD_PORT_TC1,
HPD_PORT_TC2,
HPD_PORT_TC3,
HPD_PORT_TC4,
HPD_PORT_TC5,
HPD_PORT_TC6,
HPD_NUM_PINS
};
#define for_each_hpd_pin(__pin) \
for ((__pin) = (HPD_NONE + 1); (__pin) < HPD_NUM_PINS; (__pin)++)

View file

@ -17,7 +17,7 @@
#include <drm/drm_modeset_lock.h>
#include "intel_cdclk.h"
#include "intel_display.h"
#include "intel_display_limits.h"
#include "intel_display_power.h"
#include "intel_dmc.h"
#include "intel_dpll_mgr.h"
@ -87,6 +87,11 @@ struct intel_wm_funcs {
int (*compute_global_watermarks)(struct intel_atomic_state *state);
};
struct intel_audio_state {
struct intel_encoder *encoder;
u8 eld[MAX_ELD_BYTES];
};
struct intel_audio {
/* hda/i915 audio component */
struct i915_audio_component *component;
@ -96,8 +101,8 @@ struct intel_audio {
int power_refcount;
u32 freq_cntrl;
/* Used to save the pipe-to-encoder mapping for audio */
struct intel_encoder *encoder_map[I915_MAX_PIPES];
/* current audio state for the audio component hooks */
struct intel_audio_state state[I915_MAX_PIPES];
/* necessary resource sharing with HDMI LPE audio driver. */
struct {
@ -122,6 +127,11 @@ struct intel_dpll {
int nssc;
int ssc;
} ref_clks;
/*
* Bitmask of PLLs using the PCH SSC, indexed using enum intel_dpll_id.
*/
u8 pch_ssc_use;
};
struct intel_frontbuffer_tracking {
@ -428,6 +438,24 @@ struct intel_display {
u32 block_time_us;
} sagv;
struct {
/*
* DG2: Mask of PHYs that were not calibrated by the firmware
* and should not be used.
*/
u8 phy_failed_calibration;
} snps;
struct {
/*
* Shadows for CHV DPLL_MD regs to keep the state
* checker somewhat working in the presence hardware
* crappiness (can't read out DPLL_MD for pipes B & C).
*/
u32 chv_dpll_md[I915_MAX_PIPES];
u32 bxt_phy_grc;
} state;
struct {
/* ordered wq for modesets */
struct workqueue_struct *modeset;

View file

@ -0,0 +1,124 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022 Intel Corporation
*/
#ifndef __INTEL_DISPLAY_LIMITS_H__
#define __INTEL_DISPLAY_LIMITS_H__
/*
* Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the
* rest have consecutive values and match the enum values of transcoders
* with a 1:1 transcoder -> pipe mapping.
*/
enum pipe {
INVALID_PIPE = -1,
PIPE_A = 0,
PIPE_B,
PIPE_C,
PIPE_D,
_PIPE_EDP,
I915_MAX_PIPES = _PIPE_EDP
};
enum transcoder {
INVALID_TRANSCODER = -1,
/*
* The following transcoders have a 1:1 transcoder -> pipe mapping,
* keep their values fixed: the code assumes that TRANSCODER_A=0, the
* rest have consecutive values and match the enum values of the pipes
* they map to.
*/
TRANSCODER_A = PIPE_A,
TRANSCODER_B = PIPE_B,
TRANSCODER_C = PIPE_C,
TRANSCODER_D = PIPE_D,
/*
* The following transcoders can map to any pipe, their enum value
* doesn't need to stay fixed.
*/
TRANSCODER_EDP,
TRANSCODER_DSI_0,
TRANSCODER_DSI_1,
TRANSCODER_DSI_A = TRANSCODER_DSI_0, /* legacy DSI */
TRANSCODER_DSI_C = TRANSCODER_DSI_1, /* legacy DSI */
I915_MAX_TRANSCODERS
};
/*
* Per-pipe plane identifier.
* I915_MAX_PLANES in the enum below is the maximum (across all platforms)
* number of planes per CRTC. Not all platforms really have this many planes,
* which means some arrays of size I915_MAX_PLANES may have unused entries
* between the topmost sprite plane and the cursor plane.
*
* This is expected to be passed to various register macros
* (eg. PLANE_CTL(), PS_PLANE_SEL(), etc.) so adjust with care.
*/
enum plane_id {
PLANE_PRIMARY,
PLANE_SPRITE0,
PLANE_SPRITE1,
PLANE_SPRITE2,
PLANE_SPRITE3,
PLANE_SPRITE4,
PLANE_SPRITE5,
PLANE_CURSOR,
I915_MAX_PLANES,
};
enum port {
PORT_NONE = -1,
PORT_A = 0,
PORT_B,
PORT_C,
PORT_D,
PORT_E,
PORT_F,
PORT_G,
PORT_H,
PORT_I,
/* tgl+ */
PORT_TC1 = PORT_D,
PORT_TC2,
PORT_TC3,
PORT_TC4,
PORT_TC5,
PORT_TC6,
/* XE_LPD repositions D/E offsets and bitfields */
PORT_D_XELPD = PORT_TC5,
PORT_E_XELPD,
I915_MAX_PORTS
};
enum hpd_pin {
HPD_NONE = 0,
HPD_TV = HPD_NONE, /* TV is known to be unreliable */
HPD_CRT,
HPD_SDVO_B,
HPD_SDVO_C,
HPD_PORT_A,
HPD_PORT_B,
HPD_PORT_C,
HPD_PORT_D,
HPD_PORT_E,
HPD_PORT_TC1,
HPD_PORT_TC2,
HPD_PORT_TC3,
HPD_PORT_TC4,
HPD_PORT_TC5,
HPD_PORT_TC6,
HPD_NUM_PINS
};
#endif /* __INTEL_DISPLAY_LIMITS_H__ */

View file

@ -10,6 +10,7 @@
#include "intel_display_power_map.h"
#include "intel_display_power_well.h"
#include "intel_display_types.h"
#define __LIST_INLINE_ELEMS(__elem_type, ...) \
((__elem_type[]) { __VA_ARGS__ })

View file

@ -17,6 +17,7 @@
#include "i915_irq.h"
#include "intel_crtc.h"
#include "intel_display_types.h"
#include "intel_vblank.h"
#define __dev_name_i915(i915) dev_name((i915)->drm.dev)
#define __dev_name_kms(obj) dev_name((obj)->base.dev->dev)

View file

@ -50,6 +50,7 @@
#include "i915_vma_types.h"
#include "intel_bios.h"
#include "intel_display.h"
#include "intel_display_limits.h"
#include "intel_display_power.h"
#include "intel_dpll_mgr.h"
#include "intel_pm_types.h"
@ -262,8 +263,6 @@ struct intel_encoder {
enum hpd_pin hpd_pin;
enum intel_display_power_domain power_domain;
/* for communication with audio component; protected by av_mutex */
const struct drm_connector *audio_connector;
/* VBT information for this encoder (may be NULL for older platforms) */
const struct intel_bios_encoder_data *devdata;
@ -351,6 +350,9 @@ struct intel_vbt_panel_data {
};
struct intel_panel {
/* Fixed EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
const struct drm_edid *fixed_edid;
struct list_head fixed_modes;
/* backlight */
@ -591,9 +593,8 @@ struct intel_connector {
/* Panel info for eDP and LVDS */
struct intel_panel panel;
/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
struct edid *edid;
struct edid *detect_edid;
/* Cached EDID for detect. */
const struct drm_edid *detect_edid;
/* Number of times hotplug detection was tried after an HPD interrupt */
int hotplug_retries;
@ -1261,6 +1262,8 @@ struct intel_crtc_state {
struct drm_dp_vsc_sdp vsc;
} infoframes;
u8 eld[MAX_ELD_BYTES];
/* HDMI scrambling status */
bool hdmi_scrambling;

View file

@ -42,51 +42,61 @@
#define DMC_VERSION_MAJOR(version) ((version) >> 16)
#define DMC_VERSION_MINOR(version) ((version) & 0xffff)
#define DMC_PATH(platform, major, minor) \
"i915/" \
__stringify(platform) "_dmc_ver" \
__stringify(major) "_" \
#define DMC_PATH(platform) \
"i915/" __stringify(platform) "_dmc.bin"
/*
* New DMC additions should not use this. This is used solely to remain
* compatible with systems that have not yet updated DMC blobs to use
* unversioned file names.
*/
#define DMC_LEGACY_PATH(platform, major, minor) \
"i915/" \
__stringify(platform) "_dmc_ver" \
__stringify(major) "_" \
__stringify(minor) ".bin"
#define DISPLAY_VER13_DMC_MAX_FW_SIZE 0x20000
#define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE
#define DG2_DMC_PATH DMC_PATH(dg2, 2, 08)
#define DG2_DMC_PATH DMC_LEGACY_PATH(dg2, 2, 08)
MODULE_FIRMWARE(DG2_DMC_PATH);
#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 16)
#define ADLP_DMC_PATH DMC_PATH(adlp)
#define ADLP_DMC_FALLBACK_PATH DMC_LEGACY_PATH(adlp, 2, 16)
MODULE_FIRMWARE(ADLP_DMC_PATH);
MODULE_FIRMWARE(ADLP_DMC_FALLBACK_PATH);
#define ADLS_DMC_PATH DMC_PATH(adls, 2, 01)
#define ADLS_DMC_PATH DMC_LEGACY_PATH(adls, 2, 01)
MODULE_FIRMWARE(ADLS_DMC_PATH);
#define DG1_DMC_PATH DMC_PATH(dg1, 2, 02)
#define DG1_DMC_PATH DMC_LEGACY_PATH(dg1, 2, 02)
MODULE_FIRMWARE(DG1_DMC_PATH);
#define RKL_DMC_PATH DMC_PATH(rkl, 2, 03)
#define RKL_DMC_PATH DMC_LEGACY_PATH(rkl, 2, 03)
MODULE_FIRMWARE(RKL_DMC_PATH);
#define TGL_DMC_PATH DMC_PATH(tgl, 2, 12)
#define TGL_DMC_PATH DMC_LEGACY_PATH(tgl, 2, 12)
MODULE_FIRMWARE(TGL_DMC_PATH);
#define ICL_DMC_PATH DMC_PATH(icl, 1, 09)
#define ICL_DMC_PATH DMC_LEGACY_PATH(icl, 1, 09)
#define ICL_DMC_MAX_FW_SIZE 0x6000
MODULE_FIRMWARE(ICL_DMC_PATH);
#define GLK_DMC_PATH DMC_PATH(glk, 1, 04)
#define GLK_DMC_PATH DMC_LEGACY_PATH(glk, 1, 04)
#define GLK_DMC_MAX_FW_SIZE 0x4000
MODULE_FIRMWARE(GLK_DMC_PATH);
#define KBL_DMC_PATH DMC_PATH(kbl, 1, 04)
#define KBL_DMC_PATH DMC_LEGACY_PATH(kbl, 1, 04)
#define KBL_DMC_MAX_FW_SIZE BXT_DMC_MAX_FW_SIZE
MODULE_FIRMWARE(KBL_DMC_PATH);
#define SKL_DMC_PATH DMC_PATH(skl, 1, 27)
#define SKL_DMC_PATH DMC_LEGACY_PATH(skl, 1, 27)
#define SKL_DMC_MAX_FW_SIZE BXT_DMC_MAX_FW_SIZE
MODULE_FIRMWARE(SKL_DMC_PATH);
#define BXT_DMC_PATH DMC_PATH(bxt, 1, 07)
#define BXT_DMC_PATH DMC_LEGACY_PATH(bxt, 1, 07)
#define BXT_DMC_MAX_FW_SIZE 0x3000
MODULE_FIRMWARE(BXT_DMC_PATH);
@ -97,6 +107,8 @@ MODULE_FIRMWARE(BXT_DMC_PATH);
#define DMC_V3_MAX_MMIO_COUNT 20
#define DMC_V1_MMIO_START_RANGE 0x80000
#define PIPE_TO_DMC_ID(pipe) (DMC_FW_PIPEA + ((pipe) - PIPE_A))
struct intel_css_header {
/* 0x09 for DMC */
u32 module_type;
@ -396,6 +408,28 @@ static void pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
PIPEDMC_GATING_DIS, 0);
}
void intel_dmc_enable_pipe(struct drm_i915_private *i915, enum pipe pipe)
{
if (!has_dmc_id_fw(i915, PIPE_TO_DMC_ID(pipe)))
return;
if (DISPLAY_VER(i915) >= 14)
intel_de_rmw(i915, MTL_PIPEDMC_CONTROL, 0, PIPEDMC_ENABLE_MTL(pipe));
else
intel_de_rmw(i915, PIPEDMC_CONTROL(pipe), 0, PIPEDMC_ENABLE);
}
void intel_dmc_disable_pipe(struct drm_i915_private *i915, enum pipe pipe)
{
if (!has_dmc_id_fw(i915, PIPE_TO_DMC_ID(pipe)))
return;
if (DISPLAY_VER(i915) >= 14)
intel_de_rmw(i915, MTL_PIPEDMC_CONTROL, PIPEDMC_ENABLE_MTL(pipe), 0);
else
intel_de_rmw(i915, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0);
}
/**
* intel_dmc_load_program() - write the firmware from memory to register.
* @dev_priv: i915 drm device.
@ -821,16 +855,40 @@ static void intel_dmc_runtime_pm_put(struct drm_i915_private *dev_priv)
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
}
static const char *dmc_fallback_path(struct drm_i915_private *i915)
{
if (IS_ALDERLAKE_P(i915))
return ADLP_DMC_FALLBACK_PATH;
return NULL;
}
static void dmc_load_work_fn(struct work_struct *work)
{
struct drm_i915_private *dev_priv;
struct intel_dmc *dmc;
const struct firmware *fw = NULL;
const char *fallback_path;
int err;
dev_priv = container_of(work, typeof(*dev_priv), display.dmc.work);
dmc = &dev_priv->display.dmc;
request_firmware(&fw, dev_priv->display.dmc.fw_path, dev_priv->drm.dev);
err = request_firmware(&fw, dev_priv->display.dmc.fw_path, dev_priv->drm.dev);
if (err == -ENOENT && !dev_priv->params.dmc_firmware_path) {
fallback_path = dmc_fallback_path(dev_priv);
if (fallback_path) {
drm_dbg_kms(&dev_priv->drm,
"%s not found, falling back to %s\n",
dmc->fw_path,
fallback_path);
err = request_firmware(&fw, fallback_path, dev_priv->drm.dev);
if (err == 0)
dev_priv->display.dmc.fw_path = fallback_path;
}
}
parse_dmc_fw(dev_priv, fw);
if (intel_dmc_has_payload(dev_priv)) {

View file

@ -13,6 +13,8 @@
struct drm_i915_error_state_buf;
struct drm_i915_private;
enum pipe;
enum {
DMC_FW_MAIN = 0,
DMC_FW_PIPEA,
@ -47,6 +49,8 @@ struct intel_dmc {
void intel_dmc_ucode_init(struct drm_i915_private *i915);
void intel_dmc_load_program(struct drm_i915_private *i915);
void intel_dmc_disable_program(struct drm_i915_private *i915);
void intel_dmc_enable_pipe(struct drm_i915_private *i915, enum pipe pipe);
void intel_dmc_disable_pipe(struct drm_i915_private *i915, enum pipe pipe);
void intel_dmc_ucode_fini(struct drm_i915_private *i915);
void intel_dmc_ucode_suspend(struct drm_i915_private *i915);
void intel_dmc_ucode_resume(struct drm_i915_private *i915);

View file

@ -11,6 +11,16 @@
#define DMC_PROGRAM(addr, i) _MMIO((addr) + (i) * 4)
#define DMC_SSP_BASE_ADDR_GEN9 0x00002FC0
#define _PIPEDMC_CONTROL_A 0x45250
#define _PIPEDMC_CONTROL_B 0x45254
#define PIPEDMC_CONTROL(pipe) _MMIO_PIPE(pipe, \
_PIPEDMC_CONTROL_A, \
_PIPEDMC_CONTROL_B)
#define PIPEDMC_ENABLE REG_BIT(0)
#define MTL_PIPEDMC_CONTROL _MMIO(0x45250)
#define PIPEDMC_ENABLE_MTL(pipe) REG_BIT(((pipe) - PIPE_A) * 4)
#define _ADLP_PIPEDMC_REG_MMIO_BASE_A 0x5f000
#define _TGL_PIPEDMC_REG_MMIO_BASE_A 0x92000

View file

@ -2080,7 +2080,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A)
pipe_config->has_pch_encoder = true;
pipe_config->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state);
pipe_config->has_audio =
intel_dp_has_audio(encoder, pipe_config, conn_state) &&
intel_audio_compute_config(encoder, pipe_config, conn_state);
fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode);
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
@ -3648,12 +3650,11 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
intel_dp->aux.i2c_defer_count);
intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_FAILSAFE;
} else {
struct edid *block = intel_connector->detect_edid;
/* FIXME: Get rid of drm_edid_raw() */
const struct edid *block = drm_edid_raw(intel_connector->detect_edid);
/* We have to write the checksum
* of the last block read
*/
block += intel_connector->detect_edid->extensions;
/* We have to write the checksum of the last block read */
block += block->extensions;
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
block->checksum) <= 0)
@ -4475,29 +4476,34 @@ bool intel_digital_port_connected(struct intel_encoder *encoder)
return is_connected;
}
static struct edid *
static const struct drm_edid *
intel_dp_get_edid(struct intel_dp *intel_dp)
{
struct intel_connector *intel_connector = intel_dp->attached_connector;
struct intel_connector *connector = intel_dp->attached_connector;
const struct drm_edid *fixed_edid = connector->panel.fixed_edid;
/* use cached edid if we have one */
if (intel_connector->edid) {
/* Use panel fixed edid if we have one */
if (fixed_edid) {
/* invalid edid */
if (IS_ERR(intel_connector->edid))
if (IS_ERR(fixed_edid))
return NULL;
return drm_edid_duplicate(intel_connector->edid);
} else
return drm_get_edid(&intel_connector->base,
&intel_dp->aux.ddc);
return drm_edid_dup(fixed_edid);
}
return drm_edid_read_ddc(&connector->base, &intel_dp->aux.ddc);
}
static void
intel_dp_update_dfp(struct intel_dp *intel_dp,
const struct edid *edid)
const struct drm_edid *drm_edid)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
struct intel_connector *connector = intel_dp->attached_connector;
const struct edid *edid;
/* FIXME: Get rid of drm_edid_raw() */
edid = drm_edid_raw(drm_edid);
intel_dp->dfp.max_bpc =
drm_dp_downstream_max_bpc(intel_dp->dpcd,
@ -4597,21 +4603,27 @@ intel_dp_set_edid(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
struct intel_connector *connector = intel_dp->attached_connector;
struct edid *edid;
const struct drm_edid *drm_edid;
const struct edid *edid;
bool vrr_capable;
intel_dp_unset_edid(intel_dp);
edid = intel_dp_get_edid(intel_dp);
connector->detect_edid = edid;
drm_edid = intel_dp_get_edid(intel_dp);
connector->detect_edid = drm_edid;
/* Below we depend on display info having been updated */
drm_edid_connector_update(&connector->base, drm_edid);
vrr_capable = intel_vrr_is_capable(connector);
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] VRR capable: %s\n",
connector->base.base.id, connector->base.name, str_yes_no(vrr_capable));
drm_connector_set_vrr_capable_property(&connector->base, vrr_capable);
intel_dp_update_dfp(intel_dp, edid);
intel_dp_update_dfp(intel_dp, drm_edid);
intel_dp_update_420(intel_dp);
/* FIXME: Get rid of drm_edid_raw() */
edid = drm_edid_raw(drm_edid);
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
intel_dp->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
intel_dp->has_audio = drm_detect_monitor_audio(edid);
@ -4626,7 +4638,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
struct intel_connector *connector = intel_dp->attached_connector;
drm_dp_cec_unset_edid(&intel_dp->aux);
kfree(connector->detect_edid);
drm_edid_free(connector->detect_edid);
connector->detect_edid = NULL;
intel_dp->has_hdmi_sink = false;
@ -4790,12 +4802,10 @@ intel_dp_force(struct drm_connector *connector)
static int intel_dp_get_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
struct edid *edid;
int num_modes = 0;
int num_modes;
edid = intel_connector->detect_edid;
if (edid)
num_modes = intel_connector_update_modes(connector, edid);
/* drm_edid_connector_update() done in ->detect() or ->force() */
num_modes = drm_edid_connector_add_modes(connector);
/* Also add fixed mode, which may or may not be present in EDID */
if (intel_dp_is_edp(intel_attached_dp(intel_connector)))
@ -4804,7 +4814,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
if (num_modes)
return num_modes;
if (!edid) {
if (!intel_connector->detect_edid) {
struct intel_dp *intel_dp = intel_attached_dp(intel_connector);
struct drm_display_mode *mode;
@ -5240,7 +5250,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct drm_display_mode *fixed_mode;
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
bool has_dpcd;
struct edid *edid;
const struct drm_edid *drm_edid;
if (!intel_dp_is_edp(intel_dp))
return true;
@ -5287,29 +5297,28 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
}
mutex_lock(&dev_priv->drm.mode_config.mutex);
edid = drm_get_edid(connector, &intel_dp->aux.ddc);
if (!edid) {
drm_edid = drm_edid_read_ddc(connector, &intel_dp->aux.ddc);
if (!drm_edid) {
/* Fallback to EDID from ACPI OpRegion, if any */
edid = intel_opregion_get_edid(intel_connector);
if (edid)
drm_edid = intel_opregion_get_edid(intel_connector);
if (drm_edid)
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] Using OpRegion EDID\n",
connector->base.id, connector->name);
}
if (edid) {
if (drm_add_edid_modes(connector, edid)) {
drm_connector_update_edid_property(connector, edid);
} else {
kfree(edid);
edid = ERR_PTR(-EINVAL);
if (drm_edid) {
if (drm_edid_connector_update(connector, drm_edid) ||
!drm_edid_connector_add_modes(connector)) {
drm_edid_connector_update(connector, NULL);
drm_edid_free(drm_edid);
drm_edid = ERR_PTR(-EINVAL);
}
} else {
edid = ERR_PTR(-ENOENT);
drm_edid = ERR_PTR(-ENOENT);
}
intel_connector->edid = edid;
intel_bios_init_panel_late(dev_priv, &intel_connector->panel,
encoder->devdata, IS_ERR(edid) ? NULL : edid);
intel_bios_init_panel_late(dev_priv, &intel_connector->panel, encoder->devdata,
IS_ERR(drm_edid) ? NULL : drm_edid);
intel_panel_add_edid_fixed_modes(intel_connector, true);
@ -5333,7 +5342,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
goto out_vdd_off;
}
intel_panel_init(intel_connector);
intel_panel_init(intel_connector, drm_edid);
intel_edp_backlight_setup(intel_dp, intel_connector);

View file

@ -376,7 +376,7 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
/* Still read out the GRC value for state verification */
if (phy_info->rcomp_phy != -1)
dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy);
dev_priv->display.state.bxt_phy_grc = bxt_get_grc(dev_priv, phy);
if (bxt_ddi_phy_verify_state(dev_priv, phy)) {
drm_dbg(&dev_priv->drm, "DDI PHY %d already enabled, "
@ -442,8 +442,9 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
* the corresponding calibrated value from PHY1, and disable
* the automatic calibration on PHY0.
*/
val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv,
phy_info->rcomp_phy);
val = bxt_get_grc(dev_priv, phy_info->rcomp_phy);
dev_priv->display.state.bxt_phy_grc = val;
grc_code = val << GRC_CODE_FAST_SHIFT |
val << GRC_CODE_SLOW_SHIFT |
val;
@ -568,7 +569,7 @@ bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
"BXT_PORT_CL2CM_DW6(%d)", phy);
if (phy_info->rcomp_phy != -1) {
u32 grc_code = dev_priv->bxt_phy_grc;
u32 grc_code = dev_priv->display.state.bxt_phy_grc;
grc_code = grc_code << GRC_CODE_FAST_SHIFT |
grc_code << GRC_CODE_SLOW_SHIFT |

View file

@ -1910,7 +1910,7 @@ void chv_enable_pll(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, DPLL_MD(PIPE_B),
crtc_state->dpll_hw_state.dpll_md);
intel_de_write(dev_priv, CBR4_VLV, 0);
dev_priv->chv_dpll_md[pipe] = crtc_state->dpll_hw_state.dpll_md;
dev_priv->display.state.chv_dpll_md[pipe] = crtc_state->dpll_hw_state.dpll_md;
/*
* DPLLB VGA mode also seems to cause problems.

View file

@ -618,7 +618,7 @@ static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
* Try to set up the PCH reference clock once all DPLLs
* that depend on it have been shut down.
*/
if (dev_priv->pch_ssc_use & BIT(id))
if (dev_priv->display.dpll.pch_ssc_use & BIT(id))
intel_init_pch_refclk(dev_priv);
}
@ -636,7 +636,7 @@ static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
* Try to set up the PCH reference clock once all DPLLs
* that depend on it have been shut down.
*/
if (dev_priv->pch_ssc_use & BIT(id))
if (dev_priv->display.dpll.pch_ssc_use & BIT(id))
intel_init_pch_refclk(dev_priv);
}

View file

@ -374,16 +374,16 @@ static int intel_drrs_debugfs_ctl_set(void *data, u64 val)
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(intel_drrs_debugfs_ctl_fops,
NULL, intel_drrs_debugfs_ctl_set, "%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(intel_drrs_debugfs_ctl_fops,
NULL, intel_drrs_debugfs_ctl_set, "%llu\n");
void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc)
{
debugfs_create_file("i915_drrs_status", 0444, crtc->base.debugfs_entry,
crtc, &intel_drrs_debugfs_status_fops);
debugfs_create_file("i915_drrs_ctl", 0644, crtc->base.debugfs_entry,
crtc, &intel_drrs_debugfs_ctl_fops);
debugfs_create_file_unsafe("i915_drrs_ctl", 0644, crtc->base.debugfs_entry,
crtc, &intel_drrs_debugfs_ctl_fops);
}
static int intel_drrs_debugfs_type_show(struct seq_file *m, void *unused)

View file

@ -30,21 +30,24 @@ struct intel_dsb {
struct intel_crtc *crtc;
/*
* free_pos will point the first free entry position
* and help in calculating tail of command buffer.
* maximum number of dwords the buffer will hold.
*/
int free_pos;
unsigned int size;
/*
* ins_start_offset will help to store start address of the dsb
* free_pos will point the first free dword and
* help in calculating tail of command buffer.
*/
unsigned int free_pos;
/*
* ins_start_offset will help to store start dword of the dsb
* instuction and help in identifying the batch of auto-increment
* register.
*/
u32 ins_start_offset;
unsigned int ins_start_offset;
};
#define DSB_BUF_SIZE (2 * PAGE_SIZE)
/**
* DOC: DSB
*
@ -64,80 +67,86 @@ struct intel_dsb {
/* DSB opcodes. */
#define DSB_OPCODE_SHIFT 24
#define DSB_OPCODE_NOOP 0x0
#define DSB_OPCODE_MMIO_WRITE 0x1
#define DSB_OPCODE_WAIT_USEC 0x2
#define DSB_OPCODE_WAIT_LINES 0x3
#define DSB_OPCODE_WAIT_VBLANKS 0x4
#define DSB_OPCODE_WAIT_DSL_IN 0x5
#define DSB_OPCODE_WAIT_DSL_OUT 0x6
#define DSB_OPCODE_INTERRUPT 0x7
#define DSB_OPCODE_INDEXED_WRITE 0x9
#define DSB_OPCODE_POLL 0xA
#define DSB_BYTE_EN 0xF
#define DSB_BYTE_EN_SHIFT 20
#define DSB_REG_VALUE_MASK 0xfffff
static bool assert_dsb_has_room(struct intel_dsb *dsb)
{
struct intel_crtc *crtc = dsb->crtc;
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
/* each instruction is 2 dwords */
return !drm_WARN(&i915->drm, dsb->free_pos > dsb->size - 2,
"DSB buffer overflow\n");
}
static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe,
enum dsb_id id)
{
return DSB_STATUS & intel_de_read(i915, DSB_CTRL(pipe, id));
return intel_de_read(i915, DSB_CTRL(pipe, id)) & DSB_STATUS_BUSY;
}
static bool intel_dsb_enable_engine(struct drm_i915_private *i915,
enum pipe pipe, enum dsb_id id)
static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw)
{
u32 dsb_ctrl;
u32 *buf = dsb->cmd_buf;
dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
if (DSB_STATUS & dsb_ctrl) {
drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
return false;
}
if (!assert_dsb_has_room(dsb))
return;
dsb_ctrl |= DSB_ENABLE;
intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
/* Every instruction should be 8 byte aligned. */
dsb->free_pos = ALIGN(dsb->free_pos, 2);
intel_de_posting_read(i915, DSB_CTRL(pipe, id));
return true;
dsb->ins_start_offset = dsb->free_pos;
buf[dsb->free_pos++] = ldw;
buf[dsb->free_pos++] = udw;
}
static bool intel_dsb_disable_engine(struct drm_i915_private *i915,
enum pipe pipe, enum dsb_id id)
static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb,
u32 opcode, i915_reg_t reg)
{
u32 dsb_ctrl;
const u32 *buf = dsb->cmd_buf;
u32 prev_opcode, prev_reg;
dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
if (DSB_STATUS & dsb_ctrl) {
drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
return false;
}
prev_opcode = buf[dsb->ins_start_offset + 1] >> DSB_OPCODE_SHIFT;
prev_reg = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
dsb_ctrl &= ~DSB_ENABLE;
intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
return prev_opcode == opcode && prev_reg == i915_mmio_reg_offset(reg);
}
intel_de_posting_read(i915, DSB_CTRL(pipe, id));
return true;
static bool intel_dsb_prev_ins_is_mmio_write(struct intel_dsb *dsb, i915_reg_t reg)
{
return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_MMIO_WRITE, reg);
}
static bool intel_dsb_prev_ins_is_indexed_write(struct intel_dsb *dsb, i915_reg_t reg)
{
return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_INDEXED_WRITE, reg);
}
/**
* intel_dsb_indexed_reg_write() -Write to the DSB context for auto
* increment register.
* intel_dsb_reg_write() - Emit register wriite to the DSB context
* @dsb: DSB context
* @reg: register address.
* @val: value.
*
* This function is used for writing register-value pair in command
* buffer of DSB for auto-increment register. During command buffer overflow,
* a warning is thrown and rest all erroneous condition register programming
* is done through mmio write.
* buffer of DSB.
*/
void intel_dsb_indexed_reg_write(struct intel_dsb *dsb,
i915_reg_t reg, u32 val)
void intel_dsb_reg_write(struct intel_dsb *dsb,
i915_reg_t reg, u32 val)
{
struct intel_crtc *crtc = dsb->crtc;
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 *buf = dsb->cmd_buf;
u32 reg_val;
if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
return;
}
/*
* For example the buffer will look like below for 3 dwords for auto
* increment register:
@ -154,65 +163,55 @@ void intel_dsb_indexed_reg_write(struct intel_dsb *dsb,
* we are writing odd no of dwords, Zeros will be added in the end for
* padding.
*/
reg_val = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
if (reg_val != i915_mmio_reg_offset(reg)) {
/* Every instruction should be 8 byte aligned. */
dsb->free_pos = ALIGN(dsb->free_pos, 2);
dsb->ins_start_offset = dsb->free_pos;
/* Update the size. */
buf[dsb->free_pos++] = 1;
/* Update the opcode and reg. */
buf[dsb->free_pos++] = (DSB_OPCODE_INDEXED_WRITE <<
DSB_OPCODE_SHIFT) |
i915_mmio_reg_offset(reg);
/* Update the value. */
buf[dsb->free_pos++] = val;
if (!intel_dsb_prev_ins_is_mmio_write(dsb, reg) &&
!intel_dsb_prev_ins_is_indexed_write(dsb, reg)) {
intel_dsb_emit(dsb, val,
(DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT) |
(DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
i915_mmio_reg_offset(reg));
} else {
/* Update the new value. */
u32 *buf = dsb->cmd_buf;
if (!assert_dsb_has_room(dsb))
return;
/* convert to indexed write? */
if (intel_dsb_prev_ins_is_mmio_write(dsb, reg)) {
u32 prev_val = buf[dsb->ins_start_offset + 0];
buf[dsb->ins_start_offset + 0] = 1; /* count */
buf[dsb->ins_start_offset + 1] =
(DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT) |
i915_mmio_reg_offset(reg);
buf[dsb->ins_start_offset + 2] = prev_val;
dsb->free_pos++;
}
buf[dsb->free_pos++] = val;
/* Update the size. */
/* Update the count */
buf[dsb->ins_start_offset]++;
}
/* if number of data words is odd, then the last dword should be 0.*/
if (dsb->free_pos & 0x1)
buf[dsb->free_pos] = 0;
/* if number of data words is odd, then the last dword should be 0.*/
if (dsb->free_pos & 0x1)
buf[dsb->free_pos] = 0;
}
}
/**
* intel_dsb_reg_write() -Write to the DSB context for normal
* register.
* @crtc_state: intel_crtc_state structure
* @reg: register address.
* @val: value.
*
* This function is used for writing register-value pair in command
* buffer of DSB. During command buffer overflow, a warning is thrown
* and rest all erroneous condition register programming is done
* through mmio write.
*/
void intel_dsb_reg_write(struct intel_dsb *dsb,
i915_reg_t reg, u32 val)
static u32 intel_dsb_align_tail(struct intel_dsb *dsb)
{
struct intel_crtc *crtc = dsb->crtc;
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 *buf = dsb->cmd_buf;
u32 aligned_tail, tail;
if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
return;
}
tail = dsb->free_pos * 4;
aligned_tail = ALIGN(tail, CACHELINE_BYTES);
dsb->ins_start_offset = dsb->free_pos;
buf[dsb->free_pos++] = val;
buf[dsb->free_pos++] = (DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT) |
(DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
i915_mmio_reg_offset(reg);
if (aligned_tail > tail)
memset(&dsb->cmd_buf[dsb->free_pos], 0,
aligned_tail - tail);
dsb->free_pos = aligned_tail / 4;
return aligned_tail;
}
/**
@ -228,50 +227,41 @@ void intel_dsb_commit(struct intel_dsb *dsb)
enum pipe pipe = crtc->pipe;
u32 tail;
if (!(dsb && dsb->free_pos))
tail = intel_dsb_align_tail(dsb);
if (tail == 0)
return;
if (!intel_dsb_enable_engine(dev_priv, pipe, dsb->id))
goto reset;
if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
drm_err(&dev_priv->drm,
"HEAD_PTR write failed - dsb engine is busy.\n");
drm_err(&dev_priv->drm, "DSB engine is busy.\n");
goto reset;
}
intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id),
DSB_ENABLE);
intel_de_write(dev_priv, DSB_HEAD(pipe, dsb->id),
i915_ggtt_offset(dsb->vma));
tail = ALIGN(dsb->free_pos * 4, CACHELINE_BYTES);
if (tail > dsb->free_pos * 4)
memset(&dsb->cmd_buf[dsb->free_pos], 0,
(tail - dsb->free_pos * 4));
if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
drm_err(&dev_priv->drm,
"TAIL_PTR write failed - dsb engine is busy.\n");
goto reset;
}
drm_dbg_kms(&dev_priv->drm,
"DSB execution started - head 0x%x, tail 0x%x\n",
i915_ggtt_offset(dsb->vma), tail);
intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id),
i915_ggtt_offset(dsb->vma) + tail);
if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) {
drm_dbg_kms(&dev_priv->drm,
"DSB execution started - head 0x%x, tail 0x%x\n",
i915_ggtt_offset(dsb->vma),
i915_ggtt_offset(dsb->vma) + tail);
if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1))
drm_err(&dev_priv->drm,
"Timed out waiting for DSB workload completion.\n");
goto reset;
}
reset:
dsb->free_pos = 0;
dsb->ins_start_offset = 0;
intel_dsb_disable_engine(dev_priv, pipe, dsb->id);
intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id), 0);
}
/**
* intel_dsb_prepare() - Allocate, pin and map the DSB command buffer.
* @crtc: the CRTC
* @max_cmds: number of commands we need to fit into command buffer
*
* This function prepare the command buffer which is used to store dsb
* instructions with data.
@ -279,25 +269,30 @@ void intel_dsb_commit(struct intel_dsb *dsb)
* Returns:
* DSB context, NULL on failure
*/
struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc)
struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
unsigned int max_cmds)
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
struct intel_dsb *dsb;
struct drm_i915_gem_object *obj;
struct i915_vma *vma;
u32 *buf;
intel_wakeref_t wakeref;
struct intel_dsb *dsb;
struct i915_vma *vma;
unsigned int size;
u32 *buf;
if (!HAS_DSB(i915))
return NULL;
dsb = kmalloc(sizeof(*dsb), GFP_KERNEL);
dsb = kzalloc(sizeof(*dsb), GFP_KERNEL);
if (!dsb)
goto out;
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE);
/* ~1 qword per instruction, full cachelines */
size = ALIGN(max_cmds * 8, CACHELINE_BYTES);
obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size));
if (IS_ERR(obj))
goto out_put_rpm;
@ -319,6 +314,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc)
dsb->vma = vma;
dsb->crtc = crtc;
dsb->cmd_buf = buf;
dsb->size = size / 4; /* in dwords */
dsb->free_pos = 0;
dsb->ins_start_offset = 0;

View file

@ -13,12 +13,11 @@
struct intel_crtc;
struct intel_dsb;
struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc);
struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
unsigned int max_cmds);
void intel_dsb_cleanup(struct intel_dsb *dsb);
void intel_dsb_reg_write(struct intel_dsb *dsb,
i915_reg_t reg, u32 val);
void intel_dsb_indexed_reg_write(struct intel_dsb *dsb,
i915_reg_t reg, u32 val);
void intel_dsb_commit(struct intel_dsb *dsb);
#endif

View file

@ -554,6 +554,6 @@ void intel_dvo_init(struct drm_i915_private *i915)
*/
intel_panel_add_encoder_fixed_mode(connector, encoder);
intel_panel_init(connector);
intel_panel_init(connector, NULL);
}
}

View file

@ -25,7 +25,7 @@
#include "i915_reg_defs.h"
#include "intel_display.h"
#include "intel_display_limits.h"
enum drm_connector_status;
struct drm_display_mode;

View file

@ -331,15 +331,15 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc)
{
struct drm_i915_private *i915 = fbc->i915;
GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.start,
GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.stolen.start,
fbc->compressed_fb.start, U32_MAX));
GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.start,
GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.stolen.start,
fbc->compressed_llb.start, U32_MAX));
intel_de_write(i915, FBC_CFB_BASE,
i915->dsm.start + fbc->compressed_fb.start);
i915->dsm.stolen.start + fbc->compressed_fb.start);
intel_de_write(i915, FBC_LL_BASE,
i915->dsm.start + fbc->compressed_llb.start);
i915->dsm.stolen.start + fbc->compressed_llb.start);
}
static const struct intel_fbc_funcs i8xx_fbc_funcs = {
@ -712,7 +712,7 @@ static u64 intel_fbc_stolen_end(struct drm_i915_private *i915)
* underruns, even if that range is not reserved by the BIOS. */
if (IS_BROADWELL(i915) ||
(DISPLAY_VER(i915) == 9 && !IS_BROXTON(i915)))
end = resource_size(&i915->dsm) - 8 * 1024 * 1024;
end = resource_size(&i915->dsm.stolen) - 8 * 1024 * 1024;
else
end = U64_MAX;
@ -1807,10 +1807,10 @@ static int intel_fbc_debugfs_false_color_set(void *data, u64 val)
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(intel_fbc_debugfs_false_color_fops,
intel_fbc_debugfs_false_color_get,
intel_fbc_debugfs_false_color_set,
"%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(intel_fbc_debugfs_false_color_fops,
intel_fbc_debugfs_false_color_get,
intel_fbc_debugfs_false_color_set,
"%llu\n");
static void intel_fbc_debugfs_add(struct intel_fbc *fbc,
struct dentry *parent)
@ -1819,8 +1819,8 @@ static void intel_fbc_debugfs_add(struct intel_fbc *fbc,
fbc, &intel_fbc_debugfs_status_fops);
if (fbc->funcs->set_false_color)
debugfs_create_file("i915_fbc_false_color", 0644, parent,
fbc, &intel_fbc_debugfs_false_color_fops);
debugfs_create_file_unsafe("i915_fbc_false_color", 0644, parent,
fbc, &intel_fbc_debugfs_false_color_fops);
}
void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc)

View file

@ -170,7 +170,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
* important and we should probably use that space with FBC or other
* features.
*/
if (size * 2 < dev_priv->stolen_usable_size)
if (size * 2 < dev_priv->dsm.usable_size)
obj = i915_gem_object_create_stolen(dev_priv, size);
if (IS_ERR(obj))
obj = i915_gem_object_create_shmem(dev_priv, size);

View file

@ -44,6 +44,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_connector.h"
#include "intel_ddi.h"
#include "intel_de.h"
@ -537,9 +538,7 @@ void hsw_write_infoframe(struct intel_encoder *encoder,
0);
/* Wa_14013475917 */
if ((DISPLAY_VER(dev_priv) == 13 ||
IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) && crtc_state->has_psr &&
type == DP_SDP_VSC)
if (IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC)
return;
val |= hsw_infoframe_enable(type);
@ -2271,7 +2270,8 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
pipe_config->pixel_multiplier = 2;
pipe_config->has_audio =
intel_hdmi_has_audio(encoder, pipe_config, conn_state);
intel_hdmi_has_audio(encoder, pipe_config, conn_state) &&
intel_audio_compute_config(encoder, pipe_config, conn_state);
/*
* Try to respect downstream TMDS clock limits first, if
@ -2360,7 +2360,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
kfree(to_intel_connector(connector)->detect_edid);
drm_edid_free(to_intel_connector(connector)->detect_edid);
to_intel_connector(connector)->detect_edid = NULL;
}
@ -2421,7 +2421,8 @@ intel_hdmi_set_edid(struct drm_connector *connector)
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector));
intel_wakeref_t wakeref;
struct edid *edid;
const struct drm_edid *drm_edid;
const struct edid *edid;
bool connected = false;
struct i2c_adapter *i2c;
@ -2429,17 +2430,23 @@ intel_hdmi_set_edid(struct drm_connector *connector)
i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
edid = drm_get_edid(connector, i2c);
drm_edid = drm_edid_read_ddc(connector, i2c);
if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) {
drm_dbg_kms(&dev_priv->drm,
"HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
intel_gmbus_force_bit(i2c, true);
edid = drm_get_edid(connector, i2c);
drm_edid = drm_edid_read_ddc(connector, i2c);
intel_gmbus_force_bit(i2c, false);
}
to_intel_connector(connector)->detect_edid = edid;
/* Below we depend on display info having been updated */
drm_edid_connector_update(connector, drm_edid);
to_intel_connector(connector)->detect_edid = drm_edid;
/* FIXME: Get rid of drm_edid_raw() */
edid = drm_edid_raw(drm_edid);
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
@ -2515,13 +2522,8 @@ intel_hdmi_force(struct drm_connector *connector)
static int intel_hdmi_get_modes(struct drm_connector *connector)
{
struct edid *edid;
edid = to_intel_connector(connector)->detect_edid;
if (edid == NULL)
return 0;
return intel_connector_update_modes(connector, edid);
/* drm_edid_connector_update() done in ->detect() or ->force() */
return drm_edid_connector_add_modes(connector);
}
static struct i2c_adapter *

View file

@ -477,10 +477,14 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
static int intel_lvds_get_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
const struct drm_edid *fixed_edid = intel_connector->panel.fixed_edid;
/* use cached edid if we have one */
if (!IS_ERR_OR_NULL(intel_connector->edid))
return drm_add_edid_modes(connector, intel_connector->edid);
/* Use panel fixed edid if we have one */
if (!IS_ERR_OR_NULL(fixed_edid)) {
drm_edid_connector_update(connector, fixed_edid);
return drm_edid_connector_add_modes(connector);
}
return intel_panel_get_modes(intel_connector);
}
@ -834,7 +838,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct edid *edid;
const struct drm_edid *drm_edid;
i915_reg_t lvds_reg;
u32 lvds;
u8 pin;
@ -945,27 +949,34 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
* preferred mode is the right one.
*/
mutex_lock(&dev_priv->drm.mode_config.mutex);
if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) {
const struct edid *edid;
/* FIXME: Make drm_get_edid_switcheroo() return drm_edid */
edid = drm_get_edid_switcheroo(connector,
intel_gmbus_get_adapter(dev_priv, pin));
else
edid = drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv, pin));
if (edid) {
if (drm_add_edid_modes(connector, edid)) {
drm_connector_update_edid_property(connector,
edid);
} else {
intel_gmbus_get_adapter(dev_priv, pin));
if (edid) {
drm_edid = drm_edid_alloc(edid, (edid->extensions + 1) * EDID_LENGTH);
kfree(edid);
edid = ERR_PTR(-EINVAL);
} else {
drm_edid = NULL;
}
} else {
edid = ERR_PTR(-ENOENT);
drm_edid = drm_edid_read_ddc(connector,
intel_gmbus_get_adapter(dev_priv, pin));
}
if (drm_edid) {
if (drm_edid_connector_update(connector, drm_edid) ||
!drm_edid_connector_add_modes(connector)) {
drm_edid_connector_update(connector, NULL);
drm_edid_free(drm_edid);
drm_edid = ERR_PTR(-EINVAL);
}
} else {
drm_edid = ERR_PTR(-ENOENT);
}
intel_connector->edid = edid;
intel_bios_init_panel_late(dev_priv, &intel_connector->panel, NULL,
IS_ERR(edid) ? NULL : edid);
IS_ERR(drm_edid) ? NULL : drm_edid);
/* Try EDID first */
intel_panel_add_edid_fixed_modes(intel_connector, true);
@ -988,7 +999,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto failed;
intel_panel_init(intel_connector);
intel_panel_init(intel_connector, drm_edid);
intel_backlight_setup(intel_connector, INVALID_PIPE);

View file

@ -698,8 +698,10 @@ void intel_modeset_setup_hw_state(struct drm_i915_private *i915,
drm_crtc_vblank_reset(&crtc->base);
if (crtc_state->hw.active)
if (crtc_state->hw.active) {
intel_dmc_enable_pipe(i915, crtc->pipe);
intel_crtc_vblank_on(crtc_state);
}
}
intel_fbc_sanitize(i915);

View file

@ -1101,41 +1101,34 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
* The EDID in the OpRegion, or NULL if there is none or it's invalid.
*
*/
struct edid *intel_opregion_get_edid(struct intel_connector *intel_connector)
const struct drm_edid *intel_opregion_get_edid(struct intel_connector *intel_connector)
{
struct drm_connector *connector = &intel_connector->base;
struct drm_i915_private *i915 = to_i915(connector->dev);
struct intel_opregion *opregion = &i915->display.opregion;
const void *in_edid;
const struct edid *edid;
struct edid *new_edid;
const struct drm_edid *drm_edid;
const void *edid;
int len;
if (!opregion->asle_ext)
return NULL;
in_edid = opregion->asle_ext->bddc;
edid = opregion->asle_ext->bddc;
/* Validity corresponds to number of 128-byte blocks */
len = (opregion->asle_ext->phed & ASLE_PHED_EDID_VALID_MASK) * 128;
if (!len || !memchr_inv(in_edid, 0, len))
if (!len || !memchr_inv(edid, 0, len))
return NULL;
edid = in_edid;
drm_edid = drm_edid_alloc(edid, len);
if (len < EDID_LENGTH * (1 + edid->extensions)) {
drm_dbg_kms(&i915->drm, "Invalid EDID in ACPI OpRegion (Mailbox #5): too short\n");
return NULL;
}
new_edid = drm_edid_duplicate(edid);
if (!new_edid)
return NULL;
if (!drm_edid_is_valid(new_edid)) {
kfree(new_edid);
if (!drm_edid_valid(drm_edid)) {
drm_dbg_kms(&i915->drm, "Invalid EDID in ACPI OpRegion (Mailbox #5)\n");
return NULL;
drm_edid_free(drm_edid);
drm_edid = NULL;
}
return new_edid;
return drm_edid;
}
bool intel_opregion_headless_sku(struct drm_i915_private *i915)

View file

@ -74,7 +74,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv,
pci_power_t state);
int intel_opregion_get_panel_type(struct drm_i915_private *dev_priv);
struct edid *intel_opregion_get_edid(struct intel_connector *connector);
const struct drm_edid *intel_opregion_get_edid(struct intel_connector *connector);
bool intel_opregion_headless_sku(struct drm_i915_private *i915);
@ -123,7 +123,7 @@ static inline int intel_opregion_get_panel_type(struct drm_i915_private *dev)
return -ENODEV;
}
static inline struct edid *
static inline const struct drm_edid *
intel_opregion_get_edid(struct intel_connector *connector)
{
return NULL;

View file

@ -31,6 +31,8 @@
#include <linux/kernel.h>
#include <linux/pwm.h>
#include <drm/drm_edid.h>
#include "i915_reg.h"
#include "intel_backlight.h"
#include "intel_connector.h"
@ -670,10 +672,13 @@ void intel_panel_init_alloc(struct intel_connector *connector)
INIT_LIST_HEAD(&panel->fixed_modes);
}
int intel_panel_init(struct intel_connector *connector)
int intel_panel_init(struct intel_connector *connector,
const struct drm_edid *fixed_edid)
{
struct intel_panel *panel = &connector->panel;
panel->fixed_edid = fixed_edid;
intel_backlight_init_funcs(panel);
if (!has_drrs_modes(connector))
@ -692,6 +697,9 @@ void intel_panel_fini(struct intel_connector *connector)
struct intel_panel *panel = &connector->panel;
struct drm_display_mode *fixed_mode, *next;
if (!IS_ERR_OR_NULL(panel->fixed_edid))
drm_edid_free(panel->fixed_edid);
intel_backlight_destroy(panel);
intel_bios_fini_panel(panel);

View file

@ -13,13 +13,15 @@ enum drrs_type;
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
struct drm_edid;
struct drm_i915_private;
struct intel_connector;
struct intel_crtc_state;
struct intel_encoder;
void intel_panel_init_alloc(struct intel_connector *connector);
int intel_panel_init(struct intel_connector *connector);
int intel_panel_init(struct intel_connector *connector,
const struct drm_edid *fixed_edid);
void intel_panel_fini(struct intel_connector *connector);
enum drm_connector_status
intel_panel_detect(struct drm_connector *connector, bool force);

View file

@ -467,24 +467,24 @@ static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
* clock hierarchy. That would also allow us to do
* clock bending finally.
*/
dev_priv->pch_ssc_use = 0;
dev_priv->display.dpll.pch_ssc_use = 0;
if (spll_uses_pch_ssc(dev_priv)) {
drm_dbg_kms(&dev_priv->drm, "SPLL using PCH SSC\n");
dev_priv->pch_ssc_use |= BIT(DPLL_ID_SPLL);
dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_SPLL);
}
if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
drm_dbg_kms(&dev_priv->drm, "WRPLL1 using PCH SSC\n");
dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
}
if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
drm_dbg_kms(&dev_priv->drm, "WRPLL2 using PCH SSC\n");
dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
}
if (dev_priv->pch_ssc_use)
if (dev_priv->display.dpll.pch_ssc_use)
return;
if (has_fdi) {

View file

@ -72,14 +72,13 @@ static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
return 0;
}
static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
enum pipe pipe,
enum intel_pipe_crc_source *source)
static void i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
enum pipe pipe,
enum intel_pipe_crc_source *source)
{
struct intel_encoder *encoder;
struct intel_crtc *crtc;
struct intel_digital_port *dig_port;
int ret = 0;
*source = INTEL_PIPE_CRC_SOURCE_PIPE;
@ -121,8 +120,6 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
}
}
drm_modeset_unlock_all(&dev_priv->drm);
return ret;
}
static int vlv_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
@ -132,11 +129,8 @@ static int vlv_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
{
bool need_stable_symbols = false;
if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
int ret = i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
if (ret)
return ret;
}
if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
switch (*source) {
case INTEL_PIPE_CRC_SOURCE_PIPE:
@ -200,11 +194,8 @@ static int i9xx_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
enum intel_pipe_crc_source *source,
u32 *val)
{
if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
int ret = i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
if (ret)
return ret;
}
if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
switch (*source) {
case INTEL_PIPE_CRC_SOURCE_PIPE:

View file

@ -107,7 +107,7 @@ initial_plane_vma(struct drm_i915_private *i915,
*/
if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
mem == i915->mm.stolen_region &&
size * 2 > i915->stolen_usable_size)
size * 2 > i915->dsm.usable_size)
return NULL;
obj = i915_gem_object_create_region_at(mem, phys_base, size, 0);

View file

@ -24,14 +24,13 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include "display/intel_dp.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_hdmi.h"
#include "intel_psr.h"
@ -1112,6 +1111,8 @@ static u32 wa_16013835468_bit_get(struct intel_dp *intel_dp)
return LATENCY_REPORTING_REMOVED_PIPE_B;
case PIPE_C:
return LATENCY_REPORTING_REMOVED_PIPE_C;
case PIPE_D:
return LATENCY_REPORTING_REMOVED_PIPE_D;
default:
MISSING_CASE(intel_dp->psr.pipe);
return 0;
@ -1163,6 +1164,23 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
intel_dp->psr.psr2_sel_fetch_enabled ?
IGNORE_PSR2_HW_TRACKING : 0);
/*
* Wa_16013835468
* Wa_14015648006
*/
if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) ||
IS_DISPLAY_VER(dev_priv, 12, 13)) {
u16 vtotal, vblank;
vtotal = crtc_state->uapi.adjusted_mode.crtc_vtotal -
crtc_state->uapi.adjusted_mode.crtc_vdisplay;
vblank = crtc_state->uapi.adjusted_mode.crtc_vblank_end -
crtc_state->uapi.adjusted_mode.crtc_vblank_start;
if (vblank > vtotal)
intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1, 0,
wa_16013835468_bit_get(intel_dp));
}
if (intel_dp->psr.psr2_enabled) {
if (DISPLAY_VER(dev_priv) == 9)
intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), 0,
@ -1196,20 +1214,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
else if (IS_ALDERLAKE_P(dev_priv))
intel_de_rmw(dev_priv, CLKGATE_DIS_MISC, 0,
CLKGATE_DIS_MISC_DMASC_GATING_DIS);
/* Wa_16013835468:tgl[b0+], dg1 */
if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_B0, STEP_FOREVER) ||
IS_DG1(dev_priv)) {
u16 vtotal, vblank;
vtotal = crtc_state->uapi.adjusted_mode.crtc_vtotal -
crtc_state->uapi.adjusted_mode.crtc_vdisplay;
vblank = crtc_state->uapi.adjusted_mode.crtc_vblank_end -
crtc_state->uapi.adjusted_mode.crtc_vblank_start;
if (vblank > vtotal)
intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1, 0,
wa_16013835468_bit_get(intel_dp));
}
}
}
@ -1362,6 +1366,15 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0);
/*
* Wa_16013835468
* Wa_14015648006
*/
if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) ||
IS_DISPLAY_VER(dev_priv, 12, 13))
intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1,
wa_16013835468_bit_get(intel_dp), 0);
if (intel_dp->psr.psr2_enabled) {
/* Wa_16011168373:adl-p */
if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0))
@ -1377,12 +1390,6 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
else if (IS_ALDERLAKE_P(dev_priv))
intel_de_rmw(dev_priv, CLKGATE_DIS_MISC,
CLKGATE_DIS_MISC_DMASC_GATING_DIS, 0);
/* Wa_16013835468:tgl[b0+], dg1 */
if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_B0, STEP_FOREVER) ||
IS_DG1(dev_priv))
intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1,
wa_16013835468_bit_get(intel_dp), 0);
}
intel_snps_phy_update_psr_power_state(dev_priv, phy, false);
@ -1835,6 +1842,12 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
if (full_update)
goto skip_sel_fetch_set_loop;
/* Wa_14014971492 */
if ((IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) ||
IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) &&
crtc_state->splitter.enable)
pipe_clip.y1 = 0;
ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
if (ret)
return ret;

View file

@ -39,6 +39,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_connector.h"
#include "intel_crtc.h"
#include "intel_de.h"
@ -1068,7 +1069,8 @@ static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
&tx_rate, 1))
return -ENXIO;
if (tx_rate == SDVO_HBUF_TX_DISABLED)
/* TX_DISABLED doesn't mean disabled for ELD */
if (if_index != SDVO_HBUF_INDEX_ELD && tx_rate == SDVO_HBUF_TX_DISABLED)
return 0;
if (!intel_sdvo_get_hbuf_size(intel_sdvo, &hbuf_size))
@ -1185,6 +1187,28 @@ static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
}
static void intel_sdvo_get_eld(struct intel_sdvo *intel_sdvo,
struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
ssize_t len;
u8 val;
if (!crtc_state->has_audio)
return;
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT, &val, 1))
return;
if ((val & SDVO_AUDIO_ELD_VALID) == 0)
return;
len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD,
crtc_state->eld, sizeof(crtc_state->eld));
if (len < 0)
drm_dbg_kms(&i915->drm, "failed to read ELD\n");
}
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
const struct drm_connector_state *conn_state)
{
@ -1378,7 +1402,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
pipe_config->has_hdmi_sink = intel_has_hdmi_sink(intel_sdvo, conn_state);
pipe_config->has_audio = intel_sdvo_has_audio(encoder, pipe_config, conn_state);
pipe_config->has_audio =
intel_sdvo_has_audio(encoder, pipe_config, conn_state) &&
intel_audio_compute_config(encoder, pipe_config, conn_state);
pipe_config->limited_color_range =
intel_sdvo_limited_color_range(encoder, pipe_config,
@ -1729,9 +1755,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
&val, 1)) {
u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT;
if ((val & mask) == mask)
if (val & SDVO_AUDIO_PRESENCE_DETECT)
pipe_config->has_audio = true;
}
@ -1742,6 +1766,8 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
}
intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
intel_sdvo_get_eld(intel_sdvo, pipe_config);
}
static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo)
@ -1753,12 +1779,7 @@ static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
struct drm_connector *connector = conn_state->connector;
u8 *eld = connector->eld;
eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
const u8 *eld = crtc_state->eld;
intel_sdvo_set_audio_state(intel_sdvo, 0);
@ -2903,7 +2924,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
mutex_unlock(&i915->drm.mode_config.mutex);
}
intel_panel_init(intel_connector);
intel_panel_init(intel_connector, NULL);
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto err;

View file

@ -40,7 +40,7 @@ void intel_snps_phy_wait_for_calibration(struct drm_i915_private *i915)
*/
if (intel_de_wait_for_clear(i915, DG2_PHY_MISC(phy),
DG2_PHY_DP_TX_ACK_MASK, 25))
i915->snps_phy_failed_calibration |= BIT(phy);
i915->display.snps.phy_failed_calibration |= BIT(phy);
}
}

View file

@ -0,0 +1,441 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2022-2023 Intel Corporation
*/
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_vblank.h"
/*
* This timing diagram depicts the video signal in and
* around the vertical blanking period.
*
* Assumptions about the fictitious mode used in this example:
* vblank_start >= 3
* vsync_start = vblank_start + 1
* vsync_end = vblank_start + 2
* vtotal = vblank_start + 3
*
* start of vblank:
* latch double buffered registers
* increment frame counter (ctg+)
* generate start of vblank interrupt (gen4+)
* |
* | frame start:
* | generate frame start interrupt (aka. vblank interrupt) (gmch)
* | may be shifted forward 1-3 extra lines via PIPECONF
* | |
* | | start of vsync:
* | | generate vsync interrupt
* | | |
* ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx
* . \hs/ . \hs/ \hs/ \hs/ . \hs/
* ----va---> <-----------------vb--------------------> <--------va-------------
* | | <----vs-----> |
* -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
* -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
* -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
* | | |
* last visible pixel first visible pixel
* | increment frame counter (gen3/4)
* pixel counter = vblank_start * htotal pixel counter = 0 (gen3/4)
*
* x = horizontal active
* _ = horizontal blanking
* hs = horizontal sync
* va = vertical active
* vb = vertical blanking
* vs = vertical sync
* vbs = vblank_start (number)
*
* Summary:
* - most events happen at the start of horizontal sync
* - frame start happens at the start of horizontal blank, 1-4 lines
* (depending on PIPECONF settings) after the start of vblank
* - gen3/4 pixel and frame counter are synchronized with the start
* of horizontal active on the first line of vertical active
*/
/*
* Called from drm generic code, passed a 'crtc', which we use as a pipe index.
*/
u32 i915_get_vblank_counter(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
const struct drm_display_mode *mode = &vblank->hwmode;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
u32 pixel, vbl_start, hsync_start, htotal;
u64 frame;
/*
* On i965gm TV output the frame counter only works up to
* the point when we enable the TV encoder. After that the
* frame counter ceases to work and reads zero. We need a
* vblank wait before enabling the TV encoder and so we
* have to enable vblank interrupts while the frame counter
* is still in a working state. However the core vblank code
* does not like us returning non-zero frame counter values
* when we've told it that we don't have a working frame
* counter. Thus we must stop non-zero values leaking out.
*/
if (!vblank->max_vblank_count)
return 0;
htotal = mode->crtc_htotal;
hsync_start = mode->crtc_hsync_start;
vbl_start = mode->crtc_vblank_start;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vbl_start = DIV_ROUND_UP(vbl_start, 2);
/* Convert to pixel count */
vbl_start *= htotal;
/* Start of vblank event occurs at start of hsync */
vbl_start -= htotal - hsync_start;
/*
* High & low register fields aren't synchronized, so make sure
* we get a low value that's stable across two reads of the high
* register.
*/
frame = intel_de_read64_2x32(dev_priv, PIPEFRAMEPIXEL(pipe), PIPEFRAME(pipe));
pixel = frame & PIPE_PIXEL_MASK;
frame = (frame >> PIPE_FRAME_LOW_SHIFT) & 0xffffff;
/*
* The frame counter increments at beginning of active.
* Cook up a vblank counter by also checking the pixel
* counter against vblank start.
*/
return (frame + (pixel >= vbl_start)) & 0xffffff;
}
u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
enum pipe pipe = to_intel_crtc(crtc)->pipe;
if (!vblank->max_vblank_count)
return 0;
return intel_de_read(dev_priv, PIPE_FRMCOUNT_G4X(pipe));
}
static u32 intel_crtc_scanlines_since_frame_timestamp(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct drm_vblank_crtc *vblank =
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
const struct drm_display_mode *mode = &vblank->hwmode;
u32 htotal = mode->crtc_htotal;
u32 clock = mode->crtc_clock;
u32 scan_prev_time, scan_curr_time, scan_post_time;
/*
* To avoid the race condition where we might cross into the
* next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
* reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
* during the same frame.
*/
do {
/*
* This field provides read back of the display
* pipe frame time stamp. The time stamp value
* is sampled at every start of vertical blank.
*/
scan_prev_time = intel_de_read_fw(dev_priv,
PIPE_FRMTMSTMP(crtc->pipe));
/*
* The TIMESTAMP_CTR register has the current
* time stamp value.
*/
scan_curr_time = intel_de_read_fw(dev_priv, IVB_TIMESTAMP_CTR);
scan_post_time = intel_de_read_fw(dev_priv,
PIPE_FRMTMSTMP(crtc->pipe));
} while (scan_post_time != scan_prev_time);
return div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
clock), 1000 * htotal);
}
/*
* On certain encoders on certain platforms, pipe
* scanline register will not work to get the scanline,
* since the timings are driven from the PORT or issues
* with scanline register updates.
* This function will use Framestamp and current
* timestamp registers to calculate the scanline.
*/
static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
{
struct drm_vblank_crtc *vblank =
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
const struct drm_display_mode *mode = &vblank->hwmode;
u32 vblank_start = mode->crtc_vblank_start;
u32 vtotal = mode->crtc_vtotal;
u32 scanline;
scanline = intel_crtc_scanlines_since_frame_timestamp(crtc);
scanline = min(scanline, vtotal - 1);
scanline = (scanline + vblank_start) % vtotal;
return scanline;
}
/*
* intel_de_read_fw(), only for fast reads of display block, no need for
* forcewake etc.
*/
static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
const struct drm_display_mode *mode;
struct drm_vblank_crtc *vblank;
enum pipe pipe = crtc->pipe;
int position, vtotal;
if (!crtc->active)
return 0;
vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
mode = &vblank->hwmode;
if (crtc->mode_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
return __intel_get_crtc_scanline_from_timestamp(crtc);
vtotal = mode->crtc_vtotal;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vtotal /= 2;
position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
/*
* On HSW, the DSL reg (0x70000) appears to return 0 if we
* read it just before the start of vblank. So try it again
* so we don't accidentally end up spanning a vblank frame
* increment, causing the pipe_update_end() code to squak at us.
*
* The nature of this problem means we can't simply check the ISR
* bit and return the vblank start value; nor can we use the scanline
* debug register in the transcoder as it appears to have the same
* problem. We may need to extend this to include other platforms,
* but so far testing only shows the problem on HSW.
*/
if (HAS_DDI(dev_priv) && !position) {
int i, temp;
for (i = 0; i < 100; i++) {
udelay(1);
temp = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
if (temp != position) {
position = temp;
break;
}
}
}
/*
* See update_scanline_offset() for the details on the
* scanline_offset adjustment.
*/
return (position + crtc->scanline_offset) % vtotal;
}
static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
bool in_vblank_irq,
int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
struct drm_device *dev = _crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *crtc = to_intel_crtc(_crtc);
enum pipe pipe = crtc->pipe;
int position;
int vbl_start, vbl_end, hsync_start, htotal, vtotal;
unsigned long irqflags;
bool use_scanline_counter = DISPLAY_VER(dev_priv) >= 5 ||
IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) == 2 ||
crtc->mode_flags & I915_MODE_FLAG_USE_SCANLINE_COUNTER;
if (drm_WARN_ON(&dev_priv->drm, !mode->crtc_clock)) {
drm_dbg(&dev_priv->drm,
"trying to get scanoutpos for disabled pipe %c\n",
pipe_name(pipe));
return false;
}
htotal = mode->crtc_htotal;
hsync_start = mode->crtc_hsync_start;
vtotal = mode->crtc_vtotal;
vbl_start = mode->crtc_vblank_start;
vbl_end = mode->crtc_vblank_end;
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
vbl_start = DIV_ROUND_UP(vbl_start, 2);
vbl_end /= 2;
vtotal /= 2;
}
/*
* Lock uncore.lock, as we will do multiple timing critical raw
* register reads, potentially with preemption disabled, so the
* following code must not block on uncore.lock.
*/
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
/* Get optional system timestamp before query. */
if (stime)
*stime = ktime_get();
if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
int scanlines = intel_crtc_scanlines_since_frame_timestamp(crtc);
position = __intel_get_crtc_scanline(crtc);
/*
* Already exiting vblank? If so, shift our position
* so it looks like we're already apporaching the full
* vblank end. This should make the generated timestamp
* more or less match when the active portion will start.
*/
if (position >= vbl_start && scanlines < position)
position = min(crtc->vmax_vblank_start + scanlines, vtotal - 1);
} else if (use_scanline_counter) {
/* No obvious pixelcount register. Only query vertical
* scanout position from Display scan line register.
*/
position = __intel_get_crtc_scanline(crtc);
} else {
/*
* Have access to pixelcount since start of frame.
* We can split this into vertical and horizontal
* scanout position.
*/
position = (intel_de_read_fw(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
/* convert to pixel counts */
vbl_start *= htotal;
vbl_end *= htotal;
vtotal *= htotal;
/*
* In interlaced modes, the pixel counter counts all pixels,
* so one field will have htotal more pixels. In order to avoid
* the reported position from jumping backwards when the pixel
* counter is beyond the length of the shorter field, just
* clamp the position the length of the shorter field. This
* matches how the scanline counter based position works since
* the scanline counter doesn't count the two half lines.
*/
if (position >= vtotal)
position = vtotal - 1;
/*
* Start of vblank interrupt is triggered at start of hsync,
* just prior to the first active line of vblank. However we
* consider lines to start at the leading edge of horizontal
* active. So, should we get here before we've crossed into
* the horizontal active of the first line in vblank, we would
* not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
* always add htotal-hsync_start to the current pixel position.
*/
position = (position + htotal - hsync_start) % vtotal;
}
/* Get optional system timestamp after query. */
if (etime)
*etime = ktime_get();
/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
/*
* While in vblank, position will be negative
* counting up towards 0 at vbl_end. And outside
* vblank, position will be positive counting
* up since vbl_end.
*/
if (position >= vbl_start)
position -= vbl_end;
else
position += vtotal - vbl_end;
if (use_scanline_counter) {
*vpos = position;
*hpos = 0;
} else {
*vpos = position / htotal;
*hpos = position - (*vpos * htotal);
}
return true;
}
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
ktime_t *vblank_time, bool in_vblank_irq)
{
return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
crtc, max_error, vblank_time, in_vblank_irq,
i915_get_crtc_scanoutpos);
}
int intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
unsigned long irqflags;
int position;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
position = __intel_get_crtc_scanline(crtc);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
return position;
}
static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
i915_reg_t reg = PIPEDSL(pipe);
u32 line1, line2;
line1 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
msleep(5);
line2 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
return line1 != line2;
}
static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
/* Wait for the display line to settle/start moving */
if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100))
drm_err(&dev_priv->drm,
"pipe %c scanline %s wait timed out\n",
pipe_name(pipe), str_on_off(state));
}
void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc)
{
wait_for_pipe_scanline_moving(crtc, false);
}
void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
{
wait_for_pipe_scanline_moving(crtc, true);
}

View file

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022-2023 Intel Corporation
*/
#ifndef __INTEL_VBLANK_H__
#define __INTEL_VBLANK_H__
#include <linux/ktime.h>
#include <linux/types.h>
struct drm_crtc;
struct intel_crtc;
u32 i915_get_vblank_counter(struct drm_crtc *crtc);
u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
ktime_t *vblank_time, bool in_vblank_irq);
int intel_get_crtc_scanline(struct intel_crtc *crtc);
void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc);
void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc);
#endif /* __INTEL_VBLANK_H__ */

View file

@ -6,9 +6,10 @@
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <drm/i915_drm.h>
#include <video/vga.h>
#include "soc/intel_gmch.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_de.h"
@ -98,39 +99,12 @@ void intel_vga_reset_io_mem(struct drm_i915_private *i915)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
}
static int
intel_vga_set_state(struct drm_i915_private *i915, bool enable_decode)
{
unsigned int reg = DISPLAY_VER(i915) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
u16 gmch_ctrl;
if (pci_read_config_word(i915->bridge_dev, reg, &gmch_ctrl)) {
drm_err(&i915->drm, "failed to read control word\n");
return -EIO;
}
if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode)
return 0;
if (enable_decode)
gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
else
gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
if (pci_write_config_word(i915->bridge_dev, reg, gmch_ctrl)) {
drm_err(&i915->drm, "failed to write control word\n");
return -EIO;
}
return 0;
}
static unsigned int
intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
{
struct drm_i915_private *i915 = pdev_to_i915(pdev);
intel_vga_set_state(i915, enable_decode);
intel_gmch_vga_set_state(i915, enable_decode);
if (enable_decode)
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |

View file

@ -87,6 +87,10 @@ static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited)
#define ICL_MAX_SRC_H 4096
#define ICL_MAX_DST_W 5120
#define ICL_MAX_DST_H 4096
#define TGL_MAX_SRC_W 5120
#define TGL_MAX_SRC_H 8192
#define TGL_MAX_DST_W 8192
#define TGL_MAX_DST_H 8192
#define MTL_MAX_SRC_W 4096
#define MTL_MAX_SRC_H 8192
#define MTL_MAX_DST_W 8192
@ -173,11 +177,16 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
max_src_h = SKL_MAX_SRC_H;
max_dst_w = SKL_MAX_DST_W;
max_dst_h = SKL_MAX_DST_H;
} else if (DISPLAY_VER(dev_priv) < 14) {
} else if (DISPLAY_VER(dev_priv) < 12) {
max_src_w = ICL_MAX_SRC_W;
max_src_h = ICL_MAX_SRC_H;
max_dst_w = ICL_MAX_DST_W;
max_dst_h = ICL_MAX_DST_H;
} else if (DISPLAY_VER(dev_priv) < 14) {
max_src_w = TGL_MAX_SRC_W;
max_src_h = TGL_MAX_SRC_H;
max_dst_w = TGL_MAX_DST_W;
max_dst_h = TGL_MAX_DST_H;
} else {
max_src_w = MTL_MAX_SRC_W;
max_src_h = MTL_MAX_SRC_H;

View file

@ -1627,7 +1627,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
u32 offset;
int ret;
if (w > max_width || w < min_width || h > max_height) {
if (w > max_width || w < min_width || h > max_height || h < 1) {
drm_dbg_kms(&dev_priv->drm,
"requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
w, h, min_width, max_width, max_height);

View file

@ -8,7 +8,7 @@
#include <linux/types.h>
#include "intel_display.h"
#include "intel_display_limits.h"
#include "intel_global_state.h"
#include "intel_pm_types.h"

View file

@ -1983,7 +1983,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
goto err_cleanup_connector;
}
intel_panel_init(intel_connector);
intel_panel_init(intel_connector, NULL);
intel_backlight_setup(intel_connector, INVALID_PIPE);

View file

@ -8,6 +8,7 @@
#include "display/intel_frontbuffer.h"
#include "i915_config.h"
#include "i915_drv.h"
#include "i915_gem_clflush.h"
#include "i915_sw_fence_work.h"

View file

@ -5,6 +5,7 @@
#include <drm/drm_fourcc.h>
#include "display/intel_display.h"
#include "gem/i915_gem_ioctls.h"
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"

View file

@ -4,6 +4,7 @@
* Copyright © 2014-2016 Intel Corporation
*/
#include "display/intel_display.h"
#include "display/intel_frontbuffer.h"
#include "gt/intel_gt.h"

View file

@ -110,9 +110,7 @@ static int adjust_stolen(struct drm_i915_private *i915,
else
ggtt_start &= PGTBL_ADDRESS_LO_MASK;
ggtt_res =
(struct resource) DEFINE_RES_MEM(ggtt_start,
ggtt_total_entries(ggtt) * 4);
ggtt_res = DEFINE_RES_MEM(ggtt_start, ggtt_total_entries(ggtt) * 4);
if (ggtt_res.start >= stolen[0].start && ggtt_res.start < stolen[0].end)
stolen[0].end = ggtt_res.start;
@ -211,7 +209,7 @@ static void g4x_get_stolen_reserved(struct drm_i915_private *i915,
IS_GM45(i915) ?
CTG_STOLEN_RESERVED :
ELK_STOLEN_RESERVED);
resource_size_t stolen_top = i915->dsm.end + 1;
resource_size_t stolen_top = i915->dsm.stolen.end + 1;
drm_dbg(&i915->drm, "%s_STOLEN_RESERVED = %08x\n",
IS_GM45(i915) ? "CTG" : "ELK", reg_val);
@ -276,7 +274,7 @@ static void vlv_get_stolen_reserved(struct drm_i915_private *i915,
resource_size_t *size)
{
u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
resource_size_t stolen_top = i915->dsm.end + 1;
resource_size_t stolen_top = i915->dsm.stolen.end + 1;
drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
@ -365,7 +363,7 @@ static void bdw_get_stolen_reserved(struct drm_i915_private *i915,
resource_size_t *size)
{
u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
resource_size_t stolen_top = i915->dsm.end + 1;
resource_size_t stolen_top = i915->dsm.stolen.end + 1;
drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
@ -414,7 +412,7 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915,
}
/*
* Initialize i915->dsm_reserved to contain the reserved space within the Data
* Initialize i915->dsm.reserved to contain the reserved space within the Data
* Stolen Memory. This is a range on the top of DSM that is reserved, not to
* be used by driver, so must be excluded from the region passed to the
* allocator later. In the spec this is also called as WOPCM.
@ -430,7 +428,7 @@ static int init_reserved_stolen(struct drm_i915_private *i915)
resource_size_t reserved_size;
int ret = 0;
stolen_top = i915->dsm.end + 1;
stolen_top = i915->dsm.stolen.end + 1;
reserved_base = stolen_top;
reserved_size = 0;
@ -471,13 +469,12 @@ static int init_reserved_stolen(struct drm_i915_private *i915)
goto bail_out;
}
i915->dsm_reserved =
(struct resource)DEFINE_RES_MEM(reserved_base, reserved_size);
i915->dsm.reserved = DEFINE_RES_MEM(reserved_base, reserved_size);
if (!resource_contains(&i915->dsm, &i915->dsm_reserved)) {
if (!resource_contains(&i915->dsm.stolen, &i915->dsm.reserved)) {
drm_err(&i915->drm,
"Stolen reserved area %pR outside stolen memory %pR\n",
&i915->dsm_reserved, &i915->dsm);
&i915->dsm.reserved, &i915->dsm.stolen);
ret = -EINVAL;
goto bail_out;
}
@ -485,8 +482,7 @@ static int init_reserved_stolen(struct drm_i915_private *i915)
return 0;
bail_out:
i915->dsm_reserved =
(struct resource)DEFINE_RES_MEM(reserved_base, 0);
i915->dsm.reserved = DEFINE_RES_MEM(reserved_base, 0);
return ret;
}
@ -517,27 +513,27 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem)
if (request_smem_stolen(i915, &mem->region))
return -ENOSPC;
i915->dsm = mem->region;
i915->dsm.stolen = mem->region;
if (init_reserved_stolen(i915))
return -ENOSPC;
/* Exclude the reserved region from driver use */
mem->region.end = i915->dsm_reserved.start - 1;
mem->region.end = i915->dsm.reserved.start - 1;
mem->io_size = min(mem->io_size, resource_size(&mem->region));
i915->stolen_usable_size = resource_size(&mem->region);
i915->dsm.usable_size = resource_size(&mem->region);
drm_dbg(&i915->drm,
"Memory reserved for graphics device: %lluK, usable: %lluK\n",
(u64)resource_size(&i915->dsm) >> 10,
(u64)i915->stolen_usable_size >> 10);
(u64)resource_size(&i915->dsm.stolen) >> 10,
(u64)i915->dsm.usable_size >> 10);
if (i915->stolen_usable_size == 0)
if (i915->dsm.usable_size == 0)
return -ENOSPC;
/* Basic memrange allocator for stolen space. */
drm_mm_init(&i915->mm.stolen, 0, i915->stolen_usable_size);
drm_mm_init(&i915->mm.stolen, 0, i915->dsm.usable_size);
return 0;
}
@ -587,7 +583,7 @@ i915_pages_create_for_stolen(struct drm_device *dev,
struct sg_table *st;
struct scatterlist *sg;
GEM_BUG_ON(range_overflows(offset, size, resource_size(&i915->dsm)));
GEM_BUG_ON(range_overflows(offset, size, resource_size(&i915->dsm.stolen)));
/* We hide that we have no struct page backing our stolen object
* by wrapping the contiguous physical allocation with a fake
@ -607,7 +603,7 @@ i915_pages_create_for_stolen(struct drm_device *dev,
sg->offset = 0;
sg->length = size;
sg_dma_address(sg) = (dma_addr_t)i915->dsm.start + offset;
sg_dma_address(sg) = (dma_addr_t)i915->dsm.stolen.start + offset;
sg_dma_len(sg) = size;
return st;

View file

@ -12,6 +12,7 @@
#include <drm/i915_drm.h>
#include <drm/intel-gtt.h>
#include "display/intel_display.h"
#include "gem/i915_gem_lmem.h"
#include "intel_ggtt_gmch.h"
@ -885,8 +886,8 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
static struct resource pci_resource(struct pci_dev *pdev, int bar)
{
return (struct resource)DEFINE_RES_MEM(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
return DEFINE_RES_MEM(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
}
static int gen8_gmch_probe(struct i915_ggtt *ggtt)

View file

@ -5,6 +5,7 @@
#include <linux/highmem.h>
#include "display/intel_display.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_scatterlist.h"

View file

@ -80,7 +80,7 @@ int intel_ggtt_gmch_probe(struct i915_ggtt *ggtt)
phys_addr_t gmadr_base;
int ret;
ret = intel_gmch_probe(i915->bridge_dev, to_pci_dev(i915->drm.dev), NULL);
ret = intel_gmch_probe(i915->gmch.pdev, to_pci_dev(i915->drm.dev), NULL);
if (!ret) {
drm_err(&i915->drm, "failed to set up gmch\n");
return -EIO;
@ -88,8 +88,7 @@ int intel_ggtt_gmch_probe(struct i915_ggtt *ggtt)
intel_gmch_gtt_get(&ggtt->vm.total, &gmadr_base, &ggtt->mappable_end);
ggtt->gmadr =
(struct resource)DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end);
ggtt->gmadr = DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end);
ggtt->vm.alloc_pt_dma = alloc_pt_dma;
ggtt->vm.alloc_scratch_dma = alloc_pt_dma;

View file

@ -301,7 +301,7 @@ static int chv_rc6_init(struct intel_rc6 *rc6)
pcbr = intel_uncore_read(uncore, VLV_PCBR);
if ((pcbr >> VLV_PCBR_ADDR_SHIFT) == 0) {
drm_dbg(&i915->drm, "BIOS didn't set up PCBR, fixing up\n");
paddr = i915->dsm.end + 1 - pctx_size;
paddr = i915->dsm.stolen.end + 1 - pctx_size;
GEM_BUG_ON(paddr > U32_MAX);
pctx_paddr = (paddr & ~4095);
@ -325,7 +325,7 @@ static int vlv_rc6_init(struct intel_rc6 *rc6)
/* BIOS set it up already, grab the pre-alloc'd space */
resource_size_t pcbr_offset;
pcbr_offset = (pcbr & ~4095) - i915->dsm.start;
pcbr_offset = (pcbr & ~4095) - i915->dsm.stolen.start;
pctx = i915_gem_object_create_region_at(i915->mm.stolen_region,
pcbr_offset,
pctx_size,
@ -354,10 +354,10 @@ static int vlv_rc6_init(struct intel_rc6 *rc6)
}
GEM_BUG_ON(range_overflows_end_t(u64,
i915->dsm.start,
i915->dsm.stolen.start,
pctx->stolen->start,
U32_MAX));
pctx_paddr = i915->dsm.start + pctx->stolen->start;
pctx_paddr = i915->dsm.stolen.start + pctx->stolen->start;
intel_uncore_write(uncore, VLV_PCBR, pctx_paddr);
out:
@ -448,8 +448,8 @@ static bool bxt_check_bios_rc6_setup(struct intel_rc6 *rc6)
*/
rc6_ctx_base =
intel_uncore_read(uncore, RC6_CTX_BASE) & RC6_CTX_BASE_MASK;
if (!(rc6_ctx_base >= i915->dsm_reserved.start &&
rc6_ctx_base + PAGE_SIZE < i915->dsm_reserved.end)) {
if (!(rc6_ctx_base >= i915->dsm.reserved.start &&
rc6_ctx_base + PAGE_SIZE < i915->dsm.reserved.end)) {
drm_dbg(&i915->drm, "RC6 Base address not as expected.\n");
enable_rc6 = false;
}

View file

@ -7,6 +7,7 @@
#include <drm/i915_drm.h>
#include "display/intel_display.h"
#include "i915_drv.h"
#include "i915_irq.h"
#include "intel_breadcrumbs.h"

View file

@ -12,6 +12,9 @@
struct i915_request;
struct drm_printer;
#define GT_FREQUENCY_MULTIPLIER 50
#define GEN9_FREQ_SCALER 3
void intel_rps_init_early(struct intel_rps *rps);
void intel_rps_init(struct intel_rps *rps);
void intel_rps_sanitize(struct intel_rps *rps);

View file

@ -20,7 +20,7 @@ __igt_reset_stolen(struct intel_gt *gt,
const char *msg)
{
struct i915_ggtt *ggtt = gt->ggtt;
const struct resource *dsm = &gt->i915->dsm;
const struct resource *dsm = &gt->i915->dsm.stolen;
resource_size_t num_pages, page;
struct intel_engine_cs *engine;
intel_wakeref_t wakeref;

View file

@ -49,6 +49,7 @@
#include "i915_pvinfo.h"
#include "trace.h"
#include "display/intel_display.h"
#include "gem/i915_gem_context.h"
#include "gem/i915_gem_pm.h"
#include "gt/intel_context.h"

View file

@ -36,6 +36,7 @@
#include "i915_reg.h"
#include "gvt.h"
#include "display/intel_display.h"
#include "display/intel_dpio_phy.h"
static int get_edp_pipe(struct intel_vgpu *vgpu)

View file

@ -38,7 +38,7 @@
#include <linux/types.h>
#include "display/intel_display.h"
#include "display/intel_display_limits.h"
struct intel_vgpu;

View file

@ -3,7 +3,10 @@
* Copyright © 2020 Intel Corporation
*/
#include "i915_drv.h"
#include <linux/kernel.h>
#include "i915_config.h"
#include "i915_utils.h"
unsigned long
i915_fence_context_timeout(const struct drm_i915_private *i915, u64 context)

View file

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __I915_CONFIG_H__
#define __I915_CONFIG_H__
#include <linux/types.h>
#include <linux/limits.h>
struct drm_i915_private;
unsigned long i915_fence_context_timeout(const struct drm_i915_private *i915,
u64 context);
static inline unsigned long
i915_fence_timeout(const struct drm_i915_private *i915)
{
return i915_fence_context_timeout(i915, U64_MAX);
}
#endif /* __I915_CONFIG_H__ */

View file

@ -648,13 +648,14 @@ i915_drop_caches_get(void *data, u64 *val)
return 0;
}
static int
gt_drop_caches(struct intel_gt *gt, u64 val)
{
int ret;
if (val & DROP_RESET_ACTIVE &&
wait_for(intel_engines_are_idle(gt), I915_IDLE_ENGINES_TIMEOUT))
wait_for(intel_engines_are_idle(gt), 200))
intel_gt_set_wedged(gt);
if (val & DROP_RETIRE)
@ -762,7 +763,6 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_sseu_status", i915_sseu_status, 0},
{"i915_rps_boost_info", i915_rps_boost_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
static const struct i915_debugfs_files {
const char *name;
@ -795,6 +795,6 @@ void i915_debugfs_register(struct drm_i915_private *dev_priv)
}
drm_debugfs_create_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES,
ARRAY_SIZE(i915_debugfs_list),
minor->debugfs_root, minor);
}

View file

@ -230,27 +230,16 @@ i915_debugfs_create_charp(const char *name, umode_t mode,
&i915_param_charp_fops);
}
static __always_inline void
_i915_param_create_file(struct dentry *parent, const char *name,
const char *type, int mode, void *value)
{
if (!mode)
return;
if (!__builtin_strcmp(type, "bool"))
debugfs_create_bool(name, mode, parent, value);
else if (!__builtin_strcmp(type, "int"))
i915_debugfs_create_int(name, mode, parent, value);
else if (!__builtin_strcmp(type, "unsigned int"))
i915_debugfs_create_uint(name, mode, parent, value);
else if (!__builtin_strcmp(type, "unsigned long"))
debugfs_create_ulong(name, mode, parent, value);
else if (!__builtin_strcmp(type, "char *"))
i915_debugfs_create_charp(name, mode, parent, value);
else
WARN(1, "no debugfs fops defined for param type %s (i915.%s)\n",
type, name);
}
#define _i915_param_create_file(parent, name, mode, valp) \
do { \
if (mode) \
_Generic(valp, \
bool *: debugfs_create_bool, \
int *: i915_debugfs_create_int, \
unsigned int *: i915_debugfs_create_uint, \
unsigned long *: debugfs_create_ulong, \
char **: i915_debugfs_create_charp)(name, mode, parent, valp); \
} while(0)
/* add a subdirectory with files for each i915 param */
struct dentry *i915_debugfs_params(struct drm_i915_private *i915)
@ -269,7 +258,7 @@ struct dentry *i915_debugfs_params(struct drm_i915_private *i915)
* just let the generic create file fail silently with -EEXIST.
*/
#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, #T, mode, &params->x);
#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, mode, &params->x);
I915_PARAMS_FOR_EACH(REGISTER);
#undef REGISTER

View file

@ -34,7 +34,6 @@
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pnp.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/vga_switcheroo.h>
@ -78,6 +77,7 @@
#include "pxp/intel_pxp_pm.h"
#include "soc/intel_dram.h"
#include "soc/intel_gmch.h"
#include "i915_file_private.h"
#include "i915_debugfs.h"
@ -107,141 +107,6 @@
static const struct drm_driver i915_drm_driver;
static void i915_release_bridge_dev(struct drm_device *dev,
void *bridge)
{
pci_dev_put(bridge);
}
static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
{
int domain = pci_domain_nr(to_pci_dev(dev_priv->drm.dev)->bus);
dev_priv->bridge_dev =
pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0));
if (!dev_priv->bridge_dev) {
drm_err(&dev_priv->drm, "bridge device not found\n");
return -EIO;
}
return drmm_add_action_or_reset(&dev_priv->drm, i915_release_bridge_dev,
dev_priv->bridge_dev);
}
/* Allocate space for the MCH regs if needed, return nonzero on error */
static int
intel_alloc_mchbar_resource(struct drm_i915_private *dev_priv)
{
int reg = GRAPHICS_VER(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp_lo, temp_hi = 0;
u64 mchbar_addr;
int ret;
if (GRAPHICS_VER(dev_priv) >= 4)
pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
#ifdef CONFIG_PNP
if (mchbar_addr &&
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE))
return 0;
#endif
/* Get some space for it */
dev_priv->mch_res.name = "i915 MCHBAR";
dev_priv->mch_res.flags = IORESOURCE_MEM;
ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus,
&dev_priv->mch_res,
MCHBAR_SIZE, MCHBAR_SIZE,
PCIBIOS_MIN_MEM,
0, pcibios_align_resource,
dev_priv->bridge_dev);
if (ret) {
drm_dbg(&dev_priv->drm, "failed bus alloc: %d\n", ret);
dev_priv->mch_res.start = 0;
return ret;
}
if (GRAPHICS_VER(dev_priv) >= 4)
pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
upper_32_bits(dev_priv->mch_res.start));
pci_write_config_dword(dev_priv->bridge_dev, reg,
lower_32_bits(dev_priv->mch_res.start));
return 0;
}
/* Setup MCHBAR if possible, return true if we should disable it again */
static void
intel_setup_mchbar(struct drm_i915_private *dev_priv)
{
int mchbar_reg = GRAPHICS_VER(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bool enabled;
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
return;
dev_priv->mchbar_need_disable = false;
if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
pci_read_config_dword(dev_priv->bridge_dev, DEVEN, &temp);
enabled = !!(temp & DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
enabled = temp & 1;
}
/* If it's already enabled, don't have to do anything */
if (enabled)
return;
if (intel_alloc_mchbar_resource(dev_priv))
return;
dev_priv->mchbar_need_disable = true;
/* Space is allocated or reserved, so enable it. */
if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
pci_write_config_dword(dev_priv->bridge_dev, DEVEN,
temp | DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
}
}
static void
intel_teardown_mchbar(struct drm_i915_private *dev_priv)
{
int mchbar_reg = GRAPHICS_VER(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
if (dev_priv->mchbar_need_disable) {
if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
u32 deven_val;
pci_read_config_dword(dev_priv->bridge_dev, DEVEN,
&deven_val);
deven_val &= ~DEVEN_MCHBAR_EN;
pci_write_config_dword(dev_priv->bridge_dev, DEVEN,
deven_val);
} else {
u32 mchbar_val;
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg,
&mchbar_val);
mchbar_val &= ~1;
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg,
mchbar_val);
}
}
if (dev_priv->mch_res.start)
release_resource(&dev_priv->mch_res);
}
static int i915_workqueues_init(struct drm_i915_private *dev_priv)
{
/*
@ -447,7 +312,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
if (i915_inject_probe_failure(dev_priv))
return -ENODEV;
ret = i915_get_bridge_dev(dev_priv);
ret = intel_gmch_bridge_setup(dev_priv);
if (ret < 0)
return ret;
@ -464,7 +329,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
}
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev_priv);
intel_gmch_bar_setup(dev_priv);
intel_device_info_runtime_init(dev_priv);
for_each_gt(gt, dev_priv, i) {
@ -479,7 +344,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
return 0;
err_uncore:
intel_teardown_mchbar(dev_priv);
intel_gmch_bar_teardown(dev_priv);
return ret;
}
@ -490,7 +355,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
*/
static void i915_driver_mmio_release(struct drm_i915_private *dev_priv)
{
intel_teardown_mchbar(dev_priv);
intel_gmch_bar_teardown(dev_priv);
}
/**

View file

@ -36,7 +36,7 @@
#include <drm/ttm/ttm_device.h>
#include "display/intel_display.h"
#include "display/intel_display_limits.h"
#include "display/intel_display_core.h"
#include "gem/i915_gem_context_types.h"
@ -65,27 +65,42 @@
#include "intel_uncore.h"
struct drm_i915_clock_gating_funcs;
struct drm_i915_gem_object;
struct drm_i915_private;
struct intel_connector;
struct intel_dp;
struct intel_encoder;
struct intel_limit;
struct intel_overlay_error_state;
struct vlv_s0ix_state;
struct intel_pxp;
#define I915_GEM_GPU_DOMAINS \
(I915_GEM_DOMAIN_RENDER | \
I915_GEM_DOMAIN_SAMPLER | \
I915_GEM_DOMAIN_COMMAND | \
I915_GEM_DOMAIN_INSTRUCTION | \
I915_GEM_DOMAIN_VERTEX)
#define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */
#define GEM_QUIRK_PIN_SWIZZLED_PAGES BIT(0)
/* Data Stolen Memory (DSM) aka "i915 stolen memory" */
struct i915_dsm {
/*
* The start and end of DSM which we can optionally use to create GEM
* objects backed by stolen memory.
*
* Note that usable_size tells us exactly how much of this we are
* actually allowed to use, given that some portion of it is in fact
* reserved for use by hardware functions.
*/
struct resource stolen;
/*
* Reserved portion of DSM.
*/
struct resource reserved;
/*
* Total size minus reserved ranges.
*
* DSM is segmented in hardware with different portions offlimits to
* certain functions.
*
* The drm_mm is initialised to the total accessible range, as found
* from the PCI config. On Broadwell+, this is further restricted to
* avoid the first page! The upper end of DSM is reserved for hardware
* functions and similarly removed from the accessible range.
*/
resource_size_t usable_size;
};
struct i915_suspend_saved_registers {
u32 saveDSPARB;
u32 saveSWF0[16];
@ -163,19 +178,6 @@ struct i915_gem_mm {
u32 shrink_count;
};
#define I915_IDLE_ENGINES_TIMEOUT (200) /* in ms */
unsigned long i915_fence_context_timeout(const struct drm_i915_private *i915,
u64 context);
static inline unsigned long
i915_fence_timeout(const struct drm_i915_private *i915)
{
return i915_fence_context_timeout(i915, U64_MAX);
}
#define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915))
struct i915_virtual_gpu {
struct mutex lock; /* serialises sending of g2v_notify command pkts */
bool active;
@ -205,29 +207,7 @@ struct drm_i915_private {
struct intel_runtime_info __runtime; /* Use RUNTIME_INFO() to access. */
struct intel_driver_caps caps;
/**
* Data Stolen Memory - aka "i915 stolen memory" gives us the start and
* end of stolen which we can optionally use to create GEM objects
* backed by stolen memory. Note that stolen_usable_size tells us
* exactly how much of this we are actually allowed to use, given that
* some portion of it is in fact reserved for use by hardware functions.
*/
struct resource dsm;
/**
* Reseved portion of Data Stolen Memory
*/
struct resource dsm_reserved;
/*
* Stolen memory is segmented in hardware with different portions
* offlimits to certain functions.
*
* The drm_mm is initialised to the total accessible range, as found
* from the PCI config. On Broadwell+, this is further restricted to
* avoid the first page! The upper end of stolen memory is reserved for
* hardware functions and similarly removed from the accessible range.
*/
resource_size_t stolen_usable_size; /* Total size minus reserved ranges */
struct i915_dsm dsm;
struct intel_uncore uncore;
struct intel_uncore_mmio_debug mmio_debug;
@ -236,13 +216,15 @@ struct drm_i915_private {
struct intel_gvt *gvt;
struct pci_dev *bridge_dev;
struct {
struct pci_dev *pdev;
struct resource mch_res;
bool mchbar_need_disable;
} gmch;
struct rb_root uabi_engines;
unsigned int engine_uabi_class_count[I915_LAST_UABI_ENGINE_CLASS + 1];
struct resource mch_res;
/* protects the irq masks */
spinlock_t irq_lock;
@ -288,8 +270,6 @@ struct drm_i915_private {
struct i915_gem_mm mm;
bool mchbar_need_disable;
struct intel_l3_parity l3_parity;
/*
@ -300,14 +280,6 @@ struct drm_i915_private {
struct i915_gpu_error gpu_error;
/*
* Shadows for CHV DPLL_MD regs to keep the state
* checker somewhat working in the presence hardware
* crappiness (can't read out DPLL_MD for pipes B & C).
*/
u32 chv_dpll_md[I915_MAX_PIPES];
u32 bxt_phy_grc;
u32 suspend_count;
struct i915_suspend_saved_registers regfile;
struct vlv_s0ix_state *vlv_s0ix_state;
@ -368,19 +340,11 @@ struct drm_i915_private {
struct intel_pxp *pxp;
u8 pch_ssc_use;
/* For i915gm/i945gm vblank irq workaround */
u8 vblank_enabled;
bool irq_enabled;
/*
* DG2: Mask of PHYs that were not calibrated by the firmware
* and should not be used.
*/
u8 snps_phy_failed_calibration;
struct i915_pmu pmu;
struct i915_drm_clients clients;
@ -469,9 +433,6 @@ static inline struct intel_gt *to_gt(struct drm_i915_private *i915)
#define INTEL_REVID(dev_priv) (to_pci_dev((dev_priv)->drm.dev)->revision)
#define HAS_DSB(dev_priv) (INTEL_INFO(dev_priv)->display.has_dsb)
#define HAS_DSC(__i915) (RUNTIME_INFO(__i915)->has_dsc)
#define INTEL_DISPLAY_STEP(__i915) (RUNTIME_INFO(__i915)->step.display_step)
#define INTEL_GRAPHICS_STEP(__i915) (RUNTIME_INFO(__i915)->step.graphics_step)
#define INTEL_MEDIA_STEP(__i915) (RUNTIME_INFO(__i915)->step.media_step)
@ -883,6 +844,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_RPS(dev_priv) (INTEL_INFO(dev_priv)->has_rps)
#define HAS_DMC(dev_priv) (RUNTIME_INFO(dev_priv)->has_dmc)
#define HAS_DSB(dev_priv) (INTEL_INFO(dev_priv)->display.has_dsb)
#define HAS_DSC(__i915) (RUNTIME_INFO(__i915)->has_dsc)
#define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915))
#define HAS_HECI_PXP(dev_priv) \
(INTEL_INFO(dev_priv)->has_heci_pxp)
@ -940,9 +904,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define NUM_L3_SLICES(dev_priv) (IS_HSW_GT3(dev_priv) ? \
2 : HAS_L3_DPF(dev_priv))
#define GT_FREQUENCY_MULTIPLIER 50
#define GEN9_FREQ_SCALER 3
#define INTEL_NUM_PIPES(dev_priv) (hweight8(RUNTIME_INFO(dev_priv)->pipe_mask))
#define HAS_DISPLAY(dev_priv) (RUNTIME_INFO(dev_priv)->pipe_mask != 0)

View file

@ -39,6 +39,13 @@ struct i915_gem_ww_ctx;
struct i915_gtt_view;
struct i915_vma;
#define I915_GEM_GPU_DOMAINS \
(I915_GEM_DOMAIN_RENDER | \
I915_GEM_DOMAIN_SAMPLER | \
I915_GEM_DOMAIN_COMMAND | \
I915_GEM_DOMAIN_INSTRUCTION | \
I915_GEM_DOMAIN_VERTEX)
void i915_gem_init_early(struct drm_i915_private *i915);
void i915_gem_cleanup_early(struct drm_i915_private *i915);

View file

@ -18,6 +18,8 @@ struct drm_i915_gem_object;
struct i915_address_space;
struct i915_gem_ww_ctx;
#define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */
int __must_check i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
struct sg_table *pages);
void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,

View file

@ -614,414 +614,6 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock);
}
/*
* This timing diagram depicts the video signal in and
* around the vertical blanking period.
*
* Assumptions about the fictitious mode used in this example:
* vblank_start >= 3
* vsync_start = vblank_start + 1
* vsync_end = vblank_start + 2
* vtotal = vblank_start + 3
*
* start of vblank:
* latch double buffered registers
* increment frame counter (ctg+)
* generate start of vblank interrupt (gen4+)
* |
* | frame start:
* | generate frame start interrupt (aka. vblank interrupt) (gmch)
* | may be shifted forward 1-3 extra lines via PIPECONF
* | |
* | | start of vsync:
* | | generate vsync interrupt
* | | |
* ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx
* . \hs/ . \hs/ \hs/ \hs/ . \hs/
* ----va---> <-----------------vb--------------------> <--------va-------------
* | | <----vs-----> |
* -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
* -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
* -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
* | | |
* last visible pixel first visible pixel
* | increment frame counter (gen3/4)
* pixel counter = vblank_start * htotal pixel counter = 0 (gen3/4)
*
* x = horizontal active
* _ = horizontal blanking
* hs = horizontal sync
* va = vertical active
* vb = vertical blanking
* vs = vertical sync
* vbs = vblank_start (number)
*
* Summary:
* - most events happen at the start of horizontal sync
* - frame start happens at the start of horizontal blank, 1-4 lines
* (depending on PIPECONF settings) after the start of vblank
* - gen3/4 pixel and frame counter are synchronized with the start
* of horizontal active on the first line of vertical active
*/
/* Called from drm generic code, passed a 'crtc', which
* we use as a pipe index
*/
u32 i915_get_vblank_counter(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
const struct drm_display_mode *mode = &vblank->hwmode;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
i915_reg_t high_frame, low_frame;
u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
unsigned long irqflags;
/*
* On i965gm TV output the frame counter only works up to
* the point when we enable the TV encoder. After that the
* frame counter ceases to work and reads zero. We need a
* vblank wait before enabling the TV encoder and so we
* have to enable vblank interrupts while the frame counter
* is still in a working state. However the core vblank code
* does not like us returning non-zero frame counter values
* when we've told it that we don't have a working frame
* counter. Thus we must stop non-zero values leaking out.
*/
if (!vblank->max_vblank_count)
return 0;
htotal = mode->crtc_htotal;
hsync_start = mode->crtc_hsync_start;
vbl_start = mode->crtc_vblank_start;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vbl_start = DIV_ROUND_UP(vbl_start, 2);
/* Convert to pixel count */
vbl_start *= htotal;
/* Start of vblank event occurs at start of hsync */
vbl_start -= htotal - hsync_start;
high_frame = PIPEFRAME(pipe);
low_frame = PIPEFRAMEPIXEL(pipe);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/*
* High & low register fields aren't synchronized, so make sure
* we get a low value that's stable across two reads of the high
* register.
*/
do {
high1 = intel_de_read_fw(dev_priv, high_frame) & PIPE_FRAME_HIGH_MASK;
low = intel_de_read_fw(dev_priv, low_frame);
high2 = intel_de_read_fw(dev_priv, high_frame) & PIPE_FRAME_HIGH_MASK;
} while (high1 != high2);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
high1 >>= PIPE_FRAME_HIGH_SHIFT;
pixel = low & PIPE_PIXEL_MASK;
low >>= PIPE_FRAME_LOW_SHIFT;
/*
* The frame counter increments at beginning of active.
* Cook up a vblank counter by also checking the pixel
* counter against vblank start.
*/
return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
}
u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
enum pipe pipe = to_intel_crtc(crtc)->pipe;
if (!vblank->max_vblank_count)
return 0;
return intel_uncore_read(&dev_priv->uncore, PIPE_FRMCOUNT_G4X(pipe));
}
static u32 intel_crtc_scanlines_since_frame_timestamp(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct drm_vblank_crtc *vblank =
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
const struct drm_display_mode *mode = &vblank->hwmode;
u32 htotal = mode->crtc_htotal;
u32 clock = mode->crtc_clock;
u32 scan_prev_time, scan_curr_time, scan_post_time;
/*
* To avoid the race condition where we might cross into the
* next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
* reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
* during the same frame.
*/
do {
/*
* This field provides read back of the display
* pipe frame time stamp. The time stamp value
* is sampled at every start of vertical blank.
*/
scan_prev_time = intel_de_read_fw(dev_priv,
PIPE_FRMTMSTMP(crtc->pipe));
/*
* The TIMESTAMP_CTR register has the current
* time stamp value.
*/
scan_curr_time = intel_de_read_fw(dev_priv, IVB_TIMESTAMP_CTR);
scan_post_time = intel_de_read_fw(dev_priv,
PIPE_FRMTMSTMP(crtc->pipe));
} while (scan_post_time != scan_prev_time);
return div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
clock), 1000 * htotal);
}
/*
* On certain encoders on certain platforms, pipe
* scanline register will not work to get the scanline,
* since the timings are driven from the PORT or issues
* with scanline register updates.
* This function will use Framestamp and current
* timestamp registers to calculate the scanline.
*/
static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
{
struct drm_vblank_crtc *vblank =
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
const struct drm_display_mode *mode = &vblank->hwmode;
u32 vblank_start = mode->crtc_vblank_start;
u32 vtotal = mode->crtc_vtotal;
u32 scanline;
scanline = intel_crtc_scanlines_since_frame_timestamp(crtc);
scanline = min(scanline, vtotal - 1);
scanline = (scanline + vblank_start) % vtotal;
return scanline;
}
/*
* intel_de_read_fw(), only for fast reads of display block, no need for
* forcewake etc.
*/
static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
const struct drm_display_mode *mode;
struct drm_vblank_crtc *vblank;
enum pipe pipe = crtc->pipe;
int position, vtotal;
if (!crtc->active)
return 0;
vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
mode = &vblank->hwmode;
if (crtc->mode_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
return __intel_get_crtc_scanline_from_timestamp(crtc);
vtotal = mode->crtc_vtotal;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vtotal /= 2;
position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
/*
* On HSW, the DSL reg (0x70000) appears to return 0 if we
* read it just before the start of vblank. So try it again
* so we don't accidentally end up spanning a vblank frame
* increment, causing the pipe_update_end() code to squak at us.
*
* The nature of this problem means we can't simply check the ISR
* bit and return the vblank start value; nor can we use the scanline
* debug register in the transcoder as it appears to have the same
* problem. We may need to extend this to include other platforms,
* but so far testing only shows the problem on HSW.
*/
if (HAS_DDI(dev_priv) && !position) {
int i, temp;
for (i = 0; i < 100; i++) {
udelay(1);
temp = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
if (temp != position) {
position = temp;
break;
}
}
}
/*
* See update_scanline_offset() for the details on the
* scanline_offset adjustment.
*/
return (position + crtc->scanline_offset) % vtotal;
}
static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
bool in_vblank_irq,
int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
struct drm_device *dev = _crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *crtc = to_intel_crtc(_crtc);
enum pipe pipe = crtc->pipe;
int position;
int vbl_start, vbl_end, hsync_start, htotal, vtotal;
unsigned long irqflags;
bool use_scanline_counter = DISPLAY_VER(dev_priv) >= 5 ||
IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) == 2 ||
crtc->mode_flags & I915_MODE_FLAG_USE_SCANLINE_COUNTER;
if (drm_WARN_ON(&dev_priv->drm, !mode->crtc_clock)) {
drm_dbg(&dev_priv->drm,
"trying to get scanoutpos for disabled "
"pipe %c\n", pipe_name(pipe));
return false;
}
htotal = mode->crtc_htotal;
hsync_start = mode->crtc_hsync_start;
vtotal = mode->crtc_vtotal;
vbl_start = mode->crtc_vblank_start;
vbl_end = mode->crtc_vblank_end;
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
vbl_start = DIV_ROUND_UP(vbl_start, 2);
vbl_end /= 2;
vtotal /= 2;
}
/*
* Lock uncore.lock, as we will do multiple timing critical raw
* register reads, potentially with preemption disabled, so the
* following code must not block on uncore.lock.
*/
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
/* Get optional system timestamp before query. */
if (stime)
*stime = ktime_get();
if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
int scanlines = intel_crtc_scanlines_since_frame_timestamp(crtc);
position = __intel_get_crtc_scanline(crtc);
/*
* Already exiting vblank? If so, shift our position
* so it looks like we're already apporaching the full
* vblank end. This should make the generated timestamp
* more or less match when the active portion will start.
*/
if (position >= vbl_start && scanlines < position)
position = min(crtc->vmax_vblank_start + scanlines, vtotal - 1);
} else if (use_scanline_counter) {
/* No obvious pixelcount register. Only query vertical
* scanout position from Display scan line register.
*/
position = __intel_get_crtc_scanline(crtc);
} else {
/* Have access to pixelcount since start of frame.
* We can split this into vertical and horizontal
* scanout position.
*/
position = (intel_de_read_fw(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
/* convert to pixel counts */
vbl_start *= htotal;
vbl_end *= htotal;
vtotal *= htotal;
/*
* In interlaced modes, the pixel counter counts all pixels,
* so one field will have htotal more pixels. In order to avoid
* the reported position from jumping backwards when the pixel
* counter is beyond the length of the shorter field, just
* clamp the position the length of the shorter field. This
* matches how the scanline counter based position works since
* the scanline counter doesn't count the two half lines.
*/
if (position >= vtotal)
position = vtotal - 1;
/*
* Start of vblank interrupt is triggered at start of hsync,
* just prior to the first active line of vblank. However we
* consider lines to start at the leading edge of horizontal
* active. So, should we get here before we've crossed into
* the horizontal active of the first line in vblank, we would
* not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
* always add htotal-hsync_start to the current pixel position.
*/
position = (position + htotal - hsync_start) % vtotal;
}
/* Get optional system timestamp after query. */
if (etime)
*etime = ktime_get();
/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
/*
* While in vblank, position will be negative
* counting up towards 0 at vbl_end. And outside
* vblank, position will be positive counting
* up since vbl_end.
*/
if (position >= vbl_start)
position -= vbl_end;
else
position += vtotal - vbl_end;
if (use_scanline_counter) {
*vpos = position;
*hpos = 0;
} else {
*vpos = position / htotal;
*hpos = position - (*vpos * htotal);
}
return true;
}
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
ktime_t *vblank_time, bool in_vblank_irq)
{
return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
crtc, max_error, vblank_time, in_vblank_irq,
i915_get_crtc_scanoutpos);
}
int intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
unsigned long irqflags;
int position;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
position = __intel_get_crtc_scanline(crtc);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
return position;
}
/**
* ivb_parity_work - Workqueue called when a parity error interrupt
* occurred.

View file

@ -66,18 +66,12 @@ bool intel_irqs_enabled(struct drm_i915_private *dev_priv);
void intel_synchronize_irq(struct drm_i915_private *i915);
void intel_synchronize_hardirq(struct drm_i915_private *i915);
int intel_get_crtc_scanline(struct intel_crtc *crtc);
void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
u8 pipe_mask);
void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
u8 pipe_mask);
u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv);
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
ktime_t *vblank_time, bool in_vblank_irq);
u32 i915_get_vblank_counter(struct drm_crtc *crtc);
u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
int i8xx_enable_vblank(struct drm_crtc *crtc);
int i915gm_enable_vblank(struct drm_crtc *crtc);

View file

@ -222,27 +222,44 @@ i915_param_named_unsafe(lmem_size, uint, 0400,
i915_param_named_unsafe(lmem_bar_size, uint, 0400,
"Set the lmem bar size(in MiB).");
static __always_inline void _print_param(struct drm_printer *p,
const char *name,
const char *type,
const void *x)
static void _param_print_bool(struct drm_printer *p, const char *name,
bool val)
{
if (!__builtin_strcmp(type, "bool"))
drm_printf(p, "i915.%s=%s\n", name,
str_yes_no(*(const bool *)x));
else if (!__builtin_strcmp(type, "int"))
drm_printf(p, "i915.%s=%d\n", name, *(const int *)x);
else if (!__builtin_strcmp(type, "unsigned int"))
drm_printf(p, "i915.%s=%u\n", name, *(const unsigned int *)x);
else if (!__builtin_strcmp(type, "unsigned long"))
drm_printf(p, "i915.%s=%lu\n", name, *(const unsigned long *)x);
else if (!__builtin_strcmp(type, "char *"))
drm_printf(p, "i915.%s=%s\n", name, *(const char **)x);
else
WARN_ONCE(1, "no printer defined for param type %s (i915.%s)\n",
type, name);
drm_printf(p, "i915.%s=%s\n", name, str_yes_no(val));
}
static void _param_print_int(struct drm_printer *p, const char *name,
int val)
{
drm_printf(p, "i915.%s=%d\n", name, val);
}
static void _param_print_uint(struct drm_printer *p, const char *name,
unsigned int val)
{
drm_printf(p, "i915.%s=%u\n", name, val);
}
static void _param_print_ulong(struct drm_printer *p, const char *name,
unsigned long val)
{
drm_printf(p, "i915.%s=%lu\n", name, val);
}
static void _param_print_charp(struct drm_printer *p, const char *name,
const char *val)
{
drm_printf(p, "i915.%s=%s\n", name, val);
}
#define _param_print(p, name, val) \
_Generic(val, \
bool: _param_print_bool, \
int: _param_print_int, \
unsigned int: _param_print_uint, \
unsigned long: _param_print_ulong, \
char *: _param_print_charp)(p, name, val)
/**
* i915_params_dump - dump i915 modparams
* @params: i915 modparams
@ -252,37 +269,48 @@ static __always_inline void _print_param(struct drm_printer *p,
*/
void i915_params_dump(const struct i915_params *params, struct drm_printer *p)
{
#define PRINT(T, x, ...) _print_param(p, #x, #T, &params->x);
#define PRINT(T, x, ...) _param_print(p, #x, params->x);
I915_PARAMS_FOR_EACH(PRINT);
#undef PRINT
}
static __always_inline void dup_param(const char *type, void *x)
static void _param_dup_charp(char **valp)
{
if (!__builtin_strcmp(type, "char *"))
*(void **)x = kstrdup(*(void **)x, GFP_ATOMIC);
*valp = kstrdup(*valp, GFP_ATOMIC);
}
static void _param_nop(void *valp)
{
}
#define _param_dup(valp) \
_Generic(valp, \
char **: _param_dup_charp, \
default: _param_nop)(valp)
void i915_params_copy(struct i915_params *dest, const struct i915_params *src)
{
*dest = *src;
#define DUP(T, x, ...) dup_param(#T, &dest->x);
#define DUP(T, x, ...) _param_dup(&dest->x);
I915_PARAMS_FOR_EACH(DUP);
#undef DUP
}
static __always_inline void free_param(const char *type, void *x)
static void _param_free_charp(char **valp)
{
if (!__builtin_strcmp(type, "char *")) {
kfree(*(void **)x);
*(void **)x = NULL;
}
kfree(*valp);
*valp = NULL;
}
#define _param_free(valp) \
_Generic(valp, \
char **: _param_free_charp, \
default: _param_nop)(valp)
/* free the allocated members, *not* the passed in params itself */
void i915_params_free(struct i915_params *params)
{
#define FREE(T, x, ...) free_param(#T, &params->x);
#define FREE(T, x, ...) _param_free(&params->x);
I915_PARAMS_FOR_EACH(FREE);
#undef FREE
}

View file

@ -26,6 +26,7 @@
#include <drm/drm_drv.h>
#include <drm/i915_pciids.h>
#include "display/intel_display.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_sa_media.h"

View file

@ -5737,6 +5737,7 @@
#define RESET_PCH_HANDSHAKE_ENABLE REG_BIT(4)
#define GEN8_CHICKEN_DCPR_1 _MMIO(0x46430)
#define LATENCY_REPORTING_REMOVED_PIPE_D REG_BIT(31)
#define SKL_SELECT_ALTERNATE_DC_EXIT REG_BIT(30)
#define LATENCY_REPORTING_REMOVED_PIPE_C REG_BIT(25)
#define LATENCY_REPORTING_REMOVED_PIPE_B REG_BIT(24)
@ -8105,7 +8106,7 @@ enum skl_power_gate {
#define DSB_TAIL(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x4)
#define DSB_CTRL(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x8)
#define DSB_ENABLE (1 << 31)
#define DSB_STATUS (1 << 0)
#define DSB_STATUS_BUSY (1 << 0)
#define CLKREQ_POLICY _MMIO(0x101038)
#define CLKREQ_POLICY_MEM_UP_OVRD REG_BIT(1)

View file

@ -43,6 +43,7 @@
#include "gt/intel_rps.h"
#include "i915_active.h"
#include "i915_config.h"
#include "i915_deps.h"
#include "i915_driver.h"
#include "i915_drv.h"

View file

@ -26,6 +26,7 @@
#include <linux/dma-fence-array.h>
#include <drm/drm_gem.h>
#include "display/intel_display.h"
#include "display/intel_frontbuffer.h"
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_tiling.h"

View file

@ -29,6 +29,7 @@
#include "display/intel_cdclk.h"
#include "display/intel_de.h"
#include "display/intel_display.h"
#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
#include "i915_reg.h"

View file

@ -29,7 +29,7 @@
#include "intel_step.h"
#include "display/intel_display.h"
#include "display/intel_display_limits.h"
#include "gt/intel_engine_types.h"
#include "gt/intel_context_types.h"

View file

@ -5,6 +5,7 @@
#include "display/intel_audio_regs.h"
#include "display/intel_backlight_regs.h"
#include "display/intel_display_types.h"
#include "display/intel_dmc_regs.h"
#include "display/intel_dpio_phy.h"
#include "display/vlv_dsi_pll_regs.h"

View file

@ -235,7 +235,7 @@ intel_memory_region_create(struct drm_i915_private *i915,
return ERR_PTR(-ENOMEM);
mem->i915 = i915;
mem->region = (struct resource)DEFINE_RES_MEM(start, size);
mem->region = DEFINE_RES_MEM(start, size);
mem->io_start = io_start;
mem->io_size = io_size;
mem->min_page_size = min_page_size;

View file

@ -26,6 +26,7 @@
*/
#include "display/intel_de.h"
#include "display/intel_display.h"
#include "display/intel_display_trace.h"
#include "display/skl_watermark.h"

View file

@ -8,7 +8,7 @@
#include <linux/types.h>
#include "display/intel_display.h"
#include "display/intel_display_limits.h"
enum intel_ddb_partitioning {
INTEL_DDB_PART_1_2,

View file

@ -44,7 +44,7 @@ static void trash_stolen(struct drm_i915_private *i915)
{
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
const u64 slot = ggtt->error_capture.start;
const resource_size_t size = resource_size(&i915->dsm);
const resource_size_t size = resource_size(&i915->dsm.stolen);
unsigned long page;
u32 prng = 0x12345678;
@ -53,7 +53,7 @@ static void trash_stolen(struct drm_i915_private *i915)
return;
for (page = 0; page < size; page += PAGE_SIZE) {
const dma_addr_t dma = i915->dsm.start + page;
const dma_addr_t dma = i915->dsm.stolen.start + page;
u32 __iomem *s;
int x;

View file

@ -112,7 +112,7 @@ void mock_init_ggtt(struct intel_gt *gt)
ggtt->vm.i915 = gt->i915;
ggtt->vm.is_ggtt = true;
ggtt->gmadr = (struct resource) DEFINE_RES_MEM(0, 2048 * PAGE_SIZE);
ggtt->gmadr = DEFINE_RES_MEM(0, 2048 * PAGE_SIZE);
ggtt->mappable_end = resource_size(&ggtt->gmadr);
ggtt->vm.total = 4096 * PAGE_SIZE;

View file

@ -0,0 +1,171 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include <linux/pci.h>
#include <linux/pnp.h>
#include <drm/drm_managed.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "intel_gmch.h"
#include "intel_pci_config.h"
static void intel_gmch_bridge_release(struct drm_device *dev, void *bridge)
{
pci_dev_put(bridge);
}
int intel_gmch_bridge_setup(struct drm_i915_private *i915)
{
int domain = pci_domain_nr(to_pci_dev(i915->drm.dev)->bus);
i915->gmch.pdev = pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0));
if (!i915->gmch.pdev) {
drm_err(&i915->drm, "bridge device not found\n");
return -EIO;
}
return drmm_add_action_or_reset(&i915->drm, intel_gmch_bridge_release,
i915->gmch.pdev);
}
/* Allocate space for the MCH regs if needed, return nonzero on error */
static int
intel_alloc_mchbar_resource(struct drm_i915_private *i915)
{
int reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp_lo, temp_hi = 0;
u64 mchbar_addr;
int ret;
if (GRAPHICS_VER(i915) >= 4)
pci_read_config_dword(i915->gmch.pdev, reg + 4, &temp_hi);
pci_read_config_dword(i915->gmch.pdev, reg, &temp_lo);
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
#ifdef CONFIG_PNP
if (mchbar_addr &&
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE))
return 0;
#endif
/* Get some space for it */
i915->gmch.mch_res.name = "i915 MCHBAR";
i915->gmch.mch_res.flags = IORESOURCE_MEM;
ret = pci_bus_alloc_resource(i915->gmch.pdev->bus,
&i915->gmch.mch_res,
MCHBAR_SIZE, MCHBAR_SIZE,
PCIBIOS_MIN_MEM,
0, pcibios_align_resource,
i915->gmch.pdev);
if (ret) {
drm_dbg(&i915->drm, "failed bus alloc: %d\n", ret);
i915->gmch.mch_res.start = 0;
return ret;
}
if (GRAPHICS_VER(i915) >= 4)
pci_write_config_dword(i915->gmch.pdev, reg + 4,
upper_32_bits(i915->gmch.mch_res.start));
pci_write_config_dword(i915->gmch.pdev, reg,
lower_32_bits(i915->gmch.mch_res.start));
return 0;
}
/* Setup MCHBAR if possible, return true if we should disable it again */
void intel_gmch_bar_setup(struct drm_i915_private *i915)
{
int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bool enabled;
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
return;
i915->gmch.mchbar_need_disable = false;
if (IS_I915G(i915) || IS_I915GM(i915)) {
pci_read_config_dword(i915->gmch.pdev, DEVEN, &temp);
enabled = !!(temp & DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp);
enabled = temp & 1;
}
/* If it's already enabled, don't have to do anything */
if (enabled)
return;
if (intel_alloc_mchbar_resource(i915))
return;
i915->gmch.mchbar_need_disable = true;
/* Space is allocated or reserved, so enable it. */
if (IS_I915G(i915) || IS_I915GM(i915)) {
pci_write_config_dword(i915->gmch.pdev, DEVEN,
temp | DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp);
pci_write_config_dword(i915->gmch.pdev, mchbar_reg, temp | 1);
}
}
void intel_gmch_bar_teardown(struct drm_i915_private *i915)
{
int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
if (i915->gmch.mchbar_need_disable) {
if (IS_I915G(i915) || IS_I915GM(i915)) {
u32 deven_val;
pci_read_config_dword(i915->gmch.pdev, DEVEN,
&deven_val);
deven_val &= ~DEVEN_MCHBAR_EN;
pci_write_config_dword(i915->gmch.pdev, DEVEN,
deven_val);
} else {
u32 mchbar_val;
pci_read_config_dword(i915->gmch.pdev, mchbar_reg,
&mchbar_val);
mchbar_val &= ~1;
pci_write_config_dword(i915->gmch.pdev, mchbar_reg,
mchbar_val);
}
}
if (i915->gmch.mch_res.start)
release_resource(&i915->gmch.mch_res);
}
int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode)
{
unsigned int reg = DISPLAY_VER(i915) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
u16 gmch_ctrl;
if (pci_read_config_word(i915->gmch.pdev, reg, &gmch_ctrl)) {
drm_err(&i915->drm, "failed to read control word\n");
return -EIO;
}
if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode)
return 0;
if (enable_decode)
gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
else
gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
if (pci_write_config_word(i915->gmch.pdev, reg, gmch_ctrl)) {
drm_err(&i915->drm, "failed to write control word\n");
return -EIO;
}
return 0;
}

View file

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __INTEL_GMCH_H__
#define __INTEL_GMCH_H__
#include <linux/types.h>
struct drm_i915_private;
int intel_gmch_bridge_setup(struct drm_i915_private *i915);
void intel_gmch_bar_setup(struct drm_i915_private *i915);
void intel_gmch_bar_teardown(struct drm_i915_private *i915);
int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode);
#endif /* __INTEL_GMCH_H__ */

View file

@ -9,6 +9,7 @@
#include "vlv_sideband.h"
#include "display/intel_dpio_phy.h"
#include "display/intel_display_types.h"
/*
* IOSF sideband, see VLV2_SidebandMsg_HAS.docx and