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
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) :doc: Display Refresh Rate Switching (DRRS)
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c .. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_enable :internal:
.. 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
DPIO DPIO
---- ----

View File

@@ -18,6 +18,7 @@
#include <linux/bcma/bcma_regs.h> #include <linux/bcma/bcma_regs.h>
#include <linux/platform_data/x86/apple.h> #include <linux/platform_data/x86/apple.h>
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
#include <drm/i915_pciids.h>
#include <asm/pci-direct.h> #include <asm/pci-direct.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/io_apic.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); 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 * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
* @dpcd: DisplayPort configuration data
* @caps: buffer to return the capability info in * @caps: buffer to return the capability info in
* *
* Read capabilities common to all LTTPRs. * 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. * Returns 0 on success or a negative error code on failure.
*/ */
int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, 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]) u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
{ {
int ret; return drm_dp_read_lttpr_regs(aux, dpcd,
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
ret = drm_dp_dpcd_read(aux, caps, DP_LTTPR_COMMON_CAP_SIZE);
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;
} }
EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps);
/** /**
* drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
* @dpcd: DisplayPort configuration data
* @dp_phy: LTTPR PHY to read the capabilities for * @dp_phy: LTTPR PHY to read the capabilities for
* @caps: buffer to return the capability info in * @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. * Returns 0 on success or a negative error code on failure.
*/ */
int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, 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, enum drm_dp_phy dp_phy,
u8 caps[DP_LTTPR_PHY_CAP_SIZE]) u8 caps[DP_LTTPR_PHY_CAP_SIZE])
{ {
int ret; return drm_dp_read_lttpr_regs(aux, dpcd,
DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy),
ret = drm_dp_dpcd_read(aux, caps, DP_LTTPR_PHY_CAP_SIZE);
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;
} }
EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps); EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps);

View File

