summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/display
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-07 13:11:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-07 13:11:27 +0000
commit34996e42f82bfd60bc2c191e5cae3c6ab233ec6c (patch)
tree62db60558cbf089714b48daeabca82bf2b20b20e /drivers/gpu/drm/i915/display
parentAdding debian version 6.8.12-1. (diff)
downloadlinux-34996e42f82bfd60bc2c191e5cae3c6ab233ec6c.tar.xz
linux-34996e42f82bfd60bc2c191e5cae3c6ab233ec6c.zip
Merging upstream version 6.9.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/i915/display')
-rw-r--r--drivers/gpu/drm/i915/display/dvo_ch7017.c2
-rw-r--r--drivers/gpu/drm/i915/display/dvo_ch7xxx.c2
-rw-r--r--drivers/gpu/drm/i915/display/dvo_ivch.c2
-rw-r--r--drivers/gpu/drm/i915/display/dvo_ns2501.c6
-rw-r--r--drivers/gpu/drm/i915/display/dvo_sil164.c2
-rw-r--r--drivers/gpu/drm/i915/display/dvo_tfp410.c2
-rw-r--r--drivers/gpu/drm/i915/display/i9xx_plane.c30
-rw-r--r--drivers/gpu/drm/i915/display/i9xx_plane.h7
-rw-r--r--drivers/gpu/drm/i915/display/i9xx_wm.c81
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c32
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_backlight.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c109
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.h8
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c426
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_crt.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc.c128
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc_state_dump.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_cursor.c63
-rw-r--r--drivers/gpu/drm/i915/display/intel_cx0_phy.c261
-rw-r--r--drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h63
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c70
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c226
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_core.h19
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c94
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs_params.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_device.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_driver.c190
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_driver.h6
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_irq.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h64
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c577
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h23
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux.c29
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_hdcp.c109
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c33
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c28
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.c811
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.h133
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c122
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h27
-rw-r--r--drivers/gpu/drm/i915/display/intel_drrs.c14
-rw-r--r--drivers/gpu/drm/i915/display/intel_drrs.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo_dev.h25
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbdev_fb.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_global_state.c137
-rw-r--r--drivers/gpu/drm/i915/display/intel_global_state.h13
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp.c296
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp.h7
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp_gsc.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp_regs.h28
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c22
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.c165
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug_irq.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_link_bw.c27
-rw-r--r--drivers/gpu/drm/i915/display/intel_link_bw.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.c182
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.h47
-rw-r--r--drivers/gpu/drm/i915/display/intel_panel.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane_initial.c255
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane_initial.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_pps.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c234
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.h6
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr_regs.h63
-rw-r--r--drivers/gpu/drm/i915/display/intel_sdvo.c230
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.c40
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_tv.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_vblank.c130
-rw-r--r--drivers/gpu/drm/i915/display/intel_vblank.h12
-rw-r--r--drivers/gpu/drm/i915/display/skl_universal_plane.c33
-rw-r--r--drivers/gpu/drm/i915/display/skl_universal_plane.h2
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark.c108
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark.h4
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark_regs.h4
88 files changed, 4281 insertions, 1733 deletions
diff --git a/drivers/gpu/drm/i915/display/dvo_ch7017.c b/drivers/gpu/drm/i915/display/dvo_ch7017.c
index 0589994dde..d0c3880d7f 100644
--- a/drivers/gpu/drm/i915/display/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/display/dvo_ch7017.c
@@ -205,7 +205,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
const char *str;
u8 val;
- priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL)
return false;
diff --git a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
index 6d948520e9..2e8e85da5a 100644
--- a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
@@ -216,7 +216,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
u8 vendor, device;
char *name, *devid;
- ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
+ ch7xxx = kzalloc(sizeof(*ch7xxx), GFP_KERNEL);
if (ch7xxx == NULL)
return false;
diff --git a/drivers/gpu/drm/i915/display/dvo_ivch.c b/drivers/gpu/drm/i915/display/dvo_ivch.c
index f43d8c610d..eef72bb3b7 100644
--- a/drivers/gpu/drm/i915/display/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/display/dvo_ivch.c
@@ -267,7 +267,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
u16 temp;
int i;
- priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL)
return false;
diff --git a/drivers/gpu/drm/i915/display/dvo_ns2501.c b/drivers/gpu/drm/i915/display/dvo_ns2501.c
index a724a87556..1df212fb00 100644
--- a/drivers/gpu/drm/i915/display/dvo_ns2501.c
+++ b/drivers/gpu/drm/i915/display/dvo_ns2501.c
@@ -476,7 +476,7 @@ static bool ns2501_init(struct intel_dvo_device *dvo,
struct ns2501_priv *ns;
unsigned char ch;
- ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
+ ns = kzalloc(sizeof(*ns), GFP_KERNEL);
if (ns == NULL)
return false;
@@ -551,7 +551,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
const struct drm_display_mode *adjusted_mode)
{
const struct ns2501_configuration *conf;
- struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
+ struct ns2501_priv *ns = dvo->dev_priv;
int mode_idx, i;
DRM_DEBUG_KMS
@@ -655,7 +655,7 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
/* set the NS2501 power state */
static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
{
- struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
+ struct ns2501_priv *ns = dvo->dev_priv;
DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
diff --git a/drivers/gpu/drm/i915/display/dvo_sil164.c b/drivers/gpu/drm/i915/display/dvo_sil164.c
index 4acc8ce29c..6c461024c8 100644
--- a/drivers/gpu/drm/i915/display/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/display/dvo_sil164.c
@@ -141,7 +141,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
struct sil164_priv *sil;
unsigned char ch;
- sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
+ sil = kzalloc(sizeof(*sil), GFP_KERNEL);
if (sil == NULL)
return false;
diff --git a/drivers/gpu/drm/i915/display/dvo_tfp410.c b/drivers/gpu/drm/i915/display/dvo_tfp410.c
index 009d65b0f3..0939e097f4 100644
--- a/drivers/gpu/drm/i915/display/dvo_tfp410.c
+++ b/drivers/gpu/drm/i915/display/dvo_tfp410.c
@@ -173,7 +173,7 @@ static bool tfp410_init(struct intel_dvo_device *dvo,
struct tfp410_priv *tfp;
int id;
- tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
+ tfp = kzalloc(sizeof(*tfp), GFP_KERNEL);
if (tfp == NULL)
return false;
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c
index 91f2bc405c..0279c8aabd 100644
--- a/drivers/gpu/drm/i915/display/i9xx_plane.c
+++ b/drivers/gpu/drm/i915/display/i9xx_plane.c
@@ -1060,3 +1060,33 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
plane_config->fb = intel_fb;
}
+
+bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc,
+ const struct intel_initial_plane_config *plane_config)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+ const struct intel_plane_state *plane_state =
+ to_intel_plane_state(plane->base.state);
+ enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+ u32 base;
+
+ if (!plane_state->uapi.visible)
+ return false;
+
+ base = intel_plane_ggtt_offset(plane_state);
+
+ /*
+ * We may have moved the surface to a different
+ * part of ggtt, make the plane aware of that.
+ */
+ if (plane_config->base == base)
+ return false;
+
+ if (DISPLAY_VER(dev_priv) >= 4)
+ intel_de_write(dev_priv, DSPSURF(i9xx_plane), base);
+ else
+ intel_de_write(dev_priv, DSPADDR(i9xx_plane), base);
+
+ return true;
+}
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h
index b3d724a144..0ca12d1e68 100644
--- a/drivers/gpu/drm/i915/display/i9xx_plane.h
+++ b/drivers/gpu/drm/i915/display/i9xx_plane.h
@@ -26,6 +26,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe);
void i9xx_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config);
+bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc,
+ const struct intel_initial_plane_config *plane_config);
#else
static inline unsigned int i965_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
@@ -46,6 +48,11 @@ static inline void i9xx_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
}
+static inline bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc,
+ const struct intel_initial_plane_config *plane_config)
+{
+ return false;
+}
#endif
#endif
diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c
index 11ca9572e8..628e7192eb 100644
--- a/drivers/gpu/drm/i915/display/i9xx_wm.c
+++ b/drivers/gpu/drm/i915/display/i9xx_wm.c
@@ -70,26 +70,25 @@ static const struct cxsr_latency cxsr_latency_table[] = {
{0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */
};
-static const struct cxsr_latency *intel_get_cxsr_latency(bool is_desktop,
- bool is_ddr3,
- int fsb,
- int mem)
+static const struct cxsr_latency *intel_get_cxsr_latency(struct drm_i915_private *i915)
{
- const struct cxsr_latency *latency;
int i;
- if (fsb == 0 || mem == 0)
+ if (i915->fsb_freq == 0 || i915->mem_freq == 0)
return NULL;
for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
- latency = &cxsr_latency_table[i];
+ const struct cxsr_latency *latency = &cxsr_latency_table[i];
+ bool is_desktop = !IS_MOBILE(i915);
+
if (is_desktop == latency->is_desktop &&
- is_ddr3 == latency->is_ddr3 &&
- fsb == latency->fsb_freq && mem == latency->mem_freq)
+ i915->is_ddr3 == latency->is_ddr3 &&
+ i915->fsb_freq == latency->fsb_freq &&
+ i915->mem_freq == latency->mem_freq)
return latency;
}
- DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
+ drm_dbg_kms(&i915->drm, "Unknown FSB/MEM found, disable CxSR\n");
return NULL;
}
@@ -525,6 +524,7 @@ static unsigned int intel_wm_method2(unsigned int pixel_rate,
/**
* intel_calculate_wm - calculate watermark level
+ * @i915: the device
* @pixel_rate: pixel clock
* @wm: chip FIFO params
* @fifo_size: size of the FIFO buffer
@@ -542,7 +542,8 @@ static unsigned int intel_wm_method2(unsigned int pixel_rate,
* past the watermark point. If the FIFO drains completely, a FIFO underrun
* will occur, and a display engine hang could result.
*/
-static unsigned int intel_calculate_wm(int pixel_rate,
+static unsigned int intel_calculate_wm(struct drm_i915_private *i915,
+ int pixel_rate,
const struct intel_watermark_params *wm,
int fifo_size, int cpp,
unsigned int latency_ns)
@@ -559,10 +560,10 @@ static unsigned int intel_calculate_wm(int pixel_rate,
latency_ns / 100);
entries = DIV_ROUND_UP(entries, wm->cacheline_size) +
wm->guard_size;
- DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries);
+ drm_dbg_kms(&i915->drm, "FIFO entries required for mode: %d\n", entries);
wm_size = fifo_size - entries;
- DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
+ drm_dbg_kms(&i915->drm, "FIFO watermark level: %d\n", wm_size);
/* Don't promote wm_size to unsigned... */
if (wm_size > wm->max_wm)
@@ -634,10 +635,7 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
u32 reg;
unsigned int wm;
- latency = intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
- dev_priv->is_ddr3,
- dev_priv->fsb_freq,
- dev_priv->mem_freq);
+ latency = intel_get_cxsr_latency(dev_priv);
if (!latency) {
drm_dbg_kms(&dev_priv->drm,
"Unknown FSB/MEM found, disable CxSR\n");
@@ -653,7 +651,8 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
int cpp = fb->format->cpp[0];
/* Display SR */
- wm = intel_calculate_wm(pixel_rate, &pnv_display_wm,
+ wm = intel_calculate_wm(dev_priv, pixel_rate,
+ &pnv_display_wm,
pnv_display_wm.fifo_size,
cpp, latency->display_sr);
reg = intel_uncore_read(&dev_priv->uncore, DSPFW1);
@@ -663,20 +662,23 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
drm_dbg_kms(&dev_priv->drm, "DSPFW1 register is %x\n", reg);
/* cursor SR */
- wm = intel_calculate_wm(pixel_rate, &pnv_cursor_wm,
+ wm = intel_calculate_wm(dev_priv, pixel_rate,
+ &pnv_cursor_wm,
pnv_display_wm.fifo_size,
4, latency->cursor_sr);
intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_CURSOR_SR_MASK,
FW_WM(wm, CURSOR_SR));
/* Display HPLL off SR */
- wm = intel_calculate_wm(pixel_rate, &pnv_display_hplloff_wm,
+ wm = intel_calculate_wm(dev_priv, pixel_rate,
+ &pnv_display_hplloff_wm,
pnv_display_hplloff_wm.fifo_size,
cpp, latency->display_hpll_disable);
intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_HPLL_SR_MASK, FW_WM(wm, HPLL_SR));
/* cursor HPLL off SR */
- wm = intel_calculate_wm(pixel_rate, &pnv_cursor_hplloff_wm,
+ wm = intel_calculate_wm(dev_priv, pixel_rate,
+ &pnv_cursor_hplloff_wm,
pnv_display_hplloff_wm.fifo_size,
4, latency->cursor_hpll_disable);
reg = intel_uncore_read(&dev_priv->uncore, DSPFW3);
@@ -2124,7 +2126,7 @@ static void i9xx_update_wm(struct drm_i915_private *dev_priv)
else
cpp = fb->format->cpp[0];
- planea_wm = intel_calculate_wm(crtc->config->pixel_rate,
+ planea_wm = intel_calculate_wm(dev_priv, crtc->config->pixel_rate,
wm_info, fifo_size, cpp,
pessimal_latency_ns);
} else {
@@ -2151,7 +2153,7 @@ static void i9xx_update_wm(struct drm_i915_private *dev_priv)
else
cpp = fb->format->cpp[0];
- planeb_wm = intel_calculate_wm(crtc->config->pixel_rate,
+ planeb_wm = intel_calculate_wm(dev_priv, crtc->config->pixel_rate,
wm_info, fifo_size, cpp,
pessimal_latency_ns);
} else {
@@ -2245,7 +2247,7 @@ static void i845_update_wm(struct drm_i915_private *dev_priv)
if (crtc == NULL)
return;
- planea_wm = intel_calculate_wm(crtc->config->pixel_rate,
+ planea_wm = intel_calculate_wm(dev_priv, crtc->config->pixel_rate,
&i845_wm_info,
i845_get_fifo_size(dev_priv, PLANE_A),
4, pessimal_latency_ns);
@@ -2531,7 +2533,8 @@ static void ilk_compute_wm_reg_maximums(const struct drm_i915_private *dev_priv,
max->fbc = ilk_fbc_wm_reg_max(dev_priv);
}
-static bool ilk_validate_wm_level(int level,
+static bool ilk_validate_wm_level(struct drm_i915_private *i915,
+ int level,
const struct ilk_wm_maximums *max,
struct intel_wm_level *result)
{
@@ -2554,14 +2557,17 @@ static bool ilk_validate_wm_level(int level,
*/
if (level == 0 && !result->enable) {
if (result->pri_val > max->pri)
- DRM_DEBUG_KMS("Primary WM%d too large %u (max %u)\n",
- level, result->pri_val, max->pri);
+ drm_dbg_kms(&i915->drm,
+ "Primary WM%d too large %u (max %u)\n",
+ level, result->pri_val, max->pri);
if (result->spr_val > max->spr)
- DRM_DEBUG_KMS("Sprite WM%d too large %u (max %u)\n",
- level, result->spr_val, max->spr);
+ drm_dbg_kms(&i915->drm,
+ "Sprite WM%d too large %u (max %u)\n",
+ level, result->spr_val, max->spr);
if (result->cur_val > max->cur)
- DRM_DEBUG_KMS("Cursor WM%d too large %u (max %u)\n",
- level, result->cur_val, max->cur);
+ drm_dbg_kms(&i915->drm,
+ "Cursor WM%d too large %u (max %u)\n",
+ level, result->cur_val, max->cur);
result->pri_val = min_t(u32, result->pri_val, max->pri);
result->spr_val = min_t(u32, result->spr_val, max->spr);
@@ -2761,7 +2767,7 @@ static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
}
}
-static bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv,
+static bool ilk_validate_pipe_wm(struct drm_i915_private *dev_priv,
struct intel_pipe_wm *pipe_wm)
{
/* LP0 watermark maximums depend on this pipe alone */
@@ -2776,7 +2782,7 @@ static bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv,
ilk_compute_wm_maximums(dev_priv, 0, &config, INTEL_DDB_PART_1_2, &max);
/* At least LP0 must be valid */
- if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) {
+ if (!ilk_validate_wm_level(dev_priv, 0, &max, &pipe_wm->wm[0])) {
drm_dbg_kms(&dev_priv->drm, "LP0 watermark invalid\n");
return false;
}
@@ -2845,7 +2851,7 @@ static int ilk_compute_pipe_wm(struct intel_atomic_state *state,
* register maximums since such watermarks are
* always invalid.
*/
- if (!ilk_validate_wm_level(level, &max, wm)) {
+ if (!ilk_validate_wm_level(dev_priv, level, &max, wm)) {
memset(wm, 0, sizeof(*wm));
break;
}
@@ -2976,7 +2982,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv,
if (level > last_enabled_level)
wm->enable = false;
- else if (!ilk_validate_wm_level(level, max, wm))
+ else if (!ilk_validate_wm_level(dev_priv, level, max, wm))
/* make sure all following levels get disabled */
last_enabled_level = level - 1;
@@ -4016,10 +4022,7 @@ void i9xx_wm_init(struct drm_i915_private *dev_priv)
g4x_setup_wm_latency(dev_priv);
dev_priv->display.funcs.wm = &g4x_wm_funcs;
} else if (IS_PINEVIEW(dev_priv)) {
- if (!intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
- dev_priv->is_ddr3,
- dev_priv->fsb_freq,
- dev_priv->mem_freq)) {
+ if (!intel_get_cxsr_latency(dev_priv)) {
drm_info(&dev_priv->drm,
"failed to find known CxSR latency "
"(found ddr%s fsb freq %d, mem freq %d), "
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index ec0d5168b5..2bb270f829 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -29,6 +29,7 @@
* See intel_atomic_plane.c for the plane-specific atomic functionality.
*/
+#include <drm/display/drm_dp_tunnel.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
@@ -38,6 +39,7 @@
#include "intel_atomic.h"
#include "intel_cdclk.h"
#include "intel_display_types.h"
+#include "intel_dp_tunnel.h"
#include "intel_global_state.h"
#include "intel_hdcp.h"
#include "intel_psr.h"
@@ -258,6 +260,10 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
if (crtc_state->post_csc_lut)
drm_property_blob_get(crtc_state->post_csc_lut);
+ if (crtc_state->dp_tunnel_ref.tunnel)
+ drm_dp_tunnel_ref_get(crtc_state->dp_tunnel_ref.tunnel,
+ &crtc_state->dp_tunnel_ref);
+
crtc_state->update_pipe = false;
crtc_state->update_m_n = false;
crtc_state->update_lrr = false;
@@ -309,6 +315,8 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
__drm_atomic_helper_crtc_destroy_state(&crtc_state->uapi);
intel_crtc_free_hw_state(crtc_state);
+ if (crtc_state->dp_tunnel_ref.tunnel)
+ drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
kfree(crtc_state);
}
@@ -344,6 +352,8 @@ void intel_atomic_state_clear(struct drm_atomic_state *s)
/* state->internal not reset on purpose */
state->dpll_set = state->modeset = false;
+
+ intel_dp_tunnel_atomic_cleanup_inherited_state(state);
}
struct intel_crtc_state *
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index 06c2455bdd..76d77d5a04 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -217,6 +217,9 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state,
int width, height;
unsigned int rel_data_rate;
+ if (plane->id == PLANE_CURSOR)
+ return 0;
+
if (!plane_state->uapi.visible)
return 0;
@@ -244,9 +247,6 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state,
rel_data_rate = width * height * fb->format->cpp[color_plane];
- if (plane->id == PLANE_CURSOR)
- return rel_data_rate;
-
return intel_adjusted_rate(&plane_state->uapi.src,
&plane_state->uapi.dst,
rel_data_rate);
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index ed81e1466c..40e7d86267 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -1252,17 +1252,6 @@ static const struct component_ops i915_audio_component_bind_ops = {
static void i915_audio_component_init(struct drm_i915_private *i915)
{
u32 aud_freq, aud_freq_init;
- int ret;
-
- ret = component_add_typed(i915->drm.dev,
- &i915_audio_component_bind_ops,
- I915_COMPONENT_AUDIO);
- if (ret < 0) {
- drm_err(&i915->drm,
- "failed to add audio component (%d)\n", ret);
- /* continue with reduced functionality */
- return;
- }
if (DISPLAY_VER(i915) >= 9) {
aud_freq_init = intel_de_read(i915, AUD_FREQ_CNTRL);
@@ -1285,6 +1274,21 @@ static void i915_audio_component_init(struct drm_i915_private *i915)
/* init with current cdclk */
intel_audio_cdclk_change_post(i915);
+}
+
+static void i915_audio_component_register(struct drm_i915_private *i915)
+{
+ int ret;
+
+ ret = component_add_typed(i915->drm.dev,
+ &i915_audio_component_bind_ops,
+ I915_COMPONENT_AUDIO);
+ if (ret < 0) {
+ drm_err(&i915->drm,
+ "failed to add audio component (%d)\n", ret);
+ /* continue with reduced functionality */
+ return;
+ }
i915->display.audio.component_registered = true;
}
@@ -1317,6 +1321,12 @@ void intel_audio_init(struct drm_i915_private *i915)
i915_audio_component_init(i915);
}
+void intel_audio_register(struct drm_i915_private *i915)
+{
+ if (!i915->display.audio.lpe.platdev)
+ i915_audio_component_register(i915);
+}
+
/**
* intel_audio_deinit() - deinitialize the audio driver
* @i915: the i915 drm device private data
diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h
index 9327954b80..576c061d72 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.h
+++ b/drivers/gpu/drm/i915/display/intel_audio.h
@@ -28,6 +28,7 @@ void intel_audio_codec_get_config(struct intel_encoder *encoder,
void intel_audio_cdclk_change_pre(struct drm_i915_private *dev_priv);
void intel_audio_cdclk_change_post(struct drm_i915_private *dev_priv);
void intel_audio_init(struct drm_i915_private *dev_priv);
+void intel_audio_register(struct drm_i915_private *i915);
void intel_audio_deinit(struct drm_i915_private *dev_priv);
void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c
index 3f3cd944a1..1946d7fb3c 100644
--- a/drivers/gpu/drm/i915/display/intel_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_backlight.c
@@ -1465,7 +1465,7 @@ static bool cnp_backlight_controller_is_valid(struct drm_i915_private *i915, int
if (controller == 1 &&
INTEL_PCH_TYPE(i915) >= PCH_ICP &&
- INTEL_PCH_TYPE(i915) < PCH_MTP)
+ INTEL_PCH_TYPE(i915) <= PCH_ADP)
return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT;
return true;
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index c36633d7dd..7d1e443f97 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -1748,7 +1748,8 @@ parse_mipi_config(struct drm_i915_private *i915,
/* Find the sequence block and size for the given panel. */
static const u8 *
-find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
+find_panel_sequence_block(struct drm_i915_private *i915,
+ const struct bdb_mipi_sequence *sequence,
u16 panel_id, u32 *seq_size)
{
u32 total = get_blocksize(sequence);
@@ -1765,7 +1766,7 @@ find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) {
if (index + header_size > total) {
- DRM_ERROR("Invalid sequence block (header)\n");
+ drm_err(&i915->drm, "Invalid sequence block (header)\n");
return NULL;
}
@@ -1778,7 +1779,7 @@ find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
index += header_size;
if (index + current_size > total) {
- DRM_ERROR("Invalid sequence block\n");
+ drm_err(&i915->drm, "Invalid sequence block\n");
return NULL;
}
@@ -1790,12 +1791,13 @@ find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
index += current_size;
}
- DRM_ERROR("Sequence block detected but no valid configuration\n");
+ drm_err(&i915->drm, "Sequence block detected but no valid configuration\n");
return NULL;
}
-static int goto_next_sequence(const u8 *data, int index, int total)
+static int goto_next_sequence(struct drm_i915_private *i915,
+ const u8 *data, int index, int total)
{
u16 len;
@@ -1825,7 +1827,7 @@ static int goto_next_sequence(const u8 *data, int index, int total)
len = *(data + index + 6) + 7;
break;
default:
- DRM_ERROR("Unknown operation byte\n");
+ drm_err(&i915->drm, "Unknown operation byte\n");
return 0;
}
}
@@ -1833,7 +1835,8 @@ static int goto_next_sequence(const u8 *data, int index, int total)
return 0;
}
-static int goto_next_sequence_v3(const u8 *data, int index, int total)
+static int goto_next_sequence_v3(struct drm_i915_private *i915,
+ const u8 *data, int index, int total)
{
int seq_end;
u16 len;
@@ -1844,7 +1847,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
* checking on the structure.
*/
if (total < 5) {
- DRM_ERROR("Too small sequence size\n");
+ drm_err(&i915->drm, "Too small sequence size\n");
return 0;
}
@@ -1861,7 +1864,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
seq_end = index + size_of_sequence;
if (seq_end > total) {
- DRM_ERROR("Invalid sequence size\n");
+ drm_err(&i915->drm, "Invalid sequence size\n");
return 0;
}
@@ -1871,7 +1874,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
if (operation_byte == MIPI_SEQ_ELEM_END) {
if (index != seq_end) {
- DRM_ERROR("Invalid element structure\n");
+ drm_err(&i915->drm, "Invalid element structure\n");
return 0;
}
return index;
@@ -1893,8 +1896,8 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
case MIPI_SEQ_ELEM_PMIC:
break;
default:
- DRM_ERROR("Unknown operation byte %u\n",
- operation_byte);
+ drm_err(&i915->drm, "Unknown operation byte %u\n",
+ operation_byte);
break;
}
}
@@ -2050,7 +2053,7 @@ parse_mipi_sequence(struct drm_i915_private *i915,
drm_dbg(&i915->drm, "Found MIPI sequence block v%u\n",
sequence->version);
- seq_data = find_panel_sequence_block(sequence, panel_type, &seq_size);
+ seq_data = find_panel_sequence_block(i915, sequence, panel_type, &seq_size);
if (!seq_data)
return;
@@ -2078,9 +2081,9 @@ parse_mipi_sequence(struct drm_i915_private *i915,
panel->vbt.dsi.sequence[seq_id] = data + index;
if (sequence->version >= 3)
- index = goto_next_sequence_v3(data, index, seq_size);
+ index = goto_next_sequence_v3(i915, data, index, seq_size);
else
- index = goto_next_sequence(data, index, seq_size);
+ index = goto_next_sequence(i915, data, index, seq_size);
if (!index) {
drm_err(&i915->drm, "Invalid sequence %u\n",
seq_id);
@@ -2155,12 +2158,13 @@ parse_compression_parameters(struct drm_i915_private *i915)
}
}
-static u8 translate_iboost(u8 val)
+static u8 translate_iboost(struct drm_i915_private *i915, u8 val)
{
static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
if (val >= ARRAY_SIZE(mapping)) {
- DRM_DEBUG_KMS("Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
+ drm_dbg_kms(&i915->drm,
+ "Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
return 0;
}
return mapping[val];
@@ -2224,8 +2228,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
if (IS_DGFX(i915))
return vbt_pin;
- if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) ||
- IS_ALDERLAKE_P(i915)) {
+ if (INTEL_PCH_TYPE(i915) >= PCH_MTL || IS_ALDERLAKE_P(i915)) {
ddc_pin_map = adlp_ddc_pin_map;
n_entries = ARRAY_SIZE(adlp_ddc_pin_map);
} else if (IS_ALDERLAKE_S(i915)) {
@@ -2918,12 +2921,14 @@ static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt)
/**
* intel_bios_is_valid_vbt - does the given buffer contain a valid VBT
+ * @i915: the device
* @buf: pointer to a buffer to validate
* @size: size of the buffer
*
* Returns true on valid VBT.
*/
-bool intel_bios_is_valid_vbt(const void *buf, size_t size)
+bool intel_bios_is_valid_vbt(struct drm_i915_private *i915,
+ const void *buf, size_t size)
{
const struct vbt_header *vbt = buf;
const struct bdb_header *bdb;
@@ -2932,17 +2937,17 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size)
return false;
if (sizeof(struct vbt_header) > size) {
- DRM_DEBUG_DRIVER("VBT header incomplete\n");
+ drm_dbg_kms(&i915->drm, "VBT header incomplete\n");
return false;
}
if (memcmp(vbt->signature, "$VBT", 4)) {
- DRM_DEBUG_DRIVER("VBT invalid signature\n");
+ drm_dbg_kms(&i915->drm, "VBT invalid signature\n");
return false;
}
if (vbt->vbt_size > size) {
- DRM_DEBUG_DRIVER("VBT incomplete (vbt_size overflows)\n");
+ drm_dbg_kms(&i915->drm, "VBT incomplete (vbt_size overflows)\n");
return false;
}
@@ -2952,13 +2957,13 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size)
vbt->bdb_offset,
sizeof(struct bdb_header),
size)) {
- DRM_DEBUG_DRIVER("BDB header incomplete\n");
+ drm_dbg_kms(&i915->drm, "BDB header incomplete\n");
return false;
}
bdb = get_bdb_header(vbt);
if (range_overflows_t(size_t, vbt->bdb_offset, bdb->bdb_size, size)) {
- DRM_DEBUG_DRIVER("BDB incomplete\n");
+ drm_dbg_kms(&i915->drm, "BDB incomplete\n");
return false;
}
@@ -3010,7 +3015,7 @@ static struct vbt_header *spi_oprom_get_vbt(struct drm_i915_private *i915)
for (count = 0; count < vbt_size; count += 4)
*(vbt + store++) = intel_spi_read(&i915->uncore, found + count);
- if (!intel_bios_is_valid_vbt(vbt, vbt_size))
+ if (!intel_bios_is_valid_vbt(i915, vbt, vbt_size))
goto err_free_vbt;
drm_dbg_kms(&i915->drm, "Found valid VBT in SPI flash\n");
@@ -3067,7 +3072,7 @@ static struct vbt_header *oprom_get_vbt(struct drm_i915_private *i915)
memcpy_fromio(vbt, p, vbt_size);
- if (!intel_bios_is_valid_vbt(vbt, vbt_size))
+ if (!intel_bios_is_valid_vbt(i915, vbt, vbt_size))
goto err_free_vbt;
pci_unmap_rom(pdev, oprom);
@@ -3094,7 +3099,7 @@ err_unmap_oprom:
*/
void intel_bios_init(struct drm_i915_private *i915)
{
- const struct vbt_header *vbt = i915->display.opregion.vbt;
+ const struct vbt_header *vbt;
struct vbt_header *oprom_vbt = NULL;
const struct bdb_header *bdb;
@@ -3109,6 +3114,8 @@ void intel_bios_init(struct drm_i915_private *i915)
init_vbt_defaults(i915);
+ vbt = intel_opregion_get_vbt(i915, NULL);
+
/*
* If the OpRegion does not have VBT, look in SPI flash through MMIO or
* PCI mapping
@@ -3326,7 +3333,7 @@ bool intel_bios_is_lvds_present(struct drm_i915_private *i915, u8 *i2c_pin)
* additional data. Trust that if the VBT was written into
* the OpRegion then they have validated the LVDS's existence.
*/
- if (i915->display.opregion.vbt)
+ if (intel_opregion_get_vbt(i915, NULL))
return true;
}
@@ -3420,6 +3427,7 @@ static void fill_dsc(struct intel_crtc_state *crtc_state,
struct dsc_compression_parameters_entry *dsc,
int dsc_max_bpc)
{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
int bpc = 8;
@@ -3433,8 +3441,8 @@ static void fill_dsc(struct intel_crtc_state *crtc_state,
else if (dsc->support_8bpc && dsc_max_bpc >= 8)
bpc = 8;
else
- DRM_DEBUG_KMS("VBT: Unsupported BPC %d for DCS\n",
- dsc_max_bpc);
+ drm_dbg_kms(&i915->drm, "VBT: Unsupported BPC %d for DCS\n",
+ dsc_max_bpc);
crtc_state->pipe_bpp = bpc * 3;
@@ -3454,16 +3462,16 @@ static void fill_dsc(struct intel_crtc_state *crtc_state,
} else {
/* FIXME */
if (!(dsc->slices_per_line & BIT(0)))
- DRM_DEBUG_KMS("VBT: Unsupported DSC slice count for DSI\n");
+ drm_dbg_kms(&i915->drm, "VBT: Unsupported DSC slice count for DSI\n");
crtc_state->dsc.slice_count = 1;
}
if (crtc_state->hw.adjusted_mode.crtc_hdisplay %
crtc_state->dsc.slice_count != 0)
- DRM_DEBUG_KMS("VBT: DSC hdisplay %d not divisible by slice count %d\n",
- crtc_state->hw.adjusted_mode.crtc_hdisplay,
- crtc_state->dsc.slice_count);
+ drm_dbg_kms(&i915->drm, "VBT: DSC hdisplay %d not divisible by slice count %d\n",
+ crtc_state->hw.adjusted_mode.crtc_hdisplay,
+ crtc_state->dsc.slice_count);
/*
* The VBT rc_buffer_block_size and rc_buffer_size definitions
@@ -3619,7 +3627,7 @@ int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata)
if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost)
return 0;
- return translate_iboost(devdata->child.dp_iboost_level);
+ return translate_iboost(devdata->i915, devdata->child.dp_iboost_level);
}
int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata)
@@ -3627,7 +3635,7 @@ int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata)
if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost)
return 0;
- return translate_iboost(devdata->child.hdmi_iboost_level);
+ return translate_iboost(devdata->i915, devdata->child.hdmi_iboost_level);
}
int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata)
@@ -3680,3 +3688,30 @@ void intel_bios_for_each_encoder(struct drm_i915_private *i915,
list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
func(i915, devdata);
}
+
+static int intel_bios_vbt_show(struct seq_file *m, void *unused)
+{
+ struct drm_i915_private *i915 = m->private;
+ const void *vbt;
+ size_t vbt_size;
+
+ /*
+ * FIXME: VBT might originate from other places than opregion, and then
+ * this would be incorrect.
+ */
+ vbt = intel_opregion_get_vbt(i915, &vbt_size);
+ if (vbt)
+ seq_write(m, vbt, vbt_size);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(intel_bios_vbt);
+
+void intel_bios_debugfs_register(struct drm_i915_private *i915)
+{
+ struct drm_minor *minor = i915->drm.primary;
+
+ debugfs_create_file("i915_vbt", 0444, minor->debugfs_root,
+ i915, &intel_bios_vbt_fops);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index 49e24b7cf6..06a51be4af 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -242,17 +242,15 @@ void intel_bios_init_panel_late(struct drm_i915_private *dev_priv,
const struct drm_edid *drm_edid);
void intel_bios_fini_panel(struct intel_panel *panel);
void intel_bios_driver_remove(struct drm_i915_private *dev_priv);
-bool intel_bios_is_valid_vbt(const void *buf, size_t size);
+bool intel_bios_is_valid_vbt(struct drm_i915_private *i915,
+ const void *buf, size_t size);
bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv);
bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin);
bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port);
-bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port);
bool intel_bios_is_dsi_present(struct drm_i915_private *dev_priv, enum port *port);
bool intel_bios_get_dsc_params(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
int dsc_max_bpc);
-bool intel_bios_port_supports_typec_usb(struct drm_i915_private *i915, enum port port);
-bool intel_bios_port_supports_tbt(struct drm_i915_private *i915, enum port port);
const struct intel_bios_encoder_data *
intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port);
@@ -283,4 +281,6 @@ void intel_bios_for_each_encoder(struct drm_i915_private *i915,
void (*func)(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata));
+void intel_bios_debugfs_register(struct drm_i915_private *i915);
+
#endif /* _INTEL_BIOS_H_ */
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 7ba30d26f6..f672bfd70d 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -63,6 +63,16 @@
* DMC will not change the active CDCLK frequency however, so that part
* will still be performed by the driver directly.
*
+ * Several methods exist to change the CDCLK frequency, which ones are
+ * supported depends on the platform:
+ *
+ * - Full PLL disable + re-enable with new VCO frequency. Pipes must be inactive.
+ * - CD2X divider update. Single pipe can be active as the divider update
+ * can be synchronized with the pipe's start of vblank.
+ * - Crawl the PLL smoothly to the new VCO frequency. Pipes can be active.
+ * - Squash waveform update. Pipes can be active.
+ * - Crawl and squash can also be done back to back. Pipes can be active.
+ *
* RAWCLK is a fixed frequency clock, often used by various auxiliary
* blocks such as AUX CH or backlight PWM. Hence the only thing we
* really need to know about RAWCLK is its frequency so that various
@@ -1227,186 +1237,199 @@ struct intel_cdclk_vals {
u32 cdclk;
u16 refclk;
u16 waveform;
- u8 divider; /* CD2X divider * 2 */
u8 ratio;
};
static const struct intel_cdclk_vals bxt_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 144000, .divider = 8, .ratio = 60 },
- { .refclk = 19200, .cdclk = 288000, .divider = 4, .ratio = 60 },
- { .refclk = 19200, .cdclk = 384000, .divider = 3, .ratio = 60 },
- { .refclk = 19200, .cdclk = 576000, .divider = 2, .ratio = 60 },
- { .refclk = 19200, .cdclk = 624000, .divider = 2, .ratio = 65 },
+ { .refclk = 19200, .cdclk = 144000, .ratio = 60 },
+ { .refclk = 19200, .cdclk = 288000, .ratio = 60 },
+ { .refclk = 19200, .cdclk = 384000, .ratio = 60 },
+ { .refclk = 19200, .cdclk = 576000, .ratio = 60 },
+ { .refclk = 19200, .cdclk = 624000, .ratio = 65 },
{}
};
static const struct intel_cdclk_vals glk_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 79200, .divider = 8, .ratio = 33 },
- { .refclk = 19200, .cdclk = 158400, .divider = 4, .ratio = 33 },
- { .refclk = 19200, .cdclk = 316800, .divider = 2, .ratio = 33 },
+ { .refclk = 19200, .cdclk = 79200, .ratio = 33 },
+ { .refclk = 19200, .cdclk = 158400, .ratio = 33 },
+ { .refclk = 19200, .cdclk = 316800, .ratio = 33 },
{}
};
static const struct intel_cdclk_vals icl_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 172800, .divider = 2, .ratio = 18 },
- { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 },
- { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 },
- { .refclk = 19200, .cdclk = 326400, .divider = 4, .ratio = 68 },
- { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 },
- { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 },
-
- { .refclk = 24000, .cdclk = 180000, .divider = 2, .ratio = 15 },
- { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 },
- { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
- { .refclk = 24000, .cdclk = 324000, .divider = 4, .ratio = 54 },
- { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
- { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 },
-
- { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 9 },
- { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 },
- { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 },
- { .refclk = 38400, .cdclk = 326400, .divider = 4, .ratio = 34 },
- { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 },
+ { .refclk = 19200, .cdclk = 172800, .ratio = 18 },
+ { .refclk = 19200, .cdclk = 192000, .ratio = 20 },
+ { .refclk = 19200, .cdclk = 307200, .ratio = 32 },
+ { .refclk = 19200, .cdclk = 326400, .ratio = 68 },
+ { .refclk = 19200, .cdclk = 556800, .ratio = 58 },
+ { .refclk = 19200, .cdclk = 652800, .ratio = 68 },
+
+ { .refclk = 24000, .cdclk = 180000, .ratio = 15 },
+ { .refclk = 24000, .cdclk = 192000, .ratio = 16 },
+ { .refclk = 24000, .cdclk = 312000, .ratio = 26 },
+ { .refclk = 24000, .cdclk = 324000, .ratio = 54 },
+ { .refclk = 24000, .cdclk = 552000, .ratio = 46 },
+ { .refclk = 24000, .cdclk = 648000, .ratio = 54 },
+
+ { .refclk = 38400, .cdclk = 172800, .ratio = 9 },
+ { .refclk = 38400, .cdclk = 192000, .ratio = 10 },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 16 },
+ { .refclk = 38400, .cdclk = 326400, .ratio = 34 },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 29 },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34 },
{}
};
static const struct intel_cdclk_vals rkl_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 172800, .divider = 4, .ratio = 36 },
- { .refclk = 19200, .cdclk = 192000, .divider = 4, .ratio = 40 },
- { .refclk = 19200, .cdclk = 307200, .divider = 4, .ratio = 64 },
- { .refclk = 19200, .cdclk = 326400, .divider = 8, .ratio = 136 },
- { .refclk = 19200, .cdclk = 556800, .divider = 4, .ratio = 116 },
- { .refclk = 19200, .cdclk = 652800, .divider = 4, .ratio = 136 },
-
- { .refclk = 24000, .cdclk = 180000, .divider = 4, .ratio = 30 },
- { .refclk = 24000, .cdclk = 192000, .divider = 4, .ratio = 32 },
- { .refclk = 24000, .cdclk = 312000, .divider = 4, .ratio = 52 },
- { .refclk = 24000, .cdclk = 324000, .divider = 8, .ratio = 108 },
- { .refclk = 24000, .cdclk = 552000, .divider = 4, .ratio = 92 },
- { .refclk = 24000, .cdclk = 648000, .divider = 4, .ratio = 108 },
-
- { .refclk = 38400, .cdclk = 172800, .divider = 4, .ratio = 18 },
- { .refclk = 38400, .cdclk = 192000, .divider = 4, .ratio = 20 },
- { .refclk = 38400, .cdclk = 307200, .divider = 4, .ratio = 32 },
- { .refclk = 38400, .cdclk = 326400, .divider = 8, .ratio = 68 },
- { .refclk = 38400, .cdclk = 556800, .divider = 4, .ratio = 58 },
- { .refclk = 38400, .cdclk = 652800, .divider = 4, .ratio = 68 },
+ { .refclk = 19200, .cdclk = 172800, .ratio = 36 },
+ { .refclk = 19200, .cdclk = 192000, .ratio = 40 },
+ { .refclk = 19200, .cdclk = 307200, .ratio = 64 },
+ { .refclk = 19200, .cdclk = 326400, .ratio = 136 },
+ { .refclk = 19200, .cdclk = 556800, .ratio = 116 },
+ { .refclk = 19200, .cdclk = 652800, .ratio = 136 },
+
+ { .refclk = 24000, .cdclk = 180000, .ratio = 30 },
+ { .refclk = 24000, .cdclk = 192000, .ratio = 32 },
+ { .refclk = 24000, .cdclk = 312000, .ratio = 52 },
+ { .refclk = 24000, .cdclk = 324000, .ratio = 108 },
+ { .refclk = 24000, .cdclk = 552000, .ratio = 92 },
+ { .refclk = 24000, .cdclk = 648000, .ratio = 108 },
+
+ { .refclk = 38400, .cdclk = 172800, .ratio = 18 },
+ { .refclk = 38400, .cdclk = 192000, .ratio = 20 },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 32 },
+ { .refclk = 38400, .cdclk = 326400, .ratio = 68 },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 58 },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 68 },
{}
};
static const struct intel_cdclk_vals adlp_a_step_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 },
- { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 },
- { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 },
+ { .refclk = 19200, .cdclk = 307200, .ratio = 32 },
+ { .refclk = 19200, .cdclk = 556800, .ratio = 58 },
+ { .refclk = 19200, .cdclk = 652800, .ratio = 68 },
- { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
- { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
- { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 },
+ { .refclk = 24000, .cdclk = 312000, .ratio = 26 },
+ { .refclk = 24000, .cdclk = 552000, .ratio = 46 },
+ { .refclk = 24400, .cdclk = 648000, .ratio = 54 },
- { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 },
- { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 16 },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 29 },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34 },
{}
};
static const struct intel_cdclk_vals adlp_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 },
- { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 },
- { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 },
- { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 },
- { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 },
-
- { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 },
- { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 },
- { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
- { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
- { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 },
-
- { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 },
- { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 },
- { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 },
- { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 },
+ { .refclk = 19200, .cdclk = 172800, .ratio = 27 },
+ { .refclk = 19200, .cdclk = 192000, .ratio = 20 },
+ { .refclk = 19200, .cdclk = 307200, .ratio = 32 },
+ { .refclk = 19200, .cdclk = 556800, .ratio = 58 },
+ { .refclk = 19200, .cdclk = 652800, .ratio = 68 },
+
+ { .refclk = 24000, .cdclk = 176000, .ratio = 22 },
+ { .refclk = 24000, .cdclk = 192000, .ratio = 16 },
+ { .refclk = 24000, .cdclk = 312000, .ratio = 26 },
+ { .refclk = 24000, .cdclk = 552000, .ratio = 46 },
+ { .refclk = 24000, .cdclk = 648000, .ratio = 54 },
+
+ { .refclk = 38400, .cdclk = 179200, .ratio = 14 },
+ { .refclk = 38400, .cdclk = 192000, .ratio = 10 },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 16 },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 29 },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34 },
{}
};
static const struct intel_cdclk_vals rplu_cdclk_table[] = {
- { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 },
- { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 },
- { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 },
- { .refclk = 19200, .cdclk = 480000, .divider = 2, .ratio = 50 },
- { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 },
- { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 },
-
- { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 },
- { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 },
- { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
- { .refclk = 24000, .cdclk = 480000, .divider = 2, .ratio = 40 },
- { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
- { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 },
-
- { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 },
- { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 },
- { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 },
- { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25 },
- { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 },
+ { .refclk = 19200, .cdclk = 172800, .ratio = 27 },
+ { .refclk = 19200, .cdclk = 192000, .ratio = 20 },
+ { .refclk = 19200, .cdclk = 307200, .ratio = 32 },
+ { .refclk = 19200, .cdclk = 480000, .ratio = 50 },
+ { .refclk = 19200, .cdclk = 556800, .ratio = 58 },
+ { .refclk = 19200, .cdclk = 652800, .ratio = 68 },
+
+ { .refclk = 24000, .cdclk = 176000, .ratio = 22 },
+ { .refclk = 24000, .cdclk = 192000, .ratio = 16 },
+ { .refclk = 24000, .cdclk = 312000, .ratio = 26 },
+ { .refclk = 24000, .cdclk = 480000, .ratio = 40 },
+ { .refclk = 24000, .cdclk = 552000, .ratio = 46 },
+ { .refclk = 24000, .cdclk = 648000, .ratio = 54 },
+
+ { .refclk = 38400, .cdclk = 179200, .ratio = 14 },
+ { .refclk = 38400, .cdclk = 192000, .ratio = 10 },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 16 },
+ { .refclk = 38400, .cdclk = 480000, .ratio = 25 },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 29 },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34 },
{}
};
static const struct intel_cdclk_vals dg2_cdclk_table[] = {
- { .refclk = 38400, .cdclk = 163200, .divider = 2, .ratio = 34, .waveform = 0x8888 },
- { .refclk = 38400, .cdclk = 204000, .divider = 2, .ratio = 34, .waveform = 0x9248 },
- { .refclk = 38400, .cdclk = 244800, .divider = 2, .ratio = 34, .waveform = 0xa4a4 },
- { .refclk = 38400, .cdclk = 285600, .divider = 2, .ratio = 34, .waveform = 0xa54a },
- { .refclk = 38400, .cdclk = 326400, .divider = 2, .ratio = 34, .waveform = 0xaaaa },
- { .refclk = 38400, .cdclk = 367200, .divider = 2, .ratio = 34, .waveform = 0xad5a },
- { .refclk = 38400, .cdclk = 408000, .divider = 2, .ratio = 34, .waveform = 0xb6b6 },
- { .refclk = 38400, .cdclk = 448800, .divider = 2, .ratio = 34, .waveform = 0xdbb6 },
- { .refclk = 38400, .cdclk = 489600, .divider = 2, .ratio = 34, .waveform = 0xeeee },
- { .refclk = 38400, .cdclk = 530400, .divider = 2, .ratio = 34, .waveform = 0xf7de },
- { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe },
- { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff },
+ { .refclk = 38400, .cdclk = 163200, .ratio = 34, .waveform = 0x8888 },
+ { .refclk = 38400, .cdclk = 204000, .ratio = 34, .waveform = 0x9248 },
+ { .refclk = 38400, .cdclk = 244800, .ratio = 34, .waveform = 0xa4a4 },
+ { .refclk = 38400, .cdclk = 285600, .ratio = 34, .waveform = 0xa54a },
+ { .refclk = 38400, .cdclk = 326400, .ratio = 34, .waveform = 0xaaaa },
+ { .refclk = 38400, .cdclk = 367200, .ratio = 34, .waveform = 0xad5a },
+ { .refclk = 38400, .cdclk = 408000, .ratio = 34, .waveform = 0xb6b6 },
+ { .refclk = 38400, .cdclk = 448800, .ratio = 34, .waveform = 0xdbb6 },
+ { .refclk = 38400, .cdclk = 489600, .ratio = 34, .waveform = 0xeeee },
+ { .refclk = 38400, .cdclk = 530400, .ratio = 34, .waveform = 0xf7de },
+ { .refclk = 38400, .cdclk = 571200, .ratio = 34, .waveform = 0xfefe },
+ { .refclk = 38400, .cdclk = 612000, .ratio = 34, .waveform = 0xfffe },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff },
{}
};
static const struct intel_cdclk_vals mtl_cdclk_table[] = {
- { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a },
- { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 },
- { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0x0000 },
- { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0x0000 },
- { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0x0000 },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a },
+ { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0x0000 },
{}
};
static const struct intel_cdclk_vals lnl_cdclk_table[] = {
- { .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa },
- { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a },
- { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 },
- { .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 },
- { .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee },
- { .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de },
- { .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe },
- { .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe },
- { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff },
- { .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 },
- { .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee },
- { .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de },
- { .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe },
- { .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe },
- { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff },
- { .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe },
- { .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe },
- { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff },
- { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe },
- { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe },
- { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff },
+ { .refclk = 38400, .cdclk = 153600, .ratio = 16, .waveform = 0xaaaa },
+ { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a },
+ { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 },
+ { .refclk = 38400, .cdclk = 211200, .ratio = 16, .waveform = 0xdbb6 },
+ { .refclk = 38400, .cdclk = 230400, .ratio = 16, .waveform = 0xeeee },
+ { .refclk = 38400, .cdclk = 249600, .ratio = 16, .waveform = 0xf7de },
+ { .refclk = 38400, .cdclk = 268800, .ratio = 16, .waveform = 0xfefe },
+ { .refclk = 38400, .cdclk = 288000, .ratio = 16, .waveform = 0xfffe },
+ { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0xffff },
+ { .refclk = 38400, .cdclk = 330000, .ratio = 25, .waveform = 0xdbb6 },
+ { .refclk = 38400, .cdclk = 360000, .ratio = 25, .waveform = 0xeeee },
+ { .refclk = 38400, .cdclk = 390000, .ratio = 25, .waveform = 0xf7de },
+ { .refclk = 38400, .cdclk = 420000, .ratio = 25, .waveform = 0xfefe },
+ { .refclk = 38400, .cdclk = 450000, .ratio = 25, .waveform = 0xfffe },
+ { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0xffff },
+ { .refclk = 38400, .cdclk = 487200, .ratio = 29, .waveform = 0xfefe },
+ { .refclk = 38400, .cdclk = 522000, .ratio = 29, .waveform = 0xfffe },
+ { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0xffff },
+ { .refclk = 38400, .cdclk = 571200, .ratio = 34, .waveform = 0xfefe },
+ { .refclk = 38400, .cdclk = 612000, .ratio = 34, .waveform = 0xfffe },
+ { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff },
{}
};
+static const int cdclk_squash_len = 16;
+
+static int cdclk_squash_divider(u16 waveform)
+{
+ return hweight16(waveform ?: 0xffff);
+}
+
+static int cdclk_divider(int cdclk, int vco, u16 waveform)
+{
+ /* 2 * cd2x divider */
+ return DIV_ROUND_CLOSEST(vco * cdclk_squash_divider(waveform),
+ cdclk * cdclk_squash_len);
+}
+
static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
{
const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
@@ -1745,10 +1768,10 @@ static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe
}
static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv,
- int cdclk, int vco)
+ int cdclk, int vco, u16 waveform)
{
/* cdclk = vco / 2 / div{1,1.5,2,4} */
- switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
+ switch (cdclk_divider(cdclk, vco, waveform)) {
default:
drm_WARN_ON(&dev_priv->drm,
cdclk != dev_priv->display.cdclk.hw.bypass);
@@ -1765,7 +1788,7 @@ static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv,
}
}
-static u32 cdclk_squash_waveform(struct drm_i915_private *dev_priv,
+static u16 cdclk_squash_waveform(struct drm_i915_private *dev_priv,
int cdclk)
{
const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
@@ -1827,20 +1850,13 @@ static bool cdclk_pll_is_unknown(unsigned int vco)
return vco == ~0;
}
-static const int cdclk_squash_len = 16;
-
-static int cdclk_squash_divider(u16 waveform)
-{
- return hweight16(waveform ?: 0xffff);
-}
-
static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i915,
const struct intel_cdclk_config *old_cdclk_config,
const struct intel_cdclk_config *new_cdclk_config,
struct intel_cdclk_config *mid_cdclk_config)
{
u16 old_waveform, new_waveform, mid_waveform;
- int div = 2;
+ int old_div, new_div, mid_div;
/* Return if PLL is in an unknown state, force a complete disable and re-enable. */
if (cdclk_pll_is_unknown(old_cdclk_config->vco))
@@ -1859,6 +1875,18 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91
old_waveform == new_waveform)
return false;
+ old_div = cdclk_divider(old_cdclk_config->cdclk,
+ old_cdclk_config->vco, old_waveform);
+ new_div = cdclk_divider(new_cdclk_config->cdclk,
+ new_cdclk_config->vco, new_waveform);
+
+ /*
+ * Should not happen currently. We might need more midpoint
+ * transitions if we need to also change the cd2x divider.
+ */
+ if (drm_WARN_ON(&i915->drm, old_div != new_div))
+ return false;
+
*mid_cdclk_config = *new_cdclk_config;
/*
@@ -1871,15 +1899,17 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91
if (cdclk_squash_divider(new_waveform) > cdclk_squash_divider(old_waveform)) {
mid_cdclk_config->vco = old_cdclk_config->vco;
+ mid_div = old_div;
mid_waveform = new_waveform;
} else {
mid_cdclk_config->vco = new_cdclk_config->vco;
+ mid_div = new_div;
mid_waveform = old_waveform;
}
mid_cdclk_config->cdclk = DIV_ROUND_CLOSEST(cdclk_squash_divider(mid_waveform) *
mid_cdclk_config->vco,
- cdclk_squash_len * div);
+ cdclk_squash_len * mid_div);
/* make sure the mid clock came out sane */
@@ -1901,15 +1931,43 @@ static bool pll_enable_wa_needed(struct drm_i915_private *dev_priv)
dev_priv->display.cdclk.hw.vco > 0;
}
+static u32 bxt_cdclk_ctl(struct drm_i915_private *i915,
+ const struct intel_cdclk_config *cdclk_config,
+ enum pipe pipe)
+{
+ int cdclk = cdclk_config->cdclk;
+ int vco = cdclk_config->vco;
+ u16 waveform;
+ u32 val;
+
+ waveform = cdclk_squash_waveform(i915, cdclk);
+
+ val = bxt_cdclk_cd2x_div_sel(i915, cdclk, vco, waveform) |
+ bxt_cdclk_cd2x_pipe(i915, pipe);
+
+ /*
+ * Disable SSA Precharge when CD clock frequency < 500 MHz,
+ * enable otherwise.
+ */
+ if ((IS_GEMINILAKE(i915) || IS_BROXTON(i915)) &&
+ cdclk >= 500000)
+ val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
+
+ if (DISPLAY_VER(i915) >= 20)
+ val |= MDCLK_SOURCE_SEL_CDCLK_PLL;
+ else
+ val |= skl_cdclk_decimal(cdclk);
+
+ return val;
+}
+
static void _bxt_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
{
int cdclk = cdclk_config->cdclk;
int vco = cdclk_config->vco;
- int unsquashed_cdclk;
u16 waveform;
- u32 val;
if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0 &&
!cdclk_pll_is_unknown(dev_priv->display.cdclk.hw.vco)) {
@@ -1926,29 +1984,10 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv,
waveform = cdclk_squash_waveform(dev_priv, cdclk);
- unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len,
- cdclk_squash_divider(waveform));
-
if (HAS_CDCLK_SQUASH(dev_priv))
dg2_cdclk_squash_program(dev_priv, waveform);
- val = bxt_cdclk_cd2x_div_sel(dev_priv, unsquashed_cdclk, vco) |
- bxt_cdclk_cd2x_pipe(dev_priv, pipe);
-
- /*
- * Disable SSA Precharge when CD clock frequency < 500 MHz,
- * enable otherwise.
- */
- if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) &&
- cdclk >= 500000)
- val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
-
- if (DISPLAY_VER(dev_priv) >= 20)
- val |= MDCLK_SOURCE_SEL_CDCLK_PLL;
- else
- val |= skl_cdclk_decimal(cdclk);
-
- intel_de_write(dev_priv, CDCLK_CTL, val);
+ intel_de_write(dev_priv, CDCLK_CTL, bxt_cdclk_ctl(dev_priv, cdclk_config, pipe));
if (pipe != INVALID_PIPE)
intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe));
@@ -2039,7 +2078,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
{
u32 cdctl, expected;
- int cdclk, clock, vco;
+ int cdclk, vco;
intel_update_cdclk(dev_priv);
intel_cdclk_dump_config(dev_priv, &dev_priv->display.cdclk.hw, "Current CDCLK");
@@ -2048,20 +2087,6 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
dev_priv->display.cdclk.hw.cdclk == dev_priv->display.cdclk.hw.bypass)
goto sanitize;
- /* DPLL okay; verify the cdclock
- *
- * Some BIOS versions leave an incorrect decimal frequency value and
- * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4,
- * so sanitize this register.
- */
- cdctl = intel_de_read(dev_priv, CDCLK_CTL);
- /*
- * Let's ignore the pipe field, since BIOS could have configured the
- * dividers both synching to an active pipe, or asynchronously
- * (PIPE_NONE).
- */
- cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE);
-
/* Make sure this is a legal cdclk value for the platform */
cdclk = bxt_calc_cdclk(dev_priv, dev_priv->display.cdclk.hw.cdclk);
if (cdclk != dev_priv->display.cdclk.hw.cdclk)
@@ -2072,24 +2097,21 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
if (vco != dev_priv->display.cdclk.hw.vco)
goto sanitize;
- expected = skl_cdclk_decimal(cdclk);
-
- /* Figure out what CD2X divider we should be using for this cdclk */
- if (HAS_CDCLK_SQUASH(dev_priv))
- clock = dev_priv->display.cdclk.hw.vco / 2;
- else
- clock = dev_priv->display.cdclk.hw.cdclk;
-
- expected |= bxt_cdclk_cd2x_div_sel(dev_priv, clock,
- dev_priv->display.cdclk.hw.vco);
+ /*
+ * Some BIOS versions leave an incorrect decimal frequency value and
+ * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4,
+ * so sanitize this register.
+ */
+ cdctl = intel_de_read(dev_priv, CDCLK_CTL);
+ expected = bxt_cdclk_ctl(dev_priv, &dev_priv->display.cdclk.hw, INVALID_PIPE);
/*
- * Disable SSA Precharge when CD clock frequency < 500 MHz,
- * enable otherwise.
+ * Let's ignore the pipe field, since BIOS could have configured the
+ * dividers both synching to an active pipe, or asynchronously
+ * (PIPE_NONE).
*/
- if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) &&
- dev_priv->display.cdclk.hw.cdclk >= 500000)
- expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
+ cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE);
+ expected &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE);
if (cdctl == expected)
/* All well; nothing to sanitize */
@@ -3487,15 +3509,15 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
{
u32 freq;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
- freq = dg1_rawclk(dev_priv);
- else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL)
/*
* MTL always uses a 38.4 MHz rawclk. The bspec tells us
* "RAWCLK_FREQ defaults to the values for 38.4 and does
* not need to be programmed."
*/
freq = 38400;
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ freq = dg1_rawclk(dev_priv);
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
freq = cnp_rawclk(dev_priv);
else if (HAS_PCH_SPLIT(dev_priv))
diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index c5092b7e87..ca7112b32c 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -2111,7 +2111,8 @@ static u32 intel_degamma_lut_size(const struct intel_crtc_state *crtc_state)
return DISPLAY_INFO(i915)->color.degamma_lut_size;
}
-static int check_lut_size(const struct drm_property_blob *lut, int expected)
+static int check_lut_size(struct drm_i915_private *i915,
+ const struct drm_property_blob *lut, int expected)
{
int len;
@@ -2120,8 +2121,8 @@ static int check_lut_size(const struct drm_property_blob *lut, int expected)
len = drm_color_lut_size(lut);
if (len != expected) {
- DRM_DEBUG_KMS("Invalid LUT size; got %d, expected %d\n",
- len, expected);
+ drm_dbg_kms(&i915->drm, "Invalid LUT size; got %d, expected %d\n",
+ len, expected);
return -EINVAL;
}
@@ -2146,8 +2147,8 @@ static int _check_luts(const struct intel_crtc_state *crtc_state,
degamma_length = intel_degamma_lut_size(crtc_state);
gamma_length = intel_gamma_lut_size(crtc_state);
- if (check_lut_size(degamma_lut, degamma_length) ||
- check_lut_size(gamma_lut, gamma_length))
+ if (check_lut_size(i915, degamma_lut, degamma_length) ||
+ check_lut_size(i915, gamma_lut, gamma_length))
return -EINVAL;
if (drm_color_lut_check(degamma_lut, degamma_tests) ||
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index abaacea5c2..93479db0f8 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -42,6 +42,7 @@
#include "intel_ddi.h"
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_fdi.h"
#include "intel_fdi_regs.h"
@@ -846,6 +847,9 @@ intel_crt_detect(struct drm_connector *connector,
if (!intel_display_device_enabled(dev_priv))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(dev_priv))
+ return connector->status;
+
if (dev_priv->display.params.load_detect_test) {
wakeref = intel_display_power_get(dev_priv,
intel_encoder->power_domain);
@@ -929,6 +933,9 @@ static int intel_crt_get_modes(struct drm_connector *connector)
struct i2c_adapter *ddc;
int ret;
+ if (!intel_display_driver_check_access(dev_priv))
+ return drm_edid_connector_add_modes(connector);
+
wakeref = intel_display_power_get(dev_priv,
intel_encoder->power_domain);
@@ -1069,6 +1076,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
} else {
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
}
+ intel_connector->base.polled = intel_connector->polled;
if (HAS_DDI(dev_priv)) {
assert_port_valid(dev_priv, PORT_E);
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index 8a84a31c7b..25593f6aae 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -461,70 +461,6 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
1000 * adjusted_mode->crtc_htotal);
}
-static int intel_mode_vblank_start(const struct drm_display_mode *mode)
-{
- int vblank_start = mode->crtc_vblank_start;
-
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- vblank_start = DIV_ROUND_UP(vblank_start, 2);
-
- return vblank_start;
-}
-
-static void intel_crtc_vblank_evade_scanlines(struct intel_atomic_state *state,
- struct intel_crtc *crtc,
- int *min, int *max, int *vblank_start)
-{
- const struct intel_crtc_state *old_crtc_state =
- intel_atomic_get_old_crtc_state(state, crtc);
- const struct intel_crtc_state *new_crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
- const struct intel_crtc_state *crtc_state;
- const struct drm_display_mode *adjusted_mode;
-
- /*
- * During fastsets/etc. the transcoder is still
- * running with the old timings at this point.
- *
- * TODO: maybe just use the active timings here?
- */
- if (intel_crtc_needs_modeset(new_crtc_state))
- crtc_state = new_crtc_state;
- else
- crtc_state = old_crtc_state;
-
- adjusted_mode = &crtc_state->hw.adjusted_mode;
-
- if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
- /* timing changes should happen with VRR disabled */
- drm_WARN_ON(state->base.dev, intel_crtc_needs_modeset(new_crtc_state) ||
- new_crtc_state->update_m_n || new_crtc_state->update_lrr);
-
- if (intel_vrr_is_push_sent(crtc_state))
- *vblank_start = intel_vrr_vmin_vblank_start(crtc_state);
- else
- *vblank_start = intel_vrr_vmax_vblank_start(crtc_state);
- } else {
- *vblank_start = intel_mode_vblank_start(adjusted_mode);
- }
-
- /* FIXME needs to be calibrated sensibly */
- *min = *vblank_start - intel_usecs_to_scanlines(adjusted_mode,
- VBLANK_EVASION_TIME_US);
- *max = *vblank_start - 1;
-
- /*
- * M/N and TRANS_VTOTAL are double buffered on the transcoder's
- * undelayed vblank, so with seamless M/N and LRR we must evade
- * both vblanks.
- *
- * DSB execution waits for the transcoder's undelayed vblank,
- * hence we must kick off the commit before that.
- */
- if (new_crtc_state->dsb || new_crtc_state->update_m_n || new_crtc_state->update_lrr)
- *min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay;
-}
-
/**
* intel_pipe_update_start() - start update of a set of display registers
* @state: the atomic state
@@ -542,14 +478,12 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ const struct intel_crtc_state *old_crtc_state =
+ intel_atomic_get_old_crtc_state(state, crtc);
struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
- long timeout = msecs_to_jiffies_timeout(1);
- int scanline, min, max, vblank_start;
- wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
- bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
- intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
- DEFINE_WAIT(wait);
+ struct intel_vblank_evade_ctx evade;
+ int scanline;
intel_psr_lock(new_crtc_state);
@@ -566,9 +500,7 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
if (intel_crtc_needs_vblank_work(new_crtc_state))
intel_crtc_vblank_work_init(new_crtc_state);
- intel_crtc_vblank_evade_scanlines(state, crtc, &min, &max, &vblank_start);
- if (min <= 0 || max <= 0)
- goto irq_disable;
+ intel_vblank_evade_init(old_crtc_state, new_crtc_state, &evade);
if (drm_WARN_ON(&dev_priv->drm, drm_crtc_vblank_get(&crtc->base)))
goto irq_disable;
@@ -582,58 +514,14 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
local_irq_disable();
- crtc->debug.min_vbl = min;
- crtc->debug.max_vbl = max;
+ crtc->debug.min_vbl = evade.min;
+ crtc->debug.max_vbl = evade.max;
trace_intel_pipe_update_start(crtc);
- for (;;) {
- /*
- * prepare_to_wait() has a memory barrier, which guarantees
- * other CPUs can see the task state update by the time we
- * read the scanline.
- */
- prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
-
- scanline = intel_get_crtc_scanline(crtc);
- if (scanline < min || scanline > max)
- break;
-
- if (!timeout) {
- drm_err(&dev_priv->drm,
- "Potential atomic update failure on pipe %c\n",
- pipe_name(crtc->pipe));
- break;
- }
-
- local_irq_enable();
-
- timeout = schedule_timeout(timeout);
-
- local_irq_disable();
- }
-
- finish_wait(wq, &wait);
+ scanline = intel_vblank_evade(&evade);
drm_crtc_vblank_put(&crtc->base);
- /*
- * On VLV/CHV DSI the scanline counter would appear to
- * increment approx. 1/3 of a scanline before start of vblank.
- * The registers still get latched at start of vblank however.
- * This means we must not write any registers on the first
- * line of vblank (since not the whole line is actually in
- * vblank). And unfortunately we can't use the interrupt to
- * wait here since it will fire too soon. We could use the
- * frame start interrupt instead since it will fire after the
- * critical scanline, but that would require more changes
- * in the interrupt code. So for now we'll just do the nasty
- * thing and poll for the bad scanline to pass us by.
- *
- * FIXME figure out if BXT+ DSI suffers from this as well
- */
- while (need_vlv_dsi_wa && scanline == vblank_start)
- scanline = intel_get_crtc_scanline(crtc);
-
crtc->debug.scanline_start = scanline;
crtc->debug.start_vbl_time = ktime_get();
crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
index 49fd100ec9..4bcf446c75 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
@@ -55,10 +55,9 @@ static void
intel_dump_dp_vsc_sdp(struct drm_i915_private *i915,
const struct drm_dp_vsc_sdp *vsc)
{
- if (!drm_debug_enabled(DRM_UT_KMS))
- return;
+ struct drm_printer p = drm_dbg_printer(&i915->drm, DRM_UT_KMS, NULL);
- drm_dp_vsc_sdp_log(KERN_DEBUG, i915->drm.dev, vsc);
+ drm_dp_vsc_sdp_log(&p, vsc);
}
static void
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 2dde7ac882..0d3da55e1c 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -22,6 +22,7 @@
#include "intel_frontbuffer.h"
#include "intel_psr.h"
#include "intel_psr_regs.h"
+#include "intel_vblank.h"
#include "skl_watermark.h"
#include "gem/i915_gem_object.h"
@@ -45,12 +46,23 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
return base + plane_state->view.color_plane[0].offset;
}
-static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
+static u32 intel_cursor_position(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state,
+ bool early_tpt)
{
int x = plane_state->uapi.dst.x1;
int y = plane_state->uapi.dst.y1;
u32 pos = 0;
+ /*
+ * Formula from Bspec:
+ * MAX(-1 * <Cursor vertical size from CUR_CTL base on cursor mode
+ * select setting> + 1, CUR_POS Y Position - Update region Y position
+ */
+ if (early_tpt)
+ y = max(-1 * drm_rect_height(&plane_state->uapi.dst) + 1,
+ y - crtc_state->psr2_su_area.y1);
+
if (x < 0) {
pos |= CURSOR_POS_X_SIGN;
x = -x;
@@ -272,7 +284,7 @@ static void i845_cursor_update_arm(struct intel_plane *plane,
size = CURSOR_HEIGHT(height) | CURSOR_WIDTH(width);
base = intel_cursor_base(plane_state);
- pos = intel_cursor_position(plane_state);
+ pos = intel_cursor_position(crtc_state, plane_state, false);
}
/* On these chipsets we can only modify the base/size/stride
@@ -501,17 +513,24 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
- struct drm_i915_private *i915 = to_i915(plane->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
if (!crtc_state->enable_psr2_sel_fetch)
return;
- if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
- intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id),
+ if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) {
+ if (crtc_state->enable_psr2_su_region_et) {
+ u32 val = intel_cursor_position(crtc_state, plane_state,
+ true);
+ intel_de_write_fw(dev_priv, CURPOS_ERLY_TPT(pipe), val);
+ }
+
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id),
plane_state->ctl);
- else
+ } else {
i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state);
+ }
}
/* TODO: split into noarm+arm pair */
@@ -534,7 +553,7 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane,
fbc_ctl = CUR_FBC_EN | CUR_FBC_HEIGHT(height - 1);
base = intel_cursor_base(plane_state);
- pos = intel_cursor_position(plane_state);
+ pos = intel_cursor_position(crtc_state, plane_state, false);
}
/*
@@ -645,12 +664,14 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
{
struct intel_plane *plane = to_intel_plane(_plane);
struct intel_crtc *crtc = to_intel_crtc(_crtc);
+ struct drm_i915_private *i915 = to_i915(plane->base.dev);
struct intel_plane_state *old_plane_state =
to_intel_plane_state(plane->base.state);
struct intel_plane_state *new_plane_state;
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
struct intel_crtc_state *new_crtc_state;
+ struct intel_vblank_evade_ctx evade;
int ret;
/*
@@ -743,13 +764,25 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
*/
crtc_state->active_planes = new_crtc_state->active_planes;
- /*
- * Technically we should do a vblank evasion here to make
- * sure all the cursor registers update on the same frame.
- * For now just make sure the register writes happen as
- * quickly as possible to minimize the race window.
- */
- local_irq_disable();
+ intel_vblank_evade_init(crtc_state, crtc_state, &evade);
+
+ intel_psr_lock(crtc_state);
+
+ if (!drm_WARN_ON(&i915->drm, drm_crtc_vblank_get(&crtc->base))) {
+ /*
+ * TODO: maybe check if we're still in PSR
+ * and skip the vblank evasion entirely?
+ */
+ intel_psr_wait_for_idle_locked(crtc_state);
+
+ local_irq_disable();
+
+ intel_vblank_evade(&evade);
+
+ drm_crtc_vblank_put(&crtc->base);
+ } else {
+ local_irq_disable();
+ }
if (new_plane_state->uapi.visible) {
intel_plane_update_noarm(plane, crtc_state, new_plane_state);
@@ -760,6 +793,8 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
local_irq_enable();
+ intel_psr_unlock(crtc_state);
+
intel_plane_unpin_fb(old_plane_state);
out_free:
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index 6b25e19523..64e0f820a7 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -78,7 +78,7 @@ static void intel_cx0_program_msgbus_timer(struct intel_encoder *encoder)
for_each_cx0_lane_in_mask(INTEL_CX0_BOTH_LANES, lane)
intel_de_rmw(i915,
- XELPDP_PORT_MSGBUS_TIMER(encoder->port, lane),
+ XELPDP_PORT_MSGBUS_TIMER(i915, encoder->port, lane),
XELPDP_PORT_MSGBUS_TIMER_VAL_MASK,
XELPDP_PORT_MSGBUS_TIMER_VAL);
}
@@ -117,7 +117,7 @@ static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, intel_w
static void intel_clear_response_ready_flag(struct drm_i915_private *i915,
enum port port, int lane)
{
- intel_de_rmw(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
+ intel_de_rmw(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(i915, port, lane),
0, XELPDP_PORT_P2M_RESPONSE_READY | XELPDP_PORT_P2M_ERROR_SET);
}
@@ -125,10 +125,10 @@ static void intel_cx0_bus_reset(struct drm_i915_private *i915, enum port port, i
{
enum phy phy = intel_port_to_phy(i915, port);
- intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_RESET);
- if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_RESET,
XELPDP_MSGBUS_TIMEOUT_SLOW)) {
drm_err_once(&i915->drm, "Failed to bring PHY %c to idle.\n", phy_name(phy));
@@ -144,7 +144,7 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port,
enum phy phy = intel_port_to_phy(i915, port);
if (__intel_de_wait_for_register(i915,
- XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
+ XELPDP_PORT_P2M_MSGBUS_STATUS(i915, port, lane),
XELPDP_PORT_P2M_RESPONSE_READY,
XELPDP_PORT_P2M_RESPONSE_READY,
XELPDP_MSGBUS_TIMEOUT_FAST_US,
@@ -152,7 +152,7 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port,
drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for message ACK. Status: 0x%x\n",
phy_name(phy), *val);
- if (!(intel_de_read(i915, XELPDP_PORT_MSGBUS_TIMER(port, lane)) &
+ if (!(intel_de_read(i915, XELPDP_PORT_MSGBUS_TIMER(i915, port, lane)) &
XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT))
drm_dbg_kms(&i915->drm,
"PHY %c Hardware did not detect a timeout\n",
@@ -186,7 +186,7 @@ static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port,
int ack;
u32 val;
- if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_PENDING,
XELPDP_MSGBUS_TIMEOUT_SLOW)) {
drm_dbg_kms(&i915->drm,
@@ -195,7 +195,7 @@ static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port,
return -ETIMEDOUT;
}
- intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_PENDING |
XELPDP_PORT_M2P_COMMAND_READ |
XELPDP_PORT_M2P_ADDRESS(addr));
@@ -253,7 +253,7 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port,
int ack;
u32 val;
- if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_PENDING,
XELPDP_MSGBUS_TIMEOUT_SLOW)) {
drm_dbg_kms(&i915->drm,
@@ -262,14 +262,14 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port,
return -ETIMEDOUT;
}
- intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_PENDING |
(committed ? XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED :
XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED) |
XELPDP_PORT_M2P_DATA(data) |
XELPDP_PORT_M2P_ADDRESS(addr));
- if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_PENDING,
XELPDP_MSGBUS_TIMEOUT_SLOW)) {
drm_dbg_kms(&i915->drm,
@@ -282,7 +282,7 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port,
ack = intel_cx0_wait_for_ack(i915, port, XELPDP_PORT_P2M_COMMAND_WRITE_ACK, lane, &val);
if (ack < 0)
return ack;
- } else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane)) &
+ } else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(i915, port, lane)) &
XELPDP_PORT_P2M_ERROR_SET)) {
drm_dbg_kms(&i915->drm,
"PHY %c Error occurred during write command.\n", phy_name(phy));
@@ -848,10 +848,10 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr3 = {
static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = {
.clock = 1000000, /* 10 Gbps */
.tx = { 0xbe21, /* tx cfg0 */
- 0x4800, /* tx cfg1 */
+ 0xe800, /* tx cfg1 */
0x0000, /* tx cfg2 */
},
- .cmn = {0x0500, /* cmn cfg0*/
+ .cmn = {0x0700, /* cmn cfg0*/
0x0005, /* cmn cfg1 */
0x0000, /* cmn cfg2 */
0x0000, /* cmn cfg3 */
@@ -1641,7 +1641,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = {
static const struct intel_c20pll_state mtl_c20_hdmi_300 = {
.clock = 3000000,
.tx = { 0xbe98, /* tx cfg0 */
- 0x9800, /* tx cfg1 */
+ 0x8800, /* tx cfg1 */
0x0000, /* tx cfg2 */
},
.cmn = { 0x0500, /* cmn cfg0*/
@@ -1649,8 +1649,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = {
0x0000, /* cmn cfg2 */
0x0000, /* cmn cfg3 */
},
- .mpllb = { 0x209c, /* mpllb cfg0 */
- 0x7d10, /* mpllb cfg1 */
+ .mpllb = { 0x309c, /* mpllb cfg0 */
+ 0x2110, /* mpllb cfg1 */
0xca06, /* mpllb cfg2 */
0xbe40, /* mpllb cfg3 */
0x0000, /* mpllb cfg4 */
@@ -1666,7 +1666,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = {
static const struct intel_c20pll_state mtl_c20_hdmi_600 = {
.clock = 6000000,
.tx = { 0xbe98, /* tx cfg0 */
- 0x9800, /* tx cfg1 */
+ 0x8800, /* tx cfg1 */
0x0000, /* tx cfg2 */
},
.cmn = { 0x0500, /* cmn cfg0*/
@@ -1674,8 +1674,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = {
0x0000, /* cmn cfg2 */
0x0000, /* cmn cfg3 */
},
- .mpllb = { 0x009c, /* mpllb cfg0 */
- 0x7d08, /* mpllb cfg1 */
+ .mpllb = { 0x109c, /* mpllb cfg0 */
+ 0x2108, /* mpllb cfg1 */
0xca06, /* mpllb cfg2 */
0xbe40, /* mpllb cfg3 */
0x0000, /* mpllb cfg4 */
@@ -1691,7 +1691,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = {
static const struct intel_c20pll_state mtl_c20_hdmi_800 = {
.clock = 8000000,
.tx = { 0xbe98, /* tx cfg0 */
- 0x9800, /* tx cfg1 */
+ 0x8800, /* tx cfg1 */
0x0000, /* tx cfg2 */
},
.cmn = { 0x0500, /* cmn cfg0*/
@@ -1699,8 +1699,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = {
0x0000, /* cmn cfg2 */
0x0000, /* cmn cfg3 */
},
- .mpllb = { 0x00d0, /* mpllb cfg0 */
- 0x7d08, /* mpllb cfg1 */
+ .mpllb = { 0x10d0, /* mpllb cfg0 */
+ 0x2108, /* mpllb cfg1 */
0x4a06, /* mpllb cfg2 */
0xbe40, /* mpllb cfg3 */
0x0000, /* mpllb cfg4 */
@@ -1716,7 +1716,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = {
static const struct intel_c20pll_state mtl_c20_hdmi_1000 = {
.clock = 10000000,
.tx = { 0xbe98, /* tx cfg0 */
- 0x9800, /* tx cfg1 */
+ 0x8800, /* tx cfg1 */
0x0000, /* tx cfg2 */
},
.cmn = { 0x0500, /* cmn cfg0*/
@@ -1725,7 +1725,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = {
0x0000, /* cmn cfg3 */
},
.mpllb = { 0x1104, /* mpllb cfg0 */
- 0x7d08, /* mpllb cfg1 */
+ 0x2108, /* mpllb cfg1 */
0x0a06, /* mpllb cfg2 */
0xbe40, /* mpllb cfg3 */
0x0000, /* mpllb cfg4 */
@@ -1741,7 +1741,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = {
static const struct intel_c20pll_state mtl_c20_hdmi_1200 = {
.clock = 12000000,
.tx = { 0xbe98, /* tx cfg0 */
- 0x9800, /* tx cfg1 */
+ 0x8800, /* tx cfg1 */
0x0000, /* tx cfg2 */
},
.cmn = { 0x0500, /* cmn cfg0*/
@@ -1749,8 +1749,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1200 = {
0x0000, /* cmn cfg2 */
0x0000, /* cmn cfg3 */
},
- .mpllb = { 0x0138, /* mpllb cfg0 */
- 0x7d08, /* mpllb cfg1 */
+ .mpllb = { 0x1138, /* mpllb cfg0 */
+ 0x2108, /* mpllb cfg1 */
0x5486, /* mpllb cfg2 */
0xfe40, /* mpllb cfg3 */
0x0000, /* mpllb cfg4 */
@@ -2096,13 +2096,54 @@ int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state,
return intel_c20pll_calc_state(crtc_state, encoder);
}
-static bool intel_c20_use_mplla(u32 clock)
+static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state)
{
- /* 10G and 20G rates use MPLLA */
- if (clock == 1000000 || clock == 2000000)
- return true;
+ return state->tx[0] & C20_PHY_USE_MPLLB;
+}
- return false;
+static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder,
+ const struct intel_c20pll_state *pll_state)
+{
+ unsigned int frac, frac_en, frac_quot, frac_rem, frac_den;
+ unsigned int multiplier, refclk = 38400;
+ unsigned int tx_clk_div;
+ unsigned int ref_clk_mpllb_div;
+ unsigned int fb_clk_div4_en;
+ unsigned int ref, vco;
+ unsigned int tx_rate_mult;
+ unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]);
+
+ if (intel_c20phy_use_mpllb(pll_state)) {
+ tx_rate_mult = 1;
+ frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]);
+ frac_quot = pll_state->mpllb[8];
+ frac_rem = pll_state->mpllb[9];
+ frac_den = pll_state->mpllb[7];
+ multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]);
+ tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]);
+ ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]);
+ fb_clk_div4_en = 0;
+ } else {
+ tx_rate_mult = 2;
+ frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]);
+ frac_quot = pll_state->mplla[8];
+ frac_rem = pll_state->mplla[9];
+ frac_den = pll_state->mplla[7];
+ multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]);
+ tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]);
+ ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]);
+ fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]);
+ }
+
+ if (frac_en)
+ frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den);
+ else
+ frac = 0;
+
+ ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div);
+ vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10);
+
+ return vco << tx_rate_mult >> tx_clk_div >> tx_rate;
}
static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder,
@@ -2138,7 +2179,7 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder,
PHY_C20_A_CMN_CNTX_CFG(i));
}
- if (pll_state->tx[0] & C20_PHY_USE_MPLLB) {
+ if (intel_c20phy_use_mpllb(pll_state)) {
/* MPLLB configuration */
for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) {
if (cntx)
@@ -2160,6 +2201,8 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder,
}
}
+ pll_state->clock = intel_c20pll_calc_port_clock(encoder, pll_state);
+
intel_cx0_phy_transaction_end(encoder, wakeref);
}
@@ -2174,12 +2217,12 @@ void intel_c20pll_dump_hw_state(struct drm_i915_private *i915,
drm_dbg_kms(&i915->drm, "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n",
hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]);
- if (intel_c20_use_mplla(hw_state->clock)) {
- for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++)
- drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]);
- } else {
+ if (intel_c20phy_use_mpllb(hw_state)) {
for (i = 0; i < ARRAY_SIZE(hw_state->mpllb); i++)
drm_dbg_kms(&i915->drm, "mpllb[%d] = 0x%.4x\n", i, hw_state->mpllb[i]);
+ } else {
+ for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++)
+ drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]);
}
}
@@ -2326,27 +2369,27 @@ static void intel_c20_pll_program(struct drm_i915_private *i915,
}
/* 3.3 mpllb or mplla configuration */
- if (intel_c20_use_mplla(clock)) {
- for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) {
+ if (intel_c20phy_use_mpllb(pll_state)) {
+ for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) {
if (cntx)
intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0,
- PHY_C20_A_MPLLA_CNTX_CFG(i),
- pll_state->mplla[i]);
+ PHY_C20_A_MPLLB_CNTX_CFG(i),
+ pll_state->mpllb[i]);
else
intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0,
- PHY_C20_B_MPLLA_CNTX_CFG(i),
- pll_state->mplla[i]);
+ PHY_C20_B_MPLLB_CNTX_CFG(i),
+ pll_state->mpllb[i]);
}
} else {
- for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) {
+ for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) {
if (cntx)
intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0,
- PHY_C20_A_MPLLB_CNTX_CFG(i),
- pll_state->mpllb[i]);
+ PHY_C20_A_MPLLA_CNTX_CFG(i),
+ pll_state->mplla[i]);
else
intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0,
- PHY_C20_B_MPLLB_CNTX_CFG(i),
- pll_state->mpllb[i]);
+ PHY_C20_B_MPLLA_CNTX_CFG(i),
+ pll_state->mplla[i]);
}
}
@@ -2408,51 +2451,6 @@ static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder,
return tmpclk;
}
-static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder,
- const struct intel_c20pll_state *pll_state)
-{
- unsigned int frac, frac_en, frac_quot, frac_rem, frac_den;
- unsigned int multiplier, refclk = 38400;
- unsigned int tx_clk_div;
- unsigned int ref_clk_mpllb_div;
- unsigned int fb_clk_div4_en;
- unsigned int ref, vco;
- unsigned int tx_rate_mult;
- unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]);
-
- if (pll_state->tx[0] & C20_PHY_USE_MPLLB) {
- tx_rate_mult = 1;
- frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]);
- frac_quot = pll_state->mpllb[8];
- frac_rem = pll_state->mpllb[9];
- frac_den = pll_state->mpllb[7];
- multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]);
- tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]);
- ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]);
- fb_clk_div4_en = 0;
- } else {
- tx_rate_mult = 2;
- frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]);
- frac_quot = pll_state->mplla[8];
- frac_rem = pll_state->mplla[9];
- frac_den = pll_state->mplla[7];
- multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]);
- tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]);
- ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]);
- fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]);
- }
-
- if (frac_en)
- frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den);
- else
- frac = 0;
-
- ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div);
- vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10);
-
- return vco << tx_rate_mult >> tx_clk_div >> tx_rate;
-}
-
static void intel_program_port_clock_ctl(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
bool lane_reversal)
@@ -2460,7 +2458,8 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder,
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
u32 val = 0;
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port), XELPDP_PORT_REVERSAL,
+ intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(i915, encoder->port),
+ XELPDP_PORT_REVERSAL,
lane_reversal ? XELPDP_PORT_REVERSAL : 0);
if (lane_reversal)
@@ -2481,7 +2480,7 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder,
else
val |= crtc_state->cx0pll_state.ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0;
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_LANE1_PHY_CLOCK_SELECT | XELPDP_FORWARD_CLOCK_UNGATE |
XELPDP_DDI_CLOCK_SELECT_MASK | XELPDP_SSC_ENABLE_PLLA |
XELPDP_SSC_ENABLE_PLLB, val);
@@ -2514,15 +2513,16 @@ static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915,
u8 lane_mask, u8 state)
{
enum phy phy = intel_port_to_phy(i915, port);
+ i915_reg_t buf_ctl2_reg = XELPDP_PORT_BUF_CTL2(i915, port);
int lane;
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port),
+ intel_de_rmw(i915, buf_ctl2_reg,
intel_cx0_get_powerdown_state(INTEL_CX0_BOTH_LANES, XELPDP_LANE_POWERDOWN_NEW_STATE_MASK),
intel_cx0_get_powerdown_state(lane_mask, state));
/* Wait for pending transactions.*/
for_each_cx0_lane_in_mask(lane_mask, lane)
- if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+ if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane),
XELPDP_PORT_M2P_TRANSACTION_PENDING,
XELPDP_MSGBUS_TIMEOUT_SLOW)) {
drm_dbg_kms(&i915->drm,
@@ -2531,12 +2531,12 @@ static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915,
intel_cx0_bus_reset(i915, port, lane);
}
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port),
+ intel_de_rmw(i915, buf_ctl2_reg,
intel_cx0_get_powerdown_update(INTEL_CX0_BOTH_LANES),
intel_cx0_get_powerdown_update(lane_mask));
/* Update Timeout Value */
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(port),
+ if (__intel_de_wait_for_register(i915, buf_ctl2_reg,
intel_cx0_get_powerdown_update(lane_mask), 0,
XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US, 0, NULL))
drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dus.\n",
@@ -2545,10 +2545,10 @@ static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915,
static void intel_cx0_setup_powerdown(struct drm_i915_private *i915, enum port port)
{
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port),
+ intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(i915, port),
XELPDP_POWER_STATE_READY_MASK,
XELPDP_POWER_STATE_READY(CX0_P2_STATE_READY));
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL3(port),
+ intel_de_rmw(i915, XELPDP_PORT_BUF_CTL3(i915, port),
XELPDP_POWER_STATE_ACTIVE_MASK |
XELPDP_PLL_LANE_STAGGERING_DELAY_MASK,
XELPDP_POWER_STATE_ACTIVE(CX0_P0_STATE_ACTIVE) |
@@ -2593,27 +2593,27 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915,
XELPDP_LANE_PHY_CURRENT_STATUS(1))
: XELPDP_LANE_PHY_CURRENT_STATUS(0);
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL1(port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL1(i915, port),
XELPDP_PORT_BUF_SOC_PHY_READY,
XELPDP_PORT_BUF_SOC_PHY_READY,
XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US, 0, NULL))
drm_warn(&i915->drm, "PHY %c failed to bring out of SOC reset after %dus.\n",
phy_name(phy), XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US);
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), lane_pipe_reset,
+ intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(i915, port), lane_pipe_reset,
lane_pipe_reset);
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(i915, port),
lane_phy_current_status, lane_phy_current_status,
XELPDP_PORT_RESET_START_TIMEOUT_US, 0, NULL))
drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dus.\n",
phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US);
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, port),
intel_cx0_get_pclk_refclk_request(owned_lane_mask),
intel_cx0_get_pclk_refclk_request(lane_mask));
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, port),
intel_cx0_get_pclk_refclk_ack(owned_lane_mask),
intel_cx0_get_pclk_refclk_ack(lane_mask),
XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, NULL))
@@ -2624,9 +2624,10 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915,
CX0_P2_STATE_RESET);
intel_cx0_setup_powerdown(i915, port);
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), lane_pipe_reset, 0);
+ intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(i915, port), lane_pipe_reset, 0);
- if (intel_de_wait_for_clear(i915, XELPDP_PORT_BUF_CTL2(port), lane_phy_current_status,
+ if (intel_de_wait_for_clear(i915, XELPDP_PORT_BUF_CTL2(i915, port),
+ lane_phy_current_status,
XELPDP_PORT_RESET_END_TIMEOUT))
drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dms.\n",
phy_name(phy), XELPDP_PORT_RESET_END_TIMEOUT);
@@ -2761,12 +2762,12 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder,
* 9. Set PORT_CLOCK_CTL register PCLK PLL Request
* LN<Lane for maxPCLK> to "1" to enable PLL.
*/
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES),
intel_cx0_get_pclk_pll_request(maxpclk_lane));
/* 10. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK> == "1". */
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES),
intel_cx0_get_pclk_pll_ack(maxpclk_lane),
XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, 0, NULL))
@@ -2786,7 +2787,7 @@ int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
u32 clock;
- u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port));
+ u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port));
clock = REG_FIELD_GET(XELPDP_DDI_CLOCK_SELECT_MASK, val);
@@ -2839,11 +2840,11 @@ static void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder,
*/
val |= XELPDP_DDI_CLOCK_SELECT(intel_mtl_tbt_clock_select(i915, crtc_state->port_clock));
val |= XELPDP_FORWARD_CLOCK_UNGATE;
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_DDI_CLOCK_SELECT_MASK | XELPDP_FORWARD_CLOCK_UNGATE, val);
/* 2. Read back PORT_CLOCK_CTL REGISTER */
- val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port));
+ val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port));
/*
* 3. Follow the Display Voltage Frequency Switching - Sequence
@@ -2854,10 +2855,10 @@ static void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder,
* 4. Set PORT_CLOCK_CTL register TBT CLOCK Request to "1" to enable PLL.
*/
val |= XELPDP_TBT_CLOCK_REQUEST;
- intel_de_write(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), val);
+ intel_de_write(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), val);
/* 5. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "1". */
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_TBT_CLOCK_ACK,
XELPDP_TBT_CLOCK_ACK,
100, 0, NULL))
@@ -2909,7 +2910,7 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder)
* 3. Set PORT_CLOCK_CTL register PCLK PLL Request LN<Lane for maxPCLK>
* to "0" to disable PLL.
*/
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES) |
intel_cx0_get_pclk_refclk_request(INTEL_CX0_BOTH_LANES), 0);
@@ -2919,7 +2920,7 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder)
/*
* 5. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK**> == "0".
*/
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES) |
intel_cx0_get_pclk_refclk_ack(INTEL_CX0_BOTH_LANES), 0,
XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US, 0, NULL))
@@ -2932,9 +2933,9 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder)
*/
/* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_DDI_CLOCK_SELECT_MASK, 0);
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_FORWARD_CLOCK_UNGATE, 0);
intel_cx0_phy_transaction_end(encoder, wakeref);
@@ -2953,11 +2954,11 @@ static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder)
/*
* 2. Set PORT_CLOCK_CTL register TBT CLOCK Request to "0" to disable PLL.
*/
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_TBT_CLOCK_REQUEST, 0);
/* 3. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "0". */
- if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_TBT_CLOCK_ACK, 0, 10, 0, NULL))
drm_warn(&i915->drm, "[ENCODER:%d:%s][%c] PHY PLL not unlocked after 10us.\n",
encoder->base.base.id, encoder->base.name, phy_name(phy));
@@ -2970,7 +2971,7 @@ static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder)
/*
* 5. Program PORT CLOCK CTRL register to disable and gate clocks
*/
- intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port),
XELPDP_DDI_CLOCK_SELECT_MASK |
XELPDP_FORWARD_CLOCK_UNGATE, 0);
@@ -2997,7 +2998,7 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder,
* TODO: Determine the PLL type from the SW state, once MTL PLL
* handling is done via the standard shared DPLL framework.
*/
- u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port));
+ u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port));
u32 clock = REG_FIELD_GET(XELPDP_DDI_CLOCK_SELECT_MASK, val);
if (clock == XELPDP_DDI_CLOCK_SELECT_MAXPCLK ||
@@ -3016,6 +3017,9 @@ static void intel_c10pll_state_verify(const struct intel_crtc_state *state,
const struct intel_c10pll_state *mpllb_sw_state = &state->cx0pll_state.c10;
int i;
+ if (intel_crtc_needs_fastset(state))
+ return;
+
for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) {
u8 expected = mpllb_sw_state->pll[i];
@@ -3067,10 +3071,15 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state,
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20;
- bool sw_use_mpllb = mpll_sw_state->tx[0] & C20_PHY_USE_MPLLB;
- bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB;
+ bool sw_use_mpllb = intel_c20phy_use_mpllb(mpll_sw_state);
+ bool hw_use_mpllb = intel_c20phy_use_mpllb(mpll_hw_state);
int i;
+ I915_STATE_WARN(i915, mpll_hw_state->clock != mpll_sw_state->clock,
+ "[CRTC:%d:%s] mismatch in C20: Register CLOCK (expected %d, found %d)",
+ crtc->base.base.id, crtc->base.name,
+ mpll_sw_state->clock, mpll_hw_state->clock);
+
I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb,
"[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)",
crtc->base.base.id, crtc->base.name,
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
index adf8f4ce0d..bdd0c8c4ef 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
@@ -7,16 +7,39 @@
#define __INTEL_CX0_PHY_REGS_H__
#include "i915_reg_defs.h"
+#include "intel_display_limits.h"
+
+/*
+ * Wrapper macro to convert from port number to the index used in some of the
+ * registers. For Display version 20 and above it converts the port number to a
+ * single range, starting with the TC offsets. When used together with
+ * _PICK_EVEN_2RANGES(idx, PORT_TC1, ...), this single range will be the second
+ * range. Example:
+ *
+ * PORT_TC1 -> PORT_TC1
+ * PORT_TC2 -> PORT_TC2
+ * PORT_TC3 -> PORT_TC3
+ * PORT_TC4 -> PORT_TC4
+ * PORT_A -> PORT_TC4 + 1
+ * PORT_B -> PORT_TC4 + 2
+ * ...
+ */
+#define __xe2lpd_port_idx(port) \
+ (port >= PORT_TC1 ? port : PORT_TC4 + 1 + port - PORT_A)
#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A 0x64040
#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B 0x64140
#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1 0x16F240
#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2 0x16F440
-#define XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+#define _XELPDP_PORT_M2P_MSGBUS_CTL(idx, lane) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2) + (lane) * 4)
+#define XELPDP_PORT_M2P_MSGBUS_CTL(i915__, port, lane) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_M2P_MSGBUS_CTL(__xe2lpd_port_idx(port), lane) : \
+ _XELPDP_PORT_M2P_MSGBUS_CTL(port, lane))
#define XELPDP_PORT_M2P_TRANSACTION_PENDING REG_BIT(31)
#define XELPDP_PORT_M2P_COMMAND_TYPE_MASK REG_GENMASK(30, 27)
#define XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x1)
@@ -27,11 +50,16 @@
#define XELPDP_PORT_M2P_TRANSACTION_RESET REG_BIT(15)
#define XELPDP_PORT_M2P_ADDRESS_MASK REG_GENMASK(11, 0)
#define XELPDP_PORT_M2P_ADDRESS(val) REG_FIELD_PREP(XELPDP_PORT_M2P_ADDRESS_MASK, val)
-#define XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+
+#define _XELPDP_PORT_P2M_MSGBUS_STATUS(idx, lane) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \
_XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2) + (lane) * 4 + 8)
+#define XELPDP_PORT_P2M_MSGBUS_STATUS(i915__, port, lane) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_P2M_MSGBUS_STATUS(__xe2lpd_port_idx(port), lane) : \
+ _XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane))
#define XELPDP_PORT_P2M_RESPONSE_READY REG_BIT(31)
#define XELPDP_PORT_P2M_COMMAND_TYPE_MASK REG_GENMASK(30, 27)
#define XELPDP_PORT_P2M_COMMAND_READ_ACK 0x4
@@ -54,11 +82,15 @@
#define _XELPDP_PORT_BUF_CTL1_LN0_B 0x64104
#define _XELPDP_PORT_BUF_CTL1_LN0_USBC1 0x16F200
#define _XELPDP_PORT_BUF_CTL1_LN0_USBC2 0x16F400
-#define XELPDP_PORT_BUF_CTL1(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+#define _XELPDP_PORT_BUF_CTL1(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \
_XELPDP_PORT_BUF_CTL1_LN0_A, \
_XELPDP_PORT_BUF_CTL1_LN0_B, \
_XELPDP_PORT_BUF_CTL1_LN0_USBC1, \
_XELPDP_PORT_BUF_CTL1_LN0_USBC2))
+#define XELPDP_PORT_BUF_CTL1(i915__, port) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_BUF_CTL1(__xe2lpd_port_idx(port)) : \
+ _XELPDP_PORT_BUF_CTL1(port))
#define XELPDP_PORT_BUF_D2D_LINK_ENABLE REG_BIT(29)
#define XELPDP_PORT_BUF_D2D_LINK_STATE REG_BIT(28)
#define XELPDP_PORT_BUF_SOC_PHY_READY REG_BIT(24)
@@ -75,12 +107,15 @@
#define XELPDP_PORT_WIDTH_MASK REG_GENMASK(3, 1)
#define XELPDP_PORT_WIDTH(val) REG_FIELD_PREP(XELPDP_PORT_WIDTH_MASK, val)
-#define XELPDP_PORT_BUF_CTL2(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+#define _XELPDP_PORT_BUF_CTL2(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \
_XELPDP_PORT_BUF_CTL1_LN0_A, \
_XELPDP_PORT_BUF_CTL1_LN0_B, \
_XELPDP_PORT_BUF_CTL1_LN0_USBC1, \
_XELPDP_PORT_BUF_CTL1_LN0_USBC2) + 4)
-
+#define XELPDP_PORT_BUF_CTL2(i915__, port) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_BUF_CTL2(__xe2lpd_port_idx(port)) : \
+ _XELPDP_PORT_BUF_CTL2(port))
#define XELPDP_LANE_PIPE_RESET(lane) _PICK(lane, REG_BIT(31), REG_BIT(30))
#define XELPDP_LANE_PHY_CURRENT_STATUS(lane) _PICK(lane, REG_BIT(29), REG_BIT(28))
#define XELPDP_LANE_POWERDOWN_UPDATE(lane) _PICK(lane, REG_BIT(25), REG_BIT(24))
@@ -95,11 +130,15 @@
#define XELPDP_POWER_STATE_READY_MASK REG_GENMASK(7, 4)
#define XELPDP_POWER_STATE_READY(val) REG_FIELD_PREP(XELPDP_POWER_STATE_READY_MASK, val)
-#define XELPDP_PORT_BUF_CTL3(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+#define _XELPDP_PORT_BUF_CTL3(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \
_XELPDP_PORT_BUF_CTL1_LN0_A, \
_XELPDP_PORT_BUF_CTL1_LN0_B, \
_XELPDP_PORT_BUF_CTL1_LN0_USBC1, \
_XELPDP_PORT_BUF_CTL1_LN0_USBC2) + 8)
+#define XELPDP_PORT_BUF_CTL3(i915__, port) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_BUF_CTL3(__xe2lpd_port_idx(port)) : \
+ _XELPDP_PORT_BUF_CTL3(port))
#define XELPDP_PLL_LANE_STAGGERING_DELAY_MASK REG_GENMASK(15, 8)
#define XELPDP_PLL_LANE_STAGGERING_DELAY(val) REG_FIELD_PREP(XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, val)
#define XELPDP_POWER_STATE_ACTIVE_MASK REG_GENMASK(3, 0)
@@ -114,11 +153,15 @@
#define _XELPDP_PORT_MSGBUS_TIMER_LN0_B 0x641d8
#define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1 0x16f258
#define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2 0x16f458
-#define XELPDP_PORT_MSGBUS_TIMER(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+#define _XELPDP_PORT_MSGBUS_TIMER(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
_XELPDP_PORT_MSGBUS_TIMER_LN0_A, \
_XELPDP_PORT_MSGBUS_TIMER_LN0_B, \
_XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1, \
_XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2) + (lane) * 4)
+#define XELPDP_PORT_MSGBUS_TIMER(i915__, port, lane) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_MSGBUS_TIMER(__xe2lpd_port_idx(port), lane) : \
+ _XELPDP_PORT_MSGBUS_TIMER(port, lane))
#define XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT REG_BIT(31)
#define XELPDP_PORT_MSGBUS_TIMER_VAL_MASK REG_GENMASK(23, 0)
#define XELPDP_PORT_MSGBUS_TIMER_VAL REG_FIELD_PREP(XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, 0xa000)
@@ -127,11 +170,15 @@
#define _XELPDP_PORT_CLOCK_CTL_B 0x641E0
#define _XELPDP_PORT_CLOCK_CTL_USBC1 0x16F260
#define _XELPDP_PORT_CLOCK_CTL_USBC2 0x16F460
-#define XELPDP_PORT_CLOCK_CTL(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \
+#define _XELPDP_PORT_CLOCK_CTL(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \
_XELPDP_PORT_CLOCK_CTL_A, \
_XELPDP_PORT_CLOCK_CTL_B, \
_XELPDP_PORT_CLOCK_CTL_USBC1, \
_XELPDP_PORT_CLOCK_CTL_USBC2))
+#define XELPDP_PORT_CLOCK_CTL(i915__, port) \
+ (DISPLAY_VER(i915__) >= 20 ? \
+ _XELPDP_PORT_CLOCK_CTL(__xe2lpd_port_idx(port)) : \
+ _XELPDP_PORT_CLOCK_CTL(port))
#define XELPDP_LANE_PCLK_PLL_REQUEST(lane) REG_BIT(31 - ((lane) * 4))
#define XELPDP_LANE_PCLK_PLL_ACK(lane) REG_BIT(30 - ((lane) * 4))
#define XELPDP_LANE_PCLK_REFCLK_REQUEST(lane) REG_BIT(29 - ((lane) * 4))
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 31aa5d54fd..c17462b4c2 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -54,6 +54,7 @@
#include "intel_dp_aux.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
+#include "intel_dp_tunnel.h"
#include "intel_dpio_phy.h"
#include "intel_dsi.h"
#include "intel_fdi.h"
@@ -178,7 +179,7 @@ static void mtl_wait_ddi_buf_idle(struct drm_i915_private *i915, enum port port)
int ret;
/* FIXME: find out why Bspec's 100us timeout is too short */
- ret = wait_for_us((intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) &
+ ret = wait_for_us((intel_de_read(i915, XELPDP_PORT_BUF_CTL1(i915, port)) &
XELPDP_PORT_BUF_PHY_IDLE), 10000);
if (ret)
drm_err(&i915->drm, "Timeout waiting for DDI BUF %c to get idle\n",
@@ -226,7 +227,9 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv,
}
if (DISPLAY_VER(dev_priv) >= 14)
- ret = _wait_for(!(intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_PORT_BUF_PHY_IDLE),
+ ret = _wait_for(!(intel_de_read(dev_priv,
+ XELPDP_PORT_BUF_CTL1(dev_priv, port)) &
+ XELPDP_PORT_BUF_PHY_IDLE),
timeout_us, 10, 10);
else
ret = _wait_for(!(intel_de_read(dev_priv, DDI_BUF_CTL(port)) & DDI_BUF_IS_IDLE),
@@ -2429,13 +2432,22 @@ mtl_ddi_enable_d2d(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum port port = encoder->port;
+ i915_reg_t reg;
+ u32 set_bits, wait_bits;
- intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port), 0,
- XELPDP_PORT_BUF_D2D_LINK_ENABLE);
+ if (DISPLAY_VER(dev_priv) >= 20) {
+ reg = DDI_BUF_CTL(port);
+ set_bits = XE2LPD_DDI_BUF_D2D_LINK_ENABLE;
+ wait_bits = XE2LPD_DDI_BUF_D2D_LINK_STATE;
+ } else {
+ reg = XELPDP_PORT_BUF_CTL1(dev_priv, port);
+ set_bits = XELPDP_PORT_BUF_D2D_LINK_ENABLE;
+ wait_bits = XELPDP_PORT_BUF_D2D_LINK_STATE;
+ }
- if (wait_for_us((intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) &
- XELPDP_PORT_BUF_D2D_LINK_STATE), 100)) {
- drm_err(&dev_priv->drm, "Timeout waiting for D2D Link enable for PORT_BUF_CTL %c\n",
+ intel_de_rmw(dev_priv, reg, 0, set_bits);
+ if (wait_for_us(intel_de_read(dev_priv, reg) & wait_bits, 100)) {
+ drm_err(&dev_priv->drm, "Timeout waiting for D2D Link enable for DDI/PORT_BUF_CTL %c\n",
port_name(port));
}
}
@@ -2448,7 +2460,7 @@ static void mtl_port_buf_ctl_program(struct intel_encoder *encoder,
enum port port = encoder->port;
u32 val;
- val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port));
+ val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(i915, port));
val &= ~XELPDP_PORT_WIDTH_MASK;
val |= XELPDP_PORT_WIDTH(mtl_get_port_width(crtc_state->lane_count));
@@ -2461,7 +2473,7 @@ static void mtl_port_buf_ctl_program(struct intel_encoder *encoder,
if (dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL)
val |= XELPDP_PORT_REVERSAL;
- intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val);
+ intel_de_write(i915, XELPDP_PORT_BUF_CTL1(i915, port), val);
}
static void mtl_port_buf_ctl_io_selection(struct intel_encoder *encoder)
@@ -2472,7 +2484,7 @@ static void mtl_port_buf_ctl_io_selection(struct intel_encoder *encoder)
val = intel_tc_port_in_tbt_alt_mode(dig_port) ?
XELPDP_PORT_BUF_IO_SELECT_TBT : 0;
- intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port),
+ intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(i915, encoder->port),
XELPDP_PORT_BUF_IO_SELECT_TBT, val);
}
@@ -2898,13 +2910,22 @@ mtl_ddi_disable_d2d_link(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum port port = encoder->port;
+ i915_reg_t reg;
+ u32 clr_bits, wait_bits;
- intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port),
- XELPDP_PORT_BUF_D2D_LINK_ENABLE, 0);
+ if (DISPLAY_VER(dev_priv) >= 20) {
+ reg = DDI_BUF_CTL(port);
+ clr_bits = XE2LPD_DDI_BUF_D2D_LINK_ENABLE;
+ wait_bits = XE2LPD_DDI_BUF_D2D_LINK_STATE;
+ } else {
+ reg = XELPDP_PORT_BUF_CTL1(dev_priv, port);
+ clr_bits = XELPDP_PORT_BUF_D2D_LINK_ENABLE;
+ wait_bits = XELPDP_PORT_BUF_D2D_LINK_STATE;
+ }
- if (wait_for_us(!(intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) &
- XELPDP_PORT_BUF_D2D_LINK_STATE), 100))
- drm_err(&dev_priv->drm, "Timeout waiting for D2D Link disable for PORT_BUF_CTL %c\n",
+ intel_de_rmw(dev_priv, reg, clr_bits, 0);
+ if (wait_for_us(!(intel_de_read(dev_priv, reg) & wait_bits), 100))
+ drm_err(&dev_priv->drm, "Timeout waiting for D2D Link disable for DDI/PORT_BUF_CTL %c\n",
port_name(port));
}
@@ -3038,7 +3059,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
/* De-select Thunderbolt */
if (DISPLAY_VER(dev_priv) >= 14)
- intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(encoder->port),
+ intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(dev_priv, encoder->port),
XELPDP_PORT_BUF_IO_SELECT_TBT, 0);
}
@@ -3319,10 +3340,13 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
if (dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL)
port_buf |= XELPDP_PORT_REVERSAL;
- intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port),
+ intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(dev_priv, port),
XELPDP_PORT_WIDTH_MASK | XELPDP_PORT_REVERSAL, port_buf);
buf_ctl |= DDI_PORT_WIDTH(lane_count);
+
+ if (DISPLAY_VER(dev_priv) >= 20)
+ buf_ctl |= XE2LPD_DDI_BUF_D2D_LINK_ENABLE;
} else if (IS_ALDERLAKE_P(dev_priv) && intel_phy_is_tc(dev_priv, phy)) {
drm_WARN_ON(&dev_priv->drm, !intel_tc_port_in_legacy_mode(dig_port));
buf_ctl |= DDI_BUF_CTL_TC_PHY_OWNERSHIP;
@@ -3543,6 +3567,9 @@ static void mtl_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
/* 6.i Configure and enable DDI_CTL_DE to start sending valid data to port slice */
intel_dp->DP |= DDI_BUF_CTL_ENABLE;
+ if (DISPLAY_VER(dev_priv) >= 20)
+ intel_dp->DP |= XE2LPD_DDI_BUF_D2D_LINK_ENABLE;
+
intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
intel_de_posting_read(dev_priv, DDI_BUF_CTL(port));
@@ -3941,11 +3968,11 @@ static void intel_ddi_get_config(struct intel_encoder *encoder,
if (DISPLAY_VER(dev_priv) >= 8)
bdw_get_trans_port_sync_config(pipe_config);
+ intel_psr_get_config(encoder, pipe_config);
+
intel_read_dp_sdp(encoder, pipe_config, HDMI_PACKET_TYPE_GAMUT_METADATA);
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
- intel_psr_get_config(encoder, pipe_config);
-
intel_audio_codec_get_config(encoder, pipe_config);
}
@@ -4124,7 +4151,7 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder,
intel_tc_port_sanitize_mode(enc_to_dig_port(encoder),
crtc_state);
- if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))
+ if (intel_encoder_is_dp(encoder))
intel_dp_sync_state(encoder, crtc_state);
}
@@ -5122,6 +5149,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
encoder->suspend_complete = intel_ddi_tc_encoder_suspend_complete;
encoder->shutdown_complete = intel_ddi_tc_encoder_shutdown_complete;
+ dig_port->lock = intel_tc_port_lock;
+ dig_port->unlock = intel_tc_port_unlock;
+
if (intel_tc_port_init(dig_port, is_legacy) < 0)
goto err;
}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index b10aad15a6..8af9e61282 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -33,6 +33,7 @@
#include <linux/string_helpers.h>
#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_dp_tunnel.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
@@ -73,6 +74,7 @@
#include "intel_dp.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
+#include "intel_dp_tunnel.h"
#include "intel_dpll.h"
#include "intel_dpll_mgr.h"
#include "intel_dpt.h"
@@ -104,6 +106,7 @@
#include "intel_pmdemand.h"
#include "intel_pps.h"
#include "intel_psr.h"
+#include "intel_psr_regs.h"
#include "intel_sdvo.h"
#include "intel_snps_phy.h"
#include "intel_tc.h"
@@ -2477,7 +2480,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock);
u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16,
bw_overhead);
- u32 data_n = intel_dp_max_data_rate(link_clock, nlanes);
+ u32 data_n = drm_dp_max_dprx_data_rate(link_clock, nlanes);
/*
* Windows/BIOS uses fixed M/N values always. Follow suit.
@@ -4480,6 +4483,8 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state,
saved_state->crc_enabled = slave_crtc_state->crc_enabled;
intel_crtc_free_hw_state(slave_crtc_state);
+ if (slave_crtc_state->dp_tunnel_ref.tunnel)
+ drm_dp_tunnel_ref_put(&slave_crtc_state->dp_tunnel_ref);
memcpy(slave_crtc_state, saved_state, sizeof(*slave_crtc_state));
kfree(saved_state);
@@ -4495,6 +4500,10 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state,
&master_crtc_state->hw.adjusted_mode);
slave_crtc_state->hw.scaling_filter = master_crtc_state->hw.scaling_filter;
+ if (master_crtc_state->dp_tunnel_ref.tunnel)
+ drm_dp_tunnel_ref_get(master_crtc_state->dp_tunnel_ref.tunnel,
+ &slave_crtc_state->dp_tunnel_ref);
+
copy_bigjoiner_crtc_state_nomodeset(state, slave_crtc);
slave_crtc_state->uapi.mode_changed = master_crtc_state->uapi.mode_changed;
@@ -4523,6 +4532,8 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
/* free the old crtc_state->hw members */
intel_crtc_free_hw_state(crtc_state);
+ intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
+
/* FIXME: before the switch to atomic started, a new pipe_config was
* kzalloc'd. Code that depends on any field being zero should be
* fixed, so that the crtc_state can be safely duplicated. For now,
@@ -4764,7 +4775,11 @@ static bool
intel_compare_dp_vsc_sdp(const struct drm_dp_vsc_sdp *a,
const struct drm_dp_vsc_sdp *b)
{
- return memcmp(a, b, sizeof(*a)) == 0;
+ return a->pixelformat == b->pixelformat &&
+ a->colorimetry == b->colorimetry &&
+ a->bpc == b->bpc &&
+ a->dynamic_range == b->dynamic_range &&
+ a->content_type == b->content_type;
}
static bool
@@ -4799,28 +4814,27 @@ pipe_config_infoframe_mismatch(struct drm_i915_private *dev_priv,
}
static void
-pipe_config_dp_vsc_sdp_mismatch(struct drm_i915_private *dev_priv,
+pipe_config_dp_vsc_sdp_mismatch(struct drm_i915_private *i915,
bool fastset, const char *name,
const struct drm_dp_vsc_sdp *a,
const struct drm_dp_vsc_sdp *b)
{
+ struct drm_printer p;
+
if (fastset) {
- if (!drm_debug_enabled(DRM_UT_KMS))
- return;
+ p = drm_dbg_printer(&i915->drm, DRM_UT_KMS, NULL);
- drm_dbg_kms(&dev_priv->drm,
- "fastset requirement not met in %s dp sdp\n", name);
- drm_dbg_kms(&dev_priv->drm, "expected:\n");
- drm_dp_vsc_sdp_log(KERN_DEBUG, dev_priv->drm.dev, a);
- drm_dbg_kms(&dev_priv->drm, "found:\n");
- drm_dp_vsc_sdp_log(KERN_DEBUG, dev_priv->drm.dev, b);
+ drm_printf(&p, "fastset requirement not met in %s dp sdp\n", name);
} else {
- drm_err(&dev_priv->drm, "mismatch in %s dp sdp\n", name);
- drm_err(&dev_priv->drm, "expected:\n");
- drm_dp_vsc_sdp_log(KERN_ERR, dev_priv->drm.dev, a);
- drm_err(&dev_priv->drm, "found:\n");
- drm_dp_vsc_sdp_log(KERN_ERR, dev_priv->drm.dev, b);
+ p = drm_err_printer(&i915->drm, NULL);
+
+ drm_printf(&p, "mismatch in %s dp sdp\n", name);
}
+
+ drm_printf(&p, "expected:\n");
+ drm_dp_vsc_sdp_log(&p, a);
+ drm_printf(&p, "found:\n");
+ drm_dp_vsc_sdp_log(&p, b);
}
/* Returns the length up to and including the last differing byte */
@@ -4838,10 +4852,12 @@ memcmp_diff_len(const u8 *a, const u8 *b, size_t len)
}
static void
-pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
- bool fastset, const char *name,
+pipe_config_buffer_mismatch(bool fastset, const struct intel_crtc *crtc,
+ const char *name,
const u8 *a, const u8 *b, size_t len)
{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
if (fastset) {
if (!drm_debug_enabled(DRM_UT_KMS))
return;
@@ -4850,7 +4866,8 @@ pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
len = memcmp_diff_len(a, b, len);
drm_dbg_kms(&dev_priv->drm,
- "fastset requirement not met in %s buffer\n", name);
+ "[CRTC:%d:%s] fastset requirement not met in %s buffer\n",
+ crtc->base.base.id, crtc->base.name, name);
print_hex_dump(KERN_DEBUG, "expected: ", DUMP_PREFIX_NONE,
16, 0, a, len, false);
print_hex_dump(KERN_DEBUG, "found: ", DUMP_PREFIX_NONE,
@@ -4859,7 +4876,8 @@ pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
/* only dump up to the last difference */
len = memcmp_diff_len(a, b, len);
- drm_err(&dev_priv->drm, "mismatch in %s buffer\n", name);
+ drm_err(&dev_priv->drm, "[CRTC:%d:%s] mismatch in %s buffer\n",
+ crtc->base.base.id, crtc->base.name, name);
print_hex_dump(KERN_ERR, "expected: ", DUMP_PREFIX_NONE,
16, 0, a, len, false);
print_hex_dump(KERN_ERR, "found: ", DUMP_PREFIX_NONE,
@@ -4890,18 +4908,34 @@ pipe_config_mismatch(bool fastset, const struct intel_crtc *crtc,
va_end(args);
}
-static bool fastboot_enabled(struct drm_i915_private *dev_priv)
+static void
+pipe_config_pll_mismatch(bool fastset,
+ const struct intel_crtc *crtc,
+ const char *name,
+ const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
{
- /* Enable fastboot by default on Skylake and newer */
- if (DISPLAY_VER(dev_priv) >= 9)
- return true;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- /* Enable fastboot by default on VLV and CHV */
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- return true;
+ if (fastset) {
+ if (!drm_debug_enabled(DRM_UT_KMS))
+ return;
- /* Disabled by default on all others */
- return false;
+ drm_dbg_kms(&i915->drm,
+ "[CRTC:%d:%s] fastset requirement not met in %s\n",
+ crtc->base.base.id, crtc->base.name, name);
+ drm_dbg_kms(&i915->drm, "expected:\n");
+ intel_dpll_dump_hw_state(i915, a);
+ drm_dbg_kms(&i915->drm, "found:\n");
+ intel_dpll_dump_hw_state(i915, b);
+ } else {
+ drm_err(&i915->drm, "[CRTC:%d:%s] mismatch in %s buffer\n",
+ crtc->base.base.id, crtc->base.name, name);
+ drm_err(&i915->drm, "expected:\n");
+ intel_dpll_dump_hw_state(i915, a);
+ drm_err(&i915->drm, "found:\n");
+ intel_dpll_dump_hw_state(i915, b);
+ }
}
bool
@@ -4912,14 +4946,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
struct drm_i915_private *dev_priv = to_i915(current_config->uapi.crtc->dev);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
bool ret = true;
- bool fixup_inherited = fastset &&
- current_config->inherited && !pipe_config->inherited;
-
- if (fixup_inherited && !fastboot_enabled(dev_priv)) {
- drm_dbg_kms(&dev_priv->drm,
- "initial modeset and fastboot not set\n");
- ret = false;
- }
#define PIPE_CONF_CHECK_X(name) do { \
if (current_config->name != pipe_config->name) { \
@@ -4999,7 +5025,17 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
} \
} while (0)
-#define PIPE_CONF_CHECK_TIMINGS(name) do { \
+#define PIPE_CONF_CHECK_PLL(name) do { \
+ if (!intel_dpll_compare_hw_state(dev_priv, &current_config->name, \
+ &pipe_config->name)) { \
+ pipe_config_pll_mismatch(fastset, crtc, __stringify(name), \
+ &current_config->name, \
+ &pipe_config->name); \
+ ret = false; \
+ } \
+} while (0)
+
+#define PIPE_CONF_CHECK_TIMINGS(name) do { \
PIPE_CONF_CHECK_I(name.crtc_hdisplay); \
PIPE_CONF_CHECK_I(name.crtc_htotal); \
PIPE_CONF_CHECK_I(name.crtc_hblank_start); \
@@ -5045,8 +5081,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
} while (0)
#define PIPE_CONF_CHECK_DP_VSC_SDP(name) do { \
- if (!current_config->has_psr && !pipe_config->has_psr && \
- !intel_compare_dp_vsc_sdp(&current_config->infoframes.name, \
+ if (!intel_compare_dp_vsc_sdp(&current_config->infoframes.name, \
&pipe_config->infoframes.name)) { \
pipe_config_dp_vsc_sdp_mismatch(dev_priv, fastset, __stringify(name), \
&current_config->infoframes.name, \
@@ -5059,7 +5094,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
BUILD_BUG_ON(sizeof(current_config->name) != (len)); \
BUILD_BUG_ON(sizeof(pipe_config->name) != (len)); \
if (!intel_compare_buffer(current_config->name, pipe_config->name, (len))) { \
- pipe_config_buffer_mismatch(dev_priv, fastset, __stringify(name), \
+ pipe_config_buffer_mismatch(fastset, crtc, __stringify(name), \
current_config->name, \
pipe_config->name, \
(len)); \
@@ -5199,53 +5234,16 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_CSC(csc);
PIPE_CONF_CHECK_CSC(output_csc);
-
- if (current_config->active_planes) {
- PIPE_CONF_CHECK_BOOL(has_psr);
- PIPE_CONF_CHECK_BOOL(has_psr2);
- PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
- PIPE_CONF_CHECK_I(dc3co_exitline);
- }
}
PIPE_CONF_CHECK_BOOL(double_wide);
- if (dev_priv->display.dpll.mgr) {
+ if (dev_priv->display.dpll.mgr)
PIPE_CONF_CHECK_P(shared_dpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
- PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
- PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
- PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.spll);
- PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
- PIPE_CONF_CHECK_X(dpll_hw_state.div0);
- PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
- PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
- PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
- }
+ /* FIXME convert everything over the dpll_mgr */
+ if (dev_priv->display.dpll.mgr || HAS_GMCH(dev_priv))
+ PIPE_CONF_CHECK_PLL(dpll_hw_state);
PIPE_CONF_CHECK_X(dsi_pll.ctrl);
PIPE_CONF_CHECK_X(dsi_pll.div);
@@ -5368,6 +5366,10 @@ static int intel_modeset_pipe(struct intel_atomic_state *state,
if (ret)
return ret;
+ ret = intel_dp_tunnel_atomic_add_state_for_crtc(state, crtc);
+ if (ret)
+ return ret;
+
ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc);
if (ret)
return ret;
@@ -6255,12 +6257,11 @@ static int intel_atomic_check_config(struct intel_atomic_state *state,
static int intel_atomic_check_config_and_link(struct intel_atomic_state *state)
{
- struct drm_i915_private *i915 = to_i915(state->base.dev);
struct intel_link_bw_limits new_limits;
struct intel_link_bw_limits old_limits;
int ret;
- intel_link_bw_init_limits(i915, &new_limits);
+ intel_link_bw_init_limits(state, &new_limits);
old_limits = new_limits;
while (true) {
@@ -6307,6 +6308,9 @@ int intel_atomic_check(struct drm_device *dev,
int ret, i;
bool any_ms = false;
+ if (!intel_display_driver_check_access(dev_priv))
+ return -ENODEV;
+
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
/*
@@ -7068,6 +7072,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
drm_atomic_helper_wait_for_dependencies(&state->base);
drm_dp_mst_atomic_wait_for_dependencies(&state->base);
+ intel_atomic_global_state_wait_for_dependencies(state);
/*
* During full modesets we write a lot of registers, wait
@@ -7109,6 +7114,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_commit_modeset_disables(state);
+ intel_dp_tunnel_atomic_alloc_bw(state);
+
/* FIXME: Eventually get rid of our crtc->config pointer */
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
crtc->config = new_crtc_state;
@@ -7244,6 +7251,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_pmdemand_post_plane_update(state);
drm_atomic_helper_commit_hw_done(&state->base);
+ intel_atomic_global_state_commit_done(state);
if (state->modeset) {
/* As one of the primary mmio accessors, KMS has a high
@@ -7294,6 +7302,38 @@ static void intel_atomic_track_fbs(struct intel_atomic_state *state)
plane->frontbuffer_bit);
}
+static int intel_atomic_setup_commit(struct intel_atomic_state *state, bool nonblock)
+{
+ int ret;
+
+ ret = drm_atomic_helper_setup_commit(&state->base, nonblock);
+ if (ret)
+ return ret;
+
+ ret = intel_atomic_global_state_setup_commit(state);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int intel_atomic_swap_state(struct intel_atomic_state *state)
+{
+ int ret;
+
+ ret = drm_atomic_helper_swap_state(&state->base, true);
+ if (ret)
+ return ret;
+
+ intel_atomic_swap_global_state(state);
+
+ intel_shared_dpll_swap_state(state);
+
+ intel_atomic_track_fbs(state);
+
+ return 0;
+}
+
int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,
bool nonblock)
{
@@ -7339,11 +7379,9 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,
return ret;
}
- ret = drm_atomic_helper_setup_commit(&state->base, nonblock);
- if (!ret)
- ret = drm_atomic_helper_swap_state(&state->base, true);
+ ret = intel_atomic_setup_commit(state, nonblock);
if (!ret)
- intel_atomic_swap_global_state(state);
+ ret = intel_atomic_swap_state(state);
if (ret) {
struct intel_crtc_state *new_crtc_state;
@@ -7357,8 +7395,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,
intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);
return ret;
}
- intel_shared_dpll_swap_state(state);
- intel_atomic_track_fbs(state);
drm_atomic_state_get(&state->base);
INIT_WORK(&state->base.commit_work, intel_atomic_commit_work);
@@ -7811,6 +7847,7 @@ static const struct intel_display_funcs skl_display_funcs = {
.crtc_disable = hsw_crtc_disable,
.commit_modeset_enables = skl_commit_modeset_enables,
.get_initial_plane_config = skl_get_initial_plane_config,
+ .fixup_initial_plane_config = skl_fixup_initial_plane_config,
};
static const struct intel_display_funcs ddi_display_funcs = {
@@ -7819,6 +7856,7 @@ static const struct intel_display_funcs ddi_display_funcs = {
.crtc_disable = hsw_crtc_disable,
.commit_modeset_enables = intel_commit_modeset_enables,
.get_initial_plane_config = i9xx_get_initial_plane_config,
+ .fixup_initial_plane_config = i9xx_fixup_initial_plane_config,
};
static const struct intel_display_funcs pch_split_display_funcs = {
@@ -7827,6 +7865,7 @@ static const struct intel_display_funcs pch_split_display_funcs = {
.crtc_disable = ilk_crtc_disable,
.commit_modeset_enables = intel_commit_modeset_enables,
.get_initial_plane_config = i9xx_get_initial_plane_config,
+ .fixup_initial_plane_config = i9xx_fixup_initial_plane_config,
};
static const struct intel_display_funcs vlv_display_funcs = {
@@ -7835,6 +7874,7 @@ static const struct intel_display_funcs vlv_display_funcs = {
.crtc_disable = i9xx_crtc_disable,
.commit_modeset_enables = intel_commit_modeset_enables,
.get_initial_plane_config = i9xx_get_initial_plane_config,
+ .fixup_initial_plane_config = i9xx_fixup_initial_plane_config,
};
static const struct intel_display_funcs i9xx_display_funcs = {
@@ -7843,6 +7883,7 @@ static const struct intel_display_funcs i9xx_display_funcs = {
.crtc_disable = i9xx_crtc_disable,
.commit_modeset_enables = intel_commit_modeset_enables,
.get_initial_plane_config = i9xx_get_initial_plane_config,
+ .fixup_initial_plane_config = i9xx_fixup_initial_plane_config,
};
/**
@@ -8051,8 +8092,9 @@ void intel_hpd_poll_fini(struct drm_i915_private *i915)
/* Kill all the work that may have been queued by hpd. */
drm_connector_list_iter_begin(&i915->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
- if (connector->modeset_retry_work.func)
- cancel_work_sync(&connector->modeset_retry_work);
+ if (connector->modeset_retry_work.func &&
+ cancel_work_sync(&connector->modeset_retry_work))
+ drm_connector_put(&connector->base);
if (connector->hdcp.shim) {
cancel_delayed_work_sync(&connector->hdcp.check_work);
cancel_work_sync(&connector->hdcp.prop_work);
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 47297ed858..2167dbee5e 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -28,6 +28,8 @@
#include "intel_opregion.h"
#include "intel_wm_types.h"
+struct task_struct;
+
struct drm_i915_private;
struct drm_property;
struct drm_property_blob;
@@ -47,6 +49,7 @@ struct intel_fbdev;
struct intel_fdi_funcs;
struct intel_hotplug_funcs;
struct intel_initial_plane_config;
+struct intel_opregion;
struct intel_overlay;
/* Amount of SAGV/QGV points, BSpec precisely defines this */
@@ -64,6 +67,8 @@ struct intel_display_funcs {
struct intel_crtc_state *);
void (*get_initial_plane_config)(struct intel_crtc *,
struct intel_initial_plane_config *);
+ bool (*fixup_initial_plane_config)(struct intel_crtc *crtc,
+ const struct intel_initial_plane_config *plane_config);
void (*crtc_enable)(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void (*crtc_disable)(struct intel_atomic_state *state,
@@ -172,6 +177,12 @@ struct intel_hotplug {
struct work_struct poll_init_work;
bool poll_enabled;
+ /*
+ * Queuing of hotplug_work, reenable_work and poll_init_work is
+ * enabled. Protected by drm_i915_private::irq_lock.
+ */
+ bool detection_work_enabled;
+
unsigned int hpd_storm_threshold;
/* Whether or not to count short HPD IRQs in HPD storms */
u8 hpd_short_storm_enabled;
@@ -299,6 +310,11 @@ struct intel_display {
} funcs;
struct {
+ bool any_task_allowed;
+ struct task_struct *allowed_task;
+ } access;
+
+ struct {
/* backlight registers and fields in struct intel_panel */
struct mutex lock;
} backlight;
@@ -508,12 +524,13 @@ struct intel_display {
} wq;
/* Grouping using named structs. Keep sorted. */
+ struct drm_dp_tunnel_mgr *dp_tunnel_mgr;
struct intel_audio audio;
struct intel_dpll dpll;
struct intel_fbc *fbc[I915_MAX_FBCS];
struct intel_frontbuffer_tracking fb_tracking;
struct intel_hotplug hotplug;
- struct intel_opregion opregion;
+ struct intel_opregion *opregion;
struct intel_overlay *overlay;
struct intel_display_params params;
struct intel_vbt_data vbt;
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index d951edb366..b99c024b09 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -86,28 +86,6 @@ static int i915_sr_status(struct seq_file *m, void *unused)
return 0;
}
-static int i915_opregion(struct seq_file *m, void *unused)
-{
- struct drm_i915_private *i915 = node_to_i915(m->private);
- struct intel_opregion *opregion = &i915->display.opregion;
-
- if (opregion->header)
- seq_write(m, opregion->header, OPREGION_SIZE);
-
- return 0;
-}
-
-static int i915_vbt(struct seq_file *m, void *unused)
-{
- struct drm_i915_private *i915 = node_to_i915(m->private);
- struct intel_opregion *opregion = &i915->display.opregion;
-
- if (opregion->vbt)
- seq_write(m, opregion->vbt, opregion->vbt_size);
-
- return 0;
-}
-
static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
@@ -210,7 +188,8 @@ static void intel_panel_info(struct seq_file *m,
}
static void intel_hdcp_info(struct seq_file *m,
- struct intel_connector *intel_connector)
+ struct intel_connector *intel_connector,
+ bool remote_req)
{
bool hdcp_cap, hdcp2_cap;
@@ -219,8 +198,14 @@ static void intel_hdcp_info(struct seq_file *m,
goto out;
}
- hdcp_cap = intel_hdcp_capable(intel_connector);
- hdcp2_cap = intel_hdcp2_capable(intel_connector);
+ if (remote_req) {
+ intel_hdcp_get_remote_capability(intel_connector,
+ &hdcp_cap,
+ &hdcp2_cap);
+ } else {
+ hdcp_cap = intel_hdcp_get_capability(intel_connector);
+ hdcp2_cap = intel_hdcp2_get_capability(intel_connector);
+ }
if (hdcp_cap)
seq_puts(m, "HDCP1.4 ");
@@ -307,7 +292,11 @@ static void intel_connector_info(struct seq_file *m,
}
seq_puts(m, "\tHDCP version: ");
- intel_hdcp_info(m, intel_connector);
+ if (intel_encoder_is_mst(encoder)) {
+ intel_hdcp_info(m, intel_connector, true);
+ seq_puts(m, "\tMST Hub HDCP version: ");
+ }
+ intel_hdcp_info(m, intel_connector, false);
seq_printf(m, "\tmax bpc: %u\n", connector->display_info.bpc);
@@ -1066,8 +1055,6 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
static const struct drm_info_list intel_display_debugfs_list[] = {
{"i915_frontbuffer_tracking", i915_frontbuffer_tracking, 0},
{"i915_sr_status", i915_sr_status, 0},
- {"i915_opregion", i915_opregion, 0},
- {"i915_vbt", i915_vbt, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_power_domain_info", i915_power_domain_info, 0},
{"i915_display_info", i915_display_info, 0},
@@ -1105,10 +1092,12 @@ void intel_display_debugfs_register(struct drm_i915_private *i915)
ARRAY_SIZE(intel_display_debugfs_list),
minor->debugfs_root, minor);
+ intel_bios_debugfs_register(i915);
intel_cdclk_debugfs_register(i915);
intel_dmc_debugfs_register(i915);
intel_fbc_debugfs_register(i915);
intel_hpd_debugfs_register(i915);
+ intel_opregion_debugfs_register(i915);
intel_psr_debugfs_register(i915);
intel_wm_debugfs_register(i915);
intel_display_debugfs_params(i915);
@@ -1153,7 +1142,7 @@ static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data)
seq_printf(m, "%s:%d HDCP version: ", connector->base.name,
connector->base.base.id);
- intel_hdcp_info(m, connector);
+ intel_hdcp_info(m, connector, false);
out:
drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
@@ -1413,6 +1402,20 @@ out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
return ret;
}
+static int i915_bigjoiner_enable_show(struct seq_file *m, void *data)
+{
+ struct intel_connector *connector = m->private;
+ struct drm_crtc *crtc;
+
+ crtc = connector->base.state->crtc;
+ if (connector->base.status != connector_status_connected || !crtc)
+ return -ENODEV;
+
+ seq_printf(m, "Bigjoiner enable: %d\n", connector->force_bigjoiner_enable);
+
+ return 0;
+}
+
static ssize_t i915_dsc_output_format_write(struct file *file,
const char __user *ubuf,
size_t len, loff_t *offp)
@@ -1434,6 +1437,30 @@ static ssize_t i915_dsc_output_format_write(struct file *file,
return len;
}
+static ssize_t i915_bigjoiner_enable_write(struct file *file,
+ const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct intel_connector *connector = m->private;
+ struct drm_crtc *crtc;
+ bool bigjoiner_en = 0;
+ int ret;
+
+ crtc = connector->base.state->crtc;
+ if (connector->base.status != connector_status_connected || !crtc)
+ return -ENODEV;
+
+ ret = kstrtobool_from_user(ubuf, len, &bigjoiner_en);
+ if (ret < 0)
+ return ret;
+
+ connector->force_bigjoiner_enable = bigjoiner_en;
+ *offp += len;
+
+ return len;
+}
+
static int i915_dsc_output_format_open(struct inode *inode,
struct file *file)
{
@@ -1527,6 +1554,8 @@ static const struct file_operations i915_dsc_fractional_bpp_fops = {
.write = i915_dsc_fractional_bpp_write
};
+DEFINE_SHOW_STORE_ATTRIBUTE(i915_bigjoiner_enable);
+
/*
* Returns the Current CRTC's bpc.
* Example usage: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc
@@ -1608,6 +1637,13 @@ void intel_connector_debugfs_add(struct intel_connector *connector)
connector, &i915_dsc_fractional_bpp_fops);
}
+ if (DISPLAY_VER(i915) >= 11 &&
+ (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ debugfs_create_file("i915_bigjoiner_force_enable", 0644, root,
+ connector, &i915_bigjoiner_enable_fops);
+ }
+
if (connector_type == DRM_MODE_CONNECTOR_DSI ||
connector_type == DRM_MODE_CONNECTOR_eDP ||
connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c
index b7e68eb624..f357187485 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c
@@ -3,6 +3,7 @@
* Copyright © 2023 Intel Corporation
*/
+#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <drm/drm_drv.h>
diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c
index 0b522c6a8d..c02d79b500 100644
--- a/drivers/gpu/drm/i915/display/intel_display_device.c
+++ b/drivers/gpu/drm/i915/display/intel_display_device.c
@@ -1012,7 +1012,7 @@ static void __intel_display_device_info_runtime_init(struct drm_i915_private *i9
goto display_fused_off;
}
- if (IS_GRAPHICS_VER(i915, 7, 8) && HAS_PCH_SPLIT(i915)) {
+ if (IS_DISPLAY_VER(i915, 7, 8) && HAS_PCH_SPLIT(i915)) {
u32 fuse_strap = intel_de_read(i915, FUSE_STRAP);
u32 sfuse_strap = intel_de_read(i915, SFUSE_STRAP);
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index 9df9097a02..6da5e85abe 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -35,6 +35,7 @@
#include "intel_dkl_phy.h"
#include "intel_dmc.h"
#include "intel_dp.h"
+#include "intel_dp_tunnel.h"
#include "intel_dpll.h"
#include "intel_dpll_mgr.h"
#include "intel_fb.h"
@@ -45,6 +46,7 @@
#include "intel_hdcp.h"
#include "intel_hotplug.h"
#include "intel_hti.h"
+#include "intel_modeset_lock.h"
#include "intel_modeset_setup.h"
#include "intel_opregion.h"
#include "intel_overlay.h"
@@ -276,12 +278,144 @@ cleanup_bios:
return ret;
}
+static void set_display_access(struct drm_i915_private *i915,
+ bool any_task_allowed,
+ struct task_struct *allowed_task)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ int err;
+
+ intel_modeset_lock_ctx_retry(&ctx, NULL, 0, err) {
+ err = drm_modeset_lock_all_ctx(&i915->drm, &ctx);
+ if (err)
+ continue;
+
+ i915->display.access.any_task_allowed = any_task_allowed;
+ i915->display.access.allowed_task = allowed_task;
+ }
+
+ drm_WARN_ON(&i915->drm, err);
+}
+
+/**
+ * intel_display_driver_enable_user_access - Enable display HW access for all threads
+ * @i915: i915 device instance
+ *
+ * Enable the display HW access for all threads. Examples for such accesses
+ * are modeset commits and connector probing.
+ *
+ * This function should be called during driver loading and system resume once
+ * all the HW initialization steps are done.
+ */
+void intel_display_driver_enable_user_access(struct drm_i915_private *i915)
+{
+ set_display_access(i915, true, NULL);
+
+ intel_hpd_enable_detection_work(i915);
+}
+
+/**
+ * intel_display_driver_disable_user_access - Disable display HW access for user threads
+ * @i915: i915 device instance
+ *
+ * Disable the display HW access for user threads. Examples for such accesses
+ * are modeset commits and connector probing. For the current thread the
+ * access is still enabled, which should only perform HW init/deinit
+ * programming (as the initial modeset during driver loading or the disabling
+ * modeset during driver unloading and system suspend/shutdown). This function
+ * should be followed by calling either intel_display_driver_enable_user_access()
+ * after completing the HW init programming or
+ * intel_display_driver_suspend_access() after completing the HW deinit
+ * programming.
+ *
+ * This function should be called during driver loading/unloading and system
+ * suspend/shutdown before starting the HW init/deinit programming.
+ */
+void intel_display_driver_disable_user_access(struct drm_i915_private *i915)
+{
+ intel_hpd_disable_detection_work(i915);
+
+ set_display_access(i915, false, current);
+}
+
+/**
+ * intel_display_driver_suspend_access - Suspend display HW access for all threads
+ * @i915: i915 device instance
+ *
+ * Disable the display HW access for all threads. Examples for such accesses
+ * are modeset commits and connector probing. This call should be either
+ * followed by calling intel_display_driver_resume_access(), or the driver
+ * should be unloaded/shutdown.
+ *
+ * This function should be called during driver unloading and system
+ * suspend/shutdown after completing the HW deinit programming.
+ */
+void intel_display_driver_suspend_access(struct drm_i915_private *i915)
+{
+ set_display_access(i915, false, NULL);
+}
+
+/**
+ * intel_display_driver_resume_access - Resume display HW access for the resume thread
+ * @i915: i915 device instance
+ *
+ * Enable the display HW access for the current resume thread, keeping the
+ * access disabled for all other (user) threads. Examples for such accesses
+ * are modeset commits and connector probing. The resume thread should only
+ * perform HW init programming (as the restoring modeset). This function
+ * should be followed by calling intel_display_driver_enable_user_access(),
+ * after completing the HW init programming steps.
+ *
+ * This function should be called during system resume before starting the HW
+ * init steps.
+ */
+void intel_display_driver_resume_access(struct drm_i915_private *i915)
+{
+ set_display_access(i915, false, current);
+}
+
+/**
+ * intel_display_driver_check_access - Check if the current thread has disaplay HW access
+ * @i915: i915 device instance
+ *
+ * Check whether the current thread has display HW access, print a debug
+ * message if it doesn't. Such accesses are modeset commits and connector
+ * probing. If the function returns %false any HW access should be prevented.
+ *
+ * Returns %true if the current thread has display HW access, %false
+ * otherwise.
+ */
+bool intel_display_driver_check_access(struct drm_i915_private *i915)
+{
+ char comm[TASK_COMM_LEN];
+ char current_task[TASK_COMM_LEN + 16];
+ char allowed_task[TASK_COMM_LEN + 16] = "none";
+
+ if (i915->display.access.any_task_allowed ||
+ i915->display.access.allowed_task == current)
+ return true;
+
+ snprintf(current_task, sizeof(current_task), "%s[%d]",
+ get_task_comm(comm, current),
+ task_pid_vnr(current));
+
+ if (i915->display.access.allowed_task)
+ snprintf(allowed_task, sizeof(allowed_task), "%s[%d]",
+ get_task_comm(comm, i915->display.access.allowed_task),
+ task_pid_vnr(i915->display.access.allowed_task));
+
+ drm_dbg_kms(&i915->drm,
+ "Reject display access from task %s (allowed to %s)\n",
+ current_task, allowed_task);
+
+ return false;
+}
+
/* part #2: call after irq install, but before gem init */
int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
{
struct drm_device *dev = &i915->drm;
enum pipe pipe;
- struct intel_crtc *crtc;
int ret;
if (!HAS_DISPLAY(i915))
@@ -301,10 +435,8 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
for_each_pipe(i915, pipe) {
ret = intel_crtc_init(i915, pipe);
- if (ret) {
- intel_mode_config_cleanup(i915);
- return ret;
- }
+ if (ret)
+ goto err_mode_config;
}
intel_plane_possible_crtcs_init(i915);
@@ -315,8 +447,6 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
intel_display_driver_init_hw(i915);
intel_dpll_update_ref_clks(i915);
- intel_hdcp_component_init(i915);
-
if (i915->display.cdclk.max_cdclk_freq == 0)
intel_update_max_cdclk(i915);
@@ -326,16 +456,18 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
intel_vga_disable(i915);
intel_setup_outputs(i915);
+ ret = intel_dp_tunnel_mgr_init(i915);
+ if (ret)
+ goto err_hdcp;
+
+ intel_display_driver_disable_user_access(i915);
+
drm_modeset_lock_all(dev);
intel_modeset_setup_hw_state(i915, dev->mode_config.acquire_ctx);
intel_acpi_assign_connector_fwnodes(i915);
drm_modeset_unlock_all(dev);
- for_each_intel_crtc(dev, crtc) {
- if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
- continue;
- intel_crtc_initial_plane_config(crtc);
- }
+ intel_initial_plane_config(i915);
/*
* Make sure hardware watermarks really match the state we read out.
@@ -346,6 +478,13 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
ilk_wm_sanitize(i915);
return 0;
+
+err_hdcp:
+ intel_hdcp_component_fini(i915);
+err_mode_config:
+ intel_mode_config_cleanup(i915);
+
+ return ret;
}
/* part #3: call after gem init */
@@ -357,6 +496,13 @@ int intel_display_driver_probe(struct drm_i915_private *i915)
return 0;
/*
+ * This will bind stuff into ggtt, so it needs to be done after
+ * the BIOS fb takeover and whatever else magic ggtt reservations
+ * happen during gem/ggtt init.
+ */
+ intel_hdcp_component_init(i915);
+
+ /*
* Force all active planes to recompute their states. So that on
* mode_setcrtc after probe, all the intel_plane_state variables
* are already calculated and there is no assert_plane warnings
@@ -374,7 +520,6 @@ int intel_display_driver_probe(struct drm_i915_private *i915)
/* Only enable hotplug handling once the fbdev is fully set up. */
intel_hpd_init(i915);
- intel_hpd_poll_disable(i915);
skl_watermark_ipc_init(i915);
@@ -383,7 +528,8 @@ int intel_display_driver_probe(struct drm_i915_private *i915)
void intel_display_driver_register(struct drm_i915_private *i915)
{
- struct drm_printer p = drm_debug_printer("i915 display info:");
+ struct drm_printer p = drm_dbg_printer(&i915->drm, DRM_UT_KMS,
+ "i915 display info:");
if (!HAS_DISPLAY(i915))
return;
@@ -394,6 +540,10 @@ void intel_display_driver_register(struct drm_i915_private *i915)
intel_audio_init(i915);
+ intel_display_driver_enable_user_access(i915);
+
+ intel_audio_register(i915);
+
intel_display_debugfs_register(i915);
/*
@@ -412,6 +562,7 @@ void intel_display_driver_register(struct drm_i915_private *i915)
* fbdev->async_cookie.
*/
drm_kms_helper_poll_init(&i915->drm);
+ intel_hpd_poll_disable(i915);
intel_display_device_info_print(DISPLAY_INFO(i915),
DISPLAY_RUNTIME_INFO(i915), &p);
@@ -440,6 +591,8 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915)
if (!HAS_DISPLAY(i915))
return;
+ intel_display_driver_suspend_access(i915);
+
/*
* Due to the hpd irq storm handling the hotplug work can re-arm the
* poll handlers. Hence disable polling after hpd handling is shut down.
@@ -458,6 +611,8 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915)
intel_mode_config_cleanup(i915);
+ intel_dp_tunnel_mgr_cleanup(i915);
+
intel_overlay_cleanup(i915);
intel_gmbus_teardown(i915);
@@ -486,14 +641,17 @@ void intel_display_driver_unregister(struct drm_i915_private *i915)
return;
intel_fbdev_unregister(i915);
- intel_audio_deinit(i915);
-
/*
* After flushing the fbdev (incl. a late async config which
* will have delayed queuing of a hotplug event), then flush
* the hotplug events.
*/
drm_kms_helper_poll_fini(&i915->drm);
+
+ intel_display_driver_disable_user_access(i915);
+
+ intel_audio_deinit(i915);
+
drm_atomic_helper_shutdown(&i915->drm);
acpi_video_unregister();
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.h b/drivers/gpu/drm/i915/display/intel_display_driver.h
index c276a58ee3..42cc4af6d3 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.h
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.h
@@ -32,5 +32,11 @@ int __intel_display_driver_resume(struct drm_i915_private *i915,
struct drm_atomic_state *state,
struct drm_modeset_acquire_ctx *ctx);
+void intel_display_driver_enable_user_access(struct drm_i915_private *i915);
+void intel_display_driver_disable_user_access(struct drm_i915_private *i915);
+void intel_display_driver_suspend_access(struct drm_i915_private *i915);
+void intel_display_driver_resume_access(struct drm_i915_private *i915);
+bool intel_display_driver_check_access(struct drm_i915_private *i915);
+
#endif /* __INTEL_DISPLAY_DRIVER_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index a7d8f3fc98..f846c5b108 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -266,12 +266,12 @@ void i915_disable_pipestat(struct drm_i915_private *dev_priv,
intel_uncore_posting_read(&dev_priv->uncore, reg);
}
-static bool i915_has_asle(struct drm_i915_private *dev_priv)
+static bool i915_has_asle(struct drm_i915_private *i915)
{
- if (!dev_priv->display.opregion.asle)
+ if (!IS_PINEVIEW(i915) && !IS_MOBILE(i915))
return false;
- return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv);
+ return intel_opregion_asle_present(i915);
}
/**
@@ -986,7 +986,7 @@ static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_i
* their flags both in the PICA and SDE IIR.
*/
if (*pch_iir & SDE_PICAINTERRUPT) {
- drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP);
+ drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTL);
pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0);
*pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR);
@@ -1587,7 +1587,7 @@ void ilk_de_irq_postinstall(struct drm_i915_private *i915)
struct intel_uncore *uncore = &i915->uncore;
u32 display_mask, extra_mask;
- if (GRAPHICS_VER(i915) >= 7) {
+ if (DISPLAY_VER(i915) >= 7) {
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB);
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 9529f77b87..bf3f942e19 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -33,6 +33,7 @@
#include <drm/display/drm_dp_dual_mode_helper.h>
#include <drm/display/drm_dp_mst_helper.h>
+#include <drm/display/drm_dp_tunnel.h>
#include <drm/display/drm_dsc.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
@@ -327,7 +328,6 @@ struct intel_vbt_panel_data {
struct edp_power_seq pps;
u8 drrs_msa_timing_delay;
bool low_vswing;
- bool initialized;
bool hobl;
} edp;
@@ -499,15 +499,15 @@ struct intel_hdcp_shim {
struct intel_connector *connector);
/* Detects panel's hdcp capability. This is optional for HDMI. */
- int (*hdcp_capable)(struct intel_digital_port *dig_port,
- bool *hdcp_capable);
+ int (*hdcp_get_capability)(struct intel_digital_port *dig_port,
+ bool *hdcp_capable);
/* HDCP adaptation(DP/HDMI) required on the port */
enum hdcp_wired_protocol protocol;
/* Detects whether sink is HDCP2.2 capable */
- int (*hdcp_2_2_capable)(struct intel_connector *connector,
- bool *capable);
+ int (*hdcp_2_2_get_capability)(struct intel_connector *connector,
+ bool *capable);
/* Write HDCP2.2 messages */
int (*write_2_2_msg)(struct intel_connector *connector,
@@ -532,6 +532,10 @@ struct intel_hdcp_shim {
/* HDCP2.2 Link Integrity Check */
int (*check_2_2_link)(struct intel_digital_port *dig_port,
struct intel_connector *connector);
+
+ /* HDCP remote sink cap */
+ int (*get_remote_hdcp_capability)(struct intel_connector *connector,
+ bool *hdcp_capable, bool *hdcp2_capable);
};
struct intel_hdcp {
@@ -633,6 +637,8 @@ struct intel_connector {
struct intel_dp *mst_port;
+ bool force_bigjoiner_enable;
+
struct {
struct drm_dp_aux *dsc_decompression_aux;
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
@@ -684,6 +690,8 @@ struct intel_atomic_state {
struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS];
+ struct intel_dp_tunnel_inherited_state *inherited_dp_tunnels;
+
/*
* Current watermarks can't be trusted during hardware readout, so
* don't bother calculating intermediate watermarks.
@@ -788,6 +796,8 @@ struct intel_plane_state {
struct intel_initial_plane_config {
struct intel_framebuffer *fb;
+ struct intel_memory_region *mem;
+ resource_size_t phys_base;
struct i915_vma *vma;
unsigned int tiling;
int size;
@@ -1221,12 +1231,12 @@ struct intel_crtc_state {
bool has_psr;
bool has_psr2;
bool enable_psr2_sel_fetch;
+ bool enable_psr2_su_region_et;
bool req_psr2_sdp_prior_scanline;
bool has_panel_replay;
bool wm_level_disabled;
u32 dc3co_exitline;
u16 su_y_granularity;
- struct drm_dp_vsc_sdp psr_vsc;
/*
* Frequence the dpll for the port should run at. Differs from the
@@ -1380,6 +1390,9 @@ struct intel_crtc_state {
struct drm_dsc_config config;
} dsc;
+ /* DP tunnel used for BW allocation. */
+ struct drm_dp_tunnel_ref dp_tunnel_ref;
+
/* HSW+ linetime watermarks */
u16 linetime;
u16 ips_linetime;
@@ -1410,6 +1423,10 @@ struct intel_crtc_state {
u32 psr2_man_track_ctl;
+ u32 pipe_srcsz_early_tpt;
+
+ struct drm_rect psr2_su_area;
+
/* Variable Refresh Rate state */
struct {
bool enable, in_range;
@@ -1690,13 +1707,14 @@ struct intel_psr {
/* Mutex for PSR state of the transcoder */
struct mutex lock;
-#define I915_PSR_DEBUG_MODE_MASK 0x0f
-#define I915_PSR_DEBUG_DEFAULT 0x00
-#define I915_PSR_DEBUG_DISABLE 0x01
-#define I915_PSR_DEBUG_ENABLE 0x02
-#define I915_PSR_DEBUG_FORCE_PSR1 0x03
-#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4
-#define I915_PSR_DEBUG_IRQ 0x10
+#define I915_PSR_DEBUG_MODE_MASK 0x0f
+#define I915_PSR_DEBUG_DEFAULT 0x00
+#define I915_PSR_DEBUG_DISABLE 0x01
+#define I915_PSR_DEBUG_ENABLE 0x02
+#define I915_PSR_DEBUG_FORCE_PSR1 0x03
+#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4
+#define I915_PSR_DEBUG_IRQ 0x10
+#define I915_PSR_DEBUG_SU_REGION_ET_DISABLE 0x20
u32 debug;
bool sink_support;
@@ -1710,14 +1728,20 @@ struct intel_psr {
unsigned int busy_frontbuffer_bits;
bool sink_psr2_support;
bool link_standby;
- bool colorimetry_support;
bool psr2_enabled;
bool psr2_sel_fetch_enabled;
bool psr2_sel_fetch_cff_enabled;
bool req_psr2_sdp_prior_scanline;
u8 sink_sync_latency;
- u8 io_wake_lines;
- u8 fast_wake_lines;
+
+ struct {
+ u8 io_wake_lines;
+ u8 fast_wake_lines;
+
+ /* LNL and beyond */
+ u8 check_entry_lines;
+ } alpm_parameters;
+
ktime_t last_entry_attempt;
ktime_t last_exit;
bool sink_not_reliable;
@@ -1781,6 +1805,9 @@ struct intel_dp {
/* connector directly attached - won't be use for modeset in mst world */
struct intel_connector *attached_connector;
+ struct drm_dp_tunnel *tunnel;
+ bool tunnel_suspended:1;
+
/* mst connector list */
struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES];
struct drm_dp_mst_topology_mgr mst_mgr;
@@ -1841,6 +1868,8 @@ struct intel_dp {
/* When we last wrote the OUI for eDP */
unsigned long last_oui_write;
+
+ bool colorimetry_support;
};
enum lspcon_vendor {
@@ -1898,6 +1927,9 @@ struct intel_digital_port {
u32 (*infoframes_enabled)(struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config);
bool (*connected)(struct intel_encoder *encoder);
+
+ void (*lock)(struct intel_digital_port *dig_port);
+ void (*unlock)(struct intel_digital_port *dig_port);
};
struct intel_dp_mst_encoder {
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c
index b70502586a..8357816244 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.c
+++ b/drivers/gpu/drm/i915/display/intel_dmc.c
@@ -1158,7 +1158,7 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused)
str_yes_no(intel_dmc_has_payload(i915)));
seq_printf(m, "path: %s\n", dmc ? dmc->fw_path : "N/A");
seq_printf(m, "Pipe A fw needed: %s\n",
- str_yes_no(GRAPHICS_VER(i915) >= 12));
+ str_yes_no(DISPLAY_VER(i915) >= 12));
seq_printf(m, "Pipe A fw loaded: %s\n",
str_yes_no(has_dmc_id_fw(i915, DMC_FW_PIPEA)));
seq_printf(m, "Pipe B fw needed: %s\n",
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4e8545126e..950f86fb13 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -36,6 +36,7 @@
#include <asm/byteorder.h>
#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_dp_tunnel.h>
#include <drm/display/drm_dsc_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/drm_atomic_helper.h>
@@ -56,14 +57,17 @@
#include "intel_cx0_phy.h"
#include "intel_ddi.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_dp_hdcp.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
+#include "intel_dp_tunnel.h"
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
+#include "intel_drrs.h"
#include "intel_fifo_underrun.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
@@ -151,6 +155,22 @@ int intel_dp_link_symbol_clock(int rate)
return DIV_ROUND_CLOSEST(rate * 10, intel_dp_link_symbol_size(rate));
}
+static int max_dprx_rate(struct intel_dp *intel_dp)
+{
+ if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ return drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel);
+
+ return drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+}
+
+static int max_dprx_lane_count(struct intel_dp *intel_dp)
+{
+ if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ return drm_dp_tunnel_max_dprx_lane_count(intel_dp->tunnel);
+
+ return drm_dp_max_lane_count(intel_dp->dpcd);
+}
+
static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp)
{
intel_dp->sink_rates[0] = 162000;
@@ -179,7 +199,7 @@ static void intel_dp_set_dpcd_sink_rates(struct intel_dp *intel_dp)
/*
* Sink rates for 8b/10b.
*/
- max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+ max_rate = max_dprx_rate(intel_dp);
max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
if (max_lttpr_rate)
max_rate = min(max_rate, max_lttpr_rate);
@@ -258,7 +278,7 @@ static void intel_dp_set_max_sink_lane_count(struct intel_dp *intel_dp)
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct intel_encoder *encoder = &intel_dig_port->base;
- intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
+ intel_dp->max_sink_lane_count = max_dprx_lane_count(intel_dp);
switch (intel_dp->max_sink_lane_count) {
case 1:
@@ -308,7 +328,7 @@ static int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
}
/* Theoretical max between source and sink */
-static int intel_dp_max_common_rate(struct intel_dp *intel_dp)
+int intel_dp_max_common_rate(struct intel_dp *intel_dp)
{
return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
}
@@ -325,7 +345,7 @@ static int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port)
}
/* Theoretical max between source and sink */
-static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
+int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
int source_max = intel_dp_max_source_lane_count(dig_port);
@@ -382,50 +402,27 @@ int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16,
1000000 * 16 * 8);
}
-/*
- * Given a link rate and lanes, get the data bandwidth.
- *
- * Data bandwidth is the actual payload rate, which depends on the data
- * bandwidth efficiency and the link rate.
+/**
+ * intel_dp_max_link_data_rate: Calculate the maximum rate for the given link params
+ * @intel_dp: Intel DP object
+ * @max_dprx_rate: Maximum data rate of the DPRX
+ * @max_dprx_lanes: Maximum lane count of the DPRX
*
- * For 8b/10b channel encoding, SST and non-FEC, the data bandwidth efficiency
- * is 80%. For example, for a 1.62 Gbps link, 1.62*10^9 bps * 0.80 * (1/8) =
- * 162000 kBps. With 8-bit symbols, we have 162000 kHz symbol clock. Just by
- * coincidence, the port clock in kHz matches the data bandwidth in kBps, and
- * they equal the link bit rate in Gbps multiplied by 100000. (Note that this no
- * longer holds for data bandwidth as soon as FEC or MST is taken into account!)
+ * Calculate the maximum data rate for the provided link parameters taking into
+ * account any BW limitations by a DP tunnel attached to @intel_dp.
*
- * For 128b/132b channel encoding, the data bandwidth efficiency is 96.71%. For
- * example, for a 10 Gbps link, 10*10^9 bps * 0.9671 * (1/8) = 1208875
- * kBps. With 32-bit symbols, we have 312500 kHz symbol clock. The value 1000000
- * does not match the symbol clock, the port clock (not even if you think in
- * terms of a byte clock), nor the data bandwidth. It only matches the link bit
- * rate in units of 10000 bps.
+ * Returns the maximum data rate in kBps units.
*/
-int
-intel_dp_max_data_rate(int max_link_rate, int max_lanes)
+int intel_dp_max_link_data_rate(struct intel_dp *intel_dp,
+ int max_dprx_rate, int max_dprx_lanes)
{
- int ch_coding_efficiency =
- drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate));
- int max_link_rate_kbps = max_link_rate * 10;
+ int max_rate = drm_dp_max_dprx_data_rate(max_dprx_rate, max_dprx_lanes);
- /*
- * UHBR rates always use 128b/132b channel encoding, and have
- * 97.71% data bandwidth efficiency. Consider max_link_rate the
- * link bit rate in units of 10000 bps.
- */
- /*
- * Lower than UHBR rates always use 8b/10b channel encoding, and have
- * 80% data bandwidth efficiency for SST non-FEC. However, this turns
- * out to be a nop by coincidence:
- *
- * int max_link_rate_kbps = max_link_rate * 10;
- * max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10);
- * max_link_rate = max_link_rate_kbps / 8;
- */
- return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps * max_lanes,
- ch_coding_efficiency),
- 1000000 * 8);
+ if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ max_rate = min(max_rate,
+ drm_dp_tunnel_available_bw(intel_dp->tunnel));
+
+ return max_rate;
}
bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
@@ -434,6 +431,10 @@ bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
struct intel_encoder *encoder = &intel_dig_port->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ /* eDP MSO is not compatible with joiner */
+ if (intel_dp->mso_link_count)
+ return false;
+
return DISPLAY_VER(dev_priv) >= 12 ||
(DISPLAY_VER(dev_priv) == 11 &&
encoder->port != PORT_A);
@@ -502,7 +503,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
/* The values must be in increasing order */
static const int mtl_rates[] = {
162000, 216000, 243000, 270000, 324000, 432000, 540000, 675000,
- 810000, 1000000, 1350000, 2000000,
+ 810000, 1000000, 2000000,
};
static const int icl_rates[] = {
162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000,
@@ -657,7 +658,7 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
int mode_rate, max_rate;
mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
- max_rate = intel_dp_max_data_rate(link_rate, lane_count);
+ max_rate = intel_dp_max_link_data_rate(intel_dp, link_rate, lane_count);
if (mode_rate > max_rate)
return false;
@@ -1204,11 +1205,13 @@ bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
int hdisplay, int clock)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_connector *connector = intel_dp->attached_connector;
if (!intel_dp_can_bigjoiner(intel_dp))
return false;
- return clock > i915->max_dotclk_freq || hdisplay > 5120;
+ return clock > i915->max_dotclk_freq || hdisplay > 5120 ||
+ connector->force_bigjoiner_enable;
}
static enum drm_mode_status
@@ -1259,7 +1262,8 @@ intel_dp_mode_valid(struct drm_connector *_connector,
max_link_clock = intel_dp_max_link_rate(intel_dp);
max_lanes = intel_dp_max_lane_count(intel_dp);
- max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
+ max_rate = intel_dp_max_link_data_rate(intel_dp, max_link_clock, max_lanes);
+
mode_rate = intel_dp_link_required(target_clock,
intel_dp_mode_min_output_bpp(connector, mode));
@@ -1610,8 +1614,10 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
for (lane_count = limits->min_lane_count;
lane_count <= limits->max_lane_count;
lane_count <<= 1) {
- link_avail = intel_dp_max_data_rate(link_rate,
- lane_count);
+ link_avail = intel_dp_max_link_data_rate(intel_dp,
+ link_rate,
+ lane_count);
+
if (mode_rate <= link_avail) {
pipe_config->lane_count = lane_count;
@@ -2388,6 +2394,17 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
limits);
}
+int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state)
+{
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->hw.adjusted_mode;
+ int bpp = crtc_state->dsc.compression_enable ?
+ to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) :
+ crtc_state->pipe_bpp;
+
+ return intel_dp_link_required(adjusted_mode->crtc_clock, bpp);
+}
+
static int
intel_dp_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -2455,31 +2472,16 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
return ret;
}
- if (pipe_config->dsc.compression_enable) {
- drm_dbg_kms(&i915->drm,
- "DP lane count %d clock %d Input bpp %d Compressed bpp " BPP_X16_FMT "\n",
- pipe_config->lane_count, pipe_config->port_clock,
- pipe_config->pipe_bpp,
- BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16));
-
- drm_dbg_kms(&i915->drm,
- "DP link rate required %i available %i\n",
- intel_dp_link_required(adjusted_mode->crtc_clock,
- to_bpp_int_roundup(pipe_config->dsc.compressed_bpp_x16)),
- intel_dp_max_data_rate(pipe_config->port_clock,
- pipe_config->lane_count));
- } else {
- drm_dbg_kms(&i915->drm, "DP lane count %d clock %d bpp %d\n",
- pipe_config->lane_count, pipe_config->port_clock,
- pipe_config->pipe_bpp);
+ drm_dbg_kms(&i915->drm,
+ "DP lane count %d clock %d bpp input %d compressed " BPP_X16_FMT " link rate required %d available %d\n",
+ pipe_config->lane_count, pipe_config->port_clock,
+ pipe_config->pipe_bpp,
+ BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16),
+ intel_dp_config_required_rate(pipe_config),
+ intel_dp_max_link_data_rate(intel_dp,
+ pipe_config->port_clock,
+ pipe_config->lane_count));
- drm_dbg_kms(&i915->drm,
- "DP link rate required %i available %i\n",
- intel_dp_link_required(adjusted_mode->crtc_clock,
- pipe_config->pipe_bpp),
- intel_dp_max_data_rate(pipe_config->port_clock,
- pipe_config->lane_count));
- }
return 0;
}
@@ -2621,58 +2623,38 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct drm_dp_vsc_sdp *vsc = &crtc_state->infoframes.vsc;
+ struct drm_dp_vsc_sdp *vsc;
- /* When a crtc state has PSR, VSC SDP will be handled by PSR routine */
- if (crtc_state->has_psr)
+ if ((!intel_dp->colorimetry_support ||
+ !intel_dp_needs_vsc_sdp(crtc_state, conn_state)) &&
+ !crtc_state->has_psr)
return;
- if (!intel_dp_needs_vsc_sdp(crtc_state, conn_state))
- return;
+ vsc = &crtc_state->infoframes.vsc;
crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC);
vsc->sdp_type = DP_SDP_VSC;
- intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
- &crtc_state->infoframes.vsc);
-}
-void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
- const struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state,
- struct drm_dp_vsc_sdp *vsc)
-{
- vsc->sdp_type = DP_SDP_VSC;
-
- if (crtc_state->has_psr2) {
- if (intel_dp->psr.colorimetry_support &&
- intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
- /* [PSR2, +Colorimetry] */
- intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
- vsc);
- } else {
- /*
- * [PSR2, -Colorimetry]
- * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11
- * 3D stereo + PSR/PSR2 + Y-coordinate.
- */
- vsc->revision = 0x4;
- vsc->length = 0xe;
- }
+ /* Needs colorimetry */
+ if (intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
+ intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
+ vsc);
+ } else if (crtc_state->has_psr2) {
+ /*
+ * [PSR2 without colorimetry]
+ * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11
+ * 3D stereo + PSR/PSR2 + Y-coordinate.
+ */
+ vsc->revision = 0x4;
+ vsc->length = 0xe;
} else if (crtc_state->has_panel_replay) {
- if (intel_dp->psr.colorimetry_support &&
- intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
- /* [Panel Replay with colorimetry info] */
- intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
- vsc);
- } else {
- /*
- * [Panel Replay without colorimetry info]
- * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
- * VSC SDP supporting 3D stereo + Panel Replay.
- */
- vsc->revision = 0x6;
- vsc->length = 0x10;
- }
+ /*
+ * [Panel Replay without colorimetry info]
+ * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
+ * VSC SDP supporting 3D stereo + Panel Replay.
+ */
+ vsc->revision = 0x6;
+ vsc->length = 0x10;
} else {
/*
* [PSR1]
@@ -2708,15 +2690,6 @@ intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp,
intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
}
-static bool cpu_transcoder_has_drrs(struct drm_i915_private *i915,
- enum transcoder cpu_transcoder)
-{
- if (HAS_DOUBLE_BUFFERED_M_N(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)
@@ -2739,7 +2712,7 @@ static bool can_enable_drrs(struct intel_connector *connector,
if (pipe_config->has_pch_encoder)
return false;
- if (!cpu_transcoder_has_drrs(i915, pipe_config->cpu_transcoder))
+ if (!intel_cpu_transcoder_has_drrs(i915, pipe_config->cpu_transcoder))
return false;
return downclock_mode &&
@@ -2865,12 +2838,47 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder,
intel_dp_is_uhbr(pipe_config);
}
+void intel_dp_queue_modeset_retry_work(struct intel_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+
+ drm_connector_get(&connector->base);
+ if (!queue_work(i915->unordered_wq, &connector->modeset_retry_work))
+ drm_connector_put(&connector->base);
+}
+
+void
+intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
+ struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_connector *connector;
+ struct intel_digital_connector_state *conn_state;
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ int i;
+
+ if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
+ intel_dp_queue_modeset_retry_work(intel_dp->attached_connector);
+
+ return;
+ }
+
+ for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
+ if (!conn_state->base.crtc)
+ continue;
+
+ if (connector->mst_port == intel_dp)
+ intel_dp_queue_modeset_retry_work(connector);
+ }
+}
+
int
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
const struct drm_display_mode *fixed_mode;
@@ -2971,7 +2979,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
- return 0;
+ return intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector,
+ pipe_config);
}
void intel_dp_set_link_params(struct intel_dp *intel_dp,
@@ -3307,18 +3316,21 @@ void intel_dp_sync_state(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- if (!crtc_state)
- return;
+ bool dpcd_updated = false;
/*
* Don't clobber DPCD if it's been already read out during output
* setup (eDP) or detect.
*/
- if (intel_dp->dpcd[DP_DPCD_REV] == 0)
+ if (crtc_state && intel_dp->dpcd[DP_DPCD_REV] == 0) {
intel_dp_get_dpcd(intel_dp);
+ dpcd_updated = true;
+ }
- intel_dp_reset_max_link_params(intel_dp);
+ intel_dp_tunnel_resume(intel_dp, crtc_state, dpcd_updated);
+
+ if (crtc_state)
+ intel_dp_reset_max_link_params(intel_dp);
}
bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
@@ -3354,13 +3366,6 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
fastset = false;
}
- if (CAN_PSR(intel_dp)) {
- drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset to compute PSR state\n",
- encoder->base.base.id, encoder->base.name);
- crtc_state->uapi.mode_changed = true;
- fastset = false;
- }
-
return fastset;
}
@@ -3991,6 +3996,13 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp)
&intel_dp->desc);
}
+void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
+{
+ intel_dp_set_sink_rates(intel_dp);
+ intel_dp_set_max_sink_lane_count(intel_dp);
+ intel_dp_set_common_rates(intel_dp);
+}
+
static bool
intel_dp_get_dpcd(struct intel_dp *intel_dp)
{
@@ -4007,9 +4019,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
drm_dp_is_branch(intel_dp->dpcd));
- intel_dp_set_sink_rates(intel_dp);
- intel_dp_set_max_sink_lane_count(intel_dp);
- intel_dp_set_common_rates(intel_dp);
+ intel_dp_update_sink_caps(intel_dp);
}
if (intel_dp_has_sink_count(intel_dp)) {
@@ -4119,73 +4129,6 @@ intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
return false;
}
-static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
- struct dp_sdp *sdp, size_t size)
-{
- size_t length = sizeof(struct dp_sdp);
-
- if (size < length)
- return -ENOSPC;
-
- memset(sdp, 0, size);
-
- /*
- * Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119
- * VSC SDP Header Bytes
- */
- sdp->sdp_header.HB0 = 0; /* Secondary-Data Packet ID = 0 */
- sdp->sdp_header.HB1 = vsc->sdp_type; /* Secondary-data Packet Type */
- sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */
- sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
-
- if (vsc->revision == 0x6) {
- sdp->db[0] = 1;
- sdp->db[3] = 1;
- }
-
- /*
- * Revision 0x5 and revision 0x7 supports Pixel Encoding/Colorimetry
- * Format as per DP 1.4a spec and DP 2.0 respectively.
- */
- if (!(vsc->revision == 0x5 || vsc->revision == 0x7))
- goto out;
-
- /* VSC SDP Payload for DB16 through DB18 */
- /* Pixel Encoding and Colorimetry Formats */
- sdp->db[16] = (vsc->pixelformat & 0xf) << 4; /* DB16[7:4] */
- sdp->db[16] |= vsc->colorimetry & 0xf; /* DB16[3:0] */
-
- switch (vsc->bpc) {
- case 6:
- /* 6bpc: 0x0 */
- break;
- case 8:
- sdp->db[17] = 0x1; /* DB17[3:0] */
- break;
- case 10:
- sdp->db[17] = 0x2;
- break;
- case 12:
- sdp->db[17] = 0x3;
- break;
- case 16:
- sdp->db[17] = 0x4;
- break;
- default:
- MISSING_CASE(vsc->bpc);
- break;
- }
- /* Dynamic Range and Component Bit Depth */
- if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
- sdp->db[17] |= 0x80; /* DB17[7] */
-
- /* Content Type */
- sdp->db[18] = vsc->content_type & 0x7;
-
-out:
- return length;
-}
-
static ssize_t
intel_dp_hdr_metadata_infoframe_sdp_pack(struct drm_i915_private *i915,
const struct hdmi_drm_infoframe *drm_infoframe,
@@ -4278,8 +4221,7 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder,
switch (type) {
case DP_SDP_VSC:
- len = intel_dp_vsc_sdp_pack(&crtc_state->infoframes.vsc, &sdp,
- sizeof(sdp));
+ len = drm_dp_vsc_sdp_pack(&crtc_state->infoframes.vsc, &sdp);
break;
case HDMI_PACKET_TYPE_GAMUT_METADATA:
len = intel_dp_hdr_metadata_infoframe_sdp_pack(dev_priv,
@@ -4297,24 +4239,6 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder,
dig_port->write_infoframe(encoder, crtc_state, type, &sdp, len);
}
-void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state,
- const struct drm_dp_vsc_sdp *vsc)
-{
- struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct dp_sdp sdp = {};
- ssize_t len;
-
- len = intel_dp_vsc_sdp_pack(vsc, &sdp, sizeof(sdp));
-
- if (drm_WARN_ON(&dev_priv->drm, len < 0))
- return;
-
- dig_port->write_infoframe(encoder, crtc_state, DP_SDP_VSC,
- &sdp, len);
-}
-
void intel_dp_set_infoframes(struct intel_encoder *encoder,
bool enable,
const struct intel_crtc_state *crtc_state,
@@ -4341,9 +4265,7 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder,
if (!enable)
return;
- /* When PSR is enabled, VSC SDP is handled by PSR routine */
- if (!crtc_state->has_psr)
- intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC);
+ intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC);
intel_write_dp_sdp(encoder, crtc_state, HDMI_PACKET_TYPE_GAMUT_METADATA);
}
@@ -4474,10 +4396,6 @@ static void intel_read_dp_vsc_sdp(struct intel_encoder *encoder,
struct dp_sdp sdp = {};
int ret;
- /* When PSR is enabled, VSC SDP is handled by PSR routine */
- if (crtc_state->has_psr)
- return;
-
if ((crtc_state->infoframes.enable &
intel_hdmi_infoframe_enable(type)) == 0)
return;
@@ -4688,31 +4606,36 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp,
struct drm_dp_phy_test_params *data =
&intel_dp->compliance.test_data.phytest;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
enum pipe pipe = crtc->pipe;
u32 pattern_val;
switch (data->phy_pattern) {
- case DP_PHY_TEST_PATTERN_NONE:
+ case DP_LINK_QUAL_PATTERN_DISABLE:
drm_dbg_kms(&dev_priv->drm, "Disable Phy Test Pattern\n");
intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0);
+ if (DISPLAY_VER(dev_priv) >= 10)
+ intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state),
+ DP_TP_CTL_TRAIN_PAT4_SEL_MASK | DP_TP_CTL_LINK_TRAIN_MASK,
+ DP_TP_CTL_LINK_TRAIN_NORMAL);
break;
- case DP_PHY_TEST_PATTERN_D10_2:
+ case DP_LINK_QUAL_PATTERN_D10_2:
drm_dbg_kms(&dev_priv->drm, "Set D10.2 Phy Test Pattern\n");
intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_D10_2);
break;
- case DP_PHY_TEST_PATTERN_ERROR_COUNT:
+ case DP_LINK_QUAL_PATTERN_ERROR_RATE:
drm_dbg_kms(&dev_priv->drm, "Set Error Count Phy Test Pattern\n");
intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
DDI_DP_COMP_CTL_ENABLE |
DDI_DP_COMP_CTL_SCRAMBLED_0);
break;
- case DP_PHY_TEST_PATTERN_PRBS7:
+ case DP_LINK_QUAL_PATTERN_PRBS7:
drm_dbg_kms(&dev_priv->drm, "Set PRBS7 Phy Test Pattern\n");
intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_PRBS7);
break;
- case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
+ case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM:
/*
* FIXME: Ideally pattern should come from DPCD 0x250. As
* current firmware of DPR-100 could not set it, so hardcoding
@@ -4730,7 +4653,7 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp,
DDI_DP_COMP_CTL_ENABLE |
DDI_DP_COMP_CTL_CUSTOM80);
break;
- case DP_PHY_TEST_PATTERN_CP2520:
+ case DP_LINK_QUAL_PATTERN_CP2520_PAT_1:
/*
* FIXME: Ideally pattern should come from DPCD 0x24A. As
* current firmware of DPR-100 could not set it, so hardcoding
@@ -4742,8 +4665,19 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp,
DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_HBR2 |
pattern_val);
break;
+ case DP_LINK_QUAL_PATTERN_CP2520_PAT_3:
+ if (DISPLAY_VER(dev_priv) < 10) {
+ drm_warn(&dev_priv->drm, "Platform does not support TPS4\n");
+ break;
+ }
+ drm_dbg_kms(&dev_priv->drm, "Set TPS4 compliance Phy Test Pattern\n");
+ intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0);
+ intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state),
+ DP_TP_CTL_TRAIN_PAT4_SEL_MASK | DP_TP_CTL_LINK_TRAIN_MASK,
+ DP_TP_CTL_TRAIN_PAT4_SEL_TP4A | DP_TP_CTL_LINK_TRAIN_PAT4);
+ break;
default:
- WARN(1, "Invalid Phy Test Pattern\n");
+ drm_warn(&dev_priv->drm, "Invalid Phy Test Pattern\n");
}
}
@@ -4908,13 +4842,15 @@ static bool intel_dp_mst_link_status(struct intel_dp *intel_dp)
* - %true if pending interrupts were serviced (or no interrupts were
* pending) w/o detecting an error condition.
* - %false if an error condition - like AUX failure or a loss of link - is
- * detected, which needs servicing from the hotplug work.
+ * detected, or another condition - like a DP tunnel BW state change - needs
+ * servicing from the hotplug work.
*/
static bool
intel_dp_check_mst_status(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
bool link_ok = true;
+ bool reprobe_needed = false;
drm_WARN_ON_ONCE(&i915->drm, intel_dp->active_mst_links < 0);
@@ -4941,6 +4877,13 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
intel_dp_mst_hpd_irq(intel_dp, esi, ack);
+ if (esi[3] & DP_TUNNELING_IRQ) {
+ if (drm_dp_tunnel_handle_irq(i915->display.dp_tunnel_mgr,
+ &intel_dp->aux))
+ reprobe_needed = true;
+ ack[3] |= DP_TUNNELING_IRQ;
+ }
+
if (!memchr_inv(ack, 0, sizeof(ack)))
break;
@@ -4951,7 +4894,7 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
drm_dp_mst_hpd_irq_send_new_request(&intel_dp->mst_mgr);
}
- return link_ok;
+ return link_ok && !reprobe_needed;
}
static void
@@ -5078,9 +5021,10 @@ int intel_dp_get_active_pipes(struct intel_dp *intel_dp,
if (!crtc_state->hw.active)
continue;
- if (conn_state->commit &&
- !try_wait_for_completion(&conn_state->commit->hw_done))
- continue;
+ if (conn_state->commit)
+ drm_WARN_ON(&i915->drm,
+ !wait_for_completion_timeout(&conn_state->commit->hw_done,
+ msecs_to_jiffies(5000)));
*pipe_mask |= BIT(crtc->pipe);
}
@@ -5310,23 +5254,32 @@ static void intel_dp_check_device_service_irq(struct intel_dp *intel_dp)
drm_dbg_kms(&i915->drm, "Sink specific irq unhandled\n");
}
-static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp)
+static bool intel_dp_check_link_service_irq(struct intel_dp *intel_dp)
{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ bool reprobe_needed = false;
u8 val;
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
- return;
+ return false;
if (drm_dp_dpcd_readb(&intel_dp->aux,
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val)
- return;
+ return false;
+
+ if ((val & DP_TUNNELING_IRQ) &&
+ drm_dp_tunnel_handle_irq(i915->display.dp_tunnel_mgr,
+ &intel_dp->aux))
+ reprobe_needed = true;
if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1)
- return;
+ return reprobe_needed;
if (val & HDMI_LINK_STATUS_CHANGED)
intel_dp_handle_hdmi_link_status_change(intel_dp);
+
+ return reprobe_needed;
}
/*
@@ -5347,6 +5300,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 old_sink_count = intel_dp->sink_count;
+ bool reprobe_needed = false;
bool ret;
/*
@@ -5369,7 +5323,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
}
intel_dp_check_device_service_irq(intel_dp);
- intel_dp_check_link_service_irq(intel_dp);
+ reprobe_needed = intel_dp_check_link_service_irq(intel_dp);
/* Handle CEC interrupts, if any */
drm_dp_cec_irq(&intel_dp->aux);
@@ -5396,10 +5350,10 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
* FIXME get rid of the ad-hoc phy test modeset code
* and properly incorporate it into the normal modeset.
*/
- return false;
+ reprobe_needed = true;
}
- return true;
+ return !reprobe_needed;
}
/* XXX this is probably wrong for multiple downstream ports */
@@ -5462,8 +5416,24 @@ edp_detect(struct intel_dp *intel_dp)
return connector_status_connected;
}
+void intel_digital_port_lock(struct intel_encoder *encoder)
+{
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+ if (dig_port->lock)
+ dig_port->lock(dig_port);
+}
+
+void intel_digital_port_unlock(struct intel_encoder *encoder)
+{
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+ if (dig_port->unlock)
+ dig_port->unlock(dig_port);
+}
+
/*
- * intel_digital_port_connected - is the specified port connected?
+ * intel_digital_port_connected_locked - is the specified port connected?
* @encoder: intel_encoder
*
* In cases where there's a connector physically connected but it can't be used
@@ -5471,21 +5441,44 @@ edp_detect(struct intel_dp *intel_dp)
* pretty much treat the port as disconnected. This is relevant for type-C
* (starting on ICL) where there's ownership involved.
*
+ * The caller must hold the lock acquired by calling intel_digital_port_lock()
+ * when calling this function.
+ *
* Return %true if port is connected, %false otherwise.
*/
-bool intel_digital_port_connected(struct intel_encoder *encoder)
+bool intel_digital_port_connected_locked(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+ bool is_glitch_free = intel_tc_port_handles_hpd_glitches(dig_port);
bool is_connected = false;
intel_wakeref_t wakeref;
- with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref)
- is_connected = dig_port->connected(encoder);
+ with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) {
+ unsigned long wait_expires = jiffies + msecs_to_jiffies_timeout(4);
+
+ do {
+ is_connected = dig_port->connected(encoder);
+ if (is_connected || is_glitch_free)
+ break;
+ usleep_range(10, 30);
+ } while (time_before(jiffies, wait_expires));
+ }
return is_connected;
}
+bool intel_digital_port_connected(struct intel_encoder *encoder)
+{
+ bool ret;
+
+ intel_digital_port_lock(encoder);
+ ret = intel_digital_port_connected_locked(encoder);
+ intel_digital_port_unlock(encoder);
+
+ return ret;
+}
+
static const struct drm_edid *
intel_dp_get_edid(struct intel_dp *intel_dp)
{
@@ -5670,6 +5663,7 @@ intel_dp_detect(struct drm_connector *connector,
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct intel_encoder *encoder = &dig_port->base;
enum drm_connector_status status;
+ int ret;
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
@@ -5679,6 +5673,9 @@ intel_dp_detect(struct drm_connector *connector,
if (!intel_display_device_enabled(dev_priv))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(dev_priv))
+ return connector->status;
+
/* Can't disconnect eDP */
if (intel_dp_is_edp(intel_dp))
status = edp_detect(intel_dp);
@@ -5702,9 +5699,18 @@ intel_dp_detect(struct drm_connector *connector,
intel_dp->is_mst);
}
+ intel_dp_tunnel_disconnect(intel_dp);
+
goto out;
}
+ ret = intel_dp_tunnel_detect(intel_dp, ctx);
+ if (ret == -EDEADLK)
+ return ret;
+
+ if (ret == 1)
+ intel_connector->base.epoch_counter++;
+
if (!intel_dp_is_edp(intel_dp))
intel_psr_init_dpcd(intel_dp);
@@ -5738,8 +5744,6 @@ intel_dp_detect(struct drm_connector *connector,
* with an IRQ_HPD, so force a link status check.
*/
if (!intel_dp_is_edp(intel_dp)) {
- int ret;
-
ret = intel_dp_retrain_link(encoder, ctx);
if (ret)
return ret;
@@ -5782,6 +5786,10 @@ intel_dp_force(struct drm_connector *connector)
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
+
+ if (!intel_display_driver_check_access(dev_priv))
+ return;
+
intel_dp_unset_edid(intel_dp);
if (connector->status != connector_status_connected)
@@ -5888,6 +5896,8 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
intel_dp_mst_encoder_cleanup(dig_port);
+ intel_dp_tunnel_destroy(intel_dp);
+
intel_pps_vdd_off_sync(intel_dp);
/*
@@ -5904,6 +5914,8 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder);
intel_pps_vdd_off_sync(intel_dp);
+
+ intel_dp_tunnel_suspend(intel_dp);
}
void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder)
@@ -6041,6 +6053,15 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn,
return ret;
}
+ if (!intel_connector_needs_modeset(state, conn))
+ return 0;
+
+ ret = intel_dp_tunnel_atomic_check_state(state,
+ intel_dp,
+ intel_conn);
+ if (ret)
+ return ret;
+
/*
* We don't enable port sync on BDW due to missing w/as and
* due to not having adjusted the modeset sequence appropriately.
@@ -6048,9 +6069,6 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn,
if (DISPLAY_VER(dev_priv) < 9)
return 0;
- if (!intel_connector_needs_modeset(state, conn))
- return 0;
-
if (conn->has_tile) {
ret = intel_modeset_tile_group(state, conn->tile_group->id);
if (ret)
@@ -6079,7 +6097,7 @@ static void intel_dp_oob_hotplug_event(struct drm_connector *connector,
spin_unlock_irq(&i915->irq_lock);
if (need_work)
- queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0);
+ intel_hpd_schedule_detection(i915);
}
static const struct drm_connector_funcs intel_dp_connector_funcs = {
@@ -6107,6 +6125,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
struct intel_dp *intel_dp = &dig_port->dp;
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
if (dig_port->base.type == INTEL_OUTPUT_EDP &&
(long_hpd || !intel_pps_have_panel_power_or_vdd(intel_dp))) {
@@ -6129,6 +6148,17 @@ intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd)
dig_port->base.base.name,
long_hpd ? "long" : "short");
+ /*
+ * TBT DP tunnels require the GFX driver to read out the DPRX caps in
+ * response to long HPD pulses. The DP hotplug handler does that,
+ * however the hotplug handler may be blocked by another
+ * connector's/encoder's hotplug handler. Since the TBT CM may not
+ * complete the DP tunnel BW request for the latter connector/encoder
+ * waiting for this encoder's DPRX read, perform a dummy read here.
+ */
+ if (long_hpd)
+ intel_dp_read_dprx_caps(intel_dp, dpcd);
+
if (long_hpd) {
intel_dp->reset_link_params = true;
return IRQ_NONE;
@@ -6449,6 +6479,14 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work)
mutex_unlock(&connector->dev->mode_config.mutex);
/* Send Hotplug uevent so userspace can reprobe */
drm_kms_helper_connector_hotplug_event(connector);
+
+ drm_connector_put(connector);
+}
+
+void intel_dp_init_modeset_retry_work(struct intel_connector *connector)
+{
+ INIT_WORK(&connector->modeset_retry_work,
+ intel_dp_modeset_retry_work_fn);
}
bool
@@ -6465,8 +6503,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
int type;
/* Initialize the work for modeset in case of link train failure */
- INIT_WORK(&intel_connector->modeset_retry_work,
- intel_dp_modeset_retry_work_fn);
+ intel_dp_init_modeset_retry_work(intel_connector);
if (drm_WARN(dev, dig_port->max_lanes < 1,
"Not enough lanes (%d) for DP on [ENCODER:%d:%s]\n",
@@ -6522,6 +6559,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
connector->interlace_allowed = true;
intel_connector->polled = DRM_CONNECTOR_POLL_HPD;
+ intel_connector->base.polled = intel_connector->polled;
intel_connector_attach_encoder(intel_connector, intel_encoder);
@@ -6553,6 +6591,9 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
"HDCP init failed, skipping.\n");
}
+ intel_dp->colorimetry_support =
+ intel_dp_get_colorimetry_status(intel_dp);
+
intel_dp->frl.is_trained = false;
intel_dp->frl.trained_rate_gbps = 0;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 375d0677cd..c540d3a73f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -43,6 +43,12 @@ void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
int intel_dp_min_bpp(enum intel_output_format output_format);
+void intel_dp_init_modeset_retry_work(struct intel_connector *connector);
+void intel_dp_queue_modeset_retry_work(struct intel_connector *connector);
+void
+intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
+ struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
bool intel_dp_init_connector(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector);
void intel_dp_connector_sync_state(struct intel_connector *connector,
@@ -96,7 +102,11 @@ void intel_dp_mst_suspend(struct drm_i915_private *dev_priv);
void intel_dp_mst_resume(struct drm_i915_private *dev_priv);
int intel_dp_max_link_rate(struct intel_dp *intel_dp);
int intel_dp_max_lane_count(struct intel_dp *intel_dp);
+int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
+int intel_dp_max_common_rate(struct intel_dp *intel_dp);
+int intel_dp_max_common_lane_count(struct intel_dp *intel_dp);
+void intel_dp_update_sink_caps(struct intel_dp *intel_dp);
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
u8 *link_bw, u8 *rate_select);
@@ -107,24 +117,21 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
int intel_dp_link_required(int pixel_clock, int bpp);
int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16,
int bw_overhead);
-int intel_dp_max_data_rate(int max_link_rate, int max_lanes);
+int intel_dp_max_link_data_rate(struct intel_dp *intel_dp,
+ int max_dprx_rate, int max_dprx_lanes);
bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp);
bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
-void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
- const struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state,
- struct drm_dp_vsc_sdp *vsc);
-void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state,
- const struct drm_dp_vsc_sdp *vsc);
void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_read_dp_sdp(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
unsigned int type);
+void intel_digital_port_lock(struct intel_encoder *encoder);
+void intel_digital_port_unlock(struct intel_encoder *encoder);
bool intel_digital_port_connected(struct intel_encoder *encoder);
+bool intel_digital_port_connected_locked(struct intel_encoder *encoder);
int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
u8 dsc_max_bpc);
u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
index 2e2af71bcd..4f4a0e3b31 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
@@ -9,6 +9,7 @@
#include "intel_bios.h"
#include "intel_de.h"
#include "intel_display_types.h"
+#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_dp_aux_regs.h"
#include "intel_pps.h"
@@ -228,9 +229,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
u32 aux_send_ctl_flags)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct intel_encoder *encoder = &dig_port->base;
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
- bool is_tc_port = intel_phy_is_tc(i915, phy);
i915_reg_t ch_ctl, ch_data[5];
u32 aux_clock_divider;
enum intel_display_power_domain aux_domain;
@@ -245,18 +245,16 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
for (i = 0; i < ARRAY_SIZE(ch_data); i++)
ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
- if (is_tc_port) {
- intel_tc_port_lock(dig_port);
- /*
- * Abort transfers on a disconnected port as required by
- * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX
- * timeouts that would otherwise happen.
- * TODO: abort the transfer on non-TC ports as well.
- */
- if (!intel_tc_port_connected_locked(&dig_port->base)) {
- ret = -ENXIO;
- goto out_unlock;
- }
+ intel_digital_port_lock(encoder);
+ /*
+ * Abort transfers on a disconnected port as required by
+ * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX
+ * timeouts that would otherwise happen.
+ */
+ if (!intel_dp_is_edp(intel_dp) &&
+ !intel_digital_port_connected_locked(&dig_port->base)) {
+ ret = -ENXIO;
+ goto out_unlock;
}
aux_domain = intel_aux_power_domain(dig_port);
@@ -423,8 +421,7 @@ out:
intel_pps_unlock(intel_dp, pps_wakeref);
intel_display_power_put_async(i915, aux_domain, aux_wakeref);
out_unlock:
- if (is_tc_port)
- intel_tc_port_unlock(dig_port);
+ intel_digital_port_unlock(encoder);
return ret;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
index 8538d1ce2f..9db43bd81c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
@@ -36,8 +36,10 @@ static u32 transcoder_to_stream_enc_status(enum transcoder cpu_transcoder)
}
}
-static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
+static void intel_dp_hdcp_wait_for_cp_irq(struct intel_connector *connector,
+ int timeout)
{
+ struct intel_hdcp *hdcp = &connector->hdcp;
long ret;
#define C (hdcp->cp_irq_count_cached != atomic_read(&hdcp->cp_irq_count))
@@ -45,7 +47,8 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
msecs_to_jiffies(timeout));
if (!ret)
- DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
+ drm_dbg_kms(connector->base.dev,
+ "Timedout at waiting for CP_IRQ\n");
}
static
@@ -122,13 +125,13 @@ static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
}
static
-int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
+int intel_dp_hdcp_read_bcaps(struct drm_dp_aux *aux,
+ struct drm_i915_private *i915,
u8 *bcaps)
{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
ssize_t ret;
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
+ ret = drm_dp_dpcd_read(aux, DP_AUX_HDCP_BCAPS,
bcaps, 1);
if (ret != 1) {
drm_dbg_kms(&i915->drm,
@@ -143,10 +146,11 @@ static
int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
bool *repeater_present)
{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
ssize_t ret;
u8 bcaps;
- ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
+ ret = intel_dp_hdcp_read_bcaps(&dig_port->dp.aux, i915, &bcaps);
if (ret)
return ret;
@@ -265,13 +269,14 @@ bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
}
static
-int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
- bool *hdcp_capable)
+int intel_dp_hdcp_get_capability(struct intel_digital_port *dig_port,
+ bool *hdcp_capable)
{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
ssize_t ret;
u8 bcaps;
- ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
+ ret = intel_dp_hdcp_read_bcaps(&dig_port->dp.aux, i915, &bcaps);
if (ret)
return ret;
@@ -377,7 +382,8 @@ int hdcp2_detect_msg_availability(struct intel_connector *connector,
*msg_ready = true;
break;
default:
- DRM_ERROR("Unidentified msg_id: %d\n", msg_id);
+ drm_err(connector->base.dev,
+ "Unidentified msg_id: %d\n", msg_id);
return -EINVAL;
}
@@ -413,7 +419,7 @@ intel_dp_hdcp2_wait_for_msg(struct intel_connector *connector,
* As we want to check the msg availability at timeout, Ignoring
* the timeout at wait for CP_IRQ.
*/
- intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout);
+ intel_dp_hdcp_wait_for_cp_irq(connector, timeout);
ret = hdcp2_detect_msg_availability(connector, msg_id,
&msg_ready);
if (!msg_ready)
@@ -634,24 +640,72 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
}
static
-int intel_dp_hdcp2_capable(struct intel_connector *connector,
- bool *capable)
+int _intel_dp_hdcp2_get_capability(struct drm_dp_aux *aux,
+ bool *capable)
+{
+ u8 rx_caps[3];
+ int ret, i;
+
+ *capable = false;
+
+ /*
+ * Some HDCP monitors act really shady by not giving the correct hdcp
+ * capability on the first rx_caps read and usually take an extra read
+ * to give the capability. We read rx_caps three times before we
+ * declare a monitor not capable of HDCP 2.2.
+ */
+ for (i = 0; i < 3; i++) {
+ ret = drm_dp_dpcd_read(aux,
+ DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
+ rx_caps, HDCP_2_2_RXCAPS_LEN);
+ if (ret != HDCP_2_2_RXCAPS_LEN)
+ return ret >= 0 ? -EIO : ret;
+
+ if (rx_caps[0] == HDCP_2_2_RX_CAPS_VERSION_VAL &&
+ HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2])) {
+ *capable = true;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static
+int intel_dp_hdcp2_get_capability(struct intel_connector *connector,
+ bool *capable)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_dp_aux *aux = &dig_port->dp.aux;
- u8 rx_caps[3];
+
+ return _intel_dp_hdcp2_get_capability(aux, capable);
+}
+
+static
+int intel_dp_hdcp_get_remote_capability(struct intel_connector *connector,
+ bool *hdcp_capable,
+ bool *hdcp2_capable)
+{
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct drm_dp_aux *aux = &connector->port->aux;
+ u8 bcaps;
int ret;
- *capable = false;
- ret = drm_dp_dpcd_read(aux,
- DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
- rx_caps, HDCP_2_2_RXCAPS_LEN);
- if (ret != HDCP_2_2_RXCAPS_LEN)
- return ret >= 0 ? -EIO : ret;
+ *hdcp_capable = false;
+ *hdcp2_capable = false;
+ if (!intel_encoder_is_mst(connector->encoder))
+ return -EINVAL;
+
+ ret = _intel_dp_hdcp2_get_capability(aux, hdcp2_capable);
+ if (ret)
+ drm_dbg_kms(&i915->drm,
+ "HDCP2 DPCD capability read failed err: %d\n", ret);
- if (rx_caps[0] == HDCP_2_2_RX_CAPS_VERSION_VAL &&
- HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2]))
- *capable = true;
+ ret = intel_dp_hdcp_read_bcaps(aux, i915, &bcaps);
+ if (ret)
+ return ret;
+
+ *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
return 0;
}
@@ -667,12 +721,12 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
.check_link = intel_dp_hdcp_check_link,
- .hdcp_capable = intel_dp_hdcp_capable,
+ .hdcp_get_capability = intel_dp_hdcp_get_capability,
.write_2_2_msg = intel_dp_hdcp2_write_msg,
.read_2_2_msg = intel_dp_hdcp2_read_msg,
.config_stream_type = intel_dp_hdcp2_config_stream_type,
.check_2_2_link = intel_dp_hdcp2_check_link,
- .hdcp_2_2_capable = intel_dp_hdcp2_capable,
+ .hdcp_2_2_get_capability = intel_dp_hdcp2_get_capability,
.protocol = HDCP_PROTOCOL_DP,
};
@@ -797,13 +851,14 @@ static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
.check_link = intel_dp_hdcp_check_link,
- .hdcp_capable = intel_dp_hdcp_capable,
+ .hdcp_get_capability = intel_dp_hdcp_get_capability,
.write_2_2_msg = intel_dp_hdcp2_write_msg,
.read_2_2_msg = intel_dp_hdcp2_read_msg,
.config_stream_type = intel_dp_hdcp2_config_stream_type,
.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
.check_2_2_link = intel_dp_mst_hdcp2_check_link,
- .hdcp_2_2_capable = intel_dp_hdcp2_capable,
+ .hdcp_2_2_get_capability = intel_dp_hdcp2_get_capability,
+ .get_remote_hdcp_capability = intel_dp_hdcp_get_remote_capability,
.protocol = HDCP_PROTOCOL_DP,
};
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 1abfafbbfa..fb84ca98bb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -162,6 +162,28 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI
return lttpr_count;
}
+int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE])
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+
+ if (intel_dp_is_edp(intel_dp))
+ return 0;
+
+ /*
+ * Detecting LTTPRs must be avoided on platforms with an AUX timeout
+ * period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1).
+ */
+ if (DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915))
+ if (drm_dp_dpcd_probe(&intel_dp->aux,
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV))
+ return -EIO;
+
+ if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
+ return -EIO;
+
+ return 0;
+}
+
/**
* intel_dp_init_lttpr_and_dprx_caps - detect LTTPR and DPRX caps, init the LTTPR link training mode
* @intel_dp: Intel DP struct
@@ -192,12 +214,10 @@ int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp)
if (!intel_dp_is_edp(intel_dp) &&
(DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915))) {
u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ int err = intel_dp_read_dprx_caps(intel_dp, dpcd);
- if (drm_dp_dpcd_probe(&intel_dp->aux, DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV))
- return -EIO;
-
- if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
- return -EIO;
+ if (err != 0)
+ return err;
lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd);
}
@@ -1075,7 +1095,6 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
if (!intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base)) {
lt_dbg(intel_dp, DP_PHY_DPRX, "Link Training failed on disconnected sink.\n");
@@ -1093,7 +1112,7 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp,
}
/* Schedule a Hotplug Uevent to userspace to start modeset */
- queue_work(i915->unordered_wq, &intel_connector->modeset_retry_work);
+ intel_dp_queue_modeset_retry_work(intel_connector);
}
/* Perform the link training on all LTTPRs and the DPRX on a link. */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 2c8f277589..19836a8a4f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -11,6 +11,7 @@
struct intel_crtc_state;
struct intel_dp;
+int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]);
int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp);
void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 2151e916cc..8264ff7fb6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -37,10 +37,12 @@
#include "intel_crtc.h"
#include "intel_ddi.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_dp.h"
#include "intel_dp_hdcp.h"
#include "intel_dp_mst.h"
+#include "intel_dp_tunnel.h"
#include "intel_dpio_phy.h"
#include "intel_hdcp.h"
#include "intel_hotplug.h"
@@ -522,6 +524,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
struct intel_dp *intel_dp = &intel_mst->primary->dp;
const struct intel_connector *connector =
@@ -618,7 +621,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
intel_psr_compute_config(intel_dp, pipe_config, conn_state);
- return 0;
+ return intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector,
+ pipe_config);
}
/*
@@ -875,6 +879,14 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
if (ret)
return ret;
+ if (intel_connector_needs_modeset(state, connector)) {
+ ret = intel_dp_tunnel_atomic_check_state(state,
+ intel_connector->mst_port,
+ intel_connector);
+ if (ret)
+ return ret;
+ }
+
return drm_dp_atomic_release_time_slots(&state->base,
&intel_connector->mst_port->mst_mgr,
intel_connector->port);
@@ -1148,7 +1160,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
if (first_mst_stream)
intel_ddi_wait_for_fec_status(encoder, pipe_config, true);
- drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base,
+ drm_dp_add_payload_part2(&intel_dp->mst_mgr,
drm_atomic_get_mst_payload_state(mst_state, connector->port));
if (DISPLAY_VER(dev_priv) >= 12)
@@ -1196,6 +1208,7 @@ static bool intel_dp_mst_initial_fastset_check(struct intel_encoder *encoder,
static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
+ struct drm_i915_private *i915 = to_i915(intel_connector->base.dev);
struct intel_dp *intel_dp = intel_connector->mst_port;
const struct drm_edid *drm_edid;
int ret;
@@ -1203,6 +1216,9 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
if (drm_connector_is_unregistered(connector))
return intel_connector_update_modes(connector, NULL);
+ if (!intel_display_driver_check_access(i915))
+ return drm_edid_connector_add_modes(connector);
+
drm_edid = drm_dp_mst_edid_read(connector, &intel_dp->mst_mgr, intel_connector->port);
ret = intel_connector_update_modes(connector, drm_edid);
@@ -1294,7 +1310,8 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
max_link_clock = intel_dp_max_link_rate(intel_dp);
max_lanes = intel_dp_max_lane_count(intel_dp);
- max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
+ max_rate = intel_dp_max_link_data_rate(intel_dp,
+ max_link_clock, max_lanes);
mode_rate = intel_dp_link_required(mode->clock, min_bpp);
ret = drm_modeset_lock(&mgr->base.lock, ctx);
@@ -1410,6 +1427,9 @@ intel_dp_mst_detect(struct drm_connector *connector,
if (drm_connector_is_unregistered(connector))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(i915))
+ return connector->status;
+
return drm_dp_mst_detect_port(connector, ctx, &intel_dp->mst_mgr,
intel_connector->port);
}
@@ -1539,6 +1559,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
intel_connector->port = port;
drm_dp_mst_get_port_malloc(port);
+ intel_dp_init_modeset_retry_work(intel_connector);
+
intel_connector->dp.dsc_decompression_aux = drm_dp_mst_dsc_aux_for_port(port);
intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector);
intel_connector->dp.dsc_hblank_expansion_quirk =
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
new file mode 100644
index 0000000000..75d76f91ec
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -0,0 +1,811 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "i915_drv.h"
+
+#include <drm/display/drm_dp_tunnel.h>
+
+#include "intel_atomic.h"
+#include "intel_display_limits.h"
+#include "intel_display_types.h"
+#include "intel_dp.h"
+#include "intel_dp_link_training.h"
+#include "intel_dp_mst.h"
+#include "intel_dp_tunnel.h"
+#include "intel_link_bw.h"
+
+struct intel_dp_tunnel_inherited_state {
+ struct drm_dp_tunnel_ref ref[I915_MAX_PIPES];
+};
+
+/**
+ * intel_dp_tunnel_disconnect - Disconnect a DP tunnel from a port
+ * @intel_dp: DP port object the tunnel is connected to
+ *
+ * Disconnect a DP tunnel from @intel_dp, destroying any related state. This
+ * should be called after detecting a sink-disconnect event from the port.
+ */
+void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp)
+{
+ drm_dp_tunnel_destroy(intel_dp->tunnel);
+ intel_dp->tunnel = NULL;
+}
+
+/**
+ * intel_dp_tunnel_destroy - Destroy a DP tunnel
+ * @intel_dp: DP port object the tunnel is connected to
+ *
+ * Destroy a DP tunnel connected to @intel_dp, after disabling the BW
+ * allocation mode on the tunnel. This should be called while destroying the
+ * port.
+ */
+void intel_dp_tunnel_destroy(struct intel_dp *intel_dp)
+{
+ if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);
+
+ intel_dp_tunnel_disconnect(intel_dp);
+}
+
+static int kbytes_to_mbits(int kbytes)
+{
+ return DIV_ROUND_UP(kbytes * 8, 1000);
+}
+
+static int get_current_link_bw(struct intel_dp *intel_dp,
+ bool *below_dprx_bw)
+{
+ int rate = intel_dp_max_common_rate(intel_dp);
+ int lane_count = intel_dp_max_common_lane_count(intel_dp);
+ int bw;
+
+ bw = intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
+ *below_dprx_bw = bw < drm_dp_max_dprx_data_rate(rate, lane_count);
+
+ return bw;
+}
+
+static int update_tunnel_state(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ bool old_bw_below_dprx;
+ bool new_bw_below_dprx;
+ int old_bw;
+ int new_bw;
+ int ret;
+
+ old_bw = get_current_link_bw(intel_dp, &old_bw_below_dprx);
+
+ ret = drm_dp_tunnel_update_state(intel_dp->tunnel);
+ if (ret < 0) {
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][ENCODER:%d:%s] State update failed (err %pe)\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ encoder->base.base.id, encoder->base.name,
+ ERR_PTR(ret));
+
+ return ret;
+ }
+
+ if (ret == 0 ||
+ !drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel))
+ return 0;
+
+ intel_dp_update_sink_caps(intel_dp);
+
+ new_bw = get_current_link_bw(intel_dp, &new_bw_below_dprx);
+
+ /* Suppress the notification if the mode list can't change due to bw. */
+ if (old_bw_below_dprx == new_bw_below_dprx &&
+ !new_bw_below_dprx)
+ return 0;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][ENCODER:%d:%s] Notify users about BW change: %d -> %d\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ encoder->base.base.id, encoder->base.name,
+ kbytes_to_mbits(old_bw), kbytes_to_mbits(new_bw));
+
+ return 1;
+}
+
+/*
+ * Allocate the BW for a tunnel on a DP connector/port if the connector/port
+ * was already active when detecting the tunnel. The allocated BW must be
+ * freed by the next atomic modeset, storing the BW in the
+ * intel_atomic_state::inherited_dp_tunnels, and calling
+ * intel_dp_tunnel_atomic_free_bw().
+ */
+static int allocate_initial_tunnel_bw_for_pipes(struct intel_dp *intel_dp, u8 pipe_mask)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_crtc *crtc;
+ int tunnel_bw = 0;
+ int err;
+
+ for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+ int stream_bw = intel_dp_config_required_rate(crtc_state);
+
+ tunnel_bw += stream_bw;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][ENCODER:%d:%s][CRTC:%d:%s] Initial BW for stream %d: %d/%d Mb/s\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ encoder->base.base.id, encoder->base.name,
+ crtc->base.base.id, crtc->base.name,
+ crtc->pipe,
+ kbytes_to_mbits(stream_bw), kbytes_to_mbits(tunnel_bw));
+ }
+
+ err = drm_dp_tunnel_alloc_bw(intel_dp->tunnel, tunnel_bw);
+ if (err) {
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][ENCODER:%d:%s] Initial BW allocation failed (err %pe)\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ encoder->base.base.id, encoder->base.name,
+ ERR_PTR(err));
+
+ return err;
+ }
+
+ return update_tunnel_state(intel_dp);
+}
+
+static int allocate_initial_tunnel_bw(struct intel_dp *intel_dp,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ u8 pipe_mask;
+ int err;
+
+ err = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask);
+ if (err)
+ return err;
+
+ return allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);
+}
+
+static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_dp_tunnel *tunnel;
+ int ret;
+
+ tunnel = drm_dp_tunnel_detect(i915->display.dp_tunnel_mgr,
+ &intel_dp->aux);
+ if (IS_ERR(tunnel))
+ return PTR_ERR(tunnel);
+
+ intel_dp->tunnel = tunnel;
+
+ ret = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel);
+ if (ret) {
+ if (ret == -EOPNOTSUPP)
+ return 0;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][ENCODER:%d:%s] Failed to enable BW allocation mode (ret %pe)\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ encoder->base.base.id, encoder->base.name,
+ ERR_PTR(ret));
+
+ /* Keep the tunnel with BWA disabled */
+ return 0;
+ }
+
+ ret = allocate_initial_tunnel_bw(intel_dp, ctx);
+ if (ret < 0)
+ intel_dp_tunnel_destroy(intel_dp);
+
+ return ret;
+}
+
+/**
+ * intel_dp_tunnel_detect - Detect a DP tunnel on a port
+ * @intel_dp: DP port object
+ * @ctx: lock context acquired by the connector detection handler
+ *
+ * Detect a DP tunnel on the @intel_dp port, enabling the BW allocation mode
+ * on it if supported and allocating the BW required on an already active port.
+ * The BW allocated this way must be freed by the next atomic modeset calling
+ * intel_dp_tunnel_atomic_free_bw().
+ *
+ * If @intel_dp has already a tunnel detected on it, update the tunnel's state
+ * wrt. its support for BW allocation mode and the available BW via the
+ * tunnel. If the tunnel's state change requires this - for instance the
+ * tunnel's group ID has changed - the tunnel will be dropped and recreated.
+ *
+ * Return 0 in case of success - after any tunnel detected and added to
+ * @intel_dp - 1 in case the BW on an already existing tunnel has changed in a
+ * way that requires notifying user space.
+ */
+int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
+{
+ int ret;
+
+ if (intel_dp_is_edp(intel_dp))
+ return 0;
+
+ if (intel_dp->tunnel) {
+ ret = update_tunnel_state(intel_dp);
+ if (ret >= 0)
+ return ret;
+
+ /* Try to recreate the tunnel after an update error. */
+ intel_dp_tunnel_destroy(intel_dp);
+ }
+
+ return detect_new_tunnel(intel_dp, ctx);
+}
+
+/**
+ * intel_dp_tunnel_bw_alloc_is_enabled - Query the BW allocation support on a tunnel
+ * @intel_dp: DP port object
+ *
+ * Query whether a DP tunnel is connected on @intel_dp and the tunnel supports
+ * the BW allocation mode.
+ *
+ * Returns %true if the BW allocation mode is supported on @intel_dp.
+ */
+bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)
+{
+ return drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel);
+}
+
+/**
+ * intel_dp_tunnel_suspend - Suspend a DP tunnel connected on a port
+ * @intel_dp: DP port object
+ *
+ * Suspend a DP tunnel on @intel_dp with BW allocation mode enabled on it.
+ */
+void intel_dp_tunnel_suspend(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_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+
+ if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ return;
+
+ drm_dbg_kms(&i915->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Suspend\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name);
+
+ drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);
+
+ intel_dp->tunnel_suspended = true;
+}
+
+/**
+ * intel_dp_tunnel_resume - Resume a DP tunnel connected on a port
+ * @intel_dp: DP port object
+ * @crtc_state: CRTC state
+ * @dpcd_updated: the DPCD DPRX capabilities got updated during resume
+ *
+ * Resume a DP tunnel on @intel_dp with BW allocation mode enabled on it.
+ */
+void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ bool dpcd_updated)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_connector *connector = intel_dp->attached_connector;
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ u8 pipe_mask;
+ int err = 0;
+
+ if (!intel_dp->tunnel_suspended)
+ return;
+
+ intel_dp->tunnel_suspended = false;
+
+ drm_dbg_kms(&i915->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Resume\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name);
+
+ /*
+ * The TBT Connection Manager requires the GFX driver to read out
+ * the sink's DPRX caps to be able to service any BW requests later.
+ * During resume overriding the caps in @intel_dp cached before
+ * suspend must be avoided, so do here only a dummy read, unless the
+ * capabilities were updated already during resume.
+ */
+ if (!dpcd_updated) {
+ err = intel_dp_read_dprx_caps(intel_dp, dpcd);
+
+ if (err) {
+ drm_dp_tunnel_set_io_error(intel_dp->tunnel);
+ goto out_err;
+ }
+ }
+
+ err = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel);
+ if (err)
+ goto out_err;
+
+ pipe_mask = 0;
+ if (crtc_state) {
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+ /* TODO: Add support for MST */
+ pipe_mask |= BIT(crtc->pipe);
+ }
+
+ err = allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);
+ if (err < 0)
+ goto out_err;
+
+ return;
+
+out_err:
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Tunnel can't be resumed, will drop and redect it (err %pe)\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name,
+ ERR_PTR(err));
+}
+
+static struct drm_dp_tunnel *
+get_inherited_tunnel(struct intel_atomic_state *state, struct intel_crtc *crtc)
+{
+ if (!state->inherited_dp_tunnels)
+ return NULL;
+
+ return state->inherited_dp_tunnels->ref[crtc->pipe].tunnel;
+}
+
+static int
+add_inherited_tunnel(struct intel_atomic_state *state,
+ struct drm_dp_tunnel *tunnel,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct drm_dp_tunnel *old_tunnel;
+
+ old_tunnel = get_inherited_tunnel(state, crtc);
+ if (old_tunnel) {
+ drm_WARN_ON(&i915->drm, old_tunnel != tunnel);
+ return 0;
+ }
+
+ if (!state->inherited_dp_tunnels) {
+ state->inherited_dp_tunnels = kzalloc(sizeof(*state->inherited_dp_tunnels),
+ GFP_KERNEL);
+ if (!state->inherited_dp_tunnels)
+ return -ENOMEM;
+ }
+
+ drm_dp_tunnel_ref_get(tunnel, &state->inherited_dp_tunnels->ref[crtc->pipe]);
+
+ return 0;
+}
+
+static int check_inherited_tunnel_state(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ const struct intel_digital_connector_state *old_conn_state)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_connector *connector =
+ to_intel_connector(old_conn_state->base.connector);
+ struct intel_crtc *old_crtc;
+ const struct intel_crtc_state *old_crtc_state;
+
+ /*
+ * If a BWA tunnel gets detected only after the corresponding
+ * connector got enabled already without a BWA tunnel, or a different
+ * BWA tunnel (which was removed meanwhile) the old CRTC state won't
+ * contain the state of the current tunnel. This tunnel still has a
+ * reserved BW, which needs to be released, add the state for such
+ * inherited tunnels separately only to this atomic state.
+ */
+ if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ return 0;
+
+ if (!old_conn_state->base.crtc)
+ return 0;
+
+ old_crtc = to_intel_crtc(old_conn_state->base.crtc);
+ old_crtc_state = intel_atomic_get_old_crtc_state(state, old_crtc);
+
+ if (!old_crtc_state->hw.active ||
+ old_crtc_state->dp_tunnel_ref.tunnel == intel_dp->tunnel)
+ return 0;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding state for inherited tunnel %p\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name,
+ old_crtc->base.base.id, old_crtc->base.name,
+ intel_dp->tunnel);
+
+ return add_inherited_tunnel(state, intel_dp->tunnel, old_crtc);
+}
+
+/**
+ * intel_dp_tunnel_atomic_cleanup_inherited_state - Free any inherited DP tunnel state
+ * @state: Atomic state
+ *
+ * Free the inherited DP tunnel state in @state.
+ */
+void intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state)
+{
+ enum pipe pipe;
+
+ if (!state->inherited_dp_tunnels)
+ return;
+
+ for_each_pipe(to_i915(state->base.dev), pipe)
+ if (state->inherited_dp_tunnels->ref[pipe].tunnel)
+ drm_dp_tunnel_ref_put(&state->inherited_dp_tunnels->ref[pipe]);
+
+ kfree(state->inherited_dp_tunnels);
+ state->inherited_dp_tunnels = NULL;
+}
+
+static int intel_dp_tunnel_atomic_add_group_state(struct intel_atomic_state *state,
+ struct drm_dp_tunnel *tunnel)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ u32 pipe_mask;
+ int err;
+
+ err = drm_dp_tunnel_atomic_get_group_streams_in_state(&state->base,
+ tunnel, &pipe_mask);
+ if (err)
+ return err;
+
+ drm_WARN_ON(&i915->drm, pipe_mask & ~((1 << I915_MAX_PIPES) - 1));
+
+ return intel_modeset_pipes_in_mask_early(state, "DPTUN", pipe_mask);
+}
+
+/**
+ * intel_dp_tunnel_atomic_add_state_for_crtc - Add CRTC specific DP tunnel state
+ * @state: Atomic state
+ * @crtc: CRTC to add the tunnel state for
+ *
+ * Add the DP tunnel state for @crtc if the CRTC (aka DP tunnel stream) is enabled
+ * via a DP tunnel.
+ *
+ * Return 0 in case of success, a negative error code otherwise.
+ */
+int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ const struct intel_crtc_state *new_crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ const struct drm_dp_tunnel_state *tunnel_state;
+ struct drm_dp_tunnel *tunnel = new_crtc_state->dp_tunnel_ref.tunnel;
+
+ if (!tunnel)
+ return 0;
+
+ tunnel_state = drm_dp_tunnel_atomic_get_state(&state->base, tunnel);
+ if (IS_ERR(tunnel_state))
+ return PTR_ERR(tunnel_state);
+
+ return 0;
+}
+
+static int check_group_state(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ struct intel_connector *connector,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ const struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+
+ if (!crtc_state->dp_tunnel_ref.tunnel)
+ return 0;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding group state for tunnel %p\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name,
+ crtc->base.base.id, crtc->base.name,
+ crtc_state->dp_tunnel_ref.tunnel);
+
+ return intel_dp_tunnel_atomic_add_group_state(state, crtc_state->dp_tunnel_ref.tunnel);
+}
+
+/**
+ * intel_dp_tunnel_atomic_check_state - Check a connector's DP tunnel specific state
+ * @state: Atomic state
+ * @intel_dp: DP port object
+ * @connector: connector using @intel_dp
+ *
+ * Check and add the DP tunnel atomic state for @intel_dp/@connector to
+ * @state, if there is a DP tunnel detected on @intel_dp with BW allocation
+ * mode enabled on it, or if @intel_dp/@connector was previously enabled via a
+ * DP tunnel.
+ *
+ * Returns 0 in case of success, or a negative error code otherwise.
+ */
+int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ struct intel_connector *connector)
+{
+ const struct intel_digital_connector_state *old_conn_state =
+ intel_atomic_get_old_connector_state(state, connector);
+ const struct intel_digital_connector_state *new_conn_state =
+ intel_atomic_get_new_connector_state(state, connector);
+ int err;
+
+ if (old_conn_state->base.crtc) {
+ err = check_group_state(state, intel_dp, connector,
+ to_intel_crtc(old_conn_state->base.crtc));
+ if (err)
+ return err;
+ }
+
+ if (new_conn_state->base.crtc &&
+ new_conn_state->base.crtc != old_conn_state->base.crtc) {
+ err = check_group_state(state, intel_dp, connector,
+ to_intel_crtc(new_conn_state->base.crtc));
+ if (err)
+ return err;
+ }
+
+ return check_inherited_tunnel_state(state, intel_dp, old_conn_state);
+}
+
+/**
+ * intel_dp_tunnel_atomic_compute_stream_bw - Compute the BW required by a DP tunnel stream
+ * @state: Atomic state
+ * @intel_dp: DP object
+ * @connector: connector using @intel_dp
+ * @crtc_state: state of CRTC of the given DP tunnel stream
+ *
+ * Compute the required BW of CRTC (aka DP tunnel stream), storing this BW to
+ * the DP tunnel state containing the stream in @state. Before re-calculating a
+ * BW requirement in the crtc_state state the old BW requirement computed by this
+ * function must be cleared by calling intel_dp_tunnel_atomic_clear_stream_bw().
+ *
+ * Returns 0 in case of success, a negative error code otherwise.
+ */
+int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ const struct intel_connector *connector,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ int required_rate = intel_dp_config_required_rate(crtc_state);
+ int ret;
+
+ if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
+ return 0;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Stream %d required BW %d Mb/s\n",
+ drm_dp_tunnel_name(intel_dp->tunnel),
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name,
+ crtc->base.base.id, crtc->base.name,
+ crtc->pipe,
+ kbytes_to_mbits(required_rate));
+
+ ret = drm_dp_tunnel_atomic_set_stream_bw(&state->base, intel_dp->tunnel,
+ crtc->pipe, required_rate);
+ if (ret < 0)
+ return ret;
+
+ drm_dp_tunnel_ref_get(intel_dp->tunnel,
+ &crtc_state->dp_tunnel_ref);
+
+ return 0;
+}
+
+/**
+ * intel_dp_tunnel_atomic_clear_stream_bw - Clear any DP tunnel stream BW requirement
+ * @state: Atomic state
+ * @crtc_state: state of CRTC of the given DP tunnel stream
+ *
+ * Clear any DP tunnel stream BW requirement set by
+ * intel_dp_tunnel_atomic_compute_stream_bw().
+ */
+void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+ if (!crtc_state->dp_tunnel_ref.tunnel)
+ return;
+
+ drm_dp_tunnel_atomic_set_stream_bw(&state->base,
+ crtc_state->dp_tunnel_ref.tunnel,
+ crtc->pipe, 0);
+ drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
+}
+
+/**
+ * intel_dp_tunnel_atomic_check_link - Check the DP tunnel atomic state
+ * @state: intel atomic state
+ * @limits: link BW limits
+ *
+ * Check the link configuration for all DP tunnels in @state. If the
+ * configuration is invalid @limits will be updated if possible to
+ * reduce the total BW, after which the configuration for all CRTCs in
+ * @state must be recomputed with the updated @limits.
+ *
+ * Returns:
+ * - 0 if the confugration is valid
+ * - %-EAGAIN, if the configuration is invalid and @limits got updated
+ * with fallback values with which the configuration of all CRTCs in
+ * @state must be recomputed
+ * - Other negative error, if the configuration is invalid without a
+ * fallback possibility, or the check failed for another reason
+ */
+int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
+ struct intel_link_bw_limits *limits)
+{
+ u32 failed_stream_mask;
+ int err;
+
+ err = drm_dp_tunnel_atomic_check_stream_bws(&state->base,
+ &failed_stream_mask);
+ if (err != -ENOSPC)
+ return err;
+
+ err = intel_link_bw_reduce_bpp(state, limits,
+ failed_stream_mask, "DP tunnel link BW");
+
+ return err ? : -EAGAIN;
+}
+
+static void atomic_decrease_bw(struct intel_atomic_state *state)
+{
+ struct intel_crtc *crtc;
+ const struct intel_crtc_state *old_crtc_state;
+ const struct intel_crtc_state *new_crtc_state;
+ int i;
+
+ for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ const struct drm_dp_tunnel_state *new_tunnel_state;
+ struct drm_dp_tunnel *tunnel;
+ int old_bw;
+ int new_bw;
+
+ if (!intel_crtc_needs_modeset(new_crtc_state))
+ continue;
+
+ tunnel = get_inherited_tunnel(state, crtc);
+ if (!tunnel)
+ tunnel = old_crtc_state->dp_tunnel_ref.tunnel;
+
+ if (!tunnel)
+ continue;
+
+ old_bw = drm_dp_tunnel_get_allocated_bw(tunnel);
+
+ new_tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel);
+ new_bw = drm_dp_tunnel_atomic_get_required_bw(new_tunnel_state);
+
+ if (new_bw >= old_bw)
+ continue;
+
+ drm_dp_tunnel_alloc_bw(tunnel, new_bw);
+ }
+}
+
+static void queue_retry_work(struct intel_atomic_state *state,
+ struct drm_dp_tunnel *tunnel,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_encoder *encoder;
+
+ encoder = intel_get_crtc_new_encoder(state, crtc_state);
+
+ if (!intel_digital_port_connected(encoder))
+ return;
+
+ drm_dbg_kms(&i915->drm,
+ "[DPTUN %s][ENCODER:%d:%s] BW allocation failed on a connected sink\n",
+ drm_dp_tunnel_name(tunnel),
+ encoder->base.base.id,
+ encoder->base.name);
+
+ intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state);
+}
+
+static void atomic_increase_bw(struct intel_atomic_state *state)
+{
+ struct intel_crtc *crtc;
+ const struct intel_crtc_state *crtc_state;
+ int i;
+
+ for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
+ struct drm_dp_tunnel_state *tunnel_state;
+ struct drm_dp_tunnel *tunnel = crtc_state->dp_tunnel_ref.tunnel;
+ int bw;
+
+ if (!intel_crtc_needs_modeset(crtc_state))
+ continue;
+
+ if (!tunnel)
+ continue;
+
+ tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel);
+
+ bw = drm_dp_tunnel_atomic_get_required_bw(tunnel_state);
+
+ if (drm_dp_tunnel_alloc_bw(tunnel, bw) != 0)
+ queue_retry_work(state, tunnel, crtc_state);
+ }
+}
+
+/**
+ * intel_dp_tunnel_atomic_alloc_bw - Allocate the BW for all modeset tunnels
+ * @state: Atomic state
+ *
+ * Allocate the required BW for all tunnels in @state.
+ */
+void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)
+{
+ atomic_decrease_bw(state);
+ atomic_increase_bw(state);
+}
+
+/**
+ * intel_dp_tunnel_mgr_init - Initialize the DP tunnel manager
+ * @i915: i915 device object
+ *
+ * Initialize the DP tunnel manager. The tunnel manager will support the
+ * detection/management of DP tunnels on all DP connectors, so the function
+ * must be called after all these connectors have been registered already.
+ *
+ * Return 0 in case of success, a negative error code otherwise.
+ */
+int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915)
+{
+ struct drm_dp_tunnel_mgr *tunnel_mgr;
+ struct drm_connector_list_iter connector_list_iter;
+ struct intel_connector *connector;
+ int dp_connectors = 0;
+
+ drm_connector_list_iter_begin(&i915->drm, &connector_list_iter);
+ for_each_intel_connector_iter(connector, &connector_list_iter) {
+ if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+ continue;
+
+ dp_connectors++;
+ }
+ drm_connector_list_iter_end(&connector_list_iter);
+
+ tunnel_mgr = drm_dp_tunnel_mgr_create(&i915->drm, dp_connectors);
+ if (IS_ERR(tunnel_mgr))
+ return PTR_ERR(tunnel_mgr);
+
+ i915->display.dp_tunnel_mgr = tunnel_mgr;
+
+ return 0;
+}
+
+/**
+ * intel_dp_tunnel_mgr_cleanup - Clean up the DP tunnel manager state
+ * @i915: i915 device object
+ *
+ * Clean up the DP tunnel manager state.
+ */
+void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915)
+{
+ drm_dp_tunnel_mgr_destroy(i915->display.dp_tunnel_mgr);
+ i915->display.dp_tunnel_mgr = NULL;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
new file mode 100644
index 0000000000..08b2cba84a
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_DP_TUNNEL_H__
+#define __INTEL_DP_TUNNEL_H__
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+struct drm_i915_private;
+struct drm_connector_state;
+struct drm_modeset_acquire_ctx;
+
+struct intel_atomic_state;
+struct intel_connector;
+struct intel_crtc;
+struct intel_crtc_state;
+struct intel_dp;
+struct intel_encoder;
+struct intel_link_bw_limits;
+
+#if defined(CONFIG_DRM_I915_DP_TUNNEL) && defined(I915)
+
+int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx);
+void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp);
+void intel_dp_tunnel_destroy(struct intel_dp *intel_dp);
+void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ bool dpcd_updated);
+void intel_dp_tunnel_suspend(struct intel_dp *intel_dp);
+
+bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp);
+
+void
+intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state);
+
+int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ const struct intel_connector *connector,
+ struct intel_crtc_state *crtc_state);
+void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state);
+
+int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
+int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
+ struct intel_link_bw_limits *limits);
+int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ struct intel_connector *connector);
+
+void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state);
+
+int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915);
+void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915);
+
+#else
+
+static inline int
+intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp) {}
+static inline void intel_dp_tunnel_destroy(struct intel_dp *intel_dp) {}
+static inline void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ bool dpcd_updated) {}
+static inline void intel_dp_tunnel_suspend(struct intel_dp *intel_dp) {}
+
+static inline bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)
+{
+ return false;
+}
+
+static inline void
+intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state) {}
+
+static inline int
+intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ const struct intel_connector *connector,
+ struct intel_crtc_state *crtc_state)
+{
+ return 0;
+}
+
+static inline void
+intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state) {}
+
+static inline int
+intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ return 0;
+}
+
+static inline int
+intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
+ struct intel_link_bw_limits *limits)
+{
+ return 0;
+}
+
+static inline int
+intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
+ struct intel_dp *intel_dp,
+ struct intel_connector *connector)
+{
+ return 0;
+}
+
+static inline int
+intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)
+{
+ return 0;
+}
+
+static inline int
+intel_dp_tunnel_mgr_init(struct drm_i915_private *i915)
+{
+ return 0;
+}
+
+static inline void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915) {}
+
+#endif /* CONFIG_DRM_I915_DP_TUNNEL */
+
+#endif /* __INTEL_DP_TUNNEL_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index 87deb135c9..b6d2441074 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -109,6 +109,8 @@ struct intel_dpll_mgr {
void (*update_ref_clks)(struct drm_i915_private *i915);
void (*dump_hw_state)(struct drm_i915_private *i915,
const struct intel_dpll_hw_state *hw_state);
+ bool (*compare_hw_state)(const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b);
};
static void
@@ -644,6 +646,15 @@ static void ibx_dump_hw_state(struct drm_i915_private *i915,
hw_state->fp1);
}
+static bool ibx_compare_hw_state(const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
+{
+ return a->dpll == b->dpll &&
+ a->dpll_md == b->dpll_md &&
+ a->fp0 == b->fp0 &&
+ a->fp1 == b->fp1;
+}
+
static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
.enable = ibx_pch_dpll_enable,
.disable = ibx_pch_dpll_disable,
@@ -662,6 +673,7 @@ static const struct intel_dpll_mgr pch_pll_mgr = {
.get_dplls = ibx_get_dpll,
.put_dplls = intel_put_dpll,
.dump_hw_state = ibx_dump_hw_state,
+ .compare_hw_state = ibx_compare_hw_state,
};
static void hsw_ddi_wrpll_enable(struct drm_i915_private *i915,
@@ -1220,6 +1232,13 @@ static void hsw_dump_hw_state(struct drm_i915_private *i915,
hw_state->wrpll, hw_state->spll);
}
+static bool hsw_compare_hw_state(const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
+{
+ return a->wrpll == b->wrpll &&
+ a->spll == b->spll;
+}
+
static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
.enable = hsw_ddi_wrpll_enable,
.disable = hsw_ddi_wrpll_disable,
@@ -1263,11 +1282,11 @@ static const struct dpll_info hsw_plls[] = {
{ .name = "WRPLL 2", .funcs = &hsw_ddi_wrpll_funcs, .id = DPLL_ID_WRPLL2, },
{ .name = "SPLL", .funcs = &hsw_ddi_spll_funcs, .id = DPLL_ID_SPLL, },
{ .name = "LCPLL 810", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_810,
- .flags = INTEL_DPLL_ALWAYS_ON, },
+ .always_on = true, },
{ .name = "LCPLL 1350", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_1350,
- .flags = INTEL_DPLL_ALWAYS_ON, },
+ .always_on = true, },
{ .name = "LCPLL 2700", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_2700,
- .flags = INTEL_DPLL_ALWAYS_ON, },
+ .always_on = true, },
{}
};
@@ -1278,6 +1297,7 @@ static const struct intel_dpll_mgr hsw_pll_mgr = {
.put_dplls = intel_put_dpll,
.update_ref_clks = hsw_update_dpll_ref_clks,
.dump_hw_state = hsw_dump_hw_state,
+ .compare_hw_state = hsw_compare_hw_state,
};
struct skl_dpll_regs {
@@ -1929,6 +1949,14 @@ static void skl_dump_hw_state(struct drm_i915_private *i915,
hw_state->cfgcr2);
}
+static bool skl_compare_hw_state(const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
+{
+ return a->ctrl1 == b->ctrl1 &&
+ a->cfgcr1 == b->cfgcr1 &&
+ a->cfgcr2 == b->cfgcr2;
+}
+
static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
.enable = skl_ddi_pll_enable,
.disable = skl_ddi_pll_disable,
@@ -1945,7 +1973,7 @@ static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
static const struct dpll_info skl_plls[] = {
{ .name = "DPLL 0", .funcs = &skl_ddi_dpll0_funcs, .id = DPLL_ID_SKL_DPLL0,
- .flags = INTEL_DPLL_ALWAYS_ON, },
+ .always_on = true, },
{ .name = "DPLL 1", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL1, },
{ .name = "DPLL 2", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL2, },
{ .name = "DPLL 3", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL3, },
@@ -1959,6 +1987,7 @@ static const struct intel_dpll_mgr skl_pll_mgr = {
.put_dplls = intel_put_dpll,
.update_ref_clks = skl_update_dpll_ref_clks,
.dump_hw_state = skl_dump_hw_state,
+ .compare_hw_state = skl_compare_hw_state,
};
static void bxt_ddi_pll_enable(struct drm_i915_private *i915,
@@ -2392,6 +2421,21 @@ static void bxt_dump_hw_state(struct drm_i915_private *i915,
hw_state->pcsdw12);
}
+static bool bxt_compare_hw_state(const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
+{
+ return a->ebb0 == b->ebb0 &&
+ a->ebb4 == b->ebb4 &&
+ a->pll0 == b->pll0 &&
+ a->pll1 == b->pll1 &&
+ a->pll2 == b->pll2 &&
+ a->pll3 == b->pll3 &&
+ a->pll6 == b->pll6 &&
+ a->pll8 == b->pll8 &&
+ a->pll10 == b->pll10 &&
+ a->pcsdw12 == b->pcsdw12;
+}
+
static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
.enable = bxt_ddi_pll_enable,
.disable = bxt_ddi_pll_disable,
@@ -2413,6 +2457,7 @@ static const struct intel_dpll_mgr bxt_pll_mgr = {
.put_dplls = intel_put_dpll,
.update_ref_clks = bxt_update_dpll_ref_clks,
.dump_hw_state = bxt_dump_hw_state,
+ .compare_hw_state = bxt_compare_hw_state,
};
static void icl_wrpll_get_multipliers(int bestdiv, int *pdiv,
@@ -4005,6 +4050,25 @@ static void icl_dump_hw_state(struct drm_i915_private *i915,
hw_state->mg_pll_tdc_coldst_bias);
}
+static bool icl_compare_hw_state(const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
+{
+ /* FIXME split combo vs. mg more thoroughly */
+ return a->cfgcr0 == b->cfgcr0 &&
+ a->cfgcr1 == b->cfgcr1 &&
+ a->div0 == b->div0 &&
+ a->mg_refclkin_ctl == b->mg_refclkin_ctl &&
+ a->mg_clktop2_coreclkctl1 == b->mg_clktop2_coreclkctl1 &&
+ a->mg_clktop2_hsclkctl == b->mg_clktop2_hsclkctl &&
+ a->mg_pll_div0 == b->mg_pll_div0 &&
+ a->mg_pll_div1 == b->mg_pll_div1 &&
+ a->mg_pll_lf == b->mg_pll_lf &&
+ a->mg_pll_frac_lock == b->mg_pll_frac_lock &&
+ a->mg_pll_ssc == b->mg_pll_ssc &&
+ a->mg_pll_bias == b->mg_pll_bias &&
+ a->mg_pll_tdc_coldst_bias == b->mg_pll_tdc_coldst_bias;
+}
+
static const struct intel_shared_dpll_funcs combo_pll_funcs = {
.enable = combo_pll_enable,
.disable = combo_pll_disable,
@@ -4030,7 +4094,7 @@ static const struct dpll_info icl_plls[] = {
{ .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
{ .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
{ .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
- .flags = INTEL_DPLL_IS_ALT_PORT_DPLL, },
+ .is_alt_port_dpll = true, },
{ .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
{ .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
{ .name = "MG PLL 3", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
@@ -4046,6 +4110,7 @@ static const struct intel_dpll_mgr icl_pll_mgr = {
.update_active_dpll = icl_update_active_dpll,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
static const struct dpll_info ehl_plls[] = {
@@ -4063,6 +4128,7 @@ static const struct intel_dpll_mgr ehl_pll_mgr = {
.put_dplls = icl_put_dplls,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
static const struct intel_shared_dpll_funcs dkl_pll_funcs = {
@@ -4076,7 +4142,7 @@ static const struct dpll_info tgl_plls[] = {
{ .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
{ .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
{ .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
- .flags = INTEL_DPLL_IS_ALT_PORT_DPLL, },
+ .is_alt_port_dpll = true, },
{ .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
{ .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
{ .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
@@ -4094,6 +4160,7 @@ static const struct intel_dpll_mgr tgl_pll_mgr = {
.update_active_dpll = icl_update_active_dpll,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
static const struct dpll_info rkl_plls[] = {
@@ -4110,6 +4177,7 @@ static const struct intel_dpll_mgr rkl_pll_mgr = {
.put_dplls = icl_put_dplls,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
static const struct dpll_info dg1_plls[] = {
@@ -4127,6 +4195,7 @@ static const struct intel_dpll_mgr dg1_pll_mgr = {
.put_dplls = icl_put_dplls,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
static const struct dpll_info adls_plls[] = {
@@ -4144,13 +4213,14 @@ static const struct intel_dpll_mgr adls_pll_mgr = {
.put_dplls = icl_put_dplls,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
static const struct dpll_info adlp_plls[] = {
{ .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
{ .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
{ .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
- .flags = INTEL_DPLL_IS_ALT_PORT_DPLL, },
+ .is_alt_port_dpll = true, },
{ .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
{ .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
{ .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
@@ -4166,6 +4236,7 @@ static const struct intel_dpll_mgr adlp_pll_mgr = {
.update_active_dpll = icl_update_active_dpll,
.update_ref_clks = icl_update_dpll_ref_clks,
.dump_hw_state = icl_dump_hw_state,
+ .compare_hw_state = icl_compare_hw_state,
};
/**
@@ -4458,13 +4529,31 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *i915,
/* fallback for platforms that don't use the shared dpll
* infrastructure
*/
- drm_dbg_kms(&i915->drm,
- "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
- "fp0: 0x%x, fp1: 0x%x\n",
- hw_state->dpll,
- hw_state->dpll_md,
- hw_state->fp0,
- hw_state->fp1);
+ ibx_dump_hw_state(i915, hw_state);
+ }
+}
+
+/**
+ * intel_dpll_compare_hw_state - compare the two states
+ * @i915: i915 drm device
+ * @a: first DPLL hw state
+ * @b: second DPLL hw state
+ *
+ * Compare DPLL hw states @a and @b.
+ *
+ * Returns: true if the states are equal, false if the differ
+ */
+bool intel_dpll_compare_hw_state(struct drm_i915_private *i915,
+ const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b)
+{
+ if (i915->display.dpll.mgr) {
+ return i915->display.dpll.mgr->compare_hw_state(a, b);
+ } else {
+ /* fallback for platforms that don't use the shared dpll
+ * infrastructure
+ */
+ return ibx_compare_hw_state(a, b);
}
}
@@ -4480,7 +4569,7 @@ verify_single_dpll_state(struct drm_i915_private *i915,
active = intel_dpll_get_hw_state(i915, pll, &dpll_hw_state);
- if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) {
+ if (!pll->info->always_on) {
I915_STATE_WARN(i915, !pll->on && pll->active_mask,
"%s: pll in active use but not on in sw tracking\n",
pll->info->name);
@@ -4527,8 +4616,7 @@ static bool has_alt_port_dpll(const struct intel_shared_dpll *old_pll,
const struct intel_shared_dpll *new_pll)
{
return old_pll && new_pll && old_pll != new_pll &&
- (old_pll->info->flags & INTEL_DPLL_IS_ALT_PORT_DPLL ||
- new_pll->info->flags & INTEL_DPLL_IS_ALT_PORT_DPLL);
+ (old_pll->info->is_alt_port_dpll || new_pll->info->is_alt_port_dpll);
}
void intel_shared_dpll_state_verify(struct intel_atomic_state *state,
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index 5cdec77cfd..cc0e138630 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -276,19 +276,21 @@ struct dpll_info {
*/
enum intel_display_power_domain power_domain;
-#define INTEL_DPLL_ALWAYS_ON (1 << 0)
-#define INTEL_DPLL_IS_ALT_PORT_DPLL (1 << 1)
/**
- * @flags:
+ * @always_on:
*
- * INTEL_DPLL_ALWAYS_ON
- * Inform the state checker that the DPLL is kept enabled even if
- * not in use by any CRTC.
- * INTEL_DPLL_IS_ALT_PORT_DPLL
- * Inform the state checker that the DPLL can be used as a fallback
- * (for TC->TBT fallback).
- */
- u32 flags;
+ * Inform the state checker that the DPLL is kept enabled even if
+ * not in use by any CRTC.
+ */
+ bool always_on;
+
+ /**
+ * @is_alt_port_dpll:
+ *
+ * Inform the state checker that the DPLL can be used as a fallback
+ * (for TC->TBT fallback).
+ */
+ bool is_alt_port_dpll;
};
/**
@@ -376,6 +378,9 @@ void intel_dpll_sanitize_state(struct drm_i915_private *i915);
void intel_dpll_dump_hw_state(struct drm_i915_private *i915,
const struct intel_dpll_hw_state *hw_state);
+bool intel_dpll_compare_hw_state(struct drm_i915_private *i915,
+ const struct intel_dpll_hw_state *a,
+ const struct intel_dpll_hw_state *b);
enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port);
bool intel_dpll_is_combophy(enum intel_dpll_id id);
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c
index 6282ec0fc9..597f8bd6aa 100644
--- a/drivers/gpu/drm/i915/display/intel_drrs.c
+++ b/drivers/gpu/drm/i915/display/intel_drrs.c
@@ -63,6 +63,15 @@ const char *intel_drrs_type_str(enum drrs_type drrs_type)
return str[drrs_type];
}
+bool intel_cpu_transcoder_has_drrs(struct drm_i915_private *i915,
+ enum transcoder cpu_transcoder)
+{
+ if (HAS_DOUBLE_BUFFERED_M_N(i915))
+ return true;
+
+ return intel_cpu_transcoder_has_m2_n2(i915, cpu_transcoder);
+}
+
static void
intel_drrs_set_refresh_rate_pipeconf(struct intel_crtc *crtc,
enum drrs_refresh_rate refresh_rate)
@@ -299,6 +308,7 @@ void intel_drrs_crtc_init(struct intel_crtc *crtc)
static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused)
{
struct intel_crtc *crtc = m->private;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct intel_crtc_state *crtc_state;
int ret;
@@ -310,6 +320,10 @@ static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused)
mutex_lock(&crtc->drrs.mutex);
+ seq_printf(m, "DRRS capable: %s\n",
+ str_yes_no(intel_cpu_transcoder_has_drrs(i915,
+ crtc_state->cpu_transcoder)));
+
seq_printf(m, "DRRS enabled: %s\n",
str_yes_no(crtc_state->has_drrs));
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h
index 8ef5f93a80..0982f95eab 100644
--- a/drivers/gpu/drm/i915/display/intel_drrs.h
+++ b/drivers/gpu/drm/i915/display/intel_drrs.h
@@ -9,12 +9,15 @@
#include <linux/types.h>
enum drrs_type;
+enum transcoder;
struct drm_i915_private;
struct intel_atomic_state;
struct intel_crtc;
struct intel_crtc_state;
struct intel_connector;
+bool intel_cpu_transcoder_has_drrs(struct drm_i915_private *i915,
+ enum transcoder cpu_transcoder);
const char *intel_drrs_type_str(enum drrs_type drrs_type);
bool intel_drrs_is_active(struct intel_crtc *crtc);
void intel_drrs_activate(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c
index 54d9abeb2d..e4515bf920 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -325,7 +325,7 @@ static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
- unsigned int latency = skl_watermark_max_latency(i915);
+ unsigned int latency = skl_watermark_max_latency(i915, 0);
int vblank_start;
if (crtc_state->vrr.enable) {
@@ -467,6 +467,10 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state,
if (!HAS_DSB(i915))
return NULL;
+ /* TODO: DSB is broken in Xe KMD, so disabling it until fixed */
+ if (!IS_ENABLED(I915))
+ return NULL;
+
dsb = kzalloc(sizeof(*dsb), GFP_KERNEL);
if (!dsb)
goto out;
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h
index 083390e5e4..e99c94edfa 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi.h
+++ b/drivers/gpu/drm/i915/display/intel_dsi.h
@@ -57,9 +57,6 @@ struct intel_dsi {
u16 phys; /* ICL DSI */
};
- /* if true, use HS mode, otherwise LP */
- bool hs;
-
/* virtual channel */
int channel;
@@ -93,7 +90,6 @@ struct intel_dsi {
bool bgr_enabled;
u8 pixel_overlap;
- u32 port_bits;
u32 bw_timer;
u32 dphy_reg;
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 9111e9d464..c076da75b0 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -30,11 +30,13 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_connector.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_dvo.h"
#include "intel_dvo_dev.h"
@@ -328,14 +330,21 @@ intel_dvo_detect(struct drm_connector *_connector, bool force)
if (!intel_display_device_enabled(i915))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(i915))
+ return connector->base.status;
+
return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
}
static int intel_dvo_get_modes(struct drm_connector *_connector)
{
struct intel_connector *connector = to_intel_connector(_connector);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
int num_modes;
+ if (!intel_display_driver_check_access(i915))
+ return drm_edid_connector_add_modes(&connector->base);
+
/*
* We should probably have an i2c driver get_modes function for those
* devices which will have a fixed set of modes determined by the chip
@@ -536,6 +545,7 @@ void intel_dvo_init(struct drm_i915_private *i915)
if (intel_dvo->dev.type == INTEL_DVO_CHIP_TMDS)
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
+ connector->base.polled = connector->polled;
drm_connector_init_with_ddc(&i915->drm, &connector->base,
&intel_dvo_connector_funcs,
diff --git a/drivers/gpu/drm/i915/display/intel_dvo_dev.h b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
index f7e98e1c64..af7b04539b 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo_dev.h
+++ b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
@@ -54,12 +54,6 @@ struct intel_dvo_dev_ops {
struct i2c_adapter *i2cbus);
/*
- * Called to allow the output a chance to create properties after the
- * RandR objects have been created.
- */
- void (*create_resources)(struct intel_dvo_device *dvo);
-
- /*
* Turn on/off output.
*
* Because none of our dvo drivers support an intermediate power levels,
@@ -80,16 +74,6 @@ struct intel_dvo_dev_ops {
struct drm_display_mode *mode);
/*
- * Callback for preparing mode changes on an output
- */
- void (*prepare)(struct intel_dvo_device *dvo);
-
- /*
- * Callback for committing mode changes on an output
- */
- void (*commit)(struct intel_dvo_device *dvo);
-
- /*
* Callback for setting up a video mode after fixups have been made.
*
* This is only called while the output is disabled. The dpms callback
@@ -112,15 +96,6 @@ struct intel_dvo_dev_ops {
bool (*get_hw_state)(struct intel_dvo_device *dev);
/**
- * Query the device for the modes it provides.
- *
- * This function may also update MonInfo, mm_width, and mm_height.
- *
- * \return singly-linked list of modes or NULL if no modes found.
- */
- struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
-
- /**
* Clean up driver-specific bits of the output
*/
void (*destroy) (struct intel_dvo_device *dvo);
diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
index 0c0144eaa8..3ea6470d6d 100644
--- a/drivers/gpu/drm/i915/display/intel_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fb.c
@@ -1849,9 +1849,10 @@ static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
fb->modifier, rotation);
if (stride > max_stride) {
- DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
- fb->base.id, stride,
- plane->base.base.id, plane->base.name, max_stride);
+ drm_dbg_kms(plane->base.dev,
+ "[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
+ fb->base.id, stride,
+ plane->base.base.id, plane->base.name, max_stride);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index f17a1afb49..b453fcbd67 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -1087,18 +1087,7 @@ static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state)
static bool skl_fbc_tiling_valid(const struct intel_plane_state *plane_state)
{
- const struct drm_framebuffer *fb = plane_state->hw.fb;
-
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_LINEAR:
- case I915_FORMAT_MOD_Y_TILED:
- case I915_FORMAT_MOD_Yf_TILED:
- case I915_FORMAT_MOD_4_TILED:
- case I915_FORMAT_MOD_X_TILED:
- return true;
- default:
- return false;
- }
+ return true;
}
static bool tiling_is_valid(const struct intel_plane_state *plane_state)
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c
index 717c3a3237..0665f943f6 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c
@@ -78,8 +78,9 @@ int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info
/* Use fbdev's framebuffer from lmem for discrete */
info->fix.smem_start =
- (unsigned long)(mem->io_start +
- i915_gem_object_get_dma_address(obj, 0));
+ (unsigned long)(mem->io.start +
+ i915_gem_object_get_dma_address(obj, 0) -
+ mem->region.start);
info->fix.smem_len = obj->base.size;
} else {
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
index e8e8be5414..cbcd1e91b7 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.c
+++ b/drivers/gpu/drm/i915/display/intel_global_state.c
@@ -10,12 +10,55 @@
#include "intel_display_types.h"
#include "intel_global_state.h"
+struct intel_global_commit {
+ struct kref ref;
+ struct completion done;
+};
+
+static struct intel_global_commit *commit_new(void)
+{
+ struct intel_global_commit *commit;
+
+ commit = kzalloc(sizeof(*commit), GFP_KERNEL);
+ if (!commit)
+ return NULL;
+
+ init_completion(&commit->done);
+ kref_init(&commit->ref);
+
+ return commit;
+}
+
+static void __commit_free(struct kref *kref)
+{
+ struct intel_global_commit *commit =
+ container_of(kref, typeof(*commit), ref);
+
+ kfree(commit);
+}
+
+static struct intel_global_commit *commit_get(struct intel_global_commit *commit)
+{
+ if (commit)
+ kref_get(&commit->ref);
+
+ return commit;
+}
+
+static void commit_put(struct intel_global_commit *commit)
+{
+ if (commit)
+ kref_put(&commit->ref, __commit_free);
+}
+
static void __intel_atomic_global_state_free(struct kref *kref)
{
struct intel_global_state *obj_state =
container_of(kref, struct intel_global_state, ref);
struct intel_global_obj *obj = obj_state->obj;
+ commit_put(obj_state->commit);
+
obj->funcs->atomic_destroy_state(obj, obj_state);
}
@@ -127,6 +170,8 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
obj_state->obj = obj;
obj_state->changed = false;
+ obj_state->serialized = false;
+ obj_state->commit = NULL;
kref_init(&obj_state->ref);
@@ -239,19 +284,13 @@ int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
{
- struct intel_atomic_state *state = obj_state->state;
- struct drm_i915_private *dev_priv = to_i915(state->base.dev);
- struct intel_crtc *crtc;
+ int ret;
- for_each_intel_crtc(&dev_priv->drm, crtc) {
- struct intel_crtc_state *crtc_state;
+ ret = intel_atomic_lock_global_state(obj_state);
+ if (ret)
+ return ret;
- crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
- }
-
- obj_state->changed = true;
+ obj_state->serialized = true;
return 0;
}
@@ -267,3 +306,79 @@ intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
return false;
return true;
}
+
+int
+intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
+{
+ const struct intel_global_state *old_obj_state;
+ struct intel_global_state *new_obj_state;
+ struct intel_global_obj *obj;
+ int i;
+
+ for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
+ new_obj_state, i) {
+ struct intel_global_commit *commit = NULL;
+
+ if (new_obj_state->serialized) {
+ /*
+ * New commit which is going to be completed
+ * after the hardware reprogramming is done.
+ */
+ commit = commit_new();
+ if (!commit)
+ return -ENOMEM;
+ } else if (new_obj_state->changed) {
+ /*
+ * We're going to swap to this state, so carry the
+ * previous commit along, in case it's not yet done.
+ */
+ commit = commit_get(old_obj_state->commit);
+ }
+
+ new_obj_state->commit = commit;
+ }
+
+ return 0;
+}
+
+int
+intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ const struct intel_global_state *old_obj_state;
+ struct intel_global_obj *obj;
+ int i;
+
+ for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
+ struct intel_global_commit *commit = old_obj_state->commit;
+ long ret;
+
+ if (!commit)
+ continue;
+
+ ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
+ if (ret == 0) {
+ drm_err(&i915->drm, "global state timed out\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+void
+intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
+{
+ const struct intel_global_state *new_obj_state;
+ struct intel_global_obj *obj;
+ int i;
+
+ for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
+ struct intel_global_commit *commit = new_obj_state->commit;
+
+ if (!new_obj_state->serialized)
+ continue;
+
+ complete_all(&commit->done);
+ }
+}
diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
index 5477de8f0b..6506a8e329 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.h
+++ b/drivers/gpu/drm/i915/display/intel_global_state.h
@@ -37,11 +37,11 @@ struct intel_global_obj {
(__i)++) \
for_each_if(obj)
-#define for_each_old_global_obj_in_state(__state, obj, new_obj_state, __i) \
+#define for_each_old_global_obj_in_state(__state, obj, old_obj_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->num_global_objs && \
((obj) = (__state)->global_objs[__i].ptr, \
- (new_obj_state) = (__state)->global_objs[__i].old_state, 1); \
+ (old_obj_state) = (__state)->global_objs[__i].old_state, 1); \
(__i)++) \
for_each_if(obj)
@@ -54,11 +54,14 @@ struct intel_global_obj {
(__i)++) \
for_each_if(obj)
+struct intel_global_commit;
+
struct intel_global_state {
struct intel_global_obj *obj;
struct intel_atomic_state *state;
+ struct intel_global_commit *commit;
struct kref ref;
- bool changed;
+ bool changed, serialized;
};
struct __intel_global_objs_state {
@@ -87,6 +90,10 @@ void intel_atomic_clear_global_state(struct intel_atomic_state *state);
int intel_atomic_lock_global_state(struct intel_global_state *obj_state);
int intel_atomic_serialize_global_state(struct intel_global_state *obj_state);
+int intel_atomic_global_state_setup_commit(struct intel_atomic_state *state);
+void intel_atomic_global_state_commit_done(struct intel_atomic_state *state);
+int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state);
+
bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
#endif
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index e9e4dcf345..d3e03ed5b7 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -155,7 +155,7 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915,
const struct gmbus_pin *pins;
size_t size;
- if (INTEL_PCH_TYPE(i915) >= PCH_LNL) {
+ if (INTEL_PCH_TYPE(i915) >= PCH_MTL) {
pins = gmbus_pins_mtp;
size = ARRAY_SIZE(gmbus_pins_mtp);
} else if (INTEL_PCH_TYPE(i915) >= PCH_DG2) {
@@ -164,9 +164,6 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915,
} else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) {
pins = gmbus_pins_dg1;
size = ARRAY_SIZE(gmbus_pins_dg1);
- } else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) {
- pins = gmbus_pins_mtp;
- size = ARRAY_SIZE(gmbus_pins_mtp);
} else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) {
pins = gmbus_pins_icp;
size = ARRAY_SIZE(gmbus_pins_icp);
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 39b3f7c0c7..9edac27bab 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -30,7 +30,7 @@
#define KEY_LOAD_TRIES 5
#define HDCP2_LC_RETRY_CNT 3
-static int intel_conn_to_vcpi(struct drm_atomic_state *state,
+static int intel_conn_to_vcpi(struct intel_atomic_state *state,
struct intel_connector *connector)
{
struct drm_dp_mst_topology_mgr *mgr;
@@ -43,7 +43,7 @@ static int intel_conn_to_vcpi(struct drm_atomic_state *state,
return 0;
mgr = connector->port->mgr;
- drm_modeset_lock(&mgr->base.lock, state->acquire_ctx);
+ drm_modeset_lock(&mgr->base.lock, state->base.acquire_ctx);
mst_state = to_drm_dp_mst_topology_state(mgr->base.state);
payload = drm_atomic_get_mst_payload_state(mst_state, connector->port);
if (drm_WARN_ON(mgr->dev, !payload))
@@ -68,19 +68,51 @@ out:
* DP MST topology. Though it is not compulsory, security fw should change its
* policy to mark different content_types for different streams.
*/
-static void
-intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
+static int
+intel_hdcp_required_content_stream(struct intel_atomic_state *state,
+ struct intel_digital_port *dig_port)
{
+ struct drm_connector_list_iter conn_iter;
+ struct intel_digital_port *conn_dig_port;
+ struct intel_connector *connector;
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
bool enforce_type0 = false;
int k;
if (dig_port->hdcp_auth_status)
- return;
+ return 0;
+
+ data->k = 0;
if (!dig_port->hdcp_mst_type1_capable)
enforce_type0 = true;
+ drm_connector_list_iter_begin(&i915->drm, &conn_iter);
+ for_each_intel_connector_iter(connector, &conn_iter) {
+ if (connector->base.status == connector_status_disconnected)
+ continue;
+
+ if (!intel_encoder_is_mst(intel_attached_encoder(connector)))
+ continue;
+
+ conn_dig_port = intel_attached_dig_port(connector);
+ if (conn_dig_port != dig_port)
+ continue;
+
+ data->streams[data->k].stream_id =
+ intel_conn_to_vcpi(state, connector);
+ data->k++;
+
+ /* if there is only one active stream */
+ if (dig_port->dp.active_mst_links <= 1)
+ break;
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ if (drm_WARN_ON(&i915->drm, data->k > INTEL_NUM_PIPES(i915) || data->k == 0))
+ return -EINVAL;
+
/*
* Apply common protection level across all streams in DP MST Topology.
* Use highest supported content type for all streams in DP MST Topology.
@@ -88,19 +120,25 @@ intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
for (k = 0; k < data->k; k++)
data->streams[k].stream_type =
enforce_type0 ? DRM_MODE_HDCP_CONTENT_TYPE0 : DRM_MODE_HDCP_CONTENT_TYPE1;
+
+ return 0;
}
-static void intel_hdcp_prepare_streams(struct intel_connector *connector)
+static int intel_hdcp_prepare_streams(struct intel_atomic_state *state,
+ struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
struct intel_hdcp *hdcp = &connector->hdcp;
- if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
- data->streams[0].stream_type = hdcp->content_type;
- } else {
- intel_hdcp_required_content_stream(dig_port);
- }
+ if (intel_encoder_is_mst(intel_attached_encoder(connector)))
+ return intel_hdcp_required_content_stream(state, dig_port);
+
+ data->k = 1;
+ data->streams[0].stream_id = 0;
+ data->streams[0].stream_type = hdcp->content_type;
+
+ return 0;
}
static
@@ -140,7 +178,7 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
}
/* Is HDCP1.4 capable on Platform and Sink */
-bool intel_hdcp_capable(struct intel_connector *connector)
+bool intel_hdcp_get_capability(struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
const struct intel_hdcp_shim *shim = connector->hdcp.shim;
@@ -150,8 +188,8 @@ bool intel_hdcp_capable(struct intel_connector *connector)
if (!shim)
return capable;
- if (shim->hdcp_capable) {
- shim->hdcp_capable(dig_port, &capable);
+ if (shim->hdcp_get_capability) {
+ shim->hdcp_get_capability(dig_port, &capable);
} else {
if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
capable = true;
@@ -160,12 +198,14 @@ bool intel_hdcp_capable(struct intel_connector *connector)
return capable;
}
-/* Is HDCP2.2 capable on Platform and Sink */
-bool intel_hdcp2_capable(struct intel_connector *connector)
+/*
+ * Check if the source has all the building blocks ready to make
+ * HDCP 2.2 work
+ */
+static bool intel_hdcp2_prerequisite(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
- bool capable = false;
/* I915 support for HDCP2.2 */
if (!hdcp->hdcp2_supported)
@@ -185,12 +225,40 @@ bool intel_hdcp2_capable(struct intel_connector *connector)
}
mutex_unlock(&i915->display.hdcp.hdcp_mutex);
+ return true;
+}
+
+/* Is HDCP2.2 capable on Platform and Sink */
+bool intel_hdcp2_get_capability(struct intel_connector *connector)
+{
+ struct intel_hdcp *hdcp = &connector->hdcp;
+ bool capable = false;
+
+ if (!intel_hdcp2_prerequisite(connector))
+ return false;
+
/* Sink's capability for HDCP2.2 */
- hdcp->shim->hdcp_2_2_capable(connector, &capable);
+ hdcp->shim->hdcp_2_2_get_capability(connector, &capable);
return capable;
}
+void intel_hdcp_get_remote_capability(struct intel_connector *connector,
+ bool *hdcp_capable,
+ bool *hdcp2_capable)
+{
+ struct intel_hdcp *hdcp = &connector->hdcp;
+
+ if (!hdcp->shim->get_remote_hdcp_capability)
+ return;
+
+ hdcp->shim->get_remote_hdcp_capability(connector, hdcp_capable,
+ hdcp2_capable);
+
+ if (!intel_hdcp2_prerequisite(connector))
+ *hdcp2_capable = false;
+}
+
static bool intel_hdcp_in_use(struct drm_i915_private *i915,
enum transcoder cpu_transcoder, enum port port)
{
@@ -347,7 +415,7 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *i915,
default:
drm_err(&i915->drm, "Unknown transcoder %d\n",
cpu_transcoder);
- return -EINVAL;
+ return 0;
}
}
@@ -364,7 +432,7 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *i915,
return HDCP_DDIE_REP_PRESENT | HDCP_DDIE_SHA1_M0;
default:
drm_err(&i915->drm, "Unknown port %d\n", port);
- return -EINVAL;
+ return 0;
}
}
@@ -726,8 +794,8 @@ static int intel_hdcp_auth(struct intel_connector *connector)
* whether the display supports HDCP before we write An. For HDMI
* displays, this is not necessary.
*/
- if (shim->hdcp_capable) {
- ret = shim->hdcp_capable(dig_port, &hdcp_capable);
+ if (shim->hdcp_get_capability) {
+ ret = shim->hdcp_get_capability(dig_port, &hdcp_capable);
if (ret)
return ret;
if (!hdcp_capable) {
@@ -853,8 +921,8 @@ static int intel_hdcp_auth(struct intel_connector *connector)
if (shim->stream_encryption) {
ret = shim->stream_encryption(connector, true);
if (ret) {
- drm_err(&i915->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n",
- connector->base.name, connector->base.base.id);
+ drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to enable HDCP 1.4 stream enc\n",
+ connector->base.base.id, connector->base.name);
return ret;
}
drm_dbg_kms(&i915->drm, "HDCP 1.4 transcoder: %s stream encrypted\n",
@@ -878,14 +946,14 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
u32 repeater_ctl;
int ret;
- drm_dbg_kms(&i915->drm, "[%s:%d] HDCP is being disabled...\n",
- connector->base.name, connector->base.base.id);
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP is being disabled...\n",
+ connector->base.base.id, connector->base.name);
if (hdcp->shim->stream_encryption) {
ret = hdcp->shim->stream_encryption(connector, false);
if (ret) {
- drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
- connector->base.name, connector->base.base.id);
+ drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to disable HDCP 1.4 stream enc\n",
+ connector->base.base.id, connector->base.name);
return ret;
}
drm_dbg_kms(&i915->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n",
@@ -929,8 +997,8 @@ static int intel_hdcp1_enable(struct intel_connector *connector)
struct intel_hdcp *hdcp = &connector->hdcp;
int i, ret, tries = 3;
- drm_dbg_kms(&i915->drm, "[%s:%d] HDCP is being enabled...\n",
- connector->base.name, connector->base.base.id);
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP is being enabled...\n",
+ connector->base.base.id, connector->base.name);
if (!hdcp_key_loadable(i915)) {
drm_err(&i915->drm, "HDCP key Load is not possible\n");
@@ -1027,8 +1095,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
if (drm_WARN_ON(&i915->drm,
!intel_hdcp_in_use(i915, cpu_transcoder, port))) {
drm_err(&i915->drm,
- "%s:%d HDCP link stopped encryption,%x\n",
- connector->base.name, connector->base.base.id,
+ "[CONNECTOR:%d:%s] HDCP link stopped encryption,%x\n",
+ connector->base.base.id, connector->base.name,
intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port)));
ret = -ENXIO;
intel_hdcp_update_value(connector,
@@ -1046,8 +1114,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
}
drm_dbg_kms(&i915->drm,
- "[%s:%d] HDCP link failed, retrying authentication\n",
- connector->base.name, connector->base.base.id);
+ "[CONNECTOR:%d:%s] HDCP link failed, retrying authentication\n",
+ connector->base.base.id, connector->base.name);
ret = _intel_hdcp_disable(connector);
if (ret) {
@@ -1058,15 +1126,9 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
goto out;
}
- ret = intel_hdcp1_enable(connector);
- if (ret) {
- drm_err(&i915->drm, "Failed to enable hdcp (%d)\n", ret);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
- }
-
+ intel_hdcp_update_value(connector,
+ DRM_MODE_CONTENT_PROTECTION_DESIRED,
+ true);
out:
mutex_unlock(&dig_port->hdcp_mutex);
mutex_unlock(&hdcp->mutex);
@@ -1633,6 +1695,12 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
!HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) &&
!HDCP_2_2_HDCP_2_0_REP_CONNECTED(rx_info[1]);
+ if (!dig_port->hdcp_mst_type1_capable && hdcp->content_type) {
+ drm_dbg_kms(&i915->drm,
+ "HDCP1.x or 2.0 Legacy Device Downstream\n");
+ return -EINVAL;
+ }
+
/* Converting and Storing the seq_num_v to local variable as DWORD */
seq_num_v =
drm_hdcp_be24_to_cpu((const u8 *)msgs.recvid_list.seq_num_v);
@@ -1731,8 +1799,8 @@ static int hdcp2_enable_stream_encryption(struct intel_connector *connector)
if (!(intel_de_read(i915, HDCP2_STATUS(i915, cpu_transcoder, port)) &
LINK_ENCRYPTION_STATUS)) {
- drm_err(&i915->drm, "[%s:%d] HDCP 2.2 Link is not encrypted\n",
- connector->base.name, connector->base.base.id);
+ drm_err(&i915->drm, "[CONNECTOR:%d:%s] HDCP 2.2 Link is not encrypted\n",
+ connector->base.base.id, connector->base.name);
ret = -EPERM;
goto link_recover;
}
@@ -1740,8 +1808,8 @@ static int hdcp2_enable_stream_encryption(struct intel_connector *connector)
if (hdcp->shim->stream_2_2_encryption) {
ret = hdcp->shim->stream_2_2_encryption(connector, true);
if (ret) {
- drm_err(&i915->drm, "[%s:%d] Failed to enable HDCP 2.2 stream enc\n",
- connector->base.name, connector->base.base.id);
+ drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to enable HDCP 2.2 stream enc\n",
+ connector->base.base.id, connector->base.name);
return ret;
}
drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encrypted\n",
@@ -1865,7 +1933,8 @@ hdcp2_propagate_stream_management_info(struct intel_connector *connector)
return ret;
}
-static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
+static int hdcp2_authenticate_and_encrypt(struct intel_atomic_state *state,
+ struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *i915 = to_i915(connector->base.dev);
@@ -1874,7 +1943,13 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
for (i = 0; i < tries && !dig_port->hdcp_auth_status; i++) {
ret = hdcp2_authenticate_sink(connector);
if (!ret) {
- intel_hdcp_prepare_streams(connector);
+ ret = intel_hdcp_prepare_streams(state, connector);
+ if (ret) {
+ drm_dbg_kms(&i915->drm,
+ "Prepare stream failed.(%d)\n",
+ ret);
+ break;
+ }
ret = hdcp2_propagate_stream_management_info(connector);
if (ret) {
@@ -1919,25 +1994,26 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
return ret;
}
-static int _intel_hdcp2_enable(struct intel_connector *connector)
+static int _intel_hdcp2_enable(struct intel_atomic_state *state,
+ struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
int ret;
- drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being enabled. Type: %d\n",
- connector->base.name, connector->base.base.id,
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is being enabled. Type: %d\n",
+ connector->base.base.id, connector->base.name,
hdcp->content_type);
- ret = hdcp2_authenticate_and_encrypt(connector);
+ ret = hdcp2_authenticate_and_encrypt(state, connector);
if (ret) {
drm_dbg_kms(&i915->drm, "HDCP2 Type%d Enabling Failed. (%d)\n",
hdcp->content_type, ret);
return ret;
}
- drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is enabled. Type %d\n",
- connector->base.name, connector->base.base.id,
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is enabled. Type %d\n",
+ connector->base.base.id, connector->base.name,
hdcp->content_type);
hdcp->hdcp2_encrypted = true;
@@ -1953,14 +2029,14 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery
struct intel_hdcp *hdcp = &connector->hdcp;
int ret;
- drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being Disabled\n",
- connector->base.name, connector->base.base.id);
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is being Disabled\n",
+ connector->base.base.id, connector->base.name);
if (hdcp->shim->stream_2_2_encryption) {
ret = hdcp->shim->stream_2_2_encryption(connector, false);
if (ret) {
- drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 2.2 stream enc\n",
- connector->base.name, connector->base.base.id);
+ drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to disable HDCP 2.2 stream enc\n",
+ connector->base.base.id, connector->base.name);
return ret;
}
drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encryption disabled\n",
@@ -2032,45 +2108,24 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
drm_dbg_kms(&i915->drm,
"HDCP2.2 Downstream topology change\n");
- ret = hdcp2_authenticate_repeater_topology(connector);
- if (!ret) {
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_ENABLED,
- true);
- goto out;
- }
- drm_dbg_kms(&i915->drm,
- "[%s:%d] Repeater topology auth failed.(%d)\n",
- connector->base.name, connector->base.base.id,
- ret);
} else {
drm_dbg_kms(&i915->drm,
- "[%s:%d] HDCP2.2 link failed, retrying auth\n",
- connector->base.name, connector->base.base.id);
+ "[CONNECTOR:%d:%s] HDCP2.2 link failed, retrying auth\n",
+ connector->base.base.id, connector->base.name);
}
ret = _intel_hdcp2_disable(connector, true);
if (ret) {
drm_err(&i915->drm,
- "[%s:%d] Failed to disable hdcp2.2 (%d)\n",
- connector->base.name, connector->base.base.id, ret);
+ "[CONNECTOR:%d:%s] Failed to disable hdcp2.2 (%d)\n",
+ connector->base.base.id, connector->base.name, ret);
intel_hdcp_update_value(connector,
DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
goto out;
}
- ret = _intel_hdcp2_enable(connector);
- if (ret) {
- drm_dbg_kms(&i915->drm,
- "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
- connector->base.name, connector->base.base.id,
- ret);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
- }
-
+ intel_hdcp_update_value(connector,
+ DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
out:
mutex_unlock(&dig_port->hdcp_mutex);
mutex_unlock(&hdcp->mutex);
@@ -2278,52 +2333,6 @@ int intel_hdcp_init(struct intel_connector *connector,
return 0;
}
-static int
-intel_hdcp_set_streams(struct intel_digital_port *dig_port,
- struct intel_atomic_state *state)
-{
- struct drm_connector_list_iter conn_iter;
- struct intel_digital_port *conn_dig_port;
- struct intel_connector *connector;
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct hdcp_port_data *data = &dig_port->hdcp_port_data;
-
- if (!intel_encoder_is_mst(&dig_port->base)) {
- data->k = 1;
- data->streams[0].stream_id = 0;
- return 0;
- }
-
- data->k = 0;
-
- drm_connector_list_iter_begin(&i915->drm, &conn_iter);
- for_each_intel_connector_iter(connector, &conn_iter) {
- if (connector->base.status == connector_status_disconnected)
- continue;
-
- if (!intel_encoder_is_mst(intel_attached_encoder(connector)))
- continue;
-
- conn_dig_port = intel_attached_dig_port(connector);
- if (conn_dig_port != dig_port)
- continue;
-
- data->streams[data->k].stream_id =
- intel_conn_to_vcpi(&state->base, connector);
- data->k++;
-
- /* if there is only one active stream */
- if (dig_port->dp.active_mst_links <= 1)
- break;
- }
- drm_connector_list_iter_end(&conn_iter);
-
- if (drm_WARN_ON(&i915->drm, data->k > INTEL_NUM_PIPES(i915) || data->k == 0))
- return -EINVAL;
-
- return 0;
-}
-
static int _intel_hdcp_enable(struct intel_atomic_state *state,
struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config,
@@ -2341,8 +2350,8 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state,
return -ENOENT;
if (!connector->encoder) {
- drm_err(&i915->drm, "[%s:%d] encoder is not initialized\n",
- connector->base.name, connector->base.base.id);
+ drm_err(&i915->drm, "[CONNECTOR:%d:%s] encoder is not initialized\n",
+ connector->base.base.id, connector->base.name);
return -ENODEV;
}
@@ -2368,25 +2377,18 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state,
* Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
* is capable of HDCP2.2, it is preferred to use HDCP2.2.
*/
- if (intel_hdcp2_capable(connector)) {
- ret = intel_hdcp_set_streams(dig_port, state);
- if (!ret) {
- ret = _intel_hdcp2_enable(connector);
- if (!ret)
- check_link_interval =
- DRM_HDCP2_CHECK_PERIOD_MS;
- } else {
- drm_dbg_kms(&i915->drm,
- "Set content streams failed: (%d)\n",
- ret);
- }
+ if (intel_hdcp2_get_capability(connector)) {
+ ret = _intel_hdcp2_enable(state, connector);
+ if (!ret)
+ check_link_interval =
+ DRM_HDCP2_CHECK_PERIOD_MS;
}
/*
* When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
* be attempted.
*/
- if (ret && intel_hdcp_capable(connector) &&
+ if (ret && intel_hdcp_get_capability(connector) &&
hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
ret = intel_hdcp1_enable(connector);
}
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h
index a9c784fd9b..477f2d2bb1 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.h
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
@@ -38,8 +38,11 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
bool is_hdcp_supported(struct drm_i915_private *i915, enum port port);
-bool intel_hdcp_capable(struct intel_connector *connector);
-bool intel_hdcp2_capable(struct intel_connector *connector);
+bool intel_hdcp_get_capability(struct intel_connector *connector);
+bool intel_hdcp2_get_capability(struct intel_connector *connector);
+void intel_hdcp_get_remote_capability(struct intel_connector *connector,
+ bool *hdcp_capable,
+ bool *hdcp2_capable);
void intel_hdcp_component_init(struct drm_i915_private *i915);
void intel_hdcp_component_fini(struct drm_i915_private *i915);
void intel_hdcp_cleanup(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c
index 18117b789b..302bff75b0 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c
@@ -65,7 +65,7 @@ static int intel_hdcp_gsc_initialize_message(struct drm_i915_private *i915,
goto out_unmap;
}
- err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
+ err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH);
if (err)
goto out_unmap;
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h
index 8023c85c7f..a568a457e5 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h
@@ -8,6 +8,8 @@
#include "intel_display_reg_defs.h"
+#define TRANS_HDCP(__i915) (DISPLAY_VER(__i915) >= 12)
+
/* HDCP Key Registers */
#define HDCP_KEY_CONF _MMIO(0x66c00)
#define HDCP_AKSV_SEND_TRIGGER REG_BIT(31)
@@ -82,7 +84,7 @@
#define TRANS_HDCP_CONF(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_CONF, \
_TRANSB_HDCP_CONF)
#define HDCP_CONF(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_CONF(trans) : \
PORT_HDCP_CONF(port))
@@ -95,7 +97,7 @@
_TRANSA_HDCP_ANINIT, \
_TRANSB_HDCP_ANINIT)
#define HDCP_ANINIT(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_ANINIT(trans) : \
PORT_HDCP_ANINIT(port))
@@ -105,7 +107,7 @@
#define TRANS_HDCP_ANLO(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_ANLO, \
_TRANSB_HDCP_ANLO)
#define HDCP_ANLO(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_ANLO(trans) : \
PORT_HDCP_ANLO(port))
@@ -115,7 +117,7 @@
#define TRANS_HDCP_ANHI(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_ANHI, \
_TRANSB_HDCP_ANHI)
#define HDCP_ANHI(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_ANHI(trans) : \
PORT_HDCP_ANHI(port))
@@ -126,7 +128,7 @@
_TRANSA_HDCP_BKSVLO, \
_TRANSB_HDCP_BKSVLO)
#define HDCP_BKSVLO(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_BKSVLO(trans) : \
PORT_HDCP_BKSVLO(port))
@@ -137,7 +139,7 @@
_TRANSA_HDCP_BKSVHI, \
_TRANSB_HDCP_BKSVHI)
#define HDCP_BKSVHI(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_BKSVHI(trans) : \
PORT_HDCP_BKSVHI(port))
@@ -148,7 +150,7 @@
_TRANSA_HDCP_RPRIME, \
_TRANSB_HDCP_RPRIME)
#define HDCP_RPRIME(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_RPRIME(trans) : \
PORT_HDCP_RPRIME(port))
@@ -159,7 +161,7 @@
_TRANSA_HDCP_STATUS, \
_TRANSB_HDCP_STATUS)
#define HDCP_STATUS(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP_STATUS(trans) : \
PORT_HDCP_STATUS(port))
@@ -200,7 +202,7 @@
#define AUTH_FORCE_CLR_INPUTCTR REG_BIT(19)
#define AUTH_CLR_KEYS REG_BIT(18)
#define HDCP2_AUTH(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP2_AUTH(trans) : \
PORT_HDCP2_AUTH(port))
@@ -211,7 +213,7 @@
_TRANSB_HDCP2_CTL)
#define CTL_LINK_ENCRYPTION_REQ REG_BIT(31)
#define HDCP2_CTL(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP2_CTL(trans) : \
PORT_HDCP2_CTL(port))
@@ -225,7 +227,7 @@
#define LINK_AUTH_STATUS REG_BIT(21)
#define LINK_ENCRYPTION_STATUS REG_BIT(20)
#define HDCP2_STATUS(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP2_STATUS(trans) : \
PORT_HDCP2_STATUS(port))
@@ -247,7 +249,7 @@
#define STREAM_ENCRYPTION_STATUS REG_BIT(31)
#define STREAM_TYPE_STATUS REG_BIT(30)
#define HDCP2_STREAM_STATUS(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP2_STREAM_STATUS(trans) : \
PIPE_HDCP2_STREAM_STATUS(pipe))
@@ -263,7 +265,7 @@
_TRANSB_HDCP2_AUTH_STREAM)
#define AUTH_STREAM_TYPE REG_BIT(31)
#define HDCP2_AUTH_STREAM(dev_priv, trans, port) \
- (GRAPHICS_VER(dev_priv) >= 12 ? \
+ (TRANS_HDCP(dev_priv) ? \
TRANS_HDCP2_AUTH_STREAM(trans) : \
PORT_HDCP2_AUTH_STREAM(port))
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 39e4f5f7c8..90d2236fed 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -49,6 +49,7 @@
#include "intel_cx0_phy.h"
#include "intel_ddi.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_dp.h"
#include "intel_gmbus.h"
@@ -523,10 +524,12 @@ void hsw_write_infoframe(struct intel_encoder *encoder,
0);
/* Wa_14013475917 */
- if (IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC)
- return;
+ if (!(IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC))
+ val |= hsw_infoframe_enable(type);
+
+ if (type == DP_SDP_VSC)
+ val |= VSC_DIP_HW_DATA_SW_HEA;
- val |= hsw_infoframe_enable(type);
intel_de_write(dev_priv, ctl_reg, val);
intel_de_posting_read(dev_priv, ctl_reg);
}
@@ -1729,8 +1732,8 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
}
static
-int intel_hdmi_hdcp2_capable(struct intel_connector *connector,
- bool *capable)
+int intel_hdmi_hdcp2_get_capability(struct intel_connector *connector,
+ bool *capable)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
u8 hdcp2_version;
@@ -1759,7 +1762,7 @@ static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
.check_2_2_link = intel_hdmi_hdcp2_check_link,
- .hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
+ .hdcp_2_2_get_capability = intel_hdmi_hdcp2_get_capability,
.protocol = HDCP_PROTOCOL_HDMI,
};
@@ -2503,6 +2506,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
if (!intel_display_device_enabled(dev_priv))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(dev_priv))
+ return connector->status;
+
wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
if (DISPLAY_VER(dev_priv) >= 11 &&
@@ -2531,6 +2537,9 @@ intel_hdmi_force(struct drm_connector *connector)
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
+ if (!intel_display_driver_check_access(i915))
+ return;
+
intel_hdmi_unset_edid(connector);
if (connector->status != connector_status_connected)
@@ -3015,6 +3024,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
connector->ycbcr_420_allowed = true;
intel_connector->polled = DRM_CONNECTOR_POLL_HPD;
+ intel_connector->base.polled = intel_connector->polled;
if (HAS_DDI(dev_priv))
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index 0c0700c6ec..d9ec349f3c 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -177,6 +177,46 @@ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv,
return storm;
}
+static bool detection_work_enabled(struct drm_i915_private *i915)
+{
+ lockdep_assert_held(&i915->irq_lock);
+
+ return i915->display.hotplug.detection_work_enabled;
+}
+
+static bool
+mod_delayed_detection_work(struct drm_i915_private *i915, struct delayed_work *work, int delay)
+{
+ lockdep_assert_held(&i915->irq_lock);
+
+ if (!detection_work_enabled(i915))
+ return false;
+
+ return mod_delayed_work(i915->unordered_wq, work, delay);
+}
+
+static bool
+queue_delayed_detection_work(struct drm_i915_private *i915, struct delayed_work *work, int delay)
+{
+ lockdep_assert_held(&i915->irq_lock);
+
+ if (!detection_work_enabled(i915))
+ return false;
+
+ return queue_delayed_work(i915->unordered_wq, work, delay);
+}
+
+static bool
+queue_detection_work(struct drm_i915_private *i915, struct work_struct *work)
+{
+ lockdep_assert_held(&i915->irq_lock);
+
+ if (!detection_work_enabled(i915))
+ return false;
+
+ return queue_work(i915->unordered_wq, work);
+}
+
static void
intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
{
@@ -213,9 +253,9 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
/* Enable polling and queue hotplug re-enabling. */
if (hpd_disabled) {
drm_kms_helper_poll_reschedule(&dev_priv->drm);
- mod_delayed_work(dev_priv->unordered_wq,
- &dev_priv->display.hotplug.reenable_work,
- msecs_to_jiffies(HPD_STORM_REENABLE_DELAY));
+ mod_delayed_detection_work(dev_priv,
+ &dev_priv->display.hotplug.reenable_work,
+ msecs_to_jiffies(HPD_STORM_REENABLE_DELAY));
}
}
@@ -348,9 +388,9 @@ static void i915_digport_work_func(struct work_struct *work)
if (old_bits) {
spin_lock_irq(&dev_priv->irq_lock);
dev_priv->display.hotplug.event_bits |= old_bits;
+ queue_delayed_detection_work(dev_priv,
+ &dev_priv->display.hotplug.hotplug_work, 0);
spin_unlock_irq(&dev_priv->irq_lock);
- queue_delayed_work(dev_priv->unordered_wq,
- &dev_priv->display.hotplug.hotplug_work, 0);
}
}
@@ -467,11 +507,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
if (retry) {
spin_lock_irq(&dev_priv->irq_lock);
dev_priv->display.hotplug.retry_bits |= retry;
- spin_unlock_irq(&dev_priv->irq_lock);
- mod_delayed_work(dev_priv->unordered_wq,
- &dev_priv->display.hotplug.hotplug_work,
- msecs_to_jiffies(HPD_RETRY_DELAY));
+ mod_delayed_detection_work(dev_priv,
+ &dev_priv->display.hotplug.hotplug_work,
+ msecs_to_jiffies(HPD_RETRY_DELAY));
+ spin_unlock_irq(&dev_priv->irq_lock);
}
}
@@ -590,7 +630,6 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
*/
if (storm_detected)
intel_hpd_irq_setup(dev_priv);
- spin_unlock(&dev_priv->irq_lock);
/*
* Our hotplug handler can grab modeset locks (by calling down into the
@@ -601,8 +640,10 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
if (queue_dig)
queue_work(dev_priv->display.hotplug.dp_wq, &dev_priv->display.hotplug.dig_port_work);
if (queue_hp)
- queue_delayed_work(dev_priv->unordered_wq,
- &dev_priv->display.hotplug.hotplug_work, 0);
+ queue_delayed_detection_work(dev_priv,
+ &dev_priv->display.hotplug.hotplug_work, 0);
+
+ spin_unlock(&dev_priv->irq_lock);
}
/**
@@ -710,6 +751,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
cancel_work(&dev_priv->display.hotplug.poll_init_work);
}
+ spin_lock_irq(&dev_priv->irq_lock);
+
drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
enum hpd_pin pin;
@@ -718,6 +761,9 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
if (pin == HPD_NONE)
continue;
+ if (dev_priv->display.hotplug.stats[pin].state == HPD_DISABLED)
+ continue;
+
connector->base.polled = connector->polled;
if (enabled && connector->base.polled == DRM_CONNECTOR_POLL_HPD)
@@ -726,6 +772,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
}
drm_connector_list_iter_end(&conn_iter);
+ spin_unlock_irq(&dev_priv->irq_lock);
+
if (enabled)
drm_kms_helper_poll_reschedule(&dev_priv->drm);
@@ -774,8 +822,10 @@ void intel_hpd_poll_enable(struct drm_i915_private *dev_priv)
* As well, there's no issue if we race here since we always reschedule
* this worker anyway
*/
- queue_work(dev_priv->unordered_wq,
- &dev_priv->display.hotplug.poll_init_work);
+ spin_lock_irq(&dev_priv->irq_lock);
+ queue_detection_work(dev_priv,
+ &dev_priv->display.hotplug.poll_init_work);
+ spin_unlock_irq(&dev_priv->irq_lock);
}
/**
@@ -803,8 +853,11 @@ void intel_hpd_poll_disable(struct drm_i915_private *dev_priv)
return;
WRITE_ONCE(dev_priv->display.hotplug.poll_enabled, false);
- queue_work(dev_priv->unordered_wq,
- &dev_priv->display.hotplug.poll_init_work);
+
+ spin_lock_irq(&dev_priv->irq_lock);
+ queue_detection_work(dev_priv,
+ &dev_priv->display.hotplug.poll_init_work);
+ spin_unlock_irq(&dev_priv->irq_lock);
}
void intel_hpd_init_early(struct drm_i915_private *i915)
@@ -826,6 +879,20 @@ void intel_hpd_init_early(struct drm_i915_private *i915)
i915->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(i915);
}
+static bool cancel_all_detection_work(struct drm_i915_private *i915)
+{
+ bool was_pending = false;
+
+ if (cancel_delayed_work_sync(&i915->display.hotplug.hotplug_work))
+ was_pending = true;
+ if (cancel_work_sync(&i915->display.hotplug.poll_init_work))
+ was_pending = true;
+ if (cancel_delayed_work_sync(&i915->display.hotplug.reenable_work))
+ was_pending = true;
+
+ return was_pending;
+}
+
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
{
if (!HAS_DISPLAY(dev_priv))
@@ -841,9 +908,13 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock);
cancel_work_sync(&dev_priv->display.hotplug.dig_port_work);
- cancel_delayed_work_sync(&dev_priv->display.hotplug.hotplug_work);
- cancel_work_sync(&dev_priv->display.hotplug.poll_init_work);
- cancel_delayed_work_sync(&dev_priv->display.hotplug.reenable_work);
+
+ /*
+ * All other work triggered by hotplug events should be canceled by
+ * now.
+ */
+ if (cancel_all_detection_work(dev_priv))
+ drm_dbg_kms(&dev_priv->drm, "Hotplug detection work still active\n");
}
bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
@@ -873,6 +944,62 @@ void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
spin_unlock_irq(&dev_priv->irq_lock);
}
+static void queue_work_for_missed_irqs(struct drm_i915_private *i915)
+{
+ bool queue_work = false;
+ enum hpd_pin pin;
+
+ lockdep_assert_held(&i915->irq_lock);
+
+ if (i915->display.hotplug.event_bits ||
+ i915->display.hotplug.retry_bits)
+ queue_work = true;
+
+ for_each_hpd_pin(pin) {
+ switch (i915->display.hotplug.stats[pin].state) {
+ case HPD_MARK_DISABLED:
+ queue_work = true;
+ break;
+ case HPD_ENABLED:
+ break;
+ default:
+ MISSING_CASE(i915->display.hotplug.stats[pin].state);
+ }
+ }
+
+ if (queue_work)
+ queue_delayed_detection_work(i915, &i915->display.hotplug.hotplug_work, 0);
+}
+
+void intel_hpd_enable_detection_work(struct drm_i915_private *i915)
+{
+ spin_lock_irq(&i915->irq_lock);
+ i915->display.hotplug.detection_work_enabled = true;
+ queue_work_for_missed_irqs(i915);
+ spin_unlock_irq(&i915->irq_lock);
+}
+
+void intel_hpd_disable_detection_work(struct drm_i915_private *i915)
+{
+ spin_lock_irq(&i915->irq_lock);
+ i915->display.hotplug.detection_work_enabled = false;
+ spin_unlock_irq(&i915->irq_lock);
+
+ cancel_all_detection_work(i915);
+}
+
+bool intel_hpd_schedule_detection(struct drm_i915_private *i915)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&i915->irq_lock, flags);
+ ret = queue_delayed_detection_work(i915, &i915->display.hotplug.hotplug_work, 0);
+ spin_unlock_irqrestore(&i915->irq_lock, flags);
+
+ return ret;
+}
+
static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h
index 424ae5dbf5..a17253ddec 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.h
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.h
@@ -30,4 +30,8 @@ bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
void intel_hpd_debugfs_register(struct drm_i915_private *i915);
+void intel_hpd_enable_detection_work(struct drm_i915_private *i915);
+void intel_hpd_disable_detection_work(struct drm_i915_private *i915);
+bool intel_hpd_schedule_detection(struct drm_i915_private *i915);
+
#endif /* __INTEL_HOTPLUG_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
index 04f62f27ad..76076509f7 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
@@ -163,12 +163,10 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
(!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv)))
return;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_LNL)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL)
hpd->pch_hpd = hpd_mtp;
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
hpd->pch_hpd = hpd_sde_dg1;
- else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP)
- hpd->pch_hpd = hpd_mtp;
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
hpd->pch_hpd = hpd_icp;
else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
@@ -1139,7 +1137,7 @@ static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915)
if (INTEL_PCH_TYPE(i915) >= PCH_LNL)
xe2lpd_sde_hpd_irq_setup(i915);
- else if (INTEL_PCH_TYPE(i915) >= PCH_MTP)
+ else if (INTEL_PCH_TYPE(i915) >= PCH_MTL)
mtp_hpd_irq_setup(i915);
}
diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c
index 9c6d35a405..dfd7d5e23f 100644
--- a/drivers/gpu/drm/i915/display/intel_link_bw.c
+++ b/drivers/gpu/drm/i915/display/intel_link_bw.c
@@ -6,26 +6,41 @@
#include "i915_drv.h"
#include "intel_atomic.h"
+#include "intel_crtc.h"
#include "intel_display_types.h"
#include "intel_dp_mst.h"
+#include "intel_dp_tunnel.h"
#include "intel_fdi.h"
#include "intel_link_bw.h"
/**
* intel_link_bw_init_limits - initialize BW limits
- * @i915: device instance
+ * @state: Atomic state
* @limits: link BW limits
*
* Initialize @limits.
*/
-void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_bw_limits *limits)
+void intel_link_bw_init_limits(struct intel_atomic_state *state,
+ struct intel_link_bw_limits *limits)
{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
enum pipe pipe;
limits->force_fec_pipes = 0;
limits->bpp_limit_reached_pipes = 0;
- for_each_pipe(i915, pipe)
- limits->max_bpp_x16[pipe] = INT_MAX;
+ for_each_pipe(i915, pipe) {
+ const struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state,
+ intel_crtc_for_pipe(i915, pipe));
+
+ if (state->base.duplicated && crtc_state) {
+ limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;
+ if (crtc_state->fec_enable)
+ limits->force_fec_pipes |= BIT(pipe);
+ } else {
+ limits->max_bpp_x16[pipe] = INT_MAX;
+ }
+ }
}
/**
@@ -149,6 +164,10 @@ static int check_all_link_config(struct intel_atomic_state *state,
if (ret)
return ret;
+ ret = intel_dp_tunnel_atomic_check_link(state, limits);
+ if (ret)
+ return ret;
+
ret = intel_fdi_atomic_check_link(state, limits);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h
index 2cf57307cc..6b0ccfff59 100644
--- a/drivers/gpu/drm/i915/display/intel_link_bw.h
+++ b/drivers/gpu/drm/i915/display/intel_link_bw.h
@@ -22,7 +22,7 @@ struct intel_link_bw_limits {
int max_bpp_x16[I915_MAX_PIPES];
};
-void intel_link_bw_init_limits(struct drm_i915_private *i915,
+void intel_link_bw_init_limits(struct intel_atomic_state *state,
struct intel_link_bw_limits *limits);
int intel_link_bw_reduce_bpp(struct intel_atomic_state *state,
struct intel_link_bw_limits *limits,
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
index 1ce785db6a..fcbb083318 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -250,11 +250,36 @@ struct opregion_asle_ext {
#define MAX_DSLP 1500
+#define OPREGION_SIZE (8 * 1024)
+
+struct intel_opregion {
+ struct drm_i915_private *i915;
+
+ struct opregion_header *header;
+ struct opregion_acpi *acpi;
+ struct opregion_swsci *swsci;
+ u32 swsci_gbda_sub_functions;
+ u32 swsci_sbcb_sub_functions;
+ struct opregion_asle *asle;
+ struct opregion_asle_ext *asle_ext;
+ void *rvda;
+ void *vbt_firmware;
+ const void *vbt;
+ u32 vbt_size;
+ struct work_struct asle_work;
+ struct notifier_block acpi_notifier;
+};
+
static int check_swsci_function(struct drm_i915_private *i915, u32 function)
{
- struct opregion_swsci *swsci = i915->display.opregion.swsci;
+ struct intel_opregion *opregion = i915->display.opregion;
+ struct opregion_swsci *swsci;
u32 main_function, sub_function;
+ if (!opregion)
+ return -ENODEV;
+
+ swsci = opregion->swsci;
if (!swsci)
return -ENODEV;
@@ -265,11 +290,11 @@ static int check_swsci_function(struct drm_i915_private *i915, u32 function)
/* Check if we can call the function. See swsci_setup for details. */
if (main_function == SWSCI_SBCB) {
- if ((i915->display.opregion.swsci_sbcb_sub_functions &
+ if ((opregion->swsci_sbcb_sub_functions &
(1 << sub_function)) == 0)
return -EINVAL;
} else if (main_function == SWSCI_GBDA) {
- if ((i915->display.opregion.swsci_gbda_sub_functions &
+ if ((opregion->swsci_gbda_sub_functions &
(1 << sub_function)) == 0)
return -EINVAL;
}
@@ -280,7 +305,7 @@ static int check_swsci_function(struct drm_i915_private *i915, u32 function)
static int swsci(struct drm_i915_private *dev_priv,
u32 function, u32 parm, u32 *parm_out)
{
- struct opregion_swsci *swsci = dev_priv->display.opregion.swsci;
+ struct opregion_swsci *swsci;
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
u32 scic, dslp;
u16 swsci_val;
@@ -290,6 +315,8 @@ static int swsci(struct drm_i915_private *dev_priv,
if (ret)
return ret;
+ swsci = dev_priv->display.opregion->swsci;
+
/* Driver sleep timeout in ms. */
dslp = swsci->dslp;
if (!dslp) {
@@ -462,7 +489,7 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp)
{
struct intel_connector *connector;
struct drm_connector_list_iter conn_iter;
- struct opregion_asle *asle = dev_priv->display.opregion.asle;
+ struct opregion_asle *asle = dev_priv->display.opregion->asle;
drm_dbg(&dev_priv->drm, "bclp = 0x%08x\n", bclp);
@@ -584,9 +611,8 @@ static void asle_work(struct work_struct *work)
{
struct intel_opregion *opregion =
container_of(work, struct intel_opregion, asle_work);
- struct drm_i915_private *dev_priv =
- container_of(opregion, struct drm_i915_private, display.opregion);
- struct opregion_asle *asle = dev_priv->display.opregion.asle;
+ struct drm_i915_private *dev_priv = opregion->i915;
+ struct opregion_asle *asle = opregion->asle;
u32 aslc_stat = 0;
u32 aslc_req;
@@ -632,11 +658,17 @@ static void asle_work(struct work_struct *work)
asle->aslc = aslc_stat;
}
-void intel_opregion_asle_intr(struct drm_i915_private *dev_priv)
+bool intel_opregion_asle_present(struct drm_i915_private *i915)
+{
+ return i915->display.opregion && i915->display.opregion->asle;
+}
+
+void intel_opregion_asle_intr(struct drm_i915_private *i915)
{
- if (dev_priv->display.opregion.asle)
- queue_work(dev_priv->unordered_wq,
- &dev_priv->display.opregion.asle_work);
+ struct intel_opregion *opregion = i915->display.opregion;
+
+ if (opregion && opregion->asle)
+ queue_work(i915->unordered_wq, &opregion->asle_work);
}
#define ACPI_EV_DISPLAY_SWITCH (1<<0)
@@ -692,7 +724,7 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val)
static void intel_didl_outputs(struct drm_i915_private *dev_priv)
{
- struct intel_opregion *opregion = &dev_priv->display.opregion;
+ struct intel_opregion *opregion = dev_priv->display.opregion;
struct intel_connector *connector;
struct drm_connector_list_iter conn_iter;
int i = 0, max_outputs;
@@ -731,7 +763,7 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv)
static void intel_setup_cadls(struct drm_i915_private *dev_priv)
{
- struct intel_opregion *opregion = &dev_priv->display.opregion;
+ struct intel_opregion *opregion = dev_priv->display.opregion;
struct intel_connector *connector;
struct drm_connector_list_iter conn_iter;
int i = 0;
@@ -761,7 +793,7 @@ static void intel_setup_cadls(struct drm_i915_private *dev_priv)
static void swsci_setup(struct drm_i915_private *dev_priv)
{
- struct intel_opregion *opregion = &dev_priv->display.opregion;
+ struct intel_opregion *opregion = dev_priv->display.opregion;
bool requested_callbacks = false;
u32 tmp;
@@ -839,7 +871,7 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = {
static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
{
- struct intel_opregion *opregion = &dev_priv->display.opregion;
+ struct intel_opregion *opregion = dev_priv->display.opregion;
const struct firmware *fw = NULL;
const char *name = dev_priv->display.params.vbt_firmware;
int ret;
@@ -855,7 +887,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
return ret;
}
- if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
+ if (intel_bios_is_valid_vbt(dev_priv, fw->data, fw->size)) {
opregion->vbt_firmware = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (opregion->vbt_firmware) {
drm_dbg_kms(&dev_priv->drm,
@@ -879,7 +911,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
int intel_opregion_setup(struct drm_i915_private *dev_priv)
{
- struct intel_opregion *opregion = &dev_priv->display.opregion;
+ struct intel_opregion *opregion;
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
u32 asls, mboxes;
char buf[sizeof(OPREGION_SIGNATURE)];
@@ -902,11 +934,20 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
return -ENOTSUPP;
}
+ opregion = kzalloc(sizeof(*opregion), GFP_KERNEL);
+ if (!opregion)
+ return -ENOMEM;
+
+ opregion->i915 = dev_priv;
+ dev_priv->display.opregion = opregion;
+
INIT_WORK(&opregion->asle_work, asle_work);
base = memremap(asls, OPREGION_SIZE, MEMREMAP_WB);
- if (!base)
- return -ENOMEM;
+ if (!base) {
+ err = -ENOMEM;
+ goto err_memremap;
+ }
memcpy(buf, base, sizeof(buf));
@@ -916,7 +957,6 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
goto err_out;
}
opregion->header = base;
- opregion->lid_state = base + ACPI_CLID;
drm_dbg(&dev_priv->drm, "ACPI OpRegion version %u.%u.%u\n",
opregion->header->over.major,
@@ -994,7 +1034,7 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
vbt = opregion->rvda;
vbt_size = opregion->asle->rvds;
- if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
+ if (intel_bios_is_valid_vbt(dev_priv, vbt, vbt_size)) {
drm_dbg_kms(&dev_priv->drm,
"Found valid VBT in ACPI OpRegion (RVDA)\n");
opregion->vbt = vbt;
@@ -1019,7 +1059,7 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
vbt_size = (mboxes & MBOX_ASLE_EXT) ?
OPREGION_ASLE_EXT_OFFSET : OPREGION_SIZE;
vbt_size -= OPREGION_VBT_OFFSET;
- if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
+ if (intel_bios_is_valid_vbt(dev_priv, vbt, vbt_size)) {
drm_dbg_kms(&dev_priv->drm,
"Found valid VBT in ACPI OpRegion (Mailbox #4)\n");
opregion->vbt = vbt;
@@ -1034,6 +1074,10 @@ out:
err_out:
memunmap(base);
+err_memremap:
+ kfree(opregion);
+ dev_priv->display.opregion = NULL;
+
return err;
}
@@ -1106,12 +1150,12 @@ const struct drm_edid *intel_opregion_get_edid(struct intel_connector *intel_con
{
struct drm_connector *connector = &intel_connector->base;
struct drm_i915_private *i915 = to_i915(connector->dev);
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
const struct drm_edid *drm_edid;
const void *edid;
int len;
- if (!opregion->asle_ext)
+ if (!opregion || !opregion->asle_ext)
return NULL;
edid = opregion->asle_ext->bddc;
@@ -1132,10 +1176,28 @@ const struct drm_edid *intel_opregion_get_edid(struct intel_connector *intel_con
return drm_edid;
}
+const void *intel_opregion_get_vbt(struct drm_i915_private *i915, size_t *size)
+{
+ struct intel_opregion *opregion = i915->display.opregion;
+
+ if (!opregion || !opregion->vbt)
+ return NULL;
+
+ if (size)
+ *size = opregion->vbt_size;
+
+ return opregion->vbt;
+}
+
bool intel_opregion_headless_sku(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
- struct opregion_header *header = opregion->header;
+ struct intel_opregion *opregion = i915->display.opregion;
+ struct opregion_header *header;
+
+ if (!opregion)
+ return false;
+
+ header = opregion->header;
if (!header || header->over.major < 2 ||
(header->over.major == 2 && header->over.minor < 3))
@@ -1146,9 +1208,9 @@ bool intel_opregion_headless_sku(struct drm_i915_private *i915)
void intel_opregion_register(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
- if (!opregion->header)
+ if (!opregion)
return;
if (opregion->acpi) {
@@ -1162,7 +1224,7 @@ void intel_opregion_register(struct drm_i915_private *i915)
static void intel_opregion_resume_display(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
if (opregion->acpi) {
intel_didl_outputs(i915);
@@ -1188,9 +1250,9 @@ static void intel_opregion_resume_display(struct drm_i915_private *i915)
void intel_opregion_resume(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
- if (!opregion->header)
+ if (!opregion)
return;
if (HAS_DISPLAY(i915))
@@ -1201,12 +1263,12 @@ void intel_opregion_resume(struct drm_i915_private *i915)
static void intel_opregion_suspend_display(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
if (opregion->asle)
opregion->asle->ardy = ASLE_ARDY_NOT_READY;
- cancel_work_sync(&i915->display.opregion.asle_work);
+ cancel_work_sync(&opregion->asle_work);
if (opregion->acpi)
opregion->acpi->drdy = 0;
@@ -1214,9 +1276,9 @@ static void intel_opregion_suspend_display(struct drm_i915_private *i915)
void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
- if (!opregion->header)
+ if (!opregion)
return;
intel_opregion_notify_adapter(i915, state);
@@ -1227,11 +1289,11 @@ void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state)
void intel_opregion_unregister(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
intel_opregion_suspend(i915, PCI_D1);
- if (!opregion->header)
+ if (!opregion)
return;
if (opregion->acpi_notifier.notifier_call) {
@@ -1242,26 +1304,36 @@ void intel_opregion_unregister(struct drm_i915_private *i915)
void intel_opregion_cleanup(struct drm_i915_private *i915)
{
- struct intel_opregion *opregion = &i915->display.opregion;
+ struct intel_opregion *opregion = i915->display.opregion;
- if (!opregion->header)
+ if (!opregion)
return;
- /* just clear all opregion memory pointers now */
memunmap(opregion->header);
- if (opregion->rvda) {
+ if (opregion->rvda)
memunmap(opregion->rvda);
- opregion->rvda = NULL;
- }
- if (opregion->vbt_firmware) {
- kfree(opregion->vbt_firmware);
- opregion->vbt_firmware = NULL;
- }
- opregion->header = NULL;
- opregion->acpi = NULL;
- opregion->swsci = NULL;
- opregion->asle = NULL;
- opregion->asle_ext = NULL;
- opregion->vbt = NULL;
- opregion->lid_state = NULL;
+ kfree(opregion->vbt_firmware);
+ kfree(opregion);
+ i915->display.opregion = NULL;
+}
+
+static int intel_opregion_show(struct seq_file *m, void *unused)
+{
+ struct drm_i915_private *i915 = m->private;
+ struct intel_opregion *opregion = i915->display.opregion;
+
+ if (opregion)
+ seq_write(m, opregion->header, OPREGION_SIZE);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(intel_opregion);
+
+void intel_opregion_debugfs_register(struct drm_i915_private *i915)
+{
+ struct drm_minor *minor = i915->drm.primary;
+
+ debugfs_create_file("i915_opregion", 0444, minor->debugfs_root,
+ i915, &intel_opregion_fops);
}
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.h b/drivers/gpu/drm/i915/display/intel_opregion.h
index fd2ea8ef0f..0bec224f71 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.h
+++ b/drivers/gpu/drm/i915/display/intel_opregion.h
@@ -25,38 +25,13 @@
#ifndef _INTEL_OPREGION_H_
#define _INTEL_OPREGION_H_
-#include <linux/workqueue.h>
#include <linux/pci.h>
+#include <linux/types.h>
struct drm_i915_private;
struct intel_connector;
struct intel_encoder;
-struct opregion_header;
-struct opregion_acpi;
-struct opregion_swsci;
-struct opregion_asle;
-struct opregion_asle_ext;
-
-struct intel_opregion {
- struct opregion_header *header;
- struct opregion_acpi *acpi;
- struct opregion_swsci *swsci;
- u32 swsci_gbda_sub_functions;
- u32 swsci_sbcb_sub_functions;
- struct opregion_asle *asle;
- struct opregion_asle_ext *asle_ext;
- void *rvda;
- void *vbt_firmware;
- const void *vbt;
- u32 vbt_size;
- u32 *lid_state;
- struct work_struct asle_work;
- struct notifier_block acpi_notifier;
-};
-
-#define OPREGION_SIZE (8 * 1024)
-
#ifdef CONFIG_ACPI
int intel_opregion_setup(struct drm_i915_private *dev_priv);
@@ -69,6 +44,7 @@ void intel_opregion_resume(struct drm_i915_private *dev_priv);
void intel_opregion_suspend(struct drm_i915_private *dev_priv,
pci_power_t state);
+bool intel_opregion_asle_present(struct drm_i915_private *i915);
void intel_opregion_asle_intr(struct drm_i915_private *dev_priv);
int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
bool enable);
@@ -77,8 +53,12 @@ int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv,
int intel_opregion_get_panel_type(struct drm_i915_private *dev_priv);
const struct drm_edid *intel_opregion_get_edid(struct intel_connector *connector);
+const void *intel_opregion_get_vbt(struct drm_i915_private *i915, size_t *size);
+
bool intel_opregion_headless_sku(struct drm_i915_private *i915);
+void intel_opregion_debugfs_register(struct drm_i915_private *i915);
+
#else /* CONFIG_ACPI*/
static inline int intel_opregion_setup(struct drm_i915_private *dev_priv)
@@ -107,6 +87,11 @@ static inline void intel_opregion_suspend(struct drm_i915_private *dev_priv,
{
}
+static inline bool intel_opregion_asle_present(struct drm_i915_private *i915)
+{
+ return false;
+}
+
static inline void intel_opregion_asle_intr(struct drm_i915_private *dev_priv)
{
}
@@ -134,11 +119,21 @@ intel_opregion_get_edid(struct intel_connector *connector)
return NULL;
}
+static inline const void *
+intel_opregion_get_vbt(struct drm_i915_private *i915, size_t *size)
+{
+ return NULL;
+}
+
static inline bool intel_opregion_headless_sku(struct drm_i915_private *i915)
{
return false;
}
+static inline void intel_opregion_debugfs_register(struct drm_i915_private *i915)
+{
+}
+
#endif /* CONFIG_ACPI */
#endif
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 0d8e5320a4..073ea3166c 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -37,6 +37,7 @@
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_drrs.h"
#include "intel_lvds_regs.h"
@@ -683,6 +684,9 @@ intel_panel_detect(struct drm_connector *connector, bool force)
if (!intel_display_device_enabled(i915))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(i915))
+ return connector->status;
+
return connector_status_connected;
}
diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c
index a55c09cbd0..ada1792df5 100644
--- a/drivers/gpu/drm/i915/display/intel_plane_initial.c
+++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c
@@ -3,9 +3,11 @@
* Copyright © 2021 Intel Corporation
*/
+#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
#include "i915_drv.h"
#include "intel_atomic_plane.h"
+#include "intel_crtc.h"
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_fb.h"
@@ -13,20 +15,21 @@
#include "intel_plane_initial.h"
static bool
-intel_reuse_initial_plane_obj(struct drm_i915_private *i915,
- const struct intel_initial_plane_config *plane_config,
+intel_reuse_initial_plane_obj(struct intel_crtc *this,
+ const struct intel_initial_plane_config plane_configs[],
struct drm_framebuffer **fb,
struct i915_vma **vma)
{
+ struct drm_i915_private *i915 = to_i915(this->base.dev);
struct intel_crtc *crtc;
for_each_intel_crtc(&i915->drm, crtc) {
- struct intel_crtc_state *crtc_state =
- to_intel_crtc_state(crtc->base.state);
struct intel_plane *plane =
to_intel_plane(crtc->base.primary);
- struct intel_plane_state *plane_state =
+ const struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
if (!crtc_state->uapi.active)
continue;
@@ -34,7 +37,7 @@ intel_reuse_initial_plane_obj(struct drm_i915_private *i915,
if (!plane_state->ggtt_vma)
continue;
- if (intel_plane_ggtt_offset(plane_state) == plane_config->base) {
+ if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base) {
*fb = plane_state->hw.fb;
*vma = plane_state->ggtt_vma;
return true;
@@ -44,12 +47,100 @@ intel_reuse_initial_plane_obj(struct drm_i915_private *i915,
return false;
}
+static bool
+initial_plane_phys_lmem(struct drm_i915_private *i915,
+ struct intel_initial_plane_config *plane_config)
+{
+ gen8_pte_t __iomem *gte = to_gt(i915)->ggtt->gsm;
+ struct intel_memory_region *mem;
+ dma_addr_t dma_addr;
+ gen8_pte_t pte;
+ u32 base;
+
+ base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
+
+ gte += base / I915_GTT_PAGE_SIZE;
+
+ pte = ioread64(gte);
+ if (!(pte & GEN12_GGTT_PTE_LM)) {
+ drm_err(&i915->drm,
+ "Initial plane programming missing PTE_LM bit\n");
+ return false;
+ }
+
+ dma_addr = pte & GEN12_GGTT_PTE_ADDR_MASK;
+
+ if (IS_DGFX(i915))
+ mem = i915->mm.regions[INTEL_REGION_LMEM_0];
+ else
+ mem = i915->mm.stolen_region;
+ if (!mem) {
+ drm_dbg_kms(&i915->drm,
+ "Initial plane memory region not initialized\n");
+ return false;
+ }
+
+ /*
+ * On lmem we don't currently expect this to
+ * ever be placed in the stolen portion.
+ */
+ if (dma_addr < mem->region.start || dma_addr > mem->region.end) {
+ drm_err(&i915->drm,
+ "Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n",
+ &dma_addr, mem->region.name, &mem->region.start, &mem->region.end);
+ return false;
+ }
+
+ drm_dbg(&i915->drm,
+ "Using dma_addr=%pa, based on initial plane programming\n",
+ &dma_addr);
+
+ plane_config->phys_base = dma_addr - mem->region.start;
+ plane_config->mem = mem;
+
+ return true;
+}
+
+static bool
+initial_plane_phys_smem(struct drm_i915_private *i915,
+ struct intel_initial_plane_config *plane_config)
+{
+ struct intel_memory_region *mem;
+ u32 base;
+
+ base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
+
+ mem = i915->mm.stolen_region;
+ if (!mem) {
+ drm_dbg_kms(&i915->drm,
+ "Initial plane memory region not initialized\n");
+ return false;
+ }
+
+ /* FIXME get and validate the dma_addr from the PTE */
+ plane_config->phys_base = base;
+ plane_config->mem = mem;
+
+ return true;
+}
+
+static bool
+initial_plane_phys(struct drm_i915_private *i915,
+ struct intel_initial_plane_config *plane_config)
+{
+ if (IS_DGFX(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915))
+ return initial_plane_phys_lmem(i915, plane_config);
+ else
+ return initial_plane_phys_smem(i915, plane_config);
+}
+
static struct i915_vma *
initial_plane_vma(struct drm_i915_private *i915,
struct intel_initial_plane_config *plane_config)
{
struct intel_memory_region *mem;
struct drm_i915_gem_object *obj;
+ struct drm_mm_node orig_mm = {};
struct i915_vma *vma;
resource_size_t phys_base;
u32 base, size;
@@ -58,45 +149,13 @@ initial_plane_vma(struct drm_i915_private *i915,
if (plane_config->size == 0)
return NULL;
- base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
- if (IS_DGFX(i915)) {
- gen8_pte_t __iomem *gte = to_gt(i915)->ggtt->gsm;
- gen8_pte_t pte;
-
- gte += base / I915_GTT_PAGE_SIZE;
-
- pte = ioread64(gte);
- if (!(pte & GEN12_GGTT_PTE_LM)) {
- drm_err(&i915->drm,
- "Initial plane programming missing PTE_LM bit\n");
- return NULL;
- }
-
- phys_base = pte & I915_GTT_PAGE_MASK;
- mem = i915->mm.regions[INTEL_REGION_LMEM_0];
-
- /*
- * We don't currently expect this to ever be placed in the
- * stolen portion.
- */
- if (phys_base >= resource_size(&mem->region)) {
- drm_err(&i915->drm,
- "Initial plane programming using invalid range, phys_base=%pa\n",
- &phys_base);
- return NULL;
- }
-
- drm_dbg(&i915->drm,
- "Using phys_base=%pa, based on initial plane programming\n",
- &phys_base);
- } else {
- phys_base = base;
- mem = i915->mm.stolen_region;
- }
-
- if (!mem)
+ if (!initial_plane_phys(i915, plane_config))
return NULL;
+ phys_base = plane_config->phys_base;
+ mem = plane_config->mem;
+
+ base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
size = round_up(plane_config->base + plane_config->size,
mem->min_page_size);
size -= base;
@@ -108,14 +167,19 @@ initial_plane_vma(struct drm_i915_private *i915,
*/
if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
mem == i915->mm.stolen_region &&
- size * 2 > i915->dsm.usable_size)
+ size * 2 > i915->dsm.usable_size) {
+ drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n");
return NULL;
+ }
obj = i915_gem_object_create_region_at(mem, phys_base, size,
I915_BO_ALLOC_USER |
I915_BO_PREALLOC);
- if (IS_ERR(obj))
+ if (IS_ERR(obj)) {
+ drm_dbg_kms(&i915->drm, "Failed to preallocate initial FB in %s\n",
+ mem->region.name);
return NULL;
+ }
/*
* Mark it WT ahead of time to avoid changing the
@@ -139,23 +203,66 @@ initial_plane_vma(struct drm_i915_private *i915,
goto err_obj;
}
+ /*
+ * MTL GOP likes to place the framebuffer high up in ggtt,
+ * which can cause problems for ggtt_reserve_guc_top().
+ * Try to pin it to a low ggtt address instead to avoid that.
+ */
+ base = 0;
+
+ if (base != plane_config->base) {
+ struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
+ int ret;
+
+ /*
+ * Make sure the original and new locations
+ * can't overlap. That would corrupt the original
+ * PTEs which are still being used for scanout.
+ */
+ ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm,
+ size, plane_config->base,
+ I915_COLOR_UNEVICTABLE, PIN_NOEVICT);
+ if (ret)
+ goto err_obj;
+ }
+
vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL);
if (IS_ERR(vma))
goto err_obj;
+retry:
pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base;
- if (HAS_GMCH(i915))
+ if (!i915_gem_object_is_lmem(obj))
pinctl |= PIN_MAPPABLE;
- if (i915_vma_pin(vma, 0, 0, pinctl))
+ if (i915_vma_pin(vma, 0, 0, pinctl)) {
+ if (drm_mm_node_allocated(&orig_mm)) {
+ drm_mm_remove_node(&orig_mm);
+ /*
+ * Try again, but this time pin
+ * it to its original location.
+ */
+ base = plane_config->base;
+ goto retry;
+ }
goto err_obj;
+ }
if (i915_gem_object_is_tiled(obj) &&
!i915_vma_is_map_and_fenceable(vma))
goto err_obj;
+ if (drm_mm_node_allocated(&orig_mm))
+ drm_mm_remove_node(&orig_mm);
+
+ drm_dbg_kms(&i915->drm,
+ "Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n",
+ i915_ggtt_offset(vma), plane_config->base);
+
return vma;
err_obj:
+ if (drm_mm_node_allocated(&orig_mm))
+ drm_mm_remove_node(&orig_mm);
i915_gem_object_put(obj);
return NULL;
}
@@ -210,10 +317,11 @@ err_vma:
static void
intel_find_initial_plane_obj(struct intel_crtc *crtc,
- struct intel_initial_plane_config *plane_config)
+ struct intel_initial_plane_config plane_configs[])
{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_initial_plane_config *plane_config =
+ &plane_configs[crtc->pipe];
struct intel_plane *plane =
to_intel_plane(crtc->base.primary);
struct intel_plane_state *plane_state =
@@ -239,7 +347,7 @@ intel_find_initial_plane_obj(struct intel_crtc *crtc,
* Failed to alloc the obj, check to see if we should share
* an fb with another CRTC instead
*/
- if (intel_reuse_initial_plane_obj(dev_priv, plane_config, &fb, &vma))
+ if (intel_reuse_initial_plane_obj(crtc, plane_configs, &fb, &vma))
goto valid_fb;
/*
@@ -302,25 +410,36 @@ static void plane_config_fini(struct intel_initial_plane_config *plane_config)
i915_vma_put(plane_config->vma);
}
-void intel_crtc_initial_plane_config(struct intel_crtc *crtc)
+void intel_initial_plane_config(struct drm_i915_private *i915)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct intel_initial_plane_config plane_config = {};
+ struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {};
+ struct intel_crtc *crtc;
- /*
- * Note that reserving the BIOS fb up front prevents us
- * from stuffing other stolen allocations like the ring
- * on top. This prevents some ugliness at boot time, and
- * can even allow for smooth boot transitions if the BIOS
- * fb is large enough for the active pipe configuration.
- */
- dev_priv->display.funcs.display->get_initial_plane_config(crtc, &plane_config);
+ for_each_intel_crtc(&i915->drm, crtc) {
+ struct intel_initial_plane_config *plane_config =
+ &plane_configs[crtc->pipe];
- /*
- * If the fb is shared between multiple heads, we'll
- * just get the first one.
- */
- intel_find_initial_plane_obj(crtc, &plane_config);
+ if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
+ continue;
+
+ /*
+ * Note that reserving the BIOS fb up front prevents us
+ * from stuffing other stolen allocations like the ring
+ * on top. This prevents some ugliness at boot time, and
+ * can even allow for smooth boot transitions if the BIOS
+ * fb is large enough for the active pipe configuration.
+ */
+ i915->display.funcs.display->get_initial_plane_config(crtc, plane_config);
- plane_config_fini(&plane_config);
+ /*
+ * If the fb is shared between multiple heads, we'll
+ * just get the first one.
+ */
+ intel_find_initial_plane_obj(crtc, plane_configs);
+
+ if (i915->display.funcs.display->fixup_initial_plane_config(crtc, plane_config))
+ intel_crtc_wait_for_next_vblank(crtc);
+
+ plane_config_fini(plane_config);
+ }
}
diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.h b/drivers/gpu/drm/i915/display/intel_plane_initial.h
index c7e35ab318..64ab95239c 100644
--- a/drivers/gpu/drm/i915/display/intel_plane_initial.h
+++ b/drivers/gpu/drm/i915/display/intel_plane_initial.h
@@ -6,8 +6,8 @@
#ifndef __INTEL_PLANE_INITIAL_H__
#define __INTEL_PLANE_INITIAL_H__
-struct intel_crtc;
+struct drm_i915_private;
-void intel_crtc_initial_plane_config(struct intel_crtc *crtc);
+void intel_initial_plane_config(struct drm_i915_private *i915);
#endif
diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c
index a8fa3a2099..2d65a538f8 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.c
+++ b/drivers/gpu/drm/i915/display/intel_pps.c
@@ -366,7 +366,7 @@ static bool intel_pps_is_valid(struct intel_dp *intel_dp)
if (intel_dp->pps.pps_idx == 1 &&
INTEL_PCH_TYPE(i915) >= PCH_ICP &&
- INTEL_PCH_TYPE(i915) < PCH_MTP)
+ INTEL_PCH_TYPE(i915) <= PCH_ADP)
return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT;
return true;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 925776ba13..aabd018bd7 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -173,6 +173,12 @@
* irrelevant for normal operation.
*/
+#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \
+ (intel_dp)->psr.source_support)
+
+#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \
+ (intel_dp)->psr.source_panel_replay_support)
+
bool intel_encoder_can_psr(struct intel_encoder *encoder)
{
if (intel_encoder_is_dp(encoder) || encoder->type == INTEL_OUTPUT_DP_MST)
@@ -528,7 +534,7 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp)
intel_dp_get_sink_sync_latency(intel_dp);
if (DISPLAY_VER(i915) >= 9 &&
- intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) {
+ intel_dp->psr_dpcd[0] >= DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) {
bool y_req = intel_dp->psr_dpcd[1] &
DP_PSR2_SU_Y_COORDINATE_REQUIRED;
bool alpm = intel_dp_get_alpm_status(intel_dp);
@@ -560,11 +566,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp)
if (intel_dp->psr_dpcd[0])
_psr_init_dpcd(intel_dp);
- if (intel_dp->psr.sink_psr2_support) {
- intel_dp->psr.colorimetry_support =
- intel_dp_get_colorimetry_status(intel_dp);
+ if (intel_dp->psr.sink_psr2_support)
intel_dp_get_su_granularity(intel_dp);
- }
}
static void hsw_psr_setup_aux(struct intel_dp *intel_dp)
@@ -604,6 +607,18 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp)
aux_ctl);
}
+static bool psr2_su_region_et_valid(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+
+ if (DISPLAY_VER(i915) >= 20 &&
+ intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED &&
+ !(intel_dp->psr.debug & I915_PSR_DEBUG_SU_REGION_ET_DISABLE))
+ return true;
+
+ return false;
+}
+
static void intel_psr_enable_sink(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -619,6 +634,8 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp)
DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE);
dpcd_val |= DP_PSR_ENABLE_PSR2 | DP_PSR_IRQ_HPD_WITH_CRC_ERRORS;
+ if (psr2_su_region_et_valid(intel_dp))
+ dpcd_val |= DP_PSR_ENABLE_SU_REGION_ET;
} else {
if (intel_dp->psr.link_standby)
dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE;
@@ -762,8 +779,8 @@ static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp)
static int psr2_block_count_lines(struct intel_dp *intel_dp)
{
- return intel_dp->psr.io_wake_lines < 9 &&
- intel_dp->psr.fast_wake_lines < 9 ? 8 : 12;
+ return intel_dp->psr.alpm_parameters.io_wake_lines < 9 &&
+ intel_dp->psr.alpm_parameters.fast_wake_lines < 9 ? 8 : 12;
}
static int psr2_block_count(struct intel_dp *intel_dp)
@@ -800,6 +817,7 @@ static void dg2_activate_panel_replay(struct intel_dp *intel_dp)
static void hsw_activate_psr2(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_psr *psr = &intel_dp->psr;
enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
u32 val = EDP_PSR2_ENABLE;
u32 psr_val = 0;
@@ -841,17 +859,18 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
*/
int tmp;
- tmp = map[intel_dp->psr.io_wake_lines - TGL_EDP_PSR2_IO_BUFFER_WAKE_MIN_LINES];
+ tmp = map[psr->alpm_parameters.io_wake_lines -
+ TGL_EDP_PSR2_IO_BUFFER_WAKE_MIN_LINES];
val |= TGL_EDP_PSR2_IO_BUFFER_WAKE(tmp + TGL_EDP_PSR2_IO_BUFFER_WAKE_MIN_LINES);
- tmp = map[intel_dp->psr.fast_wake_lines - TGL_EDP_PSR2_FAST_WAKE_MIN_LINES];
+ tmp = map[psr->alpm_parameters.fast_wake_lines - TGL_EDP_PSR2_FAST_WAKE_MIN_LINES];
val |= TGL_EDP_PSR2_FAST_WAKE(tmp + TGL_EDP_PSR2_FAST_WAKE_MIN_LINES);
} else if (DISPLAY_VER(dev_priv) >= 12) {
- val |= TGL_EDP_PSR2_IO_BUFFER_WAKE(intel_dp->psr.io_wake_lines);
- val |= TGL_EDP_PSR2_FAST_WAKE(intel_dp->psr.fast_wake_lines);
+ val |= TGL_EDP_PSR2_IO_BUFFER_WAKE(psr->alpm_parameters.io_wake_lines);
+ val |= TGL_EDP_PSR2_FAST_WAKE(psr->alpm_parameters.fast_wake_lines);
} else if (DISPLAY_VER(dev_priv) >= 9) {
- val |= EDP_PSR2_IO_BUFFER_WAKE(intel_dp->psr.io_wake_lines);
- val |= EDP_PSR2_FAST_WAKE(intel_dp->psr.fast_wake_lines);
+ val |= EDP_PSR2_IO_BUFFER_WAKE(psr->alpm_parameters.io_wake_lines);
+ val |= EDP_PSR2_FAST_WAKE(psr->alpm_parameters.fast_wake_lines);
}
if (intel_dp->psr.req_psr2_sdp_prior_scanline)
@@ -869,6 +888,9 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(cpu_transcoder), 0);
}
+ if (psr2_su_region_et_valid(intel_dp))
+ val |= LNL_EDP_PSR2_SU_REGION_ET_ENABLE;
+
/*
* PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is
* recommending keep this bit unset while PSR2 is enabled.
@@ -1031,6 +1053,9 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp,
return false;
}
+ if (psr2_su_region_et_valid(intel_dp))
+ crtc_state->enable_psr2_su_region_et = true;
+
return crtc_state->enable_psr2_sel_fetch = true;
}
@@ -1101,10 +1126,34 @@ static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_d
return true;
}
-static bool _compute_psr2_wake_times(struct intel_dp *intel_dp,
+static bool _lnl_compute_alpm_params(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ int check_entry_lines;
+
+ if (DISPLAY_VER(i915) < 20)
+ return true;
+
+ /* ALPM Entry Check = 2 + CEILING( 5us /tline ) */
+ check_entry_lines = 2 +
+ intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, 5);
+
+ if (check_entry_lines > 15)
+ return false;
+
+ if (i915->display.params.psr_safest_params)
+ check_entry_lines = 15;
+
+ intel_dp->psr.alpm_parameters.check_entry_lines = check_entry_lines;
+
+ return true;
+}
+
+static bool _compute_alpm_params(struct intel_dp *intel_dp,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int io_wake_lines, io_wake_time, fast_wake_lines, fast_wake_time;
u8 max_wake_lines;
@@ -1115,6 +1164,8 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp,
* it is not enough -> use 45 us.
*/
fast_wake_time = 45;
+
+ /* TODO: Check how we can use ALPM_CTL fast wake extended field */
max_wake_lines = 12;
} else {
io_wake_time = 50;
@@ -1131,12 +1182,15 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp,
fast_wake_lines > max_wake_lines)
return false;
+ if (!_lnl_compute_alpm_params(intel_dp, crtc_state))
+ return false;
+
if (i915->display.params.psr_safest_params)
io_wake_lines = fast_wake_lines = max_wake_lines;
/* According to Bspec lower limit should be set as 7 lines. */
- intel_dp->psr.io_wake_lines = max(io_wake_lines, 7);
- intel_dp->psr.fast_wake_lines = max(fast_wake_lines, 7);
+ intel_dp->psr.alpm_parameters.io_wake_lines = max(io_wake_lines, 7);
+ intel_dp->psr.alpm_parameters.fast_wake_lines = max(fast_wake_lines, 7);
return true;
}
@@ -1268,7 +1322,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
return false;
}
- if (!_compute_psr2_wake_times(intel_dp, crtc_state)) {
+ if (!_compute_alpm_params(intel_dp, crtc_state)) {
drm_dbg_kms(&dev_priv->drm,
"PSR2 not enabled, Unable to use long enough wake times\n");
return false;
@@ -1388,10 +1442,6 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
return;
crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
-
- crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC);
- intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
- &crtc_state->psr_vsc);
}
void intel_psr_get_config(struct intel_encoder *encoder,
@@ -1515,6 +1565,21 @@ static void wm_optimization_wa(struct intel_dp *intel_dp,
wa_16013835468_bit_get(intel_dp), 0);
}
+static void lnl_alpm_configure(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
+ struct intel_psr *psr = &intel_dp->psr;
+
+ if (DISPLAY_VER(dev_priv) < 20)
+ return;
+
+ intel_de_write(dev_priv, ALPM_CTL(cpu_transcoder),
+ ALPM_CTL_EXTENDED_FAST_WAKE_ENABLE |
+ ALPM_CTL_ALPM_ENTRY_CHECK(psr->alpm_parameters.check_entry_lines) |
+ ALPM_CTL_EXTENDED_FAST_WAKE_TIME(psr->alpm_parameters.fast_wake_lines));
+}
+
static void intel_psr_enable_source(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
@@ -1580,6 +1645,8 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
intel_dp->psr.psr2_sel_fetch_enabled ?
IGNORE_PSR2_HW_TRACKING : 0);
+ lnl_alpm_configure(intel_dp);
+
/*
* Wa_16013835468
* Wa_14015648006
@@ -1645,7 +1712,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
- struct intel_encoder *encoder = &dig_port->base;
u32 val;
drm_WARN_ON(&dev_priv->drm, intel_dp->psr.enabled);
@@ -1673,7 +1739,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n",
intel_dp->psr.psr2_enabled ? "2" : "1");
- intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc);
intel_snps_phy_update_psr_power_state(dev_priv, phy, true);
intel_psr_enable_sink(intel_dp);
intel_psr_enable_source(intel_dp, crtc_state);
@@ -1940,6 +2005,7 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state)
{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
struct intel_encoder *encoder;
@@ -1959,10 +2025,16 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(cpu_transcoder),
crtc_state->psr2_man_track_ctl);
+
+ if (!crtc_state->enable_psr2_su_region_et)
+ return;
+
+ intel_de_write(dev_priv, PIPE_SRCSZ_ERLY_TPT(crtc->pipe),
+ crtc_state->pipe_srcsz_early_tpt);
}
static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
- struct drm_rect *clip, bool full_update)
+ bool full_update)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -1977,22 +2049,40 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
goto exit;
}
- if (clip->y1 == -1)
+ if (crtc_state->psr2_su_area.y1 == -1)
goto exit;
if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) {
- val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1);
- val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 - 1);
+ val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(crtc_state->psr2_su_area.y1);
+ val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(crtc_state->psr2_su_area.y2 - 1);
} else {
- drm_WARN_ON(crtc_state->uapi.crtc->dev, clip->y1 % 4 || clip->y2 % 4);
+ drm_WARN_ON(crtc_state->uapi.crtc->dev,
+ crtc_state->psr2_su_area.y1 % 4 ||
+ crtc_state->psr2_su_area.y2 % 4);
- val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1 / 4 + 1);
- val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 / 4 + 1);
+ val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(
+ crtc_state->psr2_su_area.y1 / 4 + 1);
+ val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(
+ crtc_state->psr2_su_area.y2 / 4 + 1);
}
exit:
crtc_state->psr2_man_track_ctl = val;
}
+static u32 psr2_pipe_srcsz_early_tpt_calc(struct intel_crtc_state *crtc_state,
+ bool full_update)
+{
+ int width, height;
+
+ if (!crtc_state->enable_psr2_su_region_et || full_update)
+ return 0;
+
+ width = drm_rect_width(&crtc_state->psr2_su_area);
+ height = drm_rect_height(&crtc_state->psr2_su_area);
+
+ return PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1);
+}
+
static void clip_area_update(struct drm_rect *overlap_damage_area,
struct drm_rect *damage_area,
struct drm_rect *pipe_src)
@@ -2013,8 +2103,7 @@ static void clip_area_update(struct drm_rect *overlap_damage_area,
overlap_damage_area->y2 = damage_area->y2;
}
-static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *crtc_state,
- struct drm_rect *pipe_clip)
+static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
@@ -2027,9 +2116,47 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c
else
y_alignment = crtc_state->su_y_granularity;
- pipe_clip->y1 -= pipe_clip->y1 % y_alignment;
- if (pipe_clip->y2 % y_alignment)
- pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment;
+ crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment;
+ if (crtc_state->psr2_su_area.y2 % y_alignment)
+ crtc_state->psr2_su_area.y2 = ((crtc_state->psr2_su_area.y2 /
+ y_alignment) + 1) * y_alignment;
+}
+
+/*
+ * When early transport is in use we need to extend SU area to cover
+ * cursor fully when cursor is in SU area.
+ */
+static void
+intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
+ struct intel_plane_state *new_plane_state;
+ struct intel_plane *plane;
+ int i;
+
+ if (!crtc_state->enable_psr2_su_region_et)
+ return;
+
+ for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
+ struct drm_rect inter;
+
+ if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+ continue;
+
+ if (plane->id != PLANE_CURSOR)
+ continue;
+
+ if (!new_plane_state->uapi.visible)
+ continue;
+
+ inter = crtc_state->psr2_su_area;
+ if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst))
+ continue;
+
+ clip_area_update(&crtc_state->psr2_su_area, &new_plane_state->uapi.dst,
+ &crtc_state->pipe_src);
+ }
}
/*
@@ -2072,7 +2199,6 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
- struct drm_rect pipe_clip = { .x1 = 0, .y1 = -1, .x2 = INT_MAX, .y2 = -1 };
struct intel_plane_state *new_plane_state, *old_plane_state;
struct intel_plane *plane;
bool full_update = false;
@@ -2086,6 +2212,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
goto skip_sel_fetch_set_loop;
}
+ crtc_state->psr2_su_area.x1 = 0;
+ crtc_state->psr2_su_area.y1 = -1;
+ crtc_state->psr2_su_area.x2 = INT_MAX;
+ crtc_state->psr2_su_area.y2 = -1;
+
/*
* Calculate minimal selective fetch area of each plane and calculate
* the pipe damaged area.
@@ -2120,14 +2251,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
if (old_plane_state->uapi.visible) {
damaged_area.y1 = old_plane_state->uapi.dst.y1;
damaged_area.y2 = old_plane_state->uapi.dst.y2;
- clip_area_update(&pipe_clip, &damaged_area,
+ clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
&crtc_state->pipe_src);
}
if (new_plane_state->uapi.visible) {
damaged_area.y1 = new_plane_state->uapi.dst.y1;
damaged_area.y2 = new_plane_state->uapi.dst.y2;
- clip_area_update(&pipe_clip, &damaged_area,
+ clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
&crtc_state->pipe_src);
}
continue;
@@ -2135,7 +2266,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
/* If alpha changed mark the whole plane area as damaged */
damaged_area.y1 = new_plane_state->uapi.dst.y1;
damaged_area.y2 = new_plane_state->uapi.dst.y2;
- clip_area_update(&pipe_clip, &damaged_area,
+ clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
&crtc_state->pipe_src);
continue;
}
@@ -2152,7 +2283,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1;
damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1;
- clip_area_update(&pipe_clip, &damaged_area, &crtc_state->pipe_src);
+ clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src);
}
/*
@@ -2161,7 +2292,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
* should identify cases where this happens and fix the area
* calculation for those.
*/
- if (pipe_clip.y1 == -1) {
+ if (crtc_state->psr2_su_area.y1 == -1) {
drm_info_once(&dev_priv->drm,
"Selective fetch area calculation failed in pipe %c\n",
pipe_name(crtc->pipe));
@@ -2175,13 +2306,21 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
if ((IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) ||
IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) &&
crtc_state->splitter.enable)
- pipe_clip.y1 = 0;
+ crtc_state->psr2_su_area.y1 = 0;
ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
if (ret)
return ret;
- intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip);
+ /*
+ * Adjust su area to cover cursor fully as necessary (early
+ * transport). This needs to be done after
+ * drm_atomic_add_affected_planes to ensure visible cursor is added into
+ * affected planes even when cursor is not updated by itself.
+ */
+ intel_psr2_sel_fetch_et_alignment(state, crtc);
+
+ intel_psr2_sel_fetch_pipe_alignment(crtc_state);
/*
* Now that we have the pipe damaged area check if it intersect with
@@ -2196,7 +2335,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
!new_plane_state->uapi.visible)
continue;
- inter = pipe_clip;
+ inter = crtc_state->psr2_su_area;
sel_fetch_area = &new_plane_state->psr2_sel_fetch_area;
if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) {
sel_fetch_area->y1 = -1;
@@ -2241,7 +2380,9 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
}
skip_sel_fetch_set_loop:
- psr2_man_trk_ctl_calc(crtc_state, &pipe_clip, full_update);
+ psr2_man_trk_ctl_calc(crtc_state, full_update);
+ crtc_state->pipe_srcsz_early_tpt =
+ psr2_pipe_srcsz_early_tpt_calc(crtc_state, full_update);
return 0;
}
@@ -2807,6 +2948,9 @@ void intel_psr_init(struct intel_dp *intel_dp)
else
intel_dp->psr.source_support = true;
+ /* Disable early transport for now */
+ intel_dp->psr.debug |= I915_PSR_DEBUG_SU_REGION_ET_DISABLE;
+
/* Set link_standby x link_off defaults */
if (DISPLAY_VER(dev_priv) < 12)
/* For new platforms up to TGL let's respect VBT back again */
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
index 143e0595c0..cde781df84 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -21,12 +21,6 @@ struct intel_encoder;
struct intel_plane;
struct intel_plane_state;
-#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \
- (intel_dp)->psr.source_support)
-
-#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \
- (intel_dp)->psr.source_panel_replay_support)
-
bool intel_encoder_can_psr(struct intel_encoder *encoder);
void intel_psr_init_dpcd(struct intel_dp *intel_dp);
void intel_psr_pre_plane_update(struct intel_atomic_state *state,
diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h
index efe4306b37..8427a736f6 100644
--- a/drivers/gpu/drm/i915/display/intel_psr_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h
@@ -159,6 +159,7 @@
#define TGL_EDP_PSR2_BLOCK_COUNT_MASK REG_BIT(28)
#define TGL_EDP_PSR2_BLOCK_COUNT_NUM_2 REG_FIELD_PREP(TGL_EDP_PSR2_BLOCK_COUNT_MASK, 0)
#define TGL_EDP_PSR2_BLOCK_COUNT_NUM_3 REG_FIELD_PREP(TGL_EDP_PSR2_BLOCK_COUNT_MASK, 1)
+#define LNL_EDP_PSR2_SU_REGION_ET_ENABLE REG_BIT(27)
#define EDP_Y_COORDINATE_ENABLE REG_BIT(25) /* display 10, 11 and 12 */
#define EDP_PSR2_SU_SDP_SCANLINE REG_BIT(25) /* display 13+ */
#define EDP_MAX_SU_DISABLE_TIME_MASK REG_GENMASK(24, 20)
@@ -245,6 +246,11 @@
#define ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME REG_BIT(14)
#define ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME REG_BIT(13)
+/* PSR2 Early transport */
+#define _PIPE_SRCSZ_ERLY_TPT_A 0x70074
+
+#define PIPE_SRCSZ_ERLY_TPT(trans) _MMIO_TRANS2(trans, _PIPE_SRCSZ_ERLY_TPT_A)
+
#define _SEL_FETCH_PLANE_BASE_1_A 0x70890
#define _SEL_FETCH_PLANE_BASE_2_A 0x708B0
#define _SEL_FETCH_PLANE_BASE_3_A 0x708D0
@@ -290,4 +296,61 @@
_SEL_FETCH_PLANE_OFFSET_1_A - \
_SEL_FETCH_PLANE_BASE_1_A)
+#define _ALPM_CTL_A 0x60950
+#define ALPM_CTL(tran) _MMIO_TRANS2(tran, _ALPM_CTL_A)
+#define ALPM_CTL_ALPM_ENABLE REG_BIT(31)
+#define ALPM_CTL_ALPM_AUX_LESS_ENABLE REG_BIT(30)
+#define ALPM_CTL_LOBF_ENABLE REG_BIT(29)
+#define ALPM_CTL_EXTENDED_FAST_WAKE_ENABLE REG_BIT(28)
+#define ALPM_CTL_KEEP_FEC_ENABLE_FOR_AUX_WAKE_SLEEP REG_BIT(27)
+#define ALPM_CTL_RESTORE_OCCURED REG_BIT(26)
+#define ALPM_CTL_RESTORE_TO_SLEEP REG_BIT(25)
+#define ALPM_CTL_RESTORE_TO_DEEP_SLEEP REG_BIT(24)
+#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK REG_GENMASK(23, 21)
+#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_50_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 0)
+#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_128_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 1)
+#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_256_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 2)
+#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_512_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 3)
+#define ALPM_CTL_AUX_WAKE_SLEEP_HOLD_ENABLE REG_BIT(20)
+#define ALPM_CTL_ALPM_ENTRY_CHECK_MASK REG_GENMASK(19, 16)
+#define ALPM_CTL_ALPM_ENTRY_CHECK(val) REG_FIELD_PREP(ALPM_CTL_ALPM_ENTRY_CHECK_MASK, val)
+#define ALPM_CTL_EXTENDED_FAST_WAKE_TIME_MASK REG_GENMASK(13, 8)
+#define ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES 5
+#define ALPM_CTL_EXTENDED_FAST_WAKE_TIME(lines) REG_FIELD_PREP(ALPM_CTL_EXTENDED_FAST_WAKE_TIME_MASK, (lines) - ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES)
+#define ALPM_CTL_AUX_LESS_WAKE_TIME_MASK REG_GENMASK(5, 0)
+#define ALPM_CTL_AUX_LESS_WAKE_TIME(val) REG_FIELD_PREP(ALPM_CTL_AUX_LESS_WAKE_TIME_MASK, val)
+
+#define _ALPM_CTL2_A 0x60954
+#define ALPM_CTL2(tran) _MMIO_TRANS2(tran, _ALPM_CTL2_A)
+#define ALPM_CTL2_SWITCH_TO_ACTIVE_LATENCY_MASK REG_GENMASK(28, 24)
+#define ALPM_CTL2_SWITCH_TO_ACTIVE_LATENCY(val) REG_FIELD_PREP(ALPM_CTL2_SWITCH_TO_ACTIVE_LATENCY_MASK, val)
+#define ALPM_CTL2_AUX_LESS_WAKE_TIME_EXTENSION_MASK REG_GENMASK(19, 16)
+#define ALPM_CTL2_AUX_LESS_WAKE_TIME_EXTENSION(val) REG_FIELD_PREP(ALPM_CTL2_AUX_LESS_WAKE_TIME_EXTENSION_MASK, val)
+#define ALPM_CTL2_NUMBER_OF_LTTPR_MASK REG_GENMASK(15, 12)
+#define ALPM_CTL2_NUMBER_OF_LTTPR(val) REG_FIELD_PREP(ALPM_CTL2_NUMBER_OF_LTTPR_MASK, val)
+#define ALPM_CTL2_LTTPR_AUX_LESS_SLEEP_HOLD_TIME_MASK REG_GENMASK(10, 8)
+#define ALPM_CTL2_LTTPR_AUX_LESS_SLEEP_HOLD_TIME(val) REG_FIELD_PREP(ALPM_CTL2_LTTPR_AUX_LESS_SLEEP_HOLD_TIME_MASK, val)
+#define ALPM_CTL2_FEC_DECODE_EN_POSITION_AFTER_WAKE_SR REG_BIT(4)
+#define ALPM_CTL2_NUMBER_AUX_LESS_ML_PHY_SLEEP_SEQUENCES_MASK REG_GENMASK(2, 0)
+#define ALPM_CTL2_NUMBER_AUX_LESS_ML_PHY_SLEEP_SEQUENCES(val) REG_FIELD_PREP(ALPM_CTL2_NUMBER_AUX_LESS_ML_PHY_SLEEP_SEQUENCES_MASK, val)
+
+#define _PORT_ALPM_CTL_A 0x16fa2c
+#define PORT_ALPM_CTL(tran) _MMIO_TRANS2(tran, _PORT_ALPM_CTL_A)
+#define PORT_ALPM_CTL_ALPM_AUX_LESS_ENABLE REG_BIT(31)
+#define PORT_ALPM_CTL_MAX_PHY_SWING_SETUP_MASK REG_GENMASK(23, 20)
+#define PORT_ALPM_CTL_MAX_PHY_SWING_SETUP(val) REG_FIELD_PREP(PORT_ALPM_CTL_MAX_PHY_SWING_SETUP_MASK, val)
+#define PORT_ALPM_CTL_MAX_PHY_SWING_HOLD_MASK REG_GENMASK(19, 16)
+#define PORT_ALPM_CTL_MAX_PHY_SWING_HOLD(val) REG_FIELD_PREP(PORT_ALPM_CTL_MAX_PHY_SWING_HOLD_MASK, val)
+#define PORT_ALPM_CTL_SILENCE_PERIOD_MASK REG_GENMASK(7, 0)
+#define PORT_ALPM_CTL_SILENCE_PERIOD(val) REG_FIELD_PREP(PORT_ALPM_CTL_SILENCE_PERIOD_MASK, val)
+
+#define _PORT_ALPM_LFPS_CTL_A 0x16fa30
+#define PORT_ALPM_LFPS_CTL(tran) _MMIO_TRANS2(tran, _PORT_ALPM_LFPS_CTL_A)
+#define PORT_ALPM_LFPS_CTL_LFPS_START_POLARITY REG_BIT(31)
+#define PORT_ALPM_LFPS_CTL_LFPS_CYCLE_COUNT_MASK REG_GENMASK(27, 24)
+#define ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES 5
+#define ALPM_CTL_EXTENDED_FAST_WAKE_TIME(lines) REG_FIELD_PREP(ALPM_CTL_EXTENDED_FAST_WAKE_TIME_MASK, (lines) - ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES)
+#define ALPM_CTL_AUX_LESS_WAKE_TIME_MASK REG_GENMASK(5, 0)
+#define ALPM_CTL_AUX_LESS_WAKE_TIME(val) REG_FIELD_PREP(ALPM_CTL_AUX_LESS_WAKE_TIME_MASK, val)
+
#endif /* __INTEL_PSR_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index cc978ee6d1..0cd9c183f6 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -44,6 +44,7 @@
#include "intel_connector.h"
#include "intel_crtc.h"
#include "intel_de.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
@@ -251,6 +252,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
struct i2c_msg msgs[] = {
{
.addr = intel_sdvo->slave_addr,
@@ -270,7 +272,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
return true;
- DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
+ drm_dbg_kms(&i915->drm, "i2c transfer returned %d\n", ret);
return false;
}
@@ -436,7 +438,8 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
drm_WARN_ON(&dev_priv->drm, pos >= sizeof(buffer) - 1);
#undef BUF_PRINT
- DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer);
+ drm_dbg_kms(&dev_priv->drm, "%s: W: %02X %s\n", SDVO_NAME(intel_sdvo),
+ cmd, buffer);
}
static const char * const cmd_status_names[] = {
@@ -461,6 +464,7 @@ static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
const void *args, int args_len,
bool unlocked)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
u8 *buf, status;
struct i2c_msg *msgs;
int i, ret = true;
@@ -510,13 +514,13 @@ static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
else
ret = __i2c_transfer(intel_sdvo->i2c, msgs, i+3);
if (ret < 0) {
- DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+ drm_dbg_kms(&i915->drm, "I2c transfer returned %d\n", ret);
ret = false;
goto out;
}
if (ret != i+3) {
/* failure in I2C transfer */
- DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+ drm_dbg_kms(&i915->drm, "I2c transfer returned %d/%d\n", ret, i+3);
ret = false;
}
@@ -603,12 +607,13 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
drm_WARN_ON(&dev_priv->drm, pos >= sizeof(buffer) - 1);
#undef BUF_PRINT
- DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer);
+ drm_dbg_kms(&dev_priv->drm, "%s: R: %s\n",
+ SDVO_NAME(intel_sdvo), buffer);
return true;
log_fail:
- DRM_DEBUG_KMS("%s: R: ... failed %s\n",
- SDVO_NAME(intel_sdvo), buffer);
+ drm_dbg_kms(&dev_priv->drm, "%s: R: ... failed %s\n",
+ SDVO_NAME(intel_sdvo), buffer);
return false;
}
@@ -757,7 +762,7 @@ static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
}
static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
- struct intel_sdvo_dtd *dtd)
+ struct intel_sdvo_dtd *dtd)
{
return intel_sdvo_set_timing(intel_sdvo,
SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
@@ -925,8 +930,8 @@ static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
BUILD_BUG_ON(sizeof(encode) != 2);
return intel_sdvo_get_value(intel_sdvo,
- SDVO_CMD_GET_SUPP_ENCODE,
- &encode, sizeof(encode));
+ SDVO_CMD_GET_SUPP_ENCODE,
+ &encode, sizeof(encode));
}
static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
@@ -1003,6 +1008,7 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
unsigned int if_index, u8 tx_rate,
const u8 *data, unsigned int length)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
u8 set_buf_index[2] = { if_index, 0 };
u8 hbuf_size, tmp[8];
int i;
@@ -1015,8 +1021,9 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
if (!intel_sdvo_get_hbuf_size(intel_sdvo, &hbuf_size))
return false;
- DRM_DEBUG_KMS("writing sdvo hbuf: %i, length %u, hbuf_size: %i\n",
- if_index, length, hbuf_size);
+ drm_dbg_kms(&i915->drm,
+ "writing sdvo hbuf: %i, length %u, hbuf_size: %i\n",
+ if_index, length, hbuf_size);
if (hbuf_size < length)
return false;
@@ -1041,6 +1048,7 @@ static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
unsigned int if_index,
u8 *data, unsigned int length)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
u8 set_buf_index[2] = { if_index, 0 };
u8 hbuf_size, tx_rate, av_split;
int i;
@@ -1070,8 +1078,9 @@ static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
if (!intel_sdvo_get_hbuf_size(intel_sdvo, &hbuf_size))
return false;
- DRM_DEBUG_KMS("reading sdvo hbuf: %i, length %u, hbuf_size: %i\n",
- if_index, length, hbuf_size);
+ drm_dbg_kms(&i915->drm,
+ "reading sdvo hbuf: %i, length %u, hbuf_size: %i\n",
+ if_index, length, hbuf_size);
hbuf_size = min_t(unsigned int, length, hbuf_size);
@@ -1150,6 +1159,7 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
struct intel_crtc_state *crtc_state)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
ssize_t len;
@@ -1161,7 +1171,7 @@ static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
sdvo_data, sizeof(sdvo_data));
if (len < 0) {
- DRM_DEBUG_KMS("failed to read AVI infoframe\n");
+ drm_dbg_kms(&i915->drm, "failed to read AVI infoframe\n");
return;
} else if (len == 0) {
return;
@@ -1172,13 +1182,14 @@ static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
ret = hdmi_infoframe_unpack(frame, sdvo_data, len);
if (ret) {
- DRM_DEBUG_KMS("Failed to unpack AVI infoframe\n");
+ drm_dbg_kms(&i915->drm, "Failed to unpack AVI infoframe\n");
return;
}
if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
- DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
- frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
+ drm_dbg_kms(&i915->drm,
+ "Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
+ frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
}
static void intel_sdvo_get_eld(struct intel_sdvo *intel_sdvo,
@@ -1347,6 +1358,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
struct intel_sdvo_connector *intel_sdvo_connector =
to_intel_sdvo_connector(conn_state->connector);
@@ -1359,7 +1371,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
return -EINVAL;
}
- DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
+ drm_dbg_kms(&i915->drm, "forcing bpc to 8 for SDVO\n");
/* FIXME: Don't increase pipe_bpp */
pipe_config->pipe_bpp = 8*3;
pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
@@ -1438,7 +1450,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
if (!intel_sdvo_compute_avi_infoframe(intel_sdvo,
pipe_config, conn_state)) {
- DRM_DEBUG_KMS("bad AVI infoframe\n");
+ drm_dbg_kms(&i915->drm, "bad AVI infoframe\n");
return -EINVAL;
}
@@ -1913,8 +1925,8 @@ static void intel_enable_sdvo(struct intel_atomic_state *state,
*/
if (success && !input1) {
drm_dbg_kms(&dev_priv->drm,
- "First %s output reported failure to "
- "sync\n", SDVO_NAME(intel_sdvo));
+ "First %s output reported failure to sync\n",
+ SDVO_NAME(intel_sdvo));
}
if (0)
@@ -1971,37 +1983,38 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
BUILD_BUG_ON(sizeof(*caps) != 8);
if (!intel_sdvo_get_value(intel_sdvo,
SDVO_CMD_GET_DEVICE_CAPS,
caps, sizeof(*caps)))
return false;
- DRM_DEBUG_KMS("SDVO capabilities:\n"
- " vendor_id: %d\n"
- " device_id: %d\n"
- " device_rev_id: %d\n"
- " sdvo_version_major: %d\n"
- " sdvo_version_minor: %d\n"
- " sdvo_num_inputs: %d\n"
- " smooth_scaling: %d\n"
- " sharp_scaling: %d\n"
- " up_scaling: %d\n"
- " down_scaling: %d\n"
- " stall_support: %d\n"
- " output_flags: %d\n",
- caps->vendor_id,
- caps->device_id,
- caps->device_rev_id,
- caps->sdvo_version_major,
- caps->sdvo_version_minor,
- caps->sdvo_num_inputs,
- caps->smooth_scaling,
- caps->sharp_scaling,
- caps->up_scaling,
- caps->down_scaling,
- caps->stall_support,
- caps->output_flags);
+ drm_dbg_kms(&i915->drm, "SDVO capabilities:\n"
+ " vendor_id: %d\n"
+ " device_id: %d\n"
+ " device_rev_id: %d\n"
+ " sdvo_version_major: %d\n"
+ " sdvo_version_minor: %d\n"
+ " sdvo_num_inputs: %d\n"
+ " smooth_scaling: %d\n"
+ " sharp_scaling: %d\n"
+ " up_scaling: %d\n"
+ " down_scaling: %d\n"
+ " stall_support: %d\n"
+ " output_flags: %d\n",
+ caps->vendor_id,
+ caps->device_id,
+ caps->device_rev_id,
+ caps->sdvo_version_major,
+ caps->sdvo_version_minor,
+ caps->sdvo_num_inputs,
+ caps->smooth_scaling,
+ caps->sharp_scaling,
+ caps->up_scaling,
+ caps->down_scaling,
+ caps->stall_support,
+ caps->output_flags);
return true;
}
@@ -2033,7 +2046,7 @@ static u16 intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
return 0;
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
- &hotplug, sizeof(hotplug)))
+ &hotplug, sizeof(hotplug)))
return 0;
return hotplug;
@@ -2116,8 +2129,9 @@ intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
bool monitor_is_digital = drm_edid_is_digital(drm_edid);
bool connector_is_digital = !!IS_DIGITAL(sdvo);
- DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n",
- connector_is_digital, monitor_is_digital);
+ drm_dbg_kms(sdvo->base.base.dev,
+ "connector_is_digital? %d, monitor_is_digital? %d\n",
+ connector_is_digital, monitor_is_digital);
return connector_is_digital == monitor_is_digital;
}
@@ -2130,12 +2144,15 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret;
u16 response;
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.id, connector->name);
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
if (!intel_display_device_enabled(i915))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(i915))
+ return connector->status;
+
if (!intel_sdvo_set_target_output(intel_sdvo,
intel_sdvo_connector->output_flag))
return connector_status_unknown;
@@ -2145,9 +2162,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
&response, 2))
return connector_status_unknown;
- DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
- response & 0xff, response >> 8,
- intel_sdvo_connector->output_flag);
+ drm_dbg_kms(&i915->drm, "SDVO response %d %d [%x]\n",
+ response & 0xff, response >> 8,
+ intel_sdvo_connector->output_flag);
if (response == 0)
return connector_status_disconnected;
@@ -2181,11 +2198,15 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
static int intel_sdvo_get_ddc_modes(struct drm_connector *connector)
{
+ struct drm_i915_private *i915 = to_i915(connector->dev);
int num_modes = 0;
const struct drm_edid *drm_edid;
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.id, connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+
+ if (!intel_display_driver_check_access(i915))
+ return drm_edid_connector_add_modes(connector);
/* set the bus switch and get the modes */
drm_edid = intel_sdvo_get_edid(connector);
@@ -2279,6 +2300,7 @@ static const struct drm_display_mode sdvo_tv_modes[] = {
static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
struct intel_sdvo_connector *intel_sdvo_connector =
to_intel_sdvo_connector(connector);
const struct drm_connector_state *conn_state = connector->state;
@@ -2287,8 +2309,11 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
int num_modes = 0;
int i;
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.id, connector->name);
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+
+ if (!intel_display_driver_check_access(i915))
+ return 0;
/*
* Read the list of supported input resolutions for the selected TV
@@ -2775,10 +2800,11 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+ struct drm_i915_private *i915 = to_i915(intel_encoder->base.dev);
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising DVI type 0x%x\n", type);
+ drm_dbg_kms(&i915->drm, "initialising DVI type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2789,7 +2815,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
if (intel_sdvo_get_hotplug_support(intel_sdvo) &
- intel_sdvo_connector->output_flag) {
+ intel_sdvo_connector->output_flag) {
intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
/*
* Some SDVO devices have one-shot hotplug interrupts.
@@ -2801,6 +2827,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
} else {
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
}
+ intel_connector->base.polled = intel_connector->polled;
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
@@ -2823,12 +2850,13 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
static bool
intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising TV type 0x%x\n", type);
+ drm_dbg_kms(&i915->drm, "initialising TV type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2862,12 +2890,13 @@ err:
static bool
intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising analog type 0x%x\n", type);
+ drm_dbg_kms(&i915->drm, "initialising analog type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2876,6 +2905,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ intel_connector->base.polled = intel_connector->polled;
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
@@ -2898,7 +2928,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising LVDS type 0x%x\n", type);
+ drm_dbg_kms(&i915->drm, "initialising LVDS type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2982,6 +3012,7 @@ static bool intel_sdvo_output_init(struct intel_sdvo *sdvo, u16 type)
static bool
intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
static const u16 probe_order[] = {
SDVO_OUTPUT_TMDS0,
SDVO_OUTPUT_TMDS1,
@@ -3000,8 +3031,9 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
flags = intel_sdvo_filter_output_flags(intel_sdvo->caps.output_flags);
if (flags == 0) {
- DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%04x)\n",
- SDVO_NAME(intel_sdvo), intel_sdvo->caps.output_flags);
+ drm_dbg_kms(&i915->drm,
+ "%s: Unknown SDVO output type (0x%04x)\n",
+ SDVO_NAME(intel_sdvo), intel_sdvo->caps.output_flags);
return false;
}
@@ -3063,8 +3095,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->tv_format =
- drm_property_create(dev, DRM_MODE_PROP_ENUM,
- "mode", intel_sdvo_connector->format_supported_num);
+ drm_property_create(dev, DRM_MODE_PROP_ENUM,
+ "mode", intel_sdvo_connector->format_supported_num);
if (!intel_sdvo_connector->tv_format)
return false;
@@ -3090,8 +3122,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
state_assignment = response; \
drm_object_attach_property(&connector->base, \
intel_sdvo_connector->name, 0); \
- DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \
- data_value[0], data_value[1], response); \
+ drm_dbg_kms(dev, #name ": max %d, default %d, current %d\n", \
+ data_value[0], data_value[1], response); \
} \
} while (0)
@@ -3102,6 +3134,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
struct intel_sdvo_enhancements_reply enhancements)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
struct drm_device *dev = intel_sdvo->base.base.dev;
struct drm_connector *connector = &intel_sdvo_connector->base.base;
struct drm_connector_state *conn_state = connector->state;
@@ -3138,10 +3171,9 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
return false;
drm_object_attach_property(&connector->base,
- intel_sdvo_connector->right, 0);
- DRM_DEBUG_KMS("h_overscan: max %d, "
- "default %d, current %d\n",
- data_value[0], data_value[1], response);
+ intel_sdvo_connector->right, 0);
+ drm_dbg_kms(&i915->drm, "h_overscan: max %d, default %d, current %d\n",
+ data_value[0], data_value[1], response);
}
if (enhancements.overscan_v) {
@@ -3160,7 +3192,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->max_vscan = data_value[0];
intel_sdvo_connector->top =
drm_property_create_range(dev, 0,
- "top_margin", 0, data_value[0]);
+ "top_margin", 0, data_value[0]);
if (!intel_sdvo_connector->top)
return false;
@@ -3169,15 +3201,14 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->bottom =
drm_property_create_range(dev, 0,
- "bottom_margin", 0, data_value[0]);
+ "bottom_margin", 0, data_value[0]);
if (!intel_sdvo_connector->bottom)
return false;
drm_object_attach_property(&connector->base,
- intel_sdvo_connector->bottom, 0);
- DRM_DEBUG_KMS("v_overscan: max %d, "
- "default %d, current %d\n",
- data_value[0], data_value[1], response);
+ intel_sdvo_connector->bottom, 0);
+ drm_dbg_kms(&i915->drm, "v_overscan: max %d, default %d, current %d\n",
+ data_value[0], data_value[1], response);
}
ENHANCEMENT(&sdvo_state->tv, hpos, HPOS);
@@ -3205,7 +3236,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
drm_object_attach_property(&connector->base,
intel_sdvo_connector->dot_crawl, 0);
- DRM_DEBUG_KMS("dot crawl: current %d\n", response);
+ drm_dbg_kms(&i915->drm, "dot crawl: current %d\n", response);
}
return true;
@@ -3230,6 +3261,7 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector)
{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
union {
struct intel_sdvo_enhancements_reply reply;
u16 response;
@@ -3241,7 +3273,7 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
&enhancements, sizeof(enhancements)) ||
enhancements.response == 0) {
- DRM_DEBUG_KMS("No enhancement is supported\n");
+ drm_dbg_kms(&i915->drm, "No enhancement is supported\n");
return true;
}
@@ -3461,23 +3493,23 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
goto err_output;
drm_dbg_kms(&dev_priv->drm, "%s device VID/DID: %02X:%02X.%02X, "
- "clock range %dMHz - %dMHz, "
- "num inputs: %d, "
- "output 1: %c, output 2: %c\n",
- SDVO_NAME(intel_sdvo),
- intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
- intel_sdvo->caps.device_rev_id,
- intel_sdvo->pixel_clock_min / 1000,
- intel_sdvo->pixel_clock_max / 1000,
- intel_sdvo->caps.sdvo_num_inputs,
- /* check currently supported outputs */
- intel_sdvo->caps.output_flags &
- (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 |
- SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_SVID0 |
- SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_YPRPB0) ? 'Y' : 'N',
- intel_sdvo->caps.output_flags &
- (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
- SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
+ "clock range %dMHz - %dMHz, "
+ "num inputs: %d, "
+ "output 1: %c, output 2: %c\n",
+ SDVO_NAME(intel_sdvo),
+ intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
+ intel_sdvo->caps.device_rev_id,
+ intel_sdvo->pixel_clock_min / 1000,
+ intel_sdvo->pixel_clock_max / 1000,
+ intel_sdvo->caps.sdvo_num_inputs,
+ /* check currently supported outputs */
+ intel_sdvo->caps.output_flags &
+ (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 |
+ SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_SVID0 |
+ SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_YPRPB0) ? 'Y' : 'N',
+ intel_sdvo->caps.output_flags &
+ (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
+ SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
return true;
err_output:
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index dcf05e00e5..6b374d481c 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -122,6 +122,15 @@ bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port)
return intel_tc_port_in_mode(dig_port, TC_PORT_LEGACY);
}
+bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
+ struct intel_tc_port *tc = to_tc_port(dig_port);
+
+ return intel_phy_is_tc(i915, phy) && !tc->legacy_port;
+}
+
/*
* The display power domains used for TC ports depending on the
* platform and TC mode (legacy, DP-alt, TBT):
@@ -986,10 +995,11 @@ xelpdp_tc_phy_tcss_power_is_enabled(struct intel_tc_port *tc)
{
struct drm_i915_private *i915 = tc_to_i915(tc);
enum port port = tc->dig_port->base.port;
+ i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);
assert_tc_cold_blocked(tc);
- return intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_TCSS_POWER_STATE;
+ return intel_de_read(i915, reg) & XELPDP_TCSS_POWER_STATE;
}
static bool
@@ -1012,16 +1022,17 @@ static void __xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool ena
{
struct drm_i915_private *i915 = tc_to_i915(tc);
enum port port = tc->dig_port->base.port;
+ i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);
u32 val;
assert_tc_cold_blocked(tc);
- val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port));
+ val = intel_de_read(i915, reg);
if (enable)
val |= XELPDP_TCSS_POWER_REQUEST;
else
val &= ~XELPDP_TCSS_POWER_REQUEST;
- intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val);
+ intel_de_write(i915, reg, val);
}
static bool xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool enable)
@@ -1055,26 +1066,28 @@ static void xelpdp_tc_phy_take_ownership(struct intel_tc_port *tc, bool take)
{
struct drm_i915_private *i915 = tc_to_i915(tc);
enum port port = tc->dig_port->base.port;
+ i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);
u32 val;
assert_tc_cold_blocked(tc);
- val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port));
+ val = intel_de_read(i915, reg);
if (take)
val |= XELPDP_TC_PHY_OWNERSHIP;
else
val &= ~XELPDP_TC_PHY_OWNERSHIP;
- intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val);
+ intel_de_write(i915, reg, val);
}
static bool xelpdp_tc_phy_is_owned(struct intel_tc_port *tc)
{
struct drm_i915_private *i915 = tc_to_i915(tc);
enum port port = tc->dig_port->base.port;
+ i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);
assert_tc_cold_blocked(tc);
- return intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_TC_PHY_OWNERSHIP;
+ return intel_de_read(i915, reg) & XELPDP_TC_PHY_OWNERSHIP;
}
static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc)
@@ -1590,7 +1603,7 @@ void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port,
* connected ports are usable, and avoids exposing to the users objects they
* can't really use.
*/
-bool intel_tc_port_connected_locked(struct intel_encoder *encoder)
+bool intel_tc_port_connected(struct intel_encoder *encoder)
{
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
@@ -1605,19 +1618,6 @@ bool intel_tc_port_connected_locked(struct intel_encoder *encoder)
return tc_phy_hpd_live_status(tc) & mask;
}
-bool intel_tc_port_connected(struct intel_encoder *encoder)
-{
- struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
- struct intel_tc_port *tc = to_tc_port(dig_port);
- bool is_connected;
-
- mutex_lock(&tc->lock);
- is_connected = intel_tc_port_connected_locked(encoder);
- mutex_unlock(&tc->lock);
-
- return is_connected;
-}
-
static bool __intel_tc_port_link_needs_reset(struct intel_tc_port *tc)
{
bool ret;
diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h
index 80a61e5285..26c4265368 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.h
+++ b/drivers/gpu/drm/i915/display/intel_tc.h
@@ -15,9 +15,9 @@ struct intel_encoder;
bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port);
bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port);
bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port);
+bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port);
bool intel_tc_port_connected(struct intel_encoder *encoder);
-bool intel_tc_port_connected_locked(struct intel_encoder *encoder);
u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port);
int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port);
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 992a725de7..2b77d399f1 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -40,6 +40,7 @@
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_irq.h"
+#include "intel_display_driver.h"
#include "intel_display_types.h"
#include "intel_dpll.h"
#include "intel_hotplug.h"
@@ -1327,7 +1328,7 @@ intel_tv_compute_config(struct intel_encoder *encoder,
* the active portion. Hence following this formula seems
* more trouble that it's worth.
*
- * if (GRAPHICS_VER(dev_priv) == 4) {
+ * if (DISPLAY_VER(dev_priv) == 4) {
* num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
* den = tv_mode->clock;
* } else {
@@ -1723,6 +1724,9 @@ intel_tv_detect(struct drm_connector *connector,
if (!intel_display_device_enabled(i915))
return connector_status_disconnected;
+ if (!intel_display_driver_check_access(i915))
+ return connector->status;
+
if (force) {
struct drm_atomic_state *state;
@@ -1990,6 +1994,7 @@ intel_tv_init(struct drm_i915_private *dev_priv)
* More recent chipsets favour HDMI rather than integrated S-Video.
*/
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ intel_connector->base.polled = intel_connector->polled;
drm_connector_init(&dev_priv->drm, connector, &intel_tv_connector_funcs,
DRM_MODE_CONNECTOR_SVIDEO);
diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c
index fe256bf7b4..baf7354cb6 100644
--- a/drivers/gpu/drm/i915/display/intel_vblank.c
+++ b/drivers/gpu/drm/i915/display/intel_vblank.c
@@ -5,6 +5,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
+#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_vblank.h"
@@ -581,3 +582,132 @@ void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state,
intel_vblank_section_exit(i915);
spin_unlock_irqrestore(&i915->drm.vblank_time_lock, irqflags);
}
+
+static int intel_mode_vblank_start(const struct drm_display_mode *mode)
+{
+ int vblank_start = mode->crtc_vblank_start;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ vblank_start = DIV_ROUND_UP(vblank_start, 2);
+
+ return vblank_start;
+}
+
+void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state,
+ const struct intel_crtc_state *new_crtc_state,
+ struct intel_vblank_evade_ctx *evade)
+{
+ struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ const struct intel_crtc_state *crtc_state;
+ const struct drm_display_mode *adjusted_mode;
+
+ evade->crtc = crtc;
+
+ evade->need_vlv_dsi_wa = (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) &&
+ intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
+
+ /*
+ * During fastsets/etc. the transcoder is still
+ * running with the old timings at this point.
+ *
+ * TODO: maybe just use the active timings here?
+ */
+ if (intel_crtc_needs_modeset(new_crtc_state))
+ crtc_state = new_crtc_state;
+ else
+ crtc_state = old_crtc_state;
+
+ adjusted_mode = &crtc_state->hw.adjusted_mode;
+
+ if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
+ /* timing changes should happen with VRR disabled */
+ drm_WARN_ON(crtc->base.dev, intel_crtc_needs_modeset(new_crtc_state) ||
+ new_crtc_state->update_m_n || new_crtc_state->update_lrr);
+
+ if (intel_vrr_is_push_sent(crtc_state))
+ evade->vblank_start = intel_vrr_vmin_vblank_start(crtc_state);
+ else
+ evade->vblank_start = intel_vrr_vmax_vblank_start(crtc_state);
+ } else {
+ evade->vblank_start = intel_mode_vblank_start(adjusted_mode);
+ }
+
+ /* FIXME needs to be calibrated sensibly */
+ evade->min = evade->vblank_start - intel_usecs_to_scanlines(adjusted_mode,
+ VBLANK_EVASION_TIME_US);
+ evade->max = evade->vblank_start - 1;
+
+ /*
+ * M/N and TRANS_VTOTAL are double buffered on the transcoder's
+ * undelayed vblank, so with seamless M/N and LRR we must evade
+ * both vblanks.
+ *
+ * DSB execution waits for the transcoder's undelayed vblank,
+ * hence we must kick off the commit before that.
+ */
+ if (new_crtc_state->dsb || new_crtc_state->update_m_n || new_crtc_state->update_lrr)
+ evade->min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay;
+}
+
+/* must be called with vblank interrupt already enabled! */
+int intel_vblank_evade(struct intel_vblank_evade_ctx *evade)
+{
+ struct intel_crtc *crtc = evade->crtc;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ long timeout = msecs_to_jiffies_timeout(1);
+ wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
+ DEFINE_WAIT(wait);
+ int scanline;
+
+ if (evade->min <= 0 || evade->max <= 0)
+ return 0;
+
+ for (;;) {
+ /*
+ * prepare_to_wait() has a memory barrier, which guarantees
+ * other CPUs can see the task state update by the time we
+ * read the scanline.
+ */
+ prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
+
+ scanline = intel_get_crtc_scanline(crtc);
+ if (scanline < evade->min || scanline > evade->max)
+ break;
+
+ if (!timeout) {
+ drm_err(&i915->drm,
+ "Potential atomic update failure on pipe %c\n",
+ pipe_name(crtc->pipe));
+ break;
+ }
+
+ local_irq_enable();
+
+ timeout = schedule_timeout(timeout);
+
+ local_irq_disable();
+ }
+
+ finish_wait(wq, &wait);
+
+ /*
+ * On VLV/CHV DSI the scanline counter would appear to
+ * increment approx. 1/3 of a scanline before start of vblank.
+ * The registers still get latched at start of vblank however.
+ * This means we must not write any registers on the first
+ * line of vblank (since not the whole line is actually in
+ * vblank). And unfortunately we can't use the interrupt to
+ * wait here since it will fire too soon. We could use the
+ * frame start interrupt instead since it will fire after the
+ * critical scanline, but that would require more changes
+ * in the interrupt code. So for now we'll just do the nasty
+ * thing and poll for the bad scanline to pass us by.
+ *
+ * FIXME figure out if BXT+ DSI suffers from this as well
+ */
+ while (evade->need_vlv_dsi_wa && scanline == evade->vblank_start)
+ scanline = intel_get_crtc_scanline(crtc);
+
+ return scanline;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_vblank.h b/drivers/gpu/drm/i915/display/intel_vblank.h
index 17636f140c..ec6c3da3ee 100644
--- a/drivers/gpu/drm/i915/display/intel_vblank.h
+++ b/drivers/gpu/drm/i915/display/intel_vblank.h
@@ -13,6 +13,18 @@ struct drm_crtc;
struct intel_crtc;
struct intel_crtc_state;
+struct intel_vblank_evade_ctx {
+ struct intel_crtc *crtc;
+ int min, max, vblank_start;
+ bool need_vlv_dsi_wa;
+};
+
+void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state,
+ const struct intel_crtc_state *new_crtc_state,
+ struct intel_vblank_evade_ctx *evade);
+/* must be called with vblank interrupt already enabled! */
+int intel_vblank_evade(struct intel_vblank_evade_ctx *evade);
+
u32 i915_get_vblank_counter(struct drm_crtc *crtc);
u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index 8bba6c2e50..860574d04f 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -948,6 +948,11 @@ static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
if (DISPLAY_VER(dev_priv) == 13)
plane_ctl |= adlp_plane_ctl_arb_slots(plane_state);
+ if (GRAPHICS_VER(dev_priv) >= 20 &&
+ fb->modifier == I915_FORMAT_MOD_4_TILED) {
+ plane_ctl |= PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
+ }
+
return plane_ctl;
}
@@ -2627,3 +2632,31 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
error:
kfree(intel_fb);
}
+
+bool skl_fixup_initial_plane_config(struct intel_crtc *crtc,
+ const struct intel_initial_plane_config *plane_config)
+{
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+ const struct intel_plane_state *plane_state =
+ to_intel_plane_state(plane->base.state);
+ enum plane_id plane_id = plane->id;
+ enum pipe pipe = crtc->pipe;
+ u32 base;
+
+ if (!plane_state->uapi.visible)
+ return false;
+
+ base = intel_plane_ggtt_offset(plane_state);
+
+ /*
+ * We may have moved the surface to a different
+ * part of ggtt, make the plane aware of that.
+ */
+ if (plane_config->base == base)
+ return false;
+
+ intel_de_write(i915, PLANE_SURF(pipe, plane_id), base);
+
+ return true;
+}
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h
index be64c201f9..e92e00c01b 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.h
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h
@@ -22,6 +22,8 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
void skl_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config);
+bool skl_fixup_initial_plane_config(struct intel_crtc *crtc,
+ const struct intel_initial_plane_config *plane_config);
int skl_format_to_fourcc(int format, bool rgb_order, bool alpha);
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c
index 56588d6e24..c6b9be80d8 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.c
+++ b/drivers/gpu/drm/i915/display/skl_watermark.c
@@ -23,6 +23,12 @@
#include "skl_watermark.h"
#include "skl_watermark_regs.h"
+/*It is expected that DSB can do posted writes to every register in
+ * the pipe and planes within 100us. For flip queue use case, the
+ * recommended DSB execution time is 100us + one SAGV block time.
+ */
+#define DSB_EXE_TIME 100
+
static void skl_sagv_disable(struct drm_i915_private *i915);
/* Stores plane specific WM parameters */
@@ -443,12 +449,35 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state)
for_each_new_intel_crtc_in_state(state, crtc,
new_crtc_state, i) {
+ struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal;
+
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);
+ /*
+ * We store use_sagv_wm in the crtc state rather than relying on
+ * that bw state since we have no convenient way to get at the
+ * latter from the plane commit hooks (especially in the legacy
+ * cursor case).
+ *
+ * drm_atomic_check_only() gets upset if we pull more crtcs
+ * into the state, so we have to calculate this based on the
+ * individual intel_crtc_can_enable_sagv() rather than
+ * the overall intel_can_enable_sagv(). Otherwise the
+ * crtcs not included in the commit would not switch to the
+ * SAGV watermarks when we are about to enable SAGV, and that
+ * would lead to underruns. This does mean extra power draw
+ * when only a subset of the crtcs are blocking SAGV as the
+ * other crtcs can't be allowed to use the more optimal
+ * normal (ie. non-SAGV) watermarks.
+ */
+ pipe_wm->use_sagv_wm = !HAS_HW_SAGV_WM(i915) &&
+ DISPLAY_VER(i915) >= 12 &&
+ intel_crtc_can_enable_sagv(new_crtc_state);
+
if (intel_crtc_can_enable_sagv(new_crtc_state))
new_bw_state->pipe_sagv_reject &= ~BIT(crtc->pipe);
else
@@ -478,21 +507,6 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state)
return ret;
}
- for_each_new_intel_crtc_in_state(state, crtc,
- new_crtc_state, i) {
- struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal;
-
- /*
- * We store use_sagv_wm in the crtc state rather than relying on
- * that bw state since we have no convenient way to get at the
- * latter from the plane commit hooks (especially in the legacy
- * cursor case)
- */
- pipe_wm->use_sagv_wm = !HAS_HW_SAGV_WM(i915) &&
- DISPLAY_VER(i915) >= 12 &&
- intel_can_enable_sagv(i915, new_bw_state);
- }
-
return 0;
}
@@ -1367,7 +1381,7 @@ skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state)
u64 data_rate = 0;
for_each_plane_id_on_crtc(crtc, plane_id) {
- if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20)
+ if (plane_id == PLANE_CURSOR)
continue;
data_rate += crtc_state->rel_data_rate[plane_id];
@@ -1514,12 +1528,10 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state,
return 0;
/* Allocate fixed number of blocks for cursor. */
- if (DISPLAY_VER(i915) < 20) {
- cursor_size = skl_cursor_allocation(crtc_state, num_active);
- iter.size -= cursor_size;
- skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR],
- alloc->end - cursor_size, alloc->end);
- }
+ cursor_size = skl_cursor_allocation(crtc_state, num_active);
+ iter.size -= cursor_size;
+ skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR],
+ alloc->end - cursor_size, alloc->end);
iter.data_rate = skl_total_relative_data_rate(crtc_state);
@@ -1533,7 +1545,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state,
const struct skl_plane_wm *wm =
&crtc_state->wm.skl.optimal.planes[plane_id];
- if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) {
+ if (plane_id == PLANE_CURSOR) {
const struct skl_ddb_entry *ddb =
&crtc_state->wm.skl.plane_ddb[plane_id];
@@ -1581,7 +1593,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state,
const struct skl_plane_wm *wm =
&crtc_state->wm.skl.optimal.planes[plane_id];
- if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20)
+ if (plane_id == PLANE_CURSOR)
continue;
if (DISPLAY_VER(i915) < 11 &&
@@ -2898,12 +2910,51 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state,
return 0;
}
+/*
+ * If Fixed Refresh Rate:
+ * Program DEEP PKG_C_LATENCY Pkg C with highest valid latency from
+ * watermark level1 and up and above. If watermark level 1 is
+ * invalid program it with all 1's.
+ * Program PKG_C_LATENCY Added Wake Time = DSB execution time
+ * If Variable Refresh Rate:
+ * Program DEEP PKG_C_LATENCY Pkg C with all 1's.
+ * Program PKG_C_LATENCY Added Wake Time = 0
+ */
+static void
+skl_program_dpkgc_latency(struct drm_i915_private *i915, bool vrr_enabled)
+{
+ u32 max_latency = 0;
+ u32 clear = 0, val = 0;
+ u32 added_wake_time = 0;
+
+ if (DISPLAY_VER(i915) < 20)
+ return;
+
+ if (vrr_enabled) {
+ max_latency = LNL_PKG_C_LATENCY_MASK;
+ added_wake_time = 0;
+ } else {
+ max_latency = skl_watermark_max_latency(i915, 1);
+ if (max_latency == 0)
+ max_latency = LNL_PKG_C_LATENCY_MASK;
+ added_wake_time = DSB_EXE_TIME +
+ i915->display.sagv.block_time_us;
+ }
+
+ clear |= LNL_ADDED_WAKE_TIME_MASK | LNL_PKG_C_LATENCY_MASK;
+ val |= REG_FIELD_PREP(LNL_PKG_C_LATENCY_MASK, max_latency);
+ val |= REG_FIELD_PREP(LNL_ADDED_WAKE_TIME_MASK, added_wake_time);
+
+ intel_uncore_rmw(&i915->uncore, LNL_PKG_C_LATENCY, clear, val);
+}
+
static int
skl_compute_wm(struct intel_atomic_state *state)
{
struct intel_crtc *crtc;
struct intel_crtc_state __maybe_unused *new_crtc_state;
int ret, i;
+ bool vrr_enabled = false;
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
ret = skl_build_pipe_wm(state, crtc);
@@ -2928,8 +2979,13 @@ skl_compute_wm(struct intel_atomic_state *state)
ret = skl_wm_add_affected_planes(state, crtc);
if (ret)
return ret;
+
+ if (new_crtc_state->vrr.enable)
+ vrr_enabled = true;
}
+ skl_program_dpkgc_latency(to_i915(state->base.dev), vrr_enabled);
+
skl_print_wm_changes(state);
return 0;
@@ -3725,11 +3781,11 @@ void skl_watermark_debugfs_register(struct drm_i915_private *i915)
&intel_sagv_status_fops);
}
-unsigned int skl_watermark_max_latency(struct drm_i915_private *i915)
+unsigned int skl_watermark_max_latency(struct drm_i915_private *i915, int initial_wm_level)
{
int level;
- for (level = i915->display.wm.num_levels - 1; level >= 0; level--) {
+ for (level = i915->display.wm.num_levels - 1; level >= initial_wm_level; level--) {
unsigned int latency = skl_wm_latency(i915, level, NULL);
if (latency)
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h
index fb0da36fd3..e3d1d74a7b 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.h
+++ b/drivers/gpu/drm/i915/display/skl_watermark.h
@@ -46,8 +46,8 @@ void skl_watermark_ipc_update(struct drm_i915_private *i915);
bool skl_watermark_ipc_enabled(struct drm_i915_private *i915);
void skl_watermark_debugfs_register(struct drm_i915_private *i915);
-unsigned int skl_watermark_max_latency(struct drm_i915_private *i915);
-
+unsigned int skl_watermark_max_latency(struct drm_i915_private *i915,
+ int initial_wm_level);
void skl_wm_init(struct drm_i915_private *i915);
struct intel_dbuf_state {
diff --git a/drivers/gpu/drm/i915/display/skl_watermark_regs.h b/drivers/gpu/drm/i915/display/skl_watermark_regs.h
index 628c5920ad..20b30c9a66 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark_regs.h
+++ b/drivers/gpu/drm/i915/display/skl_watermark_regs.h
@@ -157,4 +157,8 @@
#define MTL_LATENCY_SAGV _MMIO(0x4578c)
#define MTL_LATENCY_QCLK_SAGV REG_GENMASK(12, 0)
+#define LNL_PKG_C_LATENCY _MMIO(0x46460)
+#define LNL_ADDED_WAKE_TIME_MASK REG_GENMASK(28, 16)
+#define LNL_PKG_C_LATENCY_MASK REG_GENMASK(12, 0)
+
#endif /* __SKL_WATERMARK_REGS_H__ */