mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
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:
commit
49ed9f39c8
98 changed files with 1825 additions and 1504 deletions
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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, ®s);
|
||||
|
||||
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, ®s);
|
||||
ibx_audio_regs_init(i915, pipe, ®s);
|
||||
|
||||
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, ®s);
|
||||
ibx_audio_regs_init(i915, pipe, ®s);
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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+ */
|
||||
|
|
|
@ -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)++)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
124
drivers/gpu/drm/i915/display/intel_display_limits.h
Normal file
124
drivers/gpu/drm/i915/display/intel_display_limits.h
Normal 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__ */
|
|
@ -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__ })
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
441
drivers/gpu/drm/i915/display/intel_vblank.c
Normal file
441
drivers/gpu/drm/i915/display/intel_vblank.c
Normal 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);
|
||||
}
|
23
drivers/gpu/drm/i915/display/intel_vblank.h
Normal file
23
drivers/gpu/drm/i915/display/intel_vblank.h
Normal 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__ */
|
|
@ -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 |
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright © 2014-2016 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "display/intel_display.h"
|
||||
#include "display/intel_frontbuffer.h"
|
||||
#include "gt/intel_gt.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -20,7 +20,7 @@ __igt_reset_stolen(struct intel_gt *gt,
|
|||
const char *msg)
|
||||
{
|
||||
struct i915_ggtt *ggtt = gt->ggtt;
|
||||
const struct resource *dsm = >->i915->dsm;
|
||||
const struct resource *dsm = >->i915->dsm.stolen;
|
||||
resource_size_t num_pages, page;
|
||||
struct intel_engine_cs *engine;
|
||||
intel_wakeref_t wakeref;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "display/intel_display.h"
|
||||
#include "display/intel_display_limits.h"
|
||||
|
||||
struct intel_vgpu;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
23
drivers/gpu/drm/i915/i915_config.h
Normal file
23
drivers/gpu/drm/i915/i915_config.h
Normal 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__ */
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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, ¶ms->x);
|
||||
#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, mode, ¶ms->x);
|
||||
I915_PARAMS_FOR_EACH(REGISTER);
|
||||
#undef REGISTER
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¶ms->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, ¶ms->x);
|
||||
#define FREE(T, x, ...) _param_free(¶ms->x);
|
||||
I915_PARAMS_FOR_EACH(FREE);
|
||||
#undef FREE
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
171
drivers/gpu/drm/i915/soc/intel_gmch.c
Normal file
171
drivers/gpu/drm/i915/soc/intel_gmch.c
Normal 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;
|
||||
}
|
18
drivers/gpu/drm/i915/soc/intel_gmch.h
Normal file
18
drivers/gpu/drm/i915/soc/intel_gmch.h
Normal 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__ */
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue