Merge tag 'drm-intel-next-2022-04-13-1' of git://anongit.freedesktop.org/drm/drm-intel into drm-next

drm/i915 feature pull for v5.19:

Features and functionality:
- Add support for new Tile 4 format on DG2 (Stan)
- Add support for new CCS clear color compression on DG2 (Mika, Juha-Pekka)
- Add support for new render and media compression formats on DG2 (Matt)
- Support multiple eDP and LVDS native mode refresh rates (Ville)
- Support static DRRS (Ville)
- ATS-M platform info (Matt)
- RPL-S PCI IDs (Tejas)
- Extend DP HDR support to HSW+ (Uma)
- Bump ADL-P DMC version to v2.16 (Madhumitha)
- Let users disable PSR2 while enabling PSR1 (José)

Refactoring and cleanups:
- Massive DRRS and panel fixed mode refactoring and cleanups (Ville)
- Power well refactoring and cleanup (Imre)
- Clean up and refactor crtc readout and compute config (Ville)
- Use kernel string helpers (Lucas)
- Refactor gmbus pin lookups and allocation (Jani)
- PCH display cleanups (Ville)
- DPLL and DPLL manager refactoring (Ville)
- Include and header refactoring (Jani, Tvrtko)
- DMC abstractions (Jani)
- Non-x86 build refactoring (Casey)
- VBT parsing refactoring (Ville)
- Bigjoiner refactoring (Ville)
- Optimize plane, pfit, scaler, etc. programming using unlocked writes (Ville)
- Split several register writes in commit to noarm+arm pairs (Ville)
- Clean up SAGV handling (Ville)
- Clean up bandwidth and ddb allocation (Ville)
- FBC cleanups (Ville)

Fixes:
- Fix native HDMI and DP HDMI DFP clock limits on deep color/4:2:0 (Ville)
- Fix DMC firmware platform check (Lucas)
- Fix cursor coordinates on bigjoiner secondary (Ville)
- Fix MSO vs. bigjoiner timing confusion (Ville)
- Fix ADL-P eDP voltage swing (José)
- Fix VRR capability property update (Manasi)
- Log DG2 SNPS PHY calibration errors (Matt, Lucas)
- Fix PCODE request status checks (Stan)
- Fix uncore unclaimed access warnings (Lucas)
- Fix VBT new max TMDS clock parsing (Shawn)
- Fix ADL-P non-existent underrun recovery (Swathi Dhanavanthri)
- Fix ADL-N stepping info (Tejas)
- Fix DPT mapping flags to contiguous (Stan)
- Fix DG2 max display bandwidth (Vinod)
- Fix DP low voltage SKU checks (Ankit)
- Fix RPL-S VT-d translation enable via quirk (Tejas)
- Fixes to PSR2 (José)
- Fix PIPE_MBUS_DBOX_CTL programming (José)
- Fix LTTPR capability read/check on DP 1.2 (Imre)
- Fix ADL-P register corruption after DDI clock enabling (Imre)
- Fix ADL-P MBUS DBOX BW and B credits (Caz)

Merges:
- Backmerge drm-next (Rodrigo, Jani)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/874k2xgewe.fsf@intel.com
This commit is contained in:
Dave Airlie 2022-04-14 12:03:08 +10:00
commit c54b39a565
149 changed files with 4374 additions and 3710 deletions

View File

@ -187,19 +187,7 @@ Display Refresh Rate Switching (DRRS)
:doc: Display Refresh Rate Switching (DRRS)
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_enable
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_disable
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_invalidate
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_flush
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_init
:internal:
DPIO
----

View File

@ -18,6 +18,7 @@
#include <linux/bcma/bcma_regs.h>
#include <linux/platform_data/x86/apple.h>
#include <drm/i915_drm.h>
#include <drm/i915_pciids.h>
#include <asm/pci-direct.h>
#include <asm/dma.h>
#include <asm/io_apic.h>

View File

@ -2390,9 +2390,36 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S
}
EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs);
static int drm_dp_read_lttpr_regs(struct drm_dp_aux *aux,
const u8 dpcd[DP_RECEIVER_CAP_SIZE], int address,
u8 *buf, int buf_size)
{
/*
* At least the DELL P2715Q monitor with a DPCD_REV < 0x14 returns
* corrupted values when reading from the 0xF0000- range with a block
* size bigger than 1.
*/
int block_size = dpcd[DP_DPCD_REV] < 0x14 ? 1 : buf_size;
int offset;
int ret;
for (offset = 0; offset < buf_size; offset += block_size) {
ret = drm_dp_dpcd_read(aux,
address + offset,
&buf[offset], block_size);
if (ret < 0)
return ret;
WARN_ON(ret != block_size);
}
return 0;
}
/**
* drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities
* @aux: DisplayPort AUX channel
* @dpcd: DisplayPort configuration data
* @caps: buffer to return the capability info in
*
* Read capabilities common to all LTTPRs.
@ -2400,25 +2427,19 @@ EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs);
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux,
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
{
int ret;
ret = drm_dp_dpcd_read(aux,
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
caps, DP_LTTPR_COMMON_CAP_SIZE);
if (ret < 0)
return ret;
WARN_ON(ret != DP_LTTPR_COMMON_CAP_SIZE);
return 0;
return drm_dp_read_lttpr_regs(aux, dpcd,
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
caps, DP_LTTPR_COMMON_CAP_SIZE);
}
EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps);
/**
* drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY
* @aux: DisplayPort AUX channel
* @dpcd: DisplayPort configuration data
* @dp_phy: LTTPR PHY to read the capabilities for
* @caps: buffer to return the capability info in
*
@ -2427,20 +2448,13 @@ EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps);
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux,
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
enum drm_dp_phy dp_phy,
u8 caps[DP_LTTPR_PHY_CAP_SIZE])
{
int ret;
ret = drm_dp_dpcd_read(aux,
DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy),
caps, DP_LTTPR_PHY_CAP_SIZE);
if (ret < 0)
return ret;
WARN_ON(ret != DP_LTTPR_PHY_CAP_SIZE);
return 0;
return drm_dp_read_lttpr_regs(aux, dpcd,
DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy),
caps, DP_LTTPR_PHY_CAP_SIZE);
}
EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps);

View File

@ -213,6 +213,7 @@ i915-y += \
display/intel_cursor.o \
display/intel_display.o \
display/intel_display_power.o \
display/intel_display_power_well.o \
display/intel_dmc.o \
display/intel_dpio_phy.o \
display/intel_dpll.o \

View File

@ -5,6 +5,8 @@
* DisplayPort support for G4x,ILK,SNB,IVB,VLV,CHV (HSW+ handled by the DDI code).
*/
#include <linux/string_helpers.h>
#include "g4x_dp.h"
#include "intel_audio.h"
#include "intel_backlight.h"
@ -22,58 +24,37 @@
#include "intel_pps.h"
#include "vlv_sideband.h"
struct dp_link_dpll {
int clock;
struct dpll dpll;
static const struct dpll g4x_dpll[] = {
{ .dot = 162000, .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8, },
{ .dot = 270000, .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2, },
};
static const struct dp_link_dpll g4x_dpll[] = {
{ 162000,
{ .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } },
{ 270000,
{ .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } }
static const struct dpll pch_dpll[] = {
{ .dot = 162000, .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9, },
{ .dot = 270000, .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8, },
};
static const struct dp_link_dpll pch_dpll[] = {
{ 162000,
{ .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } },
{ 270000,
{ .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } }
static const struct dpll vlv_dpll[] = {
{ .dot = 162000, .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81, },
{ .dot = 270000, .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27, },
};
static const struct dp_link_dpll vlv_dpll[] = {
{ 162000,
{ .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } },
{ 270000,
{ .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } }
};
/*
* CHV supports eDP 1.4 that have more link rates.
* Below only provides the fixed rate but exclude variable rate.
*/
static const struct dp_link_dpll chv_dpll[] = {
/*
* CHV requires to program fractional division for m2.
* m2 is stored in fixed point format using formula below
* (m2_int << 22) | m2_fraction
*/
{ 162000, /* m2_int = 32, m2_fraction = 1677722 */
{ .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } },
{ 270000, /* m2_int = 27, m2_fraction = 0 */
{ .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } },
static const struct dpll chv_dpll[] = {
/* m2 is .22 binary fixed point */
{ .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{ .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
};
const struct dpll *vlv_get_dpll(struct drm_i915_private *i915)
{
return IS_CHERRYVIEW(i915) ? &chv_dpll[0].dpll : &vlv_dpll[0].dpll;
return IS_CHERRYVIEW(i915) ? &chv_dpll[0] : &vlv_dpll[0];
}
void g4x_dp_set_clock(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
const struct dp_link_dpll *divisor = NULL;
const struct dpll *divisor = NULL;
int i, count = 0;
if (IS_G4X(dev_priv)) {
@ -92,8 +73,8 @@ void g4x_dp_set_clock(struct intel_encoder *encoder,
if (divisor && count) {
for (i = 0; i < count; i++) {
if (pipe_config->port_clock == divisor[i].clock) {
pipe_config->dpll = divisor[i].dpll;
if (pipe_config->port_clock == divisor[i].dot) {
pipe_config->dpll = divisor[i];
pipe_config->clock_set = true;
break;
}
@ -192,7 +173,7 @@ static void assert_dp_port(struct intel_dp *intel_dp, bool state)
I915_STATE_WARN(cur_state != state,
"[ENCODER:%d:%s] state assertion failure (expected %s, current %s)\n",
dig_port->base.base.base.id, dig_port->base.base.name,
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
#define assert_dp_port_disabled(d) assert_dp_port((d), false)
@ -202,7 +183,7 @@ static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
I915_STATE_WARN(cur_state != state,
"eDP PLL state assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
@ -514,9 +495,7 @@ static void intel_disable_dp(struct intel_atomic_state *state,
intel_dp->link_trained = false;
if (old_crtc_state->has_audio)
intel_audio_codec_disable(encoder,
old_crtc_state, old_conn_state);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
/*
* Make sure the panel is off before trying to change the mode.
@ -677,9 +656,7 @@ static void intel_enable_dp(struct intel_atomic_state *state,
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
u32 dp_reg = intel_de_read(dev_priv, intel_dp->output_reg);
enum pipe pipe = crtc->pipe;
intel_wakeref_t wakeref;
if (drm_WARN_ON(&dev_priv->drm, dp_reg & DP_PORT_EN))
@ -713,11 +690,7 @@ static void intel_enable_dp(struct intel_atomic_state *state,
intel_dp_start_link_train(intel_dp, pipe_config);
intel_dp_stop_link_train(intel_dp, pipe_config);
if (pipe_config->has_audio) {
drm_dbg(&dev_priv->drm, "Enabling DP audio on pipe %c\n",
pipe_name(pipe));
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
static void g4x_enable_dp(struct intel_atomic_state *state,

View File

@ -143,19 +143,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
&pipe_config->infoframes.hdmi);
}
static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
drm_WARN_ON(&i915->drm, !pipe_config->has_hdmi_sink);
drm_dbg_kms(&i915->drm, "Enabling HDMI audio on pipe %c\n",
pipe_name(crtc->pipe));
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
static void g4x_enable_hdmi(struct intel_atomic_state *state,
struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config,
@ -175,8 +162,9 @@ static void g4x_enable_hdmi(struct intel_atomic_state *state,
intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp);
intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg);
if (pipe_config->has_audio)
intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio &&
!pipe_config->has_hdmi_sink);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
static void ibx_enable_hdmi(struct intel_atomic_state *state,
@ -227,8 +215,9 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state,
intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg);
}
if (pipe_config->has_audio)
intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio &&
!pipe_config->has_hdmi_sink);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
static void cpt_enable_hdmi(struct intel_atomic_state *state,
@ -281,8 +270,9 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state,
intel_de_read(dev_priv, TRANS_CHICKEN1(pipe)) & ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
}
if (pipe_config->has_audio)
intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio &&
!pipe_config->has_hdmi_sink);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
static void vlv_enable_hdmi(struct intel_atomic_state *state,
@ -356,9 +346,7 @@ static void g4x_disable_hdmi(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
if (old_crtc_state->has_audio)
intel_audio_codec_disable(encoder,
old_crtc_state, old_conn_state);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
intel_disable_hdmi(state, encoder, old_crtc_state, old_conn_state);
}
@ -368,9 +356,7 @@ static void pch_disable_hdmi(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
if (old_crtc_state->has_audio)
intel_audio_codec_disable(encoder,
old_crtc_state, old_conn_state);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
}
static void pch_post_disable_hdmi(struct intel_atomic_state *state,

View File

@ -418,9 +418,6 @@ static void i9xx_plane_update_noarm(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
plane_state->view.color_plane[0].mapping_stride);
@ -441,8 +438,6 @@ static void i9xx_plane_update_noarm(struct intel_plane *plane,
intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1));
}
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void i9xx_plane_update_arm(struct intel_plane *plane,
@ -454,7 +449,6 @@ static void i9xx_plane_update_arm(struct intel_plane *plane,
int x = plane_state->view.color_plane[0].x;
int y = plane_state->view.color_plane[0].y;
u32 dspcntr, dspaddr_offset, linear_offset;
unsigned long irqflags;
dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
@ -465,8 +459,6 @@ static void i9xx_plane_update_arm(struct intel_plane *plane,
else
dspaddr_offset = linear_offset;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
@ -496,14 +488,13 @@ static void i9xx_plane_update_arm(struct intel_plane *plane,
* the control register just before the surface register.
*/
intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
if (DISPLAY_VER(dev_priv) >= 4)
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
else
intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void i830_plane_update_arm(struct intel_plane *plane,
@ -525,7 +516,6 @@ static void i9xx_plane_disable_arm(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
u32 dspcntr;
/*
@ -540,15 +530,12 @@ static void i9xx_plane_disable_arm(struct intel_plane *plane,
*/
dspcntr = i9xx_plane_ctl_crtc(crtc_state);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
if (DISPLAY_VER(dev_priv) >= 4)
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
else
intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -561,16 +548,14 @@ g4x_primary_async_flip(struct intel_plane *plane,
u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
u32 dspaddr_offset = plane_state->view.color_plane[0].offset;
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
if (async_flip)
dspcntr |= DISP_ASYNC_FLIP;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -582,12 +567,9 @@ vlv_primary_async_flip(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
u32 dspaddr_offset = plane_state->view.color_plane[0].offset;
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DSPADDR_VLV(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void

View File

@ -1967,6 +1967,8 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi)
static void icl_dsi_add_properties(struct intel_connector *connector)
{
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
u32 allowed_scalers;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) |
@ -1979,9 +1981,9 @@ static void icl_dsi_add_properties(struct intel_connector *connector)
connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
drm_connector_set_panel_orientation_with_quirk(&connector->base,
intel_dsi_get_panel_orientation(connector),
connector->panel.fixed_mode->hdisplay,
connector->panel.fixed_mode->vdisplay);
intel_dsi_get_panel_orientation(connector),
fixed_mode->hdisplay,
fixed_mode->vdisplay);
}
void icl_dsi_init(struct drm_i915_private *dev_priv)
@ -1991,7 +1993,6 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
struct intel_encoder *encoder;
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_display_mode *fixed_mode;
enum port port;
if (!intel_bios_is_dsi_present(dev_priv, &port))
@ -2048,15 +2049,16 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
intel_connector_attach_encoder(intel_connector, encoder);
mutex_lock(&dev->mode_config.mutex);
fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
mutex_unlock(&dev->mode_config.mutex);
if (!fixed_mode) {
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
drm_err(&dev_priv->drm, "DSI fixed mode info missing\n");
goto err;
}
intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
intel_panel_init(intel_connector);
intel_backlight_setup(intel_connector, INVALID_PIPE);
if (dev_priv->vbt.dsi.config->dual_link)

View File

@ -181,29 +181,67 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
}
unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
const struct intel_plane_state *plane_state,
int color_plane)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int cpp;
unsigned int pixel_rate;
if (!plane_state->uapi.visible)
return 0;
pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
return intel_plane_pixel_rate(crtc_state, plane_state) *
fb->format->cpp[color_plane];
}
cpp = fb->format->cpp[0];
static bool
use_min_ddb(const struct intel_crtc_state *crtc_state,
struct intel_plane *plane)
{
struct drm_i915_private *i915 = to_i915(plane->base.dev);
return DISPLAY_VER(i915) >= 13 &&
crtc_state->uapi.async_flip &&
plane->async_flip;
}
static unsigned int
intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
int color_plane)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int width, height;
if (plane->id == PLANE_CURSOR)
return 0;
if (!plane_state->uapi.visible)
return 0;
/*
* Based on HSD#:1408715493
* NV12 cpp == 4, P010 cpp == 8
*
* FIXME what is the logic behind this?
* We calculate extra ddb based on ratio plane rate/total data rate
* in case, in some cases we should not allocate extra ddb for the plane,
* so do not count its data rate, if this is the case.
*/
if (fb->format->is_yuv && fb->format->num_planes > 1)
cpp *= 4;
if (use_min_ddb(crtc_state, plane))
return 0;
return pixel_rate * cpp;
/*
* Src coordinates are already rotated by 270 degrees for
* the 90/270 degree plane rotation cases (to match the
* GTT mapping), hence no need to account for rotation here.
*/
width = drm_rect_width(&plane_state->uapi.src) >> 16;
height = drm_rect_height(&plane_state->uapi.src) >> 16;
/* UV plane does 1/2 pixel sub-sampling */
if (color_plane == 1) {
width /= 2;
height /= 2;
}
return width * height * fb->format->cpp[color_plane];
}
int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
@ -326,6 +364,9 @@ void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
crtc_state->nv12_planes &= ~BIT(plane->id);
crtc_state->c8_planes &= ~BIT(plane->id);
crtc_state->data_rate[plane->id] = 0;
crtc_state->data_rate_y[plane->id] = 0;
crtc_state->rel_data_rate[plane->id] = 0;
crtc_state->rel_data_rate_y[plane->id] = 0;
crtc_state->min_cdclk[plane->id] = 0;
plane_state->uapi.visible = false;
@ -551,8 +592,27 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
if (new_plane_state->uapi.visible || old_plane_state->uapi.visible)
new_crtc_state->update_planes |= BIT(plane->id);
new_crtc_state->data_rate[plane->id] =
intel_plane_data_rate(new_crtc_state, new_plane_state);
if (new_plane_state->uapi.visible &&
intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) {
new_crtc_state->data_rate_y[plane->id] =
intel_plane_data_rate(new_crtc_state, new_plane_state, 0);
new_crtc_state->data_rate[plane->id] =
intel_plane_data_rate(new_crtc_state, new_plane_state, 1);
new_crtc_state->rel_data_rate_y[plane->id] =
intel_plane_relative_data_rate(new_crtc_state,
new_plane_state, 0);
new_crtc_state->rel_data_rate[plane->id] =
intel_plane_relative_data_rate(new_crtc_state,
new_plane_state, 1);
} else if (new_plane_state->uapi.visible) {
new_crtc_state->data_rate[plane->id] =
intel_plane_data_rate(new_crtc_state, new_plane_state, 0);
new_crtc_state->rel_data_rate[plane->id] =
intel_plane_relative_data_rate(new_crtc_state,
new_plane_state, 0);
}
return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
old_plane_state, new_plane_state);
@ -616,8 +676,8 @@ int intel_plane_atomic_check(struct intel_atomic_state *state,
static struct intel_plane *
skl_next_plane_to_commit(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct skl_ddb_entry entries_y[I915_MAX_PLANES],
struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
struct skl_ddb_entry ddb[I915_MAX_PLANES],
struct skl_ddb_entry ddb_y[I915_MAX_PLANES],
unsigned int *update_mask)
{
struct intel_crtc_state *crtc_state =
@ -636,17 +696,15 @@ skl_next_plane_to_commit(struct intel_atomic_state *state,
!(*update_mask & BIT(plane_id)))
continue;
if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
entries_y,
I915_MAX_PLANES, plane_id) ||
skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
entries_uv,
I915_MAX_PLANES, plane_id))
if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb[plane_id],
ddb, I915_MAX_PLANES, plane_id) ||
skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
ddb_y, I915_MAX_PLANES, plane_id))
continue;
*update_mask &= ~BIT(plane_id);
entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
ddb[plane_id] = crtc_state->wm.skl.plane_ddb[plane_id];
ddb_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
return plane;
}
@ -728,19 +786,17 @@ static void skl_crtc_planes_update_arm(struct intel_atomic_state *state,
intel_atomic_get_old_crtc_state(state, crtc);
struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
struct skl_ddb_entry entries_y[I915_MAX_PLANES];
struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
struct skl_ddb_entry ddb[I915_MAX_PLANES];
struct skl_ddb_entry ddb_y[I915_MAX_PLANES];
u32 update_mask = new_crtc_state->update_planes;
struct intel_plane *plane;
memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
memcpy(ddb, old_crtc_state->wm.skl.plane_ddb,
sizeof(old_crtc_state->wm.skl.plane_ddb));
memcpy(ddb_y, old_crtc_state->wm.skl.plane_ddb_y,
sizeof(old_crtc_state->wm.skl.plane_ddb_y));
memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
while ((plane = skl_next_plane_to_commit(state, crtc,
entries_y, entries_uv,
&update_mask))) {
while ((plane = skl_next_plane_to_commit(state, crtc, ddb, ddb_y, &update_mask))) {
struct intel_plane_state *new_plane_state =
intel_atomic_get_new_plane_state(state, plane);
@ -802,8 +858,8 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
struct drm_framebuffer *fb = plane_state->hw.fb;
struct drm_rect *src = &plane_state->uapi.src;
struct drm_rect *dst = &plane_state->uapi.dst;
const struct drm_rect *clip = &crtc_state->pipe_src;
unsigned int rotation = plane_state->hw.rotation;
struct drm_rect clip = {};
int hscale, vscale;
if (!fb) {
@ -823,31 +879,25 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
return -ERANGE;
}
if (crtc_state->hw.enable) {
clip.x2 = crtc_state->pipe_src_w;
clip.y2 = crtc_state->pipe_src_h;
}
/* right side of the image is on the slave crtc, adjust dst to match */
if (intel_crtc_is_bigjoiner_slave(crtc_state))
drm_rect_translate(dst, -crtc_state->pipe_src_w, 0);
/*
* FIXME: This might need further adjustment for seamless scaling
* with phase information, for the 2p2 and 2p1 scenarios.
*/
plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, &clip);
plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, clip);
drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
if (!can_position && plane_state->uapi.visible &&
!drm_rect_equals(dst, &clip)) {
!drm_rect_equals(dst, clip)) {
drm_dbg_kms(&i915->drm, "Plane must cover entire CRTC\n");
drm_rect_debug_print("dst: ", dst, false);
drm_rect_debug_print("clip: ", &clip, false);
drm_rect_debug_print("clip: ", clip, false);
return -EINVAL;
}
/* final plane coordinates will be relative to the plane's pipe */
drm_rect_translate(dst, -clip->x1, -clip->y1);
return 0;
}

View File

@ -25,7 +25,8 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
const struct intel_plane_state *plane_state,
int color_plane);
void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
const struct intel_plane_state *from_plane_state,
struct intel_crtc *crtc);

View File

@ -337,8 +337,6 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
u32 eldv, tmp;
drm_dbg_kms(&dev_priv->drm, "Disable audio codec\n");
tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID);
if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL)
eldv = G4X_ELDV_DEVCL_DEVBLC;
@ -362,9 +360,6 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
u32 tmp;
int len, i;
drm_dbg_kms(&dev_priv->drm, "Enable audio codec, %u bytes ELD\n",
drm_eld_size(eld));
tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID);
if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL)
eldv = G4X_ELDV_DEVCL_DEVBLC;
@ -383,7 +378,6 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp);
len = min(drm_eld_size(eld) / 4, len);
drm_dbg(&dev_priv->drm, "ELD size %d\n", len);
for (i = 0; i < len; i++)
intel_de_write(dev_priv, G4X_HDMIW_HDMIEDID,
*((const u32 *)eld + i));
@ -501,9 +495,6 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder,
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
u32 tmp;
drm_dbg_kms(&dev_priv->drm, "Disable audio codec on transcoder %s\n",
transcoder_name(cpu_transcoder));
mutex_lock(&dev_priv->audio.mutex);
/* Disable timestamps */
@ -647,10 +638,6 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
u32 tmp;
int len, i;
drm_dbg_kms(&dev_priv->drm,
"Enable audio codec on transcoder %s, %u bytes ELD\n",
transcoder_name(cpu_transcoder), drm_eld_size(eld));
mutex_lock(&dev_priv->audio.mutex);
/* Enable Audio WA for 4k DSC usecases */
@ -703,11 +690,6 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder,
u32 tmp, eldv;
i915_reg_t aud_config, aud_cntrl_st2;
drm_dbg_kms(&dev_priv->drm,
"Disable audio codec on [ENCODER:%d:%s], pipe %c\n",
encoder->base.base.id, encoder->base.name,
pipe_name(pipe));
if (drm_WARN_ON(&dev_priv->drm, port == PORT_A))
return;
@ -754,11 +736,6 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder,
int len, i;
i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
drm_dbg_kms(&dev_priv->drm,
"Enable audio codec on [ENCODER:%d:%s], pipe %c, %u bytes ELD\n",
encoder->base.base.id, encoder->base.name,
pipe_name(pipe), drm_eld_size(eld));
if (drm_WARN_ON(&dev_priv->drm, port == PORT_A))
return;
@ -844,18 +821,20 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
if (!crtc_state->has_audio)
return;
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n",
connector->base.id, connector->name,
encoder->base.base.id, encoder->base.name,
pipe, drm_eld_size(connector->eld));
/* FIXME precompute the ELD in .compute_config() */
if (!connector->eld[0])
drm_dbg_kms(&dev_priv->drm,
"Bogus ELD on [CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
drm_dbg(&dev_priv->drm, "ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
connector->base.id,
connector->name,
encoder->base.base.id,
encoder->base.name);
connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
if (dev_priv->audio.funcs)
@ -900,9 +879,17 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct i915_audio_component *acomp = dev_priv->audio.component;
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_connector *connector = old_conn_state->connector;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
if (!old_crtc_state->has_audio)
return;
drm_dbg_kms(&dev_priv->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);
if (dev_priv->audio.funcs)
dev_priv->audio.funcs->audio_codec_disable(encoder,
old_crtc_state,

View File

@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/pwm.h>
#include <linux/string_helpers.h>
#include "intel_backlight.h"
#include "intel_connector.h"
@ -1633,7 +1634,7 @@ int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
drm_dbg_kms(&dev_priv->drm,
"Connector %s backlight initialized, %s, brightness %u/%u\n",
connector->base.name,
enableddisabled(panel->backlight.enabled),
str_enabled_disabled(panel->backlight.enabled),
panel->backlight.level, panel->backlight.max);
return 0;

View File

@ -88,7 +88,7 @@ static u32 get_blocksize(const void *block_data)
}
static const void *
find_section(const void *_bdb, enum bdb_block_id section_id)
find_raw_section(const void *_bdb, enum bdb_block_id section_id)
{
const struct bdb_header *bdb = _bdb;
const u8 *base = _bdb;
@ -118,6 +118,250 @@ find_section(const void *_bdb, enum bdb_block_id section_id)
return NULL;
}
/*
* Offset from the start of BDB to the start of the
* block data (just past the block header).
*/
static u32 block_offset(const void *bdb, enum bdb_block_id section_id)
{
const void *block;
block = find_raw_section(bdb, section_id);
if (!block)
return 0;
return block - bdb;
}
/* size of the block excluding the header */
static u32 block_size(const void *bdb, enum bdb_block_id section_id)
{
const void *block;
block = find_raw_section(bdb, section_id);
if (!block)
return 0;
return get_blocksize(block);
}
struct bdb_block_entry {
struct list_head node;
enum bdb_block_id section_id;
u8 data[];
};
static const void *
find_section(struct drm_i915_private *i915,
enum bdb_block_id section_id)
{
struct bdb_block_entry *entry;
list_for_each_entry(entry, &i915->vbt.bdb_blocks, node) {
if (entry->section_id == section_id)
return entry->data + 3;
}
return NULL;
}
static const struct {
enum bdb_block_id section_id;
size_t min_size;
} bdb_blocks[] = {
{ .section_id = BDB_GENERAL_FEATURES,
.min_size = sizeof(struct bdb_general_features), },
{ .section_id = BDB_GENERAL_DEFINITIONS,
.min_size = sizeof(struct bdb_general_definitions), },
{ .section_id = BDB_PSR,
.min_size = sizeof(struct bdb_psr), },
{ .section_id = BDB_DRIVER_FEATURES,
.min_size = sizeof(struct bdb_driver_features), },
{ .section_id = BDB_SDVO_LVDS_OPTIONS,
.min_size = sizeof(struct bdb_sdvo_lvds_options), },
{ .section_id = BDB_SDVO_PANEL_DTDS,
.min_size = sizeof(struct bdb_sdvo_panel_dtds), },
{ .section_id = BDB_EDP,
.min_size = sizeof(struct bdb_edp), },
{ .section_id = BDB_LVDS_OPTIONS,
.min_size = sizeof(struct bdb_lvds_options), },
{ .section_id = BDB_LVDS_LFP_DATA_PTRS,
.min_size = sizeof(struct bdb_lvds_lfp_data_ptrs), },
{ .section_id = BDB_LVDS_LFP_DATA,
.min_size = sizeof(struct bdb_lvds_lfp_data), },
{ .section_id = BDB_LVDS_BACKLIGHT,
.min_size = sizeof(struct bdb_lfp_backlight_data), },
{ .section_id = BDB_LFP_POWER,
.min_size = sizeof(struct bdb_lfp_power), },
{ .section_id = BDB_MIPI_CONFIG,
.min_size = sizeof(struct bdb_mipi_config), },
{ .section_id = BDB_MIPI_SEQUENCE,
.min_size = sizeof(struct bdb_mipi_sequence) },
{ .section_id = BDB_COMPRESSION_PARAMETERS,
.min_size = sizeof(struct bdb_compression_parameters), },
{ .section_id = BDB_GENERIC_DTD,
.min_size = sizeof(struct bdb_generic_dtd), },
};
static bool validate_lfp_data_ptrs(const void *bdb,
const struct bdb_lvds_lfp_data_ptrs *ptrs)
{
int fp_timing_size, dvo_timing_size, panel_pnp_id_size, panel_name_size;
int data_block_size, lfp_data_size;
int i;
data_block_size = block_size(bdb, BDB_LVDS_LFP_DATA);
if (data_block_size == 0)
return false;
/* always 3 indicating the presence of fp_timing+dvo_timing+panel_pnp_id */
if (ptrs->lvds_entries != 3)
return false;
fp_timing_size = ptrs->ptr[0].fp_timing.table_size;
dvo_timing_size = ptrs->ptr[0].dvo_timing.table_size;
panel_pnp_id_size = ptrs->ptr[0].panel_pnp_id.table_size;
panel_name_size = ptrs->panel_name.table_size;
/* fp_timing has variable size */
if (fp_timing_size < 32 ||
dvo_timing_size != sizeof(struct lvds_dvo_timing) ||
panel_pnp_id_size != sizeof(struct lvds_pnp_id))
return false;
/* panel_name is not present in old VBTs */
if (panel_name_size != 0 &&
panel_name_size != sizeof(struct lvds_lfp_panel_name))
return false;
lfp_data_size = ptrs->ptr[1].fp_timing.offset - ptrs->ptr[0].fp_timing.offset;
if (16 * lfp_data_size > data_block_size)
return false;
/*
* Except for vlv/chv machines all real VBTs seem to have 6
* unaccounted bytes in the fp_timing table. And it doesn't
* appear to be a really intentional hole as the fp_timing
* 0xffff terminator is always within those 6 missing bytes.
*/
if (fp_timing_size + dvo_timing_size + panel_pnp_id_size != lfp_data_size &&
fp_timing_size + 6 + dvo_timing_size + panel_pnp_id_size != lfp_data_size)
return false;
if (ptrs->ptr[0].fp_timing.offset + fp_timing_size > ptrs->ptr[0].dvo_timing.offset ||
ptrs->ptr[0].dvo_timing.offset + dvo_timing_size != ptrs->ptr[0].panel_pnp_id.offset ||
ptrs->ptr[0].panel_pnp_id.offset + panel_pnp_id_size != lfp_data_size)
return false;
/* make sure the table entries have uniform size */
for (i = 1; i < 16; i++) {
if (ptrs->ptr[i].fp_timing.table_size != fp_timing_size ||
ptrs->ptr[i].dvo_timing.table_size != dvo_timing_size ||
ptrs->ptr[i].panel_pnp_id.table_size != panel_pnp_id_size)
return false;
if (ptrs->ptr[i].fp_timing.offset - ptrs->ptr[i-1].fp_timing.offset != lfp_data_size ||
ptrs->ptr[i].dvo_timing.offset - ptrs->ptr[i-1].dvo_timing.offset != lfp_data_size ||
ptrs->ptr[i].panel_pnp_id.offset - ptrs->ptr[i-1].panel_pnp_id.offset != lfp_data_size)
return false;
}
/* make sure the tables fit inside the data block */
for (i = 0; i < 16; i++) {
if (ptrs->ptr[i].fp_timing.offset + fp_timing_size > data_block_size ||
ptrs->ptr[i].dvo_timing.offset + dvo_timing_size > data_block_size ||
ptrs->ptr[i].panel_pnp_id.offset + panel_pnp_id_size > data_block_size)
return false;
}
if (ptrs->panel_name.offset + 16 * panel_name_size > data_block_size)
return false;
return true;
}
/* make the data table offsets relative to the data block */
static bool fixup_lfp_data_ptrs(const void *bdb, void *ptrs_block)
{
struct bdb_lvds_lfp_data_ptrs *ptrs = ptrs_block;
u32 offset;
int i;
offset = block_offset(bdb, BDB_LVDS_LFP_DATA);
for (i = 0; i < 16; i++) {
if (ptrs->ptr[i].fp_timing.offset < offset ||
ptrs->ptr[i].dvo_timing.offset < offset ||
ptrs->ptr[i].panel_pnp_id.offset < offset)
return false;
ptrs->ptr[i].fp_timing.offset -= offset;
ptrs->ptr[i].dvo_timing.offset -= offset;
ptrs->ptr[i].panel_pnp_id.offset -= offset;
}
if (ptrs->panel_name.table_size) {
if (ptrs->panel_name.offset < offset)
return false;
ptrs->panel_name.offset -= offset;
}
return validate_lfp_data_ptrs(bdb, ptrs);
}
static void
init_bdb_block(struct drm_i915_private *i915,
const void *bdb, enum bdb_block_id section_id,
size_t min_size)
{
struct bdb_block_entry *entry;
const void *block;
size_t block_size;
block = find_raw_section(bdb, section_id);
if (!block)
return;
drm_WARN(&i915->drm, min_size == 0,
"Block %d min_size is zero\n", section_id);
block_size = get_blocksize(block);
entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3),
GFP_KERNEL);
if (!entry)
return;
entry->section_id = section_id;
memcpy(entry->data, block - 3, block_size + 3);
drm_dbg_kms(&i915->drm, "Found BDB block %d (size %zu, min size %zu)\n",
section_id, block_size, min_size);
if (section_id == BDB_LVDS_LFP_DATA_PTRS &&
!fixup_lfp_data_ptrs(bdb, entry->data + 3)) {
drm_err(&i915->drm, "VBT has malformed LFP data table pointers\n");
kfree(entry);
return;
}
list_add_tail(&entry->node, &i915->vbt.bdb_blocks);
}
static void init_bdb_blocks(struct drm_i915_private *i915,
const void *bdb)
{
int i;
for (i = 0; i < ARRAY_SIZE(bdb_blocks); i++) {
enum bdb_block_id section_id = bdb_blocks[i].section_id;
size_t min_size = bdb_blocks[i].min_size;
init_bdb_block(i915, bdb, section_id, min_size);
}
}
static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
const struct lvds_dvo_timing *dvo_timing)
@ -169,60 +413,31 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
}
static const struct lvds_dvo_timing *
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs,
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *data,
const struct bdb_lvds_lfp_data_ptrs *ptrs,
int index)
{
/*
* the size of fp_timing varies on the different platform.
* So calculate the DVO timing relative offset in LVDS data
* entry to get the DVO timing entry
*/
int lfp_data_size =
lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
int dvo_timing_offset =
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index;
return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
return (const void *)data + ptrs->ptr[index].dvo_timing.offset;
}
/* get lvds_fp_timing entry
* this function may return NULL if the corresponding entry is invalid
*/
static const struct lvds_fp_timing *
get_lvds_fp_timing(const struct bdb_header *bdb,
const struct bdb_lvds_lfp_data *data,
get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data,
const struct bdb_lvds_lfp_data_ptrs *ptrs,
int index)
{
size_t data_ofs = (const u8 *)data - (const u8 *)bdb;
u16 data_size = ((const u16 *)data)[-1]; /* stored in header */
size_t ofs;
if (index >= ARRAY_SIZE(ptrs->ptr))
return NULL;
ofs = ptrs->ptr[index].fp_timing_offset;
if (ofs < data_ofs ||
ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size)
return NULL;
return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs);
return (const void *)data + ptrs->ptr[index].fp_timing.offset;
}
/* Parse general panel options */
static void
parse_panel_options(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_panel_options(struct drm_i915_private *i915)
{
const struct bdb_lvds_options *lvds_options;
int panel_type;
int drrs_mode;
int ret;
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
if (!lvds_options)
return;
@ -257,16 +472,16 @@ parse_panel_options(struct drm_i915_private *i915,
*/
switch (drrs_mode) {
case 0:
i915->vbt.drrs_type = STATIC_DRRS_SUPPORT;
i915->vbt.drrs_type = DRRS_TYPE_STATIC;
drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n");
break;
case 2:
i915->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT;
i915->vbt.drrs_type = DRRS_TYPE_SEAMLESS;
drm_dbg_kms(&i915->drm,
"DRRS supported mode is seamless\n");
break;
default:
i915->vbt.drrs_type = DRRS_NOT_SUPPORTED;
i915->vbt.drrs_type = DRRS_TYPE_NONE;
drm_dbg_kms(&i915->drm,
"DRRS not supported (VBT input)\n");
break;
@ -275,8 +490,7 @@ parse_panel_options(struct drm_i915_private *i915,
/* Try to find integrated panel timing data */
static void
parse_lfp_panel_dtd(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_lfp_panel_dtd(struct drm_i915_private *i915)
{
const struct bdb_lvds_lfp_data *lvds_lfp_data;
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
@ -285,11 +499,11 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915,
struct drm_display_mode *panel_fixed_mode;
int panel_type = i915->vbt.panel_type;
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
lvds_lfp_data = find_section(i915, BDB_LVDS_LFP_DATA);
if (!lvds_lfp_data)
return;
lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
lvds_lfp_data_ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
if (!lvds_lfp_data_ptrs)
return;
@ -306,34 +520,32 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915,
i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
drm_dbg_kms(&i915->drm,
"Found panel mode in BIOS VBT legacy lfp table:\n");
drm_mode_debug_printmodeline(panel_fixed_mode);
"Found panel mode in BIOS VBT legacy lfp table: " DRM_MODE_FMT "\n",
DRM_MODE_ARG(panel_fixed_mode));
fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data,
fp_timing = get_lvds_fp_timing(lvds_lfp_data,
lvds_lfp_data_ptrs,
panel_type);
if (fp_timing) {
/* check the resolution, just to be sure */
if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
fp_timing->y_res == panel_fixed_mode->vdisplay) {
i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
drm_dbg_kms(&i915->drm,
"VBT initial LVDS value %x\n",
i915->vbt.bios_lvds_val);
}
/* check the resolution, just to be sure */
if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
fp_timing->y_res == panel_fixed_mode->vdisplay) {
i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
drm_dbg_kms(&i915->drm,
"VBT initial LVDS value %x\n",
i915->vbt.bios_lvds_val);
}
}
static void
parse_generic_dtd(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_generic_dtd(struct drm_i915_private *i915)
{
const struct bdb_generic_dtd *generic_dtd;
const struct generic_dtd_entry *dtd;
struct drm_display_mode *panel_fixed_mode;
int num_dtd;
generic_dtd = find_section(bdb, BDB_GENERIC_DTD);
generic_dtd = find_section(i915, BDB_GENERIC_DTD);
if (!generic_dtd)
return;
@ -397,15 +609,14 @@ parse_generic_dtd(struct drm_i915_private *i915,
panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
drm_dbg_kms(&i915->drm,
"Found panel mode in BIOS VBT generic dtd table:\n");
drm_mode_debug_printmodeline(panel_fixed_mode);
"Found panel mode in BIOS VBT generic dtd table: " DRM_MODE_FMT "\n",
DRM_MODE_ARG(panel_fixed_mode));
i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
}
static void
parse_panel_dtd(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_panel_dtd(struct drm_i915_private *i915)
{
/*
* Older VBTs provided provided DTD information for internal displays
@ -415,22 +626,21 @@ parse_panel_dtd(struct drm_i915_private *i915,
* try the new generic DTD block first on VBT >= 229, but still fall
* back to trying the old LFP block if that fails.
*/
if (bdb->version >= 229)
parse_generic_dtd(i915, bdb);
if (i915->vbt.version >= 229)
parse_generic_dtd(i915);
if (!i915->vbt.lfp_lvds_vbt_mode)
parse_lfp_panel_dtd(i915, bdb);
parse_lfp_panel_dtd(i915);
}
static void
parse_lfp_backlight(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_lfp_backlight(struct drm_i915_private *i915)
{
const struct bdb_lfp_backlight_data *backlight_data;
const struct lfp_backlight_data_entry *entry;
int panel_type = i915->vbt.panel_type;
u16 level;
backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT);
if (!backlight_data)
return;
@ -452,12 +662,12 @@ parse_lfp_backlight(struct drm_i915_private *i915,
}
i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI;
if (bdb->version >= 191) {
if (i915->vbt.version >= 191) {
size_t exp_size;
if (bdb->version >= 236)
if (i915->vbt.version >= 236)
exp_size = sizeof(struct bdb_lfp_backlight_data);
else if (bdb->version >= 234)
else if (i915->vbt.version >= 234)
exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_234;
else
exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_191;
@ -474,14 +684,14 @@ parse_lfp_backlight(struct drm_i915_private *i915,
i915->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
i915->vbt.backlight.active_low_pwm = entry->active_low_pwm;
if (bdb->version >= 234) {
if (i915->vbt.version >= 234) {
u16 min_level;
bool scale;
level = backlight_data->brightness_level[panel_type].level;
min_level = backlight_data->brightness_min_level[panel_type].level;
if (bdb->version >= 236)
if (i915->vbt.version >= 236)
scale = backlight_data->brightness_precision_bits[panel_type] == 16;
else
scale = level > 255;
@ -514,8 +724,7 @@ parse_lfp_backlight(struct drm_i915_private *i915,
/* Try to find sdvo panel data */
static void
parse_sdvo_panel_data(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_sdvo_panel_data(struct drm_i915_private *i915)
{
const struct bdb_sdvo_panel_dtds *dtds;
struct drm_display_mode *panel_fixed_mode;
@ -531,14 +740,14 @@ parse_sdvo_panel_data(struct drm_i915_private *i915,
if (index == -1) {
const struct bdb_sdvo_lvds_options *sdvo_lvds_options;
sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
sdvo_lvds_options = find_section(i915, BDB_SDVO_LVDS_OPTIONS);
if (!sdvo_lvds_options)
return;
index = sdvo_lvds_options->panel_type;
}
dtds = find_section(bdb, BDB_SDVO_PANEL_DTDS);
dtds = find_section(i915, BDB_SDVO_PANEL_DTDS);
if (!dtds)
return;
@ -551,8 +760,8 @@ parse_sdvo_panel_data(struct drm_i915_private *i915,
i915->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode;
drm_dbg_kms(&i915->drm,
"Found SDVO panel mode in BIOS VBT tables:\n");
drm_mode_debug_printmodeline(panel_fixed_mode);
"Found SDVO panel mode in BIOS VBT tables: " DRM_MODE_FMT "\n",
DRM_MODE_ARG(panel_fixed_mode));
}
static int intel_bios_ssc_frequency(struct drm_i915_private *i915,
@ -570,18 +779,17 @@ static int intel_bios_ssc_frequency(struct drm_i915_private *i915,
}
static void
parse_general_features(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_general_features(struct drm_i915_private *i915)
{
const struct bdb_general_features *general;
general = find_section(bdb, BDB_GENERAL_FEATURES);
general = find_section(i915, BDB_GENERAL_FEATURES);
if (!general)
return;
i915->vbt.int_tv_support = general->int_tv_support;
/* int_crt_support can't be trusted on earlier platforms */
if (bdb->version >= 155 &&
if (i915->vbt.version >= 155 &&
(HAS_DDI(i915) || IS_VALLEYVIEW(i915)))
i915->vbt.int_crt_support = general->int_crt_support;
i915->vbt.lvds_use_ssc = general->enable_ssc;
@ -589,7 +797,7 @@ parse_general_features(struct drm_i915_private *i915,
intel_bios_ssc_frequency(i915, general->ssc_freq);
i915->vbt.display_clock_mode = general->display_clock_mode;
i915->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
if (bdb->version >= 181) {
if (i915->vbt.version >= 181) {
i915->vbt.orientation = general->rotate_180 ?
DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP :
DRM_MODE_PANEL_ORIENTATION_NORMAL;
@ -597,7 +805,7 @@ parse_general_features(struct drm_i915_private *i915,
i915->vbt.orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
}
if (bdb->version >= 249 && general->afc_startup_config) {
if (i915->vbt.version >= 249 && general->afc_startup_config) {
i915->vbt.override_afc_startup = true;
i915->vbt.override_afc_startup_val = general->afc_startup_config == 0x1 ? 0x0 : 0x7;
}
@ -695,12 +903,11 @@ parse_sdvo_device_mapping(struct drm_i915_private *i915)
}
static void
parse_driver_features(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_driver_features(struct drm_i915_private *i915)
{
const struct bdb_driver_features *driver;
driver = find_section(bdb, BDB_DRIVER_FEATURES);
driver = find_section(i915, BDB_DRIVER_FEATURES);
if (!driver)
return;
@ -724,13 +931,13 @@ parse_driver_features(struct drm_i915_private *i915,
* in the wild with the bits correctly populated. Version
* 108 (on i85x) does not have the bits correctly populated.
*/
if (bdb->version >= 134 &&
if (i915->vbt.version >= 134 &&
driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS &&
driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS)
i915->vbt.int_lvds_support = 0;
}
if (bdb->version < 228) {
if (i915->vbt.version < 228) {
drm_dbg_kms(&i915->drm, "DRRS State Enabled:%d\n",
driver->drrs_enabled);
/*
@ -740,23 +947,22 @@ parse_driver_features(struct drm_i915_private *i915,
* driver->drrs_enabled=false
*/
if (!driver->drrs_enabled)
i915->vbt.drrs_type = DRRS_NOT_SUPPORTED;
i915->vbt.drrs_type = DRRS_TYPE_NONE;
i915->vbt.psr.enable = driver->psr_enabled;
}
}
static void
parse_power_conservation_features(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_power_conservation_features(struct drm_i915_private *i915)
{
const struct bdb_lfp_power *power;
u8 panel_type = i915->vbt.panel_type;
if (bdb->version < 228)
if (i915->vbt.version < 228)
return;
power = find_section(bdb, BDB_LFP_POWER);
power = find_section(i915, BDB_LFP_POWER);
if (!power)
return;
@ -769,21 +975,21 @@ parse_power_conservation_features(struct drm_i915_private *i915,
* power->drrs & BIT(panel_type)=false
*/
if (!(power->drrs & BIT(panel_type)))
i915->vbt.drrs_type = DRRS_NOT_SUPPORTED;
i915->vbt.drrs_type = DRRS_TYPE_NONE;
if (bdb->version >= 232)
if (i915->vbt.version >= 232)
i915->vbt.edp.hobl = power->hobl & BIT(panel_type);
}
static void
parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb)
parse_edp(struct drm_i915_private *i915)
{
const struct bdb_edp *edp;
const struct edp_power_seq *edp_pps;
const struct edp_fast_link_params *edp_link_params;
int panel_type = i915->vbt.panel_type;
edp = find_section(bdb, BDB_EDP);
edp = find_section(i915, BDB_EDP);
if (!edp)
return;
@ -876,7 +1082,7 @@ parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb)
break;
}
if (bdb->version >= 173) {
if (i915->vbt.version >= 173) {
u8 vswing;
/* Don't read from VBT if module parameter has valid value*/
@ -888,16 +1094,19 @@ parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb)
i915->vbt.edp.low_vswing = vswing == 0;
}
}
i915->vbt.edp.drrs_msa_timing_delay =
(edp->sdrrs_msa_timing_delay >> (panel_type * 2)) & 3;
}
static void
parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb)
parse_psr(struct drm_i915_private *i915)
{
const struct bdb_psr *psr;
const struct psr_table *psr_table;
int panel_type = i915->vbt.panel_type;
psr = find_section(bdb, BDB_PSR);
psr = find_section(i915, BDB_PSR);
if (!psr) {
drm_dbg_kms(&i915->drm, "No PSR BDB found.\n");
return;
@ -916,7 +1125,7 @@ parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb)
* New psr options 0=500us, 1=100us, 2=2500us, 3=0us
* Old decimal value is wake up time in multiples of 100 us.
*/
if (bdb->version >= 205 &&
if (i915->vbt.version >= 205 &&
(DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) {
switch (psr_table->tp1_wakeup_time) {
case 0:
@ -962,7 +1171,7 @@ parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb)
i915->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100;
}
if (bdb->version >= 226) {
if (i915->vbt.version >= 226) {
u32 wakeup_time = psr->psr2_tp2_tp3_wakeup_time;
wakeup_time = (wakeup_time >> (2 * panel_type)) & 0x3;
@ -1031,8 +1240,7 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915,
}
static void
parse_mipi_config(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_mipi_config(struct drm_i915_private *i915)
{
const struct bdb_mipi_config *start;
const struct mipi_config *config;
@ -1055,7 +1263,7 @@ parse_mipi_config(struct drm_i915_private *i915,
/* Parse #52 for panel index used from panel_type already
* parsed
*/
start = find_section(bdb, BDB_MIPI_CONFIG);
start = find_section(i915, BDB_MIPI_CONFIG);
if (!start) {
drm_dbg_kms(&i915->drm, "No MIPI config BDB found");
return;
@ -1082,7 +1290,7 @@ parse_mipi_config(struct drm_i915_private *i915,
return;
}
parse_dsi_backlight_ports(i915, bdb->version, port);
parse_dsi_backlight_ports(i915, i915->vbt.version, port);
/* FIXME is the 90 vs. 270 correct? */
switch (config->rotation) {
@ -1351,8 +1559,7 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915)
}
static void
parse_mipi_sequence(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_mipi_sequence(struct drm_i915_private *i915)
{
int panel_type = i915->vbt.panel_type;
const struct bdb_mipi_sequence *sequence;
@ -1365,7 +1572,7 @@ parse_mipi_sequence(struct drm_i915_private *i915,
if (i915->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID)
return;
sequence = find_section(bdb, BDB_MIPI_SEQUENCE);
sequence = find_section(i915, BDB_MIPI_SEQUENCE);
if (!sequence) {
drm_dbg_kms(&i915->drm,
"No MIPI Sequence found, parsing complete\n");
@ -1436,8 +1643,7 @@ err:
}
static void
parse_compression_parameters(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_compression_parameters(struct drm_i915_private *i915)
{
const struct bdb_compression_parameters *params;
struct intel_bios_encoder_data *devdata;
@ -1445,10 +1651,10 @@ parse_compression_parameters(struct drm_i915_private *i915,
u16 block_size;
int index;
if (bdb->version < 198)
if (i915->vbt.version < 198)
return;
params = find_section(bdb, BDB_COMPRESSION_PARAMETERS);
params = find_section(i915, BDB_COMPRESSION_PARAMETERS);
if (params) {
/* Sanity checks */
if (params->entry_size != sizeof(params->data[0])) {
@ -1955,6 +2161,12 @@ static int _intel_bios_max_tmds_clock(const struct intel_bios_encoder_data *devd
fallthrough;
case HDMI_MAX_DATA_RATE_PLATFORM:
return 0;
case HDMI_MAX_DATA_RATE_594:
return 594000;
case HDMI_MAX_DATA_RATE_340:
return 340000;
case HDMI_MAX_DATA_RATE_300:
return 300000;
case HDMI_MAX_DATA_RATE_297:
return 297000;
case HDMI_MAX_DATA_RATE_165:
@ -2077,8 +2289,7 @@ static void parse_ddi_ports(struct drm_i915_private *i915)
}
static void
parse_general_definitions(struct drm_i915_private *i915,
const struct bdb_header *bdb)
parse_general_definitions(struct drm_i915_private *i915)
{
const struct bdb_general_definitions *defs;
struct intel_bios_encoder_data *devdata;
@ -2088,7 +2299,7 @@ parse_general_definitions(struct drm_i915_private *i915,
u16 block_size;
int bus_pin;
defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
defs = find_section(i915, BDB_GENERAL_DEFINITIONS);
if (!defs) {
drm_dbg_kms(&i915->drm,
"No general definition block is found, no devices defined.\n");
@ -2108,31 +2319,31 @@ parse_general_definitions(struct drm_i915_private *i915,
if (intel_gmbus_is_valid_pin(i915, bus_pin))
i915->vbt.crt_ddc_pin = bus_pin;
if (bdb->version < 106) {
if (i915->vbt.version < 106) {
expected_size = 22;
} else if (bdb->version < 111) {
} else if (i915->vbt.version < 111) {
expected_size = 27;
} else if (bdb->version < 195) {
} else if (i915->vbt.version < 195) {
expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE;
} else if (bdb->version == 195) {
} else if (i915->vbt.version == 195) {
expected_size = 37;
} else if (bdb->version <= 215) {
} else if (i915->vbt.version <= 215) {
expected_size = 38;
} else if (bdb->version <= 237) {
} else if (i915->vbt.version <= 237) {
expected_size = 39;
} else {
expected_size = sizeof(*child);
BUILD_BUG_ON(sizeof(*child) < 39);
drm_dbg(&i915->drm,
"Expected child device config size for VBT version %u not known; assuming %u\n",
bdb->version, expected_size);
i915->vbt.version, expected_size);
}
/* Flag an error for unexpected size, but continue anyway. */
if (defs->child_dev_size != expected_size)
drm_err(&i915->drm,
"Unexpected child device config size %u (expected %u for VBT version %u)\n",
defs->child_dev_size, expected_size, bdb->version);
defs->child_dev_size, expected_size, i915->vbt.version);
/* The legacy sized child device config is the minimum we need. */
if (defs->child_dev_size < LEGACY_CHILD_DEVICE_CONFIG_SIZE) {
@ -2457,6 +2668,7 @@ void intel_bios_init(struct drm_i915_private *i915)
const struct bdb_header *bdb;
INIT_LIST_HEAD(&i915->vbt.display_devices);
INIT_LIST_HEAD(&i915->vbt.bdb_blocks);
if (!HAS_DISPLAY(i915)) {
drm_dbg_kms(&i915->drm,
@ -2488,24 +2700,26 @@ void intel_bios_init(struct drm_i915_private *i915)
drm_dbg_kms(&i915->drm,
"VBT signature \"%.*s\", BDB version %d\n",
(int)sizeof(vbt->signature), vbt->signature, bdb->version);
(int)sizeof(vbt->signature), vbt->signature, i915->vbt.version);
init_bdb_blocks(i915, bdb);
/* Grab useful general definitions */
parse_general_features(i915, bdb);
parse_general_definitions(i915, bdb);
parse_panel_options(i915, bdb);
parse_panel_dtd(i915, bdb);
parse_lfp_backlight(i915, bdb);
parse_sdvo_panel_data(i915, bdb);
parse_driver_features(i915, bdb);
parse_power_conservation_features(i915, bdb);
parse_edp(i915, bdb);
parse_psr(i915, bdb);
parse_mipi_config(i915, bdb);
parse_mipi_sequence(i915, bdb);
parse_general_features(i915);
parse_general_definitions(i915);
parse_panel_options(i915);
parse_panel_dtd(i915);
parse_lfp_backlight(i915);
parse_sdvo_panel_data(i915);
parse_driver_features(i915);
parse_power_conservation_features(i915);
parse_edp(i915);
parse_psr(i915);
parse_mipi_config(i915);
parse_mipi_sequence(i915);
/* Depends on child device list */
parse_compression_parameters(i915, bdb);
parse_compression_parameters(i915);
out:
if (!vbt) {
@ -2527,14 +2741,20 @@ out:
*/
void intel_bios_driver_remove(struct drm_i915_private *i915)
{
struct intel_bios_encoder_data *devdata, *n;
struct intel_bios_encoder_data *devdata, *nd;
struct bdb_block_entry *entry, *ne;
list_for_each_entry_safe(devdata, n, &i915->vbt.display_devices, node) {
list_for_each_entry_safe(devdata, nd, &i915->vbt.display_devices, node) {
list_del(&devdata->node);
kfree(devdata->dsc);
kfree(devdata);
}
list_for_each_entry_safe(entry, ne, &i915->vbt.bdb_blocks, node) {
list_del(&entry->node);
kfree(entry);
}
kfree(i915->vbt.sdvo_lvds_vbt_mode);
i915->vbt.sdvo_lvds_vbt_mode = NULL;
kfree(i915->vbt.lfp_lvds_vbt_mode);

View File

@ -6,6 +6,7 @@
#include <drm/drm_atomic_state_helper.h>
#include "i915_reg.h"
#include "i915_utils.h"
#include "intel_atomic.h"
#include "intel_bw.h"
#include "intel_cdclk.h"
@ -124,8 +125,8 @@ int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
/* bspec says to keep retrying for at least 1 ms */
ret = skl_pcode_request(dev_priv, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG,
points_mask,
ICL_PCODE_POINTS_RESTRICTED_MASK,
ICL_PCODE_POINTS_RESTRICTED,
ICL_PCODE_REP_QGV_MASK | ADLS_PCODE_REP_PSF_MASK,
ICL_PCODE_REP_QGV_SAFE | ADLS_PCODE_REP_PSF_SAFE,
1);
if (ret < 0) {
@ -464,20 +465,25 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel
static void dg2_get_bw_info(struct drm_i915_private *i915)
{
struct intel_bw_info *bi = &i915->max_bw[0];
unsigned int deratedbw = IS_DG2_G11(i915) ? 38000 : 50000;
int num_groups = ARRAY_SIZE(i915->max_bw);
int i;
/*
* DG2 doesn't have SAGV or QGV points, just a constant max bandwidth
* that doesn't depend on the number of planes enabled. Create a
* single dummy QGV point to reflect that. DG2-G10 platforms have a
* constant 50 GB/s bandwidth, whereas DG2-G11 platforms have 38 GB/s.
* that doesn't depend on the number of planes enabled. So fill all the
* plane group with constant bw information for uniformity with other
* platforms. DG2-G10 platforms have a constant 50 GB/s bandwidth,
* whereas DG2-G11 platforms have 38 GB/s.
*/
bi->num_planes = 1;
bi->num_qgv_points = 1;
if (IS_DG2_G11(i915))
bi->deratedbw[0] = 38000;
else
bi->deratedbw[0] = 50000;
for (i = 0; i < num_groups; i++) {
struct intel_bw_info *bi = &i915->max_bw[i];
bi->num_planes = 1;
/* Need only one dummy QGV point per group */
bi->num_qgv_points = 1;
bi->deratedbw[0] = deratedbw;
}
i915->sagv_status = I915_SAGV_NOT_CONTROLLED;
}
@ -578,6 +584,7 @@ static unsigned int intel_bw_crtc_num_active_planes(const struct intel_crtc_stat
static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
unsigned int data_rate = 0;
enum plane_id plane_id;
@ -590,11 +597,26 @@ static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_
continue;
data_rate += crtc_state->data_rate[plane_id];
if (DISPLAY_VER(i915) < 11)
data_rate += crtc_state->data_rate_y[plane_id];
}
return data_rate;
}
/* "Maximum Pipe Read Bandwidth" */
static int intel_bw_crtc_min_cdclk(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
if (DISPLAY_VER(i915) < 12)
return 0;
return DIV_ROUND_UP_ULL(mul_u32_u32(intel_bw_crtc_data_rate(crtc_state), 10), 512);
}
void intel_bw_crtc_update(struct intel_bw_state *bw_state,
const struct intel_crtc_state *crtc_state)
{
@ -633,8 +655,8 @@ static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv,
for_each_pipe(dev_priv, pipe)
data_rate += bw_state->data_rate[pipe];
if (DISPLAY_VER(dev_priv) >= 13 && intel_vtd_active(dev_priv))
data_rate = data_rate * 105 / 100;
if (DISPLAY_VER(dev_priv) >= 13 && i915_vtd_active(dev_priv))
data_rate = DIV_ROUND_UP(data_rate * 105, 100);
return data_rate;
}
@ -674,6 +696,53 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state)
return to_intel_bw_state(bw_state);
}
static bool intel_bw_state_changed(struct drm_i915_private *i915,
const struct intel_bw_state *old_bw_state,
const struct intel_bw_state *new_bw_state)
{
enum pipe pipe;
for_each_pipe(i915, pipe) {
const struct intel_dbuf_bw *old_crtc_bw =
&old_bw_state->dbuf_bw[pipe];
const struct intel_dbuf_bw *new_crtc_bw =
&new_bw_state->dbuf_bw[pipe];
enum dbuf_slice slice;
for_each_dbuf_slice(i915, slice) {
if (old_crtc_bw->max_bw[slice] != new_crtc_bw->max_bw[slice] ||
old_crtc_bw->active_planes[slice] != new_crtc_bw->active_planes[slice])
return true;
}
if (old_bw_state->min_cdclk[pipe] != new_bw_state->min_cdclk[pipe])
return true;
}
return false;
}
static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state,
struct intel_crtc *crtc,
enum plane_id plane_id,
const struct skl_ddb_entry *ddb,
unsigned int data_rate)
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe];
unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb);
enum dbuf_slice slice;
/*
* The arbiter can only really guarantee an
* equal share of the total bw to each plane.
*/
for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask) {
crtc_bw->max_bw[slice] = max(crtc_bw->max_bw[slice], data_rate);
crtc_bw->active_planes[slice] |= BIT(plane_id);
}
}
static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state,
const struct intel_crtc_state *crtc_state)
{
@ -682,52 +751,90 @@ static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state,
struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe];
enum plane_id plane_id;
memset(&crtc_bw->used_bw, 0, sizeof(crtc_bw->used_bw));
memset(crtc_bw, 0, sizeof(*crtc_bw));
if (!crtc_state->hw.active)
return;
for_each_plane_id_on_crtc(crtc, plane_id) {
const struct skl_ddb_entry *ddb_y =
&crtc_state->wm.skl.plane_ddb_y[plane_id];
const struct skl_ddb_entry *ddb_uv =
&crtc_state->wm.skl.plane_ddb_uv[plane_id];
unsigned int data_rate = crtc_state->data_rate[plane_id];
unsigned int dbuf_mask = 0;
enum dbuf_slice slice;
dbuf_mask |= skl_ddb_dbuf_slice_mask(i915, ddb_y);
dbuf_mask |= skl_ddb_dbuf_slice_mask(i915, ddb_uv);
/*
* FIXME: To calculate that more properly we probably
* need to split per plane data_rate into data_rate_y
* and data_rate_uv for multiplanar formats in order not
* to get accounted those twice if they happen to reside
* on different slices.
* However for pre-icl this would work anyway because
* we have only single slice and for icl+ uv plane has
* non-zero data rate.
* So in worst case those calculation are a bit
* pessimistic, which shouldn't pose any significant
* problem anyway.
* We assume cursors are small enough
* to not cause bandwidth problems.
*/
for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask)
crtc_bw->used_bw[slice] += data_rate;
if (plane_id == PLANE_CURSOR)
continue;
skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id,
&crtc_state->wm.skl.plane_ddb[plane_id],
crtc_state->data_rate[plane_id]);
if (DISPLAY_VER(i915) < 11)
skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id,
&crtc_state->wm.skl.plane_ddb_y[plane_id],
crtc_state->data_rate[plane_id]);
}
}
int skl_bw_calc_min_cdclk(struct intel_atomic_state *state)
/* "Maximum Data Buffer Bandwidth" */
static int
intel_bw_dbuf_min_cdclk(struct drm_i915_private *i915,
const struct intel_bw_state *bw_state)
{
unsigned int total_max_bw = 0;
enum dbuf_slice slice;
for_each_dbuf_slice(i915, slice) {
int num_active_planes = 0;
unsigned int max_bw = 0;
enum pipe pipe;
/*
* The arbiter can only really guarantee an
* equal share of the total bw to each plane.
*/
for_each_pipe(i915, pipe) {
const struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[pipe];
max_bw = max(crtc_bw->max_bw[slice], max_bw);
num_active_planes += hweight8(crtc_bw->active_planes[slice]);
}
max_bw *= num_active_planes;
total_max_bw = max(total_max_bw, max_bw);
}
return DIV_ROUND_UP(total_max_bw, 64);
}
int intel_bw_min_cdclk(struct drm_i915_private *i915,
const struct intel_bw_state *bw_state)
{
enum pipe pipe;
int min_cdclk;
min_cdclk = intel_bw_dbuf_min_cdclk(i915, bw_state);
for_each_pipe(i915, pipe)
min_cdclk = max(bw_state->min_cdclk[pipe], min_cdclk);
return min_cdclk;
}
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
bool *need_cdclk_calc)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_bw_state *new_bw_state = NULL;
struct intel_bw_state *old_bw_state = NULL;
const struct intel_bw_state *old_bw_state = NULL;
const struct intel_cdclk_state *cdclk_state;
const struct intel_crtc_state *crtc_state;
int old_min_cdclk, new_min_cdclk;
struct intel_crtc *crtc;
int max_bw = 0;
enum pipe pipe;
int i;
if (DISPLAY_VER(dev_priv) < 9)
return 0;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
new_bw_state = intel_atomic_get_bw_state(state);
if (IS_ERR(new_bw_state))
@ -736,82 +843,53 @@ int skl_bw_calc_min_cdclk(struct intel_atomic_state *state)
old_bw_state = intel_atomic_get_old_bw_state(state);
skl_crtc_calc_dbuf_bw(new_bw_state, crtc_state);
new_bw_state->min_cdclk[crtc->pipe] =
intel_bw_crtc_min_cdclk(crtc_state);
}
if (!old_bw_state)
return 0;
for_each_pipe(dev_priv, pipe) {
struct intel_dbuf_bw *crtc_bw;
enum dbuf_slice slice;
crtc_bw = &new_bw_state->dbuf_bw[pipe];
for_each_dbuf_slice(dev_priv, slice) {
/*
* Current experimental observations show that contrary
* to BSpec we get underruns once we exceed 64 * CDCLK
* for slices in total.
* As a temporary measure in order not to keep CDCLK
* bumped up all the time we calculate CDCLK according
* to this formula for overall bw consumed by slices.
*/
max_bw += crtc_bw->used_bw[slice];
}
}
new_bw_state->min_cdclk = max_bw / 64;
if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) {
if (intel_bw_state_changed(dev_priv, old_bw_state, new_bw_state)) {
int ret = intel_atomic_lock_global_state(&new_bw_state->base);
if (ret)
return ret;
}
return 0;
}
old_min_cdclk = intel_bw_min_cdclk(dev_priv, old_bw_state);
new_min_cdclk = intel_bw_min_cdclk(dev_priv, new_bw_state);
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_bw_state *new_bw_state = NULL;
struct intel_bw_state *old_bw_state = NULL;
const struct intel_crtc_state *crtc_state;
struct intel_crtc *crtc;
int min_cdclk = 0;
enum pipe pipe;
int i;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
new_bw_state = intel_atomic_get_bw_state(state);
if (IS_ERR(new_bw_state))
return PTR_ERR(new_bw_state);
old_bw_state = intel_atomic_get_old_bw_state(state);
}
if (!old_bw_state)
/*
* No need to check against the cdclk state if
* the min cdclk doesn't increase.
*
* Ie. we only ever increase the cdclk due to bandwidth
* requirements. This can reduce back and forth
* display blinking due to constant cdclk changes.
*/
if (new_min_cdclk <= old_min_cdclk)
return 0;
for_each_pipe(dev_priv, pipe) {
struct intel_cdclk_state *cdclk_state;
cdclk_state = intel_atomic_get_cdclk_state(state);
if (IS_ERR(cdclk_state))
return PTR_ERR(cdclk_state);
cdclk_state = intel_atomic_get_new_cdclk_state(state);
if (!cdclk_state)
return 0;
/*
* No need to recalculate the cdclk state if
* the min cdclk doesn't increase.
*
* Ie. we only ever increase the cdclk due to bandwidth
* requirements. This can reduce back and forth
* display blinking due to constant cdclk changes.
*/
if (new_min_cdclk <= cdclk_state->bw_min_cdclk)
return 0;
min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk);
}
new_bw_state->min_cdclk = min_cdclk;
if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) {
int ret = intel_atomic_lock_global_state(&new_bw_state->base);
if (ret)
return ret;
}
drm_dbg_kms(&dev_priv->drm,
"new bandwidth min cdclk (%d kHz) > old min cdclk (%d kHz)\n",
new_min_cdclk, cdclk_state->bw_min_cdclk);
*need_cdclk_calc = true;
return 0;
}
@ -820,7 +898,7 @@ static u16 icl_qgv_points_mask(struct drm_i915_private *i915)
{
unsigned int num_psf_gv_points = i915->max_bw[0].num_psf_gv_points;
unsigned int num_qgv_points = i915->max_bw[0].num_qgv_points;
u16 mask = 0;
u16 qgv_points = 0, psf_points = 0;
/*
* We can _not_ use the whole ADLS_QGV_PT_MASK here, as PCode rejects
@ -828,12 +906,12 @@ static u16 icl_qgv_points_mask(struct drm_i915_private *i915)
* So need to operate only with those returned from PCode.
*/
if (num_qgv_points > 0)
mask |= REG_GENMASK(num_qgv_points - 1, 0);
qgv_points = GENMASK(num_qgv_points - 1, 0);
if (num_psf_gv_points > 0)
mask |= REG_GENMASK(num_psf_gv_points - 1, 0) << ADLS_PSF_PT_SHIFT;
psf_points = GENMASK(num_psf_gv_points - 1, 0);
return mask;
return ICL_PCODE_REQ_QGV_PT(qgv_points) | ADLS_PCODE_REQ_PSF_PT(psf_points);
}
static int intel_bw_check_data_rate(struct intel_atomic_state *state, bool *changed)
@ -890,7 +968,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
unsigned int data_rate;
unsigned int num_active_planes;
int i, ret;
u32 allowed_points = 0;
u16 qgv_points = 0, psf_points = 0;
unsigned int max_bw_point = 0, max_bw = 0;
unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points;
unsigned int num_psf_gv_points = dev_priv->max_bw[0].num_psf_gv_points;
@ -948,7 +1026,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
max_bw = max_data_rate;
}
if (max_data_rate >= data_rate)
allowed_points |= REG_FIELD_PREP(ADLS_QGV_PT_MASK, BIT(i));
qgv_points |= BIT(i);
drm_dbg_kms(&dev_priv->drm, "QGV point %d: max bw %d required %d\n",
i, max_data_rate, data_rate);
@ -958,7 +1036,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
unsigned int max_data_rate = adl_psf_bw(dev_priv, i);
if (max_data_rate >= data_rate)
allowed_points |= REG_FIELD_PREP(ADLS_PSF_PT_MASK, BIT(i));
psf_points |= BIT(i);
drm_dbg_kms(&dev_priv->drm, "PSF GV point %d: max bw %d"
" required %d\n",
@ -970,20 +1048,18 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
* left, so if we couldn't - simply reject the configuration for obvious
* reasons.
*/
if ((allowed_points & ADLS_QGV_PT_MASK) == 0) {
if (qgv_points == 0) {
drm_dbg_kms(&dev_priv->drm, "No QGV points provide sufficient memory"
" bandwidth %d for display configuration(%d active planes).\n",
data_rate, num_active_planes);
return -EINVAL;
}
if (num_psf_gv_points > 0) {
if ((allowed_points & ADLS_PSF_PT_MASK) == 0) {
drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory"
" bandwidth %d for display configuration(%d active planes).\n",
data_rate, num_active_planes);
return -EINVAL;
}
if (num_psf_gv_points > 0 && psf_points == 0) {
drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory"
" bandwidth %d for display configuration(%d active planes).\n",
data_rate, num_active_planes);
return -EINVAL;
}
/*
@ -992,16 +1068,18 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
* cause.
*/
if (!intel_can_enable_sagv(dev_priv, new_bw_state)) {
allowed_points &= ADLS_PSF_PT_MASK;
allowed_points |= BIT(max_bw_point);
qgv_points = BIT(max_bw_point);
drm_dbg_kms(&dev_priv->drm, "No SAGV, using single QGV point %d\n",
max_bw_point);
}
/*
* We store the ones which need to be masked as that is what PCode
* actually accepts as a parameter.
*/
new_bw_state->qgv_points_mask = ~allowed_points &
new_bw_state->qgv_points_mask =
~(ICL_PCODE_REQ_QGV_PT(qgv_points) |
ADLS_PCODE_REQ_PSF_PT(psf_points)) &
icl_qgv_points_mask(dev_priv);
/*

View File

@ -17,7 +17,8 @@ struct intel_atomic_state;
struct intel_crtc_state;
struct intel_dbuf_bw {
int used_bw[I915_MAX_DBUF_SLICES];
unsigned int max_bw[I915_MAX_DBUF_SLICES];
u8 active_planes[I915_MAX_DBUF_SLICES];
};
struct intel_bw_state {
@ -40,10 +41,9 @@ struct intel_bw_state {
*/
u16 qgv_points_mask;
int min_cdclk[I915_MAX_PIPES];
unsigned int data_rate[I915_MAX_PIPES];
u8 num_active_planes[I915_MAX_PIPES];
int min_cdclk;
};
#define to_intel_bw_state(x) container_of((x), struct intel_bw_state, base)
@ -64,7 +64,9 @@ void intel_bw_crtc_update(struct intel_bw_state *bw_state,
const struct intel_crtc_state *crtc_state);
int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
u32 points_mask);
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state);
int skl_bw_calc_min_cdclk(struct intel_atomic_state *state);
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
bool *need_cdclk_calc);
int intel_bw_min_cdclk(struct drm_i915_private *i915,
const struct intel_bw_state *bw_state);
#endif /* __INTEL_BW_H__ */

View File

@ -72,7 +72,6 @@ struct intel_cdclk_funcs {
void (*set_cdclk)(struct drm_i915_private *i915,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe);
int (*bw_calc_min_cdclk)(struct intel_atomic_state *state);
int (*modeset_calc_cdclk)(struct intel_cdclk_state *state);
u8 (*calc_voltage_level)(int cdclk);
};
@ -83,12 +82,6 @@ void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv,
dev_priv->cdclk_funcs->get_cdclk(dev_priv, cdclk_config);
}
static int intel_cdclk_bw_calc_min_cdclk(struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
return dev_priv->cdclk_funcs->bw_calc_min_cdclk(state);
}
static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
@ -2325,13 +2318,6 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state)
dev_priv->max_cdclk_freq));
}
if (min_cdclk > dev_priv->max_cdclk_freq) {
drm_dbg_kms(&dev_priv->drm,
"required cdclk (%d kHz) exceeds max (%d kHz)\n",
min_cdclk, dev_priv->max_cdclk_freq);
return -EINVAL;
}
return min_cdclk;
}
@ -2339,7 +2325,7 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
{
struct intel_atomic_state *state = cdclk_state->base.state;
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_bw_state *bw_state = NULL;
const struct intel_bw_state *bw_state;
struct intel_crtc *crtc;
struct intel_crtc_state *crtc_state;
int min_cdclk, i;
@ -2352,10 +2338,6 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
if (min_cdclk < 0)
return min_cdclk;
bw_state = intel_atomic_get_bw_state(state);
if (IS_ERR(bw_state))
return PTR_ERR(bw_state);
if (cdclk_state->min_cdclk[crtc->pipe] == min_cdclk)
continue;
@ -2366,14 +2348,31 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
return ret;
}
min_cdclk = cdclk_state->force_min_cdclk;
for_each_pipe(dev_priv, pipe) {
bw_state = intel_atomic_get_new_bw_state(state);
if (bw_state) {
min_cdclk = intel_bw_min_cdclk(dev_priv, bw_state);
if (cdclk_state->bw_min_cdclk != min_cdclk) {
int ret;
cdclk_state->bw_min_cdclk = min_cdclk;
ret = intel_atomic_lock_global_state(&cdclk_state->base);
if (ret)
return ret;
}
}
min_cdclk = max(cdclk_state->force_min_cdclk,
cdclk_state->bw_min_cdclk);
for_each_pipe(dev_priv, pipe)
min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk);
if (!bw_state)
continue;
min_cdclk = max(bw_state->min_cdclk, min_cdclk);
if (min_cdclk > dev_priv->max_cdclk_freq) {
drm_dbg_kms(&dev_priv->drm,
"required cdclk (%d kHz) exceeds max (%d kHz)\n",
min_cdclk, dev_priv->max_cdclk_freq);
return -EINVAL;
}
return min_cdclk;
@ -2654,14 +2653,10 @@ intel_atomic_get_cdclk_state(struct intel_atomic_state *state)
int intel_cdclk_atomic_check(struct intel_atomic_state *state,
bool *need_cdclk_calc)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_cdclk_state *old_cdclk_state;
const struct intel_cdclk_state *new_cdclk_state;
struct intel_plane_state *plane_state;
struct intel_bw_state *new_bw_state;
struct intel_plane *plane;
int min_cdclk = 0;
enum pipe pipe;
int ret;
int i;
@ -2676,6 +2671,10 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state,
return ret;
}
ret = intel_bw_calc_min_cdclk(state, need_cdclk_calc);
if (ret)
return ret;
old_cdclk_state = intel_atomic_get_old_cdclk_state(state);
new_cdclk_state = intel_atomic_get_new_cdclk_state(state);
@ -2683,23 +2682,6 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state,
old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk)
*need_cdclk_calc = true;
ret = intel_cdclk_bw_calc_min_cdclk(state);
if (ret)
return ret;
new_bw_state = intel_atomic_get_new_bw_state(state);
if (!new_cdclk_state || !new_bw_state)
return 0;
for_each_pipe(i915, pipe) {
min_cdclk = max(new_cdclk_state->min_cdclk[pipe], min_cdclk);
/* Currently do this change only if we need to increase */
if (new_bw_state->min_cdclk > min_cdclk)
*need_cdclk_calc = true;
}
return 0;
}
@ -3072,7 +3054,6 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = tgl_calc_voltage_level,
};
@ -3080,7 +3061,6 @@ static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
static const struct intel_cdclk_funcs ehl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = ehl_calc_voltage_level,
};
@ -3088,7 +3068,6 @@ static const struct intel_cdclk_funcs ehl_cdclk_funcs = {
static const struct intel_cdclk_funcs icl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = icl_calc_voltage_level,
};
@ -3096,7 +3075,6 @@ static const struct intel_cdclk_funcs icl_cdclk_funcs = {
static const struct intel_cdclk_funcs bxt_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = bxt_calc_voltage_level,
};
@ -3104,53 +3082,45 @@ static const struct intel_cdclk_funcs bxt_cdclk_funcs = {
static const struct intel_cdclk_funcs skl_cdclk_funcs = {
.get_cdclk = skl_get_cdclk,
.set_cdclk = skl_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = skl_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs bdw_cdclk_funcs = {
.get_cdclk = bdw_get_cdclk,
.set_cdclk = bdw_set_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = bdw_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs chv_cdclk_funcs = {
.get_cdclk = vlv_get_cdclk,
.set_cdclk = chv_set_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = vlv_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs vlv_cdclk_funcs = {
.get_cdclk = vlv_get_cdclk,
.set_cdclk = vlv_set_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = vlv_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs hsw_cdclk_funcs = {
.get_cdclk = hsw_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
/* SNB, IVB, 965G, 945G */
static const struct intel_cdclk_funcs fixed_400mhz_cdclk_funcs = {
.get_cdclk = fixed_400mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs ilk_cdclk_funcs = {
.get_cdclk = fixed_450mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs gm45_cdclk_funcs = {
.get_cdclk = gm45_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
@ -3158,7 +3128,6 @@ static const struct intel_cdclk_funcs gm45_cdclk_funcs = {
static const struct intel_cdclk_funcs i965gm_cdclk_funcs = {
.get_cdclk = i965gm_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
@ -3166,19 +3135,16 @@ static const struct intel_cdclk_funcs i965gm_cdclk_funcs = {
static const struct intel_cdclk_funcs pnv_cdclk_funcs = {
.get_cdclk = pnv_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs g33_cdclk_funcs = {
.get_cdclk = g33_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs i945gm_cdclk_funcs = {
.get_cdclk = i945gm_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
@ -3186,37 +3152,31 @@ static const struct intel_cdclk_funcs i945gm_cdclk_funcs = {
static const struct intel_cdclk_funcs i915gm_cdclk_funcs = {
.get_cdclk = i915gm_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs i915g_cdclk_funcs = {
.get_cdclk = fixed_333mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs i865g_cdclk_funcs = {
.get_cdclk = fixed_266mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs i85x_cdclk_funcs = {
.get_cdclk = i85x_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs i845g_cdclk_funcs = {
.get_cdclk = fixed_200mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs i830_cdclk_funcs = {
.get_cdclk = fixed_133mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk,
};

View File

@ -36,6 +36,8 @@ struct intel_cdclk_state {
*/
struct intel_cdclk_config actual;
/* minimum acceptable cdclk to satisfy bandwidth requirements */
int bw_min_cdclk;
/* minimum acceptable cdclk for each pipe */
int min_cdclk[I915_MAX_PIPES];
/* minimum acceptable voltage level for each pipe */

View File

@ -31,12 +31,21 @@
struct intel_color_funcs {
int (*color_check)(struct intel_crtc_state *crtc_state);
/*
* Program double buffered color management registers during
* vblank evasion. The registers should then latch during the
* next vblank start, alongside any other double buffered registers
* involved with the same commit.
* Program non-arming double buffered color management registers
* before vblank evasion. The registers should then latch after
* the arming register is written (by color_commit_arm()) during
* the next vblank start, alongside any other double buffered
* registers involved with the same commit. This hook is optional.
*/
void (*color_commit)(const struct intel_crtc_state *crtc_state);
void (*color_commit_noarm)(const struct intel_crtc_state *crtc_state);
/*
* Program arming double buffered color management registers
* during vblank evasion. The registers (and whatever other registers
* they arm that were written by color_commit_noarm) should then latch
* during the next vblank start, alongside any other double buffered
* registers involved with the same commit.
*/
void (*color_commit_arm)(const struct intel_crtc_state *crtc_state);
/*
* Load LUTs (and other single buffered color management
* registers). Will (hopefully) be called during the vblank
@ -337,15 +346,11 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state)
ilk_csc_coeff_identity,
ilk_csc_off_zero);
}
intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
if (crtc_state->hw.ctm) {
u16 coeff[9];
@ -364,9 +369,6 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state)
ilk_csc_coeff_limited_range,
ilk_csc_postoff_limited_range);
}
intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
static void chv_load_cgm_csc(struct intel_crtc *crtc,
@ -491,7 +493,17 @@ static void icl_lut_multi_seg_pack(struct drm_color_lut *entry, u32 ldw, u32 udw
REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_LDW_MASK, ldw);
}
static void i9xx_color_commit(const struct intel_crtc_state *crtc_state)
static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state)
{
icl_load_csc_matrix(crtc_state);
}
static void ilk_color_commit_noarm(const struct intel_crtc_state *crtc_state)
{
ilk_load_csc_matrix(crtc_state);
}
static void i9xx_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@ -504,7 +516,7 @@ static void i9xx_color_commit(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, PIPECONF(pipe), val);
}
static void ilk_color_commit(const struct intel_crtc_state *crtc_state)
static void ilk_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@ -516,10 +528,11 @@ static void ilk_color_commit(const struct intel_crtc_state *crtc_state)
val |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode);
intel_de_write(dev_priv, PIPECONF(pipe), val);
ilk_load_csc_matrix(crtc_state);
intel_de_write_fw(dev_priv, PIPE_CSC_MODE(pipe),
crtc_state->csc_mode);
}
static void hsw_color_commit(const struct intel_crtc_state *crtc_state)
static void hsw_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@ -527,10 +540,11 @@ static void hsw_color_commit(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe),
crtc_state->gamma_mode);
ilk_load_csc_matrix(crtc_state);
intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
static void skl_color_commit(const struct intel_crtc_state *crtc_state)
static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@ -551,10 +565,8 @@ static void skl_color_commit(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe),
crtc_state->gamma_mode);
if (DISPLAY_VER(dev_priv) >= 11)
icl_load_csc_matrix(crtc_state);
else
ilk_load_csc_matrix(crtc_state);
intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
static void i9xx_load_lut_8(struct intel_crtc *crtc,
@ -1169,11 +1181,19 @@ void intel_color_load_luts(const struct intel_crtc_state *crtc_state)
dev_priv->color_funcs->load_luts(crtc_state);
}
void intel_color_commit(const struct intel_crtc_state *crtc_state)
void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
dev_priv->color_funcs->color_commit(crtc_state);
if (dev_priv->color_funcs->color_commit_noarm)
dev_priv->color_funcs->color_commit_noarm(crtc_state);
}
void intel_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
dev_priv->color_funcs->color_commit_arm(crtc_state);
}
static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
@ -2132,70 +2152,77 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
static const struct intel_color_funcs chv_color_funcs = {
.color_check = chv_color_check,
.color_commit = i9xx_color_commit,
.color_commit_arm = i9xx_color_commit_arm,
.load_luts = chv_load_luts,
.read_luts = chv_read_luts,
};
static const struct intel_color_funcs i965_color_funcs = {
.color_check = i9xx_color_check,
.color_commit = i9xx_color_commit,
.color_commit_arm = i9xx_color_commit_arm,
.load_luts = i965_load_luts,
.read_luts = i965_read_luts,
};
static const struct intel_color_funcs i9xx_color_funcs = {
.color_check = i9xx_color_check,
.color_commit = i9xx_color_commit,
.color_commit_arm = i9xx_color_commit_arm,
.load_luts = i9xx_load_luts,
.read_luts = i9xx_read_luts,
};
static const struct intel_color_funcs icl_color_funcs = {
.color_check = icl_color_check,
.color_commit = skl_color_commit,
.color_commit_noarm = icl_color_commit_noarm,
.color_commit_arm = skl_color_commit_arm,
.load_luts = icl_load_luts,
.read_luts = icl_read_luts,
};
static const struct intel_color_funcs glk_color_funcs = {
.color_check = glk_color_check,
.color_commit = skl_color_commit,
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = skl_color_commit_arm,
.load_luts = glk_load_luts,
.read_luts = glk_read_luts,
};
static const struct intel_color_funcs skl_color_funcs = {
.color_check = ivb_color_check,
.color_commit = skl_color_commit,
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = skl_color_commit_arm,
.load_luts = bdw_load_luts,
.read_luts = NULL,
};
static const struct intel_color_funcs bdw_color_funcs = {
.color_check = ivb_color_check,
.color_commit = hsw_color_commit,
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = hsw_color_commit_arm,
.load_luts = bdw_load_luts,
.read_luts = NULL,
};
static const struct intel_color_funcs hsw_color_funcs = {
.color_check = ivb_color_check,
.color_commit = hsw_color_commit,
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = hsw_color_commit_arm,
.load_luts = ivb_load_luts,
.read_luts = NULL,
};
static const struct intel_color_funcs ivb_color_funcs = {
.color_check = ivb_color_check,
.color_commit = ilk_color_commit,
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = ilk_color_commit_arm,
.load_luts = ivb_load_luts,
.read_luts = NULL,
};
static const struct intel_color_funcs ilk_color_funcs = {
.color_check = ilk_color_check,
.color_commit = ilk_color_commit,
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = ilk_color_commit_arm,
.load_luts = ilk_load_luts,
.read_luts = ilk_read_luts,
};

View File

@ -14,7 +14,8 @@ struct drm_property_blob;
void intel_color_init(struct intel_crtc *crtc);
int intel_color_check(struct intel_crtc_state *crtc_state);
void intel_color_commit(const struct intel_crtc_state *crtc_state);
void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state);
void intel_color_commit_arm(const struct intel_crtc_state *crtc_state);
void intel_color_load_luts(const struct intel_crtc_state *crtc_state);
void intel_color_get_config(struct intel_crtc_state *crtc_state);
int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state);

View File

@ -25,18 +25,29 @@ enum {
};
static const struct icl_procmon {
const char *name;
u32 dw1, dw9, dw10;
} icl_procmon_values[] = {
[PROCMON_0_85V_DOT_0] =
{ .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, },
[PROCMON_0_95V_DOT_0] =
{ .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, },
[PROCMON_0_95V_DOT_1] =
{ .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, },
[PROCMON_1_05V_DOT_0] =
{ .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, },
[PROCMON_1_05V_DOT_1] =
{ .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, },
[PROCMON_0_85V_DOT_0] = {
.name = "0.85V dot0 (low-voltage)",
.dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96,
},
[PROCMON_0_95V_DOT_0] = {
.name = "0.95V dot0",
.dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB,
},
[PROCMON_0_95V_DOT_1] = {
.name = "0.95V dot1",
.dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5,
},
[PROCMON_1_05V_DOT_0] = {
.name = "1.05V dot0",
.dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1,
},
[PROCMON_1_05V_DOT_1] = {
.name = "1.05V dot1",
.dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1,
},
};
static const struct icl_procmon *
@ -113,6 +124,10 @@ static bool icl_verify_procmon_ref_values(struct drm_i915_private *dev_priv,
procmon = icl_get_procmon_ref_values(dev_priv, phy);
drm_dbg_kms(&dev_priv->drm,
"Combo PHY %c Voltage/Process Info : %s\n",
phy_name(phy), procmon->name);
ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy),
(0xff << 16) | 0xff, procmon->dw1);
ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy),

View File

@ -54,6 +54,8 @@ int intel_connector_init(struct intel_connector *connector)
__drm_atomic_helper_connector_reset(&connector->base,
&conn_state->base);
INIT_LIST_HEAD(&connector->panel.fixed_modes);
return 0;
}
@ -100,7 +102,7 @@ void intel_connector_destroy(struct drm_connector *connector)
if (!IS_ERR_OR_NULL(intel_connector->edid))
kfree(intel_connector->edid);
intel_panel_fini(&intel_connector->panel);
intel_panel_fini(intel_connector);
drm_connector_cleanup(connector);

View File

@ -24,6 +24,7 @@
#include "intel_display_debugfs.h"
#include "intel_display_trace.h"
#include "intel_display_types.h"
#include "intel_drrs.h"
#include "intel_dsi.h"
#include "intel_pipe_crc.h"
#include "intel_psr.h"
@ -367,6 +368,7 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
intel_color_init(crtc);
intel_crtc_drrs_init(crtc);
intel_crtc_crc_init(crtc);
cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE);
@ -485,6 +487,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state)
intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
DEFINE_WAIT(wait);
intel_psr_lock(new_crtc_state);
if (new_crtc_state->do_async_flip)
return;
@ -516,7 +520,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state)
* VBL interrupts will start the PSR exit and prevent a PSR
* re-entry as well.
*/
intel_psr_wait_for_idle(new_crtc_state);
intel_psr_wait_for_idle_locked(new_crtc_state);
local_irq_disable();
@ -630,6 +634,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
ktime_t end_vbl_time = ktime_get();
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
intel_psr_unlock(new_crtc_state);
if (new_crtc_state->do_async_flip)
return;

View File

@ -153,6 +153,11 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
plane_state->uapi.src = src;
plane_state->uapi.dst = dst;
/* final plane coordinates will be relative to the plane's pipe */
drm_rect_translate(&plane_state->uapi.dst,
-crtc_state->pipe_src.x1,
-crtc_state->pipe_src.y1);
ret = intel_cursor_check_surface(plane_state);
if (ret)
return ret;
@ -255,7 +260,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
u32 cntl = 0, base = 0, pos = 0, size = 0;
unsigned long irqflags;
if (plane_state && plane_state->uapi.visible) {
unsigned int width = drm_rect_width(&plane_state->uapi.dst);
@ -270,8 +274,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane,
pos = intel_cursor_position(plane_state);
}
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/* On these chipsets we can only modify the base/size/stride
* whilst the cursor is disabled.
*/
@ -290,8 +292,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane,
} else {
intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
}
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void i845_cursor_disable_arm(struct intel_plane *plane,
@ -492,7 +492,6 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
unsigned long irqflags;
if (plane_state && plane_state->uapi.visible) {
int width = drm_rect_width(&plane_state->uapi.dst);
@ -508,8 +507,6 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane,
pos = intel_cursor_position(plane_state);
}
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/*
* On some platforms writing CURCNTR first will also
* cause CURPOS to be armed by the CURBASE write.
@ -555,8 +552,6 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane,
intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
intel_de_write_fw(dev_priv, CURBASE(pipe), base);
}
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void i9xx_cursor_disable_arm(struct intel_plane *plane,
@ -637,7 +632,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
* FIXME bigjoiner fastpath would be good
*/
if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) ||
crtc_state->update_pipe || crtc_state->bigjoiner)
crtc_state->update_pipe || crtc_state->bigjoiner_pipes)
goto slow;
/*
@ -715,6 +710,14 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
*/
crtc_state->active_planes = new_crtc_state->active_planes;
/*
* Technically we should do a vblank evasion here to make
* sure all the cursor registers update on the same frame.
* For now just make sure the register writes happen as
* quickly as possible to minimize the race window.
*/
local_irq_disable();
if (new_plane_state->uapi.visible) {
intel_plane_update_noarm(plane, crtc_state, new_plane_state);
intel_plane_update_arm(plane, crtc_state, new_plane_state);
@ -722,6 +725,8 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
intel_plane_disable_arm(plane, crtc_state);
}
local_irq_enable();
intel_plane_unpin_fb(old_plane_state);
out_free:

View File

@ -25,6 +25,8 @@
*
*/
#include <linux/string_helpers.h>
#include <drm/drm_privacy_screen_consumer.h>
#include <drm/drm_scdc_helper.h>
@ -43,7 +45,6 @@
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
#include "intel_drrs.h"
#include "intel_dsi.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
@ -2152,7 +2153,7 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel
enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0) <= 0)
drm_dbg_kms(&i915->drm,
"Failed to %s MSA_TIMING_PAR_IGNORE in the sink\n",
enabledisable(enable));
str_enable_disable(enable));
}
static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
@ -2818,10 +2819,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
intel_drrs_enable(intel_dp, crtc_state);
if (crtc_state->has_audio)
intel_audio_codec_enable(encoder, crtc_state, conn_state);
intel_audio_codec_enable(encoder, crtc_state, conn_state);
trans_port_sync_stop_link_train(state, encoder, crtc_state);
}
@ -2915,8 +2913,7 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
intel_de_write(dev_priv, DDI_BUF_CTL(port),
dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE);
if (crtc_state->has_audio)
intel_audio_codec_enable(encoder, crtc_state, conn_state);
intel_audio_codec_enable(encoder, crtc_state, conn_state);
}
static void intel_enable_ddi(struct intel_atomic_state *state,
@ -2957,11 +2954,8 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state,
intel_dp->link_trained = false;
if (old_crtc_state->has_audio)
intel_audio_codec_disable(encoder,
old_crtc_state, old_conn_state);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
intel_drrs_disable(intel_dp, old_crtc_state);
intel_psr_disable(intel_dp, old_crtc_state);
intel_edp_backlight_off(old_conn_state);
/* Disable the decompression in DP Sink */
@ -2980,9 +2974,7 @@ static void intel_disable_ddi_hdmi(struct intel_atomic_state *state,
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct drm_connector *connector = old_conn_state->connector;
if (old_crtc_state->has_audio)
intel_audio_codec_disable(encoder,
old_crtc_state, old_conn_state);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
false, false))
@ -3011,12 +3003,9 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
intel_ddi_set_dp_msa(crtc_state, conn_state);
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
intel_drrs_update(intel_dp, crtc_state);
intel_backlight_update(state, encoder, crtc_state, conn_state);
drm_connector_update_privacy_screen(conn_state);
@ -4308,6 +4297,13 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
return;
}
if (intel_phy_is_snps(dev_priv, phy) &&
dev_priv->snps_phy_failed_calibration & BIT(phy)) {
drm_dbg_kms(&dev_priv->drm,
"SNPS PHY %c failed to calibrate, proceeding anyway\n",
phy_name(phy));
}
dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL);
if (!dig_port)
return;

View File

@ -907,7 +907,7 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr[] = {
{ .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */
{ .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */
{ .icl = { 0x6, 0x7F, 0x2F, 0x00, 0x10 } }, /* 500 900 5.1 */
{ .icl = { 0xC, 0x73, 0x3E, 0x00, 0x01 } }, /* 650 700 0.6 */
{ .icl = { 0xC, 0x7C, 0x3C, 0x00, 0x03 } }, /* 650 700 0.6 */
{ .icl = { 0x6, 0x7F, 0x35, 0x00, 0x0A } }, /* 600 900 3.5 */
{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */
};
@ -921,7 +921,7 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[
/* NT mV Trans mV db */
{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */
{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */
{ .icl = { 0xC, 0x71, 0x2F, 0x00, 0x10 } }, /* 350 700 6.0 */
{ .icl = { 0xC, 0x71, 0x30, 0x00, 0x0F } }, /* 350 700 6.0 */
{ .icl = { 0x6, 0x7F, 0x2B, 0x00, 0x14 } }, /* 350 900 8.2 */
{ .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */
{ .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */
@ -931,19 +931,47 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[
{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */
};
static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_edp_hbr2[] = {
/* NT mV Trans mV db */
{ .icl = { 0x4, 0x50, 0x38, 0x00, 0x07 } }, /* 200 200 0.0 */
{ .icl = { 0x4, 0x58, 0x35, 0x00, 0x0A } }, /* 200 250 1.9 */
{ .icl = { 0x4, 0x60, 0x34, 0x00, 0x0B } }, /* 200 300 3.5 */
{ .icl = { 0x4, 0x6A, 0x32, 0x00, 0x0D } }, /* 200 350 4.9 */
{ .icl = { 0x4, 0x5E, 0x38, 0x00, 0x07 } }, /* 250 250 0.0 */
{ .icl = { 0x4, 0x61, 0x36, 0x00, 0x09 } }, /* 250 300 1.6 */
{ .icl = { 0x4, 0x6B, 0x34, 0x00, 0x0B } }, /* 250 350 2.9 */
{ .icl = { 0x4, 0x69, 0x39, 0x00, 0x06 } }, /* 300 300 0.0 */
{ .icl = { 0x4, 0x73, 0x37, 0x00, 0x08 } }, /* 300 350 1.3 */
{ .icl = { 0x4, 0x7A, 0x38, 0x00, 0x07 } }, /* 350 350 0.0 */
};
static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_edp_hbr3[] = {
/* NT mV Trans mV db */
{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */
{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */
{ .icl = { 0xC, 0x71, 0x30, 0x00, 0x0f } }, /* 350 700 6.0 */
{ .icl = { 0x6, 0x7F, 0x2B, 0x00, 0x14 } }, /* 350 900 8.2 */
{ .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */
{ .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */
{ .icl = { 0x6, 0x7F, 0x2F, 0x00, 0x10 } }, /* 500 900 5.1 */
{ .icl = { 0xC, 0x6C, 0x3C, 0x00, 0x03 } }, /* 650 700 0.6 */
{ .icl = { 0x6, 0x7F, 0x35, 0x00, 0x0A } }, /* 600 900 3.5 */
{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */
};
static const struct intel_ddi_buf_trans adlp_combo_phy_trans_dp_hbr2_hbr3 = {
.entries = _adlp_combo_phy_trans_dp_hbr2_hbr3,
.num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr2_hbr3),
};
static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_hbr3 = {
.entries = _icl_combo_phy_trans_dp_hbr2_edp_hbr3,
.num_entries = ARRAY_SIZE(_icl_combo_phy_trans_dp_hbr2_edp_hbr3),
.entries = _adlp_combo_phy_trans_dp_hbr2_edp_hbr3,
.num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr2_edp_hbr3),
};
static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_up_to_hbr2 = {
.entries = _icl_combo_phy_trans_edp_hbr2,
.num_entries = ARRAY_SIZE(_icl_combo_phy_trans_edp_hbr2),
.entries = _adlp_combo_phy_trans_edp_hbr2,
.num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_edp_hbr2),
};
static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr[] = {

File diff suppressed because it is too large Load Diff

View File

@ -565,7 +565,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state);
void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state);
void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc);
int vlv_get_hpll_vco(struct drm_i915_private *dev_priv);
int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
const char *name, u32 reg, int ref_freq);
@ -695,4 +694,6 @@ void assert_transcoder(struct drm_i915_private *dev_priv,
#define I915_STATE_WARN_ON(x) \
I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")")
bool intel_scanout_needs_vtd_wa(struct drm_i915_private *i915);
#endif

View File

@ -3,6 +3,8 @@
* Copyright © 2020 Intel Corporation
*/
#include <linux/string_helpers.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_fourcc.h>
@ -10,6 +12,7 @@
#include "intel_de.h"
#include "intel_display_debugfs.h"
#include "intel_display_power.h"
#include "intel_display_power_well.h"
#include "intel_display_types.h"
#include "intel_dmc.h"
#include "intel_dp.h"
@ -19,6 +22,7 @@
#include "intel_fbdev.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
#include "intel_panel.h"
#include "intel_pm.h"
#include "intel_psr.h"
#include "intel_sprite.h"
@ -52,7 +56,7 @@ static int i915_ips_status(struct seq_file *m, void *unused)
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
seq_printf(m, "Enabled by kernel parameter: %s\n",
yesno(dev_priv->params.enable_ips));
str_yes_no(dev_priv->params.enable_ips));
if (DISPLAY_VER(dev_priv) >= 8) {
seq_puts(m, "Currently: unknown\n");
@ -92,7 +96,7 @@ static int i915_sr_status(struct seq_file *m, void *unused)
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
seq_printf(m, "self-refresh: %s\n", enableddisabled(sr_enabled));
seq_printf(m, "self-refresh: %s\n", str_enabled_disabled(sr_enabled));
return 0;
}
@ -260,7 +264,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
bool enabled;
u32 val;
seq_printf(m, "Sink support: %s", yesno(psr->sink_support));
seq_printf(m, "Sink support: %s", str_yes_no(psr->sink_support));
if (psr->sink_support)
seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]);
seq_puts(m, "\n");
@ -279,7 +283,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
if (!psr->enabled) {
seq_printf(m, "PSR sink not reliable: %s\n",
yesno(psr->sink_not_reliable));
str_yes_no(psr->sink_not_reliable));
goto unlock;
}
@ -294,7 +298,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
enabled = val & EDP_PSR_ENABLE;
}
seq_printf(m, "Source PSR ctl: %s [0x%08x]\n",
enableddisabled(enabled), val);
str_enabled_disabled(enabled), val);
psr_source_status(intel_dp, m);
seq_printf(m, "Busy frontbuffer bits: 0x%08x\n",
psr->busy_frontbuffer_bits);
@ -341,7 +345,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
}
seq_printf(m, "PSR2 selective fetch: %s\n",
enableddisabled(psr->psr2_sel_fetch_enabled));
str_enabled_disabled(psr->psr2_sel_fetch_enabled));
}
unlock:
@ -432,75 +436,6 @@ static int i915_power_domain_info(struct seq_file *m, void *unused)
return 0;
}
static int i915_dmc_info(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
intel_wakeref_t wakeref;
struct intel_dmc *dmc;
i915_reg_t dc5_reg, dc6_reg = {};
if (!HAS_DMC(dev_priv))
return -ENODEV;
dmc = &dev_priv->dmc;
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
seq_printf(m, "fw loaded: %s\n", yesno(intel_dmc_has_payload(dev_priv)));
seq_printf(m, "path: %s\n", dmc->fw_path);
seq_printf(m, "Pipe A fw support: %s\n",
yesno(GRAPHICS_VER(dev_priv) >= 12));
seq_printf(m, "Pipe A fw loaded: %s\n", yesno(dmc->dmc_info[DMC_FW_PIPEA].payload));
seq_printf(m, "Pipe B fw support: %s\n", yesno(IS_ALDERLAKE_P(dev_priv)));
seq_printf(m, "Pipe B fw loaded: %s\n", yesno(dmc->dmc_info[DMC_FW_PIPEB].payload));
if (!intel_dmc_has_payload(dev_priv))
goto out;
seq_printf(m, "version: %d.%d\n", DMC_VERSION_MAJOR(dmc->version),
DMC_VERSION_MINOR(dmc->version));
if (DISPLAY_VER(dev_priv) >= 12) {
if (IS_DGFX(dev_priv)) {
dc5_reg = DG1_DMC_DEBUG_DC5_COUNT;
} else {
dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
}
/*
* NOTE: DMC_DEBUG3 is a general purpose reg.
* According to B.Specs:49196 DMC f/w reuses DC5/6 counter
* reg for DC3CO debugging and validation,
* but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter.
*/
seq_printf(m, "DC3CO count: %d\n", intel_de_read(dev_priv, IS_DGFX(dev_priv) ?
DG1_DMC_DEBUG3 : TGL_DMC_DEBUG3));
} else {
dc5_reg = IS_BROXTON(dev_priv) ? BXT_DMC_DC3_DC5_COUNT :
SKL_DMC_DC3_DC5_COUNT;
if (!IS_GEMINILAKE(dev_priv) && !IS_BROXTON(dev_priv))
dc6_reg = SKL_DMC_DC5_DC6_COUNT;
}
seq_printf(m, "DC3 -> DC5 count: %d\n",
intel_de_read(dev_priv, dc5_reg));
if (dc6_reg.reg)
seq_printf(m, "DC5 -> DC6 count: %d\n",
intel_de_read(dev_priv, dc6_reg));
out:
seq_printf(m, "program base: 0x%08x\n",
intel_de_read(dev_priv, DMC_PROGRAM(dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)));
seq_printf(m, "ssp base: 0x%08x\n",
intel_de_read(dev_priv, DMC_SSP_BASE));
seq_printf(m, "htp: 0x%08x\n", intel_de_read(dev_priv, DMC_HTP_SKL));
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
return 0;
}
static void intel_seq_print_mode(struct seq_file *m, int tabs,
const struct drm_display_mode *mode)
{
@ -537,11 +472,18 @@ static void intel_encoder_info(struct seq_file *m,
drm_connector_list_iter_end(&conn_iter);
}
static void intel_panel_info(struct seq_file *m, struct intel_panel *panel)
static void intel_panel_info(struct seq_file *m,
struct intel_connector *connector)
{
const struct drm_display_mode *mode = panel->fixed_mode;
const struct drm_display_mode *fixed_mode;
seq_printf(m, "\tfixed mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
if (list_empty(&connector->panel.fixed_modes))
return;
seq_puts(m, "\tfixed modes:\n");
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head)
intel_seq_print_mode(m, 2, fixed_mode);
}
static void intel_hdcp_info(struct seq_file *m,
@ -577,9 +519,8 @@ static void intel_dp_info(struct seq_file *m,
const struct drm_property_blob *edid = intel_connector->base.edid_blob_ptr;
seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]);
seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio));
if (intel_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)
intel_panel_info(m, &intel_connector->panel);
seq_printf(m, "\taudio support: %s\n",
str_yes_no(intel_dp->has_audio));
drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports,
edid ? edid->data : NULL, &intel_dp->aux);
@ -590,7 +531,7 @@ static void intel_dp_mst_info(struct seq_file *m,
{
bool has_audio = intel_connector->port->has_audio;
seq_printf(m, "\taudio support: %s\n", yesno(has_audio));
seq_printf(m, "\taudio support: %s\n", str_yes_no(has_audio));
}
static void intel_hdmi_info(struct seq_file *m,
@ -599,13 +540,8 @@ static void intel_hdmi_info(struct seq_file *m,
struct intel_encoder *intel_encoder = intel_attached_encoder(intel_connector);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(intel_encoder);
seq_printf(m, "\taudio support: %s\n", yesno(intel_hdmi->has_audio));
}
static void intel_lvds_info(struct seq_file *m,
struct intel_connector *intel_connector)
{
intel_panel_info(m, &intel_connector->panel);
seq_printf(m, "\taudio support: %s\n",
str_yes_no(intel_hdmi->has_audio));
}
static void intel_connector_info(struct seq_file *m,
@ -642,10 +578,6 @@ static void intel_connector_info(struct seq_file *m,
else
intel_dp_info(m, intel_connector);
break;
case DRM_MODE_CONNECTOR_LVDS:
if (encoder->type == INTEL_OUTPUT_LVDS)
intel_lvds_info(m, intel_connector);
break;
case DRM_MODE_CONNECTOR_HDMIA:
if (encoder->type == INTEL_OUTPUT_HDMI ||
encoder->type == INTEL_OUTPUT_DDI)
@ -658,6 +590,8 @@ static void intel_connector_info(struct seq_file *m,
seq_puts(m, "\tHDCP version: ");
intel_hdcp_info(m, intel_connector);
intel_panel_info(m, intel_connector);
seq_printf(m, "\tmodes:\n");
list_for_each_entry(mode, &connector->modes, head)
intel_seq_print_mode(m, 2, mode);
@ -757,7 +691,7 @@ static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane)
DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
fb->base.id, &fb->format->format,
fb->modifier, fb->width, fb->height,
yesno(plane_state->uapi.visible),
str_yes_no(plane_state->uapi.visible),
DRM_RECT_FP_ARG(&plane_state->uapi.src),
DRM_RECT_ARG(&plane_state->uapi.dst),
rot_str);
@ -796,7 +730,7 @@ static void intel_scaler_info(struct seq_file *m, struct intel_crtc *crtc)
&crtc_state->scaler_state.scalers[i];
seq_printf(m, ", scalers[%d]: use=%s, mode=%x",
i, yesno(sc->in_use), sc->mode);
i, str_yes_no(sc->in_use), sc->mode);
}
seq_puts(m, "\n");
} else {
@ -919,24 +853,24 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc)
crtc->base.base.id, crtc->base.name);
seq_printf(m, "\tuapi: enable=%s, active=%s, mode=" DRM_MODE_FMT "\n",
yesno(crtc_state->uapi.enable),
yesno(crtc_state->uapi.active),
str_yes_no(crtc_state->uapi.enable),
str_yes_no(crtc_state->uapi.active),
DRM_MODE_ARG(&crtc_state->uapi.mode));
seq_printf(m, "\thw: enable=%s, active=%s\n",
yesno(crtc_state->hw.enable), yesno(crtc_state->hw.active));
str_yes_no(crtc_state->hw.enable), str_yes_no(crtc_state->hw.active));
seq_printf(m, "\tadjusted_mode=" DRM_MODE_FMT "\n",
DRM_MODE_ARG(&crtc_state->hw.adjusted_mode));
seq_printf(m, "\tpipe__mode=" DRM_MODE_FMT "\n",
DRM_MODE_ARG(&crtc_state->hw.pipe_mode));
seq_printf(m, "\tpipe src size=%dx%d, dither=%s, bpp=%d\n",
crtc_state->pipe_src_w, crtc_state->pipe_src_h,
yesno(crtc_state->dither), crtc_state->pipe_bpp);
seq_printf(m, "\tpipe src=" DRM_RECT_FMT ", dither=%s, bpp=%d\n",
DRM_RECT_ARG(&crtc_state->pipe_src),
str_yes_no(crtc_state->dither), crtc_state->pipe_bpp);
intel_scaler_info(m, crtc);
if (crtc_state->bigjoiner)
if (crtc_state->bigjoiner_pipes)
seq_printf(m, "\tLinked to 0x%x pipes as a %s\n",
crtc_state->bigjoiner_pipes,
intel_crtc_is_bigjoiner_slave(crtc_state) ? "slave" : "master");
@ -948,8 +882,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc)
intel_plane_info(m, crtc);
seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s\n",
yesno(!crtc->cpu_fifo_underrun_disabled),
yesno(!crtc->pch_fifo_underrun_disabled));
str_yes_no(!crtc->cpu_fifo_underrun_disabled),
str_yes_no(!crtc->pch_fifo_underrun_disabled));
crtc_updates_info(m, crtc, "\t");
}
@ -1005,7 +939,8 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name,
pll->info->id);
seq_printf(m, " pipe_mask: 0x%x, active: 0x%x, on: %s\n",
pll->state.pipe_mask, pll->active_mask, yesno(pll->on));
pll->state.pipe_mask, pll->active_mask,
str_yes_no(pll->on));
seq_printf(m, " tracked hardware state:\n");
seq_printf(m, " dpll: 0x%08x\n", pll->state.hw_state.dpll);
seq_printf(m, " dpll_md: 0x%08x\n",
@ -1047,7 +982,7 @@ static int i915_ipc_status_show(struct seq_file *m, void *data)
struct drm_i915_private *dev_priv = m->private;
seq_printf(m, "Isochronous Priority Control: %s\n",
yesno(dev_priv->ipc_enabled));
str_yes_no(dev_priv->ipc_enabled));
return 0;
}
@ -1117,13 +1052,13 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
seq_printf(m, "Pipe %c\n", pipe_name(pipe));
for_each_plane_id_on_crtc(crtc, plane_id) {
entry = &crtc_state->wm.skl.plane_ddb_y[plane_id];
entry = &crtc_state->wm.skl.plane_ddb[plane_id];
seq_printf(m, " Plane%-8d%8u%8u%8u\n", plane_id + 1,
entry->start, entry->end,
skl_ddb_entry_size(entry));
}
entry = &crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR];
entry = &crtc_state->wm.skl.plane_ddb[PLANE_CURSOR];
seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start,
entry->end, skl_ddb_entry_size(entry));
}
@ -1133,97 +1068,48 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
return 0;
}
static void drrs_status_per_crtc(struct seq_file *m,
struct drm_device *dev,
struct intel_crtc *crtc)
static int i915_drrs_status(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = to_i915(dev);
struct i915_drrs *drrs = &dev_priv->drrs;
int vrefresh = 0;
struct drm_connector *connector;
struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
struct intel_crtc *crtc;
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
bool supported = false;
if (connector->state->crtc != &crtc->base)
continue;
seq_printf(m, "%s:\n", connector->name);
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
drrs->type == SEAMLESS_DRRS_SUPPORT)
supported = true;
seq_printf(m, "\tDRRS Supported: %s\n", yesno(supported));
drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n",
connector->base.base.id, connector->base.name,
intel_drrs_type_str(intel_panel_drrs_type(connector)));
}
drm_connector_list_iter_end(&conn_iter);
seq_puts(m, "\n");
if (to_intel_crtc_state(crtc->base.state)->has_drrs) {
struct intel_panel *panel;
for_each_intel_crtc(&dev_priv->drm, crtc) {
const struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
seq_printf(m, "[CRTC:%d:%s]:\n",
crtc->base.base.id, crtc->base.name);
mutex_lock(&crtc->drrs.mutex);
mutex_lock(&drrs->mutex);
/* DRRS Supported */
seq_puts(m, "\tDRRS Enabled: Yes\n");
seq_printf(m, "\tDRRS Enabled: %s\n",
str_yes_no(crtc_state->has_drrs));
/* disable_drrs() will make drrs->dp NULL */
if (!drrs->dp) {
seq_puts(m, "Idleness DRRS: Disabled\n");
mutex_unlock(&drrs->mutex);
return;
}
seq_printf(m, "\tDRRS Active: %s\n",
str_yes_no(intel_drrs_is_active(crtc)));
panel = &drrs->dp->attached_connector->panel;
seq_printf(m, "\t\tBusy_frontbuffer_bits: 0x%X",
drrs->busy_frontbuffer_bits);
seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n",
crtc->drrs.busy_frontbuffer_bits);
seq_puts(m, "\n\t\t");
if (drrs->refresh_rate_type == DRRS_HIGH_RR) {
seq_puts(m, "DRRS_State: DRRS_HIGH_RR\n");
vrefresh = drm_mode_vrefresh(panel->fixed_mode);
} else if (drrs->refresh_rate_type == DRRS_LOW_RR) {
seq_puts(m, "DRRS_State: DRRS_LOW_RR\n");
vrefresh = drm_mode_vrefresh(panel->downclock_mode);
} else {
seq_printf(m, "DRRS_State: Unknown(%d)\n",
drrs->refresh_rate_type);
mutex_unlock(&drrs->mutex);
return;
}
seq_printf(m, "\t\tVrefresh: %d", vrefresh);
seq_printf(m, "\tDRRS refresh rate: %s\n",
crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ?
"low" : "high");
seq_puts(m, "\n\t\t");
mutex_unlock(&drrs->mutex);
} else {
/* DRRS not supported. Print the VBT parameter*/
seq_puts(m, "\tDRRS Enabled : No");
mutex_unlock(&crtc->drrs.mutex);
}
seq_puts(m, "\n");
}
static int i915_drrs_status(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct drm_device *dev = &dev_priv->drm;
struct intel_crtc *crtc;
int active_crtc_cnt = 0;
drm_modeset_lock_all(dev);
for_each_intel_crtc(dev, crtc) {
if (crtc->base.state->active) {
active_crtc_cnt++;
seq_printf(m, "\nCRTC %d: ", active_crtc_cnt);
drrs_status_per_crtc(m, dev, crtc);
}
}
drm_modeset_unlock_all(dev);
if (!active_crtc_cnt)
seq_puts(m, "No active crtc found\n");
return 0;
}
@ -1259,7 +1145,7 @@ static int i915_lpsp_status(struct seq_file *m, void *unused)
return 0;
}
seq_printf(m, "LPSP: %s\n", enableddisabled(lpsp_enabled));
seq_printf(m, "LPSP: %s\n", str_enabled_disabled(lpsp_enabled));
return 0;
}
@ -1740,7 +1626,7 @@ static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data)
seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold);
seq_printf(m, "Detected: %s\n",
yesno(delayed_work_pending(&hotplug->reenable_work)));
str_yes_no(delayed_work_pending(&hotplug->reenable_work)));
return 0;
}
@ -1814,7 +1700,7 @@ static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data)
struct drm_i915_private *dev_priv = m->private;
seq_printf(m, "Enabled: %s\n",
yesno(dev_priv->hotplug.hpd_short_storm_enabled));
str_yes_no(dev_priv->hotplug.hpd_short_storm_enabled));
return 0;
}
@ -1888,13 +1774,8 @@ static int i915_drrs_ctl_set(void *data, u64 val)
struct drm_device *dev = &dev_priv->drm;
struct intel_crtc *crtc;
if (DISPLAY_VER(dev_priv) < 7)
return -ENODEV;
for_each_intel_crtc(dev, crtc) {
struct drm_connector_list_iter conn_iter;
struct intel_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_crtc_commit *commit;
int ret;
@ -1915,30 +1796,13 @@ static int i915_drrs_ctl_set(void *data, u64 val)
goto out;
}
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct intel_encoder *encoder;
struct intel_dp *intel_dp;
drm_dbg(&dev_priv->drm,
"Manually %sactivating DRRS\n", val ? "" : "de");
if (!(crtc_state->uapi.connector_mask &
drm_connector_mask(connector)))
continue;
encoder = intel_attached_encoder(to_intel_connector(connector));
if (encoder->type != INTEL_OUTPUT_EDP)
continue;
drm_dbg(&dev_priv->drm,
"Manually %sabling DRRS. %llu\n",
val ? "en" : "dis", val);
intel_dp = enc_to_intel_dp(encoder);
if (val)
intel_drrs_enable(intel_dp, crtc_state);
else
intel_drrs_disable(intel_dp, crtc_state);
}
drm_connector_list_iter_end(&conn_iter);
if (val)
intel_drrs_activate(crtc_state);
else
intel_drrs_deactivate(crtc_state);
out:
drm_modeset_unlock(&crtc->base.mutex);
@ -2020,7 +1884,6 @@ static const struct drm_info_list intel_display_debugfs_list[] = {
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_edp_psr_status", i915_edp_psr_status, 0},
{"i915_power_domain_info", i915_power_domain_info, 0},
{"i915_dmc_info", i915_dmc_info, 0},
{"i915_display_info", i915_display_info, 0},
{"i915_shared_dplls_info", i915_shared_dplls_info, 0},
{"i915_dp_mst_info", i915_dp_mst_info, 0},
@ -2064,6 +1927,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915)
ARRAY_SIZE(intel_display_debugfs_list),
minor->debugfs_root, minor);
intel_dmc_debugfs_register(i915);
intel_fbc_debugfs_register(i915);
}
@ -2209,14 +2073,14 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data)
intel_dp = intel_attached_dp(to_intel_connector(connector));
crtc_state = to_intel_crtc_state(crtc->state);
seq_printf(m, "DSC_Enabled: %s\n",
yesno(crtc_state->dsc.compression_enable));
str_yes_no(crtc_state->dsc.compression_enable));
seq_printf(m, "DSC_Sink_Support: %s\n",
yesno(drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)));
str_yes_no(drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)));
seq_printf(m, "Force_DSC_Enable: %s\n",
yesno(intel_dp->force_dsc_en));
str_yes_no(intel_dp->force_dsc_en));
if (!intel_dp_is_edp(intel_dp))
seq_printf(m, "FEC_Sink_Support: %s\n",
yesno(drm_dp_sink_supports_fec(intel_dp->fec_capable)));
str_yes_no(drm_dp_sink_supports_fec(intel_dp->fec_capable)));
} while (try_again);
drm_modeset_drop_locks(&ctx);

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,11 @@ struct drm_i915_private;
struct i915_power_well;
struct intel_encoder;
/*
* Keep the pipe, transcoder, port (DDI_LANES,DDI_IO,AUX) domain instances
* consecutive, so that the pipe,transcoder,port -> power domain macros
* work correctly.
*/
enum intel_display_power_domain {
POWER_DOMAIN_DISPLAY_CORE,
POWER_DOMAIN_PIPE_A,
@ -29,10 +34,12 @@ enum intel_display_power_domain {
POWER_DOMAIN_TRANSCODER_C,
POWER_DOMAIN_TRANSCODER_D,
POWER_DOMAIN_TRANSCODER_EDP,
/* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */
POWER_DOMAIN_TRANSCODER_VDSC_PW2,
POWER_DOMAIN_TRANSCODER_DSI_A,
POWER_DOMAIN_TRANSCODER_DSI_C,
/* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */
POWER_DOMAIN_TRANSCODER_VDSC_PW2,
POWER_DOMAIN_PORT_DDI_A_LANES,
POWER_DOMAIN_PORT_DDI_B_LANES,
POWER_DOMAIN_PORT_DDI_C_LANES,
@ -125,30 +132,6 @@ enum intel_display_power_domain {
POWER_DOMAIN_NUM,
};
/*
* i915_power_well_id:
*
* IDs used to look up power wells. Power wells accessed directly bypassing
* the power domains framework must be assigned a unique ID. The rest of power
* wells must be assigned DISP_PW_ID_NONE.
*/
enum i915_power_well_id {
DISP_PW_ID_NONE,
VLV_DISP_PW_DISP2D,
BXT_DISP_PW_DPIO_CMN_A,
VLV_DISP_PW_DPIO_CMN_BC,
GLK_DISP_PW_DPIO_CMN_C,
CHV_DISP_PW_DPIO_CMN_D,
HSW_DISP_PW_GLOBAL,
SKL_DISP_PW_MISC_IO,
SKL_DISP_PW_1,
SKL_DISP_PW_2,
ICL_DISP_PW_3,
SKL_DISP_DC_OFF,
TGL_DISP_PW_TC_COLD_OFF,
};
#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER)
@ -232,8 +215,6 @@ intel_display_power_domain_str(enum intel_display_power_domain domain);
bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
enum i915_power_well_id power_well_id);
bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv,

View File

@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2022 Intel Corporation
*/
#include "i915_drv.h"
#include "intel_display_power_well.h"
struct i915_power_well *
lookup_power_well(struct drm_i915_private *i915,
enum i915_power_well_id power_well_id)
{
struct i915_power_well *power_well;
for_each_power_well(i915, power_well)
if (power_well->desc->id == power_well_id)
return power_well;
/*
* It's not feasible to add error checking code to the callers since
* this condition really shouldn't happen and it doesn't even make sense
* to abort things like display initialization sequences. Just return
* the first power well and hope the WARN gets reported so we can fix
* our driver.
*/
drm_WARN(&i915->drm, 1,
"Power well %d not defined for this platform\n",
power_well_id);
return &i915->power_domains.power_wells[0];
}
void intel_power_well_enable(struct drm_i915_private *i915,
struct i915_power_well *power_well)
{
drm_dbg_kms(&i915->drm, "enabling %s\n", power_well->desc->name);
power_well->desc->ops->enable(i915, power_well);
power_well->hw_enabled = true;
}
void intel_power_well_disable(struct drm_i915_private *i915,
struct i915_power_well *power_well)
{
drm_dbg_kms(&i915->drm, "disabling %s\n", power_well->desc->name);
power_well->hw_enabled = false;
power_well->desc->ops->disable(i915, power_well);
}
void intel_power_well_sync_hw(struct drm_i915_private *i915,
struct i915_power_well *power_well)
{
power_well->desc->ops->sync_hw(i915, power_well);
power_well->hw_enabled =
power_well->desc->ops->is_enabled(i915, power_well);
}
void intel_power_well_get(struct drm_i915_private *i915,
struct i915_power_well *power_well)
{
if (!power_well->count++)
intel_power_well_enable(i915, power_well);
}
void intel_power_well_put(struct drm_i915_private *i915,
struct i915_power_well *power_well)
{
drm_WARN(&i915->drm, !power_well->count,
"Use count on power well %s is already zero",
power_well->desc->name);
if (!--power_well->count)
intel_power_well_disable(i915, power_well);
}
bool intel_power_well_is_enabled(struct drm_i915_private *i915,
struct i915_power_well *power_well)
{
return power_well->desc->ops->is_enabled(i915, power_well);
}
bool intel_power_well_is_enabled_cached(struct i915_power_well *power_well)
{
return power_well->hw_enabled;
}
bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
enum i915_power_well_id power_well_id)
{
struct i915_power_well *power_well;
power_well = lookup_power_well(dev_priv, power_well_id);
return intel_power_well_is_enabled(dev_priv, power_well);
}
bool intel_power_well_is_always_on(struct i915_power_well *power_well)
{
return power_well->desc->always_on;
}
const char *intel_power_well_name(struct i915_power_well *power_well)
{
return power_well->desc->name;
}
u64 intel_power_well_domains(struct i915_power_well *power_well)
{
return power_well->desc->domains;
}
int intel_power_well_refcount(struct i915_power_well *power_well)
{
return power_well->count;
}

View File

@ -0,0 +1,153 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022 Intel Corporation
*/
#ifndef __INTEL_DISPLAY_POWER_WELL_H__
#define __INTEL_DISPLAY_POWER_WELL_H__
#include <linux/types.h>
#include "intel_display.h"
struct drm_i915_private;
struct i915_power_well;
/*
* i915_power_well_id:
*
* IDs used to look up power wells. Power wells accessed directly bypassing
* the power domains framework must be assigned a unique ID. The rest of power
* wells must be assigned DISP_PW_ID_NONE.
*/
enum i915_power_well_id {
DISP_PW_ID_NONE,
VLV_DISP_PW_DISP2D,
BXT_DISP_PW_DPIO_CMN_A,
VLV_DISP_PW_DPIO_CMN_BC,
GLK_DISP_PW_DPIO_CMN_C,
CHV_DISP_PW_DPIO_CMN_D,
HSW_DISP_PW_GLOBAL,
SKL_DISP_PW_MISC_IO,
SKL_DISP_PW_1,
SKL_DISP_PW_2,
ICL_DISP_PW_3,
SKL_DISP_DC_OFF,
TGL_DISP_PW_TC_COLD_OFF,
};
struct i915_power_well_regs {
i915_reg_t bios;
i915_reg_t driver;
i915_reg_t kvmr;
i915_reg_t debug;
};
struct i915_power_well_ops {
const struct i915_power_well_regs *regs;
/*
* Synchronize the well's hw state to match the current sw state, for
* example enable/disable it based on the current refcount. Called
* during driver init and resume time, possibly after first calling
* the enable/disable handlers.
*/
void (*sync_hw)(struct drm_i915_private *i915,
struct i915_power_well *power_well);
/*
* Enable the well and resources that depend on it (for example
* interrupts located on the well). Called after the 0->1 refcount
* transition.
*/
void (*enable)(struct drm_i915_private *i915,
struct i915_power_well *power_well);
/*
* Disable the well and resources that depend on it. Called after
* the 1->0 refcount transition.
*/
void (*disable)(struct drm_i915_private *i915,
struct i915_power_well *power_well);
/* Returns the hw enabled state. */
bool (*is_enabled)(struct drm_i915_private *i915,
struct i915_power_well *power_well);
};
struct i915_power_well_desc {
const char *name;
bool always_on;
u64 domains;
/* unique identifier for this power well */
enum i915_power_well_id id;
/*
* Arbitraty data associated with this power well. Platform and power
* well specific.
*/
union {
struct {
/*
* request/status flag index in the PUNIT power well
* control/status registers.
*/
u8 idx;
} vlv;
struct {
enum dpio_phy phy;
} bxt;
struct {
/*
* request/status flag index in the power well
* constrol/status registers.
*/
u8 idx;
/* Mask of pipes whose IRQ logic is backed by the pw */
u8 irq_pipe_mask;
/*
* Instead of waiting for the status bit to ack enables,
* just wait a specific amount of time and then consider
* the well enabled.
*/
u16 fixed_enable_delay;
/* The pw is backing the VGA functionality */
bool has_vga:1;
bool has_fuses:1;
/*
* The pw is for an ICL+ TypeC PHY port in
* Thunderbolt mode.
*/
bool is_tc_tbt:1;
} hsw;
};
const struct i915_power_well_ops *ops;
};
struct i915_power_well {
const struct i915_power_well_desc *desc;
/* power well enable/disable usage count */
int count;
/* cached hw enabled state */
bool hw_enabled;
};
struct i915_power_well *lookup_power_well(struct drm_i915_private *i915,
enum i915_power_well_id id);
void intel_power_well_enable(struct drm_i915_private *i915,
struct i915_power_well *power_well);
void intel_power_well_disable(struct drm_i915_private *i915,
struct i915_power_well *power_well);
void intel_power_well_sync_hw(struct drm_i915_private *i915,
struct i915_power_well *power_well);
void intel_power_well_get(struct drm_i915_private *i915,
struct i915_power_well *power_well);
void intel_power_well_put(struct drm_i915_private *i915,
struct i915_power_well *power_well);
bool intel_power_well_is_enabled(struct drm_i915_private *i915,
struct i915_power_well *power_well);
bool intel_power_well_is_enabled_cached(struct i915_power_well *power_well);
bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
enum i915_power_well_id power_well_id);
bool intel_power_well_is_always_on(struct i915_power_well *power_well);
const char *intel_power_well_name(struct i915_power_well *power_well);
u64 intel_power_well_domains(struct i915_power_well *power_well);
int intel_power_well_refcount(struct i915_power_well *power_well);
#endif

View File

@ -9,6 +9,7 @@
#if !defined(__INTEL_DISPLAY_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
#define __INTEL_DISPLAY_TRACE_H__
#include <linux/string_helpers.h>
#include <linux/types.h>
#include <linux/tracepoint.h>
@ -161,7 +162,7 @@ TRACE_EVENT(intel_memory_cxsr,
),
TP_printk("%s->%s, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
onoff(__entry->old), onoff(__entry->new),
str_on_off(__entry->old), str_on_off(__entry->new),
__entry->frame[PIPE_A], __entry->scanline[PIPE_A],
__entry->frame[PIPE_B], __entry->scanline[PIPE_B],
__entry->frame[PIPE_C], __entry->scanline[PIPE_C])
@ -210,9 +211,9 @@ TRACE_EVENT(g4x_wm,
TP_printk("pipe %c, frame=%u, scanline=%u, wm %d/%d/%d, sr %s/%d/%d/%d, hpll %s/%d/%d/%d, fbc %s",
pipe_name(__entry->pipe), __entry->frame, __entry->scanline,
__entry->primary, __entry->sprite, __entry->cursor,
yesno(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc,
yesno(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc,
yesno(__entry->fbc))
str_yes_no(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc,
str_yes_no(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc,
str_yes_no(__entry->fbc))
);
TRACE_EVENT(vlv_wm,

View File

@ -280,8 +280,7 @@ struct intel_panel_bl_funcs {
};
struct intel_panel {
struct drm_display_mode *fixed_mode;
struct drm_display_mode *downclock_mode;
struct list_head fixed_modes;
/* backlight */
struct {
@ -847,8 +846,13 @@ struct intel_crtc_wm_state {
/* gen9+ only needs 1-step wm programming */
struct skl_pipe_wm optimal;
struct skl_ddb_entry ddb;
/*
* pre-icl: for packed/planar CbCr
* icl+: for everything
*/
struct skl_ddb_entry plane_ddb[I915_MAX_PLANES];
/* pre-icl: for planar Y */
struct skl_ddb_entry plane_ddb_y[I915_MAX_PLANES];
struct skl_ddb_entry plane_ddb_uv[I915_MAX_PLANES];
} skl;
struct {
@ -954,7 +958,7 @@ struct intel_crtc_state {
/* Pipe source size (ie. panel fitter input size)
* All planes will be positioned inside this space,
* and get clipped at the edges. */
int pipe_src_w, pipe_src_h;
struct drm_rect pipe_src;
/*
* Pipe pixel rate, adjusted for
@ -1125,11 +1129,14 @@ struct intel_crtc_state {
int min_cdclk[I915_MAX_PLANES];
/* for packed/planar CbCr */
u32 data_rate[I915_MAX_PLANES];
/* for planar Y */
u32 data_rate_y[I915_MAX_PLANES];
/* FIXME unify with data_rate[] */
u64 plane_data_rate[I915_MAX_PLANES];
u64 uv_plane_data_rate[I915_MAX_PLANES];
/* FIXME unify with data_rate[]? */
u64 rel_data_rate[I915_MAX_PLANES];
u64 rel_data_rate_y[I915_MAX_PLANES];
/* Gamma mode programmed on the pipe */
u32 gamma_mode;
@ -1154,6 +1161,9 @@ struct intel_crtc_state {
/* bitmask of planes that will be updated during the commit */
u8 update_planes;
u8 framestart_delay; /* 1-4 */
u8 msa_timing_delay; /* 0-3 */
struct {
u32 enable;
u32 gcp;
@ -1179,9 +1189,6 @@ struct intel_crtc_state {
/* enable pipe csc? */
bool csc_enable;
/* enable pipe big joiner? */
bool bigjoiner;
/* big joiner pipe bitmask */
u8 bigjoiner_pipes;
@ -1252,6 +1259,11 @@ enum intel_pipe_crc_source {
INTEL_PIPE_CRC_SOURCE_MAX,
};
enum drrs_refresh_rate {
DRRS_REFRESH_RATE_HIGH,
DRRS_REFRESH_RATE_LOW,
};
#define INTEL_PIPE_CRC_ENTRIES_NR 128
struct intel_pipe_crc {
spinlock_t lock;
@ -1294,6 +1306,16 @@ struct intel_crtc {
} active;
} wm;
struct {
struct mutex mutex;
struct delayed_work work;
enum drrs_refresh_rate refresh_rate;
unsigned int frontbuffer_bits;
unsigned int busy_frontbuffer_bits;
enum transcoder cpu_transcoder;
struct intel_link_m_n m_n, m2_n2;
} drrs;
int scanline_offset;
struct {
@ -1503,6 +1525,7 @@ struct intel_psr {
bool colorimetry_support;
bool psr2_enabled;
bool psr2_sel_fetch_enabled;
bool psr2_sel_fetch_cff_enabled;
bool req_psr2_sdp_prior_scanline;
u8 sink_sync_latency;
ktime_t last_entry_attempt;

View File

@ -28,6 +28,7 @@
#include "i915_reg.h"
#include "intel_de.h"
#include "intel_dmc.h"
#include "intel_dmc_regs.h"
/**
* DOC: DMC Firmware Support
@ -37,6 +38,10 @@
* low-power state and comes back to normal.
*/
#define DMC_VERSION(major, minor) ((major) << 16 | (minor))
#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" \
@ -47,8 +52,8 @@
#define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE
#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 14)
#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 14)
#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 16)
#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 16)
MODULE_FIRMWARE(ADLP_DMC_PATH);
#define ADLS_DMC_PATH DMC_PATH(adls, 2, 01)
@ -276,17 +281,8 @@ void intel_dmc_load_program(struct drm_i915_private *dev_priv)
struct intel_dmc *dmc = &dev_priv->dmc;
u32 id, i;
if (!HAS_DMC(dev_priv)) {
drm_err(&dev_priv->drm,
"No DMC support available for this platform\n");
if (!intel_dmc_has_payload(dev_priv))
return;
}
if (!dev_priv->dmc.dmc_info[DMC_FW_MAIN].payload) {
drm_err(&dev_priv->drm,
"Tried to program CSR with empty payload\n");
return;
}
assert_rpm_wakelock_held(&dev_priv->runtime_pm);
@ -314,6 +310,17 @@ void intel_dmc_load_program(struct drm_i915_private *dev_priv)
gen9_set_dc_state_debugmask(dev_priv);
}
void assert_dmc_loaded(struct drm_i915_private *i915)
{
drm_WARN_ONCE(&i915->drm,
!intel_de_read(i915, DMC_PROGRAM(i915->dmc.dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)),
"DMC program storage start is NULL\n");
drm_WARN_ONCE(&i915->drm, !intel_de_read(i915, DMC_SSP_BASE),
"DMC SSP Base Not fine\n");
drm_WARN_ONCE(&i915->drm, !intel_de_read(i915, DMC_HTP_SKL),
"DMC HTP Not fine\n");
}
static bool fw_info_matches_stepping(const struct intel_fw_info *fw_info,
const struct stepping_info *si)
{
@ -697,7 +704,7 @@ void intel_dmc_ucode_init(struct drm_i915_private *dev_priv)
dmc->fw_path = RKL_DMC_PATH;
dmc->required_version = RKL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE;
} else if (DISPLAY_VER(dev_priv) >= 12) {
} else if (IS_TIGERLAKE(dev_priv)) {
dmc->fw_path = TGL_DMC_PATH;
dmc->required_version = TGL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE;
@ -808,3 +815,101 @@ void intel_dmc_ucode_fini(struct drm_i915_private *dev_priv)
for (id = 0; id < DMC_FW_MAX; id++)
kfree(dev_priv->dmc.dmc_info[id].payload);
}
void intel_dmc_print_error_state(struct drm_i915_error_state_buf *m,
struct drm_i915_private *i915)
{
struct intel_dmc *dmc = &i915->dmc;
if (!HAS_DMC(i915))
return;
i915_error_printf(m, "DMC loaded: %s\n",
str_yes_no(intel_dmc_has_payload(i915)));
i915_error_printf(m, "DMC fw version: %d.%d\n",
DMC_VERSION_MAJOR(dmc->version),
DMC_VERSION_MINOR(dmc->version));
}
static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused)
{
struct drm_i915_private *i915 = m->private;
intel_wakeref_t wakeref;
struct intel_dmc *dmc;
i915_reg_t dc5_reg, dc6_reg = INVALID_MMIO_REG;
if (!HAS_DMC(i915))
return -ENODEV;
dmc = &i915->dmc;
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
seq_printf(m, "fw loaded: %s\n",
str_yes_no(intel_dmc_has_payload(i915)));
seq_printf(m, "path: %s\n", dmc->fw_path);
seq_printf(m, "Pipe A fw support: %s\n",
str_yes_no(GRAPHICS_VER(i915) >= 12));
seq_printf(m, "Pipe A fw loaded: %s\n",
str_yes_no(dmc->dmc_info[DMC_FW_PIPEA].payload));
seq_printf(m, "Pipe B fw support: %s\n",
str_yes_no(IS_ALDERLAKE_P(i915)));
seq_printf(m, "Pipe B fw loaded: %s\n",
str_yes_no(dmc->dmc_info[DMC_FW_PIPEB].payload));
if (!intel_dmc_has_payload(i915))
goto out;
seq_printf(m, "version: %d.%d\n", DMC_VERSION_MAJOR(dmc->version),
DMC_VERSION_MINOR(dmc->version));
if (DISPLAY_VER(i915) >= 12) {
if (IS_DGFX(i915)) {
dc5_reg = DG1_DMC_DEBUG_DC5_COUNT;
} else {
dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
}
/*
* NOTE: DMC_DEBUG3 is a general purpose reg.
* According to B.Specs:49196 DMC f/w reuses DC5/6 counter
* reg for DC3CO debugging and validation,
* but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter.
*/
seq_printf(m, "DC3CO count: %d\n",
intel_de_read(i915, IS_DGFX(i915) ?
DG1_DMC_DEBUG3 : TGL_DMC_DEBUG3));
} else {
dc5_reg = IS_BROXTON(i915) ? BXT_DMC_DC3_DC5_COUNT :
SKL_DMC_DC3_DC5_COUNT;
if (!IS_GEMINILAKE(i915) && !IS_BROXTON(i915))
dc6_reg = SKL_DMC_DC5_DC6_COUNT;
}
seq_printf(m, "DC3 -> DC5 count: %d\n", intel_de_read(i915, dc5_reg));
if (i915_mmio_reg_valid(dc6_reg))
seq_printf(m, "DC5 -> DC6 count: %d\n",
intel_de_read(i915, dc6_reg));
out:
seq_printf(m, "program base: 0x%08x\n",
intel_de_read(i915, DMC_PROGRAM(dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)));
seq_printf(m, "ssp base: 0x%08x\n",
intel_de_read(i915, DMC_SSP_BASE));
seq_printf(m, "htp: 0x%08x\n", intel_de_read(i915, DMC_HTP_SKL));
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(intel_dmc_debugfs_status);
void intel_dmc_debugfs_register(struct drm_i915_private *i915)
{
struct drm_minor *minor = i915->drm.primary;
debugfs_create_file("i915_dmc_info", 0444, minor->debugfs_root,
i915, &intel_dmc_debugfs_status_fops);
}

View File

@ -10,12 +10,9 @@
#include "intel_wakeref.h"
#include <linux/workqueue.h>
struct drm_i915_error_state_buf;
struct drm_i915_private;
#define DMC_VERSION(major, minor) ((major) << 16 | (minor))
#define DMC_VERSION_MAJOR(version) ((version) >> 16)
#define DMC_VERSION_MINOR(version) ((version) & 0xffff)
enum {
DMC_FW_MAIN = 0,
DMC_FW_PIPEA,
@ -54,5 +51,10 @@ 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);
bool intel_dmc_has_payload(struct drm_i915_private *i915);
void intel_dmc_debugfs_register(struct drm_i915_private *i915);
void intel_dmc_print_error_state(struct drm_i915_error_state_buf *m,
struct drm_i915_private *i915);
void assert_dmc_loaded(struct drm_i915_private *i915);
#endif /* __INTEL_DMC_H__ */

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022 Intel Corporation
*/
#ifndef __INTEL_DMC_REGS_H__
#define __INTEL_DMC_REGS_H__
#include "i915_reg_defs.h"
#define DMC_PROGRAM(addr, i) _MMIO((addr) + (i) * 4)
#define DMC_SSP_BASE_ADDR_GEN9 0x00002FC0
#define DMC_HTP_ADDR_SKL 0x00500034
#define DMC_SSP_BASE _MMIO(0x8F074)
#define DMC_HTP_SKL _MMIO(0x8F004)
#define DMC_LAST_WRITE _MMIO(0x8F034)
#define DMC_LAST_WRITE_VALUE 0xc003b400
#define DMC_MMIO_START_RANGE 0x80000
#define DMC_MMIO_END_RANGE 0x8FFFF
#define SKL_DMC_DC3_DC5_COUNT _MMIO(0x80030)
#define SKL_DMC_DC5_DC6_COUNT _MMIO(0x8002C)
#define BXT_DMC_DC3_DC5_COUNT _MMIO(0x80038)
#define TGL_DMC_DEBUG_DC5_COUNT _MMIO(0x101084)
#define TGL_DMC_DEBUG_DC6_COUNT _MMIO(0x101088)
#define DG1_DMC_DEBUG_DC5_COUNT _MMIO(0x134154)
#define TGL_DMC_DEBUG3 _MMIO(0x101090)
#define DG1_DMC_DEBUG3 _MMIO(0x13415c)
#endif /* __INTEL_DMC_REGS_H__ */

View File

@ -29,6 +29,7 @@
#include <linux/i2c.h>
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/timekeeping.h>
#include <linux/types.h>
@ -59,7 +60,6 @@
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_drrs.h"
#include "intel_fifo_underrun.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
@ -67,6 +67,7 @@
#include "intel_lspcon.h"
#include "intel_lvds.h"
#include "intel_panel.h"
#include "intel_pch_display.h"
#include "intel_pps.h"
#include "intel_psr.h"
#include "intel_tc.h"
@ -386,23 +387,13 @@ static int dg2_max_source_rate(struct intel_dp *intel_dp)
return intel_dp_is_edp(intel_dp) ? 810000 : 1350000;
}
static bool is_low_voltage_sku(struct drm_i915_private *i915, enum phy phy)
{
u32 voltage;
voltage = intel_de_read(i915, ICL_PORT_COMP_DW3(phy)) & VOLTAGE_INFO_MASK;
return voltage == VOLTAGE_INFO_0_85V;
}
static int icl_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_phy_is_combo(dev_priv, phy) &&
(is_low_voltage_sku(dev_priv, phy) || !intel_dp_is_edp(intel_dp)))
if (intel_phy_is_combo(dev_priv, phy) && !intel_dp_is_edp(intel_dp))
return 540000;
return 810000;
@ -410,23 +401,7 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
static int ehl_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_dp_is_edp(intel_dp) || is_low_voltage_sku(dev_priv, phy))
return 540000;
return 810000;
}
static int dg1_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
if (intel_phy_is_combo(i915, phy) && is_low_voltage_sku(i915, phy))
if (intel_dp_is_edp(intel_dp))
return 540000;
return 810000;
@ -469,7 +444,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
max_rate = dg2_max_source_rate(intel_dp);
else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) ||
IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
max_rate = dg1_max_source_rate(intel_dp);
max_rate = 810000;
else if (IS_JSL_EHL(dev_priv))
max_rate = ehl_max_source_rate(intel_dp);
else
@ -580,8 +555,9 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
int link_rate,
u8 lane_count)
{
/* FIXME figure out what we actually want here */
const struct drm_display_mode *fixed_mode =
intel_dp->attached_connector->panel.fixed_mode;
intel_panel_preferred_fixed_mode(intel_dp->attached_connector);
int mode_rate, max_rate;
mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
@ -783,14 +759,12 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
}
static enum intel_output_format
intel_dp_output_format(struct drm_connector *connector,
const struct drm_display_mode *mode)
intel_dp_output_format(struct intel_connector *connector,
bool ycbcr_420_output)
{
struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector));
const struct drm_display_info *info = &connector->display_info;
struct intel_dp *intel_dp = intel_attached_dp(connector);
if (!connector->ycbcr_420_allowed ||
!drm_mode_is_420_only(info, mode))
if (!connector->base.ycbcr_420_allowed || !ycbcr_420_output)
return INTEL_OUTPUT_FORMAT_RGB;
if (intel_dp->dfp.rgb_to_ycbcr &&
@ -825,11 +799,12 @@ static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp)
}
static int
intel_dp_mode_min_output_bpp(struct drm_connector *connector,
intel_dp_mode_min_output_bpp(struct intel_connector *connector,
const struct drm_display_mode *mode)
{
const struct drm_display_info *info = &connector->base.display_info;
enum intel_output_format output_format =
intel_dp_output_format(connector, mode);
intel_dp_output_format(connector, drm_mode_is_420_only(info, mode));
return intel_dp_output_bpp(output_format, intel_dp_min_bpp(output_format));
}
@ -853,6 +828,43 @@ static bool intel_dp_hdisplay_bad(struct drm_i915_private *dev_priv,
return hdisplay == 4096 && !HAS_DDI(dev_priv);
}
static int intel_dp_max_tmds_clock(struct intel_dp *intel_dp)
{
struct intel_connector *connector = intel_dp->attached_connector;
const struct drm_display_info *info = &connector->base.display_info;
int max_tmds_clock = intel_dp->dfp.max_tmds_clock;
/* Only consider the sink's max TMDS clock if we know this is a HDMI DFP */
if (max_tmds_clock && info->max_tmds_clock)
max_tmds_clock = min(max_tmds_clock, info->max_tmds_clock);
return max_tmds_clock;
}
static enum drm_mode_status
intel_dp_tmds_clock_valid(struct intel_dp *intel_dp,
int clock, int bpc, bool ycbcr420_output,
bool respect_downstream_limits)
{
int tmds_clock, min_tmds_clock, max_tmds_clock;
if (!respect_downstream_limits)
return MODE_OK;
tmds_clock = intel_hdmi_tmds_clock(clock, bpc, ycbcr420_output);
min_tmds_clock = intel_dp->dfp.min_tmds_clock;
max_tmds_clock = intel_dp_max_tmds_clock(intel_dp);
if (min_tmds_clock && tmds_clock < min_tmds_clock)
return MODE_CLOCK_LOW;
if (max_tmds_clock && tmds_clock > max_tmds_clock)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static enum drm_mode_status
intel_dp_mode_valid_downstream(struct intel_connector *connector,
const struct drm_display_mode *mode,
@ -860,13 +872,14 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
{
struct intel_dp *intel_dp = intel_attached_dp(connector);
const struct drm_display_info *info = &connector->base.display_info;
int tmds_clock;
enum drm_mode_status status;
bool ycbcr_420_only;
/* If PCON supports FRL MODE, check FRL bandwidth constraints */
if (intel_dp->dfp.pcon_max_frl_bw) {
int target_bw;
int max_frl_bw;
int bpp = intel_dp_mode_min_output_bpp(&connector->base, mode);
int bpp = intel_dp_mode_min_output_bpp(connector, mode);
target_bw = bpp * target_clock;
@ -885,16 +898,23 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
target_clock > intel_dp->dfp.max_dotclock)
return MODE_CLOCK_HIGH;
/* Assume 8bpc for the DP++/HDMI/DVI TMDS clock check */
tmds_clock = intel_hdmi_tmds_clock(target_clock, 8,
drm_mode_is_420_only(info, mode));
ycbcr_420_only = drm_mode_is_420_only(info, mode);
if (intel_dp->dfp.min_tmds_clock &&
tmds_clock < intel_dp->dfp.min_tmds_clock)
return MODE_CLOCK_LOW;
if (intel_dp->dfp.max_tmds_clock &&
tmds_clock > intel_dp->dfp.max_tmds_clock)
return MODE_CLOCK_HIGH;
/* Assume 8bpc for the DP++/HDMI/DVI TMDS clock check */
status = intel_dp_tmds_clock_valid(intel_dp, target_clock,
8, ycbcr_420_only, true);
if (status != MODE_OK) {
if (ycbcr_420_only ||
!connector->base.ycbcr_420_allowed ||
!drm_mode_is_420_also(info, mode))
return status;
status = intel_dp_tmds_clock_valid(intel_dp, target_clock,
8, true, true);
if (status != MODE_OK)
return status;
}
return MODE_OK;
}
@ -911,13 +931,13 @@ static bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
}
static enum drm_mode_status
intel_dp_mode_valid(struct drm_connector *connector,
intel_dp_mode_valid(struct drm_connector *_connector,
struct drm_display_mode *mode)
{
struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector));
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_connector *connector = to_intel_connector(_connector);
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
const struct drm_display_mode *fixed_mode;
int target_clock = mode->clock;
int max_rate, mode_rate, max_lanes, max_link_clock;
int max_dotclk = dev_priv->max_dotclk_freq;
@ -932,8 +952,9 @@ intel_dp_mode_valid(struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_H_ILLEGAL;
fixed_mode = intel_panel_fixed_mode(connector, mode);
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
status = intel_panel_mode_valid(intel_connector, mode);
status = intel_panel_mode_valid(connector, mode);
if (status != MODE_OK)
return status;
@ -1007,8 +1028,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
if (mode_rate > max_rate && !dsc)
return MODE_CLOCK_HIGH;
status = intel_dp_mode_valid_downstream(intel_connector,
mode, target_clock);
status = intel_dp_mode_valid_downstream(connector, mode, target_clock);
if (status != MODE_OK)
return status;
@ -1130,44 +1150,50 @@ static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
}
static bool intel_dp_hdmi_ycbcr420(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
static bool intel_dp_is_ycbcr420(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
(crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 &&
intel_dp->dfp.ycbcr_444_to_420);
}
static bool intel_dp_hdmi_tmds_clock_valid(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state, int bpc)
static int intel_dp_hdmi_compute_bpc(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
int bpc, bool respect_downstream_limits)
{
bool ycbcr420_output = intel_dp_is_ycbcr420(intel_dp, crtc_state);
int clock = crtc_state->hw.adjusted_mode.crtc_clock;
int tmds_clock = intel_hdmi_tmds_clock(clock, bpc,
intel_dp_hdmi_ycbcr420(intel_dp, crtc_state));
if (intel_dp->dfp.min_tmds_clock &&
tmds_clock < intel_dp->dfp.min_tmds_clock)
return false;
/*
* Current bpc could already be below 8bpc due to
* FDI bandwidth constraints or other limits.
* HDMI minimum is 8bpc however.
*/
bpc = max(bpc, 8);
if (intel_dp->dfp.max_tmds_clock &&
tmds_clock > intel_dp->dfp.max_tmds_clock)
return false;
/*
* We will never exceed downstream TMDS clock limits while
* attempting deep color. If the user insists on forcing an
* out of spec mode they will have to be satisfied with 8bpc.
*/
if (!respect_downstream_limits)
bpc = 8;
return true;
}
for (; bpc >= 8; bpc -= 2) {
if (intel_hdmi_bpc_possible(crtc_state, bpc,
intel_dp->has_hdmi_sink, ycbcr420_output) &&
intel_dp_tmds_clock_valid(intel_dp, clock, bpc, ycbcr420_output,
respect_downstream_limits) == MODE_OK)
return bpc;
}
static bool intel_dp_hdmi_bpc_possible(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
int bpc)
{
return intel_hdmi_bpc_possible(crtc_state, bpc, intel_dp->has_hdmi_sink,
intel_dp_hdmi_ycbcr420(intel_dp, crtc_state)) &&
intel_dp_hdmi_tmds_clock_valid(intel_dp, crtc_state, bpc);
return -EINVAL;
}
static int intel_dp_max_bpp(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
const struct intel_crtc_state *crtc_state,
bool respect_downstream_limits)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_connector *intel_connector = intel_dp->attached_connector;
@ -1179,10 +1205,14 @@ static int intel_dp_max_bpp(struct intel_dp *intel_dp,
bpc = min_t(int, bpc, intel_dp->dfp.max_bpc);
if (intel_dp->dfp.min_tmds_clock) {
for (; bpc >= 10; bpc -= 2) {
if (intel_dp_hdmi_bpc_possible(intel_dp, crtc_state, bpc))
break;
}
int max_hdmi_bpc;
max_hdmi_bpc = intel_dp_hdmi_compute_bpc(intel_dp, crtc_state, bpc,
respect_downstream_limits);
if (max_hdmi_bpc < 0)
return 0;
bpc = min(bpc, max_hdmi_bpc);
}
bpp = bpc * 3;
@ -1424,13 +1454,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
pipe_config->lane_count,
adjusted_mode->crtc_clock,
adjusted_mode->crtc_hdisplay,
pipe_config->bigjoiner,
pipe_config->bigjoiner_pipes,
pipe_bpp);
dsc_dp_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
adjusted_mode->crtc_clock,
adjusted_mode->crtc_hdisplay,
pipe_config->bigjoiner);
pipe_config->bigjoiner_pipes);
if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
drm_dbg_kms(&dev_priv->drm,
"Compressed BPP/Slice Count not supported\n");
@ -1464,7 +1494,7 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
* then we need to use 2 VDSC instances.
*/
if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq ||
pipe_config->bigjoiner) {
pipe_config->bigjoiner_pipes) {
if (pipe_config->dsc.slice_count < 2) {
drm_dbg_kms(&dev_priv->drm,
"Cannot split stream to use 2 VDSC instances\n");
@ -1497,13 +1527,16 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
static int
intel_dp_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
struct drm_connector_state *conn_state,
bool respect_downstream_limits)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
const struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct link_config_limits limits;
bool joiner_needs_dsc = false;
int ret;
limits.min_rate = intel_dp_common_rate(intel_dp, 0);
@ -1513,7 +1546,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format);
limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config);
limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config, respect_downstream_limits);
if (intel_dp->use_max_params) {
/*
@ -1537,7 +1570,14 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
adjusted_mode->crtc_clock))
pipe_config->bigjoiner = true;
pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
/*
* Pipe joiner needs compression up to display 12 due to bandwidth
* limitation. DG2 onwards pipe joiner can be enabled without
* compression.
*/
joiner_needs_dsc = DISPLAY_VER(i915) < 13 && pipe_config->bigjoiner_pipes;
/*
* Optimize for slow and wide for everything, because there are some
@ -1545,13 +1585,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
*/
ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits);
/*
* Pipe joiner needs compression upto display12 due to BW limitation. DG2
* onwards pipe joiner can be enabled without compression.
*/
drm_dbg_kms(&i915->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en);
if (ret || intel_dp->force_dsc_en || (DISPLAY_VER(i915) < 13 &&
pipe_config->bigjoiner)) {
if (ret || joiner_needs_dsc || intel_dp->force_dsc_en) {
drm_dbg_kms(&i915->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n",
str_yes_no(ret), str_yes_no(joiner_needs_dsc),
str_yes_no(intel_dp->force_dsc_en));
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
conn_state, &limits);
if (ret < 0)
@ -1786,6 +1823,137 @@ intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp,
intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
}
static bool cpu_transcoder_has_drrs(struct drm_i915_private *i915,
enum transcoder cpu_transcoder)
{
/* M1/N1 is double buffered */
if (DISPLAY_VER(i915) >= 9 || IS_BROADWELL(i915))
return true;
return intel_cpu_transcoder_has_m2_n2(i915, cpu_transcoder);
}
static bool can_enable_drrs(struct intel_connector *connector,
const struct intel_crtc_state *pipe_config,
const struct drm_display_mode *downclock_mode)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
if (pipe_config->vrr.enable)
return false;
/*
* DRRS and PSR can't be enable together, so giving preference to PSR
* as it allows more power-savings by complete shutting down display,
* so to guarantee this, intel_drrs_compute_config() must be called
* after intel_psr_compute_config().
*/
if (pipe_config->has_psr)
return false;
/* FIXME missing FDI M2/N2 etc. */
if (pipe_config->has_pch_encoder)
return false;
if (!cpu_transcoder_has_drrs(i915, pipe_config->cpu_transcoder))
return false;
return downclock_mode &&
intel_panel_drrs_type(connector) == DRRS_TYPE_SEAMLESS;
}
static void
intel_dp_drrs_compute_config(struct intel_connector *connector,
struct intel_crtc_state *pipe_config,
int output_bpp, bool constant_n)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
const struct drm_display_mode *downclock_mode =
intel_panel_downclock_mode(connector, &pipe_config->hw.adjusted_mode);
int pixel_clock;
if (!can_enable_drrs(connector, pipe_config, downclock_mode)) {
if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder))
intel_zero_m_n(&pipe_config->dp_m2_n2);
return;
}
if (IS_IRONLAKE(i915) || IS_SANDYBRIDGE(i915) || IS_IVYBRIDGE(i915))
pipe_config->msa_timing_delay = i915->vbt.edp.drrs_msa_timing_delay;
pipe_config->has_drrs = true;
pixel_clock = downclock_mode->clock;
if (pipe_config->splitter.enable)
pixel_clock /= pipe_config->splitter.link_count;
intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock,
pipe_config->port_clock, &pipe_config->dp_m2_n2,
constant_n, pipe_config->fec_enable);
/* FIXME: abstract this better */
if (pipe_config->splitter.enable)
pipe_config->dp_m2_n2.data_m *= pipe_config->splitter.link_count;
}
static bool intel_dp_has_audio(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_dp *intel_dp = enc_to_intel_dp(encoder);
const struct intel_digital_connector_state *intel_conn_state =
to_intel_digital_connector_state(conn_state);
if (!intel_dp_port_has_audio(i915, encoder->port))
return false;
if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
return intel_dp->has_audio;
else
return intel_conn_state->force_audio == HDMI_AUDIO_ON;
}
static int
intel_dp_compute_output_format(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state,
bool respect_downstream_limits)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_connector *connector = intel_dp->attached_connector;
const struct drm_display_info *info = &connector->base.display_info;
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
bool ycbcr_420_only;
int ret;
ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode);
crtc_state->output_format = intel_dp_output_format(connector, ycbcr_420_only);
if (ycbcr_420_only && !intel_dp_is_ycbcr420(intel_dp, crtc_state)) {
drm_dbg_kms(&i915->drm,
"YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n");
crtc_state->output_format = INTEL_OUTPUT_FORMAT_RGB;
}
ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state,
respect_downstream_limits);
if (ret) {
if (intel_dp_is_ycbcr420(intel_dp, crtc_state) ||
!connector->base.ycbcr_420_allowed ||
!drm_mode_is_420_also(info, adjusted_mode))
return ret;
crtc_state->output_format = intel_dp_output_format(connector, true);
ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state,
respect_downstream_limits);
}
return ret;
}
int
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@ -1794,38 +1962,19 @@ intel_dp_compute_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
enum port port = encoder->port;
struct intel_connector *intel_connector = intel_dp->attached_connector;
struct intel_digital_connector_state *intel_conn_state =
to_intel_digital_connector_state(conn_state);
const struct drm_display_mode *fixed_mode;
struct intel_connector *connector = intel_dp->attached_connector;
bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N);
int ret = 0, output_bpp;
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A)
pipe_config->has_pch_encoder = true;
pipe_config->output_format = intel_dp_output_format(&intel_connector->base,
adjusted_mode);
pipe_config->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state);
if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
}
if (!intel_dp_port_has_audio(dev_priv, port))
pipe_config->has_audio = false;
else if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
pipe_config->has_audio = intel_dp->has_audio;
else
pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
ret = intel_panel_compute_config(intel_connector, adjusted_mode);
if (ret)
return ret;
ret = intel_panel_fitting(pipe_config, conn_state);
fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode);
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
ret = intel_panel_compute_config(connector, adjusted_mode);
if (ret)
return ret;
}
@ -1843,10 +1992,23 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (intel_dp_hdisplay_bad(dev_priv, adjusted_mode->crtc_hdisplay))
return -EINVAL;
ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state);
if (ret < 0)
/*
* Try to respect downstream TMDS clock limits first, if
* that fails assume the user might know something we don't.
*/
ret = intel_dp_compute_output_format(encoder, pipe_config, conn_state, true);
if (ret)
ret = intel_dp_compute_output_format(encoder, pipe_config, conn_state, false);
if (ret)
return ret;
if ((intel_dp_is_edp(intel_dp) && fixed_mode) ||
pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
}
pipe_config->limited_color_range =
intel_dp_limited_color_range(pipe_config, conn_state);
@ -1892,8 +2054,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
intel_vrr_compute_config(pipe_config, conn_state);
intel_psr_compute_config(intel_dp, pipe_config, conn_state);
intel_drrs_compute_config(intel_dp, pipe_config, output_bpp,
constant_n);
intel_dp_drrs_compute_config(connector, pipe_config,
output_bpp, constant_n);
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
@ -1976,7 +2138,7 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
if (ret < 0)
drm_dbg_kms(&i915->drm,
"Failed to %s sink decompression state\n",
enabledisable(enable));
str_enable_disable(enable));
}
static void
@ -2452,7 +2614,7 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_PROTOCOL_CONVERTER_CONTROL_0, tmp) != 1)
drm_dbg_kms(&i915->drm, "Failed to %s protocol converter HDMI mode\n",
enabledisable(intel_dp->has_hdmi_sink));
str_enable_disable(intel_dp->has_hdmi_sink));
tmp = crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 &&
intel_dp->dfp.ycbcr_444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0;
@ -2461,45 +2623,15 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1)
drm_dbg_kms(&i915->drm,
"Failed to %s protocol converter YCbCr 4:2:0 conversion mode\n",
enabledisable(intel_dp->dfp.ycbcr_444_to_420));
str_enable_disable(intel_dp->dfp.ycbcr_444_to_420));
tmp = 0;
if (intel_dp->dfp.rgb_to_ycbcr) {
bool bt2020, bt709;
/*
* FIXME: Currently if userspace selects BT2020 or BT709, but PCON supports only
* RGB->YCbCr for BT601 colorspace, we go ahead with BT601, as default.
*
*/
tmp = DP_CONVERSION_BT601_RGB_YCBCR_ENABLE;
bt2020 = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd,
intel_dp->downstream_ports,
DP_DS_HDMI_BT2020_RGB_YCBCR_CONV);
bt709 = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd,
intel_dp->downstream_ports,
DP_DS_HDMI_BT709_RGB_YCBCR_CONV);
switch (crtc_state->infoframes.vsc.colorimetry) {
case DP_COLORIMETRY_BT2020_RGB:
case DP_COLORIMETRY_BT2020_YCC:
if (bt2020)
tmp = DP_CONVERSION_BT2020_RGB_YCBCR_ENABLE;
break;
case DP_COLORIMETRY_BT709_YCC:
case DP_COLORIMETRY_XVYCC_709:
if (bt709)
tmp = DP_CONVERSION_BT709_RGB_YCBCR_ENABLE;
break;
default:
break;
}
}
tmp = intel_dp->dfp.rgb_to_ycbcr ?
DP_CONVERSION_BT709_RGB_YCBCR_ENABLE : 0;
if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0)
drm_dbg_kms(&i915->drm,
"Failed to %s protocol converter RGB->YCbCr conversion mode\n",
enabledisable(tmp));
str_enable_disable(tmp));
}
@ -2572,9 +2704,9 @@ static void intel_edp_mso_mode_fixup(struct intel_connector *connector,
drm_mode_set_name(mode);
drm_dbg_kms(&i915->drm,
"[CONNECTOR:%d:%s] using generated MSO mode: ",
connector->base.base.id, connector->base.name);
drm_mode_debug_printmodeline(mode);
"[CONNECTOR:%d:%s] using generated MSO mode: " DRM_MODE_FMT "\n",
connector->base.base.id, connector->base.name,
DRM_MODE_ARG(mode));
}
static void intel_edp_mso_init(struct intel_dp *intel_dp)
@ -2787,8 +2919,9 @@ intel_dp_configure_mst(struct intel_dp *intel_dp)
drm_dbg_kms(&i915->drm,
"[ENCODER:%d:%s] MST support: port: %s, sink: %s, modparam: %s\n",
encoder->base.base.id, encoder->base.name,
yesno(intel_dp_mst_source_support(intel_dp)), yesno(sink_can_mst),
yesno(i915->params.enable_dp_mst));
str_yes_no(intel_dp_mst_source_support(intel_dp)),
str_yes_no(sink_can_mst),
str_yes_no(i915->params.enable_dp_mst));
if (!intel_dp_mst_source_support(intel_dp))
return;
@ -4347,9 +4480,7 @@ intel_dp_update_420(struct intel_dp *intel_dp)
intel_dp->downstream_ports);
rgb_to_ycbcr = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd,
intel_dp->downstream_ports,
DP_DS_HDMI_BT601_RGB_YCBCR_CONV |
DP_DS_HDMI_BT709_RGB_YCBCR_CONV |
DP_DS_HDMI_BT2020_RGB_YCBCR_CONV);
DP_DS_HDMI_BT709_RGB_YCBCR_CONV);
if (DISPLAY_VER(i915) >= 11) {
/* Let PCON convert from RGB->YCbCr if possible */
@ -4375,21 +4506,28 @@ intel_dp_update_420(struct intel_dp *intel_dp)
drm_dbg_kms(&i915->drm,
"[CONNECTOR:%d:%s] RGB->YcbCr conversion? %s, YCbCr 4:2:0 allowed? %s, YCbCr 4:4:4->4:2:0 conversion? %s\n",
connector->base.base.id, connector->base.name,
yesno(intel_dp->dfp.rgb_to_ycbcr),
yesno(connector->base.ycbcr_420_allowed),
yesno(intel_dp->dfp.ycbcr_444_to_420));
str_yes_no(intel_dp->dfp.rgb_to_ycbcr),
str_yes_no(connector->base.ycbcr_420_allowed),
str_yes_no(intel_dp->dfp.ycbcr_444_to_420));
}
static void
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;
bool vrr_capable;
intel_dp_unset_edid(intel_dp);
edid = intel_dp_get_edid(intel_dp);
connector->detect_edid = edid;
vrr_capable = intel_vrr_is_capable(&connector->base);
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_420(intel_dp);
@ -4422,6 +4560,9 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
intel_dp->dfp.ycbcr_444_to_420 = false;
connector->base.ycbcr_420_allowed = false;
drm_connector_set_vrr_capable_property(&connector->base,
false);
}
static int
@ -4572,26 +4713,12 @@ static int intel_dp_get_modes(struct drm_connector *connector)
int num_modes = 0;
edid = intel_connector->detect_edid;
if (edid) {
if (edid)
num_modes = intel_connector_update_modes(connector, edid);
if (intel_vrr_is_capable(connector))
drm_connector_set_vrr_capable_property(connector,
true);
}
/* Also add fixed mode, which may or may not be present in EDID */
if (intel_dp_is_edp(intel_attached_dp(intel_connector)) &&
intel_connector->panel.fixed_mode) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev,
intel_connector->panel.fixed_mode);
if (mode) {
drm_mode_probed_add(connector, mode);
num_modes++;
}
}
if (intel_dp_is_edp(intel_attached_dp(intel_connector)))
num_modes += intel_panel_get_modes(intel_connector);
if (num_modes)
return num_modes;
@ -4643,9 +4770,7 @@ intel_dp_connector_register(struct drm_connector *connector)
if (lspcon_init(dig_port)) {
lspcon_detect_hdr_capability(lspcon);
if (lspcon->hdr_supported)
drm_object_attach_property(&connector->base,
connector->dev->mode_config.hdr_output_metadata_property,
0);
drm_connector_attach_hdr_output_metadata_property(connector);
}
return ret;
@ -4914,6 +5039,25 @@ bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
return intel_bios_is_port_edp(dev_priv, port);
}
static bool
has_gamut_metadata_dip(struct drm_i915_private *i915, enum port port)
{
if (intel_bios_is_lspcon_present(i915, port))
return false;
if (DISPLAY_VER(i915) >= 11)
return true;
if (port == PORT_A)
return false;
if (IS_HASWELL(i915) || IS_BROADWELL(i915) ||
DISPLAY_VER(i915) >= 9)
return true;
return false;
}
static void
intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
{
@ -4940,10 +5084,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
intel_attach_dp_colorspace_property(connector);
}
if (IS_GEMINILAKE(dev_priv) || DISPLAY_VER(dev_priv) >= 11)
drm_object_attach_property(&connector->base,
connector->dev->mode_config.hdr_output_metadata_property,
0);
if (has_gamut_metadata_dip(dev_priv, port))
drm_connector_attach_hdr_output_metadata_property(connector);
if (intel_dp_is_edp(intel_dp)) {
u32 allowed_scalers;
@ -4962,14 +5104,30 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
drm_connector_attach_vrr_capable_property(connector);
}
static void
intel_edp_add_properties(struct intel_dp *intel_dp)
{
struct intel_connector *connector = intel_dp->attached_connector;
struct drm_i915_private *i915 = to_i915(connector->base.dev);
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
if (!fixed_mode)
return;
drm_connector_set_panel_orientation_with_quirk(&connector->base,
i915->vbt.orientation,
fixed_mode->hdisplay,
fixed_mode->vdisplay);
}
static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct intel_connector *intel_connector)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector = &intel_connector->base;
struct drm_display_mode *fixed_mode = NULL;
struct drm_display_mode *downclock_mode = NULL;
struct drm_display_mode *fixed_mode;
bool has_dpcd;
enum pipe pipe = INVALID_PIPE;
struct edid *edid;
@ -5026,20 +5184,20 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
}
intel_connector->edid = edid;
fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
if (fixed_mode)
downclock_mode = intel_drrs_init(intel_connector, fixed_mode);
intel_panel_add_edid_fixed_modes(intel_connector,
dev_priv->vbt.drrs_type != DRRS_TYPE_NONE);
/* MSO requires information from the EDID */
intel_edp_mso_init(intel_dp);
/* multiply the mode clock and horizontal timings for MSO */
intel_edp_mso_mode_fixup(intel_connector, fixed_mode);
intel_edp_mso_mode_fixup(intel_connector, downclock_mode);
list_for_each_entry(fixed_mode, &intel_connector->panel.fixed_modes, head)
intel_edp_mso_mode_fixup(intel_connector, fixed_mode);
/* fallback to VBT if available for eDP */
if (!fixed_mode)
fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
if (!intel_panel_preferred_fixed_mode(intel_connector))
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
mutex_unlock(&dev->mode_config.mutex);
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
@ -5061,16 +5219,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
pipe_name(pipe));
}
intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
intel_panel_init(intel_connector);
if (!(dev_priv->quirks & QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
intel_connector->panel.backlight.power = intel_pps_backlight_power;
intel_backlight_setup(intel_connector, pipe);
if (fixed_mode) {
drm_connector_set_panel_orientation_with_quirk(connector,
dev_priv->vbt.orientation,
fixed_mode->hdisplay, fixed_mode->vdisplay);
}
intel_edp_add_properties(intel_dp);
return true;

View File

@ -55,6 +55,7 @@ static u8 *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp,
}
static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp,
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
enum drm_dp_phy dp_phy)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
@ -63,7 +64,7 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp,
intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name));
if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) {
if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dpcd, dp_phy, phy_caps) < 0) {
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
"[ENCODER:%d:%s][%s] failed to read the PHY caps\n",
encoder->base.base.id, encoder->base.name, phy_name);
@ -77,10 +78,12 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp,
phy_caps);
}
static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp)
static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp,
const u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
int ret;
if (intel_dp_is_edp(intel_dp))
return false;
@ -92,8 +95,9 @@ static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp)
if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915))
return false;
if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
intel_dp->lttpr_common_caps) < 0)
ret = drm_dp_read_lttpr_common_caps(&intel_dp->aux, dpcd,
intel_dp->lttpr_common_caps);
if (ret < 0)
goto reset_caps;
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
@ -122,14 +126,14 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
}
static int intel_dp_init_lttpr(struct intel_dp *intel_dp)
static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
int lttpr_count;
int i;
if (!intel_dp_read_lttpr_common_caps(intel_dp))
if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd))
return 0;
lttpr_count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps);
@ -168,7 +172,7 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp)
}
for (i = 0; i < lttpr_count; i++)
intel_dp_read_lttpr_phy_caps(intel_dp, DP_PHY_LTTPR(i));
intel_dp_read_lttpr_phy_caps(intel_dp, dpcd, DP_PHY_LTTPR(i));
return lttpr_count;
}
@ -193,9 +197,18 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp)
*/
int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp)
{
int lttpr_count = intel_dp_init_lttpr(intel_dp);
u8 dpcd[DP_RECEIVER_CAP_SIZE];
int lttpr_count;
/* The DPTX shall read the DPRX caps after LTTPR detection. */
if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
return -EIO;
lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd);
/*
* The DPTX shall read the DPRX caps after LTTPR detection, so re-read
* it here.
*/
if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) {
intel_dp_reset_lttpr_common_caps(intel_dp);
return -EIO;

View File

@ -398,9 +398,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
if (ret) {
drm_dbg_kms(&i915->drm, "failed to update payload %d\n", ret);
}
if (old_crtc_state->has_audio)
intel_audio_codec_disable(encoder,
old_crtc_state, old_conn_state);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
}
static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
@ -599,8 +598,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
intel_crtc_vblank_on(pipe_config);
if (pipe_config->has_audio)
intel_audio_codec_enable(encoder, pipe_config, conn_state);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
/* Enable hdcp if it's desired */
if (conn_state->content_protection ==

View File

@ -4,6 +4,7 @@
*/
#include <linux/kernel.h>
#include <linux/string_helpers.h>
#include "intel_crtc.h"
#include "intel_de.h"
@ -253,12 +254,12 @@ static const struct intel_limit ilk_limits_dual_lvds_100m = {
static const struct intel_limit intel_limits_vlv = {
/*
* These are the data rate limits (measured in fast clocks)
* These are based on the data rate limits (measured in fast clocks)
* since those are the strictest limits we have. The fast
* clock and actual rate limits are more relaxed, so checking
* them would make no difference.
*/
.dot = { .min = 25000 * 5, .max = 270000 * 5 },
.dot = { .min = 25000, .max = 270000 },
.vco = { .min = 4000000, .max = 6000000 },
.n = { .min = 1, .max = 7 },
.m1 = { .min = 2, .max = 3 },
@ -269,12 +270,12 @@ static const struct intel_limit intel_limits_vlv = {
static const struct intel_limit intel_limits_chv = {
/*
* These are the data rate limits (measured in fast clocks)
* These are based on the data rate limits (measured in fast clocks)
* since those are the strictest limits we have. The fast
* clock and actual rate limits are more relaxed, so checking
* them would make no difference.
*/
.dot = { .min = 25000 * 5, .max = 540000 * 5},
.dot = { .min = 25000, .max = 540000 },
.vco = { .min = 4800000, .max = 6480000 },
.n = { .min = 1, .max = 1 },
.m1 = { .min = 2, .max = 2 },
@ -284,8 +285,7 @@ static const struct intel_limit intel_limits_chv = {
};
static const struct intel_limit intel_limits_bxt = {
/* FIXME: find real dot limits */
.dot = { .min = 0, .max = INT_MAX },
.dot = { .min = 25000, .max = 594000 },
.vco = { .min = 4800000, .max = 6700000 },
.n = { .min = 1, .max = 1 },
.m1 = { .min = 2, .max = 2 },
@ -336,26 +336,26 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
int vlv_calc_dpll_params(int refclk, struct dpll *clock)
{
clock->m = clock->m1 * clock->m2;
clock->p = clock->p1 * clock->p2;
clock->p = clock->p1 * clock->p2 * 5;
if (WARN_ON(clock->n == 0 || clock->p == 0))
return 0;
clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
return clock->dot / 5;
return clock->dot;
}
int chv_calc_dpll_params(int refclk, struct dpll *clock)
{
clock->m = clock->m1 * clock->m2;
clock->p = clock->p1 * clock->p2;
clock->p = clock->p1 * clock->p2 * 5;
if (WARN_ON(clock->n == 0 || clock->p == 0))
return 0;
clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
clock->n << 22);
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
return clock->dot / 5;
return clock->dot;
}
/*
@ -424,8 +424,7 @@ i9xx_select_p2_div(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* refclk, or FALSE.
*
* Target and reference clocks are specified in kHz.
*
@ -483,8 +482,7 @@ i9xx_find_best_dpll(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* refclk, or FALSE.
*
* Target and reference clocks are specified in kHz.
*
@ -540,8 +538,7 @@ pnv_find_best_dpll(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* refclk, or FALSE.
*
* Target and reference clocks are specified in kHz.
*
@ -640,8 +637,7 @@ static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
/*
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* refclk, or FALSE.
*/
static bool
vlv_find_best_dpll(const struct intel_limit *limit,
@ -658,8 +654,6 @@ vlv_find_best_dpll(const struct intel_limit *limit,
int max_n = min(limit->n.max, refclk / 19200);
bool found = false;
target *= 5; /* fast clock */
memset(best_clock, 0, sizeof(*best_clock));
/* based on hardware requirement, prefer smaller n to precision */
@ -667,7 +661,7 @@ vlv_find_best_dpll(const struct intel_limit *limit,
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
clock.p2 -= clock.p2 > 10 ? 2 : 1) {
clock.p = clock.p1 * clock.p2;
clock.p = clock.p1 * clock.p2 * 5;
/* based on hardware requirement, prefer bigger m1,m2 values */
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
unsigned int ppm;
@ -701,8 +695,7 @@ vlv_find_best_dpll(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* refclk, or FALSE.
*/
static bool
chv_find_best_dpll(const struct intel_limit *limit,
@ -728,7 +721,6 @@ chv_find_best_dpll(const struct intel_limit *limit,
*/
clock.n = 1;
clock.m1 = 2;
target *= 5; /* fast clock */
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
for (clock.p2 = limit->p2.p2_fast;
@ -736,7 +728,7 @@ chv_find_best_dpll(const struct intel_limit *limit,
clock.p2 -= clock.p2 > 10 ? 2 : 1) {
unsigned int error_ppm;
clock.p = clock.p1 * clock.p2;
clock.p = clock.p1 * clock.p2 * 5;
m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
refclk * clock.m1);
@ -1945,7 +1937,7 @@ static void assert_pll(struct drm_i915_private *dev_priv,
cur_state = intel_de_read(dev_priv, DPLL(pipe)) & DPLL_VCO_ENABLE;
I915_STATE_WARN(cur_state != state,
"PLL state assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe)

View File

@ -21,6 +21,8 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <linux/string_helpers.h>
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_dpio_phy.h"
@ -178,13 +180,14 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
struct intel_dpll_hw_state hw_state;
if (drm_WARN(&dev_priv->drm, !pll,
"asserting DPLL %s with no DPLL\n", onoff(state)))
"asserting DPLL %s with no DPLL\n", str_on_off(state)))
return;
cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state);
I915_STATE_WARN(cur_state != state,
"%s assertion failure (expected %s, current %s)\n",
pll->info->name, onoff(state), onoff(cur_state));
pll->info->name, str_on_off(state),
str_on_off(cur_state));
}
static enum tc_port icl_pll_id_to_tc_port(enum intel_dpll_id id)
@ -832,7 +835,7 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
{
u64 freq2k;
unsigned p, n2, r2;
struct hsw_wrpll_rnp best = { 0, 0, 0 };
struct hsw_wrpll_rnp best = {};
unsigned budget;
freq2k = clock / 100;
@ -1330,13 +1333,6 @@ struct skl_wrpll_context {
unsigned int p; /* chosen divider */
};
static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
{
memset(ctx, 0, sizeof(*ctx));
ctx->min_deviation = U64_MAX;
}
/* DCO freq must be within +1%/-6% of the DCO central freq */
#define SKL_DCO_MAX_PDEVIATION 100
#define SKL_DCO_MAX_NDEVIATION 600
@ -1502,28 +1498,28 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */,
int ref_clock,
struct skl_wrpll_params *wrpll_params)
{
u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
u64 dco_central_freq[3] = { 8400000000ULL,
9000000000ULL,
9600000000ULL };
static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20,
24, 28, 30, 32, 36, 40, 42, 44,
48, 52, 54, 56, 60, 64, 66, 68,
70, 72, 76, 78, 80, 84, 88, 90,
92, 96, 98 };
static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
static const u64 dco_central_freq[3] = { 8400000000ULL,
9000000000ULL,
9600000000ULL };
static const u8 even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20,
24, 28, 30, 32, 36, 40, 42, 44,
48, 52, 54, 56, 60, 64, 66, 68,
70, 72, 76, 78, 80, 84, 88, 90,
92, 96, 98 };
static const u8 odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
static const struct {
const int *list;
const u8 *list;
int n_dividers;
} dividers[] = {
{ even_dividers, ARRAY_SIZE(even_dividers) },
{ odd_dividers, ARRAY_SIZE(odd_dividers) },
};
struct skl_wrpll_context ctx;
struct skl_wrpll_context ctx = {
.min_deviation = U64_MAX,
};
unsigned int dco, d, i;
unsigned int p0, p1, p2;
skl_wrpll_context_init(&ctx);
u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
for (d = 0; d < ARRAY_SIZE(dividers); d++) {
for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
@ -1574,8 +1570,8 @@ skip_remaining_dividers:
static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct skl_wrpll_params wrpll_params = {};
u32 ctrl1, cfgcr1, cfgcr2;
struct skl_wrpll_params wrpll_params = { 0, };
/*
* See comment in intel_dpll_hw_state to understand why we always use 0
@ -1902,7 +1898,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
/* Write M2 integer */
temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0));
temp &= ~PORT_PLL_M2_MASK;
temp &= ~PORT_PLL_M2_INT_MASK;
temp |= pll->state.hw_state.pll0;
intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 0), temp);
@ -2038,7 +2034,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
hw_state->pll0 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0));
hw_state->pll0 &= PORT_PLL_M2_MASK;
hw_state->pll0 &= PORT_PLL_M2_INT_MASK;
hw_state->pll1 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 1));
hw_state->pll1 &= PORT_PLL_N_MASK;
@ -2087,82 +2083,64 @@ out:
return ret;
}
/* bxt clock parameters */
struct bxt_clk_div {
int clock;
u32 p1;
u32 p2;
u32 m2_int;
u32 m2_frac;
bool m2_frac_en;
u32 n;
int vco;
};
/* pre-calculated values for DP linkrates */
static const struct bxt_clk_div bxt_dp_clk_val[] = {
{162000, 4, 2, 32, 1677722, 1, 1},
{270000, 4, 1, 27, 0, 0, 1},
{540000, 2, 1, 27, 0, 0, 1},
{216000, 3, 2, 32, 1677722, 1, 1},
{243000, 4, 1, 24, 1258291, 1, 1},
{324000, 4, 1, 32, 1677722, 1, 1},
{432000, 3, 1, 32, 1677722, 1, 1}
static const struct dpll bxt_dp_clk_val[] = {
/* m2 is .22 binary fixed point */
{ .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{ .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
{ .dot = 540000, .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
{ .dot = 216000, .p1 = 3, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{ .dot = 243000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6133333 /* 24.3 */ },
{ .dot = 324000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{ .dot = 432000, .p1 = 3, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
};
static bool
bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state,
struct bxt_clk_div *clk_div)
struct dpll *clk_div)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct dpll best_clock;
/* Calculate HDMI div */
/*
* FIXME: tie the following calculation into
* i9xx_crtc_compute_clock
*/
if (!bxt_find_best_dpll(crtc_state, &best_clock)) {
if (!bxt_find_best_dpll(crtc_state, clk_div)) {
drm_dbg(&i915->drm, "no PLL dividers found for clock %d pipe %c\n",
crtc_state->port_clock,
pipe_name(crtc->pipe));
return false;
}
clk_div->p1 = best_clock.p1;
clk_div->p2 = best_clock.p2;
drm_WARN_ON(&i915->drm, best_clock.m1 != 2);
clk_div->n = best_clock.n;
clk_div->m2_int = best_clock.m2 >> 22;
clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
clk_div->m2_frac_en = clk_div->m2_frac != 0;
clk_div->vco = best_clock.vco;
drm_WARN_ON(&i915->drm, clk_div->m1 != 2);
return true;
}
static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state,
struct bxt_clk_div *clk_div)
struct dpll *clk_div)
{
int clock = crtc_state->port_clock;
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
int i;
*clk_div = bxt_dp_clk_val[0];
for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
if (bxt_dp_clk_val[i].clock == clock) {
if (crtc_state->port_clock == bxt_dp_clk_val[i].dot) {
*clk_div = bxt_dp_clk_val[i];
break;
}
}
clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
chv_calc_dpll_params(i915->dpll.ref_clks.nssc, clk_div);
drm_WARN_ON(&i915->drm, clk_div->vco == 0 ||
clk_div->dot != crtc_state->port_clock);
}
static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
const struct bxt_clk_div *clk_div)
const struct dpll *clk_div)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_dpll_hw_state *dpll_hw_state = &crtc_state->dpll_hw_state;
@ -2206,23 +2184,23 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
lanestagger = 0x02;
dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
dpll_hw_state->pll0 = clk_div->m2_int;
dpll_hw_state->pll0 = PORT_PLL_M2_INT(clk_div->m2 >> 22);
dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
dpll_hw_state->pll2 = clk_div->m2_frac;
dpll_hw_state->pll2 = PORT_PLL_M2_FRAC(clk_div->m2 & 0x3fffff);
if (clk_div->m2_frac_en)
if (clk_div->m2 & 0x3fffff)
dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
dpll_hw_state->pll6 = PORT_PLL_PROP_COEFF(prop_coef) |
PORT_PLL_INT_COEFF(int_coef) |
PORT_PLL_GAIN_CTL(gain_ctl);
dpll_hw_state->pll8 = targ_cnt;
dpll_hw_state->pll8 = PORT_PLL_TARGET_CNT(targ_cnt);
dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
dpll_hw_state->pll9 = PORT_PLL_LOCK_THRESHOLD(5);
dpll_hw_state->pll10 =
PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
| PORT_PLL_DCO_AMP_OVR_EN_H;
dpll_hw_state->pll10 = PORT_PLL_DCO_AMP(15) |
PORT_PLL_DCO_AMP_OVR_EN_H;
dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
@ -2234,7 +2212,7 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
static bool
bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
{
struct bxt_clk_div clk_div = {};
struct dpll clk_div = {};
bxt_ddi_dp_pll_dividers(crtc_state, &clk_div);
@ -2244,7 +2222,7 @@ bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
static bool
bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
{
struct bxt_clk_div clk_div = {};
struct dpll clk_div = {};
bxt_ddi_hdmi_pll_dividers(crtc_state, &clk_div);
@ -2258,12 +2236,12 @@ static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915,
struct dpll clock;
clock.m1 = 2;
clock.m2 = (pll_state->pll0 & PORT_PLL_M2_MASK) << 22;
clock.m2 = REG_FIELD_GET(PORT_PLL_M2_INT_MASK, pll_state->pll0) << 22;
if (pll_state->pll3 & PORT_PLL_M2_FRAC_ENABLE)
clock.m2 |= pll_state->pll2 & PORT_PLL_M2_FRAC_MASK;
clock.n = (pll_state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT;
clock.p1 = (pll_state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT;
clock.p2 = (pll_state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT;
clock.m2 |= REG_FIELD_GET(PORT_PLL_M2_FRAC_MASK, pll_state->pll2);
clock.n = REG_FIELD_GET(PORT_PLL_N_MASK, pll_state->pll1);
clock.p1 = REG_FIELD_GET(PORT_PLL_P1_MASK, pll_state->ebb0);
clock.p2 = REG_FIELD_GET(PORT_PLL_P2_MASK, pll_state->ebb0);
return chv_calc_dpll_params(i915->dpll.ref_clks.nssc, &clock);
}
@ -2758,8 +2736,8 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
struct intel_dpll_hw_state *state,
bool is_dkl)
{
static const u8 div1_vals[] = { 7, 5, 3, 2 };
u32 dco_min_freq, dco_max_freq;
int div1_vals[] = {7, 5, 3, 2};
unsigned int i;
int div2;

View File

@ -249,7 +249,7 @@ intel_dpt_create(struct intel_framebuffer *fb)
size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE);
if (HAS_LMEM(i915))
dpt_obj = i915_gem_object_create_lmem(i915, size, 0);
dpt_obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_CONTIGUOUS);
else
dpt_obj = i915_gem_object_create_stolen(i915, size);
if (IS_ERR(dpt_obj))

View File

@ -47,74 +47,36 @@
* requested by userspace.
*/
static bool can_enable_drrs(struct intel_connector *connector,
const struct intel_crtc_state *pipe_config)
const char *intel_drrs_type_str(enum drrs_type drrs_type)
{
const struct drm_i915_private *i915 = to_i915(connector->base.dev);
static const char * const str[] = {
[DRRS_TYPE_NONE] = "none",
[DRRS_TYPE_STATIC] = "static",
[DRRS_TYPE_SEAMLESS] = "seamless",
};
if (pipe_config->vrr.enable)
return false;
if (drrs_type >= ARRAY_SIZE(str))
return "<invalid>";
/*
* DRRS and PSR can't be enable together, so giving preference to PSR
* as it allows more power-savings by complete shutting down display,
* so to guarantee this, intel_drrs_compute_config() must be called
* after intel_psr_compute_config().
*/
if (pipe_config->has_psr)
return false;
return connector->panel.downclock_mode &&
i915->drrs.type == SEAMLESS_DRRS_SUPPORT;
}
void
intel_drrs_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *pipe_config,
int output_bpp, bool constant_n)
{
struct intel_connector *connector = intel_dp->attached_connector;
struct drm_i915_private *i915 = to_i915(connector->base.dev);
int pixel_clock;
if (!can_enable_drrs(connector, pipe_config)) {
if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder))
intel_zero_m_n(&pipe_config->dp_m2_n2);
return;
}
pipe_config->has_drrs = true;
pixel_clock = connector->panel.downclock_mode->clock;
if (pipe_config->splitter.enable)
pixel_clock /= pipe_config->splitter.link_count;
intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock,
pipe_config->port_clock, &pipe_config->dp_m2_n2,
constant_n, pipe_config->fec_enable);
/* FIXME: abstract this better */
if (pipe_config->splitter.enable)
pipe_config->dp_m2_n2.data_m *= pipe_config->splitter.link_count;
return str[drrs_type];
}
static void
intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state,
enum drrs_refresh_rate_type refresh_type)
intel_drrs_set_refresh_rate_pipeconf(struct intel_crtc *crtc,
enum drrs_refresh_rate refresh_rate)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum transcoder cpu_transcoder = crtc->drrs.cpu_transcoder;
u32 val, bit;
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
bit = PIPECONF_EDP_RR_MODE_SWITCH_VLV;
bit = PIPECONF_REFRESH_RATE_ALT_VLV;
else
bit = PIPECONF_EDP_RR_MODE_SWITCH;
bit = PIPECONF_REFRESH_RATE_ALT_ILK;
val = intel_de_read(dev_priv, PIPECONF(cpu_transcoder));
if (refresh_type == DRRS_LOW_RR)
if (refresh_rate == DRRS_REFRESH_RATE_LOW)
val |= bit;
else
val &= ~bit;
@ -123,244 +85,171 @@ intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state,
}
static void
intel_drrs_set_refresh_rate_m_n(const struct intel_crtc_state *crtc_state,
enum drrs_refresh_rate_type refresh_type)
intel_drrs_set_refresh_rate_m_n(struct intel_crtc *crtc,
enum drrs_refresh_rate refresh_rate)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
intel_cpu_transcoder_set_m1_n1(crtc, crtc_state->cpu_transcoder,
refresh_type == DRRS_LOW_RR ?
&crtc_state->dp_m2_n2 : &crtc_state->dp_m_n);
intel_cpu_transcoder_set_m1_n1(crtc, crtc->drrs.cpu_transcoder,
refresh_rate == DRRS_REFRESH_RATE_LOW ?
&crtc->drrs.m2_n2 : &crtc->drrs.m_n);
}
static void intel_drrs_set_state(struct drm_i915_private *dev_priv,
const struct intel_crtc_state *crtc_state,
enum drrs_refresh_rate_type refresh_type)
bool intel_drrs_is_active(struct intel_crtc *crtc)
{
struct intel_dp *intel_dp = dev_priv->drrs.dp;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_display_mode *mode;
return crtc->drrs.cpu_transcoder != INVALID_TRANSCODER;
}
if (!intel_dp) {
drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n");
return;
}
static void intel_drrs_set_state(struct intel_crtc *crtc,
enum drrs_refresh_rate refresh_rate)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
if (!crtc) {
drm_dbg_kms(&dev_priv->drm,
"DRRS: intel_crtc not initialized\n");
return;
}
if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n");
return;
}
if (refresh_type == dev_priv->drrs.refresh_rate_type)
if (refresh_rate == crtc->drrs.refresh_rate)
return;
if (!crtc_state->hw.active) {
drm_dbg_kms(&dev_priv->drm,
"eDP encoder disabled. CRTC not Active\n");
return;
}
if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv))
intel_drrs_set_refresh_rate_m_n(crtc_state, refresh_type);
else if (DISPLAY_VER(dev_priv) > 6)
intel_drrs_set_refresh_rate_pipeconf(crtc_state, refresh_type);
dev_priv->drrs.refresh_rate_type = refresh_type;
if (refresh_type == DRRS_LOW_RR)
mode = intel_dp->attached_connector->panel.downclock_mode;
if (intel_cpu_transcoder_has_m2_n2(dev_priv, crtc->drrs.cpu_transcoder))
intel_drrs_set_refresh_rate_pipeconf(crtc, refresh_rate);
else
mode = intel_dp->attached_connector->panel.fixed_mode;
drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n",
drm_mode_vrefresh(mode));
intel_drrs_set_refresh_rate_m_n(crtc, refresh_rate);
crtc->drrs.refresh_rate = refresh_rate;
}
static void
intel_drrs_enable_locked(struct intel_dp *intel_dp)
static void intel_drrs_schedule_work(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
mod_delayed_work(system_wq, &crtc->drrs.work, msecs_to_jiffies(1000));
}
dev_priv->drrs.busy_frontbuffer_bits = 0;
dev_priv->drrs.dp = intel_dp;
static unsigned int intel_drrs_frontbuffer_bits(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
unsigned int frontbuffer_bits;
frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe);
for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc,
crtc_state->bigjoiner_pipes)
frontbuffer_bits |= INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe);
return frontbuffer_bits;
}
/**
* intel_drrs_enable - init drrs struct if supported
* @intel_dp: DP struct
* @crtc_state: A pointer to the active crtc state.
* intel_drrs_activate - activate DRRS
* @crtc_state: the crtc state
*
* Initializes frontbuffer_bits and drrs.dp
* Activates DRRS on the crtc.
*/
void intel_drrs_enable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
void intel_drrs_activate(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
if (!crtc_state->has_drrs)
return;
drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n");
if (!crtc_state->hw.active)
return;
mutex_lock(&dev_priv->drrs.mutex);
if (intel_crtc_is_bigjoiner_slave(crtc_state))
return;
if (dev_priv->drrs.dp) {
drm_warn(&dev_priv->drm, "DRRS already enabled\n");
goto unlock;
}
mutex_lock(&crtc->drrs.mutex);
intel_drrs_enable_locked(intel_dp);
crtc->drrs.cpu_transcoder = crtc_state->cpu_transcoder;
crtc->drrs.m_n = crtc_state->dp_m_n;
crtc->drrs.m2_n2 = crtc_state->dp_m2_n2;
crtc->drrs.frontbuffer_bits = intel_drrs_frontbuffer_bits(crtc_state);
crtc->drrs.busy_frontbuffer_bits = 0;
unlock:
mutex_unlock(&dev_priv->drrs.mutex);
}
intel_drrs_schedule_work(crtc);
static void
intel_drrs_disable_locked(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
intel_drrs_set_state(dev_priv, crtc_state, DRRS_HIGH_RR);
dev_priv->drrs.dp = NULL;
mutex_unlock(&crtc->drrs.mutex);
}
/**
* intel_drrs_disable - Disable DRRS
* @intel_dp: DP struct
* @old_crtc_state: Pointer to old crtc_state.
* intel_drrs_deactivate - deactivate DRRS
* @old_crtc_state: the old crtc state
*
* Deactivates DRRS on the crtc.
*/
void intel_drrs_disable(struct intel_dp *intel_dp,
const struct intel_crtc_state *old_crtc_state)
void intel_drrs_deactivate(const struct intel_crtc_state *old_crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
if (!old_crtc_state->has_drrs)
return;
mutex_lock(&dev_priv->drrs.mutex);
if (!dev_priv->drrs.dp) {
mutex_unlock(&dev_priv->drrs.mutex);
return;
}
intel_drrs_disable_locked(intel_dp, old_crtc_state);
mutex_unlock(&dev_priv->drrs.mutex);
cancel_delayed_work_sync(&dev_priv->drrs.work);
}
/**
* intel_drrs_update - Update DRRS state
* @intel_dp: Intel DP
* @crtc_state: new CRTC state
*
* This function will update DRRS states, disabling or enabling DRRS when
* executing fastsets. For full modeset, intel_drrs_disable() and
* intel_drrs_enable() should be called instead.
*/
void
intel_drrs_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
if (dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT)
if (!old_crtc_state->hw.active)
return;
mutex_lock(&dev_priv->drrs.mutex);
if (intel_crtc_is_bigjoiner_slave(old_crtc_state))
return;
/* New state matches current one? */
if (crtc_state->has_drrs == !!dev_priv->drrs.dp)
goto unlock;
mutex_lock(&crtc->drrs.mutex);
if (crtc_state->has_drrs)
intel_drrs_enable_locked(intel_dp);
else
intel_drrs_disable_locked(intel_dp, crtc_state);
if (intel_drrs_is_active(crtc))
intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH);
unlock:
mutex_unlock(&dev_priv->drrs.mutex);
crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
crtc->drrs.frontbuffer_bits = 0;
crtc->drrs.busy_frontbuffer_bits = 0;
mutex_unlock(&crtc->drrs.mutex);
cancel_delayed_work_sync(&crtc->drrs.work);
}
static void intel_drrs_downclock_work(struct work_struct *work)
{
struct drm_i915_private *dev_priv =
container_of(work, typeof(*dev_priv), drrs.work.work);
struct intel_dp *intel_dp;
struct drm_crtc *crtc;
struct intel_crtc *crtc = container_of(work, typeof(*crtc), drrs.work.work);
mutex_lock(&dev_priv->drrs.mutex);
mutex_lock(&crtc->drrs.mutex);
intel_dp = dev_priv->drrs.dp;
if (intel_drrs_is_active(crtc) && !crtc->drrs.busy_frontbuffer_bits)
intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_LOW);
if (!intel_dp)
goto unlock;
/*
* The delayed work can race with an invalidate hence we need to
* recheck.
*/
if (dev_priv->drrs.busy_frontbuffer_bits)
goto unlock;
crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config, DRRS_LOW_RR);
unlock:
mutex_unlock(&dev_priv->drrs.mutex);
mutex_unlock(&crtc->drrs.mutex);
}
static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits,
unsigned int all_frontbuffer_bits,
bool invalidate)
{
struct intel_dp *intel_dp;
struct drm_crtc *crtc;
enum pipe pipe;
struct intel_crtc *crtc;
if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
if (dev_priv->vbt.drrs_type != DRRS_TYPE_SEAMLESS)
return;
cancel_delayed_work(&dev_priv->drrs.work);
for_each_intel_crtc(&dev_priv->drm, crtc) {
unsigned int frontbuffer_bits;
mutex_lock(&dev_priv->drrs.mutex);
mutex_lock(&crtc->drrs.mutex);
intel_dp = dev_priv->drrs.dp;
if (!intel_dp) {
mutex_unlock(&dev_priv->drrs.mutex);
return;
frontbuffer_bits = all_frontbuffer_bits & crtc->drrs.frontbuffer_bits;
if (!frontbuffer_bits) {
mutex_unlock(&crtc->drrs.mutex);
continue;
}
if (invalidate)
crtc->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
else
crtc->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
/* flush/invalidate means busy screen hence upclock */
intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH);
/*
* flush also means no more activity hence schedule downclock, if all
* other fbs are quiescent too
*/
if (!crtc->drrs.busy_frontbuffer_bits)
intel_drrs_schedule_work(crtc);
else
cancel_delayed_work(&crtc->drrs.work);
mutex_unlock(&crtc->drrs.mutex);
}
crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
pipe = to_intel_crtc(crtc)->pipe;
frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
if (invalidate)
dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
else
dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
/* flush/invalidate means busy screen hence upclock */
if (frontbuffer_bits)
intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config,
DRRS_HIGH_RR);
/*
* flush also means no more activity hence schedule downclock, if all
* other fbs are quiescent too
*/
if (!invalidate && !dev_priv->drrs.busy_frontbuffer_bits)
schedule_delayed_work(&dev_priv->drrs.work,
msecs_to_jiffies(1000));
mutex_unlock(&dev_priv->drrs.mutex);
}
/**
@ -397,68 +286,17 @@ void intel_drrs_flush(struct drm_i915_private *dev_priv,
intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false);
}
void intel_drrs_page_flip(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
unsigned int frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe);
intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false);
}
/**
* intel_drrs_init - Init basic DRRS work and mutex.
* @connector: eDP connector
* @fixed_mode: preferred mode of panel
* intel_crtc_drrs_init - Init DRRS for CRTC
* @crtc: crtc
*
* This function is called only once at driver load to initialize basic
* This function is called only once at driver load to initialize basic
* DRRS stuff.
*
* Returns:
* Downclock mode if panel supports it, else return NULL.
* DRRS support is determined by the presence of downclock mode (apart
* from VBT setting).
*/
struct drm_display_mode *
intel_drrs_init(struct intel_connector *connector,
struct drm_display_mode *fixed_mode)
void intel_crtc_drrs_init(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_encoder *encoder = connector->encoder;
struct drm_display_mode *downclock_mode = NULL;
INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work);
mutex_init(&dev_priv->drrs.mutex);
if (DISPLAY_VER(dev_priv) <= 6) {
drm_dbg_kms(&dev_priv->drm,
"DRRS supported for Gen7 and above\n");
return NULL;
}
if ((DISPLAY_VER(dev_priv) < 8 && !HAS_GMCH(dev_priv)) &&
encoder->port != PORT_A) {
drm_dbg_kms(&dev_priv->drm,
"DRRS only supported on eDP port A\n");
return NULL;
}
if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n");
return NULL;
}
downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode);
if (!downclock_mode) {
drm_dbg_kms(&dev_priv->drm,
"Downclock mode is not found. DRRS not supported\n");
return NULL;
}
dev_priv->drrs.type = dev_priv->vbt.drrs_type;
dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
drm_dbg_kms(&dev_priv->drm,
"seamless DRRS supported for eDP panel.\n");
return downclock_mode;
INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work);
mutex_init(&crtc->drrs.mutex);
crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
}

View File

@ -8,29 +8,21 @@
#include <linux/types.h>
enum drrs_type;
struct drm_i915_private;
struct intel_atomic_state;
struct intel_crtc;
struct intel_crtc_state;
struct intel_connector;
struct intel_dp;
void intel_drrs_enable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_drrs_disable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_drrs_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
const char *intel_drrs_type_str(enum drrs_type drrs_type);
bool intel_drrs_is_active(struct intel_crtc *crtc);
void intel_drrs_activate(const struct intel_crtc_state *crtc_state);
void intel_drrs_deactivate(const struct intel_crtc_state *crtc_state);
void intel_drrs_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits);
void intel_drrs_flush(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits);
void intel_drrs_page_flip(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_drrs_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *pipe_config,
int output_bpp, bool constant_n);
struct drm_display_mode *intel_drrs_init(struct intel_connector *connector,
struct drm_display_mode *fixed_mode);
void intel_crtc_drrs_init(struct intel_crtc *crtc);
#endif /* __INTEL_DRRS_H__ */

View File

@ -283,14 +283,12 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE);
if (IS_ERR(obj)) {
drm_err(&i915->drm, "Gem object creation failed\n");
kfree(dsb);
goto out;
}
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
if (IS_ERR(vma)) {
drm_err(&i915->drm, "Vma creation failed\n");
i915_gem_object_put(obj);
kfree(dsb);
goto out;
@ -298,7 +296,6 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC);
if (IS_ERR(buf)) {
drm_err(&i915->drm, "Command buffer creation failed\n");
i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
kfree(dsb);
goto out;
@ -311,6 +308,10 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
dsb->ins_start_offset = 0;
crtc_state->dsb = dsb;
out:
if (!crtc_state->dsb)
drm_info(&i915->drm,
"DSB queue setup failed, will fallback to MMIO for display HW programming\n");
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
}

View File

@ -34,26 +34,7 @@ int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi)
int intel_dsi_get_modes(struct drm_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->dev);
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *mode;
drm_dbg_kms(&i915->drm, "\n");
if (!intel_connector->panel.fixed_mode) {
drm_dbg_kms(&i915->drm, "no fixed mode\n");
return 0;
}
mode = drm_mode_duplicate(connector->dev,
intel_connector->panel.fixed_mode);
if (!mode) {
drm_dbg_kms(&i915->drm, "drm_mode_duplicate failed\n");
return 0;
}
drm_mode_probed_add(connector, mode);
return 1;
return intel_panel_get_modes(to_intel_connector(connector));
}
enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
@ -61,7 +42,8 @@ enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_connector *intel_connector = to_intel_connector(connector);
const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(intel_connector, mode);
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
enum drm_mode_status status;

View File

@ -30,6 +30,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <asm/unaligned.h>
@ -686,9 +687,9 @@ void intel_dsi_log_params(struct intel_dsi *intel_dsi)
intel_dsi->burst_mode_ratio);
drm_dbg_kms(&i915->drm, "Reset timer %d\n", intel_dsi->rst_timer_val);
drm_dbg_kms(&i915->drm, "Eot %s\n",
enableddisabled(intel_dsi->eotp_pkt));
str_enabled_disabled(intel_dsi->eotp_pkt));
drm_dbg_kms(&i915->drm, "Clockstop %s\n",
enableddisabled(!intel_dsi->clock_stop));
str_enabled_disabled(!intel_dsi->clock_stop));
drm_dbg_kms(&i915->drm, "Mode %s\n",
intel_dsi->operation_mode ? "command" : "video");
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
@ -715,7 +716,7 @@ void intel_dsi_log_params(struct intel_dsi *intel_dsi)
drm_dbg_kms(&i915->drm, "HS to LP Clock Count 0x%x\n",
intel_dsi->clk_hs_to_lp_count);
drm_dbg_kms(&i915->drm, "BTA %s\n",
enableddisabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA)));
str_enabled_disabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA)));
}
bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)

View File

@ -226,7 +226,7 @@ intel_dvo_mode_valid(struct drm_connector *connector,
struct intel_connector *intel_connector = to_intel_connector(connector);
struct intel_dvo *intel_dvo = intel_attached_dvo(intel_connector);
const struct drm_display_mode *fixed_mode =
intel_connector->panel.fixed_mode;
intel_panel_fixed_mode(intel_connector, mode);
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
int target_clock = mode->clock;
@ -257,9 +257,9 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder,
{
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
struct intel_connector *connector = to_intel_connector(conn_state->connector);
const struct drm_display_mode *fixed_mode =
intel_dvo->attached_connector->panel.fixed_mode;
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(intel_dvo->attached_connector, adjusted_mode);
/*
* If we have timings from the BIOS for the panel, put them in
@ -333,8 +333,6 @@ intel_dvo_detect(struct drm_connector *connector, bool force)
static int intel_dvo_get_modes(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
const struct drm_display_mode *fixed_mode =
to_intel_connector(connector)->panel.fixed_mode;
int num_modes;
/*
@ -348,17 +346,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
if (num_modes)
return num_modes;
if (fixed_mode) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, fixed_mode);
if (mode) {
drm_mode_probed_add(connector, mode);
num_modes++;
}
}
return num_modes;
return intel_panel_get_modes(to_intel_connector(connector));
}
static const struct drm_connector_funcs intel_dvo_connector_funcs = {
@ -390,27 +378,6 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
.destroy = intel_dvo_enc_destroy,
};
/*
* Attempts to get a fixed panel timing for LVDS (currently only the i830).
*
* Other chips with DVO LVDS will need to extend this to deal with the LVDS
* chip being on DVOB/C and having multiple pipes.
*/
static struct drm_display_mode *
intel_dvo_get_current_mode(struct intel_encoder *encoder)
{
struct drm_display_mode *mode;
mode = intel_encoder_current_mode(encoder);
if (mode) {
DRM_DEBUG_KMS("using current (BIOS) mode: ");
drm_mode_debug_printmodeline(mode);
mode->type |= DRM_MODE_TYPE_PREFERRED;
}
return mode;
}
static enum port intel_dvo_port(i915_reg_t dvo_reg)
{
if (i915_mmio_reg_equal(dvo_reg, DVOA))
@ -561,9 +528,11 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
* headers, likely), so for now, just get the current
* mode being output through DVO.
*/
intel_panel_init(&intel_connector->panel,
intel_dvo_get_current_mode(intel_encoder),
NULL);
intel_panel_add_encoder_fixed_mode(intel_connector,
intel_encoder);
intel_panel_init(intel_connector);
intel_dvo->panel_wants_dither = true;
}

View File

@ -107,6 +107,21 @@ static const struct drm_format_info gen12_ccs_cc_formats[] = {
.hsub = 1, .vsub = 1, .has_alpha = true },
};
static const struct drm_format_info gen12_flat_ccs_cc_formats[] = {
{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
.char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
.hsub = 1, .vsub = 1, },
{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
.char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
.hsub = 1, .vsub = 1, },
{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
.char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
.hsub = 1, .vsub = 1, .has_alpha = true },
{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
.char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
.hsub = 1, .vsub = 1, .has_alpha = true },
};
struct intel_modifier_desc {
u64 modifier;
struct {
@ -135,11 +150,32 @@ struct intel_modifier_desc {
INTEL_PLANE_CAP_CCS_MC)
#define INTEL_PLANE_CAP_TILING_MASK (INTEL_PLANE_CAP_TILING_X | \
INTEL_PLANE_CAP_TILING_Y | \
INTEL_PLANE_CAP_TILING_Yf)
INTEL_PLANE_CAP_TILING_Yf | \
INTEL_PLANE_CAP_TILING_4)
#define INTEL_PLANE_CAP_TILING_NONE 0
static const struct intel_modifier_desc intel_modifiers[] = {
{
.modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS,
.display_ver = { 13, 13 },
.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_MC,
}, {
.modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC,
.display_ver = { 13, 13 },
.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC_CC,
.ccs.cc_planes = BIT(1),
FORMAT_OVERRIDE(gen12_flat_ccs_cc_formats),
}, {
.modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS,
.display_ver = { 13, 13 },
.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC,
}, {
.modifier = I915_FORMAT_MOD_4_TILED,
.display_ver = { 13, 13 },
.plane_caps = INTEL_PLANE_CAP_TILING_4,
}, {
.modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
.display_ver = { 12, 13 },
.plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_MC,
@ -380,17 +416,13 @@ bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier)
static bool format_is_yuv_semiplanar(const struct intel_modifier_desc *md,
const struct drm_format_info *info)
{
int yuv_planes;
if (!info->is_yuv)
return false;
if (plane_caps_contain_any(md->plane_caps, INTEL_PLANE_CAP_CCS_MASK))
yuv_planes = 4;
if (hweight8(md->ccs.planar_aux_planes) == 2)
return info->num_planes == 4;
else
yuv_planes = 2;
return info->num_planes == yuv_planes;
return info->num_planes == 2;
}
/**
@ -515,12 +547,13 @@ static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_p
int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
{
const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
struct drm_i915_private *i915 = to_i915(fb->dev);
if (intel_fb_is_ccs_modifier(fb->modifier))
if (md->ccs.packed_aux_planes | md->ccs.planar_aux_planes)
return main_to_ccs_plane(fb, main_plane);
else if (DISPLAY_VER(i915) < 11 &&
intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
format_is_yuv_semiplanar(md, fb->format))
return 1;
else
return 0;
@ -545,6 +578,15 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
return 128;
else
return 512;
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
case I915_FORMAT_MOD_4_TILED:
/*
* Each 4K tile consists of 64B(8*8) subtiles, with
* same shape as Y Tile(i.e 4*16B OWords)
*/
return 128;
case I915_FORMAT_MOD_Y_TILED_CCS:
if (intel_fb_is_ccs_aux_plane(fb, color_plane))
return 128;
@ -650,6 +692,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
return I915_TILING_Y;
case INTEL_PLANE_CAP_TILING_X:
return I915_TILING_X;
case INTEL_PLANE_CAP_TILING_4:
case INTEL_PLANE_CAP_TILING_Yf:
case INTEL_PLANE_CAP_TILING_NONE:
return I915_TILING_NONE;
@ -737,8 +780,13 @@ unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
case I915_FORMAT_MOD_Yf_TILED:
return 1 * 1024 * 1024;
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
return 16 * 1024;
default:
MISSING_CASE(fb->modifier);
return 0;

View File

@ -27,6 +27,7 @@ struct intel_plane_state;
#define INTEL_PLANE_CAP_TILING_X BIT(3)
#define INTEL_PLANE_CAP_TILING_Y BIT(4)
#define INTEL_PLANE_CAP_TILING_Yf BIT(5)
#define INTEL_PLANE_CAP_TILING_4 BIT(6)
bool intel_fb_is_ccs_modifier(u64 modifier);
bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier);

View File

@ -38,9 +38,12 @@
* forcibly disable it to allow proper screen updates.
*/
#include <linux/string_helpers.h>
#include <drm/drm_fourcc.h>
#include "i915_drv.h"
#include "i915_utils.h"
#include "i915_vgpu.h"
#include "intel_cdclk.h"
#include "intel_de.h"
@ -87,7 +90,6 @@ struct intel_fbc {
* with stolen_lock.
*/
struct mutex lock;
unsigned int possible_framebuffer_bits;
unsigned int busy_bits;
struct drm_mm_node compressed_fb;
@ -665,6 +667,10 @@ static bool intel_fbc_is_compressing(struct intel_fbc *fbc)
static void intel_fbc_nuke(struct intel_fbc *fbc)
{
struct drm_i915_private *i915 = fbc->i915;
drm_WARN_ON(&i915->drm, fbc->flip_pending);
trace_intel_fbc_nuke(fbc->state.plane);
fbc->funcs->nuke(fbc);
@ -946,6 +952,7 @@ static bool tiling_is_valid(const struct intel_plane_state *plane_state)
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
return DISPLAY_VER(i915) >= 9;
case I915_FORMAT_MOD_4_TILED:
case I915_FORMAT_MOD_X_TILED:
return true;
default:
@ -966,6 +973,7 @@ static void intel_fbc_update_state(struct intel_atomic_state *state,
struct intel_fbc_state *fbc_state = &fbc->state;
WARN_ON(plane_state->no_fbc_reason);
WARN_ON(fbc_state->plane && fbc_state->plane != plane);
fbc_state->plane = plane;
@ -1270,6 +1278,8 @@ static void __intel_fbc_disable(struct intel_fbc *fbc)
__intel_fbc_cleanup_cfb(fbc);
fbc->state.plane = NULL;
fbc->flip_pending = false;
fbc->busy_bits = 0;
}
static void __intel_fbc_post_update(struct intel_fbc *fbc)
@ -1313,7 +1323,7 @@ static unsigned int intel_fbc_get_frontbuffer_bit(struct intel_fbc *fbc)
if (fbc->state.plane)
return fbc->state.plane->frontbuffer_bit;
else
return fbc->possible_framebuffer_bits;
return 0;
}
static void __intel_fbc_invalidate(struct intel_fbc *fbc,
@ -1325,11 +1335,14 @@ static void __intel_fbc_invalidate(struct intel_fbc *fbc,
mutex_lock(&fbc->lock);
fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits;
frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc);
if (!frontbuffer_bits)
goto out;
if (fbc->state.plane && fbc->busy_bits)
intel_fbc_deactivate(fbc, "frontbuffer write");
fbc->busy_bits |= frontbuffer_bits;
intel_fbc_deactivate(fbc, "frontbuffer write");
out:
mutex_unlock(&fbc->lock);
}
@ -1351,18 +1364,22 @@ static void __intel_fbc_flush(struct intel_fbc *fbc,
{
mutex_lock(&fbc->lock);
frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc);
if (!frontbuffer_bits)
goto out;
fbc->busy_bits &= ~frontbuffer_bits;
if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE)
goto out;
if (!fbc->busy_bits && fbc->state.plane &&
(frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) {
if (fbc->active)
intel_fbc_nuke(fbc);
else if (!fbc->flip_pending)
__intel_fbc_post_update(fbc);
}
if (fbc->busy_bits || fbc->flip_pending)
goto out;
if (fbc->active)
intel_fbc_nuke(fbc);
else
intel_fbc_activate(fbc);
out:
mutex_unlock(&fbc->lock);
@ -1500,25 +1517,6 @@ void intel_fbc_update(struct intel_atomic_state *state,
}
}
/**
* intel_fbc_global_disable - globally disable FBC
* @i915: i915 device instance
*
* This function disables FBC regardless of which CRTC is associated with it.
*/
void intel_fbc_global_disable(struct drm_i915_private *i915)
{
struct intel_fbc *fbc;
enum intel_fbc_id fbc_id;
for_each_intel_fbc(i915, fbc, fbc_id) {
mutex_lock(&fbc->lock);
if (fbc->state.plane)
__intel_fbc_disable(fbc);
mutex_unlock(&fbc->lock);
}
}
static void intel_fbc_underrun_work_fn(struct work_struct *work)
{
struct intel_fbc *fbc = container_of(work, typeof(*fbc), underrun_work);
@ -1640,7 +1638,7 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *i915)
static bool need_fbc_vtd_wa(struct drm_i915_private *i915)
{
/* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */
if (intel_vtd_active(i915) &&
if (i915_vtd_active(i915) &&
(IS_SKYLAKE(i915) || IS_BROXTON(i915))) {
drm_info(&i915->drm,
"Disabling framebuffer compression (FBC) to prevent screen flicker with VT-d enabled\n");
@ -1652,11 +1650,7 @@ static bool need_fbc_vtd_wa(struct drm_i915_private *i915)
void intel_fbc_add_plane(struct intel_fbc *fbc, struct intel_plane *plane)
{
if (!fbc)
return;
plane->fbc = fbc;
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
}
static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915,
@ -1709,22 +1703,26 @@ void intel_fbc_init(struct drm_i915_private *i915)
drm_dbg_kms(&i915->drm, "Sanitized enable_fbc value: %d\n",
i915->params.enable_fbc);
for_each_fbc_id(i915, fbc_id) {
struct intel_fbc *fbc;
for_each_fbc_id(i915, fbc_id)
i915->fbc[fbc_id] = intel_fbc_create(i915, fbc_id);
}
fbc = intel_fbc_create(i915, fbc_id);
if (!fbc)
continue;
/**
* intel_fbc_sanitize - Sanitize FBC
* @i915: the i915 device
*
* Make sure FBC is initially disabled since we have no
* idea eg. into which parts of stolen it might be scribbling
* into.
*/
void intel_fbc_sanitize(struct drm_i915_private *i915)
{
struct intel_fbc *fbc;
enum intel_fbc_id fbc_id;
/*
* We still don't have any sort of hardware state readout
* for FBC, so deactivate it in case the BIOS activated it
* to make sure software matches the hardware state.
*/
for_each_intel_fbc(i915, fbc, fbc_id) {
if (intel_fbc_hw_is_active(fbc))
intel_fbc_hw_deactivate(fbc);
i915->fbc[fbc->id] = fbc;
}
}
@ -1743,7 +1741,7 @@ static int intel_fbc_debugfs_status_show(struct seq_file *m, void *unused)
if (fbc->active) {
seq_puts(m, "FBC enabled\n");
seq_printf(m, "Compressing: %s\n",
yesno(intel_fbc_is_compressing(fbc)));
str_yes_no(intel_fbc_is_compressing(fbc)));
} else {
seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason);
}

View File

@ -30,10 +30,10 @@ void intel_fbc_post_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_fbc_init(struct drm_i915_private *dev_priv);
void intel_fbc_cleanup(struct drm_i915_private *dev_priv);
void intel_fbc_sanitize(struct drm_i915_private *dev_priv);
void intel_fbc_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_fbc_disable(struct intel_crtc *crtc);
void intel_fbc_global_disable(struct drm_i915_private *dev_priv);
void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits,
enum fb_op_origin origin);

View File

@ -3,6 +3,8 @@
* Copyright © 2020 Intel Corporation
*/
#include <linux/string_helpers.h>
#include "intel_atomic.h"
#include "intel_crtc.h"
#include "intel_ddi.h"
@ -34,7 +36,7 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
}
I915_STATE_WARN(cur_state != state,
"FDI TX state assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
void assert_fdi_tx_enabled(struct drm_i915_private *i915, enum pipe pipe)
@ -55,7 +57,7 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
cur_state = intel_de_read(dev_priv, FDI_RX_CTL(pipe)) & FDI_RX_ENABLE;
I915_STATE_WARN(cur_state != state,
"FDI RX state assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
void assert_fdi_rx_enabled(struct drm_i915_private *i915, enum pipe pipe)
@ -93,7 +95,7 @@ static void assert_fdi_rx_pll(struct drm_i915_private *i915,
cur_state = intel_de_read(i915, FDI_RX_CTL(pipe)) & FDI_RX_PLL_ENABLE;
I915_STATE_WARN(cur_state != state,
"FDI RX PLL assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
void assert_fdi_rx_pll_enabled(struct drm_i915_private *i915, enum pipe pipe)

View File

@ -38,6 +38,16 @@
#include "intel_display_types.h"
#include "intel_gmbus.h"
struct intel_gmbus {
struct i2c_adapter adapter;
#define GMBUS_FORCE_BIT_RETRY (1U << 31)
u32 force_bit;
u32 reg0;
i915_reg_t gpio_reg;
struct i2c_algo_bit_data bit_algo;
struct drm_i915_private *dev_priv;
};
struct gmbus_pin {
const char *name;
enum i915_gpio gpio;
@ -106,51 +116,47 @@ static const struct gmbus_pin gmbus_pins_dg2[] = {
[GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ },
};
/* pin is expected to be valid */
static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915,
unsigned int pin)
{
if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG2)
return &gmbus_pins_dg2[pin];
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
return &gmbus_pins_dg1[pin];
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
return &gmbus_pins_icp[pin];
else if (HAS_PCH_CNP(dev_priv))
return &gmbus_pins_cnp[pin];
else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
return &gmbus_pins_bxt[pin];
else if (DISPLAY_VER(dev_priv) == 9)
return &gmbus_pins_skl[pin];
else if (IS_BROADWELL(dev_priv))
return &gmbus_pins_bdw[pin];
else
return &gmbus_pins[pin];
const struct gmbus_pin *pins;
size_t size;
if (INTEL_PCH_TYPE(i915) >= PCH_DG2) {
pins = gmbus_pins_dg2;
size = ARRAY_SIZE(gmbus_pins_dg2);
} else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) {
pins = gmbus_pins_dg1;
size = ARRAY_SIZE(gmbus_pins_dg1);
} else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) {
pins = gmbus_pins_icp;
size = ARRAY_SIZE(gmbus_pins_icp);
} else if (HAS_PCH_CNP(i915)) {
pins = gmbus_pins_cnp;
size = ARRAY_SIZE(gmbus_pins_cnp);
} else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) {
pins = gmbus_pins_bxt;
size = ARRAY_SIZE(gmbus_pins_bxt);
} else if (DISPLAY_VER(i915) == 9) {
pins = gmbus_pins_skl;
size = ARRAY_SIZE(gmbus_pins_skl);
} else if (IS_BROADWELL(i915)) {
pins = gmbus_pins_bdw;
size = ARRAY_SIZE(gmbus_pins_bdw);
} else {
pins = gmbus_pins;
size = ARRAY_SIZE(gmbus_pins);
}
if (pin >= size || !pins[pin].name)
return NULL;
return &pins[pin];
}
bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
unsigned int pin)
bool intel_gmbus_is_valid_pin(struct drm_i915_private *i915, unsigned int pin)
{
unsigned int size;
if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG2)
size = ARRAY_SIZE(gmbus_pins_dg2);
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
size = ARRAY_SIZE(gmbus_pins_dg1);
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
size = ARRAY_SIZE(gmbus_pins_icp);
else if (HAS_PCH_CNP(dev_priv))
size = ARRAY_SIZE(gmbus_pins_cnp);
else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
size = ARRAY_SIZE(gmbus_pins_bxt);
else if (DISPLAY_VER(dev_priv) == 9)
size = ARRAY_SIZE(gmbus_pins_skl);
else if (IS_BROADWELL(dev_priv))
size = ARRAY_SIZE(gmbus_pins_bdw);
else
size = ARRAY_SIZE(gmbus_pins);
return pin < size && get_gmbus_pin(dev_priv, pin)->name;
return get_gmbus_pin(i915, pin);
}
/* Intel GPIO access functions */
@ -294,9 +300,7 @@ static void set_data(void *data, int state_high)
static int
intel_gpio_pre_xfer(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus,
adapter);
struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
intel_gmbus_reset(dev_priv);
@ -313,9 +317,7 @@ intel_gpio_pre_xfer(struct i2c_adapter *adapter)
static void
intel_gpio_post_xfer(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus,
adapter);
struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
set_data(bus, 1);
@ -326,14 +328,13 @@ intel_gpio_post_xfer(struct i2c_adapter *adapter)
}
static void
intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
intel_gpio_setup(struct intel_gmbus *bus, i915_reg_t gpio_reg)
{
struct drm_i915_private *dev_priv = bus->dev_priv;
struct i2c_algo_bit_data *algo;
algo = &bus->bit_algo;
bus->gpio_reg = GPIO(get_gmbus_pin(dev_priv, pin)->gpio);
bus->gpio_reg = gpio_reg;
bus->adapter.algo_data = algo;
algo->setsda = set_data;
algo->setscl = set_clock;
@ -614,9 +615,7 @@ static int
do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
u32 gmbus0_source)
{
struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus,
adapter);
struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
int i = 0, inc, try = 0;
int ret = 0;
@ -746,8 +745,7 @@ out:
static int
gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
struct intel_gmbus *bus =
container_of(adapter, struct intel_gmbus, adapter);
struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
intel_wakeref_t wakeref;
int ret;
@ -771,8 +769,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus =
container_of(adapter, struct intel_gmbus, adapter);
struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
u8 cmd = DRM_HDCP_DDC_AKSV;
u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
@ -863,7 +860,6 @@ static const struct i2c_lock_operations gmbus_lock_ops = {
int intel_gmbus_setup(struct drm_i915_private *dev_priv)
{
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
struct intel_gmbus *bus;
unsigned int pin;
int ret;
@ -880,17 +876,24 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
init_waitqueue_head(&dev_priv->gmbus_wait_queue);
for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
if (!intel_gmbus_is_valid_pin(dev_priv, pin))
const struct gmbus_pin *gmbus_pin;
struct intel_gmbus *bus;
gmbus_pin = get_gmbus_pin(dev_priv, pin);
if (!gmbus_pin)
continue;
bus = &dev_priv->gmbus[pin];
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus) {
ret = -ENOMEM;
goto err;
}
bus->adapter.owner = THIS_MODULE;
bus->adapter.class = I2C_CLASS_DDC;
snprintf(bus->adapter.name,
sizeof(bus->adapter.name),
"i915 gmbus %s",
get_gmbus_pin(dev_priv, pin)->name);
"i915 gmbus %s", gmbus_pin->name);
bus->adapter.dev.parent = &pdev->dev;
bus->dev_priv = dev_priv;
@ -911,11 +914,15 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
if (IS_I830(dev_priv))
bus->force_bit = 1;
intel_gpio_setup(bus, pin);
intel_gpio_setup(bus, GPIO(gmbus_pin->gpio));
ret = i2c_add_adapter(&bus->adapter);
if (ret)
if (ret) {
kfree(bus);
goto err;
}
dev_priv->gmbus[pin] = bus;
}
intel_gmbus_reset(dev_priv);
@ -923,24 +930,19 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
return 0;
err:
while (pin--) {
if (!intel_gmbus_is_valid_pin(dev_priv, pin))
continue;
intel_gmbus_teardown(dev_priv);
bus = &dev_priv->gmbus[pin];
i2c_del_adapter(&bus->adapter);
}
return ret;
}
struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
unsigned int pin)
{
if (drm_WARN_ON(&dev_priv->drm,
!intel_gmbus_is_valid_pin(dev_priv, pin)))
if (drm_WARN_ON(&dev_priv->drm, pin >= ARRAY_SIZE(dev_priv->gmbus) ||
!dev_priv->gmbus[pin]))
return NULL;
return &dev_priv->gmbus[pin].adapter;
return &dev_priv->gmbus[pin]->adapter;
}
void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
@ -968,14 +970,18 @@ bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
void intel_gmbus_teardown(struct drm_i915_private *dev_priv)
{
struct intel_gmbus *bus;
unsigned int pin;
for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
if (!intel_gmbus_is_valid_pin(dev_priv, pin))
struct intel_gmbus *bus;
bus = dev_priv->gmbus[pin];
if (!bus)
continue;
bus = &dev_priv->gmbus[pin];
i2c_del_adapter(&bus->adapter);
kfree(bus);
dev_priv->gmbus[pin] = NULL;
}
}

View File

@ -20,6 +20,7 @@
#include "intel_connector.h"
#include "intel_de.h"
#include "intel_display_power.h"
#include "intel_display_power_well.h"
#include "intel_display_types.h"
#include "intel_hdcp.h"
#include "intel_pcode.h"

View File

@ -30,6 +30,7 @@
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
@ -2637,7 +2638,7 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n",
connector->base.id, connector->name,
yesno(scrambling), high_tmds_clock_ratio ? 40 : 10);
str_yes_no(scrambling), high_tmds_clock_ratio ? 40 : 10);
/* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */
return drm_scdc_set_high_tmds_clock_ratio(adapter,

View File

@ -389,7 +389,8 @@ intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(intel_connector, mode);
int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
enum drm_mode_status status;
@ -475,19 +476,12 @@ 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);
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
/* use cached edid if we have one */
if (!IS_ERR_OR_NULL(intel_connector->edid))
return drm_add_edid_modes(connector, intel_connector->edid);
mode = drm_mode_duplicate(dev, intel_connector->panel.fixed_mode);
if (mode == NULL)
return 0;
drm_mode_probed_add(connector, mode);
return 1;
return intel_panel_get_modes(intel_connector);
}
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
@ -786,16 +780,18 @@ bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv)
static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
{
struct drm_device *dev = lvds_encoder->base.base.dev;
struct drm_i915_private *dev_priv = to_i915(lvds_encoder->base.base.dev);
struct intel_connector *connector = lvds_encoder->attached_connector;
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
unsigned int val;
struct drm_i915_private *dev_priv = to_i915(dev);
/* use the module option value if specified */
if (dev_priv->params.lvds_channel_mode > 0)
return dev_priv->params.lvds_channel_mode == 2;
/* single channel LVDS is limited to 112 MHz */
if (lvds_encoder->attached_connector->panel.fixed_mode->clock > 112999)
if (fixed_mode->clock > 112999)
return true;
if (dmi_check_system(intel_dual_link_lvds))
@ -833,8 +829,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_display_mode *fixed_mode = NULL;
struct drm_display_mode *downclock_mode = NULL;
struct edid *edid;
i915_reg_t lvds_reg;
u32 lvds;
@ -973,35 +967,30 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
}
intel_connector->edid = edid;
fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
if (fixed_mode)
goto out;
/* Try EDID first */
intel_panel_add_edid_fixed_modes(intel_connector,
dev_priv->vbt.drrs_type != DRRS_TYPE_NONE);
/* Failed to get EDID, what about VBT? */
fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
if (fixed_mode)
goto out;
if (!intel_panel_preferred_fixed_mode(intel_connector))
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
/*
* If we didn't get EDID, try checking if the panel is already turned
* on. If so, assume that whatever is currently programmed is the
* correct mode.
* If we didn't get a fixed mode from EDID or VBT, try checking
* if the panel is already turned on. If so, assume that
* whatever is currently programmed is the correct mode.
*/
fixed_mode = intel_encoder_current_mode(intel_encoder);
if (fixed_mode) {
drm_dbg_kms(&dev_priv->drm, "using current (BIOS) mode: ");
drm_mode_debug_printmodeline(fixed_mode);
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
}
if (!intel_panel_preferred_fixed_mode(intel_connector))
intel_panel_add_encoder_fixed_mode(intel_connector, intel_encoder);
/* If we still don't have a mode after all that, give up. */
if (!fixed_mode)
goto failed;
out:
mutex_unlock(&dev->mode_config.mutex);
intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
/* If we still don't have a mode after all that, give up. */
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto failed;
intel_panel_init(intel_connector);
intel_backlight_setup(intel_connector, INVALID_PIPE);
lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
@ -1013,8 +1002,6 @@ out:
return;
failed:
mutex_unlock(&dev->mode_config.mutex);
drm_dbg_kms(&dev_priv->drm, "No LVDS modes found, disabling.\n");
drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder);

View File

@ -958,19 +958,21 @@ static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
static int check_overlay_dst(struct intel_overlay *overlay,
struct drm_intel_overlay_put_image *rec)
{
const struct intel_crtc_state *pipe_config =
const struct intel_crtc_state *crtc_state =
overlay->crtc->config;
struct drm_rect req, clipped;
if (rec->dst_height == 0 || rec->dst_width == 0)
drm_rect_init(&req, rec->dst_x, rec->dst_y,
rec->dst_width, rec->dst_height);
clipped = req;
drm_rect_intersect(&clipped, &crtc_state->pipe_src);
if (!drm_rect_visible(&clipped) ||
!drm_rect_equals(&clipped, &req))
return -EINVAL;
if (rec->dst_x < pipe_config->pipe_src_w &&
rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
rec->dst_y < pipe_config->pipe_src_h &&
rec->dst_y + rec->dst_height <= pipe_config->pipe_src_h)
return 0;
else
return -EINVAL;
return 0;
}
static int check_overlay_scaling(struct drm_intel_overlay_put_image *rec)
@ -1160,7 +1162,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
crtc->overlay = overlay;
/* line too wide, i.e. one-line-mode */
if (crtc->config->pipe_src_w > 1024 &&
if (drm_rect_width(&crtc->config->pipe_src) > 1024 &&
crtc->config->gmch_pfit.control & PFIT_ENABLE) {
overlay->pfit_active = true;
update_pfit_vscale_ratio(overlay);

View File

@ -35,6 +35,7 @@
#include "intel_connector.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_drrs.h"
#include "intel_panel.h"
bool intel_panel_use_ssc(struct drm_i915_private *i915)
@ -45,10 +46,83 @@ bool intel_panel_use_ssc(struct drm_i915_private *i915)
&& !(i915->quirks & QUIRK_LVDS_SSC_DISABLE);
}
const struct drm_display_mode *
intel_panel_preferred_fixed_mode(struct intel_connector *connector)
{
return list_first_entry_or_null(&connector->panel.fixed_modes,
struct drm_display_mode, head);
}
const struct drm_display_mode *
intel_panel_fixed_mode(struct intel_connector *connector,
const struct drm_display_mode *mode)
{
const struct drm_display_mode *fixed_mode, *best_mode = NULL;
int vrefresh = drm_mode_vrefresh(mode);
/* pick the fixed_mode that is closest in terms of vrefresh */
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
if (!best_mode ||
abs(drm_mode_vrefresh(fixed_mode) - vrefresh) <
abs(drm_mode_vrefresh(best_mode) - vrefresh))
best_mode = fixed_mode;
}
return best_mode;
}
const struct drm_display_mode *
intel_panel_downclock_mode(struct intel_connector *connector,
const struct drm_display_mode *adjusted_mode)
{
const struct drm_display_mode *fixed_mode, *best_mode = NULL;
int vrefresh = drm_mode_vrefresh(adjusted_mode);
/* pick the fixed_mode with the lowest refresh rate */
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
if (drm_mode_vrefresh(fixed_mode) < vrefresh) {
vrefresh = drm_mode_vrefresh(fixed_mode);
best_mode = fixed_mode;
}
}
return best_mode;
}
int intel_panel_get_modes(struct intel_connector *connector)
{
const struct drm_display_mode *fixed_mode;
int num_modes = 0;
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->base.dev, fixed_mode);
if (mode) {
drm_mode_probed_add(&connector->base, mode);
num_modes++;
}
}
return num_modes;
}
enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
if (list_empty(&connector->panel.fixed_modes) ||
list_is_singular(&connector->panel.fixed_modes))
return DRRS_TYPE_NONE;
return i915->vbt.drrs_type;
}
int intel_panel_compute_config(struct intel_connector *connector,
struct drm_display_mode *adjusted_mode)
{
const struct drm_display_mode *fixed_mode = connector->panel.fixed_mode;
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(connector, adjusted_mode);
if (!fixed_mode)
return 0;
@ -75,128 +149,142 @@ int intel_panel_compute_config(struct intel_connector *connector,
return 0;
}
static bool is_downclock_mode(const struct drm_display_mode *downclock_mode,
const struct drm_display_mode *fixed_mode)
static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
const struct drm_display_mode *preferred_mode)
{
return drm_mode_match(downclock_mode, fixed_mode,
return drm_mode_match(mode, preferred_mode,
DRM_MODE_MATCH_TIMINGS |
DRM_MODE_MATCH_FLAGS |
DRM_MODE_MATCH_3D_FLAGS) &&
downclock_mode->clock < fixed_mode->clock;
mode->clock != preferred_mode->clock;
}
struct drm_display_mode *
intel_panel_edid_downclock_mode(struct intel_connector *connector,
const struct drm_display_mode *fixed_mode)
static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
const struct drm_display_mode *scan, *best_mode = NULL;
struct drm_display_mode *downclock_mode;
int best_clock = fixed_mode->clock;
const struct drm_display_mode *preferred_mode =
intel_panel_preferred_fixed_mode(connector);
struct drm_display_mode *mode, *next;
list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
if (!is_alt_fixed_mode(mode, preferred_mode))
continue;
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] using alternate EDID fixed mode: " DRM_MODE_FMT "\n",
connector->base.base.id, connector->base.name,
DRM_MODE_ARG(mode));
list_move_tail(&mode->head, &connector->panel.fixed_modes);
}
}
static void intel_panel_add_edid_preferred_mode(struct intel_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct drm_display_mode *scan, *fixed_mode = NULL;
if (list_empty(&connector->base.probed_modes))
return;
/* make sure the preferred mode is first */
list_for_each_entry(scan, &connector->base.probed_modes, head) {
/*
* If one mode has the same resolution with the fixed_panel
* mode while they have the different refresh rate, it means
* that the reduced downclock is found. In such
* case we can set the different FPx0/1 to dynamically select
* between low and high frequency.
*/
if (is_downclock_mode(scan, fixed_mode) &&
scan->clock < best_clock) {
/*
* The downclock is already found. But we
* expect to find the lower downclock.
*/
best_clock = scan->clock;
best_mode = scan;
if (scan->type & DRM_MODE_TYPE_PREFERRED) {
fixed_mode = scan;
break;
}
}
if (!best_mode)
return NULL;
downclock_mode = drm_mode_duplicate(&dev_priv->drm, best_mode);
if (!downclock_mode)
return NULL;
if (!fixed_mode)
fixed_mode = list_first_entry(&connector->base.probed_modes,
typeof(*fixed_mode), head);
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] using downclock mode from EDID: ",
connector->base.base.id, connector->base.name);
drm_mode_debug_printmodeline(downclock_mode);
"[CONNECTOR:%d:%s] using %s EDID fixed mode: " DRM_MODE_FMT "\n",
connector->base.base.id, connector->base.name,
fixed_mode->type & DRM_MODE_TYPE_PREFERRED ? "preferred" : "first",
DRM_MODE_ARG(fixed_mode));
return downclock_mode;
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
list_move_tail(&fixed_mode->head, &connector->panel.fixed_modes);
}
struct drm_display_mode *
intel_panel_edid_fixed_mode(struct intel_connector *connector)
static void intel_panel_destroy_probed_modes(struct intel_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
const struct drm_display_mode *scan;
struct drm_display_mode *fixed_mode;
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct drm_display_mode *mode, *next;
if (list_empty(&connector->base.probed_modes))
return NULL;
/* prefer fixed mode from EDID if available */
list_for_each_entry(scan, &connector->base.probed_modes, head) {
if ((scan->type & DRM_MODE_TYPE_PREFERRED) == 0)
continue;
fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan);
if (!fixed_mode)
return NULL;
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] using preferred mode from EDID: ",
connector->base.base.id, connector->base.name);
drm_mode_debug_printmodeline(fixed_mode);
return fixed_mode;
list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
list_del(&mode->head);
drm_mode_destroy(&i915->drm, mode);
}
scan = list_first_entry(&connector->base.probed_modes,
typeof(*scan), head);
fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan);
if (!fixed_mode)
return NULL;
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] using first mode from EDID: ",
connector->base.base.id, connector->base.name);
drm_mode_debug_printmodeline(fixed_mode);
return fixed_mode;
}
struct drm_display_mode *
intel_panel_vbt_fixed_mode(struct intel_connector *connector)
void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
intel_panel_add_edid_preferred_mode(connector);
if (intel_panel_preferred_fixed_mode(connector) && has_drrs)
intel_panel_add_edid_alt_fixed_modes(connector);
intel_panel_destroy_probed_modes(connector);
}
static void intel_panel_add_fixed_mode(struct intel_connector *connector,
struct drm_display_mode *fixed_mode,
const char *type)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct drm_display_info *info = &connector->base.display_info;
struct drm_display_mode *fixed_mode;
if (!dev_priv->vbt.lfp_lvds_vbt_mode)
return NULL;
fixed_mode = drm_mode_duplicate(&dev_priv->drm,
dev_priv->vbt.lfp_lvds_vbt_mode);
if (!fixed_mode)
return NULL;
return;
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s] using mode from VBT: ",
connector->base.base.id, connector->base.name);
drm_mode_debug_printmodeline(fixed_mode);
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
info->width_mm = fixed_mode->width_mm;
info->height_mm = fixed_mode->height_mm;
return fixed_mode;
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s fixed mode: " DRM_MODE_FMT "\n",
connector->base.base.id, connector->base.name, type,
DRM_MODE_ARG(fixed_mode));
list_add_tail(&fixed_mode->head, &connector->panel.fixed_modes);
}
void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
const struct drm_display_mode *mode;
mode = i915->vbt.lfp_lvds_vbt_mode;
if (!mode)
return;
intel_panel_add_fixed_mode(connector,
drm_mode_duplicate(&i915->drm, mode),
"VBT LFP");
}
void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
const struct drm_display_mode *mode;
mode = i915->vbt.sdvo_lvds_vbt_mode;
if (!mode)
return;
intel_panel_add_fixed_mode(connector,
drm_mode_duplicate(&i915->drm, mode),
"VBT SDVO");
}
void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector,
struct intel_encoder *encoder)
{
intel_panel_add_fixed_mode(connector,
intel_encoder_current_mode(encoder),
"current (BIOS)");
}
/* adjusted_mode has been preset to be the panel's fixed mode */
@ -205,18 +293,20 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
{
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
int x, y, width, height;
/* Native modes don't need fitting */
if (adjusted_mode->crtc_hdisplay == crtc_state->pipe_src_w &&
adjusted_mode->crtc_vdisplay == crtc_state->pipe_src_h &&
if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
adjusted_mode->crtc_vdisplay == pipe_src_h &&
crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
return 0;
switch (conn_state->scaling_mode) {
case DRM_MODE_SCALE_CENTER:
width = crtc_state->pipe_src_w;
height = crtc_state->pipe_src_h;
width = pipe_src_w;
height = pipe_src_h;
x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
break;
@ -224,19 +314,17 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
case DRM_MODE_SCALE_ASPECT:
/* Scale but preserve the aspect ratio */
{
u32 scaled_width = adjusted_mode->crtc_hdisplay
* crtc_state->pipe_src_h;
u32 scaled_height = crtc_state->pipe_src_w
* adjusted_mode->crtc_vdisplay;
u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
if (scaled_width > scaled_height) { /* pillar */
width = scaled_height / crtc_state->pipe_src_h;
width = scaled_height / pipe_src_h;
if (width & 1)
width++;
x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
y = 0;
height = adjusted_mode->crtc_vdisplay;
} else if (scaled_width < scaled_height) { /* letter */
height = scaled_width / crtc_state->pipe_src_w;
height = scaled_width / pipe_src_w;
if (height & 1)
height++;
y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
@ -251,8 +339,8 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
break;
case DRM_MODE_SCALE_NONE:
WARN_ON(adjusted_mode->crtc_hdisplay != crtc_state->pipe_src_w);
WARN_ON(adjusted_mode->crtc_vdisplay != crtc_state->pipe_src_h);
WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
fallthrough;
case DRM_MODE_SCALE_FULLSCREEN:
x = y = 0;
@ -333,10 +421,10 @@ static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
{
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
u32 scaled_width = adjusted_mode->crtc_hdisplay *
crtc_state->pipe_src_h;
u32 scaled_height = crtc_state->pipe_src_w *
adjusted_mode->crtc_vdisplay;
int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
/* 965+ is easy, it does everything in hw */
if (scaled_width > scaled_height)
@ -345,7 +433,7 @@ static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
else if (scaled_width < scaled_height)
*pfit_control |= PFIT_ENABLE |
PFIT_SCALING_LETTER;
else if (adjusted_mode->crtc_hdisplay != crtc_state->pipe_src_w)
else if (adjusted_mode->crtc_hdisplay != pipe_src_w)
*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
}
@ -354,10 +442,10 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
u32 *border)
{
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
u32 scaled_width = adjusted_mode->crtc_hdisplay *
crtc_state->pipe_src_h;
u32 scaled_height = crtc_state->pipe_src_w *
adjusted_mode->crtc_vdisplay;
int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
u32 bits;
/*
@ -367,12 +455,11 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
*/
if (scaled_width > scaled_height) { /* pillar */
centre_horizontally(adjusted_mode,
scaled_height /
crtc_state->pipe_src_h);
scaled_height / pipe_src_h);
*border = LVDS_BORDER_ENABLE;
if (crtc_state->pipe_src_h != adjusted_mode->crtc_vdisplay) {
bits = panel_fitter_scaling(crtc_state->pipe_src_h,
if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
bits = panel_fitter_scaling(pipe_src_h,
adjusted_mode->crtc_vdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
@ -383,12 +470,11 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
}
} else if (scaled_width < scaled_height) { /* letter */
centre_vertically(adjusted_mode,
scaled_width /
crtc_state->pipe_src_w);
scaled_width / pipe_src_w);
*border = LVDS_BORDER_ENABLE;
if (crtc_state->pipe_src_w != adjusted_mode->crtc_hdisplay) {
bits = panel_fitter_scaling(crtc_state->pipe_src_w,
if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
bits = panel_fitter_scaling(pipe_src_w,
adjusted_mode->crtc_hdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
@ -413,10 +499,12 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
/* Native modes don't need fitting */
if (adjusted_mode->crtc_hdisplay == crtc_state->pipe_src_w &&
adjusted_mode->crtc_vdisplay == crtc_state->pipe_src_h)
if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
adjusted_mode->crtc_vdisplay == pipe_src_h)
goto out;
switch (conn_state->scaling_mode) {
@ -425,8 +513,8 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
* For centered modes, we have to calculate border widths &
* heights and modify the values programmed into the CRTC.
*/
centre_horizontally(adjusted_mode, crtc_state->pipe_src_w);
centre_vertically(adjusted_mode, crtc_state->pipe_src_h);
centre_horizontally(adjusted_mode, pipe_src_w);
centre_vertically(adjusted_mode, pipe_src_h);
border = LVDS_BORDER_ENABLE;
break;
case DRM_MODE_SCALE_ASPECT:
@ -442,8 +530,8 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
* Full scaling, even if it changes the aspect ratio.
* Fortunately this is all done for us in hw.
*/
if (crtc_state->pipe_src_h != adjusted_mode->crtc_vdisplay ||
crtc_state->pipe_src_w != adjusted_mode->crtc_hdisplay) {
if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
pipe_src_w != adjusted_mode->crtc_hdisplay) {
pfit_control |= PFIT_ENABLE;
if (DISPLAY_VER(dev_priv) >= 4)
pfit_control |= PFIT_SCALING_AUTO;
@ -508,7 +596,8 @@ enum drm_mode_status
intel_panel_mode_valid(struct intel_connector *connector,
const struct drm_display_mode *mode)
{
const struct drm_display_mode *fixed_mode = connector->panel.fixed_mode;
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(connector, mode);
if (!fixed_mode)
return MODE_OK;
@ -525,29 +614,29 @@ intel_panel_mode_valid(struct intel_connector *connector,
return MODE_OK;
}
int intel_panel_init(struct intel_panel *panel,
struct drm_display_mode *fixed_mode,
struct drm_display_mode *downclock_mode)
int intel_panel_init(struct intel_connector *connector)
{
struct intel_panel *panel = &connector->panel;
intel_backlight_init_funcs(panel);
panel->fixed_mode = fixed_mode;
panel->downclock_mode = downclock_mode;
drm_dbg_kms(connector->base.dev,
"[CONNECTOR:%d:%s] DRRS type: %s\n",
connector->base.base.id, connector->base.name,
intel_drrs_type_str(intel_panel_drrs_type(connector)));
return 0;
}
void intel_panel_fini(struct intel_panel *panel)
void intel_panel_fini(struct intel_connector *connector)
{
struct intel_connector *intel_connector =
container_of(panel, struct intel_connector, panel);
struct intel_panel *panel = &connector->panel;
struct drm_display_mode *fixed_mode, *next;
intel_backlight_destroy(panel);
if (panel->fixed_mode)
drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
if (panel->downclock_mode)
drm_mode_destroy(intel_connector->base.dev,
panel->downclock_mode);
list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) {
list_del(&fixed_mode->head);
drm_mode_destroy(connector->base.dev, fixed_mode);
}
}

View File

@ -9,23 +9,30 @@
#include <linux/types.h>
enum drm_connector_status;
enum drrs_type;
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
struct drm_i915_private;
struct intel_connector;
struct intel_crtc_state;
struct intel_panel;
struct intel_encoder;
int intel_panel_init(struct intel_panel *panel,
struct drm_display_mode *fixed_mode,
struct drm_display_mode *downclock_mode);
void intel_panel_fini(struct intel_panel *panel);
int intel_panel_init(struct intel_connector *connector);
void intel_panel_fini(struct intel_connector *connector);
enum drm_connector_status
intel_panel_detect(struct drm_connector *connector, bool force);
bool intel_panel_use_ssc(struct drm_i915_private *i915);
void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
const struct drm_display_mode *
intel_panel_preferred_fixed_mode(struct intel_connector *connector);
const struct drm_display_mode *
intel_panel_fixed_mode(struct intel_connector *connector,
const struct drm_display_mode *mode);
const struct drm_display_mode *
intel_panel_downclock_mode(struct intel_connector *connector,
const struct drm_display_mode *adjusted_mode);
int intel_panel_get_modes(struct intel_connector *connector);
enum drrs_type intel_panel_drrs_type(struct intel_connector *connector);
enum drm_mode_status
intel_panel_mode_valid(struct intel_connector *connector,
const struct drm_display_mode *mode);
@ -33,12 +40,10 @@ int intel_panel_fitting(struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
int intel_panel_compute_config(struct intel_connector *connector,
struct drm_display_mode *adjusted_mode);
struct drm_display_mode *
intel_panel_edid_downclock_mode(struct intel_connector *connector,
const struct drm_display_mode *fixed_mode);
struct drm_display_mode *
intel_panel_edid_fixed_mode(struct intel_connector *connector);
struct drm_display_mode *
intel_panel_vbt_fixed_mode(struct intel_connector *connector);
void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs);
void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector);
void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector);
void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector,
struct intel_encoder *encoder);
#endif /* __INTEL_PANEL_H__ */

View File

@ -14,6 +14,23 @@
#include "intel_pps.h"
#include "intel_sdvo.h"
bool intel_has_pch_trancoder(struct drm_i915_private *i915,
enum pipe pch_transcoder)
{
return HAS_PCH_IBX(i915) || HAS_PCH_CPT(i915) ||
(HAS_PCH_LPT_H(i915) && pch_transcoder == PIPE_A);
}
enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
if (HAS_PCH_LPT(i915))
return PIPE_A;
else
return crtc->pipe;
}
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, enum port port,
i915_reg_t dp_reg)
@ -88,6 +105,67 @@ static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
pipe_name(pipe));
}
static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv,
enum port port, i915_reg_t hdmi_reg)
{
u32 val = intel_de_read(dev_priv, hdmi_reg);
if (val & SDVO_ENABLE ||
(val & SDVO_PIPE_SEL_MASK) == SDVO_PIPE_SEL(PIPE_A))
return;
drm_dbg_kms(&dev_priv->drm,
"Sanitizing transcoder select for HDMI %c\n",
port_name(port));
val &= ~SDVO_PIPE_SEL_MASK;
val |= SDVO_PIPE_SEL(PIPE_A);
intel_de_write(dev_priv, hdmi_reg, val);
}
static void ibx_sanitize_pch_dp_port(struct drm_i915_private *dev_priv,
enum port port, i915_reg_t dp_reg)
{
u32 val = intel_de_read(dev_priv, dp_reg);
if (val & DP_PORT_EN ||
(val & DP_PIPE_SEL_MASK) == DP_PIPE_SEL(PIPE_A))
return;
drm_dbg_kms(&dev_priv->drm,
"Sanitizing transcoder select for DP %c\n",
port_name(port));
val &= ~DP_PIPE_SEL_MASK;
val |= DP_PIPE_SEL(PIPE_A);
intel_de_write(dev_priv, dp_reg, val);
}
static void ibx_sanitize_pch_ports(struct drm_i915_private *dev_priv)
{
/*
* The BIOS may select transcoder B on some of the PCH
* ports even it doesn't enable the port. This would trip
* assert_pch_dp_disabled() and assert_pch_hdmi_disabled().
* Sanitize the transcoder select bits to prevent that. We
* assume that the BIOS never actually enabled the port,
* because if it did we'd actually have to toggle the port
* on and back off to make the transcoder A select stick
* (see. intel_dp_link_down(), intel_disable_hdmi(),
* intel_disable_sdvo()).
*/
ibx_sanitize_pch_dp_port(dev_priv, PORT_B, PCH_DP_B);
ibx_sanitize_pch_dp_port(dev_priv, PORT_C, PCH_DP_C);
ibx_sanitize_pch_dp_port(dev_priv, PORT_D, PCH_DP_D);
/* PCH SDVOB multiplex with HDMIB */
ibx_sanitize_pch_hdmi_port(dev_priv, PORT_B, PCH_HDMIB);
ibx_sanitize_pch_hdmi_port(dev_priv, PORT_C, PCH_HDMIC);
ibx_sanitize_pch_hdmi_port(dev_priv, PORT_D, PCH_HDMID);
}
static void intel_pch_transcoder_set_m1_n1(struct intel_crtc *crtc,
const struct intel_link_m_n *m_n)
{
@ -181,7 +259,7 @@ static void ilk_enable_pch_transcoder(const struct intel_crtc_state *crtc_state)
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
/* Configure frame start delay to match the CPU */
val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK;
val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1);
val |= TRANS_CHICKEN2_FRAME_START_DELAY(crtc_state->framestart_delay - 1);
intel_de_write(dev_priv, reg, val);
}
@ -192,7 +270,7 @@ static void ilk_enable_pch_transcoder(const struct intel_crtc_state *crtc_state)
if (HAS_PCH_IBX(dev_priv)) {
/* Configure frame start delay to match the CPU */
val &= ~TRANS_FRAME_START_DELAY_MASK;
val |= TRANS_FRAME_START_DELAY(dev_priv->framestart_delay - 1);
val |= TRANS_FRAME_START_DELAY(crtc_state->framestart_delay - 1);
/*
* Make the BPC in transcoder be consistent with
@ -466,9 +544,11 @@ void ilk_pch_get_config(struct intel_crtc_state *crtc_state)
ilk_pch_clock_get(crtc_state);
}
static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder)
static void lpt_enable_pch_transcoder(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 val, pipeconf_val;
/* FDI must be feeding us bits for PCH ports */
@ -480,7 +560,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
/* Configure frame start delay to match the CPU */
val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK;
val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1);
val |= TRANS_CHICKEN2_FRAME_START_DELAY(crtc_state->framestart_delay - 1);
intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val);
val = TRANS_ENABLE;
@ -521,7 +601,6 @@ void lpt_pch_enable(struct intel_atomic_state *state,
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
assert_pch_transcoder_disabled(dev_priv, PIPE_A);
@ -530,7 +609,7 @@ void lpt_pch_enable(struct intel_atomic_state *state,
/* Set transcoder timing. */
ilk_pch_transcoder_set_timings(crtc_state, PIPE_A);
lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
lpt_enable_pch_transcoder(crtc_state);
}
void lpt_pch_disable(struct intel_atomic_state *state,
@ -563,3 +642,9 @@ void lpt_pch_get_config(struct intel_crtc_state *crtc_state)
crtc_state->hw.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv);
}
void intel_pch_sanitize(struct drm_i915_private *i915)
{
if (HAS_PCH_IBX(i915))
ibx_sanitize_pch_ports(i915);
}

View File

@ -6,11 +6,19 @@
#ifndef _INTEL_PCH_DISPLAY_H_
#define _INTEL_PCH_DISPLAY_H_
#include <linux/types.h>
enum pipe;
struct drm_i915_private;
struct intel_atomic_state;
struct intel_crtc;
struct intel_crtc_state;
struct intel_link_m_n;
bool intel_has_pch_trancoder(struct drm_i915_private *i915,
enum pipe pch_transcoder);
enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc);
void ilk_pch_pre_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void ilk_pch_enable(struct intel_atomic_state *state,
@ -32,4 +40,6 @@ void intel_pch_transcoder_get_m1_n1(struct intel_crtc *crtc,
void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc,
struct intel_link_m_n *m_n);
void intel_pch_sanitize(struct drm_i915_private *i915);
#endif

View File

@ -127,6 +127,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
break;
default:
drm_dbg(&dev_priv->drm,

View File

@ -100,11 +100,15 @@ static bool psr_global_enabled(struct intel_dp *intel_dp)
static bool psr2_global_enabled(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) {
case I915_PSR_DEBUG_DISABLE:
case I915_PSR_DEBUG_FORCE_PSR1:
return false;
default:
if (i915->params.enable_psr == 1)
return false;
return true;
}
}
@ -1217,6 +1221,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
intel_dp->psr.dc3co_exit_delay = val;
intel_dp->psr.dc3co_exitline = crtc_state->dc3co_exitline;
intel_dp->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch;
intel_dp->psr.psr2_sel_fetch_cff_enabled = false;
intel_dp->psr.req_psr2_sdp_prior_scanline =
crtc_state->req_psr2_sdp_prior_scanline;
@ -1432,28 +1437,42 @@ unlock:
mutex_unlock(&psr->lock);
}
static inline u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv)
static u32 man_trk_ctl_enable_bit_get(struct drm_i915_private *dev_priv)
{
return IS_ALDERLAKE_P(dev_priv) ? 0 : PSR2_MAN_TRK_CTL_ENABLE;
}
static u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv)
{
return IS_ALDERLAKE_P(dev_priv) ?
ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME :
PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
}
static inline u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev_priv)
static u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev_priv)
{
return IS_ALDERLAKE_P(dev_priv) ?
ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE :
PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE;
}
static u32 man_trk_ctl_continuos_full_frame(struct drm_i915_private *dev_priv)
{
return IS_ALDERLAKE_P(dev_priv) ?
ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME :
PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME;
}
static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
if (intel_dp->psr.psr2_sel_fetch_enabled)
intel_de_rmw(dev_priv,
PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0,
man_trk_ctl_single_full_frame_bit_get(dev_priv));
intel_de_write(dev_priv,
PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder),
man_trk_ctl_enable_bit_get(dev_priv) |
man_trk_ctl_partial_frame_bit_get(dev_priv) |
man_trk_ctl_single_full_frame_bit_get(dev_priv));
/*
* Display WA #0884: skl+
@ -1537,10 +1556,21 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->enable_psr2_sel_fetch)
return;
for_each_intel_encoder_mask_with_psr(&dev_priv->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
lockdep_assert_held(&intel_dp->psr.lock);
if (intel_dp->psr.psr2_sel_fetch_cff_enabled)
return;
break;
}
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder),
crtc_state->psr2_man_track_ctl);
}
@ -1550,10 +1580,7 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 val = 0;
if (!IS_ALDERLAKE_P(dev_priv))
val = PSR2_MAN_TRK_CTL_ENABLE;
u32 val = man_trk_ctl_enable_bit_get(dev_priv);
/* SF partial frame enable has to be set even on full update */
val |= man_trk_ctl_partial_frame_bit_get(dev_priv);
@ -1911,13 +1938,13 @@ static int _psr1_ready_for_pipe_update_locked(struct intel_dp *intel_dp)
}
/**
* intel_psr_wait_for_idle - wait for PSR be ready for a pipe update
* intel_psr_wait_for_idle_locked - wait for PSR be ready for a pipe update
* @new_crtc_state: new CRTC state
*
* This function is expected to be called from pipe_update_start() where it is
* not expected to race with PSR enable or disable.
*/
void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state)
void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(new_crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
@ -1930,12 +1957,10 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state)
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
int ret;
mutex_lock(&intel_dp->psr.lock);
lockdep_assert_held(&intel_dp->psr.lock);
if (!intel_dp->psr.enabled) {
mutex_unlock(&intel_dp->psr.lock);
if (!intel_dp->psr.enabled)
continue;
}
if (intel_dp->psr.psr2_enabled)
ret = _psr2_ready_for_pipe_update_locked(intel_dp);
@ -1944,8 +1969,6 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state)
if (ret)
drm_err(&dev_priv->drm, "PSR wait timed out, atomic update may fail\n");
mutex_unlock(&intel_dp->psr.lock);
}
}
@ -2122,6 +2145,27 @@ unlock:
mutex_unlock(&intel_dp->psr.lock);
}
static void _psr_invalidate_handle(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
if (intel_dp->psr.psr2_sel_fetch_enabled) {
u32 val;
if (intel_dp->psr.psr2_sel_fetch_cff_enabled)
return;
val = man_trk_ctl_enable_bit_get(dev_priv) |
man_trk_ctl_partial_frame_bit_get(dev_priv) |
man_trk_ctl_continuos_full_frame(dev_priv);
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), val);
intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
intel_dp->psr.psr2_sel_fetch_cff_enabled = true;
} else {
intel_psr_exit(intel_dp);
}
}
/**
* intel_psr_invalidate - Invalidade PSR
* @dev_priv: i915 device
@ -2158,7 +2202,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv,
intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits;
if (pipe_frontbuffer_bits)
intel_psr_exit(intel_dp);
_psr_invalidate_handle(intel_dp);
mutex_unlock(&intel_dp->psr.lock);
}
@ -2190,6 +2234,42 @@ tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits,
intel_dp->psr.dc3co_exit_delay);
}
static void _psr_flush_handle(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
if (intel_dp->psr.psr2_sel_fetch_enabled) {
if (intel_dp->psr.psr2_sel_fetch_cff_enabled) {
/* can we turn CFF off? */
if (intel_dp->psr.busy_frontbuffer_bits == 0) {
u32 val = man_trk_ctl_enable_bit_get(dev_priv) |
man_trk_ctl_partial_frame_bit_get(dev_priv) |
man_trk_ctl_single_full_frame_bit_get(dev_priv);
/*
* turn continuous full frame off and do a single
* full frame
*/
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder),
val);
intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
intel_dp->psr.psr2_sel_fetch_cff_enabled = false;
}
} else {
/*
* continuous full frame is disabled, only a single full
* frame is required
*/
psr_force_hw_tracking_exit(intel_dp);
}
} else {
psr_force_hw_tracking_exit(intel_dp);
if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits)
schedule_work(&intel_dp->psr.work);
}
}
/**
* intel_psr_flush - Flush PSR
* @dev_priv: i915 device
@ -2227,25 +2307,22 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
* we have to ensure that the PSR is not activated until
* intel_psr_resume() is called.
*/
if (intel_dp->psr.paused) {
mutex_unlock(&intel_dp->psr.lock);
continue;
}
if (intel_dp->psr.paused)
goto unlock;
if (origin == ORIGIN_FLIP ||
(origin == ORIGIN_CURSOR_UPDATE &&
!intel_dp->psr.psr2_sel_fetch_enabled)) {
tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin);
mutex_unlock(&intel_dp->psr.lock);
continue;
goto unlock;
}
/* By definition flush = invalidate + flush */
if (pipe_frontbuffer_bits)
psr_force_hw_tracking_exit(intel_dp);
if (pipe_frontbuffer_bits == 0)
goto unlock;
if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits)
schedule_work(&intel_dp->psr.work);
/* By definition flush = invalidate + flush */
_psr_flush_handle(intel_dp);
unlock:
mutex_unlock(&intel_dp->psr.lock);
}
}
@ -2436,3 +2513,51 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
return ret;
}
/**
* intel_psr_lock - grab PSR lock
* @crtc_state: the crtc state
*
* This is initially meant to be used by around CRTC update, when
* vblank sensitive registers are updated and we need grab the lock
* before it to avoid vblank evasion.
*/
void intel_psr_lock(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->has_psr)
return;
for_each_intel_encoder_mask_with_psr(&i915->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
mutex_lock(&intel_dp->psr.lock);
break;
}
}
/**
* intel_psr_unlock - release PSR lock
* @crtc_state: the crtc state
*
* Release the PSR lock that was held during pipe update.
*/
void intel_psr_unlock(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->has_psr)
return;
for_each_intel_encoder_mask_with_psr(&i915->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
mutex_unlock(&intel_dp->psr.lock);
break;
}
}

View File

@ -41,7 +41,7 @@ void intel_psr_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config);
void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
void intel_psr_short_pulse(struct intel_dp *intel_dp);
void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state);
void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state);
bool intel_psr_enabled(struct intel_dp *intel_dp);
int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
@ -55,4 +55,7 @@ void intel_psr2_disable_plane_sel_fetch(struct intel_plane *plane,
void intel_psr_pause(struct intel_dp *intel_dp);
void intel_psr_resume(struct intel_dp *intel_dp);
void intel_psr_lock(const struct intel_crtc_state *crtc_state);
void intel_psr_unlock(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_PSR_H__ */

View File

@ -283,7 +283,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
static const struct {
u8 cmd;
const char *name;
} __attribute__ ((packed)) sdvo_cmd_names[] = {
} __packed sdvo_cmd_names[] = {
SDVO_CMD_NAME_ENTRY(RESET),
SDVO_CMD_NAME_ENTRY(GET_DEVICE_CAPS),
SDVO_CMD_NAME_ENTRY(GET_FIRMWARE_REV),
@ -783,24 +783,22 @@ static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
static bool
intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
u16 clock,
u16 width,
u16 height)
const struct drm_display_mode *mode)
{
struct intel_sdvo_preferred_input_timing_args args;
memset(&args, 0, sizeof(args));
args.clock = clock;
args.width = width;
args.height = height;
args.clock = mode->clock / 10;
args.width = mode->hdisplay;
args.height = mode->vdisplay;
args.interlace = 0;
if (IS_LVDS(intel_sdvo_connector)) {
const struct drm_display_mode *fixed_mode =
intel_sdvo_connector->base.panel.fixed_mode;
intel_panel_fixed_mode(&intel_sdvo_connector->base, mode);
if (fixed_mode->hdisplay != width ||
fixed_mode->vdisplay != height)
if (fixed_mode->hdisplay != args.width ||
fixed_mode->vdisplay != args.height)
args.scaled = 1;
}
@ -1236,9 +1234,7 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,
intel_sdvo_connector,
mode->clock / 10,
mode->hdisplay,
mode->vdisplay))
mode))
return false;
if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
@ -1335,6 +1331,8 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
adjusted_mode);
pipe_config->sdvo_tv_clock = true;
} else if (IS_LVDS(intel_sdvo_connector)) {
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(&intel_sdvo_connector->base, mode);
int ret;
ret = intel_panel_compute_config(&intel_sdvo_connector->base,
@ -1342,8 +1340,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
if (ret)
return ret;
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
intel_sdvo_connector->base.panel.fixed_mode))
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, fixed_mode))
return -EINVAL;
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
@ -1465,7 +1462,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
const struct intel_sdvo_connector_state *sdvo_state =
to_intel_sdvo_connector_state(conn_state);
const struct intel_sdvo_connector *intel_sdvo_connector =
struct intel_sdvo_connector *intel_sdvo_connector =
to_intel_sdvo_connector(conn_state->connector);
const struct drm_display_mode *mode = &crtc_state->hw.mode;
struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
@ -1496,11 +1493,14 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
return;
/* lvds has a special fixed output timing. */
if (IS_LVDS(intel_sdvo_connector))
intel_sdvo_get_dtd_from_mode(&output_dtd,
intel_sdvo_connector->base.panel.fixed_mode);
else
if (IS_LVDS(intel_sdvo_connector)) {
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(&intel_sdvo_connector->base, mode);
intel_sdvo_get_dtd_from_mode(&output_dtd, fixed_mode);
} else {
intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
}
if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
drm_info(&dev_priv->drm,
"Setting output timings on %s failed\n",
@ -2291,33 +2291,12 @@ static int intel_sdvo_get_lvds_modes(struct drm_connector *connector)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct drm_display_mode *newmode;
int num_modes = 0;
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
/*
* Fetch modes from VBT. For SDVO prefer the VBT mode since some
* SDVO->LVDS transcoders can't cope with the EDID mode.
*/
if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) {
newmode = drm_mode_duplicate(connector->dev,
dev_priv->vbt.sdvo_lvds_vbt_mode);
if (newmode != NULL) {
/* Guarantee the mode is preferred */
newmode->type = (DRM_MODE_TYPE_PREFERRED |
DRM_MODE_TYPE_DRIVER);
drm_mode_probed_add(connector, newmode);
num_modes++;
}
}
/*
* Attempt to get the mode list from DDC.
* Assume that the preferred modes are
* arranged in priority order.
*/
num_modes += intel_panel_get_modes(to_intel_connector(connector));
num_modes += intel_ddc_get_modes(connector, &intel_sdvo->ddc);
return num_modes;
@ -2747,6 +2726,8 @@ static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
__drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
&conn_state->base.base);
INIT_LIST_HEAD(&sdvo_connector->base.panel.fixed_modes);
return sdvo_connector;
}
@ -2890,7 +2871,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
struct drm_connector *connector;
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
struct drm_display_mode *mode;
DRM_DEBUG_KMS("initialising LVDS device %d\n", device);
@ -2919,20 +2899,20 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;
intel_sdvo_get_lvds_modes(connector);
/*
* Fetch modes from VBT. For SDVO prefer the VBT mode since some
* SDVO->LVDS transcoders can't cope with the EDID mode.
*/
intel_panel_add_vbt_sdvo_fixed_mode(intel_connector);
list_for_each_entry(mode, &connector->probed_modes, head) {
if (mode->type & DRM_MODE_TYPE_PREFERRED) {
struct drm_display_mode *fixed_mode =
drm_mode_duplicate(connector->dev, mode);
intel_panel_init(&intel_connector->panel,
fixed_mode, NULL);
break;
}
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
intel_ddc_get_modes(connector, &intel_sdvo->ddc);
intel_panel_add_edid_fixed_modes(intel_connector, false);
}
if (!intel_connector->panel.fixed_mode)
intel_panel_init(intel_connector);
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto err;
return true;

View File

@ -32,10 +32,14 @@ void intel_snps_phy_wait_for_calibration(struct drm_i915_private *i915)
if (!intel_phy_is_snps(i915, phy))
continue;
/*
* If calibration does not complete successfully, we'll remember
* which phy was affected and skip setup of the corresponding
* output later.
*/
if (intel_de_wait_for_clear(i915, DG2_PHY_MISC(phy),
DG2_PHY_DP_TX_ACK_MASK, 25))
drm_err(&i915->drm, "SNPS PHY %c failed to calibrate after 25ms.\n",
phy_name(phy));
i915->snps_phy_failed_calibration |= BIT(phy);
}
}

View File

@ -30,6 +30,8 @@
* support.
*/
#include <linux/string_helpers.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_color_mgmt.h>
@ -96,13 +98,13 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
if (src_x % hsub || src_w % hsub) {
drm_dbg_kms(&i915->drm, "src x/w (%u, %u) must be a multiple of %u (rotated: %s)\n",
src_x, src_w, hsub, yesno(rotated));
src_x, src_w, hsub, str_yes_no(rotated));
return -EINVAL;
}
if (src_y % vsub || src_h % vsub) {
drm_dbg_kms(&i915->drm, "src y/h (%u, %u) must be a multiple of %u (rotated: %s)\n",
src_y, src_h, vsub, yesno(rotated));
src_y, src_h, vsub, str_yes_no(rotated));
return -EINVAL;
}
@ -430,9 +432,6 @@ vlv_sprite_update_noarm(struct intel_plane *plane,
int crtc_y = plane_state->uapi.dst.y1;
u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, SPSTRIDE(pipe, plane_id),
plane_state->view.color_plane[0].mapping_stride);
@ -440,8 +439,6 @@ vlv_sprite_update_noarm(struct intel_plane *plane,
SP_POS_Y(crtc_y) | SP_POS_X(crtc_x));
intel_de_write_fw(dev_priv, SPSIZE(pipe, plane_id),
SP_HEIGHT(crtc_h - 1) | SP_WIDTH(crtc_w - 1));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -457,14 +454,11 @@ vlv_sprite_update_arm(struct intel_plane *plane,
u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y;
u32 sprctl, linear_offset;
unsigned long irqflags;
sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
chv_sprite_update_csc(plane_state);
@ -494,8 +488,6 @@ vlv_sprite_update_arm(struct intel_plane *plane,
vlv_sprite_update_clrc(plane_state);
vlv_sprite_update_gamma(plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -505,14 +497,9 @@ vlv_sprite_disable_arm(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
enum plane_id plane_id = plane->id;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, SPCNTR(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, SPSURF(pipe, plane_id), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool
@ -862,15 +849,12 @@ ivb_sprite_update_noarm(struct intel_plane *plane,
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u32 sprscale = 0;
unsigned long irqflags;
if (crtc_w != src_w || crtc_h != src_h)
sprscale = SPRITE_SCALE_ENABLE |
SPRITE_SRC_WIDTH(src_w - 1) |
SPRITE_SRC_HEIGHT(src_h - 1);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, SPRSTRIDE(pipe),
plane_state->view.color_plane[0].mapping_stride);
intel_de_write_fw(dev_priv, SPRPOS(pipe),
@ -879,8 +863,6 @@ ivb_sprite_update_noarm(struct intel_plane *plane,
SPRITE_HEIGHT(crtc_h - 1) | SPRITE_WIDTH(crtc_w - 1));
if (IS_IVYBRIDGE(dev_priv))
intel_de_write_fw(dev_priv, SPRSCALE(pipe), sprscale);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -895,14 +877,11 @@ ivb_sprite_update_arm(struct intel_plane *plane,
u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y;
u32 sprctl, linear_offset;
unsigned long irqflags;
sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (key->flags) {
intel_de_write_fw(dev_priv, SPRKEYVAL(pipe), key->min_value);
intel_de_write_fw(dev_priv, SPRKEYMSK(pipe),
@ -931,8 +910,6 @@ ivb_sprite_update_arm(struct intel_plane *plane,
intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
ivb_sprite_update_gamma(plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -941,17 +918,12 @@ ivb_sprite_disable_arm(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, SPRCTL(pipe), 0);
/* Disable the scaler */
if (IS_IVYBRIDGE(dev_priv))
intel_de_write_fw(dev_priv, SPRSCALE(pipe), 0);
intel_de_write_fw(dev_priv, SPRSURF(pipe), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool
@ -1204,15 +1176,12 @@ g4x_sprite_update_noarm(struct intel_plane *plane,
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u32 dvsscale = 0;
unsigned long irqflags;
if (crtc_w != src_w || crtc_h != src_h)
dvsscale = DVS_SCALE_ENABLE |
DVS_SRC_WIDTH(src_w - 1) |
DVS_SRC_HEIGHT(src_h - 1);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DVSSTRIDE(pipe),
plane_state->view.color_plane[0].mapping_stride);
intel_de_write_fw(dev_priv, DVSPOS(pipe),
@ -1220,8 +1189,6 @@ g4x_sprite_update_noarm(struct intel_plane *plane,
intel_de_write_fw(dev_priv, DVSSIZE(pipe),
DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1));
intel_de_write_fw(dev_priv, DVSSCALE(pipe), dvsscale);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -1236,14 +1203,11 @@ g4x_sprite_update_arm(struct intel_plane *plane,
u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y;
u32 dvscntr, linear_offset;
unsigned long irqflags;
dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (key->flags) {
intel_de_write_fw(dev_priv, DVSKEYVAL(pipe), key->min_value);
intel_de_write_fw(dev_priv, DVSKEYMSK(pipe),
@ -1267,8 +1231,6 @@ g4x_sprite_update_arm(struct intel_plane *plane,
g4x_sprite_update_gamma(plane_state);
else
ilk_sprite_update_gamma(plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -1277,16 +1239,11 @@ g4x_sprite_disable_arm(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DVSCNTR(pipe), 0);
/* Disable the scaler */
intel_de_write_fw(dev_priv, DVSSCALE(pipe), 0);
intel_de_write_fw(dev_priv, DVSSURF(pipe), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool

View File

@ -1145,8 +1145,8 @@ intel_tv_get_config(struct intel_encoder *encoder,
intel_tv_mode_to_mode(&mode, &tv_mode);
drm_dbg_kms(&dev_priv->drm, "TV mode:\n");
drm_mode_debug_printmodeline(&mode);
drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n",
DRM_MODE_ARG(&mode));
intel_tv_scale_mode_horiz(&mode, hdisplay,
xpos, mode.hdisplay - xsize - xpos);
@ -1250,8 +1250,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
tv_conn_state->bypass_vfilter = false;
}
drm_dbg_kms(&dev_priv->drm, "TV mode:\n");
drm_mode_debug_printmodeline(adjusted_mode);
drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n",
DRM_MODE_ARG(adjusted_mode));
/*
* The pipe scanline counter behaviour looks as follows when
@ -1806,8 +1806,8 @@ intel_tv_get_modes(struct drm_connector *connector)
*/
intel_tv_mode_to_mode(mode, tv_mode);
if (count == 0) {
drm_dbg_kms(&dev_priv->drm, "TV mode:\n");
drm_mode_debug_printmodeline(mode);
drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n",
DRM_MODE_ARG(mode));
}
intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
intel_tv_scale_mode_vert(mode, input->h, 0, 0);

View File

@ -289,6 +289,9 @@ struct bdb_general_features {
#define HDMI_MAX_DATA_RATE_PLATFORM 0 /* 204 */
#define HDMI_MAX_DATA_RATE_297 1 /* 204 */
#define HDMI_MAX_DATA_RATE_165 2 /* 204 */
#define HDMI_MAX_DATA_RATE_594 3 /* 249 */
#define HDMI_MAX_DATA_RATE_340 4 /* 249 */
#define HDMI_MAX_DATA_RATE_300 5 /* 249 */
#define LEGACY_CHILD_DEVICE_CONFIG_SIZE 33
@ -719,20 +722,22 @@ struct bdb_lvds_options {
/*
* Block 41 - LFP Data Table Pointers
*/
struct lvds_lfp_data_ptr_table {
u16 offset; /* offsets are from start of bdb */
u8 table_size;
} __packed;
/* LFP pointer table contains entries to the struct below */
struct lvds_lfp_data_ptr {
u16 fp_timing_offset; /* offsets are from start of bdb */
u8 fp_table_size;
u16 dvo_timing_offset;
u8 dvo_table_size;
u16 panel_pnp_id_offset;
u8 pnp_table_size;
struct lvds_lfp_data_ptr_table fp_timing;
struct lvds_lfp_data_ptr_table dvo_timing;
struct lvds_lfp_data_ptr_table panel_pnp_id;
} __packed;
struct bdb_lvds_lfp_data_ptrs {
u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
struct lvds_lfp_data_ptr ptr[16];
struct lvds_lfp_data_ptr_table panel_name; /* 156-163? */
} __packed;
/*
@ -774,6 +779,10 @@ struct bdb_lvds_lfp_data {
struct lvds_lfp_data_entry data[16];
} __packed;
struct lvds_lfp_panel_name {
u8 name[13];
} __packed;
/*
* Block 43 - LFP Backlight Control Data Block
*/

View File

@ -378,10 +378,18 @@ calculate_rc_params(struct rc_parameters *rc,
{
int bpc = vdsc_cfg->bits_per_component;
int bpp = vdsc_cfg->bits_per_pixel >> 4;
int ofs_und6[] = { 0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 };
int ofs_und8[] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 };
int ofs_und12[] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 };
int ofs_und15[] = { 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 };
static const s8 ofs_und6[] = {
0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12
};
static const s8 ofs_und8[] = {
2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12
};
static const s8 ofs_und12[] = {
2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12
};
static const s8 ofs_und15[] = {
10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12
};
int qp_bpc_modifier = (bpc - 8) * 2;
u32 res, buf_i, bpp_i;
@ -579,7 +587,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state)
u8 num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1;
int i = 0;
if (crtc_state->bigjoiner)
if (crtc_state->bigjoiner_pipes)
num_vdsc_instances *= 2;
/* Populate PICTURE_PARAMETER_SET_0 registers */
@ -1113,7 +1121,7 @@ void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state)
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dss_ctl1_val = 0;
if (crtc_state->bigjoiner && !crtc_state->dsc.compression_enable) {
if (crtc_state->bigjoiner_pipes && !crtc_state->dsc.compression_enable) {
if (intel_crtc_is_bigjoiner_slave(crtc_state))
dss_ctl1_val |= UNCOMPRESSED_JOINER_SLAVE;
else
@ -1140,7 +1148,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state)
dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
dss_ctl1_val |= JOINER_ENABLE;
}
if (crtc_state->bigjoiner) {
if (crtc_state->bigjoiner_pipes) {
dss_ctl1_val |= BIG_JOINER_ENABLE;
if (!intel_crtc_is_bigjoiner_slave(crtc_state))
dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE;
@ -1156,7 +1164,7 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
/* Disable only if either of them is enabled */
if (old_crtc_state->dsc.compression_enable ||
old_crtc_state->bigjoiner) {
old_crtc_state->bigjoiner_pipes) {
intel_de_write(dev_priv, dss_ctl1_reg(crtc, old_crtc_state->cpu_transcoder), 0);
intel_de_write(dev_priv, dss_ctl2_reg(crtc, old_crtc_state->cpu_transcoder), 0);
}

View File

@ -69,9 +69,9 @@ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_stat
/* The hw imposes the extra scanline before frame start */
if (DISPLAY_VER(i915) >= 13)
return crtc_state->vrr.guardband + i915->framestart_delay + 1;
return crtc_state->vrr.guardband + crtc_state->framestart_delay + 1;
else
return crtc_state->vrr.pipeline_full + i915->framestart_delay + 1;
return crtc_state->vrr.pipeline_full + crtc_state->framestart_delay + 1;
}
int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state)

View File

@ -197,7 +197,8 @@ int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
return skl_update_scaler(crtc_state, !crtc_state->hw.active,
SKL_CRTC_INDEX,
&crtc_state->scaler_state.scaler_id,
crtc_state->pipe_src_w, crtc_state->pipe_src_h,
drm_rect_width(&crtc_state->pipe_src),
drm_rect_height(&crtc_state->pipe_src),
width, height, NULL, 0,
crtc_state->pch_pfit.enabled);
}
@ -400,10 +401,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct intel_crtc_scaler_state *scaler_state =
&crtc_state->scaler_state;
struct drm_rect src = {
.x2 = crtc_state->pipe_src_w << 16,
.y2 = crtc_state->pipe_src_h << 16,
};
const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
u16 uv_rgb_hphase, uv_rgb_vphase;
enum pipe pipe = crtc->pipe;
@ -412,7 +409,7 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
int x = dst->x1;
int y = dst->y1;
int hscale, vscale;
unsigned long irqflags;
struct drm_rect src;
int id;
u32 ps_ctrl;
@ -423,6 +420,10 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
crtc_state->scaler_state.scaler_id < 0))
return;
drm_rect_init(&src, 0, 0,
drm_rect_width(&crtc_state->pipe_src) << 16,
drm_rect_height(&crtc_state->pipe_src) << 16);
hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX);
vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX);
@ -434,8 +435,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
skl_scaler_setup_filter(dev_priv, pipe, id, 0,
crtc_state->hw.scaling_filter);
@ -449,8 +448,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
x << 16 | y);
intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id),
width << 16 | height);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
void
@ -519,15 +516,10 @@ static void skl_detach_scaler(struct intel_crtc *crtc, int id)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, SKL_PS_CTRL(crtc->pipe, id), 0);
intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(crtc->pipe, id), 0);
intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(crtc->pipe, id), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
/*

View File

@ -615,9 +615,20 @@ skl_plane_disable_arm(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
skl_write_plane_wm(plane, crtc_state);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0);
}
static void
icl_plane_disable_arm(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0);
@ -627,8 +638,6 @@ skl_plane_disable_arm(struct intel_plane *plane,
intel_psr2_disable_plane_sel_fetch(plane, crtc_state);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool
@ -762,6 +771,18 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier)
return PLANE_CTL_TILED_X;
case I915_FORMAT_MOD_Y_TILED:
return PLANE_CTL_TILED_Y;
case I915_FORMAT_MOD_4_TILED:
return PLANE_CTL_TILED_4;
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
return PLANE_CTL_TILED_4 |
PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
return PLANE_CTL_TILED_4 |
PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
@ -1065,7 +1086,7 @@ static void icl_plane_csc_load_black(struct intel_plane *plane)
intel_de_write_fw(i915, PLANE_CSC_POSTOFF(pipe, plane_id, 2), 0);
}
static int skl_plane_color_plane(const struct intel_plane_state *plane_state)
static int icl_plane_color_plane(const struct intel_plane_state *plane_state)
{
/* Program the UV plane on planar master */
if (plane_state->planar_linked_plane && !plane_state->planar_slave)
@ -1082,14 +1103,11 @@ skl_plane_update_noarm(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
int color_plane = skl_plane_color_plane(plane_state);
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
u32 stride = skl_plane_stride(plane_state, 0);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
unsigned long irqflags;
/* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) {
@ -1097,15 +1115,6 @@ skl_plane_update_noarm(struct intel_plane *plane,
crtc_y = 0;
}
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/*
* FIXME: pxp session invalidation can hit any time even at time of commit
* or after the commit, display content will be garbage.
*/
if (plane_state->force_black)
icl_plane_csc_load_black(plane);
intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id),
PLANE_STRIDE_(stride));
intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id),
@ -1113,25 +1122,7 @@ skl_plane_update_noarm(struct intel_plane *plane,
intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
if (intel_fb_is_rc_ccs_cc_modifier(fb->modifier)) {
intel_de_write_fw(dev_priv, PLANE_CC_VAL(pipe, plane_id, 0),
lower_32_bits(plane_state->ccval));
intel_de_write_fw(dev_priv, PLANE_CC_VAL(pipe, plane_id, 1),
upper_32_bits(plane_state->ccval));
}
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id),
plane_state->cus_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id))
icl_program_input_csc(plane, crtc_state, plane_state);
skl_write_plane_wm(plane, crtc_state);
intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
@ -1142,21 +1133,17 @@ skl_plane_update_arm(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
int color_plane = skl_plane_color_plane(plane_state);
u32 x = plane_state->view.color_plane[color_plane].x;
u32 y = plane_state->view.color_plane[color_plane].y;
u32 plane_color_ctl = 0;
u32 plane_ctl = plane_state->ctl;
unsigned long irqflags;
u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y;
u32 plane_ctl, plane_color_ctl = 0;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
plane_ctl = plane_state->ctl |
skl_plane_ctl_crtc(crtc_state);
if (DISPLAY_VER(dev_priv) >= 10)
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), skl_plane_keyval(plane_state));
intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), skl_plane_keymsk(plane_state));
intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), skl_plane_keymax(plane_state));
@ -1165,12 +1152,11 @@ skl_plane_update_arm(struct intel_plane *plane,
PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id),
skl_plane_aux_dist(plane_state, color_plane));
skl_plane_aux_dist(plane_state, 0));
if (DISPLAY_VER(dev_priv) < 11)
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id),
PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) |
PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id),
PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) |
PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
if (DISPLAY_VER(dev_priv) >= 10)
intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl);
@ -1192,9 +1178,116 @@ skl_plane_update_arm(struct intel_plane *plane,
*/
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
skl_plane_surf(plane_state, color_plane));
skl_plane_surf(plane_state, 0));
}
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
static void
icl_plane_update_noarm(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
int color_plane = icl_plane_color_plane(plane_state);
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
int x = plane_state->view.color_plane[color_plane].x;
int y = plane_state->view.color_plane[color_plane].y;
int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u32 plane_color_ctl;
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
/* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) {
crtc_x = 0;
crtc_y = 0;
}
intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id),
PLANE_STRIDE_(stride));
intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id),
PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), skl_plane_keyval(plane_state));
intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), skl_plane_keymsk(plane_state));
intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), skl_plane_keymax(plane_state));
intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id),
PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
if (intel_fb_is_rc_ccs_cc_modifier(fb->modifier)) {
intel_de_write_fw(dev_priv, PLANE_CC_VAL(pipe, plane_id, 0),
lower_32_bits(plane_state->ccval));
intel_de_write_fw(dev_priv, PLANE_CC_VAL(pipe, plane_id, 1),
upper_32_bits(plane_state->ccval));
}
/* FLAT CCS doesn't need to program AUX_DIST */
if (!HAS_FLAT_CCS(dev_priv))
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id),
skl_plane_aux_dist(plane_state, color_plane));
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id),
plane_state->cus_ctl);
intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id))
icl_program_input_csc(plane, crtc_state, plane_state);
skl_write_plane_wm(plane, crtc_state);
/*
* FIXME: pxp session invalidation can hit any time even at time of commit
* or after the commit, display content will be garbage.
*/
if (plane_state->force_black)
icl_plane_csc_load_black(plane);
intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane);
}
static void
icl_plane_update_arm(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
int color_plane = icl_plane_color_plane(plane_state);
u32 plane_ctl;
plane_ctl = plane_state->ctl |
skl_plane_ctl_crtc(crtc_state);
/*
* Enable the scaler before the plane so that we don't
* get a catastrophic underrun even if the two operations
* end up happening in two different frames.
*
* TODO: split into noarm+arm pair
*/
if (plane_state->scaler_id >= 0)
skl_program_plane_scaler(plane, crtc_state, plane_state);
/*
* The control register self-arms if the plane was previously
* disabled. Try to make the plane enable atomic by writing
* the control register just before the surface register.
*/
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
skl_plane_surf(plane_state, color_plane));
}
static void
@ -1204,7 +1297,6 @@ skl_plane_async_flip(struct intel_plane *plane,
bool async_flip)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
unsigned long irqflags;
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 plane_ctl = plane_state->ctl;
@ -1214,13 +1306,9 @@ skl_plane_async_flip(struct intel_plane *plane,
if (async_flip)
plane_ctl |= PLANE_CTL_ASYNC_FLIP;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
skl_plane_surf(plane_state, 0));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool intel_format_is_p01x(u32 format)
@ -1325,7 +1413,7 @@ static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_s
to_i915(plane_state->uapi.plane->dev);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_w = drm_rect_width(&plane_state->uapi.dst);
int pipe_src_w = crtc_state->pipe_src_w;
int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
/*
* Display WA #1175: glk
@ -1545,9 +1633,10 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
/*
* CCS AUX surface doesn't have its own x/y offsets, we must make sure
* they match with the main surface x/y offsets.
* they match with the main surface x/y offsets. On DG2
* there's no aux plane on fb so skip this checking.
*/
if (intel_fb_is_ccs_modifier(fb->modifier)) {
if (intel_fb_is_ccs_modifier(fb->modifier) && aux_plane) {
while (!skl_check_main_ccs_coordinates(plane_state, x, y,
offset, aux_plane)) {
if (offset == 0)
@ -1591,6 +1680,8 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1;
int ccs_plane = intel_fb_is_ccs_modifier(fb->modifier) ?
skl_main_to_aux_plane(fb, uv_plane) : 0;
int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation);
int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation);
int x = plane_state->uapi.src.x1 >> 17;
@ -1611,8 +1702,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
offset = intel_plane_compute_aligned_offset(&x, &y,
plane_state, uv_plane);
if (intel_fb_is_ccs_modifier(fb->modifier)) {
int ccs_plane = main_to_ccs_plane(fb, uv_plane);
if (ccs_plane) {
u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
u32 alignment = intel_surf_alignment(fb, uv_plane);
@ -2011,9 +2101,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
case DRM_FORMAT_Y216:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
if (modifier == DRM_FORMAT_MOD_LINEAR ||
modifier == I915_FORMAT_MOD_X_TILED ||
modifier == I915_FORMAT_MOD_Y_TILED)
if (!intel_fb_is_ccs_modifier(modifier))
return true;
fallthrough;
default:
@ -2094,6 +2182,10 @@ static bool gen12_plane_has_mc_ccs(struct drm_i915_private *i915,
if (IS_ADLP_DISPLAY_STEP(i915, STEP_A0, STEP_B0))
return false;
/* Wa_14013215631 */
if (IS_DG2_DISPLAY_STEP(i915, STEP_A0, STEP_C0))
return false;
return plane_id < PLANE_SPRITE4;
}
@ -2106,6 +2198,8 @@ static u8 skl_get_plane_caps(struct drm_i915_private *i915,
caps |= INTEL_PLANE_CAP_TILING_Y;
if (DISPLAY_VER(i915) < 12)
caps |= INTEL_PLANE_CAP_TILING_Yf;
if (HAS_4TILE(i915))
caps |= INTEL_PLANE_CAP_TILING_4;
if (skl_plane_has_rc_ccs(i915, pipe, plane_id)) {
caps |= INTEL_PLANE_CAP_CCS_RC;
@ -2162,9 +2256,15 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
}
plane->max_stride = skl_plane_max_stride;
plane->update_noarm = skl_plane_update_noarm;
plane->update_arm = skl_plane_update_arm;
plane->disable_arm = skl_plane_disable_arm;
if (DISPLAY_VER(dev_priv) >= 11) {
plane->update_noarm = icl_plane_update_noarm;
plane->update_arm = icl_plane_update_arm;
plane->disable_arm = icl_plane_disable_arm;
} else {
plane->update_noarm = skl_plane_update_noarm;
plane->update_arm = skl_plane_update_arm;
plane->disable_arm = skl_plane_disable_arm;
}
plane->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check;
@ -2278,13 +2378,14 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
unsigned int aligned_height;
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
static_assert(PLANE_CTL_TILED_YF == PLANE_CTL_TILED_4);
if (!plane->get_hw_state(plane, &pipe))
return;
drm_WARN_ON(dev, pipe != crtc->pipe);
if (crtc_state->bigjoiner) {
if (crtc_state->bigjoiner_pipes) {
drm_dbg_kms(&dev_priv->drm,
"Unsupported bigjoiner configuration for initial FB\n");
return;
@ -2332,19 +2433,34 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
case PLANE_CTL_TILED_Y:
plane_config->tiling = I915_TILING_Y;
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = DISPLAY_VER(dev_priv) >= 12 ?
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
I915_FORMAT_MOD_Y_TILED_CCS;
if (DISPLAY_VER(dev_priv) >= 12)
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED;
break;
case PLANE_CTL_TILED_YF:
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
else
fb->modifier = I915_FORMAT_MOD_Yf_TILED;
case PLANE_CTL_TILED_YF: /* aka PLANE_CTL_TILED_4 on XE_LPD+ */
if (HAS_4TILE(dev_priv)) {
u32 rc_mask = PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
if ((val & rc_mask) == rc_mask)
fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS;
else if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC;
else
fb->modifier = I915_FORMAT_MOD_4_TILED;
} else {
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
else
fb->modifier = I915_FORMAT_MOD_Yf_TILED;
}
break;
default:
MISSING_CASE(tiling);

View File

@ -1660,6 +1660,8 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
static void vlv_dsi_add_properties(struct intel_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
u32 allowed_scalers;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
@ -1673,8 +1675,8 @@ static void vlv_dsi_add_properties(struct intel_connector *connector)
drm_connector_set_panel_orientation_with_quirk(&connector->base,
intel_dsi_get_panel_orientation(connector),
connector->panel.fixed_mode->hdisplay,
connector->panel.fixed_mode->vdisplay);
fixed_mode->hdisplay,
fixed_mode->vdisplay);
}
#define NS_KHZ_RATIO 1000000
@ -1857,7 +1859,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
struct drm_encoder *encoder;
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_display_mode *current_mode, *fixed_mode;
struct drm_display_mode *current_mode;
enum port port;
enum pipe pipe;
@ -1978,15 +1980,16 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
intel_connector_attach_encoder(intel_connector, intel_encoder);
mutex_lock(&dev->mode_config.mutex);
fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
mutex_unlock(&dev->mode_config.mutex);
if (!fixed_mode) {
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
drm_dbg_kms(&dev_priv->drm, "no fixed mode\n");
goto err_cleanup_connector;
}
intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
intel_panel_init(intel_connector);
intel_backlight_setup(intel_connector, INVALID_PIPE);
vlv_dsi_add_properties(intel_connector);

View File

@ -26,6 +26,7 @@
*/
#include <linux/kernel.h>
#include <linux/string_helpers.h>
#include "i915_drv.h"
#include "intel_de.h"
@ -393,10 +394,7 @@ static void glk_dsi_program_esc_clock(struct drm_device *dev,
/* Calculate TXESC2 divider */
div2_value = DIV_ROUND_UP(div1_value, txesc1_div);
if (div2_value < 10)
txesc2_div = div2_value;
else
txesc2_div = 10;
txesc2_div = min_t(u32, div2_value, 10);
intel_de_write(dev_priv, MIPIO_TXESC_CLK_DIV1,
(1 << (txesc1_div - 1)) & GLK_TX_ESC_CLK_DIV1_MASK);
@ -581,7 +579,7 @@ static void assert_dsi_pll(struct drm_i915_private *i915, bool state)
I915_STATE_WARN(cur_state != state,
"DSI PLL state assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
str_on_off(state), str_on_off(cur_state));
}
void assert_dsi_pll_enabled(struct drm_i915_private *i915)

View File

@ -64,6 +64,7 @@
*
*/
#include <linux/highmem.h>
#include <linux/log2.h>
#include <linux/nospec.h>

View File

@ -4,8 +4,9 @@
* Copyright © 2008,2010 Intel Corporation
*/
#include <linux/intel-iommu.h>
#include <linux/dma-resv.h>
#include <linux/highmem.h>
#include <linux/intel-iommu.h>
#include <linux/sync_file.h>
#include <linux/uaccess.h>

View File

@ -3,6 +3,8 @@
* Copyright © 2019 Intel Corporation
*/
#include <uapi/drm/i915_drm.h>
#include "intel_memory_region.h"
#include "gem/i915_gem_region.h"
#include "gem/i915_gem_lmem.h"

View File

@ -22,6 +22,7 @@
*
*/
#include <linux/highmem.h>
#include <linux/sched/mm.h>
#include <drm/drm_cache.h>

View File

@ -14,6 +14,7 @@
#include "i915_drv.h"
#include "i915_gem_object.h"
#include "i915_gem_region.h"
#include "i915_gem_tiling.h"
#include "i915_scatterlist.h"
static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)

View File

@ -3,6 +3,8 @@
* Copyright © 2019 Intel Corporation
*/
#include <uapi/drm/i915_drm.h>
#include "intel_memory_region.h"
#include "i915_gem_region.h"
#include "i915_drv.h"

View File

@ -12,8 +12,9 @@
#include "gem/i915_gem_region.h"
#include "i915_drv.h"
#include "i915_gemfs.h"
#include "i915_gem_object.h"
#include "i915_gem_tiling.h"
#include "i915_gemfs.h"
#include "i915_scatterlist.h"
#include "i915_trace.h"

View File

@ -15,6 +15,7 @@
#include "i915_drv.h"
#include "i915_gem_stolen.h"
#include "i915_reg.h"
#include "i915_utils.h"
#include "i915_vgpu.h"
#include "intel_mchbar_regs.h"
@ -401,7 +402,7 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem)
return 0;
}
if (intel_vtd_active(i915) && GRAPHICS_VER(i915) < 8) {
if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) {
drm_notice(&i915->drm,
"%s, disabling use of stolen memory\n",
"DMAR active");

View File

@ -219,6 +219,14 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj,
return ret;
}
bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
return to_gt(i915)->ggtt->bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 &&
i915_gem_object_is_tiled(obj);
}
int
i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
unsigned int tiling, unsigned int stride)

View File

@ -8,8 +8,10 @@
#include <linux/types.h>
struct drm_i915_gem_object;
struct drm_i915_private;
bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj);
u32 i915_gem_fence_size(struct drm_i915_private *i915, u32 size,
unsigned int tiling, unsigned int stride);
u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size,

View File

@ -9,6 +9,7 @@
#include "i915_drv.h"
#include "i915_gemfs.h"
#include "i915_utils.h"
int i915_gemfs_init(struct drm_i915_private *i915)
{
@ -32,7 +33,7 @@ int i915_gemfs_init(struct drm_i915_private *i915)
*/
opts = NULL;
if (intel_vtd_active(i915)) {
if (i915_vtd_active(i915)) {
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
opts = huge_opt;
drm_info(&i915->drm,

View File

@ -5,6 +5,8 @@
*/
#include <linux/prime_numbers.h>
#include <linux/string_helpers.h>
#include <linux/swap.h>
#include "i915_selftest.h"
@ -804,7 +806,7 @@ static int igt_mock_ppgtt_huge_fill(void *arg)
if (vma->resource->page_sizes_gtt != expected_gtt) {
pr_err("gtt=%u, expected=%u, size=%zd, single=%s\n",
vma->resource->page_sizes_gtt, expected_gtt,
obj->base.size, yesno(!!single));
obj->base.size, str_yes_no(!!single));
err = -EINVAL;
break;
}
@ -960,7 +962,7 @@ static int igt_mock_ppgtt_64K(void *arg)
if (vma->resource->page_sizes_gtt != expected_gtt) {
pr_err("gtt=%u, expected=%u, i=%d, single=%s\n",
vma->resource->page_sizes_gtt,
expected_gtt, i, yesno(!!single));
expected_gtt, i, str_yes_no(!!single));
err = -EINVAL;
goto out_vma_unpin;
}
@ -1706,14 +1708,14 @@ static int igt_shrink_thp(void *arg)
I915_SHRINK_WRITEBACK);
if (should_swap == i915_gem_object_has_pages(obj)) {
pr_err("unexpected pages mismatch, should_swap=%s\n",
yesno(should_swap));
str_yes_no(should_swap));
err = -EINVAL;
goto out_put;
}
if (should_swap == (obj->mm.page_sizes.sg || obj->mm.page_sizes.phys)) {
pr_err("unexpected residual page-size bits, should_swap=%s\n",
yesno(should_swap));
str_yes_no(should_swap));
err = -EINVAL;
goto out_put;
}

View File

@ -5,6 +5,7 @@
*/
#include <linux/prime_numbers.h>
#include <linux/string_helpers.h>
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_pm.h"
@ -700,7 +701,7 @@ static int igt_ctx_exec(void *arg)
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj),
engine->name,
yesno(i915_gem_context_has_full_ppgtt(ctx)),
str_yes_no(i915_gem_context_has_full_ppgtt(ctx)),
err);
intel_context_put(ce);
kernel_context_close(ctx);
@ -834,7 +835,7 @@ static int igt_shared_ctx_exec(void *arg)
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj),
engine->name,
yesno(i915_gem_context_has_full_ppgtt(ctx)),
str_yes_no(i915_gem_context_has_full_ppgtt(ctx)),
err);
intel_context_put(ce);
kernel_context_close(ctx);
@ -1415,7 +1416,7 @@ static int igt_ctx_readonly(void *arg)
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj),
ce->engine->name,
yesno(i915_gem_context_has_full_ppgtt(ctx)),
str_yes_no(i915_gem_context_has_full_ppgtt(ctx)),
err);
i915_gem_context_unlock_engines(ctx);
goto out_file;

View File

@ -4,6 +4,7 @@
* Copyright © 2016 Intel Corporation
*/
#include <linux/highmem.h>
#include <linux/prime_numbers.h>
#include "gem/i915_gem_internal.h"

View File

@ -4,6 +4,7 @@
*/
#include <linux/kthread.h>
#include <linux/string_helpers.h>
#include <trace/events/dma_fence.h>
#include <uapi/linux/sched/types.h>
@ -512,7 +513,7 @@ void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
if (!b)
return;
drm_printf(p, "IRQ: %s\n", enableddisabled(b->irq_armed));
drm_printf(p, "IRQ: %s\n", str_enabled_disabled(b->irq_armed));
if (!list_empty(&b->signalers))
print_signals(b, p);
}

View File

@ -3,6 +3,8 @@
* Copyright © 2016 Intel Corporation
*/
#include <linux/string_helpers.h>
#include <drm/drm_print.h>
#include "gem/i915_gem_context.h"
@ -1706,9 +1708,8 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine,
u8 read, write;
drm_printf(m, "\tExeclist tasklet queued? %s (%s), preempt? %s, timeslice? %s\n",
yesno(test_bit(TASKLET_STATE_SCHED,
&engine->sched_engine->tasklet.state)),
enableddisabled(!atomic_read(&engine->sched_engine->tasklet.count)),
str_yes_no(test_bit(TASKLET_STATE_SCHED, &engine->sched_engine->tasklet.state)),
str_enabled_disabled(!atomic_read(&engine->sched_engine->tasklet.count)),
repr_timer(&engine->execlists.preempt),
repr_timer(&engine->execlists.timer));
@ -1969,7 +1970,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
drm_printf(m, "\tAwake? %d\n", atomic_read(&engine->wakeref.count));
drm_printf(m, "\tBarriers?: %s\n",
yesno(!llist_empty(&engine->barrier_tasks)));
str_yes_no(!llist_empty(&engine->barrier_tasks)));
drm_printf(m, "\tLatency: %luus\n",
ewma__engine_latency_read(&engine->latency));
if (intel_engine_supports_stats(engine))
@ -2011,7 +2012,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
drm_printf(m, "HWSP:\n");
hexdump(m, engine->status_page.addr, PAGE_SIZE);
drm_printf(m, "Idle? %s\n", yesno(intel_engine_is_idle(engine)));
drm_printf(m, "Idle? %s\n", str_yes_no(intel_engine_is_idle(engine)));
intel_engine_print_breadcrumbs(engine, m);
}

View File

@ -107,6 +107,7 @@
*
*/
#include <linux/interrupt.h>
#include <linux/string_helpers.h>
#include "i915_drv.h"
#include "i915_trace.h"
@ -1335,11 +1336,11 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
} else if (timeslice_expired(engine, last)) {
ENGINE_TRACE(engine,
"expired:%s last=%llx:%lld, prio=%d, hint=%d, yield?=%s\n",
yesno(timer_expired(&execlists->timer)),
str_yes_no(timer_expired(&execlists->timer)),
last->fence.context, last->fence.seqno,
rq_prio(last),
sched_engine->queue_priority_hint,
yesno(timeslice_yield(execlists, last)));
str_yes_no(timeslice_yield(execlists, last)));
/*
* Consume this timeslice; ensure we start a new one.
@ -1427,7 +1428,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
__i915_request_is_complete(rq) ? "!" :
__i915_request_has_started(rq) ? "*" :
"",
yesno(engine != ve->siblings[0]));
str_yes_no(engine != ve->siblings[0]));
WRITE_ONCE(ve->request, NULL);
WRITE_ONCE(ve->base.sched_engine->queue_priority_hint, INT_MIN);

View File

@ -18,6 +18,7 @@
#include "intel_gt_regs.h"
#include "i915_drv.h"
#include "i915_scatterlist.h"
#include "i915_utils.h"
#include "i915_vgpu.h"
#include "intel_gtt.h"
@ -104,7 +105,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915)
* Query intel_iommu to see if we need the workaround. Presumably that
* was loaded first.
*/
if (!intel_vtd_active(i915))
if (!i915_vtd_active(i915))
return false;
if (GRAPHICS_VER(i915) == 5 && IS_MOBILE(i915))
@ -1256,7 +1257,7 @@ int i915_ggtt_probe_hw(struct drm_i915_private *i915)
if (ret)
return ret;
if (intel_vtd_active(i915))
if (i915_vtd_active(i915))
drm_info(&i915->drm, "VT-d active for gfx access\n");
return 0;

View File

@ -3,6 +3,8 @@
* Copyright © 2008-2015 Intel Corporation
*/
#include <linux/highmem.h>
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_scatterlist.h"

View File

@ -3,6 +3,7 @@
* Copyright © 2019 Intel Corporation
*/
#include <linux/string_helpers.h>
#include <linux/suspend.h>
#include "i915_drv.h"
@ -157,7 +158,7 @@ static void gt_sanitize(struct intel_gt *gt, bool force)
enum intel_engine_id id;
intel_wakeref_t wakeref;
GT_TRACE(gt, "force:%s", yesno(force));
GT_TRACE(gt, "force:%s", str_yes_no(force));
/* Use a raw wakeref to avoid calling intel_display_power_get early */
wakeref = intel_runtime_pm_get(gt->uncore->rpm);

View File

@ -5,6 +5,7 @@
*/
#include <linux/seq_file.h>
#include <linux/string_helpers.h>
#include "i915_drv.h"
#include "i915_reg.h"
@ -105,14 +106,14 @@ static int vlv_drpc(struct seq_file *m)
rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL);
seq_printf(m, "RC6 Enabled: %s\n",
yesno(rcctl1 & (GEN7_RC_CTL_TO_MODE |
str_yes_no(rcctl1 & (GEN7_RC_CTL_TO_MODE |
GEN6_RC_CTL_EI_MODE(1))));
seq_printf(m, "Render Power Well: %s\n",
(pw_status & VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up" : "Down");
seq_printf(m, "Media Power Well: %s\n",
(pw_status & VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down");
print_rc6_res(m, "Render RC6 residency since boot:", VLV_GT_RENDER_RC6);
print_rc6_res(m, "Render RC6 residency since boot:", GEN6_GT_GFX_RC6);
print_rc6_res(m, "Media RC6 residency since boot:", VLV_GT_MEDIA_RC6);
return fw_domains_show(m, NULL);
@ -140,19 +141,19 @@ static int gen6_drpc(struct seq_file *m)
snb_pcode_read(i915, GEN6_PCODE_READ_RC6VIDS, &rc6vids, NULL);
seq_printf(m, "RC1e Enabled: %s\n",
yesno(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE));
str_yes_no(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE));
seq_printf(m, "RC6 Enabled: %s\n",
yesno(rcctl1 & GEN6_RC_CTL_RC6_ENABLE));
str_yes_no(rcctl1 & GEN6_RC_CTL_RC6_ENABLE));
if (GRAPHICS_VER(i915) >= 9) {
seq_printf(m, "Render Well Gating Enabled: %s\n",
yesno(gen9_powergate_enable & GEN9_RENDER_PG_ENABLE));
str_yes_no(gen9_powergate_enable & GEN9_RENDER_PG_ENABLE));
seq_printf(m, "Media Well Gating Enabled: %s\n",
yesno(gen9_powergate_enable & GEN9_MEDIA_PG_ENABLE));
str_yes_no(gen9_powergate_enable & GEN9_MEDIA_PG_ENABLE));
}
seq_printf(m, "Deep RC6 Enabled: %s\n",
yesno(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE));
str_yes_no(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE));
seq_printf(m, "Deepest RC6 Enabled: %s\n",
yesno(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE));
str_yes_no(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE));
seq_puts(m, "Current RC state: ");
switch (gt_core_status & GEN6_RCn_MASK) {
case GEN6_RC0:
@ -176,7 +177,7 @@ static int gen6_drpc(struct seq_file *m)
}
seq_printf(m, "Core Power Down: %s\n",
yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK));
str_yes_no(gt_core_status & GEN6_CORE_CPD_STATE_MASK));
if (GRAPHICS_VER(i915) >= 9) {
seq_printf(m, "Render Power Well: %s\n",
(gen9_powergate_status &
@ -216,16 +217,17 @@ static int ilk_drpc(struct seq_file *m)
rstdbyctl = intel_uncore_read(uncore, RSTDBYCTL);
crstandvid = intel_uncore_read16(uncore, CRSTANDVID);
seq_printf(m, "HD boost: %s\n", yesno(rgvmodectl & MEMMODE_BOOST_EN));
seq_printf(m, "HD boost: %s\n",
str_yes_no(rgvmodectl & MEMMODE_BOOST_EN));
seq_printf(m, "Boost freq: %d\n",
(rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
MEMMODE_BOOST_FREQ_SHIFT);
seq_printf(m, "HW control enabled: %s\n",
yesno(rgvmodectl & MEMMODE_HWIDLE_EN));
str_yes_no(rgvmodectl & MEMMODE_HWIDLE_EN));
seq_printf(m, "SW control enabled: %s\n",
yesno(rgvmodectl & MEMMODE_SWMODE_EN));
str_yes_no(rgvmodectl & MEMMODE_SWMODE_EN));
seq_printf(m, "Gated voltage change: %s\n",
yesno(rgvmodectl & MEMMODE_RCLK_GATE));
str_yes_no(rgvmodectl & MEMMODE_RCLK_GATE));
seq_printf(m, "Starting frequency: P%d\n",
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
seq_printf(m, "Max P-state: P%d\n",
@ -234,7 +236,7 @@ static int ilk_drpc(struct seq_file *m)
seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f));
seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
seq_printf(m, "Render standby enabled: %s\n",
yesno(!(rstdbyctl & RCX_SW_EXIT)));
str_yes_no(!(rstdbyctl & RCX_SW_EXIT)));
seq_puts(m, "Current RS state: ");
switch (rstdbyctl & RSX_STATUS_MASK) {
case RSX_STATUS_ON:
@ -307,12 +309,11 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p)
rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL);
drm_printf(p, "Video Turbo Mode: %s\n",
yesno(rpmodectl & GEN6_RP_MEDIA_TURBO));
str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO));
drm_printf(p, "HW control enabled: %s\n",
yesno(rpmodectl & GEN6_RP_ENABLE));
str_yes_no(rpmodectl & GEN6_RP_ENABLE));
drm_printf(p, "SW control enabled: %s\n",
yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) ==
GEN6_RP_MEDIA_SW_MODE));
str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
vlv_punit_get(i915);
freq_sts = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
@ -417,12 +418,11 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p)
pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
drm_printf(p, "Video Turbo Mode: %s\n",
yesno(rpmodectl & GEN6_RP_MEDIA_TURBO));
str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO));
drm_printf(p, "HW control enabled: %s\n",
yesno(rpmodectl & GEN6_RP_ENABLE));
str_yes_no(rpmodectl & GEN6_RP_ENABLE));
drm_printf(p, "SW control enabled: %s\n",
yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) ==
GEN6_RP_MEDIA_SW_MODE));
str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n",
pm_ier, pm_imr, pm_mask);
@ -542,7 +542,7 @@ static int llc_show(struct seq_file *m, void *data)
intel_wakeref_t wakeref;
int gpu_freq, ia_freq;
seq_printf(m, "LLC: %s\n", yesno(HAS_LLC(i915)));
seq_printf(m, "LLC: %s\n", str_yes_no(HAS_LLC(i915)));
seq_printf(m, "%s: %uMB\n", edram ? "eDRAM" : "eLLC",
i915->edram_size_mb);
@ -604,10 +604,12 @@ static int rps_boost_show(struct seq_file *m, void *data)
struct drm_i915_private *i915 = gt->i915;
struct intel_rps *rps = &gt->rps;
seq_printf(m, "RPS enabled? %s\n", yesno(intel_rps_is_enabled(rps)));
seq_printf(m, "RPS active? %s\n", yesno(intel_rps_is_active(rps)));
seq_printf(m, "RPS enabled? %s\n",
str_yes_no(intel_rps_is_enabled(rps)));
seq_printf(m, "RPS active? %s\n",
str_yes_no(intel_rps_is_active(rps)));
seq_printf(m, "GPU busy? %s, %llums\n",
yesno(gt->awake),
str_yes_no(gt->awake),
ktime_to_ms(intel_gt_get_awake_time(gt)));
seq_printf(m, "Boosts outstanding? %d\n",
atomic_read(&rps->num_waiters));

View File

@ -1440,7 +1440,6 @@
#define VLV_MEDIA_RC6_COUNT_EN (1 << 1)
#define VLV_RENDER_RC6_COUNT_EN (1 << 0)
#define GEN6_GT_GFX_RC6 _MMIO(0x138108)
#define VLV_GT_RENDER_RC6 _MMIO(0x138108)
#define VLV_GT_MEDIA_RC6 _MMIO(0x13810c)
#define GEN6_GT_GFX_RC6p _MMIO(0x13810c)

View File

@ -13,10 +13,22 @@
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_lmem.h"
#include "i915_trace.h"
#include "i915_utils.h"
#include "intel_gt.h"
#include "intel_gt_regs.h"
#include "intel_gtt.h"
static bool intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *i915)
{
return IS_BROXTON(i915) && i915_vtd_active(i915);
}
bool intel_vm_no_concurrent_access_wa(struct drm_i915_private *i915)
{
return IS_CHERRYVIEW(i915) || intel_ggtt_update_needs_vtd_wa(i915);
}
struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz)
{
struct drm_i915_gem_object *obj;

Some files were not shown because too many files have changed in this diff Show More