@@ -213,6 +213,7 @@ i915-y += \
display/intel_cursor.o \ display/intel_cursor.o \
display/intel_display.o \ display/intel_display.o \
display/intel_display_power.o \ display/intel_display_power.o \
display/intel_display_power_well.o \
display/intel_dmc.o \ display/intel_dmc.o \
display/intel_dpio_phy.o \ display/intel_dpio_phy.o \
display/intel_dpll.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). * 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 "g4x_dp.h"
#include "intel_audio.h" #include "intel_audio.h"
#include "intel_backlight.h" #include "intel_backlight.h"
@@ -22,58 +24,37 @@
#include "intel_pps.h" #include "intel_pps.h"
#include "vlv_sideband.h" #include "vlv_sideband.h"
struct dp_link_dpll { static const struct dpll g4x_dpll[] = {
int clock; { .dot = 162000, .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8, },
struct dpll dpll; { .dot = 270000, .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2, },
}; };
static const struct dp_link_dpll g4x_dpll[] = { static const struct dpll pch_dpll[] = {
{ 162000, { .dot = 162000, .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9, },
{ .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } }, { .dot = 270000, .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8, },
{ 270000,
{ .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } }
}; };
static const struct dp_link_dpll pch_dpll[] = { static const struct dpll vlv_dpll[] = {
{ 162000, { .dot = 162000, .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81, },
{ .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } }, { .dot = 270000, .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27, },
{ 270000,
{ .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } }
}; };
static const struct dp_link_dpll vlv_dpll[] = { static const struct dpll chv_dpll[] = {
{ 162000, /* m2 is .22 binary fixed point */
{ .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } }, { .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{ 270000, { .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
{ .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 } },
}; };
const struct dpll *vlv_get_dpll(struct drm_i915_private *i915) 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, void g4x_dp_set_clock(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config) struct intel_crtc_state *pipe_config)
{ {
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 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; int i, count = 0;
if (IS_G4X(dev_priv)) { if (IS_G4X(dev_priv)) {
@@ -92,8 +73,8 @@ void g4x_dp_set_clock(struct intel_encoder *encoder,
if (divisor && count) { if (divisor && count) {
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (pipe_config->port_clock == divisor[i].clock) { if (pipe_config->port_clock == divisor[i].dot) {
pipe_config->dpll = divisor[i].dpll; pipe_config->dpll = divisor[i];
pipe_config->clock_set = true; pipe_config->clock_set = true;
break; break;
} }
@@ -192,7 +173,7 @@ static void assert_dp_port(struct intel_dp *intel_dp, bool state)
I915_STATE_WARN(cur_state != state, I915_STATE_WARN(cur_state != state,
"[ENCODER:%d:%s] state assertion failure (expected %s, current %s)\n", "[ENCODER:%d:%s] state assertion failure (expected %s, current %s)\n",
dig_port->base.base.base.id, dig_port->base.base.name, 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) #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, I915_STATE_WARN(cur_state != state,
"eDP PLL state assertion failure (expected %s, current %s)\n", "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_enabled(d) assert_edp_pll((d), true)
#define assert_edp_pll_disabled(d) assert_edp_pll((d), false) #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; 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. * 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 drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 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); u32 dp_reg = intel_de_read(dev_priv, intel_dp->output_reg);
enum pipe pipe = crtc->pipe;
intel_wakeref_t wakeref; intel_wakeref_t wakeref;
if (drm_WARN_ON(&dev_priv->drm, dp_reg & DP_PORT_EN)) 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_start_link_train(intel_dp, pipe_config);
intel_dp_stop_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config);
if (pipe_config->has_audio) { intel_audio_codec_enable(encoder, pipe_config, conn_state);
drm_dbg(&dev_priv->drm, "Enabling DP audio on pipe %c\n",
pipe_name(pipe));
intel_audio_codec_enable(encoder, pipe_config, conn_state);
}
} }
static void g4x_enable_dp(struct intel_atomic_state *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); &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, static void g4x_enable_hdmi(struct intel_atomic_state *state,
struct intel_encoder *encoder, struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config, 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_write(dev_priv, intel_hdmi->hdmi_reg, temp);
intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg);
if (pipe_config->has_audio) drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio &&
intel_enable_hdmi_audio(encoder, pipe_config, conn_state); !pipe_config->has_hdmi_sink);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
} }
static void ibx_enable_hdmi(struct intel_atomic_state *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); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg);
} }
if (pipe_config->has_audio) drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio &&
intel_enable_hdmi_audio(encoder, pipe_config, conn_state); !pipe_config->has_hdmi_sink);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
} }
static void cpt_enable_hdmi(struct intel_atomic_state *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); intel_de_read(dev_priv, TRANS_CHICKEN1(pipe)) & ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
} }
if (pipe_config->has_audio) drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio &&
intel_enable_hdmi_audio(encoder, pipe_config, conn_state); !pipe_config->has_hdmi_sink);
intel_audio_codec_enable(encoder, pipe_config, conn_state);
} }
static void vlv_enable_hdmi(struct intel_atomic_state *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 intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_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); 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 intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_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, 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; 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), intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
plane_state->view.color_plane[0].mapping_stride); 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), intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1)); 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, 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 x = plane_state->view.color_plane[0].x;
int y = plane_state->view.color_plane[0].y; int y = plane_state->view.color_plane[0].y;
u32 dspcntr, dspaddr_offset, linear_offset; u32 dspcntr, dspaddr_offset, linear_offset;
unsigned long irqflags;
dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); 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 else
dspaddr_offset = linear_offset; dspaddr_offset = linear_offset;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) { if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
int crtc_x = plane_state->uapi.dst.x1; int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1; 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. * the control register just before the surface register.
*/ */
intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
if (DISPLAY_VER(dev_priv) >= 4) if (DISPLAY_VER(dev_priv) >= 4)
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset); intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
else else
intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset); 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, 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
u32 dspcntr; u32 dspcntr;
/* /*
@@ -540,15 +530,12 @@ static void i9xx_plane_disable_arm(struct intel_plane *plane,
*/ */
dspcntr = i9xx_plane_ctl_crtc(crtc_state); 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); intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
if (DISPLAY_VER(dev_priv) >= 4) if (DISPLAY_VER(dev_priv) >= 4)
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0); intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
else else
intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0); intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void 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 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
u32 dspaddr_offset = plane_state->view.color_plane[0].offset; u32 dspaddr_offset = plane_state->view.color_plane[0].offset;
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
if (async_flip) if (async_flip)
dspcntr |= DISP_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, DSPCNTR(i9xx_plane), dspcntr);
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset); intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
u32 dspaddr_offset = plane_state->view.color_plane[0].offset; u32 dspaddr_offset = plane_state->view.color_plane[0].offset;
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; 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_de_write_fw(dev_priv, DSPADDR_VLV(i9xx_plane),
intel_plane_ggtt_offset(plane_state) + dspaddr_offset); intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void 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) 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; u32 allowed_scalers;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | 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; connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
drm_connector_set_panel_orientation_with_quirk(&connector->base, drm_connector_set_panel_orientation_with_quirk(&connector->base,
intel_dsi_get_panel_orientation(connector), intel_dsi_get_panel_orientation(connector),
connector->panel.fixed_mode->hdisplay, fixed_mode->hdisplay,
connector->panel.fixed_mode->vdisplay); fixed_mode->vdisplay);
} }
void icl_dsi_init(struct drm_i915_private *dev_priv) 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_encoder *encoder;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_display_mode *fixed_mode;
enum port port; enum port port;
if (!intel_bios_is_dsi_present(dev_priv, &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); intel_connector_attach_encoder(intel_connector, encoder);
mutex_lock(&dev->mode_config.mutex); 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); 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"); drm_err(&dev_priv->drm, "DSI fixed mode info missing\n");
goto err; goto err;
} }
intel_panel_init(&intel_connector->panel, fixed_mode, NULL); intel_panel_init(intel_connector);
intel_backlight_setup(intel_connector, INVALID_PIPE); intel_backlight_setup(intel_connector, INVALID_PIPE);
if (dev_priv->vbt.dsi.config->dual_link) 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, 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; const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int cpp;
unsigned int pixel_rate;
if (!plane_state->uapi.visible) if (!plane_state->uapi.visible)
return 0; 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 * We calculate extra ddb based on ratio plane rate/total data rate
* NV12 cpp == 4, P010 cpp == 8 * 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.
* FIXME what is the logic behind this?
*/ */
if (fb->format->is_yuv && fb->format->num_planes > 1) if (use_min_ddb(crtc_state, plane))
cpp *= 4; 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, 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->nv12_planes &= ~BIT(plane->id);
crtc_state->c8_planes &= ~BIT(plane->id); crtc_state->c8_planes &= ~BIT(plane->id);
crtc_state->data_rate[plane->id] = 0; 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; crtc_state->min_cdclk[plane->id] = 0;
plane_state->uapi.visible = false; 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) if (new_plane_state->uapi.visible || old_plane_state->uapi.visible)
new_crtc_state->update_planes |= BIT(plane->id); new_crtc_state->update_planes |= BIT(plane->id);
new_crtc_state->data_rate[plane->id] = if (new_plane_state->uapi.visible &&
intel_plane_data_rate(new_crtc_state, new_plane_state); 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, return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
old_plane_state, new_plane_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 * static struct intel_plane *
skl_next_plane_to_commit(struct intel_atomic_state *state, skl_next_plane_to_commit(struct intel_atomic_state *state,
struct intel_crtc *crtc, struct intel_crtc *crtc,
struct skl_ddb_entry entries_y[I915_MAX_PLANES], struct skl_ddb_entry ddb[I915_MAX_PLANES],
struct skl_ddb_entry entries_uv[I915_MAX_PLANES], struct skl_ddb_entry ddb_y[I915_MAX_PLANES],
unsigned int *update_mask) unsigned int *update_mask)
{ {
struct intel_crtc_state *crtc_state = 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))) !(*update_mask & BIT(plane_id)))
continue; continue;
if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id], if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb[plane_id],
entries_y, ddb, I915_MAX_PLANES, plane_id) ||
I915_MAX_PLANES, plane_id) || skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id], ddb_y, I915_MAX_PLANES, plane_id))
entries_uv,
I915_MAX_PLANES, plane_id))
continue; continue;
*update_mask &= ~BIT(plane_id); *update_mask &= ~BIT(plane_id);
entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id]; ddb[plane_id] = crtc_state->wm.skl.plane_ddb[plane_id];
entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id]; ddb_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
return plane; 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); intel_atomic_get_old_crtc_state(state, crtc);
struct intel_crtc_state *new_crtc_state = struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); intel_atomic_get_new_crtc_state(state, crtc);
struct skl_ddb_entry entries_y[I915_MAX_PLANES]; struct skl_ddb_entry ddb[I915_MAX_PLANES];
struct skl_ddb_entry entries_uv[I915_MAX_PLANES]; struct skl_ddb_entry ddb_y[I915_MAX_PLANES];
u32 update_mask = new_crtc_state->update_planes; u32 update_mask = new_crtc_state->update_planes;
struct intel_plane *plane; 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)); 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, while ((plane = skl_next_plane_to_commit(state, crtc, ddb, ddb_y, &update_mask))) {
entries_y, entries_uv,
&update_mask))) {
struct intel_plane_state *new_plane_state = struct intel_plane_state *new_plane_state =
intel_atomic_get_new_plane_state(state, plane); 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_framebuffer *fb = plane_state->hw.fb;
struct drm_rect *src = &plane_state->uapi.src; struct drm_rect *src = &plane_state->uapi.src;
struct drm_rect *dst = &plane_state->uapi.dst; struct drm_rect *dst = &plane_state->uapi.dst;
const struct drm_rect *clip = &crtc_state->pipe_src;
unsigned int rotation = plane_state->hw.rotation; unsigned int rotation = plane_state->hw.rotation;
struct drm_rect clip = {};
int hscale, vscale; int hscale, vscale;
if (!fb) { if (!fb) {
@@ -823,31 +879,25 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
return -ERANGE; 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 * FIXME: This might need further adjustment for seamless scaling
* with phase information, for the 2p2 and 2p1 scenarios. * 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); drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
if (!can_position && plane_state->uapi.visible && 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_dbg_kms(&i915->drm, "Plane must cover entire CRTC\n");
drm_rect_debug_print("dst: ", dst, false); drm_rect_debug_print("dst: ", dst, false);
drm_rect_debug_print("clip: ", &clip, false); drm_rect_debug_print("clip: ", clip, false);
return -EINVAL; return -EINVAL;
} }
/* final plane coordinates will be relative to the plane's pipe */
drm_rect_translate(dst, -clip->x1, -clip->y1);
return 0; 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); const struct intel_plane_state *plane_state);
unsigned int intel_plane_data_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);
void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
const struct intel_plane_state *from_plane_state, const struct intel_plane_state *from_plane_state,
struct intel_crtc *crtc); 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); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
u32 eldv, tmp; u32 eldv, tmp;
drm_dbg_kms(&dev_priv->drm, "Disable audio codec\n");
tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID); tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID);
if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL)
eldv = G4X_ELDV_DEVCL_DEVBLC; eldv = G4X_ELDV_DEVCL_DEVBLC;
@@ -362,9 +360,6 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
u32 tmp; u32 tmp;
int len, i; 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); tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID);
if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL)
eldv = G4X_ELDV_DEVCL_DEVBLC; 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); intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp);
len = min(drm_eld_size(eld) / 4, len); len = min(drm_eld_size(eld) / 4, len);
drm_dbg(&dev_priv->drm, "ELD size %d\n", len);
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
intel_de_write(dev_priv, G4X_HDMIW_HDMIEDID, intel_de_write(dev_priv, G4X_HDMIW_HDMIEDID,
*((const u32 *)eld + i)); *((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; enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
u32 tmp; 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); mutex_lock(&dev_priv->audio.mutex);
/* Disable timestamps */ /* Disable timestamps */
@@ -647,10 +638,6 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
u32 tmp; u32 tmp;
int len, i; 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); mutex_lock(&dev_priv->audio.mutex);
/* Enable Audio WA for 4k DSC usecases */ /* Enable Audio WA for 4k DSC usecases */
@@ -703,11 +690,6 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder,
u32 tmp, eldv; u32 tmp, eldv;
i915_reg_t aud_config, aud_cntrl_st2; 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)) if (drm_WARN_ON(&dev_priv->drm, port == PORT_A))
return; return;
@@ -754,11 +736,6 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder,
int len, i; int len, i;
i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; 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)) if (drm_WARN_ON(&dev_priv->drm, port == PORT_A))
return; return;
@@ -844,18 +821,20 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
enum port port = encoder->port; enum port port = encoder->port;
enum pipe pipe = crtc->pipe; 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() */ /* FIXME precompute the ELD in .compute_config() */
if (!connector->eld[0]) if (!connector->eld[0])
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
"Bogus ELD on [CONNECTOR:%d:%s]\n", "Bogus ELD on [CONNECTOR:%d:%s]\n",
connector->base.id, connector->name); 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; connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
if (dev_priv->audio.funcs) 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 drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct i915_audio_component *acomp = dev_priv->audio.component; struct i915_audio_component *acomp = dev_priv->audio.component;
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); 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 port port = encoder->port;
enum pipe pipe = crtc->pipe; 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) if (dev_priv->audio.funcs)
dev_priv->audio.funcs->audio_codec_disable(encoder, dev_priv->audio.funcs->audio_codec_disable(encoder,
old_crtc_state, old_crtc_state,

View File

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

View File

@@ -88,7 +88,7 @@ static u32 get_blocksize(const void *block_data)
} }
static const void * 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 struct bdb_header *bdb = _bdb;
const u8 *base = _bdb; const u8 *base = _bdb;
@@ -118,6 +118,250 @@ find_section(const void *_bdb, enum bdb_block_id section_id)
return NULL; 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 static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
const struct lvds_dvo_timing *dvo_timing) 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 * static const struct lvds_dvo_timing *
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *data,
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, const struct bdb_lvds_lfp_data_ptrs *ptrs,
int index) int index)
{ {
/* return (const void *)data + ptrs->ptr[index].dvo_timing.offset;
* 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);
} }
/* get lvds_fp_timing entry
* this function may return NULL if the corresponding entry is invalid
*/
static const struct lvds_fp_timing * static const struct lvds_fp_timing *
get_lvds_fp_timing(const struct bdb_header *bdb, get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data,
const struct bdb_lvds_lfp_data *data,
const struct bdb_lvds_lfp_data_ptrs *ptrs, const struct bdb_lvds_lfp_data_ptrs *ptrs,
int index) int index)
{ {
size_t data_ofs = (const u8 *)data - (const u8 *)bdb; return (const void *)data + ptrs->ptr[index].fp_timing.offset;
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);
} }
/* Parse general panel options */ /* Parse general panel options */
static void static void
parse_panel_options(struct drm_i915_private *i915, parse_panel_options(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_lvds_options *lvds_options; const struct bdb_lvds_options *lvds_options;
int panel_type; int panel_type;
int drrs_mode; int drrs_mode;
int ret; int ret;
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
if (!lvds_options) if (!lvds_options)
return; return;
@@ -257,16 +472,16 @@ parse_panel_options(struct drm_i915_private *i915,
*/ */
switch (drrs_mode) { switch (drrs_mode) {
case 0: 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"); drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n");
break; break;
case 2: case 2:
i915->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; i915->vbt.drrs_type = DRRS_TYPE_SEAMLESS;
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"DRRS supported mode is seamless\n"); "DRRS supported mode is seamless\n");
break; break;
default: default:
i915->vbt.drrs_type = DRRS_NOT_SUPPORTED; i915->vbt.drrs_type = DRRS_TYPE_NONE;
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"DRRS not supported (VBT input)\n"); "DRRS not supported (VBT input)\n");
break; break;
@@ -275,8 +490,7 @@ parse_panel_options(struct drm_i915_private *i915,
/* Try to find integrated panel timing data */ /* Try to find integrated panel timing data */
static void static void
parse_lfp_panel_dtd(struct drm_i915_private *i915, parse_lfp_panel_dtd(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_lvds_lfp_data *lvds_lfp_data; const struct bdb_lvds_lfp_data *lvds_lfp_data;
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; 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; struct drm_display_mode *panel_fixed_mode;
int panel_type = i915->vbt.panel_type; 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) if (!lvds_lfp_data)
return; 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) if (!lvds_lfp_data_ptrs)
return; return;
@@ -306,34 +520,32 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915,
i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Found panel mode in BIOS VBT legacy lfp table:\n"); "Found panel mode in BIOS VBT legacy lfp table: " DRM_MODE_FMT "\n",
drm_mode_debug_printmodeline(panel_fixed_mode); 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, lvds_lfp_data_ptrs,
panel_type); panel_type);
if (fp_timing) {
/* check the resolution, just to be sure */ /* check the resolution, just to be sure */
if (fp_timing->x_res == panel_fixed_mode->hdisplay && if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
fp_timing->y_res == panel_fixed_mode->vdisplay) { fp_timing->y_res == panel_fixed_mode->vdisplay) {
i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val; i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"VBT initial LVDS value %x\n", "VBT initial LVDS value %x\n",
i915->vbt.bios_lvds_val); i915->vbt.bios_lvds_val);
}
} }
} }
static void static void
parse_generic_dtd(struct drm_i915_private *i915, parse_generic_dtd(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_generic_dtd *generic_dtd; const struct bdb_generic_dtd *generic_dtd;
const struct generic_dtd_entry *dtd; const struct generic_dtd_entry *dtd;
struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *panel_fixed_mode;
int num_dtd; int num_dtd;
generic_dtd = find_section(bdb, BDB_GENERIC_DTD); generic_dtd = find_section(i915, BDB_GENERIC_DTD);
if (!generic_dtd) if (!generic_dtd)
return; return;
@@ -397,15 +609,14 @@ parse_generic_dtd(struct drm_i915_private *i915,
panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Found panel mode in BIOS VBT generic dtd table:\n"); "Found panel mode in BIOS VBT generic dtd table: " DRM_MODE_FMT "\n",
drm_mode_debug_printmodeline(panel_fixed_mode); DRM_MODE_ARG(panel_fixed_mode));
i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
} }
static void static void
parse_panel_dtd(struct drm_i915_private *i915, parse_panel_dtd(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
/* /*
* Older VBTs provided provided DTD information for internal displays * 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 * try the new generic DTD block first on VBT >= 229, but still fall
* back to trying the old LFP block if that fails. * back to trying the old LFP block if that fails.
*/ */
if (bdb->version >= 229) if (i915->vbt.version >= 229)
parse_generic_dtd(i915, bdb); parse_generic_dtd(i915);
if (!i915->vbt.lfp_lvds_vbt_mode) if (!i915->vbt.lfp_lvds_vbt_mode)
parse_lfp_panel_dtd(i915, bdb); parse_lfp_panel_dtd(i915);
} }
static void static void
parse_lfp_backlight(struct drm_i915_private *i915, parse_lfp_backlight(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_lfp_backlight_data *backlight_data; const struct bdb_lfp_backlight_data *backlight_data;
const struct lfp_backlight_data_entry *entry; const struct lfp_backlight_data_entry *entry;
int panel_type = i915->vbt.panel_type; int panel_type = i915->vbt.panel_type;
u16 level; u16 level;
backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT);
if (!backlight_data) if (!backlight_data)
return; return;
@@ -452,12 +662,12 @@ parse_lfp_backlight(struct drm_i915_private *i915,
} }
i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI;
if (bdb->version >= 191) { if (i915->vbt.version >= 191) {
size_t exp_size; size_t exp_size;
if (bdb->version >= 236) if (i915->vbt.version >= 236)
exp_size = sizeof(struct bdb_lfp_backlight_data); 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; exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_234;
else else
exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_191; 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.pwm_freq_hz = entry->pwm_freq_hz;
i915->vbt.backlight.active_low_pwm = entry->active_low_pwm; i915->vbt.backlight.active_low_pwm = entry->active_low_pwm;
if (bdb->version >= 234) { if (i915->vbt.version >= 234) {
u16 min_level; u16 min_level;
bool scale; bool scale;
level = backlight_data->brightness_level[panel_type].level; level = backlight_data->brightness_level[panel_type].level;
min_level = backlight_data->brightness_min_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; scale = backlight_data->brightness_precision_bits[panel_type] == 16;
else else
scale = level > 255; scale = level > 255;
@@ -514,8 +724,7 @@ parse_lfp_backlight(struct drm_i915_private *i915,
/* Try to find sdvo panel data */ /* Try to find sdvo panel data */
static void static void
parse_sdvo_panel_data(struct drm_i915_private *i915, parse_sdvo_panel_data(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_sdvo_panel_dtds *dtds; const struct bdb_sdvo_panel_dtds *dtds;
struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *panel_fixed_mode;
@@ -531,14 +740,14 @@ parse_sdvo_panel_data(struct drm_i915_private *i915,
if (index == -1) { if (index == -1) {
const struct bdb_sdvo_lvds_options *sdvo_lvds_options; 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) if (!sdvo_lvds_options)
return; return;
index = sdvo_lvds_options->panel_type; index = sdvo_lvds_options->panel_type;
} }
dtds = find_section(bdb, BDB_SDVO_PANEL_DTDS); dtds = find_section(i915, BDB_SDVO_PANEL_DTDS);
if (!dtds) if (!dtds)
return; return;
@@ -551,8 +760,8 @@ parse_sdvo_panel_data(struct drm_i915_private *i915,
i915->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; i915->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode;
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Found SDVO panel mode in BIOS VBT tables:\n"); "Found SDVO panel mode in BIOS VBT tables: " DRM_MODE_FMT "\n",
drm_mode_debug_printmodeline(panel_fixed_mode); DRM_MODE_ARG(panel_fixed_mode));
} }
static int intel_bios_ssc_frequency(struct drm_i915_private *i915, 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 static void
parse_general_features(struct drm_i915_private *i915, parse_general_features(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_general_features *general; const struct bdb_general_features *general;
general = find_section(bdb, BDB_GENERAL_FEATURES); general = find_section(i915, BDB_GENERAL_FEATURES);
if (!general) if (!general)
return; return;
i915->vbt.int_tv_support = general->int_tv_support; i915->vbt.int_tv_support = general->int_tv_support;
/* int_crt_support can't be trusted on earlier platforms */ /* 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))) (HAS_DDI(i915) || IS_VALLEYVIEW(i915)))
i915->vbt.int_crt_support = general->int_crt_support; i915->vbt.int_crt_support = general->int_crt_support;
i915->vbt.lvds_use_ssc = general->enable_ssc; 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); intel_bios_ssc_frequency(i915, general->ssc_freq);
i915->vbt.display_clock_mode = general->display_clock_mode; i915->vbt.display_clock_mode = general->display_clock_mode;
i915->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; 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 ? i915->vbt.orientation = general->rotate_180 ?
DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP : DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP :
DRM_MODE_PANEL_ORIENTATION_NORMAL; 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; 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 = true;
i915->vbt.override_afc_startup_val = general->afc_startup_config == 0x1 ? 0x0 : 0x7; 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 static void
parse_driver_features(struct drm_i915_private *i915, parse_driver_features(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_driver_features *driver; const struct bdb_driver_features *driver;
driver = find_section(bdb, BDB_DRIVER_FEATURES); driver = find_section(i915, BDB_DRIVER_FEATURES);
if (!driver) if (!driver)
return; return;
@@ -724,13 +931,13 @@ parse_driver_features(struct drm_i915_private *i915,
* in the wild with the bits correctly populated. Version * in the wild with the bits correctly populated. Version
* 108 (on i85x) does not have the bits correctly populated. * 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_LVDS &&
driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS) driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS)
i915->vbt.int_lvds_support = 0; 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", drm_dbg_kms(&i915->drm, "DRRS State Enabled:%d\n",
driver->drrs_enabled); driver->drrs_enabled);
/* /*
@@ -740,23 +947,22 @@ parse_driver_features(struct drm_i915_private *i915,
* driver->drrs_enabled=false * driver->drrs_enabled=false
*/ */
if (!driver->drrs_enabled) 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; i915->vbt.psr.enable = driver->psr_enabled;
} }
} }
static void static void
parse_power_conservation_features(struct drm_i915_private *i915, parse_power_conservation_features(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_lfp_power *power; const struct bdb_lfp_power *power;
u8 panel_type = i915->vbt.panel_type; u8 panel_type = i915->vbt.panel_type;
if (bdb->version < 228) if (i915->vbt.version < 228)
return; return;
power = find_section(bdb, BDB_LFP_POWER); power = find_section(i915, BDB_LFP_POWER);
if (!power) if (!power)
return; return;
@@ -769,21 +975,21 @@ parse_power_conservation_features(struct drm_i915_private *i915,
* power->drrs & BIT(panel_type)=false * power->drrs & BIT(panel_type)=false
*/ */
if (!(power->drrs & BIT(panel_type))) 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); i915->vbt.edp.hobl = power->hobl & BIT(panel_type);
} }
static void 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 bdb_edp *edp;
const struct edp_power_seq *edp_pps; const struct edp_power_seq *edp_pps;
const struct edp_fast_link_params *edp_link_params; const struct edp_fast_link_params *edp_link_params;
int panel_type = i915->vbt.panel_type; int panel_type = i915->vbt.panel_type;
edp = find_section(bdb, BDB_EDP); edp = find_section(i915, BDB_EDP);
if (!edp) if (!edp)
return; return;
@@ -876,7 +1082,7 @@ parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb)
break; break;
} }
if (bdb->version >= 173) { if (i915->vbt.version >= 173) {
u8 vswing; u8 vswing;
/* Don't read from VBT if module parameter has valid value*/ /* 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.low_vswing = vswing == 0;
} }
} }
i915->vbt.edp.drrs_msa_timing_delay =
(edp->sdrrs_msa_timing_delay >> (panel_type * 2)) & 3;
} }
static void 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 bdb_psr *psr;
const struct psr_table *psr_table; const struct psr_table *psr_table;
int panel_type = i915->vbt.panel_type; int panel_type = i915->vbt.panel_type;
psr = find_section(bdb, BDB_PSR); psr = find_section(i915, BDB_PSR);
if (!psr) { if (!psr) {
drm_dbg_kms(&i915->drm, "No PSR BDB found.\n"); drm_dbg_kms(&i915->drm, "No PSR BDB found.\n");
return; 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 * New psr options 0=500us, 1=100us, 2=2500us, 3=0us
* Old decimal value is wake up time in multiples of 100 us. * 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))) { (DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) {
switch (psr_table->tp1_wakeup_time) { switch (psr_table->tp1_wakeup_time) {
case 0: 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; 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; u32 wakeup_time = psr->psr2_tp2_tp3_wakeup_time;
wakeup_time = (wakeup_time >> (2 * panel_type)) & 0x3; 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 static void
parse_mipi_config(struct drm_i915_private *i915, parse_mipi_config(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_mipi_config *start; const struct bdb_mipi_config *start;
const struct mipi_config *config; 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 /* Parse #52 for panel index used from panel_type already
* parsed * parsed
*/ */
start = find_section(bdb, BDB_MIPI_CONFIG); start = find_section(i915, BDB_MIPI_CONFIG);
if (!start) { if (!start) {
drm_dbg_kms(&i915->drm, "No MIPI config BDB found"); drm_dbg_kms(&i915->drm, "No MIPI config BDB found");
return; return;
@@ -1082,7 +1290,7 @@ parse_mipi_config(struct drm_i915_private *i915,
return; 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? */ /* FIXME is the 90 vs. 270 correct? */
switch (config->rotation) { switch (config->rotation) {
@@ -1351,8 +1559,7 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915)
} }
static void static void
parse_mipi_sequence(struct drm_i915_private *i915, parse_mipi_sequence(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
int panel_type = i915->vbt.panel_type; int panel_type = i915->vbt.panel_type;
const struct bdb_mipi_sequence *sequence; 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) if (i915->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID)
return; return;
sequence = find_section(bdb, BDB_MIPI_SEQUENCE); sequence = find_section(i915, BDB_MIPI_SEQUENCE);
if (!sequence) { if (!sequence) {
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"No MIPI Sequence found, parsing complete\n"); "No MIPI Sequence found, parsing complete\n");
@@ -1436,8 +1643,7 @@ err:
} }
static void static void
parse_compression_parameters(struct drm_i915_private *i915, parse_compression_parameters(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_compression_parameters *params; const struct bdb_compression_parameters *params;
struct intel_bios_encoder_data *devdata; struct intel_bios_encoder_data *devdata;
@@ -1445,10 +1651,10 @@ parse_compression_parameters(struct drm_i915_private *i915,
u16 block_size; u16 block_size;
int index; int index;
if (bdb->version < 198) if (i915->vbt.version < 198)
return; return;
params = find_section(bdb, BDB_COMPRESSION_PARAMETERS); params = find_section(i915, BDB_COMPRESSION_PARAMETERS);
if (params) { if (params) {
/* Sanity checks */ /* Sanity checks */
if (params->entry_size != sizeof(params->data[0])) { 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; fallthrough;
case HDMI_MAX_DATA_RATE_PLATFORM: case HDMI_MAX_DATA_RATE_PLATFORM:
return 0; 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: case HDMI_MAX_DATA_RATE_297:
return 297000; return 297000;
case HDMI_MAX_DATA_RATE_165: case HDMI_MAX_DATA_RATE_165:
@@ -2077,8 +2289,7 @@ static void parse_ddi_ports(struct drm_i915_private *i915)
} }
static void static void
parse_general_definitions(struct drm_i915_private *i915, parse_general_definitions(struct drm_i915_private *i915)
const struct bdb_header *bdb)
{ {
const struct bdb_general_definitions *defs; const struct bdb_general_definitions *defs;
struct intel_bios_encoder_data *devdata; struct intel_bios_encoder_data *devdata;
@@ -2088,7 +2299,7 @@ parse_general_definitions(struct drm_i915_private *i915,
u16 block_size; u16 block_size;
int bus_pin; int bus_pin;
defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); defs = find_section(i915, BDB_GENERAL_DEFINITIONS);
if (!defs) { if (!defs) {
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"No general definition block is found, no devices defined.\n"); "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)) if (intel_gmbus_is_valid_pin(i915, bus_pin))
i915->vbt.crt_ddc_pin = bus_pin; i915->vbt.crt_ddc_pin = bus_pin;
if (bdb->version < 106) { if (i915->vbt.version < 106) {
expected_size = 22; expected_size = 22;
} else if (bdb->version < 111) { } else if (i915->vbt.version < 111) {
expected_size = 27; expected_size = 27;
} else if (bdb->version < 195) { } else if (i915->vbt.version < 195) {
expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE; expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE;
} else if (bdb->version == 195) { } else if (i915->vbt.version == 195) {
expected_size = 37; expected_size = 37;
} else if (bdb->version <= 215) { } else if (i915->vbt.version <= 215) {
expected_size = 38; expected_size = 38;
} else if (bdb->version <= 237) { } else if (i915->vbt.version <= 237) {
expected_size = 39; expected_size = 39;
} else { } else {
expected_size = sizeof(*child); expected_size = sizeof(*child);
BUILD_BUG_ON(sizeof(*child) < 39); BUILD_BUG_ON(sizeof(*child) < 39);
drm_dbg(&i915->drm, drm_dbg(&i915->drm,
"Expected child device config size for VBT version %u not known; assuming %u\n", "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. */ /* Flag an error for unexpected size, but continue anyway. */
if (defs->child_dev_size != expected_size) if (defs->child_dev_size != expected_size)
drm_err(&i915->drm, drm_err(&i915->drm,
"Unexpected child device config size %u (expected %u for VBT version %u)\n", "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. */ /* The legacy sized child device config is the minimum we need. */
if (defs->child_dev_size < LEGACY_CHILD_DEVICE_CONFIG_SIZE) { 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; const struct bdb_header *bdb;
INIT_LIST_HEAD(&i915->vbt.display_devices); INIT_LIST_HEAD(&i915->vbt.display_devices);
INIT_LIST_HEAD(&i915->vbt.bdb_blocks);
if (!HAS_DISPLAY(i915)) { if (!HAS_DISPLAY(i915)) {
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
@@ -2488,24 +2700,26 @@ void intel_bios_init(struct drm_i915_private *i915)
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"VBT signature \"%.*s\", BDB version %d\n", "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 */ /* Grab useful general definitions */
parse_general_features(i915, bdb); parse_general_features(i915);
parse_general_definitions(i915, bdb); parse_general_definitions(i915);
parse_panel_options(i915, bdb); parse_panel_options(i915);
parse_panel_dtd(i915, bdb); parse_panel_dtd(i915);
parse_lfp_backlight(i915, bdb); parse_lfp_backlight(i915);
parse_sdvo_panel_data(i915, bdb); parse_sdvo_panel_data(i915);
parse_driver_features(i915, bdb); parse_driver_features(i915);
parse_power_conservation_features(i915, bdb); parse_power_conservation_features(i915);
parse_edp(i915, bdb); parse_edp(i915);
parse_psr(i915, bdb); parse_psr(i915);
parse_mipi_config(i915, bdb); parse_mipi_config(i915);
parse_mipi_sequence(i915, bdb); parse_mipi_sequence(i915);
/* Depends on child device list */ /* Depends on child device list */
parse_compression_parameters(i915, bdb); parse_compression_parameters(i915);
out: out:
if (!vbt) { if (!vbt) {
@@ -2527,14 +2741,20 @@ out:
*/ */
void intel_bios_driver_remove(struct drm_i915_private *i915) 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); list_del(&devdata->node);
kfree(devdata->dsc); kfree(devdata->dsc);
kfree(devdata); 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); kfree(i915->vbt.sdvo_lvds_vbt_mode);
i915->vbt.sdvo_lvds_vbt_mode = NULL; i915->vbt.sdvo_lvds_vbt_mode = NULL;
kfree(i915->vbt.lfp_lvds_vbt_mode); kfree(i915->vbt.lfp_lvds_vbt_mode);

View File

@@ -6,6 +6,7 @@
#include <drm/drm_atomic_state_helper.h> #include <drm/drm_atomic_state_helper.h>
#include "i915_reg.h" #include "i915_reg.h"
#include "i915_utils.h"
#include "intel_atomic.h" #include "intel_atomic.h"
#include "intel_bw.h" #include "intel_bw.h"
#include "intel_cdclk.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 */ /* bspec says to keep retrying for at least 1 ms */
ret = skl_pcode_request(dev_priv, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG, ret = skl_pcode_request(dev_priv, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG,
points_mask, points_mask,
ICL_PCODE_POINTS_RESTRICTED_MASK, ICL_PCODE_REP_QGV_MASK | ADLS_PCODE_REP_PSF_MASK,
ICL_PCODE_POINTS_RESTRICTED, ICL_PCODE_REP_QGV_SAFE | ADLS_PCODE_REP_PSF_SAFE,
1); 1);
if (ret < 0) { 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) 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 * 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 * that doesn't depend on the number of planes enabled. So fill all the
* single dummy QGV point to reflect that. DG2-G10 platforms have a * plane group with constant bw information for uniformity with other
* constant 50 GB/s bandwidth, whereas DG2-G11 platforms have 38 GB/s. * platforms. DG2-G10 platforms have a constant 50 GB/s bandwidth,
* whereas DG2-G11 platforms have 38 GB/s.
*/ */
bi->num_planes = 1; for (i = 0; i < num_groups; i++) {
bi->num_qgv_points = 1; struct intel_bw_info *bi = &i915->max_bw[i];
if (IS_DG2_G11(i915))
bi->deratedbw[0] = 38000; bi->num_planes = 1;
else /* Need only one dummy QGV point per group */
bi->deratedbw[0] = 50000; bi->num_qgv_points = 1;
bi->deratedbw[0] = deratedbw;
}
i915->sagv_status = I915_SAGV_NOT_CONTROLLED; 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) 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 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; unsigned int data_rate = 0;
enum plane_id plane_id; enum plane_id plane_id;
@@ -590,11 +597,26 @@ static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_
continue; continue;
data_rate += crtc_state->data_rate[plane_id]; 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; 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, void intel_bw_crtc_update(struct intel_bw_state *bw_state,
const struct intel_crtc_state *crtc_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) for_each_pipe(dev_priv, pipe)
data_rate += bw_state->data_rate[pipe]; data_rate += bw_state->data_rate[pipe];
if (DISPLAY_VER(dev_priv) >= 13 && intel_vtd_active(dev_priv)) if (DISPLAY_VER(dev_priv) >= 13 && i915_vtd_active(dev_priv))
data_rate = data_rate * 105 / 100; data_rate = DIV_ROUND_UP(data_rate * 105, 100);
return data_rate; return data_rate;
} }
@@ -674,6 +696,53 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state)
return to_intel_bw_state(bw_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, static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state,
const struct intel_crtc_state *crtc_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]; struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe];
enum plane_id plane_id; 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) if (!crtc_state->hw.active)
return; return;
for_each_plane_id_on_crtc(crtc, plane_id) { 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 * We assume cursors are small enough
* need to split per plane data_rate into data_rate_y * to not cause bandwidth problems.
* 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.
*/ */
for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask) if (plane_id == PLANE_CURSOR)
crtc_bw->used_bw[slice] += data_rate; 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 drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_bw_state *new_bw_state = NULL; 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; const struct intel_crtc_state *crtc_state;
int old_min_cdclk, new_min_cdclk;
struct intel_crtc *crtc; struct intel_crtc *crtc;
int max_bw = 0;
enum pipe pipe;
int i; int i;
if (DISPLAY_VER(dev_priv) < 9)
return 0;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
new_bw_state = intel_atomic_get_bw_state(state); new_bw_state = intel_atomic_get_bw_state(state);
if (IS_ERR(new_bw_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); old_bw_state = intel_atomic_get_old_bw_state(state);
skl_crtc_calc_dbuf_bw(new_bw_state, crtc_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) if (!old_bw_state)
return 0; return 0;
for_each_pipe(dev_priv, pipe) { if (intel_bw_state_changed(dev_priv, old_bw_state, new_bw_state)) {
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) {
int ret = intel_atomic_lock_global_state(&new_bw_state->base); int ret = intel_atomic_lock_global_state(&new_bw_state->base);
if (ret) if (ret)
return 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) /*
{ * No need to check against the cdclk state if
struct drm_i915_private *dev_priv = to_i915(state->base.dev); * the min cdclk doesn't increase.
struct intel_bw_state *new_bw_state = NULL; *
struct intel_bw_state *old_bw_state = NULL; * Ie. we only ever increase the cdclk due to bandwidth
const struct intel_crtc_state *crtc_state; * requirements. This can reduce back and forth
struct intel_crtc *crtc; * display blinking due to constant cdclk changes.
int min_cdclk = 0; */
enum pipe pipe; if (new_min_cdclk <= old_min_cdclk)
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)
return 0; return 0;
for_each_pipe(dev_priv, pipe) { cdclk_state = intel_atomic_get_cdclk_state(state);
struct intel_cdclk_state *cdclk_state; if (IS_ERR(cdclk_state))
return PTR_ERR(cdclk_state);
cdclk_state = intel_atomic_get_new_cdclk_state(state); /*
if (!cdclk_state) * No need to recalculate the cdclk state if
return 0; * 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); 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);
new_bw_state->min_cdclk = min_cdclk; *need_cdclk_calc = true;
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;
}
return 0; 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_psf_gv_points = i915->max_bw[0].num_psf_gv_points;
unsigned int num_qgv_points = i915->max_bw[0].num_qgv_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 * 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. * So need to operate only with those returned from PCode.
*/ */
if (num_qgv_points > 0) 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) 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) 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 data_rate;
unsigned int num_active_planes; unsigned int num_active_planes;
int i, ret; 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 max_bw_point = 0, max_bw = 0;
unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points; 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; 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; max_bw = max_data_rate;
} }
if (max_data_rate >= 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", drm_dbg_kms(&dev_priv->drm, "QGV point %d: max bw %d required %d\n",
i, max_data_rate, data_rate); 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); unsigned int max_data_rate = adl_psf_bw(dev_priv, i);
if (max_data_rate >= data_rate) 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" drm_dbg_kms(&dev_priv->drm, "PSF GV point %d: max bw %d"
" required %d\n", " 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 * left, so if we couldn't - simply reject the configuration for obvious
* reasons. * 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" drm_dbg_kms(&dev_priv->drm, "No QGV points provide sufficient memory"
" bandwidth %d for display configuration(%d active planes).\n", " bandwidth %d for display configuration(%d active planes).\n",
data_rate, num_active_planes); data_rate, num_active_planes);
return -EINVAL; return -EINVAL;
} }
if (num_psf_gv_points > 0) { if (num_psf_gv_points > 0 && psf_points == 0) {
if ((allowed_points & ADLS_PSF_PT_MASK) == 0) { drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory"
drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory" " bandwidth %d for display configuration(%d active planes).\n",
" bandwidth %d for display configuration(%d active planes).\n", data_rate, num_active_planes);
data_rate, num_active_planes); return -EINVAL;
return -EINVAL;
}
} }
/* /*
@@ -992,16 +1068,18 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
* cause. * cause.
*/ */
if (!intel_can_enable_sagv(dev_priv, new_bw_state)) { if (!intel_can_enable_sagv(dev_priv, new_bw_state)) {
allowed_points &= ADLS_PSF_PT_MASK; qgv_points = BIT(max_bw_point);
allowed_points |= BIT(max_bw_point);
drm_dbg_kms(&dev_priv->drm, "No SAGV, using single QGV point %d\n", drm_dbg_kms(&dev_priv->drm, "No SAGV, using single QGV point %d\n",
max_bw_point); max_bw_point);
} }
/* /*
* We store the ones which need to be masked as that is what PCode * We store the ones which need to be masked as that is what PCode
* actually accepts as a parameter. * 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); icl_qgv_points_mask(dev_priv);
/* /*

View File

@@ -17,7 +17,8 @@ struct intel_atomic_state;
struct intel_crtc_state; struct intel_crtc_state;
struct intel_dbuf_bw { 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 { struct intel_bw_state {
@@ -40,10 +41,9 @@ struct intel_bw_state {
*/ */
u16 qgv_points_mask; u16 qgv_points_mask;
int min_cdclk[I915_MAX_PIPES];
unsigned int data_rate[I915_MAX_PIPES]; unsigned int data_rate[I915_MAX_PIPES];
u8 num_active_planes[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) #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); const struct intel_crtc_state *crtc_state);
int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv, int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
u32 points_mask); u32 points_mask);
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state); int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
int skl_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__ */ #endif /* __INTEL_BW_H__ */

View File

@@ -72,7 +72,6 @@ struct intel_cdclk_funcs {
void (*set_cdclk)(struct drm_i915_private *i915, void (*set_cdclk)(struct drm_i915_private *i915,
const struct intel_cdclk_config *cdclk_config, const struct intel_cdclk_config *cdclk_config,
enum pipe pipe); enum pipe pipe);
int (*bw_calc_min_cdclk)(struct intel_atomic_state *state);
int (*modeset_calc_cdclk)(struct intel_cdclk_state *state); int (*modeset_calc_cdclk)(struct intel_cdclk_state *state);
u8 (*calc_voltage_level)(int cdclk); 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); 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, static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config, const struct intel_cdclk_config *cdclk_config,
enum pipe pipe) 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)); 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; 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 intel_atomic_state *state = cdclk_state->base.state;
struct drm_i915_private *dev_priv = to_i915(state->base.dev); 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 *crtc;
struct intel_crtc_state *crtc_state; struct intel_crtc_state *crtc_state;
int min_cdclk, i; int min_cdclk, i;
@@ -2352,10 +2338,6 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
if (min_cdclk < 0) if (min_cdclk < 0)
return min_cdclk; 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) if (cdclk_state->min_cdclk[crtc->pipe] == min_cdclk)
continue; continue;
@@ -2366,14 +2348,31 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
return ret; return ret;
} }
min_cdclk = cdclk_state->force_min_cdclk; bw_state = intel_atomic_get_new_bw_state(state);
for_each_pipe(dev_priv, pipe) { 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); min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk);
if (!bw_state) if (min_cdclk > dev_priv->max_cdclk_freq) {
continue; drm_dbg_kms(&dev_priv->drm,
"required cdclk (%d kHz) exceeds max (%d kHz)\n",
min_cdclk = max(bw_state->min_cdclk, min_cdclk); min_cdclk, dev_priv->max_cdclk_freq);
return -EINVAL;
} }
return min_cdclk; 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, int intel_cdclk_atomic_check(struct intel_atomic_state *state,
bool *need_cdclk_calc) 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 *old_cdclk_state;
const struct intel_cdclk_state *new_cdclk_state; const struct intel_cdclk_state *new_cdclk_state;
struct intel_plane_state *plane_state; struct intel_plane_state *plane_state;
struct intel_bw_state *new_bw_state;
struct intel_plane *plane; struct intel_plane *plane;
int min_cdclk = 0;
enum pipe pipe;
int ret; int ret;
int i; int i;
@@ -2676,6 +2671,10 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state,
return ret; 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); old_cdclk_state = intel_atomic_get_old_cdclk_state(state);
new_cdclk_state = intel_atomic_get_new_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) old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk)
*need_cdclk_calc = true; *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; 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 = { static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk, .get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk, .set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = tgl_calc_voltage_level, .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 = { static const struct intel_cdclk_funcs ehl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk, .get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk, .set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = ehl_calc_voltage_level, .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 = { static const struct intel_cdclk_funcs icl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk, .get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk, .set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = icl_calc_voltage_level, .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 = { static const struct intel_cdclk_funcs bxt_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk, .get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk, .set_cdclk = bxt_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = bxt_calc_voltage_level, .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 = { static const struct intel_cdclk_funcs skl_cdclk_funcs = {
.get_cdclk = skl_get_cdclk, .get_cdclk = skl_get_cdclk,
.set_cdclk = skl_set_cdclk, .set_cdclk = skl_set_cdclk,
.bw_calc_min_cdclk = skl_bw_calc_min_cdclk,
.modeset_calc_cdclk = skl_modeset_calc_cdclk, .modeset_calc_cdclk = skl_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs bdw_cdclk_funcs = { static const struct intel_cdclk_funcs bdw_cdclk_funcs = {
.get_cdclk = bdw_get_cdclk, .get_cdclk = bdw_get_cdclk,
.set_cdclk = bdw_set_cdclk, .set_cdclk = bdw_set_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = bdw_modeset_calc_cdclk, .modeset_calc_cdclk = bdw_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs chv_cdclk_funcs = { static const struct intel_cdclk_funcs chv_cdclk_funcs = {
.get_cdclk = vlv_get_cdclk, .get_cdclk = vlv_get_cdclk,
.set_cdclk = chv_set_cdclk, .set_cdclk = chv_set_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = vlv_modeset_calc_cdclk, .modeset_calc_cdclk = vlv_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs vlv_cdclk_funcs = { static const struct intel_cdclk_funcs vlv_cdclk_funcs = {
.get_cdclk = vlv_get_cdclk, .get_cdclk = vlv_get_cdclk,
.set_cdclk = vlv_set_cdclk, .set_cdclk = vlv_set_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = vlv_modeset_calc_cdclk, .modeset_calc_cdclk = vlv_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs hsw_cdclk_funcs = { static const struct intel_cdclk_funcs hsw_cdclk_funcs = {
.get_cdclk = hsw_get_cdclk, .get_cdclk = hsw_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
/* SNB, IVB, 965G, 945G */ /* SNB, IVB, 965G, 945G */
static const struct intel_cdclk_funcs fixed_400mhz_cdclk_funcs = { static const struct intel_cdclk_funcs fixed_400mhz_cdclk_funcs = {
.get_cdclk = fixed_400mhz_get_cdclk, .get_cdclk = fixed_400mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs ilk_cdclk_funcs = { static const struct intel_cdclk_funcs ilk_cdclk_funcs = {
.get_cdclk = fixed_450mhz_get_cdclk, .get_cdclk = fixed_450mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs gm45_cdclk_funcs = { static const struct intel_cdclk_funcs gm45_cdclk_funcs = {
.get_cdclk = gm45_get_cdclk, .get_cdclk = gm45_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_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 = { static const struct intel_cdclk_funcs i965gm_cdclk_funcs = {
.get_cdclk = i965gm_get_cdclk, .get_cdclk = i965gm_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_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 = { static const struct intel_cdclk_funcs pnv_cdclk_funcs = {
.get_cdclk = pnv_get_cdclk, .get_cdclk = pnv_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs g33_cdclk_funcs = { static const struct intel_cdclk_funcs g33_cdclk_funcs = {
.get_cdclk = g33_get_cdclk, .get_cdclk = g33_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs i945gm_cdclk_funcs = { static const struct intel_cdclk_funcs i945gm_cdclk_funcs = {
.get_cdclk = i945gm_get_cdclk, .get_cdclk = i945gm_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_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 = { static const struct intel_cdclk_funcs i915gm_cdclk_funcs = {
.get_cdclk = i915gm_get_cdclk, .get_cdclk = i915gm_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs i915g_cdclk_funcs = { static const struct intel_cdclk_funcs i915g_cdclk_funcs = {
.get_cdclk = fixed_333mhz_get_cdclk, .get_cdclk = fixed_333mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs i865g_cdclk_funcs = { static const struct intel_cdclk_funcs i865g_cdclk_funcs = {
.get_cdclk = fixed_266mhz_get_cdclk, .get_cdclk = fixed_266mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs i85x_cdclk_funcs = { static const struct intel_cdclk_funcs i85x_cdclk_funcs = {
.get_cdclk = i85x_get_cdclk, .get_cdclk = i85x_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs i845g_cdclk_funcs = { static const struct intel_cdclk_funcs i845g_cdclk_funcs = {
.get_cdclk = fixed_200mhz_get_cdclk, .get_cdclk = fixed_200mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };
static const struct intel_cdclk_funcs i830_cdclk_funcs = { static const struct intel_cdclk_funcs i830_cdclk_funcs = {
.get_cdclk = fixed_133mhz_get_cdclk, .get_cdclk = fixed_133mhz_get_cdclk,
.bw_calc_min_cdclk = intel_bw_calc_min_cdclk,
.modeset_calc_cdclk = fixed_modeset_calc_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk,
}; };

View File

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

View File

@@ -31,12 +31,21 @@
struct intel_color_funcs { struct intel_color_funcs {
int (*color_check)(struct intel_crtc_state *crtc_state); int (*color_check)(struct intel_crtc_state *crtc_state);
/* /*
* Program double buffered color management registers during * Program non-arming double buffered color management registers
* vblank evasion. The registers should then latch during the * before vblank evasion. The registers should then latch after
* next vblank start, alongside any other double buffered registers * the arming register is written (by color_commit_arm()) during
* involved with the same commit. * 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 * Load LUTs (and other single buffered color management
* registers). Will (hopefully) be called during the vblank * 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_coeff_identity,
ilk_csc_off_zero); 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) 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 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) { if (crtc_state->hw.ctm) {
u16 coeff[9]; 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_coeff_limited_range,
ilk_csc_postoff_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, 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); 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 intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 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); 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 intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 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); val |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode);
intel_de_write(dev_priv, PIPECONF(pipe), val); 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 intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 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), intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe),
crtc_state->gamma_mode); 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 intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 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), intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe),
crtc_state->gamma_mode); crtc_state->gamma_mode);
if (DISPLAY_VER(dev_priv) >= 11) intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
icl_load_csc_matrix(crtc_state); crtc_state->csc_mode);
else
ilk_load_csc_matrix(crtc_state);
} }
static void i9xx_load_lut_8(struct intel_crtc *crtc, 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); 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); 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) 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 = { static const struct intel_color_funcs chv_color_funcs = {
.color_check = chv_color_check, .color_check = chv_color_check,
.color_commit = i9xx_color_commit, .color_commit_arm = i9xx_color_commit_arm,
.load_luts = chv_load_luts, .load_luts = chv_load_luts,
.read_luts = chv_read_luts, .read_luts = chv_read_luts,
}; };
static const struct intel_color_funcs i965_color_funcs = { static const struct intel_color_funcs i965_color_funcs = {
.color_check = i9xx_color_check, .color_check = i9xx_color_check,
.color_commit = i9xx_color_commit, .color_commit_arm = i9xx_color_commit_arm,
.load_luts = i965_load_luts, .load_luts = i965_load_luts,
.read_luts = i965_read_luts, .read_luts = i965_read_luts,
}; };
static const struct intel_color_funcs i9xx_color_funcs = { static const struct intel_color_funcs i9xx_color_funcs = {
.color_check = i9xx_color_check, .color_check = i9xx_color_check,
.color_commit = i9xx_color_commit, .color_commit_arm = i9xx_color_commit_arm,
.load_luts = i9xx_load_luts, .load_luts = i9xx_load_luts,
.read_luts = i9xx_read_luts, .read_luts = i9xx_read_luts,
}; };
static const struct intel_color_funcs icl_color_funcs = { static const struct intel_color_funcs icl_color_funcs = {
.color_check = icl_color_check, .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, .load_luts = icl_load_luts,
.read_luts = icl_read_luts, .read_luts = icl_read_luts,
}; };
static const struct intel_color_funcs glk_color_funcs = { static const struct intel_color_funcs glk_color_funcs = {
.color_check = glk_color_check, .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, .load_luts = glk_load_luts,
.read_luts = glk_read_luts, .read_luts = glk_read_luts,
}; };
static const struct intel_color_funcs skl_color_funcs = { static const struct intel_color_funcs skl_color_funcs = {
.color_check = ivb_color_check, .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, .load_luts = bdw_load_luts,
.read_luts = NULL, .read_luts = NULL,
}; };
static const struct intel_color_funcs bdw_color_funcs = { static const struct intel_color_funcs bdw_color_funcs = {
.color_check = ivb_color_check, .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, .load_luts = bdw_load_luts,
.read_luts = NULL, .read_luts = NULL,
}; };
static const struct intel_color_funcs hsw_color_funcs = { static const struct intel_color_funcs hsw_color_funcs = {
.color_check = ivb_color_check, .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, .load_luts = ivb_load_luts,
.read_luts = NULL, .read_luts = NULL,
}; };
static const struct intel_color_funcs ivb_color_funcs = { static const struct intel_color_funcs ivb_color_funcs = {
.color_check = ivb_color_check, .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, .load_luts = ivb_load_luts,
.read_luts = NULL, .read_luts = NULL,
}; };
static const struct intel_color_funcs ilk_color_funcs = { static const struct intel_color_funcs ilk_color_funcs = {
.color_check = ilk_color_check, .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, .load_luts = ilk_load_luts,
.read_luts = ilk_read_luts, .read_luts = ilk_read_luts,
}; };

View File

@@ -14,7 +14,8 @@ struct drm_property_blob;
void intel_color_init(struct intel_crtc *crtc); void intel_color_init(struct intel_crtc *crtc);
int intel_color_check(struct intel_crtc_state *crtc_state); 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_load_luts(const struct intel_crtc_state *crtc_state);
void intel_color_get_config(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); 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 { static const struct icl_procmon {
const char *name;
u32 dw1, dw9, dw10; u32 dw1, dw9, dw10;
} icl_procmon_values[] = { } icl_procmon_values[] = {
[PROCMON_0_85V_DOT_0] = [PROCMON_0_85V_DOT_0] = {
{ .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, }, .name = "0.85V dot0 (low-voltage)",
[PROCMON_0_95V_DOT_0] = .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96,
{ .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, }, },
[PROCMON_0_95V_DOT_1] = [PROCMON_0_95V_DOT_0] = {
{ .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, }, .name = "0.95V dot0",
[PROCMON_1_05V_DOT_0] = .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB,
{ .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, }, },
[PROCMON_1_05V_DOT_1] = [PROCMON_0_95V_DOT_1] = {
{ .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, }, .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 * 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); 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), ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy),
(0xff << 16) | 0xff, procmon->dw1); (0xff << 16) | 0xff, procmon->dw1);
ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy), 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, __drm_atomic_helper_connector_reset(&connector->base,
&conn_state->base); &conn_state->base);
INIT_LIST_HEAD(&connector->panel.fixed_modes);
return 0; return 0;
} }
@@ -100,7 +102,7 @@ void intel_connector_destroy(struct drm_connector *connector)
if (!IS_ERR_OR_NULL(intel_connector->edid)) if (!IS_ERR_OR_NULL(intel_connector->edid))
kfree(intel_connector->edid); kfree(intel_connector->edid);
intel_panel_fini(&intel_connector->panel); intel_panel_fini(intel_connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);

View File

@@ -24,6 +24,7 @@
#include "intel_display_debugfs.h" #include "intel_display_debugfs.h"
#include "intel_display_trace.h" #include "intel_display_trace.h"
#include "intel_display_types.h" #include "intel_display_types.h"
#include "intel_drrs.h"
#include "intel_dsi.h" #include "intel_dsi.h"
#include "intel_pipe_crc.h" #include "intel_pipe_crc.h"
#include "intel_psr.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_color_init(crtc);
intel_crtc_drrs_init(crtc);
intel_crtc_crc_init(crtc); intel_crtc_crc_init(crtc);
cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE); 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); intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
intel_psr_lock(new_crtc_state);
if (new_crtc_state->do_async_flip) if (new_crtc_state->do_async_flip)
return; 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 * VBL interrupts will start the PSR exit and prevent a PSR
* re-entry as well. * re-entry as well.
*/ */
intel_psr_wait_for_idle(new_crtc_state); intel_psr_wait_for_idle_locked(new_crtc_state);
local_irq_disable(); 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(); ktime_t end_vbl_time = ktime_get();
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
intel_psr_unlock(new_crtc_state);
if (new_crtc_state->do_async_flip) if (new_crtc_state->do_async_flip)
return; 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.src = src;
plane_state->uapi.dst = dst; 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); ret = intel_cursor_check_surface(plane_state);
if (ret) if (ret)
return 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
u32 cntl = 0, base = 0, pos = 0, size = 0; u32 cntl = 0, base = 0, pos = 0, size = 0;
unsigned long irqflags;
if (plane_state && plane_state->uapi.visible) { if (plane_state && plane_state->uapi.visible) {
unsigned int width = drm_rect_width(&plane_state->uapi.dst); 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); 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 /* On these chipsets we can only modify the base/size/stride
* whilst the cursor is disabled. * whilst the cursor is disabled.
*/ */
@@ -290,8 +292,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane,
} else { } else {
intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos); 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, 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe; enum pipe pipe = plane->pipe;
u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0; u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
unsigned long irqflags;
if (plane_state && plane_state->uapi.visible) { if (plane_state && plane_state->uapi.visible) {
int width = drm_rect_width(&plane_state->uapi.dst); 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); pos = intel_cursor_position(plane_state);
} }
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/* /*
* On some platforms writing CURCNTR first will also * On some platforms writing CURCNTR first will also
* cause CURPOS to be armed by the CURBASE write. * 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, CURPOS(pipe), pos);
intel_de_write_fw(dev_priv, CURBASE(pipe), base); 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, 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 * FIXME bigjoiner fastpath would be good
*/ */
if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) || 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; goto slow;
/* /*
@@ -715,6 +710,14 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
*/ */
crtc_state->active_planes = new_crtc_state->active_planes; 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) { if (new_plane_state->uapi.visible) {
intel_plane_update_noarm(plane, crtc_state, new_plane_state); intel_plane_update_noarm(plane, crtc_state, new_plane_state);
intel_plane_update_arm(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); intel_plane_disable_arm(plane, crtc_state);
} }
local_irq_enable();
intel_plane_unpin_fb(old_plane_state); intel_plane_unpin_fb(old_plane_state);
out_free: out_free:

View File

@@ -25,6 +25,8 @@
* *
*/ */
#include <linux/string_helpers.h>
#include <drm/drm_privacy_screen_consumer.h> #include <drm/drm_privacy_screen_consumer.h>
#include <drm/drm_scdc_helper.h> #include <drm/drm_scdc_helper.h>
@@ -43,7 +45,6 @@
#include "intel_dp_link_training.h" #include "intel_dp_link_training.h"
#include "intel_dp_mst.h" #include "intel_dp_mst.h"
#include "intel_dpio_phy.h" #include "intel_dpio_phy.h"
#include "intel_drrs.h"
#include "intel_dsi.h" #include "intel_dsi.h"
#include "intel_fdi.h" #include "intel_fdi.h"
#include "intel_fifo_underrun.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) enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0) <= 0)
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Failed to %s MSA_TIMING_PAR_IGNORE in the sink\n", "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, 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) if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
intel_drrs_enable(intel_dp, crtc_state); intel_audio_codec_enable(encoder, crtc_state, conn_state);
if (crtc_state->has_audio)
intel_audio_codec_enable(encoder, crtc_state, conn_state);
trans_port_sync_stop_link_train(state, encoder, crtc_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), intel_de_write(dev_priv, DDI_BUF_CTL(port),
dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE); 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, 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; 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_psr_disable(intel_dp, old_crtc_state);
intel_edp_backlight_off(old_conn_state); intel_edp_backlight_off(old_conn_state);
/* Disable the decompression in DP Sink */ /* 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_i915_private *i915 = to_i915(encoder->base.dev);
struct drm_connector *connector = old_conn_state->connector; 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, if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
false, false)) 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 intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_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_ddi_set_dp_msa(crtc_state, conn_state);
intel_dp_set_infoframes(encoder, true, 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); intel_backlight_update(state, encoder, crtc_state, conn_state);
drm_connector_update_privacy_screen(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; 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); dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL);
if (!dig_port) if (!dig_port)
return; 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 = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */
{ .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */ { .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */
{ .icl = { 0x6, 0x7F, 0x2F, 0x00, 0x10 } }, /* 500 900 5.1 */ { .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, 0x35, 0x00, 0x0A } }, /* 600 900 3.5 */
{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ { .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 */ /* NT mV Trans mV db */
{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */
{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ { .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 = { 0x6, 0x7F, 0x2B, 0x00, 0x14 } }, /* 350 900 8.2 */
{ .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */ { .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */
{ .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */ { .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 */ { .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 = { static const struct intel_ddi_buf_trans adlp_combo_phy_trans_dp_hbr2_hbr3 = {
.entries = _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), .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr2_hbr3),
}; };
static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_hbr3 = { static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_hbr3 = {
.entries = _icl_combo_phy_trans_dp_hbr2_edp_hbr3, .entries = _adlp_combo_phy_trans_dp_hbr2_edp_hbr3,
.num_entries = ARRAY_SIZE(_icl_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 = { static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_up_to_hbr2 = {
.entries = _icl_combo_phy_trans_edp_hbr2, .entries = _adlp_combo_phy_trans_edp_hbr2,
.num_entries = ARRAY_SIZE(_icl_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[] = { 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 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_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
void i830_disable_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_hpll_vco(struct drm_i915_private *dev_priv);
int vlv_get_cck_clock(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); 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) \ #define I915_STATE_WARN_ON(x) \
I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")") I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")")
bool intel_scanout_needs_vtd_wa(struct drm_i915_private *i915);
#endif #endif

View File

@@ -3,6 +3,8 @@
* Copyright © 2020 Intel Corporation * Copyright © 2020 Intel Corporation
*/ */
#include <linux/string_helpers.h>
#include <drm/drm_debugfs.h> #include <drm/drm_debugfs.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
@@ -10,6 +12,7 @@
#include "intel_de.h" #include "intel_de.h"
#include "intel_display_debugfs.h" #include "intel_display_debugfs.h"
#include "intel_display_power.h" #include "intel_display_power.h"
#include "intel_display_power_well.h"
#include "intel_display_types.h" #include "intel_display_types.h"
#include "intel_dmc.h" #include "intel_dmc.h"
#include "intel_dp.h" #include "intel_dp.h"
@@ -19,6 +22,7 @@
#include "intel_fbdev.h" #include "intel_fbdev.h"
#include "intel_hdcp.h" #include "intel_hdcp.h"
#include "intel_hdmi.h" #include "intel_hdmi.h"
#include "intel_panel.h"
#include "intel_pm.h" #include "intel_pm.h"
#include "intel_psr.h" #include "intel_psr.h"
#include "intel_sprite.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); wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
seq_printf(m, "Enabled by kernel parameter: %s\n", 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) { if (DISPLAY_VER(dev_priv) >= 8) {
seq_puts(m, "Currently: unknown\n"); 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); 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; return 0;
} }
@@ -260,7 +264,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
bool enabled; bool enabled;
u32 val; 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) if (psr->sink_support)
seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]); seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]);
seq_puts(m, "\n"); 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) { if (!psr->enabled) {
seq_printf(m, "PSR sink not reliable: %s\n", seq_printf(m, "PSR sink not reliable: %s\n",
yesno(psr->sink_not_reliable)); str_yes_no(psr->sink_not_reliable));
goto unlock; 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; enabled = val & EDP_PSR_ENABLE;
} }
seq_printf(m, "Source PSR ctl: %s [0x%08x]\n", seq_printf(m, "Source PSR ctl: %s [0x%08x]\n",
enableddisabled(enabled), val); str_enabled_disabled(enabled), val);
psr_source_status(intel_dp, m); psr_source_status(intel_dp, m);
seq_printf(m, "Busy frontbuffer bits: 0x%08x\n", seq_printf(m, "Busy frontbuffer bits: 0x%08x\n",
psr->busy_frontbuffer_bits); 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", seq_printf(m, "PSR2 selective fetch: %s\n",
enableddisabled(psr->psr2_sel_fetch_enabled)); str_enabled_disabled(psr->psr2_sel_fetch_enabled));
} }
unlock: unlock:
@@ -432,75 +436,6 @@ static int i915_power_domain_info(struct seq_file *m, void *unused)
return 0; 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, static void intel_seq_print_mode(struct seq_file *m, int tabs,
const struct drm_display_mode *mode) 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); 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, 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; 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, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]);
seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio)); seq_printf(m, "\taudio support: %s\n",
if (intel_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) str_yes_no(intel_dp->has_audio));
intel_panel_info(m, &intel_connector->panel);
drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports, drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports,
edid ? edid->data : NULL, &intel_dp->aux); 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; 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, 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_encoder *intel_encoder = intel_attached_encoder(intel_connector);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(intel_encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(intel_encoder);
seq_printf(m, "\taudio support: %s\n", yesno(intel_hdmi->has_audio)); seq_printf(m, "\taudio support: %s\n",
} str_yes_no(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);
} }
static void intel_connector_info(struct seq_file *m, static void intel_connector_info(struct seq_file *m,
@@ -642,10 +578,6 @@ static void intel_connector_info(struct seq_file *m,
else else
intel_dp_info(m, intel_connector); intel_dp_info(m, intel_connector);
break; break;
case DRM_MODE_CONNECTOR_LVDS:
if (encoder->type == INTEL_OUTPUT_LVDS)
intel_lvds_info(m, intel_connector);
break;
case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIA:
if (encoder->type == INTEL_OUTPUT_HDMI || if (encoder->type == INTEL_OUTPUT_HDMI ||
encoder->type == INTEL_OUTPUT_DDI) encoder->type == INTEL_OUTPUT_DDI)
@@ -658,6 +590,8 @@ static void intel_connector_info(struct seq_file *m,
seq_puts(m, "\tHDCP version: "); seq_puts(m, "\tHDCP version: ");
intel_hdcp_info(m, intel_connector); intel_hdcp_info(m, intel_connector);
intel_panel_info(m, intel_connector);
seq_printf(m, "\tmodes:\n"); seq_printf(m, "\tmodes:\n");
list_for_each_entry(mode, &connector->modes, head) list_for_each_entry(mode, &connector->modes, head)
intel_seq_print_mode(m, 2, mode); 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", DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
fb->base.id, &fb->format->format, fb->base.id, &fb->format->format,
fb->modifier, fb->width, fb->height, 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_FP_ARG(&plane_state->uapi.src),
DRM_RECT_ARG(&plane_state->uapi.dst), DRM_RECT_ARG(&plane_state->uapi.dst),
rot_str); 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]; &crtc_state->scaler_state.scalers[i];
seq_printf(m, ", scalers[%d]: use=%s, mode=%x", 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"); seq_puts(m, "\n");
} else { } 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); crtc->base.base.id, crtc->base.name);
seq_printf(m, "\tuapi: enable=%s, active=%s, mode=" DRM_MODE_FMT "\n", seq_printf(m, "\tuapi: enable=%s, active=%s, mode=" DRM_MODE_FMT "\n",
yesno(crtc_state->uapi.enable), str_yes_no(crtc_state->uapi.enable),
yesno(crtc_state->uapi.active), str_yes_no(crtc_state->uapi.active),
DRM_MODE_ARG(&crtc_state->uapi.mode)); DRM_MODE_ARG(&crtc_state->uapi.mode));
seq_printf(m, "\thw: enable=%s, active=%s\n", 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", seq_printf(m, "\tadjusted_mode=" DRM_MODE_FMT "\n",
DRM_MODE_ARG(&crtc_state->hw.adjusted_mode)); DRM_MODE_ARG(&crtc_state->hw.adjusted_mode));
seq_printf(m, "\tpipe__mode=" DRM_MODE_FMT "\n", seq_printf(m, "\tpipe__mode=" DRM_MODE_FMT "\n",
DRM_MODE_ARG(&crtc_state->hw.pipe_mode)); DRM_MODE_ARG(&crtc_state->hw.pipe_mode));
seq_printf(m, "\tpipe src size=%dx%d, dither=%s, bpp=%d\n", seq_printf(m, "\tpipe src=" DRM_RECT_FMT ", dither=%s, bpp=%d\n",
crtc_state->pipe_src_w, crtc_state->pipe_src_h, DRM_RECT_ARG(&crtc_state->pipe_src),
yesno(crtc_state->dither), crtc_state->pipe_bpp); str_yes_no(crtc_state->dither), crtc_state->pipe_bpp);
intel_scaler_info(m, crtc); 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", seq_printf(m, "\tLinked to 0x%x pipes as a %s\n",
crtc_state->bigjoiner_pipes, crtc_state->bigjoiner_pipes,
intel_crtc_is_bigjoiner_slave(crtc_state) ? "slave" : "master"); 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); intel_plane_info(m, crtc);
seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s\n", seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s\n",
yesno(!crtc->cpu_fifo_underrun_disabled), str_yes_no(!crtc->cpu_fifo_underrun_disabled),
yesno(!crtc->pch_fifo_underrun_disabled)); str_yes_no(!crtc->pch_fifo_underrun_disabled));
crtc_updates_info(m, crtc, "\t"); 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, seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name,
pll->info->id); pll->info->id);
seq_printf(m, " pipe_mask: 0x%x, active: 0x%x, on: %s\n", 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, " tracked hardware state:\n");
seq_printf(m, " dpll: 0x%08x\n", pll->state.hw_state.dpll); seq_printf(m, " dpll: 0x%08x\n", pll->state.hw_state.dpll);
seq_printf(m, " dpll_md: 0x%08x\n", 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; struct drm_i915_private *dev_priv = m->private;
seq_printf(m, "Isochronous Priority Control: %s\n", seq_printf(m, "Isochronous Priority Control: %s\n",
yesno(dev_priv->ipc_enabled)); str_yes_no(dev_priv->ipc_enabled));
return 0; 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)); seq_printf(m, "Pipe %c\n", pipe_name(pipe));
for_each_plane_id_on_crtc(crtc, plane_id) { 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, seq_printf(m, " Plane%-8d%8u%8u%8u\n", plane_id + 1,
entry->start, entry->end, entry->start, entry->end,
skl_ddb_entry_size(entry)); 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, seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start,
entry->end, skl_ddb_entry_size(entry)); entry->end, skl_ddb_entry_size(entry));
} }
@@ -1133,97 +1068,48 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
return 0; return 0;
} }
static void drrs_status_per_crtc(struct seq_file *m, static int i915_drrs_status(struct seq_file *m, void *unused)
struct drm_device *dev,
struct intel_crtc *crtc)
{ {
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct i915_drrs *drrs = &dev_priv->drrs;
int vrefresh = 0;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
struct intel_crtc *crtc;
drm_connector_list_iter_begin(dev, &conn_iter); drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) { for_each_intel_connector_iter(connector, &conn_iter) {
bool supported = false; seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n",
connector->base.base.id, connector->base.name,
if (connector->state->crtc != &crtc->base) intel_drrs_type_str(intel_panel_drrs_type(connector)));
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_end(&conn_iter); drm_connector_list_iter_end(&conn_iter);
seq_puts(m, "\n"); seq_puts(m, "\n");
if (to_intel_crtc_state(crtc->base.state)->has_drrs) { for_each_intel_crtc(&dev_priv->drm, crtc) {
struct intel_panel *panel; 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 */ /* 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 */ seq_printf(m, "\tDRRS Active: %s\n",
if (!drrs->dp) { str_yes_no(intel_drrs_is_active(crtc)));
seq_puts(m, "Idleness DRRS: Disabled\n");
mutex_unlock(&drrs->mutex);
return;
}
panel = &drrs->dp->attached_connector->panel; seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n",
seq_printf(m, "\t\tBusy_frontbuffer_bits: 0x%X", crtc->drrs.busy_frontbuffer_bits);
drrs->busy_frontbuffer_bits);
seq_puts(m, "\n\t\t"); seq_printf(m, "\tDRRS refresh rate: %s\n",
if (drrs->refresh_rate_type == DRRS_HIGH_RR) { crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ?
seq_puts(m, "DRRS_State: DRRS_HIGH_RR\n"); "low" : "high");
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_puts(m, "\n\t\t"); mutex_unlock(&crtc->drrs.mutex);
mutex_unlock(&drrs->mutex);
} else {
/* DRRS not supported. Print the VBT parameter*/
seq_puts(m, "\tDRRS Enabled : No");
} }
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; return 0;
} }
@@ -1259,7 +1145,7 @@ static int i915_lpsp_status(struct seq_file *m, void *unused)
return 0; return 0;
} }
seq_printf(m, "LPSP: %s\n", enableddisabled(lpsp_enabled)); seq_printf(m, "LPSP: %s\n", str_enabled_disabled(lpsp_enabled));
return 0; 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, "Threshold: %d\n", hotplug->hpd_storm_threshold);
seq_printf(m, "Detected: %s\n", seq_printf(m, "Detected: %s\n",
yesno(delayed_work_pending(&hotplug->reenable_work))); str_yes_no(delayed_work_pending(&hotplug->reenable_work)));
return 0; 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; struct drm_i915_private *dev_priv = m->private;
seq_printf(m, "Enabled: %s\n", 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; return 0;
} }
@@ -1888,13 +1774,8 @@ static int i915_drrs_ctl_set(void *data, u64 val)
struct drm_device *dev = &dev_priv->drm; struct drm_device *dev = &dev_priv->drm;
struct intel_crtc *crtc; struct intel_crtc *crtc;
if (DISPLAY_VER(dev_priv) < 7)
return -ENODEV;
for_each_intel_crtc(dev, crtc) { for_each_intel_crtc(dev, crtc) {
struct drm_connector_list_iter conn_iter;
struct intel_crtc_state *crtc_state; struct intel_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_crtc_commit *commit; struct drm_crtc_commit *commit;
int ret; int ret;
@@ -1915,30 +1796,13 @@ static int i915_drrs_ctl_set(void *data, u64 val)
goto out; goto out;
} }
drm_connector_list_iter_begin(dev, &conn_iter); drm_dbg(&dev_priv->drm,
drm_for_each_connector_iter(connector, &conn_iter) { "Manually %sactivating DRRS\n", val ? "" : "de");
struct intel_encoder *encoder;
struct intel_dp *intel_dp;
if (!(crtc_state->uapi.connector_mask & if (val)
drm_connector_mask(connector))) intel_drrs_activate(crtc_state);
continue; else
intel_drrs_deactivate(crtc_state);
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);
out: out:
drm_modeset_unlock(&crtc->base.mutex); 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_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_edp_psr_status", i915_edp_psr_status, 0},
{"i915_power_domain_info", i915_power_domain_info, 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_display_info", i915_display_info, 0},
{"i915_shared_dplls_info", i915_shared_dplls_info, 0}, {"i915_shared_dplls_info", i915_shared_dplls_info, 0},
{"i915_dp_mst_info", i915_dp_mst_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), ARRAY_SIZE(intel_display_debugfs_list),
minor->debugfs_root, minor); minor->debugfs_root, minor);
intel_dmc_debugfs_register(i915);
intel_fbc_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)); intel_dp = intel_attached_dp(to_intel_connector(connector));
crtc_state = to_intel_crtc_state(crtc->state); crtc_state = to_intel_crtc_state(crtc->state);
seq_printf(m, "DSC_Enabled: %s\n", 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", 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", 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)) if (!intel_dp_is_edp(intel_dp))
seq_printf(m, "FEC_Sink_Support: %s\n", 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); } while (try_again);
drm_modeset_drop_locks(&ctx); 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 i915_power_well;
struct intel_encoder; 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 { enum intel_display_power_domain {
POWER_DOMAIN_DISPLAY_CORE, POWER_DOMAIN_DISPLAY_CORE,
POWER_DOMAIN_PIPE_A, POWER_DOMAIN_PIPE_A,
@@ -29,10 +34,12 @@ enum intel_display_power_domain {
POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_C,
POWER_DOMAIN_TRANSCODER_D, POWER_DOMAIN_TRANSCODER_D,
POWER_DOMAIN_TRANSCODER_EDP, 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_A,
POWER_DOMAIN_TRANSCODER_DSI_C, 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_A_LANES,
POWER_DOMAIN_PORT_DDI_B_LANES, POWER_DOMAIN_PORT_DDI_B_LANES,
POWER_DOMAIN_PORT_DDI_C_LANES, POWER_DOMAIN_PORT_DDI_C_LANES,
@@ -125,30 +132,6 @@ enum intel_display_power_domain {
POWER_DOMAIN_NUM, 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(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \ #define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER) ((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, bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain); 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, bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain); enum intel_display_power_domain domain);
intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv, 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) #if !defined(__INTEL_DISPLAY_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
#define __INTEL_DISPLAY_TRACE_H__ #define __INTEL_DISPLAY_TRACE_H__
#include <linux/string_helpers.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/tracepoint.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", 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_A], __entry->scanline[PIPE_A],
__entry->frame[PIPE_B], __entry->scanline[PIPE_B], __entry->frame[PIPE_B], __entry->scanline[PIPE_B],
__entry->frame[PIPE_C], __entry->scanline[PIPE_C]) __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", 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, pipe_name(__entry->pipe), __entry->frame, __entry->scanline,
__entry->primary, __entry->sprite, __entry->cursor, __entry->primary, __entry->sprite, __entry->cursor,
yesno(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc, str_yes_no(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc,
yesno(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc, str_yes_no(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc,
yesno(__entry->fbc)) str_yes_no(__entry->fbc))
); );
TRACE_EVENT(vlv_wm, TRACE_EVENT(vlv_wm,

View File

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

View File

@@ -28,6 +28,7 @@
#include "i915_reg.h" #include "i915_reg.h"
#include "intel_de.h" #include "intel_de.h"
#include "intel_dmc.h" #include "intel_dmc.h"
#include "intel_dmc_regs.h"
/** /**
* DOC: DMC Firmware Support * DOC: DMC Firmware Support
@@ -37,6 +38,10 @@
* low-power state and comes back to normal. * 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) \ #define DMC_PATH(platform, major, minor) \
"i915/" \ "i915/" \
__stringify(platform) "_dmc_ver" \ __stringify(platform) "_dmc_ver" \
@@ -47,8 +52,8 @@
#define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE #define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE
#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 14) #define ADLP_DMC_PATH DMC_PATH(adlp, 2, 16)
#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 14) #define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 16)
MODULE_FIRMWARE(ADLP_DMC_PATH); MODULE_FIRMWARE(ADLP_DMC_PATH);
#define ADLS_DMC_PATH DMC_PATH(adls, 2, 01) #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; struct intel_dmc *dmc = &dev_priv->dmc;
u32 id, i; u32 id, i;
if (!HAS_DMC(dev_priv)) { if (!intel_dmc_has_payload(dev_priv))
drm_err(&dev_priv->drm,
"No DMC support available for this platform\n");
return; 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); 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); 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, static bool fw_info_matches_stepping(const struct intel_fw_info *fw_info,
const struct stepping_info *si) 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->fw_path = RKL_DMC_PATH;
dmc->required_version = RKL_DMC_VERSION_REQUIRED; dmc->required_version = RKL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; 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->fw_path = TGL_DMC_PATH;
dmc->required_version = TGL_DMC_VERSION_REQUIRED; dmc->required_version = TGL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; 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++) for (id = 0; id < DMC_FW_MAX; id++)
kfree(dev_priv->dmc.dmc_info[id].payload); 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 "intel_wakeref.h"
#include <linux/workqueue.h> #include <linux/workqueue.h>
struct drm_i915_error_state_buf;
struct drm_i915_private; 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 { enum {
DMC_FW_MAIN = 0, DMC_FW_MAIN = 0,
DMC_FW_PIPEA, 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_suspend(struct drm_i915_private *i915);
void intel_dmc_ucode_resume(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); 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__ */ #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/i2c.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/timekeeping.h> #include <linux/timekeeping.h>
#include <linux/types.h> #include <linux/types.h>
@@ -59,7 +60,6 @@
#include "intel_dp_mst.h" #include "intel_dp_mst.h"
#include "intel_dpio_phy.h" #include "intel_dpio_phy.h"
#include "intel_dpll.h" #include "intel_dpll.h"
#include "intel_drrs.h"
#include "intel_fifo_underrun.h" #include "intel_fifo_underrun.h"
#include "intel_hdcp.h" #include "intel_hdcp.h"
#include "intel_hdmi.h" #include "intel_hdmi.h"
@@ -67,6 +67,7 @@
#include "intel_lspcon.h" #include "intel_lspcon.h"
#include "intel_lvds.h" #include "intel_lvds.h"
#include "intel_panel.h" #include "intel_panel.h"
#include "intel_pch_display.h"
#include "intel_pps.h" #include "intel_pps.h"
#include "intel_psr.h" #include "intel_psr.h"
#include "intel_tc.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; 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) static int icl_max_source_rate(struct intel_dp *intel_dp)
{ {
struct intel_digital_port *dig_port = dp_to_dig_port(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); 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); enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_phy_is_combo(dev_priv, phy) && if (intel_phy_is_combo(dev_priv, phy) && !intel_dp_is_edp(intel_dp))
(is_low_voltage_sku(dev_priv, phy) || !intel_dp_is_edp(intel_dp)))
return 540000; return 540000;
return 810000; 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) static int ehl_max_source_rate(struct intel_dp *intel_dp)
{ {
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); if (intel_dp_is_edp(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))
return 540000; return 540000;
return 810000; return 810000;
@@ -469,7 +444,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
max_rate = dg2_max_source_rate(intel_dp); max_rate = dg2_max_source_rate(intel_dp);
else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) || else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) ||
IS_DG1(dev_priv) || IS_ROCKETLAKE(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)) else if (IS_JSL_EHL(dev_priv))
max_rate = ehl_max_source_rate(intel_dp); max_rate = ehl_max_source_rate(intel_dp);
else else
@@ -580,8 +555,9 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
int link_rate, int link_rate,
u8 lane_count) u8 lane_count)
{ {
/* FIXME figure out what we actually want here */
const struct drm_display_mode *fixed_mode = 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; int mode_rate, max_rate;
mode_rate = intel_dp_link_required(fixed_mode->clock, 18); 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 static enum intel_output_format
intel_dp_output_format(struct drm_connector *connector, intel_dp_output_format(struct intel_connector *connector,
const struct drm_display_mode *mode) bool ycbcr_420_output)
{ {
struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); struct intel_dp *intel_dp = intel_attached_dp(connector);
const struct drm_display_info *info = &connector->display_info;
if (!connector->ycbcr_420_allowed || if (!connector->base.ycbcr_420_allowed || !ycbcr_420_output)
!drm_mode_is_420_only(info, mode))
return INTEL_OUTPUT_FORMAT_RGB; return INTEL_OUTPUT_FORMAT_RGB;
if (intel_dp->dfp.rgb_to_ycbcr && 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 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_mode *mode)
{ {
const struct drm_display_info *info = &connector->base.display_info;
enum intel_output_format output_format = 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)); 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); 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 static enum drm_mode_status
intel_dp_mode_valid_downstream(struct intel_connector *connector, intel_dp_mode_valid_downstream(struct intel_connector *connector,
const struct drm_display_mode *mode, 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); struct intel_dp *intel_dp = intel_attached_dp(connector);
const struct drm_display_info *info = &connector->base.display_info; 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 PCON supports FRL MODE, check FRL bandwidth constraints */
if (intel_dp->dfp.pcon_max_frl_bw) { if (intel_dp->dfp.pcon_max_frl_bw) {
int target_bw; int target_bw;
int max_frl_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; 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) target_clock > intel_dp->dfp.max_dotclock)
return MODE_CLOCK_HIGH; return MODE_CLOCK_HIGH;
/* Assume 8bpc for the DP++/HDMI/DVI TMDS clock check */ ycbcr_420_only = drm_mode_is_420_only(info, mode);
tmds_clock = intel_hdmi_tmds_clock(target_clock, 8,
drm_mode_is_420_only(info, mode));
if (intel_dp->dfp.min_tmds_clock && /* Assume 8bpc for the DP++/HDMI/DVI TMDS clock check */
tmds_clock < intel_dp->dfp.min_tmds_clock) status = intel_dp_tmds_clock_valid(intel_dp, target_clock,
return MODE_CLOCK_LOW; 8, ycbcr_420_only, true);
if (intel_dp->dfp.max_tmds_clock &&
tmds_clock > intel_dp->dfp.max_tmds_clock) if (status != MODE_OK) {
return MODE_CLOCK_HIGH; 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; return MODE_OK;
} }
@@ -911,13 +931,13 @@ static bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
} }
static enum drm_mode_status 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 drm_display_mode *mode)
{ {
struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); struct intel_connector *connector = to_intel_connector(_connector);
struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dp *intel_dp = intel_attached_dp(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct drm_i915_private *dev_priv = to_i915(connector->dev); const struct drm_display_mode *fixed_mode;
int target_clock = mode->clock; int target_clock = mode->clock;
int max_rate, mode_rate, max_lanes, max_link_clock; int max_rate, mode_rate, max_lanes, max_link_clock;
int max_dotclk = dev_priv->max_dotclk_freq; 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) if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_H_ILLEGAL; return MODE_H_ILLEGAL;
fixed_mode = intel_panel_fixed_mode(connector, mode);
if (intel_dp_is_edp(intel_dp) && fixed_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) if (status != MODE_OK)
return status; return status;
@@ -1007,8 +1028,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
if (mode_rate > max_rate && !dsc) if (mode_rate > max_rate && !dsc)
return MODE_CLOCK_HIGH; return MODE_CLOCK_HIGH;
status = intel_dp_mode_valid_downstream(intel_connector, status = intel_dp_mode_valid_downstream(connector, mode, target_clock);
mode, target_clock);
if (status != MODE_OK) if (status != MODE_OK)
return status; 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); drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
} }
static bool intel_dp_hdmi_ycbcr420(struct intel_dp *intel_dp, static bool intel_dp_is_ycbcr420(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state) const struct intel_crtc_state *crtc_state)
{ {
return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 || return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
(crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 && (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 &&
intel_dp->dfp.ycbcr_444_to_420); intel_dp->dfp.ycbcr_444_to_420);
} }
static bool intel_dp_hdmi_tmds_clock_valid(struct intel_dp *intel_dp, static int intel_dp_hdmi_compute_bpc(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state, int bpc) 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 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) * Current bpc could already be below 8bpc due to
return false; * 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) * We will never exceed downstream TMDS clock limits while
return false; * 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, return -EINVAL;
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);
} }
static int intel_dp_max_bpp(struct intel_dp *intel_dp, 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 drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_connector *intel_connector = intel_dp->attached_connector; 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); bpc = min_t(int, bpc, intel_dp->dfp.max_bpc);
if (intel_dp->dfp.min_tmds_clock) { if (intel_dp->dfp.min_tmds_clock) {
for (; bpc >= 10; bpc -= 2) { int max_hdmi_bpc;
if (intel_dp_hdmi_bpc_possible(intel_dp, crtc_state, bpc))
break; 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; bpp = bpc * 3;
@@ -1424,13 +1454,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
pipe_config->lane_count, pipe_config->lane_count,
adjusted_mode->crtc_clock, adjusted_mode->crtc_clock,
adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay,
pipe_config->bigjoiner, pipe_config->bigjoiner_pipes,
pipe_bpp); pipe_bpp);
dsc_dp_slice_count = dsc_dp_slice_count =
intel_dp_dsc_get_slice_count(intel_dp, intel_dp_dsc_get_slice_count(intel_dp,
adjusted_mode->crtc_clock, adjusted_mode->crtc_clock,
adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay,
pipe_config->bigjoiner); pipe_config->bigjoiner_pipes);
if (!dsc_max_output_bpp || !dsc_dp_slice_count) { if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
"Compressed BPP/Slice Count not supported\n"); "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. * then we need to use 2 VDSC instances.
*/ */
if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq || if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq ||
pipe_config->bigjoiner) { pipe_config->bigjoiner_pipes) {
if (pipe_config->dsc.slice_count < 2) { if (pipe_config->dsc.slice_count < 2) {
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
"Cannot split stream to use 2 VDSC instances\n"); "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 static int
intel_dp_compute_link_config(struct intel_encoder *encoder, intel_dp_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config, 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 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 = const struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode; &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct link_config_limits limits; struct link_config_limits limits;
bool joiner_needs_dsc = false;
int ret; int ret;
limits.min_rate = intel_dp_common_rate(intel_dp, 0); 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.max_lane_count = intel_dp_max_lane_count(intel_dp);
limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); 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) { 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, if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
adjusted_mode->crtc_clock)) 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 * 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); ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits);
/* if (ret || joiner_needs_dsc || intel_dp->force_dsc_en) {
* Pipe joiner needs compression upto display12 due to BW limitation. DG2 drm_dbg_kms(&i915->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n",
* onwards pipe joiner can be enabled without compression. str_yes_no(ret), str_yes_no(joiner_needs_dsc),
*/ str_yes_no(intel_dp->force_dsc_en));
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)) {
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
conn_state, &limits); conn_state, &limits);
if (ret < 0) 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); 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 int
intel_dp_compute_config(struct intel_encoder *encoder, intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config, 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_i915_private *dev_priv = to_i915(encoder->base.dev);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
enum port port = encoder->port; const struct drm_display_mode *fixed_mode;
struct intel_connector *intel_connector = intel_dp->attached_connector; struct intel_connector *connector = intel_dp->attached_connector;
struct intel_digital_connector_state *intel_conn_state =
to_intel_digital_connector_state(conn_state);
bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N); bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N);
int ret = 0, output_bpp; 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->has_pch_encoder = true;
pipe_config->output_format = intel_dp_output_format(&intel_connector->base, pipe_config->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state);
adjusted_mode);
if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode);
ret = intel_panel_fitting(pipe_config, conn_state); if (intel_dp_is_edp(intel_dp) && fixed_mode) {
if (ret) ret = intel_panel_compute_config(connector, adjusted_mode);
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);
if (ret) if (ret)
return 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)) if (intel_dp_hdisplay_bad(dev_priv, adjusted_mode->crtc_hdisplay))
return -EINVAL; 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; 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 = pipe_config->limited_color_range =
intel_dp_limited_color_range(pipe_config, conn_state); 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_vrr_compute_config(pipe_config, conn_state);
intel_psr_compute_config(intel_dp, pipe_config, conn_state); intel_psr_compute_config(intel_dp, pipe_config, conn_state);
intel_drrs_compute_config(intel_dp, pipe_config, output_bpp, intel_dp_drrs_compute_config(connector, pipe_config,
constant_n); output_bpp, constant_n);
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
intel_dp_compute_hdr_metadata_infoframe_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) if (ret < 0)
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Failed to %s sink decompression state\n", "Failed to %s sink decompression state\n",
enabledisable(enable)); str_enable_disable(enable));
} }
static void 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, if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_PROTOCOL_CONVERTER_CONTROL_0, tmp) != 1) DP_PROTOCOL_CONVERTER_CONTROL_0, tmp) != 1)
drm_dbg_kms(&i915->drm, "Failed to %s protocol converter HDMI mode\n", 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 && tmp = crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 &&
intel_dp->dfp.ycbcr_444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0; 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) DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1)
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Failed to %s protocol converter YCbCr 4:2:0 conversion mode\n", "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; tmp = intel_dp->dfp.rgb_to_ycbcr ?
if (intel_dp->dfp.rgb_to_ycbcr) { DP_CONVERSION_BT709_RGB_YCBCR_ENABLE : 0;
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;
}
}
if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0) if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0)
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Failed to %s protocol converter RGB->YCbCr conversion mode\n", "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_mode_set_name(mode);
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"[CONNECTOR:%d:%s] using generated MSO mode: ", "[CONNECTOR:%d:%s] using generated MSO mode: " DRM_MODE_FMT "\n",
connector->base.base.id, connector->base.name); connector->base.base.id, connector->base.name,
drm_mode_debug_printmodeline(mode); DRM_MODE_ARG(mode));
} }
static void intel_edp_mso_init(struct intel_dp *intel_dp) 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, drm_dbg_kms(&i915->drm,
"[ENCODER:%d:%s] MST support: port: %s, sink: %s, modparam: %s\n", "[ENCODER:%d:%s] MST support: port: %s, sink: %s, modparam: %s\n",
encoder->base.base.id, encoder->base.name, encoder->base.base.id, encoder->base.name,
yesno(intel_dp_mst_source_support(intel_dp)), yesno(sink_can_mst), str_yes_no(intel_dp_mst_source_support(intel_dp)),
yesno(i915->params.enable_dp_mst)); str_yes_no(sink_can_mst),
str_yes_no(i915->params.enable_dp_mst));
if (!intel_dp_mst_source_support(intel_dp)) if (!intel_dp_mst_source_support(intel_dp))
return; return;
@@ -4347,9 +4480,7 @@ intel_dp_update_420(struct intel_dp *intel_dp)
intel_dp->downstream_ports); intel_dp->downstream_ports);
rgb_to_ycbcr = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd, rgb_to_ycbcr = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd,
intel_dp->downstream_ports, intel_dp->downstream_ports,
DP_DS_HDMI_BT601_RGB_YCBCR_CONV | DP_DS_HDMI_BT709_RGB_YCBCR_CONV);
DP_DS_HDMI_BT709_RGB_YCBCR_CONV |
DP_DS_HDMI_BT2020_RGB_YCBCR_CONV);
if (DISPLAY_VER(i915) >= 11) { if (DISPLAY_VER(i915) >= 11) {
/* Let PCON convert from RGB->YCbCr if possible */ /* 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, 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:%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, connector->base.base.id, connector->base.name,
yesno(intel_dp->dfp.rgb_to_ycbcr), str_yes_no(intel_dp->dfp.rgb_to_ycbcr),
yesno(connector->base.ycbcr_420_allowed), str_yes_no(connector->base.ycbcr_420_allowed),
yesno(intel_dp->dfp.ycbcr_444_to_420)); str_yes_no(intel_dp->dfp.ycbcr_444_to_420));
} }
static void static void
intel_dp_set_edid(struct intel_dp *intel_dp) 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 intel_connector *connector = intel_dp->attached_connector;
struct edid *edid; struct edid *edid;
bool vrr_capable;
intel_dp_unset_edid(intel_dp); intel_dp_unset_edid(intel_dp);
edid = intel_dp_get_edid(intel_dp); edid = intel_dp_get_edid(intel_dp);
connector->detect_edid = edid; 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_dfp(intel_dp, edid);
intel_dp_update_420(intel_dp); 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; intel_dp->dfp.ycbcr_444_to_420 = false;
connector->base.ycbcr_420_allowed = false; connector->base.ycbcr_420_allowed = false;
drm_connector_set_vrr_capable_property(&connector->base,
false);
} }
static int static int
@@ -4572,26 +4713,12 @@ static int intel_dp_get_modes(struct drm_connector *connector)
int num_modes = 0; int num_modes = 0;
edid = intel_connector->detect_edid; edid = intel_connector->detect_edid;
if (edid) { if (edid)
num_modes = intel_connector_update_modes(connector, 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 */ /* Also add fixed mode, which may or may not be present in EDID */
if (intel_dp_is_edp(intel_attached_dp(intel_connector)) && if (intel_dp_is_edp(intel_attached_dp(intel_connector)))
intel_connector->panel.fixed_mode) { num_modes += intel_panel_get_modes(intel_connector);
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 (num_modes) if (num_modes)
return num_modes; return num_modes;
@@ -4643,9 +4770,7 @@ intel_dp_connector_register(struct drm_connector *connector)
if (lspcon_init(dig_port)) { if (lspcon_init(dig_port)) {
lspcon_detect_hdr_capability(lspcon); lspcon_detect_hdr_capability(lspcon);
if (lspcon->hdr_supported) if (lspcon->hdr_supported)
drm_object_attach_property(&connector->base, drm_connector_attach_hdr_output_metadata_property(connector);
connector->dev->mode_config.hdr_output_metadata_property,
0);
} }
return ret; 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); 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 static void
intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector) 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); intel_attach_dp_colorspace_property(connector);
} }
if (IS_GEMINILAKE(dev_priv) || DISPLAY_VER(dev_priv) >= 11) if (has_gamut_metadata_dip(dev_priv, port))
drm_object_attach_property(&connector->base, drm_connector_attach_hdr_output_metadata_property(connector);
connector->dev->mode_config.hdr_output_metadata_property,
0);
if (intel_dp_is_edp(intel_dp)) { if (intel_dp_is_edp(intel_dp)) {
u32 allowed_scalers; 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); 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, static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct intel_connector *intel_connector) struct intel_connector *intel_connector)
{ {
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct drm_device *dev = &dev_priv->drm; struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector = &intel_connector->base; struct drm_connector *connector = &intel_connector->base;
struct drm_display_mode *fixed_mode = NULL; struct drm_display_mode *fixed_mode;
struct drm_display_mode *downclock_mode = NULL;
bool has_dpcd; bool has_dpcd;
enum pipe pipe = INVALID_PIPE; enum pipe pipe = INVALID_PIPE;
struct edid *edid; struct edid *edid;
@@ -5026,20 +5184,20 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
} }
intel_connector->edid = edid; intel_connector->edid = edid;
fixed_mode = intel_panel_edid_fixed_mode(intel_connector); intel_panel_add_edid_fixed_modes(intel_connector,
if (fixed_mode) dev_priv->vbt.drrs_type != DRRS_TYPE_NONE);
downclock_mode = intel_drrs_init(intel_connector, fixed_mode);
/* MSO requires information from the EDID */ /* MSO requires information from the EDID */
intel_edp_mso_init(intel_dp); intel_edp_mso_init(intel_dp);
/* multiply the mode clock and horizontal timings for MSO */ /* multiply the mode clock and horizontal timings for MSO */
intel_edp_mso_mode_fixup(intel_connector, fixed_mode); list_for_each_entry(fixed_mode, &intel_connector->panel.fixed_modes, head)
intel_edp_mso_mode_fixup(intel_connector, downclock_mode); intel_edp_mso_mode_fixup(intel_connector, fixed_mode);
/* fallback to VBT if available for eDP */ /* fallback to VBT if available for eDP */
if (!fixed_mode) if (!intel_panel_preferred_fixed_mode(intel_connector))
fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { 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)); 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)) if (!(dev_priv->quirks & QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
intel_connector->panel.backlight.power = intel_pps_backlight_power; intel_connector->panel.backlight.power = intel_pps_backlight_power;
intel_backlight_setup(intel_connector, pipe); intel_backlight_setup(intel_connector, pipe);
if (fixed_mode) { intel_edp_add_properties(intel_dp);
drm_connector_set_panel_orientation_with_quirk(connector,
dev_priv->vbt.orientation,
fixed_mode->hdisplay, fixed_mode->vdisplay);
}
return true; 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, 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) enum drm_dp_phy dp_phy)
{ {
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; 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)); 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, drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
"[ENCODER:%d:%s][%s] failed to read the PHY caps\n", "[ENCODER:%d:%s][%s] failed to read the PHY caps\n",
encoder->base.base.id, encoder->base.name, phy_name); 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); 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 intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_i915_private *i915 = to_i915(encoder->base.dev);
int ret;
if (intel_dp_is_edp(intel_dp)) if (intel_dp_is_edp(intel_dp))
return false; 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)) if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915))
return false; return false;
if (drm_dp_read_lttpr_common_caps(&intel_dp->aux, ret = drm_dp_read_lttpr_common_caps(&intel_dp->aux, dpcd,
intel_dp->lttpr_common_caps) < 0) intel_dp->lttpr_common_caps);
if (ret < 0)
goto reset_caps; goto reset_caps;
drm_dbg_kms(&dp_to_i915(intel_dp)->drm, 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; 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 intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_i915_private *i915 = to_i915(encoder->base.dev);
int lttpr_count; int lttpr_count;
int i; int i;
if (!intel_dp_read_lttpr_common_caps(intel_dp)) if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd))
return 0; return 0;
lttpr_count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps); 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++) 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; 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 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)) { if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) {
intel_dp_reset_lttpr_common_caps(intel_dp); intel_dp_reset_lttpr_common_caps(intel_dp);
return -EIO; return -EIO;

View File

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

View File

@@ -4,6 +4,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string_helpers.h>
#include "intel_crtc.h" #include "intel_crtc.h"
#include "intel_de.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 = { 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 * since those are the strictest limits we have. The fast
* clock and actual rate limits are more relaxed, so checking * clock and actual rate limits are more relaxed, so checking
* them would make no difference. * them would make no difference.
*/ */
.dot = { .min = 25000 * 5, .max = 270000 * 5 }, .dot = { .min = 25000, .max = 270000 },
.vco = { .min = 4000000, .max = 6000000 }, .vco = { .min = 4000000, .max = 6000000 },
.n = { .min = 1, .max = 7 }, .n = { .min = 1, .max = 7 },
.m1 = { .min = 2, .max = 3 }, .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 = { 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 * since those are the strictest limits we have. The fast
* clock and actual rate limits are more relaxed, so checking * clock and actual rate limits are more relaxed, so checking
* them would make no difference. * them would make no difference.
*/ */
.dot = { .min = 25000 * 5, .max = 540000 * 5}, .dot = { .min = 25000, .max = 540000 },
.vco = { .min = 4800000, .max = 6480000 }, .vco = { .min = 4800000, .max = 6480000 },
.n = { .min = 1, .max = 1 }, .n = { .min = 1, .max = 1 },
.m1 = { .min = 2, .max = 2 }, .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 = { static const struct intel_limit intel_limits_bxt = {
/* FIXME: find real dot limits */ .dot = { .min = 25000, .max = 594000 },
.dot = { .min = 0, .max = INT_MAX },
.vco = { .min = 4800000, .max = 6700000 }, .vco = { .min = 4800000, .max = 6700000 },
.n = { .min = 1, .max = 1 }, .n = { .min = 1, .max = 1 },
.m1 = { .min = 2, .max = 2 }, .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) int vlv_calc_dpll_params(int refclk, struct dpll *clock)
{ {
clock->m = clock->m1 * clock->m2; 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)) if (WARN_ON(clock->n == 0 || clock->p == 0))
return 0; return 0;
clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); 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) int chv_calc_dpll_params(int refclk, struct dpll *clock)
{ {
clock->m = clock->m1 * clock->m2; 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)) if (WARN_ON(clock->n == 0 || clock->p == 0))
return 0; return 0;
clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m), clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
clock->n << 22); clock->n << 22);
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); 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 * Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation: * refclk, or FALSE.
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* *
* Target and reference clocks are specified in kHz. * 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 * Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation: * refclk, or FALSE.
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* *
* Target and reference clocks are specified in kHz. * 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 * Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation: * refclk, or FALSE.
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
* *
* Target and reference clocks are specified in kHz. * 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 * Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation: * refclk, or FALSE.
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/ */
static bool static bool
vlv_find_best_dpll(const struct intel_limit *limit, 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); int max_n = min(limit->n.max, refclk / 19200);
bool found = false; bool found = false;
target *= 5; /* fast clock */
memset(best_clock, 0, sizeof(*best_clock)); memset(best_clock, 0, sizeof(*best_clock));
/* based on hardware requirement, prefer smaller n to precision */ /* 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.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow; for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
clock.p2 -= clock.p2 > 10 ? 2 : 1) { 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 */ /* based on hardware requirement, prefer bigger m1,m2 values */
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
unsigned int ppm; 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 * Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation: * refclk, or FALSE.
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/ */
static bool static bool
chv_find_best_dpll(const struct intel_limit *limit, 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.n = 1;
clock.m1 = 2; clock.m1 = 2;
target *= 5; /* fast clock */
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
for (clock.p2 = limit->p2.p2_fast; 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) { clock.p2 -= clock.p2 > 10 ? 2 : 1) {
unsigned int error_ppm; 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, m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
refclk * clock.m1); 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; cur_state = intel_de_read(dev_priv, DPLL(pipe)) & DPLL_VCO_ENABLE;
I915_STATE_WARN(cur_state != state, I915_STATE_WARN(cur_state != state,
"PLL state assertion failure (expected %s, current %s)\n", "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) void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe)

View File

@@ -21,6 +21,8 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include <linux/string_helpers.h>
#include "intel_de.h" #include "intel_de.h"
#include "intel_display_types.h" #include "intel_display_types.h"
#include "intel_dpio_phy.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; struct intel_dpll_hw_state hw_state;
if (drm_WARN(&dev_priv->drm, !pll, 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; return;
cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state); cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state);
I915_STATE_WARN(cur_state != state, I915_STATE_WARN(cur_state != state,
"%s assertion failure (expected %s, current %s)\n", "%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) 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; u64 freq2k;
unsigned p, n2, r2; unsigned p, n2, r2;
struct hsw_wrpll_rnp best = { 0, 0, 0 }; struct hsw_wrpll_rnp best = {};
unsigned budget; unsigned budget;
freq2k = clock / 100; freq2k = clock / 100;
@@ -1330,13 +1333,6 @@ struct skl_wrpll_context {
unsigned int p; /* chosen divider */ 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 */ /* DCO freq must be within +1%/-6% of the DCO central freq */
#define SKL_DCO_MAX_PDEVIATION 100 #define SKL_DCO_MAX_PDEVIATION 100
#define SKL_DCO_MAX_NDEVIATION 600 #define SKL_DCO_MAX_NDEVIATION 600
@@ -1502,28 +1498,28 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */,
int ref_clock, int ref_clock,
struct skl_wrpll_params *wrpll_params) struct skl_wrpll_params *wrpll_params)
{ {
u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ static const u64 dco_central_freq[3] = { 8400000000ULL,
u64 dco_central_freq[3] = { 8400000000ULL, 9000000000ULL,
9000000000ULL, 9600000000ULL };
9600000000ULL }; static const u8 even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20,
static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 30, 32, 36, 40, 42, 44,
24, 28, 30, 32, 36, 40, 42, 44, 48, 52, 54, 56, 60, 64, 66, 68,
48, 52, 54, 56, 60, 64, 66, 68, 70, 72, 76, 78, 80, 84, 88, 90,
70, 72, 76, 78, 80, 84, 88, 90, 92, 96, 98 };
92, 96, 98 }; static const u8 odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
static const struct { static const struct {
const int *list; const u8 *list;
int n_dividers; int n_dividers;
} dividers[] = { } dividers[] = {
{ even_dividers, ARRAY_SIZE(even_dividers) }, { even_dividers, ARRAY_SIZE(even_dividers) },
{ odd_dividers, ARRAY_SIZE(odd_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 dco, d, i;
unsigned int p0, p1, p2; unsigned int p0, p1, p2;
u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
skl_wrpll_context_init(&ctx);
for (d = 0; d < ARRAY_SIZE(dividers); d++) { for (d = 0; d < ARRAY_SIZE(dividers); d++) {
for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { 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) 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 drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct skl_wrpll_params wrpll_params = {};
u32 ctrl1, cfgcr1, cfgcr2; 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 * 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 */ /* Write M2 integer */
temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0)); 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; temp |= pll->state.hw_state.pll0;
intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 0), temp); 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->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
hw_state->pll0 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0)); 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 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 1));
hw_state->pll1 &= PORT_PLL_N_MASK; hw_state->pll1 &= PORT_PLL_N_MASK;
@@ -2087,82 +2083,64 @@ out:
return ret; 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 */ /* pre-calculated values for DP linkrates */
static const struct bxt_clk_div bxt_dp_clk_val[] = { static const struct dpll bxt_dp_clk_val[] = {
{162000, 4, 2, 32, 1677722, 1, 1}, /* m2 is .22 binary fixed point */
{270000, 4, 1, 27, 0, 0, 1}, { .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{540000, 2, 1, 27, 0, 0, 1}, { .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
{216000, 3, 2, 32, 1677722, 1, 1}, { .dot = 540000, .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
{243000, 4, 1, 24, 1258291, 1, 1}, { .dot = 216000, .p1 = 3, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
{324000, 4, 1, 32, 1677722, 1, 1}, { .dot = 243000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6133333 /* 24.3 */ },
{432000, 3, 1, 32, 1677722, 1, 1} { .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 static bool
bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state, 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 drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct dpll best_clock;
/* Calculate HDMI div */ /* Calculate HDMI div */
/* /*
* FIXME: tie the following calculation into * FIXME: tie the following calculation into
* i9xx_crtc_compute_clock * 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", drm_dbg(&i915->drm, "no PLL dividers found for clock %d pipe %c\n",
crtc_state->port_clock, crtc_state->port_clock,
pipe_name(crtc->pipe)); pipe_name(crtc->pipe));
return false; return false;
} }
clk_div->p1 = best_clock.p1; drm_WARN_ON(&i915->drm, clk_div->m1 != 2);
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;
return true; return true;
} }
static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state, 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; int i;
*clk_div = bxt_dp_clk_val[0]; *clk_div = bxt_dp_clk_val[0];
for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) { 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]; *clk_div = bxt_dp_clk_val[i];
break; 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, 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 drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_dpll_hw_state *dpll_hw_state = &crtc_state->dpll_hw_state; 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; lanestagger = 0x02;
dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2); 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->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->pll3 = PORT_PLL_M2_FRAC_ENABLE;
dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef); dpll_hw_state->pll6 = PORT_PLL_PROP_COEFF(prop_coef) |
dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl); 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 = dpll_hw_state->pll10 = PORT_PLL_DCO_AMP(15) |
PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT) PORT_PLL_DCO_AMP_OVR_EN_H;
| PORT_PLL_DCO_AMP_OVR_EN_H;
dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE; 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 static bool
bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state) 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); 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 static bool
bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state) 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); 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; struct dpll clock;
clock.m1 = 2; 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) if (pll_state->pll3 & PORT_PLL_M2_FRAC_ENABLE)
clock.m2 |= pll_state->pll2 & PORT_PLL_M2_FRAC_MASK; clock.m2 |= REG_FIELD_GET(PORT_PLL_M2_FRAC_MASK, pll_state->pll2);
clock.n = (pll_state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT; clock.n = REG_FIELD_GET(PORT_PLL_N_MASK, pll_state->pll1);
clock.p1 = (pll_state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT; clock.p1 = REG_FIELD_GET(PORT_PLL_P1_MASK, pll_state->ebb0);
clock.p2 = (pll_state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT; clock.p2 = REG_FIELD_GET(PORT_PLL_P2_MASK, pll_state->ebb0);
return chv_calc_dpll_params(i915->dpll.ref_clks.nssc, &clock); 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, struct intel_dpll_hw_state *state,
bool is_dkl) bool is_dkl)
{ {
static const u8 div1_vals[] = { 7, 5, 3, 2 };
u32 dco_min_freq, dco_max_freq; u32 dco_min_freq, dco_max_freq;
int div1_vals[] = {7, 5, 3, 2};
unsigned int i; unsigned int i;
int div2; 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); size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE);
if (HAS_LMEM(i915)) 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 else
dpt_obj = i915_gem_object_create_stolen(i915, size); dpt_obj = i915_gem_object_create_stolen(i915, size);
if (IS_ERR(dpt_obj)) if (IS_ERR(dpt_obj))

View File

@@ -47,74 +47,36 @@
* requested by userspace. * requested by userspace.
*/ */
static bool can_enable_drrs(struct intel_connector *connector, const char *intel_drrs_type_str(enum drrs_type drrs_type)
const struct intel_crtc_state *pipe_config)
{ {
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) if (drrs_type >= ARRAY_SIZE(str))
return false; return "<invalid>";
/* return str[drrs_type];
* 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;
} }
static void static void
intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state, intel_drrs_set_refresh_rate_pipeconf(struct intel_crtc *crtc,
enum drrs_refresh_rate_type refresh_type) 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); 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; u32 val, bit;
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
bit = PIPECONF_EDP_RR_MODE_SWITCH_VLV; bit = PIPECONF_REFRESH_RATE_ALT_VLV;
else else
bit = PIPECONF_EDP_RR_MODE_SWITCH; bit = PIPECONF_REFRESH_RATE_ALT_ILK;
val = intel_de_read(dev_priv, PIPECONF(cpu_transcoder)); val = intel_de_read(dev_priv, PIPECONF(cpu_transcoder));
if (refresh_type == DRRS_LOW_RR) if (refresh_rate == DRRS_REFRESH_RATE_LOW)
val |= bit; val |= bit;
else else
val &= ~bit; val &= ~bit;
@@ -123,244 +85,171 @@ intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state,
} }
static void static void
intel_drrs_set_refresh_rate_m_n(const struct intel_crtc_state *crtc_state, intel_drrs_set_refresh_rate_m_n(struct intel_crtc *crtc,
enum drrs_refresh_rate_type refresh_type) 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->drrs.cpu_transcoder,
refresh_rate == DRRS_REFRESH_RATE_LOW ?
intel_cpu_transcoder_set_m1_n1(crtc, crtc_state->cpu_transcoder, &crtc->drrs.m2_n2 : &crtc->drrs.m_n);
refresh_type == DRRS_LOW_RR ?
&crtc_state->dp_m2_n2 : &crtc_state->dp_m_n);
} }
static void intel_drrs_set_state(struct drm_i915_private *dev_priv, bool intel_drrs_is_active(struct intel_crtc *crtc)
const struct intel_crtc_state *crtc_state,
enum drrs_refresh_rate_type refresh_type)
{ {
struct intel_dp *intel_dp = dev_priv->drrs.dp; return crtc->drrs.cpu_transcoder != INVALID_TRANSCODER;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); }
struct drm_display_mode *mode;
if (!intel_dp) { static void intel_drrs_set_state(struct intel_crtc *crtc,
drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n"); enum drrs_refresh_rate refresh_rate)
return; {
} struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
if (!crtc) { if (refresh_rate == crtc->drrs.refresh_rate)
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)
return; return;
if (!crtc_state->hw.active) { if (intel_cpu_transcoder_has_m2_n2(dev_priv, crtc->drrs.cpu_transcoder))
drm_dbg_kms(&dev_priv->drm, intel_drrs_set_refresh_rate_pipeconf(crtc, refresh_rate);
"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;
else else
mode = intel_dp->attached_connector->panel.fixed_mode; intel_drrs_set_refresh_rate_m_n(crtc, refresh_rate);
drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n",
drm_mode_vrefresh(mode)); crtc->drrs.refresh_rate = refresh_rate;
} }
static void static void intel_drrs_schedule_work(struct intel_crtc *crtc)
intel_drrs_enable_locked(struct intel_dp *intel_dp)
{ {
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; static unsigned int intel_drrs_frontbuffer_bits(const struct intel_crtc_state *crtc_state)
dev_priv->drrs.dp = intel_dp; {
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_drrs_activate - activate DRRS
* @intel_dp: DP struct * @crtc_state: the crtc state
* @crtc_state: A pointer to the active crtc state.
* *
* Initializes frontbuffer_bits and drrs.dp * Activates DRRS on the crtc.
*/ */
void intel_drrs_enable(struct intel_dp *intel_dp, void intel_drrs_activate(const struct intel_crtc_state *crtc_state)
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) if (!crtc_state->has_drrs)
return; 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) { mutex_lock(&crtc->drrs.mutex);
drm_warn(&dev_priv->drm, "DRRS already enabled\n");
goto unlock;
}
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: intel_drrs_schedule_work(crtc);
mutex_unlock(&dev_priv->drrs.mutex);
}
static void mutex_unlock(&crtc->drrs.mutex);
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;
} }
/** /**
* intel_drrs_disable - Disable DRRS * intel_drrs_deactivate - deactivate DRRS
* @intel_dp: DP struct * @old_crtc_state: the old crtc state
* @old_crtc_state: Pointer to old crtc_state.
* *
* Deactivates DRRS on the crtc.
*/ */
void intel_drrs_disable(struct intel_dp *intel_dp, void intel_drrs_deactivate(const struct intel_crtc_state *old_crtc_state)
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) if (!old_crtc_state->has_drrs)
return; return;
mutex_lock(&dev_priv->drrs.mutex); if (!old_crtc_state->hw.active)
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)
return; return;
mutex_lock(&dev_priv->drrs.mutex); if (intel_crtc_is_bigjoiner_slave(old_crtc_state))
return;
/* New state matches current one? */ mutex_lock(&crtc->drrs.mutex);
if (crtc_state->has_drrs == !!dev_priv->drrs.dp)
goto unlock;
if (crtc_state->has_drrs) if (intel_drrs_is_active(crtc))
intel_drrs_enable_locked(intel_dp); intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH);
else
intel_drrs_disable_locked(intel_dp, crtc_state);
unlock: crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
mutex_unlock(&dev_priv->drrs.mutex); 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) static void intel_drrs_downclock_work(struct work_struct *work)
{ {
struct drm_i915_private *dev_priv = struct intel_crtc *crtc = container_of(work, typeof(*crtc), drrs.work.work);
container_of(work, typeof(*dev_priv), drrs.work.work);
struct intel_dp *intel_dp;
struct drm_crtc *crtc;
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) mutex_unlock(&crtc->drrs.mutex);
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);
} }
static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv, static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits, unsigned int all_frontbuffer_bits,
bool invalidate) bool invalidate)
{ {
struct intel_dp *intel_dp; struct intel_crtc *crtc;
struct drm_crtc *crtc;
enum pipe pipe;
if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) if (dev_priv->vbt.drrs_type != DRRS_TYPE_SEAMLESS)
return; 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; frontbuffer_bits = all_frontbuffer_bits & crtc->drrs.frontbuffer_bits;
if (!intel_dp) { if (!frontbuffer_bits) {
mutex_unlock(&dev_priv->drrs.mutex); mutex_unlock(&crtc->drrs.mutex);
return; 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); 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. * intel_crtc_drrs_init - Init DRRS for CRTC
* @connector: eDP connector * @crtc: crtc
* @fixed_mode: preferred mode of panel
* *
* 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. * 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 * void intel_crtc_drrs_init(struct intel_crtc *crtc)
intel_drrs_init(struct intel_connector *connector,
struct drm_display_mode *fixed_mode)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work);
struct intel_encoder *encoder = connector->encoder; mutex_init(&crtc->drrs.mutex);
struct drm_display_mode *downclock_mode = NULL; crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
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;
} }

View File

@@ -8,29 +8,21 @@
#include <linux/types.h> #include <linux/types.h>
enum drrs_type;
struct drm_i915_private; struct drm_i915_private;
struct intel_atomic_state; struct intel_atomic_state;
struct intel_crtc; struct intel_crtc;
struct intel_crtc_state; struct intel_crtc_state;
struct intel_connector; struct intel_connector;
struct intel_dp;
void intel_drrs_enable(struct intel_dp *intel_dp, const char *intel_drrs_type_str(enum drrs_type drrs_type);
const struct intel_crtc_state *crtc_state); bool intel_drrs_is_active(struct intel_crtc *crtc);
void intel_drrs_disable(struct intel_dp *intel_dp, void intel_drrs_activate(const struct intel_crtc_state *crtc_state);
const struct intel_crtc_state *crtc_state); void intel_drrs_deactivate(const struct intel_crtc_state *crtc_state);
void intel_drrs_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_drrs_invalidate(struct drm_i915_private *dev_priv, void intel_drrs_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits); unsigned int frontbuffer_bits);
void intel_drrs_flush(struct drm_i915_private *dev_priv, void intel_drrs_flush(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits); unsigned int frontbuffer_bits);
void intel_drrs_page_flip(struct intel_atomic_state *state, void intel_crtc_drrs_init(struct intel_crtc *crtc);
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);
#endif /* __INTEL_DRRS_H__ */ #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); obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE);
if (IS_ERR(obj)) { if (IS_ERR(obj)) {
drm_err(&i915->drm, "Gem object creation failed\n");
kfree(dsb); kfree(dsb);
goto out; goto out;
} }
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
if (IS_ERR(vma)) { if (IS_ERR(vma)) {
drm_err(&i915->drm, "Vma creation failed\n");
i915_gem_object_put(obj); i915_gem_object_put(obj);
kfree(dsb); kfree(dsb);
goto out; 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); buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC);
if (IS_ERR(buf)) { if (IS_ERR(buf)) {
drm_err(&i915->drm, "Command buffer creation failed\n");
i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP); i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
kfree(dsb); kfree(dsb);
goto out; goto out;
@@ -311,6 +308,10 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
dsb->ins_start_offset = 0; dsb->ins_start_offset = 0;
crtc_state->dsb = dsb; crtc_state->dsb = dsb;
out: 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); 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) int intel_dsi_get_modes(struct drm_connector *connector)
{ {
struct drm_i915_private *i915 = to_i915(connector->dev); return intel_panel_get_modes(to_intel_connector(connector));
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;
} }
enum drm_mode_status intel_dsi_mode_valid(struct drm_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 drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_connector *intel_connector = to_intel_connector(connector); 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; int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
enum drm_mode_status status; enum drm_mode_status status;

View File

@@ -30,6 +30,7 @@
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h> #include <linux/pinctrl/machine.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string_helpers.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
@@ -686,9 +687,9 @@ void intel_dsi_log_params(struct intel_dsi *intel_dsi)
intel_dsi->burst_mode_ratio); intel_dsi->burst_mode_ratio);
drm_dbg_kms(&i915->drm, "Reset timer %d\n", intel_dsi->rst_timer_val); drm_dbg_kms(&i915->drm, "Reset timer %d\n", intel_dsi->rst_timer_val);
drm_dbg_kms(&i915->drm, "Eot %s\n", 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", 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", drm_dbg_kms(&i915->drm, "Mode %s\n",
intel_dsi->operation_mode ? "command" : "video"); intel_dsi->operation_mode ? "command" : "video");
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) 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", drm_dbg_kms(&i915->drm, "HS to LP Clock Count 0x%x\n",
intel_dsi->clk_hs_to_lp_count); intel_dsi->clk_hs_to_lp_count);
drm_dbg_kms(&i915->drm, "BTA %s\n", 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) 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_connector *intel_connector = to_intel_connector(connector);
struct intel_dvo *intel_dvo = intel_attached_dvo(intel_connector); struct intel_dvo *intel_dvo = intel_attached_dvo(intel_connector);
const struct drm_display_mode *fixed_mode = 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 max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
int target_clock = mode->clock; 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_dvo *intel_dvo = enc_to_dvo(encoder);
struct intel_connector *connector = to_intel_connector(conn_state->connector); 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; 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 * 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) static int intel_dvo_get_modes(struct drm_connector *connector)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->dev); 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; int num_modes;
/* /*
@@ -348,17 +346,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
if (num_modes) if (num_modes)
return num_modes; return num_modes;
if (fixed_mode) { return intel_panel_get_modes(to_intel_connector(connector));
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;
} }
static const struct drm_connector_funcs intel_dvo_connector_funcs = { 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, .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) static enum port intel_dvo_port(i915_reg_t dvo_reg)
{ {
if (i915_mmio_reg_equal(dvo_reg, DVOA)) 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 * headers, likely), so for now, just get the current
* mode being output through DVO. * mode being output through DVO.
*/ */
intel_panel_init(&intel_connector->panel, intel_panel_add_encoder_fixed_mode(intel_connector,
intel_dvo_get_current_mode(intel_encoder), intel_encoder);
NULL);
intel_panel_init(intel_connector);
intel_dvo->panel_wants_dither = true; 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 }, .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 { struct intel_modifier_desc {
u64 modifier; u64 modifier;
struct { struct {
@@ -135,11 +150,32 @@ struct intel_modifier_desc {
INTEL_PLANE_CAP_CCS_MC) INTEL_PLANE_CAP_CCS_MC)
#define INTEL_PLANE_CAP_TILING_MASK (INTEL_PLANE_CAP_TILING_X | \ #define INTEL_PLANE_CAP_TILING_MASK (INTEL_PLANE_CAP_TILING_X | \
INTEL_PLANE_CAP_TILING_Y | \ 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 #define INTEL_PLANE_CAP_TILING_NONE 0
static const struct intel_modifier_desc intel_modifiers[] = { 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, .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
.display_ver = { 12, 13 }, .display_ver = { 12, 13 },
.plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_MC, .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, static bool format_is_yuv_semiplanar(const struct intel_modifier_desc *md,
const struct drm_format_info *info) const struct drm_format_info *info)
{ {
int yuv_planes;
if (!info->is_yuv) if (!info->is_yuv)
return false; return false;
if (plane_caps_contain_any(md->plane_caps, INTEL_PLANE_CAP_CCS_MASK)) if (hweight8(md->ccs.planar_aux_planes) == 2)
yuv_planes = 4; return info->num_planes == 4;
else else
yuv_planes = 2; return info->num_planes == 2;
return info->num_planes == yuv_planes;
} }
/** /**
@@ -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) 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); 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); return main_to_ccs_plane(fb, main_plane);
else if (DISPLAY_VER(i915) < 11 && 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; return 1;
else else
return 0; return 0;
@@ -545,6 +578,15 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
return 128; return 128;
else else
return 512; 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: case I915_FORMAT_MOD_Y_TILED_CCS:
if (intel_fb_is_ccs_aux_plane(fb, color_plane)) if (intel_fb_is_ccs_aux_plane(fb, color_plane))
return 128; return 128;
@@ -650,6 +692,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
return I915_TILING_Y; return I915_TILING_Y;
case INTEL_PLANE_CAP_TILING_X: case INTEL_PLANE_CAP_TILING_X:
return I915_TILING_X; return I915_TILING_X;
case INTEL_PLANE_CAP_TILING_4:
case INTEL_PLANE_CAP_TILING_Yf: case INTEL_PLANE_CAP_TILING_Yf:
case INTEL_PLANE_CAP_TILING_NONE: case INTEL_PLANE_CAP_TILING_NONE:
return I915_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_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS: case I915_FORMAT_MOD_Yf_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
case I915_FORMAT_MOD_Yf_TILED: case I915_FORMAT_MOD_Yf_TILED:
return 1 * 1024 * 1024; 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: default:
MISSING_CASE(fb->modifier); MISSING_CASE(fb->modifier);
return 0; 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_X BIT(3)
#define INTEL_PLANE_CAP_TILING_Y BIT(4) #define INTEL_PLANE_CAP_TILING_Y BIT(4)
#define INTEL_PLANE_CAP_TILING_Yf BIT(5) #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_ccs_modifier(u64 modifier);
bool intel_fb_is_rc_ccs_cc_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. * forcibly disable it to allow proper screen updates.
*/ */
#include <linux/string_helpers.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_utils.h"
#include "i915_vgpu.h" #include "i915_vgpu.h"
#include "intel_cdclk.h" #include "intel_cdclk.h"
#include "intel_de.h" #include "intel_de.h"
@@ -87,7 +90,6 @@ struct intel_fbc {
* with stolen_lock. * with stolen_lock.
*/ */
struct mutex lock; struct mutex lock;
unsigned int possible_framebuffer_bits;
unsigned int busy_bits; unsigned int busy_bits;
struct drm_mm_node compressed_fb; 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) 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); trace_intel_fbc_nuke(fbc->state.plane);
fbc->funcs->nuke(fbc); 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_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED: case I915_FORMAT_MOD_Yf_TILED:
return DISPLAY_VER(i915) >= 9; return DISPLAY_VER(i915) >= 9;
case I915_FORMAT_MOD_4_TILED:
case I915_FORMAT_MOD_X_TILED: case I915_FORMAT_MOD_X_TILED:
return true; return true;
default: default:
@@ -966,6 +973,7 @@ static void intel_fbc_update_state(struct intel_atomic_state *state,
struct intel_fbc_state *fbc_state = &fbc->state; struct intel_fbc_state *fbc_state = &fbc->state;
WARN_ON(plane_state->no_fbc_reason); WARN_ON(plane_state->no_fbc_reason);
WARN_ON(fbc_state->plane && fbc_state->plane != 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); __intel_fbc_cleanup_cfb(fbc);
fbc->state.plane = NULL; fbc->state.plane = NULL;
fbc->flip_pending = false;
fbc->busy_bits = 0;
} }
static void __intel_fbc_post_update(struct intel_fbc *fbc) 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) if (fbc->state.plane)
return fbc->state.plane->frontbuffer_bit; return fbc->state.plane->frontbuffer_bit;
else else
return fbc->possible_framebuffer_bits; return 0;
} }
static void __intel_fbc_invalidate(struct intel_fbc *fbc, 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); 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) fbc->busy_bits |= frontbuffer_bits;
intel_fbc_deactivate(fbc, "frontbuffer write"); intel_fbc_deactivate(fbc, "frontbuffer write");
out:
mutex_unlock(&fbc->lock); mutex_unlock(&fbc->lock);
} }
@@ -1351,18 +1364,22 @@ static void __intel_fbc_flush(struct intel_fbc *fbc,
{ {
mutex_lock(&fbc->lock); mutex_lock(&fbc->lock);
frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc);
if (!frontbuffer_bits)
goto out;
fbc->busy_bits &= ~frontbuffer_bits; fbc->busy_bits &= ~frontbuffer_bits;
if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE) if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE)
goto out; goto out;
if (!fbc->busy_bits && fbc->state.plane && if (fbc->busy_bits || fbc->flip_pending)
(frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) { goto out;
if (fbc->active)
intel_fbc_nuke(fbc); if (fbc->active)
else if (!fbc->flip_pending) intel_fbc_nuke(fbc);
__intel_fbc_post_update(fbc); else
} intel_fbc_activate(fbc);
out: out:
mutex_unlock(&fbc->lock); 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) static void intel_fbc_underrun_work_fn(struct work_struct *work)
{ {
struct intel_fbc *fbc = container_of(work, typeof(*fbc), underrun_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) static bool need_fbc_vtd_wa(struct drm_i915_private *i915)
{ {
/* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */ /* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */
if (intel_vtd_active(i915) && if (i915_vtd_active(i915) &&
(IS_SKYLAKE(i915) || IS_BROXTON(i915))) { (IS_SKYLAKE(i915) || IS_BROXTON(i915))) {
drm_info(&i915->drm, drm_info(&i915->drm,
"Disabling framebuffer compression (FBC) to prevent screen flicker with VT-d enabled\n"); "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) void intel_fbc_add_plane(struct intel_fbc *fbc, struct intel_plane *plane)
{ {
if (!fbc)
return;
plane->fbc = fbc; plane->fbc = fbc;
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
} }
static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915, 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", drm_dbg_kms(&i915->drm, "Sanitized enable_fbc value: %d\n",
i915->params.enable_fbc); i915->params.enable_fbc);
for_each_fbc_id(i915, fbc_id) { for_each_fbc_id(i915, fbc_id)
struct intel_fbc *fbc; i915->fbc[fbc_id] = intel_fbc_create(i915, fbc_id);
}
fbc = intel_fbc_create(i915, fbc_id); /**
if (!fbc) * intel_fbc_sanitize - Sanitize FBC
continue; * @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;
/* for_each_intel_fbc(i915, fbc, 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.
*/
if (intel_fbc_hw_is_active(fbc)) if (intel_fbc_hw_is_active(fbc))
intel_fbc_hw_deactivate(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) { if (fbc->active) {
seq_puts(m, "FBC enabled\n"); seq_puts(m, "FBC enabled\n");
seq_printf(m, "Compressing: %s\n", seq_printf(m, "Compressing: %s\n",
yesno(intel_fbc_is_compressing(fbc))); str_yes_no(intel_fbc_is_compressing(fbc)));
} else { } else {
seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason); 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); struct intel_crtc *crtc);
void intel_fbc_init(struct drm_i915_private *dev_priv); void intel_fbc_init(struct drm_i915_private *dev_priv);
void intel_fbc_cleanup(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, void intel_fbc_update(struct intel_atomic_state *state,
struct intel_crtc *crtc); struct intel_crtc *crtc);
void intel_fbc_disable(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, void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits, unsigned int frontbuffer_bits,
enum fb_op_origin origin); enum fb_op_origin origin);

View File

@@ -3,6 +3,8 @@
* Copyright © 2020 Intel Corporation * Copyright © 2020 Intel Corporation
*/ */
#include <linux/string_helpers.h>
#include "intel_atomic.h" #include "intel_atomic.h"
#include "intel_crtc.h" #include "intel_crtc.h"
#include "intel_ddi.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, I915_STATE_WARN(cur_state != state,
"FDI TX state assertion failure (expected %s, current %s)\n", "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) 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; cur_state = intel_de_read(dev_priv, FDI_RX_CTL(pipe)) & FDI_RX_ENABLE;
I915_STATE_WARN(cur_state != state, I915_STATE_WARN(cur_state != state,
"FDI RX state assertion failure (expected %s, current %s)\n", "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) 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; cur_state = intel_de_read(i915, FDI_RX_CTL(pipe)) & FDI_RX_PLL_ENABLE;
I915_STATE_WARN(cur_state != state, I915_STATE_WARN(cur_state != state,
"FDI RX PLL assertion failure (expected %s, current %s)\n", "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) 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_display_types.h"
#include "intel_gmbus.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 { struct gmbus_pin {
const char *name; const char *name;
enum i915_gpio gpio; enum i915_gpio gpio;
@@ -106,51 +116,47 @@ static const struct gmbus_pin gmbus_pins_dg2[] = {
[GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ }, [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 *i915,
static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
unsigned int pin) unsigned int pin)
{ {
if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG2) const struct gmbus_pin *pins;
return &gmbus_pins_dg2[pin]; size_t size;
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
return &gmbus_pins_dg1[pin]; if (INTEL_PCH_TYPE(i915) >= PCH_DG2) {
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) pins = gmbus_pins_dg2;
return &gmbus_pins_icp[pin]; size = ARRAY_SIZE(gmbus_pins_dg2);
else if (HAS_PCH_CNP(dev_priv)) } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) {
return &gmbus_pins_cnp[pin]; pins = gmbus_pins_dg1;
else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) size = ARRAY_SIZE(gmbus_pins_dg1);
return &gmbus_pins_bxt[pin]; } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) {
else if (DISPLAY_VER(dev_priv) == 9) pins = gmbus_pins_icp;
return &gmbus_pins_skl[pin]; size = ARRAY_SIZE(gmbus_pins_icp);
else if (IS_BROADWELL(dev_priv)) } else if (HAS_PCH_CNP(i915)) {
return &gmbus_pins_bdw[pin]; pins = gmbus_pins_cnp;
else size = ARRAY_SIZE(gmbus_pins_cnp);
return &gmbus_pins[pin]; } 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, bool intel_gmbus_is_valid_pin(struct drm_i915_private *i915, unsigned int pin)
unsigned int pin)
{ {
unsigned int size; return get_gmbus_pin(i915, pin);
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;
} }
/* Intel GPIO access functions */ /* Intel GPIO access functions */
@@ -294,9 +300,7 @@ static void set_data(void *data, int state_high)
static int static int
intel_gpio_pre_xfer(struct i2c_adapter *adapter) intel_gpio_pre_xfer(struct i2c_adapter *adapter)
{ {
struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = bus->dev_priv; struct drm_i915_private *dev_priv = bus->dev_priv;
intel_gmbus_reset(dev_priv); intel_gmbus_reset(dev_priv);
@@ -313,9 +317,7 @@ intel_gpio_pre_xfer(struct i2c_adapter *adapter)
static void static void
intel_gpio_post_xfer(struct i2c_adapter *adapter) intel_gpio_post_xfer(struct i2c_adapter *adapter)
{ {
struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = bus->dev_priv; struct drm_i915_private *dev_priv = bus->dev_priv;
set_data(bus, 1); set_data(bus, 1);
@@ -326,14 +328,13 @@ intel_gpio_post_xfer(struct i2c_adapter *adapter)
} }
static void 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; struct i2c_algo_bit_data *algo;
algo = &bus->bit_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; bus->adapter.algo_data = algo;
algo->setsda = set_data; algo->setsda = set_data;
algo->setscl = set_clock; algo->setscl = set_clock;
@@ -614,9 +615,7 @@ static int
do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
u32 gmbus0_source) u32 gmbus0_source)
{ {
struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = bus->dev_priv; struct drm_i915_private *dev_priv = bus->dev_priv;
int i = 0, inc, try = 0; int i = 0, inc, try = 0;
int ret = 0; int ret = 0;
@@ -746,8 +745,7 @@ out:
static int static int
gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{ {
struct intel_gmbus *bus = struct intel_gmbus *bus = to_intel_gmbus(adapter);
container_of(adapter, struct intel_gmbus, adapter);
struct drm_i915_private *dev_priv = bus->dev_priv; struct drm_i915_private *dev_priv = bus->dev_priv;
intel_wakeref_t wakeref; intel_wakeref_t wakeref;
int ret; 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) int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
{ {
struct intel_gmbus *bus = struct intel_gmbus *bus = to_intel_gmbus(adapter);
container_of(adapter, struct intel_gmbus, adapter);
struct drm_i915_private *dev_priv = bus->dev_priv; struct drm_i915_private *dev_priv = bus->dev_priv;
u8 cmd = DRM_HDCP_DDC_AKSV; u8 cmd = DRM_HDCP_DDC_AKSV;
u8 buf[DRM_HDCP_KSV_LEN] = { 0 }; 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) int intel_gmbus_setup(struct drm_i915_private *dev_priv)
{ {
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
struct intel_gmbus *bus;
unsigned int pin; unsigned int pin;
int ret; int ret;
@@ -880,17 +876,24 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
init_waitqueue_head(&dev_priv->gmbus_wait_queue); init_waitqueue_head(&dev_priv->gmbus_wait_queue);
for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) { 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; 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.owner = THIS_MODULE;
bus->adapter.class = I2C_CLASS_DDC; bus->adapter.class = I2C_CLASS_DDC;
snprintf(bus->adapter.name, snprintf(bus->adapter.name,
sizeof(bus->adapter.name), sizeof(bus->adapter.name),
"i915 gmbus %s", "i915 gmbus %s", gmbus_pin->name);
get_gmbus_pin(dev_priv, pin)->name);
bus->adapter.dev.parent = &pdev->dev; bus->adapter.dev.parent = &pdev->dev;
bus->dev_priv = dev_priv; bus->dev_priv = dev_priv;
@@ -911,11 +914,15 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
if (IS_I830(dev_priv)) if (IS_I830(dev_priv))
bus->force_bit = 1; bus->force_bit = 1;
intel_gpio_setup(bus, pin); intel_gpio_setup(bus, GPIO(gmbus_pin->gpio));
ret = i2c_add_adapter(&bus->adapter); ret = i2c_add_adapter(&bus->adapter);
if (ret) if (ret) {
kfree(bus);
goto err; goto err;
}
dev_priv->gmbus[pin] = bus;
} }
intel_gmbus_reset(dev_priv); intel_gmbus_reset(dev_priv);
@@ -923,24 +930,19 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
return 0; return 0;
err: err:
while (pin--) { intel_gmbus_teardown(dev_priv);
if (!intel_gmbus_is_valid_pin(dev_priv, pin))
continue;
bus = &dev_priv->gmbus[pin];
i2c_del_adapter(&bus->adapter);
}
return ret; return ret;
} }
struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
unsigned int pin) unsigned int pin)
{ {
if (drm_WARN_ON(&dev_priv->drm, if (drm_WARN_ON(&dev_priv->drm, pin >= ARRAY_SIZE(dev_priv->gmbus) ||
!intel_gmbus_is_valid_pin(dev_priv, pin))) !dev_priv->gmbus[pin]))
return NULL; 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) 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) void intel_gmbus_teardown(struct drm_i915_private *dev_priv)
{ {
struct intel_gmbus *bus;
unsigned int pin; unsigned int pin;
for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); 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; continue;
bus = &dev_priv->gmbus[pin];
i2c_del_adapter(&bus->adapter); i2c_del_adapter(&bus->adapter);
kfree(bus);
dev_priv->gmbus[pin] = NULL;
} }
} }

View File

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

View File

@@ -30,6 +30,7 @@
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string_helpers.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.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, drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n", "[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n",
connector->base.id, connector->name, 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 */ /* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */
return drm_scdc_set_high_tmds_clock_ratio(adapter, 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 drm_display_mode *mode)
{ {
struct intel_connector *intel_connector = to_intel_connector(connector); 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; int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
enum drm_mode_status status; 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) static int intel_lvds_get_modes(struct drm_connector *connector)
{ {
struct intel_connector *intel_connector = to_intel_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 */ /* use cached edid if we have one */
if (!IS_ERR_OR_NULL(intel_connector->edid)) if (!IS_ERR_OR_NULL(intel_connector->edid))
return drm_add_edid_modes(connector, intel_connector->edid); return drm_add_edid_modes(connector, intel_connector->edid);
mode = drm_mode_duplicate(dev, intel_connector->panel.fixed_mode); return intel_panel_get_modes(intel_connector);
if (mode == NULL)
return 0;
drm_mode_probed_add(connector, mode);
return 1;
} }
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { 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) 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; unsigned int val;
struct drm_i915_private *dev_priv = to_i915(dev);
/* use the module option value if specified */ /* use the module option value if specified */
if (dev_priv->params.lvds_channel_mode > 0) if (dev_priv->params.lvds_channel_mode > 0)
return dev_priv->params.lvds_channel_mode == 2; return dev_priv->params.lvds_channel_mode == 2;
/* single channel LVDS is limited to 112 MHz */ /* 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; return true;
if (dmi_check_system(intel_dual_link_lvds)) 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 intel_connector *intel_connector;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_display_mode *fixed_mode = NULL;
struct drm_display_mode *downclock_mode = NULL;
struct edid *edid; struct edid *edid;
i915_reg_t lvds_reg; i915_reg_t lvds_reg;
u32 lvds; u32 lvds;
@@ -973,35 +967,30 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
} }
intel_connector->edid = edid; intel_connector->edid = edid;
fixed_mode = intel_panel_edid_fixed_mode(intel_connector); /* Try EDID first */
if (fixed_mode) intel_panel_add_edid_fixed_modes(intel_connector,
goto out; dev_priv->vbt.drrs_type != DRRS_TYPE_NONE);
/* Failed to get EDID, what about VBT? */ /* Failed to get EDID, what about VBT? */
fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); if (!intel_panel_preferred_fixed_mode(intel_connector))
if (fixed_mode) intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
goto out;
/* /*
* If we didn't get EDID, try checking if the panel is already turned * If we didn't get a fixed mode from EDID or VBT, try checking
* on. If so, assume that whatever is currently programmed is the * if the panel is already turned on. If so, assume that
* correct mode. * whatever is currently programmed is the correct mode.
*/ */
fixed_mode = intel_encoder_current_mode(intel_encoder); if (!intel_panel_preferred_fixed_mode(intel_connector))
if (fixed_mode) { intel_panel_add_encoder_fixed_mode(intel_connector, intel_encoder);
drm_dbg_kms(&dev_priv->drm, "using current (BIOS) mode: ");
drm_mode_debug_printmodeline(fixed_mode);
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
}
/* 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); 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); intel_backlight_setup(intel_connector, INVALID_PIPE);
lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
@@ -1013,8 +1002,6 @@ out:
return; return;
failed: failed:
mutex_unlock(&dev->mode_config.mutex);
drm_dbg_kms(&dev_priv->drm, "No LVDS modes found, disabling.\n"); drm_dbg_kms(&dev_priv->drm, "No LVDS modes found, disabling.\n");
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder); 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, static int check_overlay_dst(struct intel_overlay *overlay,
struct drm_intel_overlay_put_image *rec) struct drm_intel_overlay_put_image *rec)
{ {
const struct intel_crtc_state *pipe_config = const struct intel_crtc_state *crtc_state =
overlay->crtc->config; 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; return -EINVAL;
if (rec->dst_x < pipe_config->pipe_src_w && return 0;
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;
} }
static int check_overlay_scaling(struct drm_intel_overlay_put_image *rec) 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; crtc->overlay = overlay;
/* line too wide, i.e. one-line-mode */ /* 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) { crtc->config->gmch_pfit.control & PFIT_ENABLE) {
overlay->pfit_active = true; overlay->pfit_active = true;
update_pfit_vscale_ratio(overlay); update_pfit_vscale_ratio(overlay);

View File

@@ -35,6 +35,7 @@
#include "intel_connector.h" #include "intel_connector.h"
#include "intel_de.h" #include "intel_de.h"
#include "intel_display_types.h" #include "intel_display_types.h"
#include "intel_drrs.h"
#include "intel_panel.h" #include "intel_panel.h"
bool intel_panel_use_ssc(struct drm_i915_private *i915) 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); && !(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, int intel_panel_compute_config(struct intel_connector *connector,
struct drm_display_mode *adjusted_mode) 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) if (!fixed_mode)
return 0; return 0;
@@ -75,128 +149,142 @@ int intel_panel_compute_config(struct intel_connector *connector,
return 0; return 0;
} }
static bool is_downclock_mode(const struct drm_display_mode *downclock_mode, static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
const struct drm_display_mode *fixed_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_TIMINGS |
DRM_MODE_MATCH_FLAGS | DRM_MODE_MATCH_FLAGS |
DRM_MODE_MATCH_3D_FLAGS) && DRM_MODE_MATCH_3D_FLAGS) &&
downclock_mode->clock < fixed_mode->clock; mode->clock != preferred_mode->clock;
} }
struct drm_display_mode * static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector)
intel_panel_edid_downclock_mode(struct intel_connector *connector,
const struct drm_display_mode *fixed_mode)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
const struct drm_display_mode *scan, *best_mode = NULL; const struct drm_display_mode *preferred_mode =
struct drm_display_mode *downclock_mode; intel_panel_preferred_fixed_mode(connector);
int best_clock = fixed_mode->clock; 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) { list_for_each_entry(scan, &connector->base.probed_modes, head) {
/* if (scan->type & DRM_MODE_TYPE_PREFERRED) {
* If one mode has the same resolution with the fixed_panel fixed_mode = scan;
* mode while they have the different refresh rate, it means break;
* 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 (!best_mode) if (!fixed_mode)
return NULL; fixed_mode = list_first_entry(&connector->base.probed_modes,
typeof(*fixed_mode), head);
downclock_mode = drm_mode_duplicate(&dev_priv->drm, best_mode);
if (!downclock_mode)
return NULL;
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] using downclock mode from EDID: ", "[CONNECTOR:%d:%s] using %s EDID fixed mode: " DRM_MODE_FMT "\n",
connector->base.base.id, connector->base.name); connector->base.base.id, connector->base.name,
drm_mode_debug_printmodeline(downclock_mode); 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 * static void intel_panel_destroy_probed_modes(struct intel_connector *connector)
intel_panel_edid_fixed_mode(struct intel_connector *connector)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct drm_i915_private *i915 = to_i915(connector->base.dev);
const struct drm_display_mode *scan; struct drm_display_mode *mode, *next;
struct drm_display_mode *fixed_mode;
if (list_empty(&connector->base.probed_modes)) list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
return NULL; list_del(&mode->head);
drm_mode_destroy(&i915->drm, mode);
/* 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;
} }
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 * void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs)
intel_panel_vbt_fixed_mode(struct intel_connector *connector)
{ {
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_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) if (!fixed_mode)
return NULL; return;
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; fixed_mode->type |= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
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);
info->width_mm = fixed_mode->width_mm; info->width_mm = fixed_mode->width_mm;
info->height_mm = fixed_mode->height_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 */ /* 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 = const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.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; int x, y, width, height;
/* Native modes don't need fitting */ /* Native modes don't need fitting */
if (adjusted_mode->crtc_hdisplay == crtc_state->pipe_src_w && if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
adjusted_mode->crtc_vdisplay == crtc_state->pipe_src_h && adjusted_mode->crtc_vdisplay == pipe_src_h &&
crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420) crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
return 0; return 0;
switch (conn_state->scaling_mode) { switch (conn_state->scaling_mode) {
case DRM_MODE_SCALE_CENTER: case DRM_MODE_SCALE_CENTER:
width = crtc_state->pipe_src_w; width = pipe_src_w;
height = crtc_state->pipe_src_h; height = pipe_src_h;
x = (adjusted_mode->crtc_hdisplay - width + 1)/2; x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
y = (adjusted_mode->crtc_vdisplay - height + 1)/2; y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
break; break;
@@ -224,19 +314,17 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
case DRM_MODE_SCALE_ASPECT: case DRM_MODE_SCALE_ASPECT:
/* Scale but preserve the aspect ratio */ /* Scale but preserve the aspect ratio */
{ {
u32 scaled_width = adjusted_mode->crtc_hdisplay u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
* crtc_state->pipe_src_h; u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
u32 scaled_height = crtc_state->pipe_src_w
* adjusted_mode->crtc_vdisplay;
if (scaled_width > scaled_height) { /* pillar */ if (scaled_width > scaled_height) { /* pillar */
width = scaled_height / crtc_state->pipe_src_h; width = scaled_height / pipe_src_h;
if (width & 1) if (width & 1)
width++; width++;
x = (adjusted_mode->crtc_hdisplay - width + 1) / 2; x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
y = 0; y = 0;
height = adjusted_mode->crtc_vdisplay; height = adjusted_mode->crtc_vdisplay;
} else if (scaled_width < scaled_height) { /* letter */ } else if (scaled_width < scaled_height) { /* letter */
height = scaled_width / crtc_state->pipe_src_w; height = scaled_width / pipe_src_w;
if (height & 1) if (height & 1)
height++; height++;
y = (adjusted_mode->crtc_vdisplay - height + 1) / 2; y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
@@ -251,8 +339,8 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
break; break;
case DRM_MODE_SCALE_NONE: case DRM_MODE_SCALE_NONE:
WARN_ON(adjusted_mode->crtc_hdisplay != crtc_state->pipe_src_w); WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
WARN_ON(adjusted_mode->crtc_vdisplay != crtc_state->pipe_src_h); WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
fallthrough; fallthrough;
case DRM_MODE_SCALE_FULLSCREEN: case DRM_MODE_SCALE_FULLSCREEN:
x = y = 0; 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 = const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode; &crtc_state->hw.adjusted_mode;
u32 scaled_width = adjusted_mode->crtc_hdisplay * int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
crtc_state->pipe_src_h; int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
u32 scaled_height = crtc_state->pipe_src_w * u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
adjusted_mode->crtc_vdisplay; u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
/* 965+ is easy, it does everything in hw */ /* 965+ is easy, it does everything in hw */
if (scaled_width > scaled_height) 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) else if (scaled_width < scaled_height)
*pfit_control |= PFIT_ENABLE | *pfit_control |= PFIT_ENABLE |
PFIT_SCALING_LETTER; 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; *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
} }
@@ -354,10 +442,10 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
u32 *border) u32 *border)
{ {
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
u32 scaled_width = adjusted_mode->crtc_hdisplay * int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
crtc_state->pipe_src_h; int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
u32 scaled_height = crtc_state->pipe_src_w * u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
adjusted_mode->crtc_vdisplay; u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
u32 bits; u32 bits;
/* /*
@@ -367,12 +455,11 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
*/ */
if (scaled_width > scaled_height) { /* pillar */ if (scaled_width > scaled_height) { /* pillar */
centre_horizontally(adjusted_mode, centre_horizontally(adjusted_mode,
scaled_height / scaled_height / pipe_src_h);
crtc_state->pipe_src_h);
*border = LVDS_BORDER_ENABLE; *border = LVDS_BORDER_ENABLE;
if (crtc_state->pipe_src_h != adjusted_mode->crtc_vdisplay) { if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
bits = panel_fitter_scaling(crtc_state->pipe_src_h, bits = panel_fitter_scaling(pipe_src_h,
adjusted_mode->crtc_vdisplay); adjusted_mode->crtc_vdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | *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 */ } else if (scaled_width < scaled_height) { /* letter */
centre_vertically(adjusted_mode, centre_vertically(adjusted_mode,
scaled_width / scaled_width / pipe_src_w);
crtc_state->pipe_src_w);
*border = LVDS_BORDER_ENABLE; *border = LVDS_BORDER_ENABLE;
if (crtc_state->pipe_src_w != adjusted_mode->crtc_hdisplay) { if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
bits = panel_fitter_scaling(crtc_state->pipe_src_w, bits = panel_fitter_scaling(pipe_src_w,
adjusted_mode->crtc_hdisplay); adjusted_mode->crtc_hdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | *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); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; 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 */ /* Native modes don't need fitting */
if (adjusted_mode->crtc_hdisplay == crtc_state->pipe_src_w && if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
adjusted_mode->crtc_vdisplay == crtc_state->pipe_src_h) adjusted_mode->crtc_vdisplay == pipe_src_h)
goto out; goto out;
switch (conn_state->scaling_mode) { 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 & * For centered modes, we have to calculate border widths &
* heights and modify the values programmed into the CRTC. * heights and modify the values programmed into the CRTC.
*/ */
centre_horizontally(adjusted_mode, crtc_state->pipe_src_w); centre_horizontally(adjusted_mode, pipe_src_w);
centre_vertically(adjusted_mode, crtc_state->pipe_src_h); centre_vertically(adjusted_mode, pipe_src_h);
border = LVDS_BORDER_ENABLE; border = LVDS_BORDER_ENABLE;
break; break;
case DRM_MODE_SCALE_ASPECT: 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. * Full scaling, even if it changes the aspect ratio.
* Fortunately this is all done for us in hw. * Fortunately this is all done for us in hw.
*/ */
if (crtc_state->pipe_src_h != adjusted_mode->crtc_vdisplay || if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
crtc_state->pipe_src_w != adjusted_mode->crtc_hdisplay) { pipe_src_w != adjusted_mode->crtc_hdisplay) {
pfit_control |= PFIT_ENABLE; pfit_control |= PFIT_ENABLE;
if (DISPLAY_VER(dev_priv) >= 4) if (DISPLAY_VER(dev_priv) >= 4)
pfit_control |= PFIT_SCALING_AUTO; pfit_control |= PFIT_SCALING_AUTO;
@@ -508,7 +596,8 @@ enum drm_mode_status
intel_panel_mode_valid(struct intel_connector *connector, intel_panel_mode_valid(struct intel_connector *connector,
const struct drm_display_mode *mode) 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) if (!fixed_mode)
return MODE_OK; return MODE_OK;
@@ -525,29 +614,29 @@ intel_panel_mode_valid(struct intel_connector *connector,
return MODE_OK; return MODE_OK;
} }
int intel_panel_init(struct intel_panel *panel, int intel_panel_init(struct intel_connector *connector)
struct drm_display_mode *fixed_mode,
struct drm_display_mode *downclock_mode)
{ {
struct intel_panel *panel = &connector->panel;
intel_backlight_init_funcs(panel); intel_backlight_init_funcs(panel);
panel->fixed_mode = fixed_mode; drm_dbg_kms(connector->base.dev,
panel->downclock_mode = downclock_mode; "[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; return 0;
} }
void intel_panel_fini(struct intel_panel *panel) void intel_panel_fini(struct intel_connector *connector)
{ {
struct intel_connector *intel_connector = struct intel_panel *panel = &connector->panel;
container_of(panel, struct intel_connector, panel); struct drm_display_mode *fixed_mode, *next;
intel_backlight_destroy(panel); intel_backlight_destroy(panel);
if (panel->fixed_mode) list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) {
drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); list_del(&fixed_mode->head);
drm_mode_destroy(connector->base.dev, fixed_mode);
if (panel->downclock_mode) }
drm_mode_destroy(intel_connector->base.dev,
panel->downclock_mode);
} }

View File

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

View File

@@ -14,6 +14,23 @@
#include "intel_pps.h" #include "intel_pps.h"
#include "intel_sdvo.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, static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, enum port port, enum pipe pipe, enum port port,
i915_reg_t dp_reg) i915_reg_t dp_reg)
@@ -88,6 +105,67 @@ static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
pipe_name(pipe)); 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, static void intel_pch_transcoder_set_m1_n1(struct intel_crtc *crtc,
const struct intel_link_m_n *m_n) 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; val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
/* Configure frame start delay to match the CPU */ /* Configure frame start delay to match the CPU */
val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; 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); 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)) { if (HAS_PCH_IBX(dev_priv)) {
/* Configure frame start delay to match the CPU */ /* Configure frame start delay to match the CPU */
val &= ~TRANS_FRAME_START_DELAY_MASK; 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 * 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); ilk_pch_clock_get(crtc_state);
} }
static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, static void lpt_enable_pch_transcoder(const struct intel_crtc_state *crtc_state)
enum transcoder cpu_transcoder)
{ {
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; u32 val, pipeconf_val;
/* FDI must be feeding us bits for PCH ports */ /* 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; val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
/* Configure frame start delay to match the CPU */ /* Configure frame start delay to match the CPU */
val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; 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); intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val);
val = TRANS_ENABLE; 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); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct intel_crtc_state *crtc_state = const struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); intel_atomic_get_new_crtc_state(state, crtc);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
assert_pch_transcoder_disabled(dev_priv, PIPE_A); assert_pch_transcoder_disabled(dev_priv, PIPE_A);
@@ -530,7 +609,7 @@ void lpt_pch_enable(struct intel_atomic_state *state,
/* Set transcoder timing. */ /* Set transcoder timing. */
ilk_pch_transcoder_set_timings(crtc_state, PIPE_A); 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, 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); 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_ #ifndef _INTEL_PCH_DISPLAY_H_
#define _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_atomic_state;
struct intel_crtc; struct intel_crtc;
struct intel_crtc_state; struct intel_crtc_state;
struct intel_link_m_n; 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, void ilk_pch_pre_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc); struct intel_crtc *crtc);
void ilk_pch_enable(struct intel_atomic_state *state, 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, void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc,
struct intel_link_m_n *m_n); struct intel_link_m_n *m_n);
void intel_pch_sanitize(struct drm_i915_private *i915);
#endif #endif

View File

@@ -127,6 +127,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
case DRM_FORMAT_MOD_LINEAR: case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED: case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
break; break;
default: default:
drm_dbg(&dev_priv->drm, 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) 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) { switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) {
case I915_PSR_DEBUG_DISABLE: case I915_PSR_DEBUG_DISABLE:
case I915_PSR_DEBUG_FORCE_PSR1: case I915_PSR_DEBUG_FORCE_PSR1:
return false; return false;
default: default:
if (i915->params.enable_psr == 1)
return false;
return true; 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_exit_delay = val;
intel_dp->psr.dc3co_exitline = crtc_state->dc3co_exitline; 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_enabled = crtc_state->enable_psr2_sel_fetch;
intel_dp->psr.psr2_sel_fetch_cff_enabled = false;
intel_dp->psr.req_psr2_sdp_prior_scanline = intel_dp->psr.req_psr2_sdp_prior_scanline =
crtc_state->req_psr2_sdp_prior_scanline; crtc_state->req_psr2_sdp_prior_scanline;
@@ -1432,28 +1437,42 @@ unlock:
mutex_unlock(&psr->lock); 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) ? return IS_ALDERLAKE_P(dev_priv) ?
ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME : ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME :
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) ? return IS_ALDERLAKE_P(dev_priv) ?
ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE : ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE :
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) static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
{ {
struct drm_i915_private *dev_priv = dp_to_i915(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_enabled)
intel_de_rmw(dev_priv, intel_de_write(dev_priv,
PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder),
man_trk_ctl_single_full_frame_bit_get(dev_priv)); 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+ * 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) 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 drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->enable_psr2_sel_fetch) if (!crtc_state->enable_psr2_sel_fetch)
return; 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), intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder),
crtc_state->psr2_man_track_ctl); 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 intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 val = 0; u32 val = man_trk_ctl_enable_bit_get(dev_priv);
if (!IS_ALDERLAKE_P(dev_priv))
val = PSR2_MAN_TRK_CTL_ENABLE;
/* SF partial frame enable has to be set even on full update */ /* SF partial frame enable has to be set even on full update */
val |= man_trk_ctl_partial_frame_bit_get(dev_priv); 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 * @new_crtc_state: new CRTC state
* *
* This function is expected to be called from pipe_update_start() where it is * This function is expected to be called from pipe_update_start() where it is
* not expected to race with PSR enable or disable. * 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 drm_i915_private *dev_priv = to_i915(new_crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder; 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); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
int ret; int ret;
mutex_lock(&intel_dp->psr.lock); lockdep_assert_held(&intel_dp->psr.lock);
if (!intel_dp->psr.enabled) { if (!intel_dp->psr.enabled)
mutex_unlock(&intel_dp->psr.lock);
continue; continue;
}
if (intel_dp->psr.psr2_enabled) if (intel_dp->psr.psr2_enabled)
ret = _psr2_ready_for_pipe_update_locked(intel_dp); 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) if (ret)
drm_err(&dev_priv->drm, "PSR wait timed out, atomic update may fail\n"); 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); 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 * intel_psr_invalidate - Invalidade PSR
* @dev_priv: i915 device * @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; intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits;
if (pipe_frontbuffer_bits) if (pipe_frontbuffer_bits)
intel_psr_exit(intel_dp); _psr_invalidate_handle(intel_dp);
mutex_unlock(&intel_dp->psr.lock); 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); 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 * intel_psr_flush - Flush PSR
* @dev_priv: i915 device * @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 * we have to ensure that the PSR is not activated until
* intel_psr_resume() is called. * intel_psr_resume() is called.
*/ */
if (intel_dp->psr.paused) { if (intel_dp->psr.paused)
mutex_unlock(&intel_dp->psr.lock); goto unlock;
continue;
}
if (origin == ORIGIN_FLIP || if (origin == ORIGIN_FLIP ||
(origin == ORIGIN_CURSOR_UPDATE && (origin == ORIGIN_CURSOR_UPDATE &&
!intel_dp->psr.psr2_sel_fetch_enabled)) { !intel_dp->psr.psr2_sel_fetch_enabled)) {
tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin); tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin);
mutex_unlock(&intel_dp->psr.lock); goto unlock;
continue;
} }
/* By definition flush = invalidate + flush */ if (pipe_frontbuffer_bits == 0)
if (pipe_frontbuffer_bits) goto unlock;
psr_force_hw_tracking_exit(intel_dp);
if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits) /* By definition flush = invalidate + flush */
schedule_work(&intel_dp->psr.work); _psr_flush_handle(intel_dp);
unlock:
mutex_unlock(&intel_dp->psr.lock); mutex_unlock(&intel_dp->psr.lock);
} }
} }
@@ -2436,3 +2513,51 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
return ret; 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); struct intel_crtc_state *pipe_config);
void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); 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_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); bool intel_psr_enabled(struct intel_dp *intel_dp);
int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc); 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_pause(struct intel_dp *intel_dp);
void intel_psr_resume(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__ */ #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 { static const struct {
u8 cmd; u8 cmd;
const char *name; const char *name;
} __attribute__ ((packed)) sdvo_cmd_names[] = { } __packed sdvo_cmd_names[] = {
SDVO_CMD_NAME_ENTRY(RESET), SDVO_CMD_NAME_ENTRY(RESET),
SDVO_CMD_NAME_ENTRY(GET_DEVICE_CAPS), SDVO_CMD_NAME_ENTRY(GET_DEVICE_CAPS),
SDVO_CMD_NAME_ENTRY(GET_FIRMWARE_REV), 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 static bool
intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector, struct intel_sdvo_connector *intel_sdvo_connector,
u16 clock, const struct drm_display_mode *mode)
u16 width,
u16 height)
{ {
struct intel_sdvo_preferred_input_timing_args args; struct intel_sdvo_preferred_input_timing_args args;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.clock = clock; args.clock = mode->clock / 10;
args.width = width; args.width = mode->hdisplay;
args.height = height; args.height = mode->vdisplay;
args.interlace = 0; args.interlace = 0;
if (IS_LVDS(intel_sdvo_connector)) { if (IS_LVDS(intel_sdvo_connector)) {
const struct drm_display_mode *fixed_mode = 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 || if (fixed_mode->hdisplay != args.width ||
fixed_mode->vdisplay != height) fixed_mode->vdisplay != args.height)
args.scaled = 1; 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, if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,
intel_sdvo_connector, intel_sdvo_connector,
mode->clock / 10, mode))
mode->hdisplay,
mode->vdisplay))
return false; return false;
if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, 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); adjusted_mode);
pipe_config->sdvo_tv_clock = true; pipe_config->sdvo_tv_clock = true;
} else if (IS_LVDS(intel_sdvo_connector)) { } 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; int ret;
ret = intel_panel_compute_config(&intel_sdvo_connector->base, 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) if (ret)
return ret; return ret;
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, fixed_mode))
intel_sdvo_connector->base.panel.fixed_mode))
return -EINVAL; return -EINVAL;
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo, (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 drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
const struct intel_sdvo_connector_state *sdvo_state = const struct intel_sdvo_connector_state *sdvo_state =
to_intel_sdvo_connector_state(conn_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); to_intel_sdvo_connector(conn_state->connector);
const struct drm_display_mode *mode = &crtc_state->hw.mode; const struct drm_display_mode *mode = &crtc_state->hw.mode;
struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); 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; return;
/* lvds has a special fixed output timing. */ /* lvds has a special fixed output timing. */
if (IS_LVDS(intel_sdvo_connector)) if (IS_LVDS(intel_sdvo_connector)) {
intel_sdvo_get_dtd_from_mode(&output_dtd, const struct drm_display_mode *fixed_mode =
intel_sdvo_connector->base.panel.fixed_mode); intel_panel_fixed_mode(&intel_sdvo_connector->base, mode);
else
intel_sdvo_get_dtd_from_mode(&output_dtd, fixed_mode);
} else {
intel_sdvo_get_dtd_from_mode(&output_dtd, mode); intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
}
if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
drm_info(&dev_priv->drm, drm_info(&dev_priv->drm,
"Setting output timings on %s failed\n", "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 intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
struct drm_i915_private *dev_priv = to_i915(connector->dev); struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct drm_display_mode *newmode;
int num_modes = 0; int num_modes = 0;
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name); connector->base.id, connector->name);
/* num_modes += intel_panel_get_modes(to_intel_connector(connector));
* 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_ddc_get_modes(connector, &intel_sdvo->ddc); num_modes += intel_ddc_get_modes(connector, &intel_sdvo->ddc);
return num_modes; 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, __drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
&conn_state->base.base); &conn_state->base.base);
INIT_LIST_HEAD(&sdvo_connector->base.panel.fixed_modes);
return sdvo_connector; return sdvo_connector;
} }
@@ -2890,7 +2871,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
struct drm_connector *connector; struct drm_connector *connector;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector; struct intel_sdvo_connector *intel_sdvo_connector;
struct drm_display_mode *mode;
DRM_DEBUG_KMS("initialising LVDS device %d\n", device); 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)) if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err; 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 (!intel_panel_preferred_fixed_mode(intel_connector)) {
if (mode->type & DRM_MODE_TYPE_PREFERRED) { intel_ddc_get_modes(connector, &intel_sdvo->ddc);
struct drm_display_mode *fixed_mode = intel_panel_add_edid_fixed_modes(intel_connector, false);
drm_mode_duplicate(connector->dev, mode);
intel_panel_init(&intel_connector->panel,
fixed_mode, NULL);
break;
}
} }
if (!intel_connector->panel.fixed_mode) intel_panel_init(intel_connector);
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto err; goto err;
return true; 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)) if (!intel_phy_is_snps(i915, phy))
continue; 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), if (intel_de_wait_for_clear(i915, DG2_PHY_MISC(phy),
DG2_PHY_DP_TX_ACK_MASK, 25)) DG2_PHY_DP_TX_ACK_MASK, 25))
drm_err(&i915->drm, "SNPS PHY %c failed to calibrate after 25ms.\n", i915->snps_phy_failed_calibration |= BIT(phy);
phy_name(phy));
} }
} }

View File

@@ -30,6 +30,8 @@
* support. * support.
*/ */
#include <linux/string_helpers.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_color_mgmt.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) { 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", 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; return -EINVAL;
} }
if (src_y % vsub || src_h % vsub) { 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", 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; return -EINVAL;
} }
@@ -430,9 +432,6 @@ vlv_sprite_update_noarm(struct intel_plane *plane,
int crtc_y = plane_state->uapi.dst.y1; int crtc_y = plane_state->uapi.dst.y1;
u32 crtc_w = drm_rect_width(&plane_state->uapi.dst); u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
u32 crtc_h = drm_rect_height(&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), intel_de_write_fw(dev_priv, SPSTRIDE(pipe, plane_id),
plane_state->view.color_plane[0].mapping_stride); 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)); SP_POS_Y(crtc_y) | SP_POS_X(crtc_x));
intel_de_write_fw(dev_priv, SPSIZE(pipe, plane_id), intel_de_write_fw(dev_priv, SPSIZE(pipe, plane_id),
SP_HEIGHT(crtc_h - 1) | SP_WIDTH(crtc_w - 1)); SP_HEIGHT(crtc_h - 1) | SP_WIDTH(crtc_w - 1));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void static void
@@ -457,14 +454,11 @@ vlv_sprite_update_arm(struct intel_plane *plane,
u32 x = plane_state->view.color_plane[0].x; u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y; u32 y = plane_state->view.color_plane[0].y;
u32 sprctl, linear_offset; u32 sprctl, linear_offset;
unsigned long irqflags;
sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state); sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); 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) if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
chv_sprite_update_csc(plane_state); 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_clrc(plane_state);
vlv_sprite_update_gamma(plane_state); vlv_sprite_update_gamma(plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe; enum pipe pipe = plane->pipe;
enum plane_id plane_id = plane->id; 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, SPCNTR(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, SPSURF(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 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_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u32 sprscale = 0; u32 sprscale = 0;
unsigned long irqflags;
if (crtc_w != src_w || crtc_h != src_h) if (crtc_w != src_w || crtc_h != src_h)
sprscale = SPRITE_SCALE_ENABLE | sprscale = SPRITE_SCALE_ENABLE |
SPRITE_SRC_WIDTH(src_w - 1) | SPRITE_SRC_WIDTH(src_w - 1) |
SPRITE_SRC_HEIGHT(src_h - 1); SPRITE_SRC_HEIGHT(src_h - 1);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, SPRSTRIDE(pipe), intel_de_write_fw(dev_priv, SPRSTRIDE(pipe),
plane_state->view.color_plane[0].mapping_stride); plane_state->view.color_plane[0].mapping_stride);
intel_de_write_fw(dev_priv, SPRPOS(pipe), 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)); SPRITE_HEIGHT(crtc_h - 1) | SPRITE_WIDTH(crtc_w - 1));
if (IS_IVYBRIDGE(dev_priv)) if (IS_IVYBRIDGE(dev_priv))
intel_de_write_fw(dev_priv, SPRSCALE(pipe), sprscale); intel_de_write_fw(dev_priv, SPRSCALE(pipe), sprscale);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void static void
@@ -895,14 +877,11 @@ ivb_sprite_update_arm(struct intel_plane *plane,
u32 x = plane_state->view.color_plane[0].x; u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y; u32 y = plane_state->view.color_plane[0].y;
u32 sprctl, linear_offset; u32 sprctl, linear_offset;
unsigned long irqflags;
sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state); sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (key->flags) { if (key->flags) {
intel_de_write_fw(dev_priv, SPRKEYVAL(pipe), key->min_value); intel_de_write_fw(dev_priv, SPRKEYVAL(pipe), key->min_value);
intel_de_write_fw(dev_priv, SPRKEYMSK(pipe), 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); intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
ivb_sprite_update_gamma(plane_state); ivb_sprite_update_gamma(plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe; 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); intel_de_write_fw(dev_priv, SPRCTL(pipe), 0);
/* Disable the scaler */ /* Disable the scaler */
if (IS_IVYBRIDGE(dev_priv)) if (IS_IVYBRIDGE(dev_priv))
intel_de_write_fw(dev_priv, SPRSCALE(pipe), 0); intel_de_write_fw(dev_priv, SPRSCALE(pipe), 0);
intel_de_write_fw(dev_priv, SPRSURF(pipe), 0); intel_de_write_fw(dev_priv, SPRSURF(pipe), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static bool 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_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u32 dvsscale = 0; u32 dvsscale = 0;
unsigned long irqflags;
if (crtc_w != src_w || crtc_h != src_h) if (crtc_w != src_w || crtc_h != src_h)
dvsscale = DVS_SCALE_ENABLE | dvsscale = DVS_SCALE_ENABLE |
DVS_SRC_WIDTH(src_w - 1) | DVS_SRC_WIDTH(src_w - 1) |
DVS_SRC_HEIGHT(src_h - 1); DVS_SRC_HEIGHT(src_h - 1);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, DVSSTRIDE(pipe), intel_de_write_fw(dev_priv, DVSSTRIDE(pipe),
plane_state->view.color_plane[0].mapping_stride); plane_state->view.color_plane[0].mapping_stride);
intel_de_write_fw(dev_priv, DVSPOS(pipe), 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), intel_de_write_fw(dev_priv, DVSSIZE(pipe),
DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1)); DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1));
intel_de_write_fw(dev_priv, DVSSCALE(pipe), dvsscale); intel_de_write_fw(dev_priv, DVSSCALE(pipe), dvsscale);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void static void
@@ -1236,14 +1203,11 @@ g4x_sprite_update_arm(struct intel_plane *plane,
u32 x = plane_state->view.color_plane[0].x; u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y; u32 y = plane_state->view.color_plane[0].y;
u32 dvscntr, linear_offset; u32 dvscntr, linear_offset;
unsigned long irqflags;
dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state); dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (key->flags) { if (key->flags) {
intel_de_write_fw(dev_priv, DVSKEYVAL(pipe), key->min_value); intel_de_write_fw(dev_priv, DVSKEYVAL(pipe), key->min_value);
intel_de_write_fw(dev_priv, DVSKEYMSK(pipe), 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); g4x_sprite_update_gamma(plane_state);
else else
ilk_sprite_update_gamma(plane_state); ilk_sprite_update_gamma(plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static void 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe; 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); intel_de_write_fw(dev_priv, DVSCNTR(pipe), 0);
/* Disable the scaler */ /* Disable the scaler */
intel_de_write_fw(dev_priv, DVSSCALE(pipe), 0); intel_de_write_fw(dev_priv, DVSSCALE(pipe), 0);
intel_de_write_fw(dev_priv, DVSSURF(pipe), 0); intel_de_write_fw(dev_priv, DVSSURF(pipe), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static bool static bool

View File

@@ -1145,8 +1145,8 @@ intel_tv_get_config(struct intel_encoder *encoder,
intel_tv_mode_to_mode(&mode, &tv_mode); intel_tv_mode_to_mode(&mode, &tv_mode);
drm_dbg_kms(&dev_priv->drm, "TV mode:\n"); drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n",
drm_mode_debug_printmodeline(&mode); DRM_MODE_ARG(&mode));
intel_tv_scale_mode_horiz(&mode, hdisplay, intel_tv_scale_mode_horiz(&mode, hdisplay,
xpos, mode.hdisplay - xsize - xpos); xpos, mode.hdisplay - xsize - xpos);
@@ -1250,8 +1250,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
tv_conn_state->bypass_vfilter = false; tv_conn_state->bypass_vfilter = false;
} }
drm_dbg_kms(&dev_priv->drm, "TV mode:\n"); drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n",
drm_mode_debug_printmodeline(adjusted_mode); DRM_MODE_ARG(adjusted_mode));
/* /*
* The pipe scanline counter behaviour looks as follows when * 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); intel_tv_mode_to_mode(mode, tv_mode);
if (count == 0) { if (count == 0) {
drm_dbg_kms(&dev_priv->drm, "TV mode:\n"); drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n",
drm_mode_debug_printmodeline(mode); DRM_MODE_ARG(mode));
} }
intel_tv_scale_mode_horiz(mode, input->w, 0, 0); intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
intel_tv_scale_mode_vert(mode, input->h, 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_PLATFORM 0 /* 204 */
#define HDMI_MAX_DATA_RATE_297 1 /* 204 */ #define HDMI_MAX_DATA_RATE_297 1 /* 204 */
#define HDMI_MAX_DATA_RATE_165 2 /* 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 #define LEGACY_CHILD_DEVICE_CONFIG_SIZE 33
@@ -719,20 +722,22 @@ struct bdb_lvds_options {
/* /*
* Block 41 - LFP Data Table Pointers * 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 */ /* LFP pointer table contains entries to the struct below */
struct lvds_lfp_data_ptr { struct lvds_lfp_data_ptr {
u16 fp_timing_offset; /* offsets are from start of bdb */ struct lvds_lfp_data_ptr_table fp_timing;
u8 fp_table_size; struct lvds_lfp_data_ptr_table dvo_timing;
u16 dvo_timing_offset; struct lvds_lfp_data_ptr_table panel_pnp_id;
u8 dvo_table_size;
u16 panel_pnp_id_offset;
u8 pnp_table_size;
} __packed; } __packed;
struct bdb_lvds_lfp_data_ptrs { struct bdb_lvds_lfp_data_ptrs {
u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
struct lvds_lfp_data_ptr ptr[16]; struct lvds_lfp_data_ptr ptr[16];
struct lvds_lfp_data_ptr_table panel_name; /* 156-163? */
} __packed; } __packed;
/* /*
@@ -774,6 +779,10 @@ struct bdb_lvds_lfp_data {
struct lvds_lfp_data_entry data[16]; struct lvds_lfp_data_entry data[16];
} __packed; } __packed;
struct lvds_lfp_panel_name {
u8 name[13];
} __packed;
/* /*
* Block 43 - LFP Backlight Control Data Block * 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 bpc = vdsc_cfg->bits_per_component;
int bpp = vdsc_cfg->bits_per_pixel >> 4; 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 }; static const s8 ofs_und6[] = {
int ofs_und8[] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 }; 0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -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_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; int qp_bpc_modifier = (bpc - 8) * 2;
u32 res, buf_i, bpp_i; 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; u8 num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1;
int i = 0; int i = 0;
if (crtc_state->bigjoiner) if (crtc_state->bigjoiner_pipes)
num_vdsc_instances *= 2; num_vdsc_instances *= 2;
/* Populate PICTURE_PARAMETER_SET_0 registers */ /* 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); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dss_ctl1_val = 0; 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)) if (intel_crtc_is_bigjoiner_slave(crtc_state))
dss_ctl1_val |= UNCOMPRESSED_JOINER_SLAVE; dss_ctl1_val |= UNCOMPRESSED_JOINER_SLAVE;
else else
@@ -1140,7 +1148,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state)
dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE; dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
dss_ctl1_val |= JOINER_ENABLE; dss_ctl1_val |= JOINER_ENABLE;
} }
if (crtc_state->bigjoiner) { if (crtc_state->bigjoiner_pipes) {
dss_ctl1_val |= BIG_JOINER_ENABLE; dss_ctl1_val |= BIG_JOINER_ENABLE;
if (!intel_crtc_is_bigjoiner_slave(crtc_state)) if (!intel_crtc_is_bigjoiner_slave(crtc_state))
dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE; 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 */ /* Disable only if either of them is enabled */
if (old_crtc_state->dsc.compression_enable || 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_ctl1_reg(crtc, old_crtc_state->cpu_transcoder), 0);
intel_de_write(dev_priv, dss_ctl2_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 */ /* The hw imposes the extra scanline before frame start */
if (DISPLAY_VER(i915) >= 13) 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 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) 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, return skl_update_scaler(crtc_state, !crtc_state->hw.active,
SKL_CRTC_INDEX, SKL_CRTC_INDEX,
&crtc_state->scaler_state.scaler_id, &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, width, height, NULL, 0,
crtc_state->pch_pfit.enabled); 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); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct intel_crtc_scaler_state *scaler_state = const struct intel_crtc_scaler_state *scaler_state =
&crtc_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; const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
u16 uv_rgb_hphase, uv_rgb_vphase; u16 uv_rgb_hphase, uv_rgb_vphase;
enum pipe pipe = crtc->pipe; 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 x = dst->x1;
int y = dst->y1; int y = dst->y1;
int hscale, vscale; int hscale, vscale;
unsigned long irqflags; struct drm_rect src;
int id; int id;
u32 ps_ctrl; 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)) crtc_state->scaler_state.scaler_id < 0))
return; 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); hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX);
vscale = drm_rect_calc_vscale(&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 = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode; 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, skl_scaler_setup_filter(dev_priv, pipe, id, 0,
crtc_state->hw.scaling_filter); crtc_state->hw.scaling_filter);
@@ -449,8 +448,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
x << 16 | y); x << 16 | y);
intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id), intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id),
width << 16 | height); width << 16 | height);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
void 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_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(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_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_POS(crtc->pipe, id), 0);
intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id; enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe; 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)) if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0); 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_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_CTL(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, PLANE_SURF(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 static bool
@@ -762,6 +771,18 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier)
return PLANE_CTL_TILED_X; return PLANE_CTL_TILED_X;
case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Y_TILED:
return PLANE_CTL_TILED_Y; 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_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; 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); 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 */ /* Program the UV plane on planar master */
if (plane_state->planar_linked_plane && !plane_state->planar_slave) 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id; enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe; enum pipe pipe = plane->pipe;
int color_plane = skl_plane_color_plane(plane_state); u32 stride = skl_plane_stride(plane_state, 0);
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_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1; int crtc_y = plane_state->uapi.dst.y1;
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&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 */ /* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) { if (plane_state->scaler_id >= 0) {
@@ -1097,15 +1115,6 @@ skl_plane_update_noarm(struct intel_plane *plane,
crtc_y = 0; 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), intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id),
PLANE_STRIDE_(stride)); PLANE_STRIDE_(stride));
intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id), 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), intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1)); 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); 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 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); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id; enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe; enum pipe pipe = plane->pipe;
int color_plane = skl_plane_color_plane(plane_state); u32 x = plane_state->view.color_plane[0].x;
u32 x = plane_state->view.color_plane[color_plane].x; u32 y = plane_state->view.color_plane[0].y;
u32 y = plane_state->view.color_plane[color_plane].y; u32 plane_ctl, plane_color_ctl = 0;
u32 plane_color_ctl = 0;
u32 plane_ctl = plane_state->ctl;
unsigned long irqflags;
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) if (DISPLAY_VER(dev_priv) >= 10)
plane_color_ctl = plane_state->color_ctl | plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state); 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_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_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_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)); PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), 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),
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) |
PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) | PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
if (DISPLAY_VER(dev_priv) >= 10) if (DISPLAY_VER(dev_priv) >= 10)
intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl); 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_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 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 static void
@@ -1204,7 +1297,6 @@ skl_plane_async_flip(struct intel_plane *plane,
bool async_flip) bool async_flip)
{ {
struct drm_i915_private *dev_priv = to_i915(plane->base.dev); struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
unsigned long irqflags;
enum plane_id plane_id = plane->id; enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe; enum pipe pipe = plane->pipe;
u32 plane_ctl = plane_state->ctl; u32 plane_ctl = plane_state->ctl;
@@ -1214,13 +1306,9 @@ skl_plane_async_flip(struct intel_plane *plane,
if (async_flip) if (async_flip)
plane_ctl |= PLANE_CTL_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_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
skl_plane_surf(plane_state, 0)); skl_plane_surf(plane_state, 0));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
} }
static bool intel_format_is_p01x(u32 format) 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); to_i915(plane_state->uapi.plane->dev);
int crtc_x = plane_state->uapi.dst.x1; int crtc_x = plane_state->uapi.dst.x1;
int crtc_w = drm_rect_width(&plane_state->uapi.dst); 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 * 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 * 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, while (!skl_check_main_ccs_coordinates(plane_state, x, y,
offset, aux_plane)) { offset, aux_plane)) {
if (offset == 0) 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; const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation; unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1; 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_width = intel_plane_max_width(plane, fb, uv_plane, rotation);
int max_height = intel_plane_max_height(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; 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, offset = intel_plane_compute_aligned_offset(&x, &y,
plane_state, uv_plane); plane_state, uv_plane);
if (intel_fb_is_ccs_modifier(fb->modifier)) { if (ccs_plane) {
int ccs_plane = main_to_ccs_plane(fb, uv_plane);
u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset; u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
u32 alignment = intel_surf_alignment(fb, uv_plane); 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_Y216:
case DRM_FORMAT_XVYU12_16161616: case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616: case DRM_FORMAT_XVYU16161616:
if (modifier == DRM_FORMAT_MOD_LINEAR || if (!intel_fb_is_ccs_modifier(modifier))
modifier == I915_FORMAT_MOD_X_TILED ||
modifier == I915_FORMAT_MOD_Y_TILED)
return true; return true;
fallthrough; fallthrough;
default: 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)) if (IS_ADLP_DISPLAY_STEP(i915, STEP_A0, STEP_B0))
return false; return false;
/* Wa_14013215631 */
if (IS_DG2_DISPLAY_STEP(i915, STEP_A0, STEP_C0))
return false;
return plane_id < PLANE_SPRITE4; 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; caps |= INTEL_PLANE_CAP_TILING_Y;
if (DISPLAY_VER(i915) < 12) if (DISPLAY_VER(i915) < 12)
caps |= INTEL_PLANE_CAP_TILING_Yf; 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)) { if (skl_plane_has_rc_ccs(i915, pipe, plane_id)) {
caps |= INTEL_PLANE_CAP_CCS_RC; 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->max_stride = skl_plane_max_stride;
plane->update_noarm = skl_plane_update_noarm; if (DISPLAY_VER(dev_priv) >= 11) {
plane->update_arm = skl_plane_update_arm; plane->update_noarm = icl_plane_update_noarm;
plane->disable_arm = skl_plane_disable_arm; 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->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check; plane->check_plane = skl_plane_check;
@@ -2278,13 +2378,14 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
unsigned int aligned_height; unsigned int aligned_height;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb; struct intel_framebuffer *intel_fb;
static_assert(PLANE_CTL_TILED_YF == PLANE_CTL_TILED_4);
if (!plane->get_hw_state(plane, &pipe)) if (!plane->get_hw_state(plane, &pipe))
return; return;
drm_WARN_ON(dev, pipe != crtc->pipe); drm_WARN_ON(dev, pipe != crtc->pipe);
if (crtc_state->bigjoiner) { if (crtc_state->bigjoiner_pipes) {
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
"Unsupported bigjoiner configuration for initial FB\n"); "Unsupported bigjoiner configuration for initial FB\n");
return; return;
@@ -2332,19 +2433,34 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
case PLANE_CTL_TILED_Y: case PLANE_CTL_TILED_Y:
plane_config->tiling = I915_TILING_Y; plane_config->tiling = I915_TILING_Y;
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = DISPLAY_VER(dev_priv) >= 12 ? if (DISPLAY_VER(dev_priv) >= 12)
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS : fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS;
I915_FORMAT_MOD_Y_TILED_CCS; else
fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
else else
fb->modifier = I915_FORMAT_MOD_Y_TILED; fb->modifier = I915_FORMAT_MOD_Y_TILED;
break; break;
case PLANE_CTL_TILED_YF: case PLANE_CTL_TILED_YF: /* aka PLANE_CTL_TILED_4 on XE_LPD+ */
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) if (HAS_4TILE(dev_priv)) {
fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; u32 rc_mask = PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
else PLANE_CTL_CLEAR_COLOR_DISABLE;
fb->modifier = I915_FORMAT_MOD_Yf_TILED;
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; break;
default: default:
MISSING_CASE(tiling); 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) static void vlv_dsi_add_properties(struct intel_connector *connector)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); 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; u32 allowed_scalers;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN); 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, drm_connector_set_panel_orientation_with_quirk(&connector->base,
intel_dsi_get_panel_orientation(connector), intel_dsi_get_panel_orientation(connector),
connector->panel.fixed_mode->hdisplay, fixed_mode->hdisplay,
connector->panel.fixed_mode->vdisplay); fixed_mode->vdisplay);
} }
#define NS_KHZ_RATIO 1000000 #define NS_KHZ_RATIO 1000000
@@ -1857,7 +1859,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_display_mode *current_mode, *fixed_mode; struct drm_display_mode *current_mode;
enum port port; enum port port;
enum pipe pipe; 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); intel_connector_attach_encoder(intel_connector, intel_encoder);
mutex_lock(&dev->mode_config.mutex); 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); 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"); drm_dbg_kms(&dev_priv->drm, "no fixed mode\n");
goto err_cleanup_connector; 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); intel_backlight_setup(intel_connector, INVALID_PIPE);
vlv_dsi_add_properties(intel_connector); vlv_dsi_add_properties(intel_connector);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -219,6 +219,14 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj,
return ret; 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 int
i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
unsigned int tiling, unsigned int stride) unsigned int tiling, unsigned int stride)

View File

@@ -8,8 +8,10 @@
#include <linux/types.h> #include <linux/types.h>
struct drm_i915_gem_object;
struct drm_i915_private; 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, u32 i915_gem_fence_size(struct drm_i915_private *i915, u32 size,
unsigned int tiling, unsigned int stride); unsigned int tiling, unsigned int stride);
u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size, u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size,

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
*/ */
#include <linux/prime_numbers.h> #include <linux/prime_numbers.h>
#include <linux/string_helpers.h>
#include "gem/i915_gem_internal.h" #include "gem/i915_gem_internal.h"
#include "gem/i915_gem_pm.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", pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj), ndwords, dw, max_dwords(obj),
engine->name, engine->name,
yesno(i915_gem_context_has_full_ppgtt(ctx)), str_yes_no(i915_gem_context_has_full_ppgtt(ctx)),
err); err);
intel_context_put(ce); intel_context_put(ce);
kernel_context_close(ctx); 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", pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj), ndwords, dw, max_dwords(obj),
engine->name, engine->name,
yesno(i915_gem_context_has_full_ppgtt(ctx)), str_yes_no(i915_gem_context_has_full_ppgtt(ctx)),
err); err);
intel_context_put(ce); intel_context_put(ce);
kernel_context_close(ctx); 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", pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj), ndwords, dw, max_dwords(obj),
ce->engine->name, ce->engine->name,
yesno(i915_gem_context_has_full_ppgtt(ctx)), str_yes_no(i915_gem_context_has_full_ppgtt(ctx)),
err); err);
i915_gem_context_unlock_engines(ctx); i915_gem_context_unlock_engines(ctx);
goto out_file; goto out_file;

View File

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

View File

@@ -4,6 +4,7 @@
*/ */
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/string_helpers.h>
#include <trace/events/dma_fence.h> #include <trace/events/dma_fence.h>
#include <uapi/linux/sched/types.h> #include <uapi/linux/sched/types.h>
@@ -512,7 +513,7 @@ void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
if (!b) if (!b)
return; 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)) if (!list_empty(&b->signalers))
print_signals(b, p); print_signals(b, p);
} }

View File

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

View File

@@ -107,6 +107,7 @@
* *
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/string_helpers.h>
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_trace.h" #include "i915_trace.h"
@@ -1335,11 +1336,11 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
} else if (timeslice_expired(engine, last)) { } else if (timeslice_expired(engine, last)) {
ENGINE_TRACE(engine, ENGINE_TRACE(engine,
"expired:%s last=%llx:%lld, prio=%d, hint=%d, yield?=%s\n", "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, last->fence.context, last->fence.seqno,
rq_prio(last), rq_prio(last),
sched_engine->queue_priority_hint, 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. * 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_is_complete(rq) ? "!" :
__i915_request_has_started(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->request, NULL);
WRITE_ONCE(ve->base.sched_engine->queue_priority_hint, INT_MIN); WRITE_ONCE(ve->base.sched_engine->queue_priority_hint, INT_MIN);

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
*/ */
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/string_helpers.h>
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_reg.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); rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL);
seq_printf(m, "RC6 Enabled: %s\n", 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)))); GEN6_RC_CTL_EI_MODE(1))));
seq_printf(m, "Render Power Well: %s\n", seq_printf(m, "Render Power Well: %s\n",
(pw_status & VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up" : "Down"); (pw_status & VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up" : "Down");
seq_printf(m, "Media Power Well: %s\n", seq_printf(m, "Media Power Well: %s\n",
(pw_status & VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down"); (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); print_rc6_res(m, "Media RC6 residency since boot:", VLV_GT_MEDIA_RC6);
return fw_domains_show(m, NULL); 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); snb_pcode_read(i915, GEN6_PCODE_READ_RC6VIDS, &rc6vids, NULL);
seq_printf(m, "RC1e Enabled: %s\n", 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", 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) { if (GRAPHICS_VER(i915) >= 9) {
seq_printf(m, "Render Well Gating Enabled: %s\n", 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", 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", 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", 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: "); seq_puts(m, "Current RC state: ");
switch (gt_core_status & GEN6_RCn_MASK) { switch (gt_core_status & GEN6_RCn_MASK) {
case GEN6_RC0: case GEN6_RC0:
@@ -176,7 +177,7 @@ static int gen6_drpc(struct seq_file *m)
} }
seq_printf(m, "Core Power Down: %s\n", 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) { if (GRAPHICS_VER(i915) >= 9) {
seq_printf(m, "Render Power Well: %s\n", seq_printf(m, "Render Power Well: %s\n",
(gen9_powergate_status & (gen9_powergate_status &
@@ -216,16 +217,17 @@ static int ilk_drpc(struct seq_file *m)
rstdbyctl = intel_uncore_read(uncore, RSTDBYCTL); rstdbyctl = intel_uncore_read(uncore, RSTDBYCTL);
crstandvid = intel_uncore_read16(uncore, CRSTANDVID); 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", seq_printf(m, "Boost freq: %d\n",
(rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >> (rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
MEMMODE_BOOST_FREQ_SHIFT); MEMMODE_BOOST_FREQ_SHIFT);
seq_printf(m, "HW control enabled: %s\n", 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", 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", 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", seq_printf(m, "Starting frequency: P%d\n",
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
seq_printf(m, "Max P-state: P%d\n", 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, "RS1 VID: %d\n", (crstandvid & 0x3f));
seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
seq_printf(m, "Render standby enabled: %s\n", 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: "); seq_puts(m, "Current RS state: ");
switch (rstdbyctl & RSX_STATUS_MASK) { switch (rstdbyctl & RSX_STATUS_MASK) {
case RSX_STATUS_ON: 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); rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL);
drm_printf(p, "Video Turbo Mode: %s\n", 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", 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", drm_printf(p, "SW control enabled: %s\n",
yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
GEN6_RP_MEDIA_SW_MODE));
vlv_punit_get(i915); vlv_punit_get(i915);
freq_sts = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); 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); pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
drm_printf(p, "Video Turbo Mode: %s\n", 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", 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", drm_printf(p, "SW control enabled: %s\n",
yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
GEN6_RP_MEDIA_SW_MODE));
drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n",
pm_ier, pm_imr, pm_mask); pm_ier, pm_imr, pm_mask);
@@ -542,7 +542,7 @@ static int llc_show(struct seq_file *m, void *data)
intel_wakeref_t wakeref; intel_wakeref_t wakeref;
int gpu_freq, ia_freq; 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", seq_printf(m, "%s: %uMB\n", edram ? "eDRAM" : "eLLC",
i915->edram_size_mb); 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 drm_i915_private *i915 = gt->i915;
struct intel_rps *rps = &gt->rps; struct intel_rps *rps = &gt->rps;
seq_printf(m, "RPS enabled? %s\n", yesno(intel_rps_is_enabled(rps))); seq_printf(m, "RPS enabled? %s\n",
seq_printf(m, "RPS active? %s\n", yesno(intel_rps_is_active(rps))); 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", 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))); ktime_to_ms(intel_gt_get_awake_time(gt)));
seq_printf(m, "Boosts outstanding? %d\n", seq_printf(m, "Boosts outstanding? %d\n",
atomic_read(&rps->num_waiters)); atomic_read(&rps->num_waiters));

View File

@@ -1440,7 +1440,6 @@
#define VLV_MEDIA_RC6_COUNT_EN (1 << 1) #define VLV_MEDIA_RC6_COUNT_EN (1 << 1)
#define VLV_RENDER_RC6_COUNT_EN (1 << 0) #define VLV_RENDER_RC6_COUNT_EN (1 << 0)
#define GEN6_GT_GFX_RC6 _MMIO(0x138108) #define GEN6_GT_GFX_RC6 _MMIO(0x138108)
#define VLV_GT_RENDER_RC6 _MMIO(0x138108)
#define VLV_GT_MEDIA_RC6 _MMIO(0x13810c) #define VLV_GT_MEDIA_RC6 _MMIO(0x13810c)
#define GEN6_GT_GFX_RC6p _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_internal.h"
#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_lmem.h"
#include "i915_trace.h" #include "i915_trace.h"
#include "i915_utils.h"
#include "intel_gt.h" #include "intel_gt.h"
#include "intel_gt_regs.h" #include "intel_gt_regs.h"
#include "intel_gtt.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 *alloc_pt_lmem(struct i915_address_space *vm, int sz)
{ {
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;

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