summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/display
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display')
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi.c79
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.c138
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c58
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c52
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.c124
-rw-r--r--drivers/gpu/drm/i915/display/intel_combo_phy.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_csr.c12
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c1009
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c1689
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.h43
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c39
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c116
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h140
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c798
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h23
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c554
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.h17
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c40
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.c23
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c221
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h28
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c15
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp.c89
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c20
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.c64
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_lspcon.c97
-rw-r--r--drivers/gpu/drm/i915/display/intel_lspcon.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_lvds.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c249
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.h14
-rw-r--r--drivers/gpu/drm/i915/display/intel_sprite.c235
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_vbt_defs.h13
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.c201
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.h6
-rw-r--r--drivers/gpu/drm/i915/display/vlv_dsi.c8
48 files changed, 4499 insertions, 1811 deletions
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index 520715b7d5b5..a9439b415603 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -205,6 +205,32 @@ static int dsi_send_pkt_payld(struct intel_dsi_host *host,
return 0;
}
+void icl_dsi_frame_update(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ u32 tmp, mode_flags;
+ enum port port;
+
+ mode_flags = crtc_state->mode_flags;
+
+ /*
+ * case 1 also covers dual link
+ * In case of dual link, frame update should be set on
+ * DSI_0
+ */
+ if (mode_flags & I915_MODE_FLAG_DSI_USE_TE0)
+ port = PORT_A;
+ else if (mode_flags & I915_MODE_FLAG_DSI_USE_TE1)
+ port = PORT_B;
+ else
+ return;
+
+ tmp = intel_de_read(dev_priv, DSI_CMD_FRMCTL(port));
+ tmp |= DSI_FRAME_UPDATE_REQUEST;
+ intel_de_write(dev_priv, DSI_CMD_FRMCTL(port), tmp);
+}
+
static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -429,7 +455,7 @@ static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
intel_de_write(dev_priv, ICL_PORT_TX_DW2_GRP(phy), tmp);
/* For EHL, TGL, set latency optimization for PCS_DW1 lanes */
- if (IS_ELKHARTLAKE(dev_priv) || (INTEL_GEN(dev_priv) >= 12)) {
+ if (IS_JSL_EHL(dev_priv) || (INTEL_GEN(dev_priv) >= 12)) {
tmp = intel_de_read(dev_priv,
ICL_PORT_PCS_DW1_AUX(phy));
tmp &= ~LATENCY_OPTIM_MASK;
@@ -586,7 +612,7 @@ gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder,
}
}
- if (IS_ELKHARTLAKE(dev_priv)) {
+ if (IS_JSL_EHL(dev_priv)) {
for_each_dsi_phy(phy, intel_dsi->phys) {
tmp = intel_de_read(dev_priv, ICL_DPHY_CHKN(phy));
tmp |= ICL_DPHY_CHKN_AFE_OVER_PPI_STRAP;
@@ -1447,6 +1473,18 @@ static bool gen11_dsi_is_periodic_cmd_mode(struct intel_dsi *intel_dsi)
return (val & DSI_PERIODIC_FRAME_UPDATE_ENABLE);
}
+static void gen11_dsi_get_cmd_mode_config(struct intel_dsi *intel_dsi,
+ struct intel_crtc_state *pipe_config)
+{
+ if (intel_dsi->ports == (BIT(PORT_B) | BIT(PORT_A)))
+ pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE1 |
+ I915_MODE_FLAG_DSI_USE_TE0;
+ else if (intel_dsi->ports == BIT(PORT_B))
+ pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE1;
+ else
+ pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE0;
+}
+
static void gen11_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
@@ -1454,11 +1492,10 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- intel_dsc_get_config(encoder, pipe_config);
-
/* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */
pipe_config->port_clock = intel_dpll_get_freq(i915,
- pipe_config->shared_dpll);
+ pipe_config->shared_dpll,
+ &pipe_config->dpll_hw_state);
pipe_config->hw.adjusted_mode.crtc_clock = intel_dsi->pclk;
if (intel_dsi->dual_link)
@@ -1468,6 +1505,10 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
pipe_config->pipe_bpp = bdw_get_pipemisc_bpp(crtc);
+ /* Get the details on which TE should be enabled */
+ if (is_cmd_mode(intel_dsi))
+ gen11_dsi_get_cmd_mode_config(intel_dsi, pipe_config);
+
if (gen11_dsi_is_periodic_cmd_mode(intel_dsi))
pipe_config->mode_flags |= I915_MODE_FLAG_DSI_PERIODIC_CMD_MODE;
}
@@ -1562,18 +1603,8 @@ static int gen11_dsi_compute_config(struct intel_encoder *encoder,
* receive TE from the slave if
* dual link is enabled
*/
- if (is_cmd_mode(intel_dsi)) {
- if (intel_dsi->ports == (BIT(PORT_B) | BIT(PORT_A)))
- pipe_config->mode_flags |=
- I915_MODE_FLAG_DSI_USE_TE1 |
- I915_MODE_FLAG_DSI_USE_TE0;
- else if (intel_dsi->ports == BIT(PORT_B))
- pipe_config->mode_flags |=
- I915_MODE_FLAG_DSI_USE_TE1;
- else
- pipe_config->mode_flags |=
- I915_MODE_FLAG_DSI_USE_TE0;
- }
+ if (is_cmd_mode(intel_dsi))
+ gen11_dsi_get_cmd_mode_config(intel_dsi, pipe_config);
return 0;
}
@@ -1636,6 +1667,19 @@ out:
return ret;
}
+static bool gen11_dsi_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->dsc.compression_enable) {
+ drm_dbg_kms(encoder->base.dev, "Forcing full modeset due to DSC being enabled\n");
+ crtc_state->uapi.mode_changed = true;
+
+ return false;
+ }
+
+ return true;
+}
+
static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
{
intel_encoder_destroy(encoder);
@@ -1891,6 +1935,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
encoder->update_pipe = intel_panel_update_backlight;
encoder->compute_config = gen11_dsi_compute_config;
encoder->get_hw_state = gen11_dsi_get_hw_state;
+ encoder->initial_fastset_check = gen11_dsi_initial_fastset_check;
encoder->type = INTEL_OUTPUT_DSI;
encoder->cloneable = 0;
encoder->pipe_mask = ~0;
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 86be032bcf96..e00fdc47c0eb 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -133,7 +133,6 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
struct drm_crtc_state *crtc_state;
intel_hdcp_atomic_check(conn, old_state, new_state);
- intel_psr_atomic_check(conn, old_state, new_state);
if (!new_state->crtc)
return 0;
@@ -270,14 +269,15 @@ void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state)
intel_crtc_put_color_blobs(crtc_state);
}
-void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state)
+void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state,
+ const struct intel_crtc_state *from_crtc_state)
{
drm_property_replace_blob(&crtc_state->hw.degamma_lut,
- crtc_state->uapi.degamma_lut);
+ from_crtc_state->uapi.degamma_lut);
drm_property_replace_blob(&crtc_state->hw.gamma_lut,
- crtc_state->uapi.gamma_lut);
+ from_crtc_state->uapi.gamma_lut);
drm_property_replace_blob(&crtc_state->hw.ctm,
- crtc_state->uapi.ctm);
+ from_crtc_state->uapi.ctm);
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.h b/drivers/gpu/drm/i915/display/intel_atomic.h
index 285de07011dc..62a3365ed5e6 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.h
+++ b/drivers/gpu/drm/i915/display/intel_atomic.h
@@ -43,7 +43,8 @@ struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
void intel_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state);
-void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state);
+void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state,
+ const struct intel_crtc_state *from_crtc_state);
struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev);
void intel_atomic_state_free(struct drm_atomic_state *state);
void intel_atomic_state_clear(struct drm_atomic_state *state);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index 79032701873a..7e9f84b00859 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -247,11 +247,19 @@ static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
}
void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
- const struct intel_plane_state *from_plane_state)
+ const struct intel_plane_state *from_plane_state,
+ struct intel_crtc *crtc)
{
intel_plane_clear_hw_state(plane_state);
- plane_state->hw.crtc = from_plane_state->uapi.crtc;
+ /*
+ * For the bigjoiner slave uapi.crtc will point at
+ * the master crtc. So we explicitly assign the right
+ * slave crtc to hw.crtc. uapi.crtc!=NULL simply indicates
+ * the plane is logically enabled on the uapi level.
+ */
+ plane_state->hw.crtc = from_plane_state->uapi.crtc ? &crtc->base : NULL;
+
plane_state->hw.fb = from_plane_state->uapi.fb;
if (plane_state->hw.fb)
drm_framebuffer_get(plane_state->hw.fb);
@@ -262,6 +270,22 @@ void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
plane_state->hw.rotation = from_plane_state->uapi.rotation;
plane_state->hw.color_encoding = from_plane_state->uapi.color_encoding;
plane_state->hw.color_range = from_plane_state->uapi.color_range;
+ plane_state->hw.scaling_filter = from_plane_state->uapi.scaling_filter;
+
+ plane_state->uapi.src = drm_plane_state_src(&from_plane_state->uapi);
+ plane_state->uapi.dst = drm_plane_state_dest(&from_plane_state->uapi);
+}
+
+void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
+ const struct intel_plane_state *from_plane_state)
+{
+ intel_plane_clear_hw_state(plane_state);
+
+ memcpy(&plane_state->hw, &from_plane_state->hw,
+ sizeof(plane_state->hw));
+
+ if (plane_state->hw.fb)
+ drm_framebuffer_get(plane_state->hw.fb);
}
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
@@ -318,15 +342,16 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
old_plane_state, new_plane_state);
}
-static struct intel_crtc *
-get_crtc_from_states(const struct intel_plane_state *old_plane_state,
- const struct intel_plane_state *new_plane_state)
+static struct intel_plane *
+intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id)
{
- if (new_plane_state->uapi.crtc)
- return to_intel_crtc(new_plane_state->uapi.crtc);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_plane *plane;
- if (old_plane_state->uapi.crtc)
- return to_intel_crtc(old_plane_state->uapi.crtc);
+ for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) {
+ if (plane->id == plane_id)
+ return plane;
+ }
return NULL;
}
@@ -334,23 +359,37 @@ get_crtc_from_states(const struct intel_plane_state *old_plane_state,
int intel_plane_atomic_check(struct intel_atomic_state *state,
struct intel_plane *plane)
{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
struct intel_plane_state *new_plane_state =
intel_atomic_get_new_plane_state(state, plane);
const struct intel_plane_state *old_plane_state =
intel_atomic_get_old_plane_state(state, plane);
- struct intel_crtc *crtc =
- get_crtc_from_states(old_plane_state, new_plane_state);
- const struct intel_crtc_state *old_crtc_state;
- struct intel_crtc_state *new_crtc_state;
+ const struct intel_plane_state *new_master_plane_state;
+ struct intel_crtc *crtc = intel_get_crtc_for_pipe(i915, plane->pipe);
+ 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);
+
+ if (new_crtc_state && new_crtc_state->bigjoiner_slave) {
+ struct intel_plane *master_plane =
+ intel_crtc_get_plane(new_crtc_state->bigjoiner_linked_crtc,
+ plane->id);
+
+ new_master_plane_state =
+ intel_atomic_get_new_plane_state(state, master_plane);
+ } else {
+ new_master_plane_state = new_plane_state;
+ }
+
+ intel_plane_copy_uapi_to_hw_state(new_plane_state,
+ new_master_plane_state,
+ crtc);
- intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state);
new_plane_state->uapi.visible = false;
- if (!crtc)
+ if (!new_crtc_state)
return 0;
- old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
- new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
-
return intel_plane_atomic_check_with_state(old_crtc_state,
new_crtc_state,
old_plane_state,
@@ -408,7 +447,11 @@ void intel_update_plane(struct intel_plane *plane,
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
trace_intel_update_plane(&plane->base, crtc);
- plane->update_plane(plane, crtc_state, plane_state);
+
+ if (crtc_state->uapi.async_flip && plane->async_flip)
+ plane->async_flip(plane, crtc_state, plane_state);
+ else
+ plane->update_plane(plane, crtc_state, plane_state);
}
void intel_disable_plane(struct intel_plane *plane,
@@ -474,6 +517,63 @@ void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
}
}
+int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
+ struct intel_crtc_state *crtc_state,
+ int min_scale, int max_scale,
+ bool can_position)
+{
+ struct drm_framebuffer *fb = plane_state->hw.fb;
+ struct drm_rect *src = &plane_state->uapi.src;
+ struct drm_rect *dst = &plane_state->uapi.dst;
+ unsigned int rotation = plane_state->hw.rotation;
+ struct drm_rect clip = {};
+ int hscale, vscale;
+
+ if (!fb) {
+ plane_state->uapi.visible = false;
+ return 0;
+ }
+
+ drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
+
+ /* Check scaling */
+ hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
+ vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
+ if (hscale < 0 || vscale < 0) {
+ DRM_DEBUG_KMS("Invalid scaling of plane\n");
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
+ return -ERANGE;
+ }
+
+ if (crtc_state->hw.enable) {
+ clip.x2 = crtc_state->pipe_src_w;
+ clip.y2 = crtc_state->pipe_src_h;
+ }
+
+ /* right side of the image is on the slave crtc, adjust dst to match */
+ if (crtc_state->bigjoiner_slave)
+ drm_rect_translate(dst, -crtc_state->pipe_src_w, 0);
+
+ /*
+ * FIXME: This might need further adjustment for seamless scaling
+ * with phase information, for the 2p2 and 2p1 scenarios.
+ */
+ plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, &clip);
+
+ drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
+
+ if (!can_position && plane_state->uapi.visible &&
+ !drm_rect_equals(dst, &clip)) {
+ DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
+ drm_rect_debug_print("dst: ", dst, false);
+ drm_rect_debug_print("clip: ", &clip, false);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
.prepare_fb = intel_prepare_plane_fb,
.cleanup_fb = intel_cleanup_plane_fb,
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
index 59dd1fbb02ea..5c78a087ed86 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
@@ -24,7 +24,10 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
- const struct intel_plane_state *from_plane_state);
+ const struct intel_plane_state *from_plane_state,
+ struct intel_crtc *crtc);
+void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
+ const struct intel_plane_state *from_plane_state);
void intel_update_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
@@ -52,6 +55,10 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
struct intel_plane *plane,
bool *need_cdclk_calc);
+int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
+ struct intel_crtc_state *crtc_state,
+ int min_scale, int max_scale,
+ bool can_position);
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state);
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 4716484af62d..4cc949b228f2 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -425,6 +425,7 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv,
const struct bdb_lfp_backlight_data *backlight_data;
const struct lfp_backlight_data_entry *entry;
int panel_type = dev_priv->vbt.panel_type;
+ u16 level;
backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
if (!backlight_data)
@@ -459,14 +460,39 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv,
dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;
- dev_priv->vbt.backlight.min_brightness = entry->min_brightness;
+
+ if (bdb->version >= 234) {
+ u16 min_level;
+ bool scale;
+
+ level = backlight_data->brightness_level[panel_type].level;
+ min_level = backlight_data->brightness_min_level[panel_type].level;
+
+ if (bdb->version >= 236)
+ scale = backlight_data->brightness_precision_bits[panel_type] == 16;
+ else
+ scale = level > 255;
+
+ if (scale)
+ min_level = min_level / 255;
+
+ if (min_level > 255) {
+ drm_warn(&dev_priv->drm, "Brightness min level > 255\n");
+ level = 255;
+ }
+ dev_priv->vbt.backlight.min_brightness = min_level;
+ } else {
+ level = backlight_data->level[panel_type];
+ dev_priv->vbt.backlight.min_brightness = entry->min_brightness;
+ }
+
drm_dbg_kms(&dev_priv->drm,
"VBT backlight PWM modulation frequency %u Hz, "
"active %s, min brightness %u, level %u, controller %u\n",
dev_priv->vbt.backlight.pwm_freq_hz,
dev_priv->vbt.backlight.active_low_pwm ? "low" : "high",
dev_priv->vbt.backlight.min_brightness,
- backlight_data->level[panel_type],
+ level,
dev_priv->vbt.backlight.controller);
}
@@ -1602,7 +1628,9 @@ static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin)
const u8 *ddc_pin_map;
int n_entries;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) {
+ return vbt_pin;
+ } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
ddc_pin_map = icp_ddc_pin_map;
n_entries = ARRAY_SIZE(icp_ddc_pin_map);
} else if (HAS_PCH_CNP(dev_priv)) {
@@ -1660,20 +1688,18 @@ static enum port dvo_port_to_port(struct drm_i915_private *dev_priv,
[PORT_I] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 },
};
/*
- * Bspec lists the ports as A, B, C, D - however internally in our
- * driver we keep them as PORT_A, PORT_B, PORT_D and PORT_E so the
- * registers in Display Engine match the right offsets. Apply the
- * mapping here to translate from VBT to internal convention.
+ * RKL VBT uses PHY based mapping. Combo PHYs A,B,C,D
+ * map to DDI A,B,TC1,TC2 respectively.
*/
static const int rkl_port_mapping[][3] = {
[PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 },
[PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 },
[PORT_C] = { -1 },
- [PORT_D] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
- [PORT_E] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
+ [PORT_TC1] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
+ [PORT_TC2] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
};
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
return __dvo_port_to_port(ARRAY_SIZE(rkl_port_mapping),
ARRAY_SIZE(rkl_port_mapping[0]),
rkl_port_mapping,
@@ -1889,7 +1915,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
expected_size = 37;
} else if (bdb->version <= 215) {
expected_size = 38;
- } else if (bdb->version <= 229) {
+ } else if (bdb->version <= 237) {
expected_size = 39;
} else {
expected_size = sizeof(*child);
@@ -2638,10 +2664,16 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv,
aux_ch = AUX_CH_B;
break;
case DP_AUX_C:
- aux_ch = IS_ROCKETLAKE(dev_priv) ? AUX_CH_D : AUX_CH_C;
+ /*
+ * RKL/DG1 VBT uses PHY based mapping. Combo PHYs A,B,C,D
+ * map to DDI A,B,TC1,TC2 respectively.
+ */
+ aux_ch = (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) ?
+ AUX_CH_USBC1 : AUX_CH_C;
break;
case DP_AUX_D:
- aux_ch = IS_ROCKETLAKE(dev_priv) ? AUX_CH_E : AUX_CH_D;
+ aux_ch = (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) ?
+ AUX_CH_USBC2 : AUX_CH_D;
break;
case DP_AUX_E:
aux_ch = AUX_CH_E;
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index cb93f6cf6d37..c449d28d0560 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -1233,6 +1233,30 @@ static const struct intel_cdclk_vals icl_cdclk_table[] = {
{}
};
+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 },
+ {}
+};
+
static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
{
const struct intel_cdclk_vals *table = dev_priv->cdclk.table;
@@ -2588,7 +2612,7 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
*/
void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
{
- if (IS_ELKHARTLAKE(dev_priv)) {
+ if (IS_JSL_EHL(dev_priv)) {
if (dev_priv->cdclk.hw.ref == 24000)
dev_priv->max_cdclk_freq = 552000;
else
@@ -2680,6 +2704,18 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv)
DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000));
}
+static int dg1_rawclk(struct drm_i915_private *dev_priv)
+{
+ /*
+ * DG1 always uses a 38.4 MHz rawclk. The bspec tells us
+ * "Program Numerator=2, Denominator=4, Divider=37 decimal."
+ */
+ I915_WRITE(PCH_RAWCLK_FREQ,
+ CNP_RAWCLK_DEN(4) | CNP_RAWCLK_DIV(37) | ICP_RAWCLK_NUM(2));
+
+ return 38400;
+}
+
static int cnp_rawclk(struct drm_i915_private *dev_priv)
{
u32 rawclk;
@@ -2788,7 +2824,9 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
{
u32 freq;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
+ 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))
freq = pch_rawclk(dev_priv);
@@ -2809,13 +2847,19 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
*/
void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (IS_ROCKETLAKE(dev_priv)) {
+ dev_priv->display.set_cdclk = bxt_set_cdclk;
+ dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
+ dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
+ dev_priv->display.calc_voltage_level = tgl_calc_voltage_level;
+ dev_priv->cdclk.table = rkl_cdclk_table;
+ } else if (INTEL_GEN(dev_priv) >= 12) {
dev_priv->display.set_cdclk = bxt_set_cdclk;
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
dev_priv->display.calc_voltage_level = tgl_calc_voltage_level;
dev_priv->cdclk.table = icl_cdclk_table;
- } else if (IS_ELKHARTLAKE(dev_priv)) {
+ } else if (IS_JSL_EHL(dev_priv)) {
dev_priv->display.set_cdclk = bxt_set_cdclk;
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index 945bb03bdd4d..172d398081ee 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -638,10 +638,17 @@ static void ilk_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
ilk_load_lut_8(crtc, gamma_lut);
- else
+ break;
+ case GAMMA_MODE_MODE_10BIT:
ilk_load_lut_10(crtc, gamma_lut);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
static int ivb_lut_10_size(u32 prec_index)
@@ -745,21 +752,27 @@ static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
+ const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) {
- ilk_load_lut_8(crtc, gamma_lut);
- } else if (crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) {
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ ilk_load_lut_8(crtc, blob);
+ break;
+ case GAMMA_MODE_MODE_SPLIT:
ivb_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
ivb_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
- } else {
- const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
-
+ break;
+ case GAMMA_MODE_MODE_10BIT:
ivb_load_lut_10(crtc, blob,
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
@@ -768,21 +781,28 @@ static void bdw_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
+ const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) {
- ilk_load_lut_8(crtc, gamma_lut);
- } else if (crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) {
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ ilk_load_lut_8(crtc, blob);
+ break;
+ case GAMMA_MODE_MODE_SPLIT:
bdw_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
- } else {
- const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
+ break;
+ case GAMMA_MODE_MODE_10BIT:
bdw_load_lut_10(crtc, blob,
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
@@ -818,12 +838,14 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state)
* as compared to just 16 to achieve this.
*/
intel_de_write(dev_priv, PRE_CSC_GAMC_DATA(pipe),
- lut[i].green);
+ lut[i].green);
}
/* Clamp values > 1.0. */
while (i++ < 35)
intel_de_write(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
+
+ intel_de_write(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
}
static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_state)
@@ -851,6 +873,8 @@ static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_stat
/* Clamp values > 1.0. */
while (i++ < 35)
intel_de_write(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
+
+ intel_de_write(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
}
static void glk_load_luts(const struct intel_crtc_state *crtc_state)
@@ -871,11 +895,17 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state)
else
glk_load_degamma_lut_linear(crtc_state);
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) {
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
ilk_load_lut_8(crtc, gamma_lut);
- } else {
+ break;
+ case GAMMA_MODE_MODE_10BIT:
bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
@@ -1007,9 +1037,13 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state)
icl_program_gamma_superfine_segment(crtc_state);
icl_program_gamma_multi_segment(crtc_state);
break;
- default:
+ case GAMMA_MODE_MODE_10BIT:
bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
intel_dsb_commit(crtc_state);
@@ -1026,13 +1060,6 @@ static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color)
return drm_color_lut_extract(color->red, 14);
}
-static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
-{
- entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_MASK, ldw), 10);
- entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_MASK, ldw), 10);
- entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_MASK, udw), 10);
-}
-
static void chv_load_cgm_degamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
@@ -1060,6 +1087,13 @@ static u32 chv_cgm_gamma_udw(const struct drm_color_lut *color)
return drm_color_lut_extract(color->red, 10);
}
+static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
+{
+ entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_MASK, ldw), 10);
+ entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_MASK, ldw), 10);
+ entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_MASK, udw), 10);
+}
+
static void chv_load_cgm_gamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
@@ -1733,7 +1767,7 @@ bool intel_color_lut_equal(struct drm_property_blob *blob1,
break;
default:
MISSING_CASE(gamma_mode);
- return false;
+ return false;
}
return true;
@@ -1913,23 +1947,34 @@ static void ilk_read_luts(struct intel_crtc_state *crtc_state)
if ((crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0)
return;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
- else
+ break;
+ case GAMMA_MODE_MODE_10BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_10(crtc);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
-static struct drm_property_blob *glk_read_lut_10(struct intel_crtc *crtc,
+/* On BDW+ the index auto increment mode actually works */
+static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
u32 prec_index)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
int i, hw_lut_size = ivb_lut_10_size(prec_index);
+ int lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
+ drm_WARN_ON(&dev_priv->drm, lut_size != hw_lut_size);
+
blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * hw_lut_size,
+ sizeof(struct drm_color_lut) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1939,7 +1984,7 @@ static struct drm_property_blob *glk_read_lut_10(struct intel_crtc *crtc,
intel_de_write(dev_priv, PREC_PAL_INDEX(pipe),
prec_index | PAL_PREC_AUTO_INCREMENT);
- for (i = 0; i < hw_lut_size; i++) {
+ for (i = 0; i < lut_size; i++) {
u32 val = intel_de_read(dev_priv, PREC_PAL_DATA(pipe));
ilk_lut_10_pack(&lut[i], val);
@@ -1957,10 +2002,17 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state)
if (!crtc_state->gamma_enable)
return;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
- else
- crtc_state->hw.gamma_lut = glk_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
+ case GAMMA_MODE_MODE_10BIT:
+ crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
static struct drm_property_blob *
@@ -2012,11 +2064,15 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
case GAMMA_MODE_MODE_8BIT:
crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
break;
+ case GAMMA_MODE_MODE_10BIT:
+ crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
crtc_state->hw.gamma_lut = icl_read_lut_multi_segment(crtc);
break;
default:
- crtc_state->hw.gamma_lut = glk_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
}
}
diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c
index 157d8c8c605a..d5ad61e4083e 100644
--- a/drivers/gpu/drm/i915/display/intel_combo_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c
@@ -188,8 +188,9 @@ static bool has_phy_misc(struct drm_i915_private *i915, enum phy phy)
* PHY-B and may not even have instances of the register for the
* other combo PHY's.
*/
- if (IS_ELKHARTLAKE(i915) ||
- IS_ROCKETLAKE(i915))
+ if (IS_JSL_EHL(i915) ||
+ IS_ROCKETLAKE(i915) ||
+ IS_DG1(i915))
return phy < PHY_C;
return true;
@@ -242,14 +243,14 @@ static bool phy_is_master(struct drm_i915_private *dev_priv, enum phy phy)
*
* ICL,TGL:
* A(master) -> B(slave), C(slave)
- * RKL:
+ * RKL,DG1:
* A(master) -> B(slave)
* C(master) -> D(slave)
*
* We must set the IREFGEN bit for any PHY acting as a master
* to another PHY.
*/
- if (IS_ROCKETLAKE(dev_priv) && phy == PHY_C)
+ if ((IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) && phy == PHY_C)
return true;
return phy == PHY_A;
@@ -282,7 +283,7 @@ static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW8(phy),
IREFGEN, IREFGEN);
- if (IS_ELKHARTLAKE(dev_priv)) {
+ if (IS_JSL_EHL(dev_priv)) {
if (ehl_vbt_ddi_d_present(dev_priv))
expected_val = ICL_PHY_MISC_MUX_DDID;
@@ -376,7 +377,7 @@ static void icl_combo_phys_init(struct drm_i915_private *dev_priv)
* "internal" child devices.
*/
val = intel_de_read(dev_priv, ICL_PHY_MISC(phy));
- if (IS_ELKHARTLAKE(dev_priv) && phy == PHY_A) {
+ if (IS_JSL_EHL(dev_priv) && phy == PHY_A) {
val &= ~ICL_PHY_MISC_MUX_DDID;
if (ehl_vbt_ddi_d_present(dev_priv))
diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c
index d5db16764619..67dc64df78a5 100644
--- a/drivers/gpu/drm/i915/display/intel_csr.c
+++ b/drivers/gpu/drm/i915/display/intel_csr.c
@@ -40,13 +40,16 @@
#define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE
+#define DG1_CSR_PATH "i915/dg1_dmc_ver2_02.bin"
+#define DG1_CSR_VERSION_REQUIRED CSR_VERSION(2, 2)
+MODULE_FIRMWARE(DG1_CSR_PATH);
+
#define RKL_CSR_PATH "i915/rkl_dmc_ver2_02.bin"
#define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 2)
MODULE_FIRMWARE(RKL_CSR_PATH);
#define TGL_CSR_PATH "i915/tgl_dmc_ver2_08.bin"
#define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 8)
-#define TGL_CSR_MAX_FW_SIZE 0x6000
MODULE_FIRMWARE(TGL_CSR_PATH);
#define ICL_CSR_PATH "i915/icl_dmc_ver1_09.bin"
@@ -686,14 +689,17 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
*/
intel_csr_runtime_pm_get(dev_priv);
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ csr->fw_path = DG1_CSR_PATH;
+ csr->required_version = DG1_CSR_VERSION_REQUIRED;
+ csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
+ } else if (IS_ROCKETLAKE(dev_priv)) {
csr->fw_path = RKL_CSR_PATH;
csr->required_version = RKL_CSR_VERSION_REQUIRED;
csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
} else if (INTEL_GEN(dev_priv) >= 12) {
csr->fw_path = TGL_CSR_PATH;
csr->required_version = TGL_CSR_VERSION_REQUIRED;
- /* Allow to load fw via parameter using the last known size */
csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
} else if (IS_GEN(dev_priv, 11)) {
csr->fw_path = ICL_CSR_PATH;
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index cdcb7b1034ae..92940a0c5ef8 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -28,6 +28,7 @@
#include <drm/drm_scdc_helper.h>
#include "i915_drv.h"
+#include "i915_trace.h"
#include "intel_audio.h"
#include "intel_combo_phy.h"
#include "intel_connector.h"
@@ -582,6 +583,34 @@ static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = {
{ 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */
};
+static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr[] = {
+ /* NT mV Trans mV db */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */
+ { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */
+ { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */
+ { 0xA, 0x35, 0x36, 0x00, 0x09 }, /* 200 350 4.9 */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */
+ { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */
+ { 0xA, 0x35, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */
+ { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */
+ { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */
+ { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
+};
+
+static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2[] = {
+ /* NT mV Trans mV db */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 250 1.9 */
+ { 0x1, 0x7F, 0x3D, 0x00, 0x02 }, /* 200 300 3.5 */
+ { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 200 350 4.9 */
+ { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */
+ { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 300 1.6 */
+ { 0xA, 0x35, 0x3A, 0x00, 0x05 }, /* 250 350 2.9 */
+ { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */
+ { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */
+ { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
+};
+
struct icl_mg_phy_ddi_buf_trans {
u32 cri_txdeemph_override_11_6;
u32 cri_txdeemph_override_5_0;
@@ -1034,133 +1063,286 @@ cnl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries)
}
static const struct cnl_ddi_buf_trans *
-icl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+icl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+icl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
+ return icl_combo_phy_ddi_translations_dp_hbr2;
+}
+
+static const struct cnl_ddi_buf_trans *
+icl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- if (type == INTEL_OUTPUT_HDMI) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
- return icl_combo_phy_ddi_translations_hdmi;
- } else if (rate > 540000 && type == INTEL_OUTPUT_EDP) {
+ if (crtc_state->port_clock > 540000) {
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
return icl_combo_phy_ddi_translations_edp_hbr3;
- } else if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) {
+ } else if (dev_priv->vbt.edp.low_vswing) {
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
return icl_combo_phy_ddi_translations_edp_hbr2;
}
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
- return icl_combo_phy_ddi_translations_dp_hbr2;
+ return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+icl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return icl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
}
static const struct icl_mg_phy_ddi_buf_trans *
-icl_get_mg_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+icl_get_mg_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
- if (type == INTEL_OUTPUT_HDMI) {
- *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi);
- return icl_mg_phy_ddi_translations_hdmi;
- } else if (rate > 270000) {
+ *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi);
+ return icl_mg_phy_ddi_translations_hdmi;
+}
+
+static const struct icl_mg_phy_ddi_buf_trans *
+icl_get_mg_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (crtc_state->port_clock > 270000) {
*n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hbr2_hbr3);
return icl_mg_phy_ddi_translations_hbr2_hbr3;
+ } else {
+ *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr);
+ return icl_mg_phy_ddi_translations_rbr_hbr;
}
+}
+
+static const struct icl_mg_phy_ddi_buf_trans *
+icl_get_mg_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return icl_get_mg_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else
+ return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries);
+}
- *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr);
- return icl_mg_phy_ddi_translations_rbr_hbr;
+static const struct cnl_ddi_buf_trans *
+ehl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
}
static const struct cnl_ddi_buf_trans *
-ehl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+ehl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp);
+ return ehl_combo_phy_ddi_translations_dp;
+}
+
+static const struct cnl_ddi_buf_trans *
+ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- switch (type) {
- case INTEL_OUTPUT_HDMI:
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
- return icl_combo_phy_ddi_translations_hdmi;
- case INTEL_OUTPUT_EDP:
- if (dev_priv->vbt.edp.low_vswing) {
- if (rate > 540000) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
- return icl_combo_phy_ddi_translations_edp_hbr3;
- } else {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
- return icl_combo_phy_ddi_translations_edp_hbr2;
- }
- }
- /* fall through */
- default:
- /* All combo DP and eDP ports that do not support low_vswing */
- *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp);
- return ehl_combo_phy_ddi_translations_dp;
+ if (dev_priv->vbt.edp.low_vswing) {
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
+ return icl_combo_phy_ddi_translations_edp_hbr2;
}
+
+ return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
}
static const struct cnl_ddi_buf_trans *
-tgl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
+ehl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
int *n_entries)
{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return ehl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2);
+ return icl_combo_phy_ddi_translations_dp_hbr2;
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- switch (type) {
- case INTEL_OUTPUT_HDMI:
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
- return icl_combo_phy_ddi_translations_hdmi;
- case INTEL_OUTPUT_EDP:
- if (dev_priv->vbt.edp.hobl) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- if (!intel_dp->hobl_failed && rate <= 540000) {
- /* Same table applies to TGL, RKL and DG1 */
- *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
- return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
- }
+ if (dev_priv->vbt.edp.low_vswing) {
+ if (crtc_state->port_clock > 270000) {
+ *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr2);
+ return jsl_combo_phy_ddi_translations_edp_hbr2;
+ } else {
+ *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr);
+ return jsl_combo_phy_ddi_translations_edp_hbr;
}
+ }
- if (rate > 540000) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
- return icl_combo_phy_ddi_translations_edp_hbr3;
- } else if (dev_priv->vbt.edp.low_vswing) {
- *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
- return icl_combo_phy_ddi_translations_edp_hbr2;
- }
- /* fall through */
- default:
- /* All combo DP and eDP ports that do not support low_vswing */
- if (rate > 270000) {
- if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
- *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
- return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
- }
+ return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+jsl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return jsl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
+ return icl_combo_phy_ddi_translations_hdmi;
+}
+
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (crtc_state->port_clock > 270000) {
+ if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
+ *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
+ return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
+ } else {
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
return tgl_combo_phy_ddi_translations_dp_hbr2;
}
-
+ } else {
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr);
return tgl_combo_phy_ddi_translations_dp_hbr;
}
}
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ if (crtc_state->port_clock > 540000) {
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
+ return icl_combo_phy_ddi_translations_edp_hbr3;
+ } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) {
+ *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
+ return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
+ } else if (dev_priv->vbt.edp.low_vswing) {
+ *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
+ return icl_combo_phy_ddi_translations_edp_hbr2;
+ }
+
+ return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
+static const struct cnl_ddi_buf_trans *
+tgl_get_combo_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries);
+ else
+ return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries);
+}
+
static const struct tgl_dkl_phy_ddi_buf_trans *
-tgl_get_dkl_buf_trans(struct intel_encoder *encoder, int type, int rate,
- int *n_entries)
+tgl_get_dkl_buf_trans_hdmi(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans);
+ return tgl_dkl_phy_hdmi_ddi_trans;
+}
+
+static const struct tgl_dkl_phy_ddi_buf_trans *
+tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
{
- if (type == INTEL_OUTPUT_HDMI) {
- *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans);
- return tgl_dkl_phy_hdmi_ddi_trans;
- } else if (rate > 270000) {
+ if (crtc_state->port_clock > 270000) {
*n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans_hbr2);
return tgl_dkl_phy_dp_ddi_trans_hbr2;
+ } else {
+ *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans);
+ return tgl_dkl_phy_dp_ddi_trans;
}
+}
- *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans);
- return tgl_dkl_phy_dp_ddi_trans;
+static const struct tgl_dkl_phy_ddi_buf_trans *
+tgl_get_dkl_buf_trans(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int *n_entries)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ return tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, n_entries);
+ else
+ return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries);
}
-static int intel_ddi_hdmi_level(struct intel_encoder *encoder)
+static int intel_ddi_hdmi_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
int n_entries, level, default_entry;
@@ -1168,19 +1350,15 @@ static int intel_ddi_hdmi_level(struct intel_encoder *encoder)
if (INTEL_GEN(dev_priv) >= 12) {
if (intel_phy_is_combo(dev_priv, phy))
- tgl_get_combo_buf_trans(encoder, INTEL_OUTPUT_HDMI,
- 0, &n_entries);
+ tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries);
else
- tgl_get_dkl_buf_trans(encoder, INTEL_OUTPUT_HDMI, 0,
- &n_entries);
+ tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries);
default_entry = n_entries - 1;
} else if (INTEL_GEN(dev_priv) == 11) {
if (intel_phy_is_combo(dev_priv, phy))
- icl_get_combo_buf_trans(encoder, INTEL_OUTPUT_HDMI,
- 0, &n_entries);
+ icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries);
else
- icl_get_mg_buf_trans(encoder, INTEL_OUTPUT_HDMI, 0,
- &n_entries);
+ icl_get_mg_buf_trans_hdmi(encoder, crtc_state, &n_entries);
default_entry = n_entries - 1;
} else if (IS_CANNONLAKE(dev_priv)) {
cnl_get_buf_trans_hdmi(encoder, &n_entries);
@@ -1507,14 +1685,15 @@ void hsw_fdi_link_train(struct intel_encoder *encoder,
DP_TP_CTL_ENABLE);
}
-static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
+static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
intel_dp->DP = dig_port->saved_port_bits |
DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
- intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
+ intel_dp->DP |= DDI_PORT_WIDTH(crtc_state->lane_count);
}
static int icl_calc_tbt_pll_link(struct drm_i915_private *dev_priv,
@@ -1577,7 +1756,8 @@ static void intel_ddi_clock_get(struct intel_encoder *encoder,
encoder->port);
else
pipe_config->port_clock =
- intel_dpll_get_freq(dev_priv, pipe_config->shared_dpll);
+ intel_dpll_get_freq(dev_priv, pipe_config->shared_dpll,
+ &pipe_config->dpll_hw_state);
ddi_dotclock_get(pipe_config);
}
@@ -2117,13 +2297,6 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
intel_phy_is_tc(dev_priv, phy))
intel_display_power_get(dev_priv,
intel_ddi_main_link_aux_domain(dig_port));
-
- /*
- * VDSC power is needed when DSC is enabled
- */
- if (crtc_state->dsc.compression_enable)
- intel_display_power_get(dev_priv,
- intel_dsc_power_domain(crtc_state));
}
void intel_ddi_enable_pipe_clock(struct intel_encoder *encoder,
@@ -2178,13 +2351,14 @@ static void _skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
}
static void skl_ddi_set_iboost(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
u8 iboost;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
iboost = intel_bios_hdmi_boost_level(encoder);
else
iboost = intel_bios_dp_boost_level(encoder);
@@ -2193,14 +2367,12 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder,
const struct ddi_buf_trans *ddi_translations;
int n_entries;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
ddi_translations = intel_ddi_get_buf_trans_hdmi(encoder, &n_entries);
- else if (type == INTEL_OUTPUT_EDP)
- ddi_translations = intel_ddi_get_buf_trans_edp(encoder,
- &n_entries);
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
+ ddi_translations = intel_ddi_get_buf_trans_edp(encoder, &n_entries);
else
- ddi_translations = intel_ddi_get_buf_trans_dp(encoder,
- &n_entries);
+ ddi_translations = intel_ddi_get_buf_trans_dp(encoder, &n_entries);
if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
return;
@@ -2223,16 +2395,17 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder,
}
static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
const struct bxt_ddi_buf_trans *ddi_translations;
enum port port = encoder->port;
int n_entries;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
ddi_translations = bxt_get_buf_trans_hdmi(encoder, &n_entries);
- else if (type == INTEL_OUTPUT_EDP)
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
ddi_translations = bxt_get_buf_trans_edp(encoder, &n_entries);
else
ddi_translations = bxt_get_buf_trans_dp(encoder, &n_entries);
@@ -2249,7 +2422,8 @@ static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
ddi_translations[level].deemphasis);
}
-static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp)
+static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2259,33 +2433,30 @@ static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp)
if (INTEL_GEN(dev_priv) >= 12) {
if (intel_phy_is_combo(dev_priv, phy))
- tgl_get_combo_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ tgl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else
- tgl_get_dkl_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
} else if (INTEL_GEN(dev_priv) == 11) {
- if (IS_ELKHARTLAKE(dev_priv))
- ehl_get_combo_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ if (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE))
+ jsl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
+ else if (IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE))
+ ehl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else if (intel_phy_is_combo(dev_priv, phy))
- icl_get_combo_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ icl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else
- icl_get_mg_buf_trans(encoder, encoder->type,
- intel_dp->link_rate, &n_entries);
+ icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
} else if (IS_CANNONLAKE(dev_priv)) {
- if (encoder->type == INTEL_OUTPUT_EDP)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
cnl_get_buf_trans_edp(encoder, &n_entries);
else
cnl_get_buf_trans_dp(encoder, &n_entries);
} else if (IS_GEN9_LP(dev_priv)) {
- if (encoder->type == INTEL_OUTPUT_EDP)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
bxt_get_buf_trans_edp(encoder, &n_entries);
else
bxt_get_buf_trans_dp(encoder, &n_entries);
} else {
- if (encoder->type == INTEL_OUTPUT_EDP)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
intel_ddi_get_buf_trans_edp(encoder, &n_entries);
else
intel_ddi_get_buf_trans_dp(encoder, &n_entries);
@@ -2312,7 +2483,8 @@ static u8 intel_ddi_dp_preemph_max(struct intel_dp *intel_dp)
}
static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
const struct cnl_ddi_buf_trans *ddi_translations;
@@ -2320,9 +2492,9 @@ static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
int n_entries, ln;
u32 val;
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
ddi_translations = cnl_get_buf_trans_hdmi(encoder, &n_entries);
- else if (type == INTEL_OUTPUT_EDP)
+ else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
ddi_translations = cnl_get_buf_trans_edp(encoder, &n_entries);
else
ddi_translations = cnl_get_buf_trans_dp(encoder, &n_entries);
@@ -2376,22 +2548,16 @@ static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
}
static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
- int level, enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum port port = encoder->port;
int width, rate, ln;
u32 val;
- if (type == INTEL_OUTPUT_HDMI) {
- width = 4;
- rate = 0; /* Rate is always < than 6GHz for HDMI */
- } else {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- width = intel_dp->lane_count;
- rate = intel_dp->link_rate;
- }
+ width = crtc_state->lane_count;
+ rate = crtc_state->port_clock;
/*
* 1. If port type is eDP or DP,
@@ -2399,10 +2565,10 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
* else clear to 0b.
*/
val = intel_de_read(dev_priv, CNL_PORT_PCS_DW1_LN0(port));
- if (type != INTEL_OUTPUT_HDMI)
- val |= COMMON_KEEPER_EN;
- else
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
val &= ~COMMON_KEEPER_EN;
+ else
+ val |= COMMON_KEEPER_EN;
intel_de_write(dev_priv, CNL_PORT_PCS_DW1_GRP(port), val);
/* 2. Program loadgen select */
@@ -2434,7 +2600,7 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
intel_de_write(dev_priv, CNL_PORT_TX_DW5_GRP(port), val);
/* 5. Program swing and de-emphasis */
- cnl_ddi_vswing_program(encoder, level, type);
+ cnl_ddi_vswing_program(encoder, crtc_state, level);
/* 6. Set training enable to trigger update */
val = intel_de_read(dev_priv, CNL_PORT_TX_DW5_LN0(port));
@@ -2443,23 +2609,23 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder,
}
static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
- u32 level, int type, int rate)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ const struct cnl_ddi_buf_trans *ddi_translations;
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
- const struct cnl_ddi_buf_trans *ddi_translations = NULL;
- u32 n_entries, val;
- int ln;
+ int n_entries, ln;
+ u32 val;
if (INTEL_GEN(dev_priv) >= 12)
- ddi_translations = tgl_get_combo_buf_trans(encoder, type, rate,
- &n_entries);
- else if (IS_ELKHARTLAKE(dev_priv))
- ddi_translations = ehl_get_combo_buf_trans(encoder, type, rate,
- &n_entries);
+ ddi_translations = tgl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
+ else if (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE))
+ ddi_translations = jsl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
+ else if (IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE))
+ ddi_translations = ehl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
else
- ddi_translations = icl_get_combo_buf_trans(encoder, type, rate,
- &n_entries);
+ ddi_translations = icl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
if (!ddi_translations)
return;
@@ -2470,7 +2636,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
level = n_entries - 1;
}
- if (type == INTEL_OUTPUT_EDP) {
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
val = EDP4K2K_MODE_OVRD_EN | EDP4K2K_MODE_OVRD_OPTIMIZED;
@@ -2518,25 +2684,16 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
}
static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
- u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
- int width = 0;
- int rate = 0;
+ int width, rate, ln;
u32 val;
- int ln = 0;
- if (type == INTEL_OUTPUT_HDMI) {
- width = 4;
- /* Rate is always < than 6GHz for HDMI */
- } else {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- width = intel_dp->lane_count;
- rate = intel_dp->link_rate;
- }
+ width = crtc_state->lane_count;
+ rate = crtc_state->port_clock;
/*
* 1. If port type is eDP or DP,
@@ -2544,7 +2701,7 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
* else clear to 0b.
*/
val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN0(phy));
- if (type == INTEL_OUTPUT_HDMI)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
val &= ~COMMON_KEEPER_EN;
else
val |= COMMON_KEEPER_EN;
@@ -2579,7 +2736,7 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val);
/* 5. Program swing and de-emphasis */
- icl_ddi_combo_vswing_program(encoder, level, type, rate);
+ icl_ddi_combo_vswing_program(encoder, crtc_state, level);
/* 6. Set training enable to trigger update */
val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy));
@@ -2588,23 +2745,16 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
}
static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
- int link_clock, u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port);
const struct icl_mg_phy_ddi_buf_trans *ddi_translations;
- u32 n_entries, val;
- int ln, rate = 0;
-
- if (type != INTEL_OUTPUT_HDMI) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- rate = intel_dp->link_rate;
- }
+ int n_entries, ln;
+ u32 val;
- ddi_translations = icl_get_mg_buf_trans(encoder, type, rate,
- &n_entries);
+ ddi_translations = icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
/* The table does not have values for level 3 and level 9. */
if (level >= n_entries || level == 3 || level == 9) {
drm_dbg_kms(&dev_priv->drm,
@@ -2671,7 +2821,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
*/
for (ln = 0; ln < 2; ln++) {
val = intel_de_read(dev_priv, MG_CLKHUB(ln, tc_port));
- if (link_clock < 300000)
+ if (crtc_state->port_clock < 300000)
val |= CFG_LOW_RATE_LKREN_EN;
else
val &= ~CFG_LOW_RATE_LKREN_EN;
@@ -2682,7 +2832,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
for (ln = 0; ln < 2; ln++) {
val = intel_de_read(dev_priv, MG_TX1_DCC(ln, tc_port));
val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
- if (link_clock <= 500000) {
+ if (crtc_state->port_clock <= 500000) {
val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
} else {
val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
@@ -2692,7 +2842,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
val = intel_de_read(dev_priv, MG_TX2_DCC(ln, tc_port));
val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
- if (link_clock <= 500000) {
+ if (crtc_state->port_clock <= 500000) {
val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
} else {
val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
@@ -2718,38 +2868,30 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
}
static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
- int link_clock,
- u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
if (intel_phy_is_combo(dev_priv, phy))
- icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
+ icl_combo_phy_ddi_vswing_sequence(encoder, crtc_state, level);
else
- icl_mg_phy_ddi_vswing_sequence(encoder, link_clock, level,
- type);
+ icl_mg_phy_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int link_clock,
- u32 level, enum intel_output_type type)
+tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port);
const struct tgl_dkl_phy_ddi_buf_trans *ddi_translations;
- u32 n_entries, val, ln, dpcnt_mask, dpcnt_val;
- int rate = 0;
-
- if (type != INTEL_OUTPUT_HDMI) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- rate = intel_dp->link_rate;
- }
+ u32 val, dpcnt_mask, dpcnt_val;
+ int n_entries, ln;
- ddi_translations = tgl_get_dkl_buf_trans(encoder, encoder->type, rate,
- &n_entries);
+ ddi_translations = tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
if (level >= n_entries)
level = n_entries - 1;
@@ -2785,20 +2927,20 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int link_clock,
}
static void tgl_ddi_vswing_sequence(struct intel_encoder *encoder,
- int link_clock,
- u32 level,
- enum intel_output_type type)
+ const struct intel_crtc_state *crtc_state,
+ int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
if (intel_phy_is_combo(dev_priv, phy))
- icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
+ icl_combo_phy_ddi_vswing_sequence(encoder, crtc_state, level);
else
- tgl_dkl_phy_ddi_vswing_sequence(encoder, link_clock, level, type);
+ tgl_dkl_phy_ddi_vswing_sequence(encoder, crtc_state, level);
}
-static u32 translate_signal_level(struct intel_dp *intel_dp, int signal_levels)
+static int translate_signal_level(struct intel_dp *intel_dp,
+ u8 signal_levels)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int i;
@@ -2815,55 +2957,58 @@ static u32 translate_signal_level(struct intel_dp *intel_dp, int signal_levels)
return 0;
}
-static u32 intel_ddi_dp_level(struct intel_dp *intel_dp)
+static int intel_ddi_dp_level(struct intel_dp *intel_dp)
{
u8 train_set = intel_dp->train_set[0];
- int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
- DP_TRAIN_PRE_EMPHASIS_MASK);
+ u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+ DP_TRAIN_PRE_EMPHASIS_MASK);
return translate_signal_level(intel_dp, signal_levels);
}
static void
-tgl_set_signal_levels(struct intel_dp *intel_dp)
+tgl_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- tgl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
- level, encoder->type);
+ tgl_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-icl_set_signal_levels(struct intel_dp *intel_dp)
+icl_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- icl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
- level, encoder->type);
+ icl_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-cnl_set_signal_levels(struct intel_dp *intel_dp)
+cnl_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- cnl_ddi_vswing_sequence(encoder, level, encoder->type);
+ cnl_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-bxt_set_signal_levels(struct intel_dp *intel_dp)
+bxt_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
- bxt_ddi_vswing_sequence(encoder, level, encoder->type);
+ bxt_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
-hsw_set_signal_levels(struct intel_dp *intel_dp)
+hsw_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2880,7 +3025,7 @@ hsw_set_signal_levels(struct intel_dp *intel_dp)
intel_dp->DP |= signal_levels;
if (IS_GEN9_BC(dev_priv))
- skl_ddi_set_iboost(encoder, level, encoder->type);
+ skl_ddi_set_iboost(encoder, crtc_state, level);
intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
intel_de_posting_read(dev_priv, DDI_BUF_CTL(port));
@@ -2903,6 +3048,40 @@ static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv,
return 0;
}
+static void dg1_map_plls_to_ports(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+ enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
+ u32 val;
+
+ /*
+ * If we fail this, something went very wrong: first 2 PLLs should be
+ * used by first 2 phys and last 2 PLLs by last phys
+ */
+ if (drm_WARN_ON(&dev_priv->drm,
+ (pll->info->id < DPLL_ID_DG1_DPLL2 && phy >= PHY_C) ||
+ (pll->info->id >= DPLL_ID_DG1_DPLL2 && phy < PHY_C)))
+ return;
+
+ mutex_lock(&dev_priv->dpll.lock);
+
+ val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy));
+ drm_WARN_ON(&dev_priv->drm,
+ (val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)) == 0);
+
+ val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ val |= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy);
+ intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val);
+ intel_de_posting_read(dev_priv, DG1_DPCLKA_CFGCR0(phy));
+
+ val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+ intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val);
+
+ mutex_unlock(&dev_priv->dpll.lock);
+}
+
static void icl_map_plls_to_ports(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
@@ -2950,6 +3129,19 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder,
mutex_unlock(&dev_priv->dpll.lock);
}
+static void dg1_unmap_plls_to_ports(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
+
+ mutex_lock(&dev_priv->dpll.lock);
+
+ intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), 0,
+ DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy));
+
+ mutex_unlock(&dev_priv->dpll.lock);
+}
+
static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2965,6 +3157,37 @@ static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpll.lock);
}
+static void dg1_sanitize_port_clk_off(struct drm_i915_private *dev_priv,
+ u32 port_mask, bool ddi_clk_needed)
+{
+ enum port port;
+ u32 val;
+
+ for_each_port_masked(port, port_mask) {
+ enum phy phy = intel_port_to_phy(dev_priv, port);
+ bool ddi_clk_off;
+
+ val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy));
+ ddi_clk_off = val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+
+ if (ddi_clk_needed == !ddi_clk_off)
+ continue;
+
+ /*
+ * Punt on the case now where clock is gated, but it would
+ * be needed by the port. Something else is really broken then.
+ */
+ if (drm_WARN_ON(&dev_priv->drm, ddi_clk_needed))
+ continue;
+
+ drm_notice(&dev_priv->drm,
+ "PHY %c is disabled with an ungated DDI clock, gate it\n",
+ phy_name(phy));
+ val |= DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+ intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val);
+ }
+}
+
static void icl_sanitize_port_clk_off(struct drm_i915_private *dev_priv,
u32 port_mask, bool ddi_clk_needed)
{
@@ -3047,7 +3270,10 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder)
ddi_clk_needed = false;
}
- icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed);
+ if (IS_DG1(dev_priv))
+ dg1_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed);
+ else
+ icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed);
}
static void intel_ddi_clk_select(struct intel_encoder *encoder,
@@ -3068,7 +3294,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,
if (!intel_phy_is_combo(dev_priv, phy))
intel_de_write(dev_priv, DDI_CLK_SEL(port),
icl_pll_to_ddi_clk_sel(encoder, crtc_state));
- else if (IS_ELKHARTLAKE(dev_priv) && port >= PORT_C)
+ else if (IS_JSL_EHL(dev_priv) && port >= PORT_C)
/*
* MG does not exist but the programming is required
* to ungate DDIC and DDID
@@ -3117,7 +3343,7 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder)
if (INTEL_GEN(dev_priv) >= 11) {
if (!intel_phy_is_combo(dev_priv, phy) ||
- (IS_ELKHARTLAKE(dev_priv) && port >= PORT_C))
+ (IS_JSL_EHL(dev_priv) && port >= PORT_C))
intel_de_write(dev_priv, DDI_CLK_SEL(port),
DDI_CLK_SEL_NONE);
} else if (IS_CANNONLAKE(dev_priv)) {
@@ -3223,6 +3449,37 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port,
}
}
+static enum transcoder
+tgl_dp_tp_transcoder(const struct intel_crtc_state *crtc_state)
+{
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
+ return crtc_state->mst_master_transcoder;
+ else
+ return crtc_state->cpu_transcoder;
+}
+
+i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (INTEL_GEN(dev_priv) >= 12)
+ return TGL_DP_TP_CTL(tgl_dp_tp_transcoder(crtc_state));
+ else
+ return DP_TP_CTL(encoder->port);
+}
+
+i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (INTEL_GEN(dev_priv) >= 12)
+ return TGL_DP_TP_STATUS(tgl_dp_tp_transcoder(crtc_state));
+ else
+ return DP_TP_STATUS(encoder->port);
+}
+
static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
@@ -3247,11 +3504,12 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder,
return;
intel_dp = enc_to_intel_dp(encoder);
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val |= DP_TP_CTL_FEC_ENABLE;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
- if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
+ if (intel_de_wait_for_set(dev_priv,
+ dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_FEC_ENABLE_LIVE, 1))
drm_err(&dev_priv->drm,
"Timed out waiting for FEC Enable Status\n");
@@ -3268,10 +3526,10 @@ static void intel_ddi_disable_fec_state(struct intel_encoder *encoder,
return;
intel_dp = enc_to_intel_dp(encoder);
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val &= ~DP_TP_CTL_FEC_ENABLE;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
- intel_de_posting_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
+ intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
}
static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3285,13 +3543,10 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
int level = intel_ddi_dp_level(intel_dp);
- enum transcoder transcoder = crtc_state->cpu_transcoder;
- intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
- crtc_state->lane_count, is_mst);
-
- intel_dp->regs.dp_tp_ctl = TGL_DP_TP_CTL(transcoder);
- intel_dp->regs.dp_tp_status = TGL_DP_TP_STATUS(transcoder);
+ intel_dp_set_link_params(intel_dp,
+ crtc_state->port_clock,
+ crtc_state->lane_count);
/*
* 1. Enable Power Wells
@@ -3360,8 +3615,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
*/
/* 7.e Configure voltage swing and related IO settings */
- tgl_ddi_vswing_sequence(encoder, crtc_state->port_clock, level,
- encoder->type);
+ tgl_ddi_vswing_sequence(encoder, crtc_state, level);
/*
* 7.f Combo PHY: Configure PORT_CL_DW10 Static Power Down to power up
@@ -3384,10 +3638,10 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
* We only configure what the register value will be here. Actual
* enabling happens during link training farther down.
*/
- intel_ddi_init_dp_buf_reg(encoder);
+ intel_ddi_init_dp_buf_reg(encoder, crtc_state);
if (!is_mst)
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
/*
@@ -3404,15 +3658,16 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
* Pattern, wait for 5 idle patterns (DP_TP_STATUS Min_Idles_Sent)
* (timeout after 800 us)
*/
- intel_dp_start_link_train(intel_dp);
+ intel_dp_start_link_train(intel_dp, crtc_state);
/* 7.k Set DP_TP_CTL link training to Normal */
if (!is_trans_port_sync_mode(crtc_state))
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
/* 7.l Configure and enable FEC if needed */
intel_ddi_enable_fec(encoder, crtc_state);
- intel_dsc_enable(encoder, crtc_state);
+ if (!crtc_state->bigjoiner)
+ intel_dsc_enable(encoder, crtc_state);
}
static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3434,8 +3689,9 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
else
drm_WARN_ON(&dev_priv->drm, is_mst && port == PORT_A);
- intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
- crtc_state->lane_count, is_mst);
+ intel_dp_set_link_params(intel_dp,
+ crtc_state->port_clock,
+ crtc_state->lane_count);
intel_edp_panel_on(intel_dp);
@@ -3449,12 +3705,11 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
icl_program_mg_dp_mode(dig_port, crtc_state);
if (INTEL_GEN(dev_priv) >= 11)
- icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
- level, encoder->type);
+ icl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_CANNONLAKE(dev_priv))
- cnl_ddi_vswing_sequence(encoder, level, encoder->type);
+ cnl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_GEN9_LP(dev_priv))
- bxt_ddi_vswing_sequence(encoder, level, encoder->type);
+ bxt_ddi_vswing_sequence(encoder, crtc_state, level);
else
intel_prepare_dp_ddi_buffers(encoder, crtc_state);
@@ -3467,24 +3722,25 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
lane_reversal);
}
- intel_ddi_init_dp_buf_reg(encoder);
+ intel_ddi_init_dp_buf_reg(encoder, crtc_state);
if (!is_mst)
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
true);
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
- intel_dp_start_link_train(intel_dp);
+ intel_dp_start_link_train(intel_dp, crtc_state);
if ((port != PORT_A || INTEL_GEN(dev_priv) >= 9) &&
!is_trans_port_sync_mode(crtc_state))
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
intel_ddi_enable_fec(encoder, crtc_state);
if (!is_mst)
intel_ddi_enable_pipe_clock(encoder, crtc_state);
- intel_dsc_enable(encoder, crtc_state);
+ if (!crtc_state->bigjoiner)
+ intel_dsc_enable(encoder, crtc_state);
}
static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3517,7 +3773,7 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state,
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- int level = intel_ddi_hdmi_level(encoder);
+ int level = intel_ddi_hdmi_level(encoder, crtc_state);
intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
intel_ddi_clk_select(encoder, crtc_state);
@@ -3527,20 +3783,18 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state,
icl_program_mg_dp_mode(dig_port, crtc_state);
if (INTEL_GEN(dev_priv) >= 12)
- tgl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
- level, INTEL_OUTPUT_HDMI);
+ tgl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (INTEL_GEN(dev_priv) == 11)
- icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
- level, INTEL_OUTPUT_HDMI);
+ icl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_CANNONLAKE(dev_priv))
- cnl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+ cnl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (IS_GEN9_LP(dev_priv))
- bxt_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+ bxt_ddi_vswing_sequence(encoder, crtc_state, level);
else
intel_prepare_hdmi_ddi_buffers(encoder, level);
if (IS_GEN9_BC(dev_priv))
- skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI);
+ skl_ddi_set_iboost(encoder, crtc_state, level);
intel_ddi_enable_pipe_clock(encoder, crtc_state);
@@ -3573,7 +3827,9 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state,
drm_WARN_ON(&dev_priv->drm, crtc_state->has_pch_encoder);
- if (INTEL_GEN(dev_priv) >= 11)
+ if (IS_DG1(dev_priv))
+ dg1_map_plls_to_ports(encoder, crtc_state);
+ else if (INTEL_GEN(dev_priv) >= 11)
icl_map_plls_to_ports(encoder, crtc_state);
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
@@ -3612,12 +3868,10 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,
}
if (intel_crtc_has_dp_encoder(crtc_state)) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
val |= DP_TP_CTL_LINK_TRAIN_PAT1;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
}
/* Disable FEC in DP Sink */
@@ -3647,7 +3901,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
* Power down sink before disabling the port, otherwise we end
* up getting interrupts from the sink on detecting link loss.
*/
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D3);
if (INTEL_GEN(dev_priv) >= 12) {
if (is_mst) {
@@ -3737,6 +3991,21 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
ilk_pfit_disable(old_crtc_state);
}
+ if (old_crtc_state->bigjoiner_linked_crtc) {
+ struct intel_atomic_state *state =
+ to_intel_atomic_state(old_crtc_state->uapi.state);
+ struct intel_crtc *slave =
+ old_crtc_state->bigjoiner_linked_crtc;
+ const struct intel_crtc_state *old_slave_crtc_state =
+ intel_atomic_get_old_crtc_state(state, slave);
+
+ intel_crtc_vblank_off(old_slave_crtc_state);
+ trace_intel_pipe_disable(slave);
+
+ intel_dsc_disable(old_slave_crtc_state);
+ skl_scaler_disable(old_slave_crtc_state);
+ }
+
/*
* When called from DP MST code:
* - old_conn_state will be NULL
@@ -3757,7 +4026,9 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
intel_ddi_post_disable_dp(state, encoder, old_crtc_state,
old_conn_state);
- if (INTEL_GEN(dev_priv) >= 11)
+ if (IS_DG1(dev_priv))
+ dg1_unmap_plls_to_ports(encoder);
+ else if (INTEL_GEN(dev_priv) >= 11)
icl_unmap_plls_to_ports(encoder);
if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port)
@@ -3830,12 +4101,14 @@ static void trans_port_sync_stop_link_train(struct intel_atomic_state *state,
crtc_state->cpu_transcoder)
continue;
- intel_dp_stop_link_train(enc_to_intel_dp(slave_encoder));
+ intel_dp_stop_link_train(enc_to_intel_dp(slave_encoder),
+ slave_crtc_state);
}
usleep_range(200, 400);
- intel_dp_stop_link_train(enc_to_intel_dp(encoder));
+ intel_dp_stop_link_train(enc_to_intel_dp(encoder),
+ crtc_state);
}
static void intel_enable_ddi_dp(struct intel_atomic_state *state,
@@ -3848,7 +4121,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
enum port port = encoder->port;
if (port == PORT_A && INTEL_GEN(dev_priv) < 9)
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
intel_edp_backlight_on(crtc_state, conn_state);
intel_psr_enable(intel_dp, crtc_state, conn_state);
@@ -3951,7 +4224,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
{
drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
- intel_ddi_enable_transcoder_func(encoder, crtc_state);
+ if (!crtc_state->bigjoiner_slave)
+ intel_ddi_enable_transcoder_func(encoder, crtc_state);
intel_enable_pipe(crtc_state);
@@ -4109,15 +4383,16 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state,
crtc_state->lane_lat_optim_mask);
}
-static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
+static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
- struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
- enum port port = dig_port->base.port;
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum port port = encoder->port;
u32 dp_tp_ctl, ddi_buf_ctl;
bool wait = false;
- dp_tp_ctl = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ dp_tp_ctl = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
if (dp_tp_ctl & DP_TP_CTL_ENABLE) {
ddi_buf_ctl = intel_de_read(dev_priv, DDI_BUF_CTL(port));
@@ -4129,23 +4404,23 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
dp_tp_ctl &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
dp_tp_ctl |= DP_TP_CTL_LINK_TRAIN_PAT1;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, dp_tp_ctl);
- intel_de_posting_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl);
+ intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
if (wait)
intel_wait_ddi_buf_idle(dev_priv, port);
}
dp_tp_ctl = DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT1;
- if (intel_dp->link_mst)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
dp_tp_ctl |= DP_TP_CTL_MODE_MST;
- else {
+ } else {
dp_tp_ctl |= DP_TP_CTL_MODE_SST;
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
}
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, dp_tp_ctl);
- intel_de_posting_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl);
+ intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
intel_dp->DP |= DDI_BUF_CTL_ENABLE;
intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
@@ -4155,16 +4430,17 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
}
static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
u32 temp;
- temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ temp = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
- switch (dp_train_pat & train_pat_mask) {
+ switch (intel_dp_training_pattern_symbol(dp_train_pat)) {
case DP_TRAINING_PATTERN_DISABLE:
temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
break;
@@ -4182,20 +4458,21 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
break;
}
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, temp);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), temp);
}
-static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp)
+static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum port port = encoder->port;
u32 val;
- val = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
+ val = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
val &= ~DP_TP_CTL_LINK_TRAIN_MASK;
val |= DP_TP_CTL_LINK_TRAIN_IDLE;
- intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, val);
+ intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), val);
/*
* Until TGL on PORT_A we can have only eDP in SST mode. There the only
@@ -4207,7 +4484,8 @@ static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp)
if (port == PORT_A && INTEL_GEN(dev_priv) < 12)
return;
- if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
+ if (intel_de_wait_for_set(dev_priv,
+ dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_IDLE_DONE, 1))
drm_err(&dev_priv->drm,
"Timed out waiting for DP idle patterns\n");
@@ -4231,7 +4509,7 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
{
if (INTEL_GEN(dev_priv) >= 12 && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 2;
- else if (IS_ELKHARTLAKE(dev_priv) && crtc_state->port_clock > 594000)
+ else if (IS_JSL_EHL(dev_priv) && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 3;
else if (INTEL_GEN(dev_priv) >= 11 && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 1;
@@ -4299,21 +4577,14 @@ static void bdw_get_trans_port_sync_config(struct intel_crtc_state *crtc_state)
crtc_state->sync_mode_slaves_mask);
}
-void intel_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *pipe_config)
+static void intel_ddi_read_func_ctl(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc);
enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
u32 temp, flags = 0;
- /* XXX: DSI transcoder paranoia */
- if (drm_WARN_ON(&dev_priv->drm, transcoder_is_dsi(cpu_transcoder)))
- return;
-
- intel_dsc_get_config(encoder, pipe_config);
-
temp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (temp & TRANS_DDI_PHSYNC)
flags |= DRM_MODE_FLAG_PHSYNC;
@@ -4375,12 +4646,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
intel_dp_get_m_n(intel_crtc, pipe_config);
if (INTEL_GEN(dev_priv) >= 11) {
- i915_reg_t dp_tp_ctl;
-
- if (IS_GEN(dev_priv, 11))
- dp_tp_ctl = DP_TP_CTL(encoder->port);
- else
- dp_tp_ctl = TGL_DP_TP_CTL(pipe_config->cpu_transcoder);
+ i915_reg_t dp_tp_ctl = dp_tp_ctl_reg(encoder, pipe_config);
pipe_config->fec_enable =
intel_de_read(dev_priv, dp_tp_ctl) & DP_TP_CTL_FEC_ENABLE;
@@ -4412,15 +4678,29 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
default:
break;
}
+}
- if (INTEL_GEN(dev_priv) >= 12) {
- enum transcoder transcoder =
- intel_dp_mst_is_slave_trans(pipe_config) ?
- pipe_config->mst_master_transcoder :
- pipe_config->cpu_transcoder;
+void intel_ddi_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
- intel_dp->regs.dp_tp_ctl = TGL_DP_TP_CTL(transcoder);
- intel_dp->regs.dp_tp_status = TGL_DP_TP_STATUS(transcoder);
+ /* XXX: DSI transcoder paranoia */
+ if (drm_WARN_ON(&dev_priv->drm, transcoder_is_dsi(cpu_transcoder)))
+ return;
+
+ if (pipe_config->bigjoiner_slave) {
+ /* read out pipe settings from master */
+ enum transcoder save = pipe_config->cpu_transcoder;
+
+ /* Our own transcoder needs to be disabled when reading it in intel_ddi_read_func_ctl() */
+ WARN_ON(pipe_config->output_types);
+ pipe_config->cpu_transcoder = (enum transcoder)pipe_config->bigjoiner_linked_crtc->pipe;
+ intel_ddi_read_func_ctl(encoder, pipe_config);
+ pipe_config->cpu_transcoder = save;
+ } else {
+ intel_ddi_read_func_ctl(encoder, pipe_config);
}
pipe_config->has_audio =
@@ -4447,7 +4727,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
}
- intel_ddi_clock_get(encoder, pipe_config);
+ if (!pipe_config->bigjoiner_slave)
+ intel_ddi_clock_get(encoder, pipe_config);
if (IS_GEN9_LP(dev_priv))
pipe_config->lane_lat_optim_mask =
@@ -4477,6 +4758,22 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
}
+static void intel_ddi_sync_state(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ if (intel_crtc_has_dp_encoder(crtc_state))
+ intel_dp_sync_state(encoder, crtc_state);
+}
+
+static bool intel_ddi_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ if (intel_crtc_has_dp_encoder(crtc_state))
+ return intel_dp_initial_fastset_check(encoder, crtc_state);
+
+ return true;
+}
+
static enum intel_output_type
intel_ddi_compute_output_type(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
@@ -4687,11 +4984,6 @@ intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
dig_port->dp.voltage_max = intel_ddi_dp_voltage_max;
dig_port->dp.preemph_max = intel_ddi_dp_preemph_max;
- if (INTEL_GEN(dev_priv) < 12) {
- dig_port->dp.regs.dp_tp_ctl = DP_TP_CTL(port);
- dig_port->dp.regs.dp_tp_status = DP_TP_STATUS(port);
- }
-
if (!intel_dp_init_connector(dig_port, connector)) {
kfree(connector);
return NULL;
@@ -4974,11 +5266,20 @@ static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
i915->hti_state & HDPORT_PHY_USED_HDMI(phy));
}
+static enum hpd_pin dg1_hpd_pin(struct drm_i915_private *dev_priv,
+ enum port port)
+{
+ if (port >= PORT_TC1)
+ return HPD_PORT_C + port - PORT_TC1;
+ else
+ return HPD_PORT_A + port - PORT_A;
+}
+
static enum hpd_pin tgl_hpd_pin(struct drm_i915_private *dev_priv,
enum port port)
{
- if (port >= PORT_D)
- return HPD_PORT_TC1 + port - PORT_D;
+ if (port >= PORT_TC1)
+ return HPD_PORT_TC1 + port - PORT_TC1;
else
return HPD_PORT_A + port - PORT_A;
}
@@ -4989,8 +5290,8 @@ static enum hpd_pin rkl_hpd_pin(struct drm_i915_private *dev_priv,
if (HAS_PCH_TGP(dev_priv))
return tgl_hpd_pin(dev_priv, port);
- if (port >= PORT_D)
- return HPD_PORT_C + port - PORT_D;
+ if (port >= PORT_TC1)
+ return HPD_PORT_C + port - PORT_TC1;
else
return HPD_PORT_A + port - PORT_A;
}
@@ -5025,11 +5326,14 @@ static enum hpd_pin cnl_hpd_pin(struct drm_i915_private *dev_priv,
return HPD_PORT_A + port - PORT_A;
}
+#define port_tc_name(port) ((port) - PORT_TC1 + '1')
+#define tc_port_name(tc_port) ((tc_port) - TC_PORT_1 + '1')
+
void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
{
struct intel_digital_port *dig_port;
struct intel_encoder *encoder;
- bool init_hdmi, init_dp, init_lspcon = false;
+ bool init_hdmi, init_dp;
enum phy phy = intel_port_to_phy(dev_priv, port);
/*
@@ -5055,7 +5359,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
* is initialized before lspcon.
*/
init_dp = true;
- init_lspcon = true;
init_hdmi = false;
drm_dbg_kms(&dev_priv->drm, "VBT says port %c has lspcon\n",
port_name(port));
@@ -5074,8 +5377,31 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
encoder = &dig_port->base;
- drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
- DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
+ if (INTEL_GEN(dev_priv) >= 12) {
+ enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS,
+ "DDI %s%c/PHY %s%c",
+ port >= PORT_TC1 ? "TC" : "",
+ port >= PORT_TC1 ? port_tc_name(port) : port_name(port),
+ tc_port != TC_PORT_NONE ? "TC" : "",
+ tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
+ } else if (INTEL_GEN(dev_priv) >= 11) {
+ enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS,
+ "DDI %c%s/PHY %s%c",
+ port_name(port),
+ port >= PORT_C ? " (TC)" : "",
+ tc_port != TC_PORT_NONE ? "TC" : "",
+ tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
+ } else {
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS,
+ "DDI %c/PHY %c", port_name(port), phy_name(phy));
+ }
mutex_init(&dig_port->hdcp_mutex);
dig_port->num_hdcp_streams = 0;
@@ -5092,7 +5418,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
encoder->update_pipe = intel_ddi_update_pipe;
encoder->get_hw_state = intel_ddi_get_hw_state;
encoder->get_config = intel_ddi_get_config;
+ encoder->sync_state = intel_ddi_sync_state;
+ encoder->initial_fastset_check = intel_ddi_initial_fastset_check;
encoder->suspend = intel_dp_encoder_suspend;
+ encoder->shutdown = intel_dp_encoder_shutdown;
encoder->get_power_domains = intel_ddi_get_power_domains;
encoder->type = INTEL_OUTPUT_DDI;
@@ -5101,11 +5430,13 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
encoder->cloneable = 0;
encoder->pipe_mask = ~0;
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv))
+ encoder->hpd_pin = dg1_hpd_pin(dev_priv, port);
+ else if (IS_ROCKETLAKE(dev_priv))
encoder->hpd_pin = rkl_hpd_pin(dev_priv, port);
else if (INTEL_GEN(dev_priv) >= 12)
encoder->hpd_pin = tgl_hpd_pin(dev_priv, port);
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
encoder->hpd_pin = ehl_hpd_pin(dev_priv, port);
else if (IS_GEN(dev_priv, 11))
encoder->hpd_pin = icl_hpd_pin(dev_priv, port);
@@ -5156,22 +5487,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
goto err;
}
- if (init_lspcon) {
- if (lspcon_init(dig_port))
- /* TODO: handle hdmi info frame part */
- drm_dbg_kms(&dev_priv->drm,
- "LSPCON init success on port %c\n",
- port_name(port));
- else
- /*
- * LSPCON init faied, but DP init was success, so
- * lets try to drive as DP++ port.
- */
- drm_err(&dev_priv->drm,
- "LSPCON init failed on port %c\n",
- port_name(port));
- }
-
if (INTEL_GEN(dev_priv) >= 11) {
if (intel_phy_is_tc(dev_priv, phy))
dig_port->connected = intel_tc_port_connected;
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h
index f5fb62fc9400..dcc711cfe4fe 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.h
+++ b/drivers/gpu/drm/i915/display/intel_ddi.h
@@ -7,6 +7,7 @@
#define __INTEL_DDI_H__
#include "intel_display.h"
+#include "i915_reg.h"
struct drm_connector_state;
struct drm_i915_private;
@@ -18,6 +19,10 @@ struct intel_dpll_hw_state;
struct intel_encoder;
enum transcoder;
+i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
void intel_ddi_fdi_post_disable(struct intel_atomic_state *state,
struct intel_encoder *intel_encoder,
const struct intel_crtc_state *old_crtc_state,
@@ -41,8 +46,10 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
bool state);
void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
struct intel_crtc_state *crtc_state);
-u32 bxt_signal_levels(struct intel_dp *intel_dp);
-u32 ddi_signal_levels(struct intel_dp *intel_dp);
+u32 bxt_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+u32 ddi_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
enum transcoder cpu_transcoder,
bool enable);
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index aabf09f89cad..53a00cf3fa32 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -154,7 +154,7 @@ static void ilk_pch_clock_get(struct intel_crtc *crtc,
static int intel_framebuffer_init(struct intel_framebuffer *ifb,
struct drm_i915_gem_object *obj,
struct drm_mode_fb_cmd2 *mode_cmd);
-static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state);
+static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state);
static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state);
static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
const struct intel_link_m_n *m_n,
@@ -1808,6 +1808,17 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ u32 mode_flags = crtc->mode_flags;
+
+ /*
+ * From Gen 11, In case of dsi cmd mode, frame counter wouldnt
+ * have updated at the beginning of TE, if we want to use
+ * the hw counter, then we would find it updated in only
+ * the next TE, hence switching to sw counter.
+ */
+ if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
+ return 0;
/*
* On i965gm the hardware frame counter reads
@@ -1990,13 +2001,17 @@ static int ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
return ccs_plane - fb->format->num_planes / 2;
}
-/* Return either the main plane's CCS or - if not a CCS FB - UV plane */
int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
{
+ struct drm_i915_private *i915 = to_i915(fb->dev);
+
if (is_ccs_modifier(fb->modifier))
return main_to_ccs_plane(fb, main_plane);
-
- return 1;
+ else if (INTEL_GEN(i915) < 11 &&
+ intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
+ return 1;
+ else
+ return 0;
}
bool
@@ -3616,6 +3631,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
struct intel_plane *intel_plane = to_intel_plane(primary);
struct intel_plane_state *intel_state =
to_intel_plane_state(plane_state);
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(intel_crtc->base.state);
struct drm_framebuffer *fb;
struct i915_vma *vma;
@@ -3638,7 +3655,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
if (c == &intel_crtc->base)
continue;
- if (!to_intel_crtc(c)->active)
+ if (!to_intel_crtc_state(c->state)->uapi.active)
continue;
state = to_intel_plane_state(c->primary->state);
@@ -3660,6 +3677,11 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
* pretend the BIOS never had it enabled.
*/
intel_plane_disable_noatomic(intel_crtc, intel_plane);
+ if (crtc_state->bigjoiner) {
+ struct intel_crtc *slave =
+ crtc_state->bigjoiner_linked_crtc;
+ intel_plane_disable_noatomic(slave, to_intel_plane(slave->base.primary));
+ }
return;
@@ -3696,7 +3718,8 @@ valid_fb:
drm_framebuffer_get(fb);
plane_state->crtc = &intel_crtc->base;
- intel_plane_copy_uapi_to_hw_state(intel_state, intel_state);
+ intel_plane_copy_uapi_to_hw_state(intel_state, intel_state,
+ intel_crtc);
intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
@@ -3704,127 +3727,6 @@ valid_fb:
&to_intel_frontbuffer(fb)->bits);
}
-static int skl_max_plane_width(const struct drm_framebuffer *fb,
- int color_plane,
- unsigned int rotation)
-{
- int cpp = fb->format->cpp[color_plane];
-
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_LINEAR:
- case I915_FORMAT_MOD_X_TILED:
- /*
- * Validated limit is 4k, but has 5k should
- * work apart from the following features:
- * - Ytile (already limited to 4k)
- * - FP16 (already limited to 4k)
- * - render compression (already limited to 4k)
- * - KVMR sprite and cursor (don't care)
- * - horizontal panning (TODO verify this)
- * - pipe and plane scaling (TODO verify this)
- */
- if (cpp == 8)
- return 4096;
- else
- return 5120;
- case I915_FORMAT_MOD_Y_TILED_CCS:
- case I915_FORMAT_MOD_Yf_TILED_CCS:
- case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
- /* FIXME AUX plane? */
- case I915_FORMAT_MOD_Y_TILED:
- case I915_FORMAT_MOD_Yf_TILED:
- if (cpp == 8)
- return 2048;
- else
- return 4096;
- default:
- MISSING_CASE(fb->modifier);
- return 2048;
- }
-}
-
-static int glk_max_plane_width(const struct drm_framebuffer *fb,
- int color_plane,
- unsigned int rotation)
-{
- int cpp = fb->format->cpp[color_plane];
-
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_LINEAR:
- case I915_FORMAT_MOD_X_TILED:
- if (cpp == 8)
- return 4096;
- else
- return 5120;
- case I915_FORMAT_MOD_Y_TILED_CCS:
- case I915_FORMAT_MOD_Yf_TILED_CCS:
- /* FIXME AUX plane? */
- case I915_FORMAT_MOD_Y_TILED:
- case I915_FORMAT_MOD_Yf_TILED:
- if (cpp == 8)
- return 2048;
- else
- return 5120;
- default:
- MISSING_CASE(fb->modifier);
- return 2048;
- }
-}
-
-static int icl_min_plane_width(const struct drm_framebuffer *fb)
-{
- /* Wa_14011264657, Wa_14011050563: gen11+ */
- switch (fb->format->format) {
- case DRM_FORMAT_C8:
- return 18;
- case DRM_FORMAT_RGB565:
- return 10;
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ARGB2101010:
- case DRM_FORMAT_ABGR2101010:
- case DRM_FORMAT_XVYU2101010:
- case DRM_FORMAT_Y212:
- case DRM_FORMAT_Y216:
- return 6;
- case DRM_FORMAT_NV12:
- return 20;
- case DRM_FORMAT_P010:
- case DRM_FORMAT_P012:
- case DRM_FORMAT_P016:
- return 12;
- case DRM_FORMAT_XRGB16161616F:
- case DRM_FORMAT_XBGR16161616F:
- case DRM_FORMAT_ARGB16161616F:
- case DRM_FORMAT_ABGR16161616F:
- case DRM_FORMAT_XVYU12_16161616:
- case DRM_FORMAT_XVYU16161616:
- return 4;
- default:
- return 1;
- }
-}
-
-static int icl_max_plane_width(const struct drm_framebuffer *fb,
- int color_plane,
- unsigned int rotation)
-{
- return 5120;
-}
-
-static int skl_max_plane_height(void)
-{
- return 4096;
-}
-
-static int icl_max_plane_height(void)
-{
- return 4320;
-}
static bool
skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
@@ -3882,35 +3784,55 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state)
return y;
}
+static int intel_plane_min_width(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ if (plane->min_width)
+ return plane->min_width(fb, color_plane, rotation);
+ else
+ return 1;
+}
+
+static int intel_plane_max_width(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ if (plane->max_width)
+ return plane->max_width(fb, color_plane, rotation);
+ else
+ return INT_MAX;
+}
+
+static int intel_plane_max_height(struct intel_plane *plane,
+ const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ if (plane->max_height)
+ return plane->max_height(fb, color_plane, rotation);
+ else
+ return INT_MAX;
+}
+
static int skl_check_main_surface(struct intel_plane_state *plane_state)
{
- struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int x = plane_state->uapi.src.x1 >> 16;
int y = plane_state->uapi.src.y1 >> 16;
int w = drm_rect_width(&plane_state->uapi.src) >> 16;
int h = drm_rect_height(&plane_state->uapi.src) >> 16;
- int max_width, min_width, max_height;
- u32 alignment, offset;
+ int min_width = intel_plane_min_width(plane, fb, 0, rotation);
+ int max_width = intel_plane_max_width(plane, fb, 0, rotation);
+ int max_height = intel_plane_max_height(plane, fb, 0, rotation);
int aux_plane = intel_main_to_aux_plane(fb, 0);
u32 aux_offset = plane_state->color_plane[aux_plane].offset;
-
- if (INTEL_GEN(dev_priv) >= 11) {
- max_width = icl_max_plane_width(fb, 0, rotation);
- min_width = icl_min_plane_width(fb);
- } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
- max_width = glk_max_plane_width(fb, 0, rotation);
- min_width = 1;
- } else {
- max_width = skl_max_plane_width(fb, 0, rotation);
- min_width = 1;
- }
-
- if (INTEL_GEN(dev_priv) >= 11)
- max_height = icl_max_plane_height();
- else
- max_height = skl_max_plane_height();
+ u32 alignment, offset;
if (w > max_width || w < min_width || h > max_height) {
drm_dbg_kms(&dev_priv->drm,
@@ -3930,7 +3852,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
* main surface offset, and it must be non-negative. Make
* sure that is what we will get.
*/
- if (offset > aux_offset)
+ if (aux_plane && offset > aux_offset)
offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
offset, aux_offset & ~(alignment - 1));
@@ -3993,22 +3915,19 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
{
- struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ struct drm_i915_private *i915 = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1;
- int max_width = skl_max_plane_width(fb, uv_plane, rotation);
- int max_height = 4096;
+ int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation);
+ int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation);
int x = plane_state->uapi.src.x1 >> 17;
int y = plane_state->uapi.src.y1 >> 17;
int w = drm_rect_width(&plane_state->uapi.src) >> 17;
int h = drm_rect_height(&plane_state->uapi.src) >> 17;
u32 offset;
- intel_add_fb_offsets(&x, &y, plane_state, uv_plane);
- offset = intel_plane_compute_aligned_offset(&x, &y,
- plane_state, uv_plane);
-
/* FIXME not quite sure how/if these apply to the chroma plane */
if (w > max_width || h > max_height) {
drm_dbg_kms(&i915->drm,
@@ -4017,10 +3936,14 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
return -EINVAL;
}
+ intel_add_fb_offsets(&x, &y, plane_state, uv_plane);
+ offset = intel_plane_compute_aligned_offset(&x, &y,
+ plane_state, uv_plane);
+
if (is_ccs_modifier(fb->modifier)) {
int ccs_plane = main_to_ccs_plane(fb, uv_plane);
- int aux_offset = plane_state->color_plane[ccs_plane].offset;
- int alignment = intel_surf_alignment(fb, uv_plane);
+ u32 aux_offset = plane_state->color_plane[ccs_plane].offset;
+ u32 alignment = intel_surf_alignment(fb, uv_plane);
if (offset > aux_offset)
offset = intel_plane_adjust_aligned_offset(&x, &y,
@@ -4128,7 +4051,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
}
for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) {
- plane_state->color_plane[i].offset = ~0xfff;
+ plane_state->color_plane[i].offset = 0;
plane_state->color_plane[i].x = 0;
plane_state->color_plane[i].y = 0;
}
@@ -4392,12 +4315,10 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state,
if (ret)
return ret;
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- i9xx_plane_has_windowing(plane),
- true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ i9xx_plane_has_windowing(plane));
if (ret)
return ret;
@@ -4786,6 +4707,9 @@ u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
u32 plane_ctl = 0;
+ if (crtc_state->uapi.async_flip)
+ plane_ctl |= PLANE_CTL_ASYNC_FLIP;
+
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
return plane_ctl;
@@ -4933,13 +4857,16 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
intel_has_gpu_reset(&dev_priv->gt));
}
-void intel_prepare_reset(struct drm_i915_private *dev_priv)
+void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
struct drm_atomic_state *state;
int ret;
+ if (!HAS_DISPLAY(dev_priv))
+ return;
+
/* reset doesn't touch the display */
if (!dev_priv->params.force_reset_modeset_test &&
!gpu_reset_clobbers_display(dev_priv))
@@ -4993,13 +4920,16 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
state->acquire_ctx = ctx;
}
-void intel_finish_reset(struct drm_i915_private *dev_priv)
+void intel_display_finish_reset(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
struct drm_atomic_state *state;
int ret;
+ if (!HAS_DISPLAY(dev_priv))
+ return;
+
/* reset doesn't touch the display */
if (!test_bit(I915_RESET_MODESET, &dev_priv->gt.reset.flags))
return;
@@ -5023,18 +4953,14 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
intel_pps_unlock_regs_wa(dev_priv);
intel_modeset_init_hw(dev_priv);
intel_init_clock_gating(dev_priv);
-
- spin_lock_irq(&dev_priv->irq_lock);
- if (dev_priv->display.hpd_irq_setup)
- dev_priv->display.hpd_irq_setup(dev_priv);
- spin_unlock_irq(&dev_priv->irq_lock);
+ intel_hpd_init(dev_priv);
ret = __intel_display_resume(dev, state, ctx);
if (ret)
drm_err(&dev_priv->drm,
"Restoring old state failed with %i\n", ret);
- intel_hpd_init(dev_priv);
+ intel_hpd_poll_disable(dev_priv);
}
drm_atomic_state_put(state);
@@ -6153,18 +6079,16 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
static int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
int width, height;
if (crtc_state->pch_pfit.enabled) {
width = drm_rect_width(&crtc_state->pch_pfit.dst);
height = drm_rect_height(&crtc_state->pch_pfit.dst);
} else {
- width = adjusted_mode->crtc_hdisplay;
- height = adjusted_mode->crtc_vdisplay;
+ width = pipe_mode->crtc_hdisplay;
+ height = pipe_mode->crtc_vdisplay;
}
-
return skl_update_scaler(crtc_state, !crtc_state->hw.active,
SKL_CRTC_INDEX,
&crtc_state->scaler_state.scaler_id,
@@ -6275,6 +6199,105 @@ void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state)
skl_detach_scaler(crtc, i);
}
+static int cnl_coef_tap(int i)
+{
+ return i % 7;
+}
+
+static u16 cnl_nearest_filter_coef(int t)
+{
+ return t == 3 ? 0x0800 : 0x3000;
+}
+
+/*
+ * Theory behind setting nearest-neighbor integer scaling:
+ *
+ * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set.
+ * The letter represents the filter tap (D is the center tap) and the number
+ * represents the coefficient set for a phase (0-16).
+ *
+ * +------------+------------------------+------------------------+
+ * |Index value | Data value coeffient 1 | Data value coeffient 2 |
+ * +------------+------------------------+------------------------+
+ * | 00h | B0 | A0 |
+ * +------------+------------------------+------------------------+
+ * | 01h | D0 | C0 |
+ * +------------+------------------------+------------------------+
+ * | 02h | F0 | E0 |
+ * +------------+------------------------+------------------------+
+ * | 03h | A1 | G0 |
+ * +------------+------------------------+------------------------+
+ * | 04h | C1 | B1 |
+ * +------------+------------------------+------------------------+
+ * | ... | ... | ... |
+ * +------------+------------------------+------------------------+
+ * | 38h | B16 | A16 |
+ * +------------+------------------------+------------------------+
+ * | 39h | D16 | C16 |
+ * +------------+------------------------+------------------------+
+ * | 3Ah | F16 | C16 |
+ * +------------+------------------------+------------------------+
+ * | 3Bh | Reserved | G16 |
+ * +------------+------------------------+------------------------+
+ *
+ * To enable nearest-neighbor scaling: program scaler coefficents with
+ * the center tap (Dxx) values set to 1 and all other values set to 0 as per
+ * SCALER_COEFFICIENT_FORMAT
+ *
+ */
+
+static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv,
+ enum pipe pipe, int id, int set)
+{
+ int i;
+
+ intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set),
+ PS_COEE_INDEX_AUTO_INC);
+
+ for (i = 0; i < 17 * 7; i += 2) {
+ u32 tmp;
+ int t;
+
+ t = cnl_coef_tap(i);
+ tmp = cnl_nearest_filter_coef(t);
+
+ t = cnl_coef_tap(i + 1);
+ tmp |= cnl_nearest_filter_coef(t) << 16;
+
+ intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set),
+ tmp);
+ }
+
+ intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0);
+}
+
+inline u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set)
+{
+ if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) {
+ return (PS_FILTER_PROGRAMMED |
+ PS_Y_VERT_FILTER_SELECT(set) |
+ PS_Y_HORZ_FILTER_SELECT(set) |
+ PS_UV_VERT_FILTER_SELECT(set) |
+ PS_UV_HORZ_FILTER_SELECT(set));
+ }
+
+ return PS_FILTER_MEDIUM;
+}
+
+void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
+ int id, int set, enum drm_scaling_filter filter)
+{
+ switch (filter) {
+ case DRM_SCALING_FILTER_DEFAULT:
+ break;
+ case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
+ cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set);
+ break;
+ default:
+ MISSING_CASE(filter);
+ }
+}
+
static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -6295,6 +6318,7 @@ static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
int hscale, vscale;
unsigned long irqflags;
int id;
+ u32 ps_ctrl;
if (!crtc_state->pch_pfit.enabled)
return;
@@ -6311,10 +6335,16 @@ static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
id = scaler_state->scaler_id;
+ ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
+ ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode;
+
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), PS_SCALER_EN |
- PS_FILTER_MEDIUM | scaler_state->scalers[id].mode);
+ skl_scaler_setup_filter(dev_priv, pipe, id, 0,
+ crtc_state->hw.scaling_filter);
+
+ intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl);
+
intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id),
PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id),
@@ -6560,6 +6590,43 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
icl_wa_scalerclkgating(dev_priv, pipe, false);
}
+static void skl_disable_async_flip_wa(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ const struct intel_crtc_state *new_crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_plane *plane;
+ struct intel_plane_state *new_plane_state;
+ int i;
+
+ for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
+ u32 update_mask = new_crtc_state->update_planes;
+ u32 plane_ctl, surf_addr;
+ enum plane_id plane_id;
+ unsigned long irqflags;
+ enum pipe pipe;
+
+ if (crtc->pipe != plane->pipe ||
+ !(update_mask & BIT(plane->id)))
+ continue;
+
+ plane_id = plane->id;
+ pipe = plane->pipe;
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ plane_ctl = intel_de_read_fw(dev_priv, PLANE_CTL(pipe, plane_id));
+ surf_addr = intel_de_read_fw(dev_priv, PLANE_SURF(pipe, plane_id));
+
+ plane_ctl &= ~PLANE_CTL_ASYNC_FLIP;
+
+ intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
+ intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), surf_addr);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
+ intel_wait_for_vblank(dev_priv, crtc->pipe);
+}
+
static void intel_pre_plane_update(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -6645,6 +6712,15 @@ static void intel_pre_plane_update(struct intel_atomic_state *state,
*/
if (IS_GEN(dev_priv, 2) && planes_disabling(old_crtc_state, new_crtc_state))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
+ /*
+ * WA for platforms where async address update enable bit
+ * is double buffered and only latched at start of vblank.
+ */
+ if (old_crtc_state->uapi.async_flip &&
+ !new_crtc_state->uapi.async_flip &&
+ IS_GEN_RANGE(dev_priv, 9, 10))
+ skl_disable_async_flip_wa(state, crtc, new_crtc_state);
}
static void intel_crtc_disable_planes(struct intel_atomic_state *state,
@@ -6944,7 +7020,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state,
if (intel_crtc_has_dp_encoder(new_crtc_state))
intel_dp_set_m_n(new_crtc_state, M1_N1);
- intel_set_pipe_timings(new_crtc_state);
+ intel_set_transcoder_timings(new_crtc_state);
intel_set_pipe_src_size(new_crtc_state);
if (new_crtc_state->has_pch_encoder)
@@ -7068,6 +7144,45 @@ static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, reg, val);
}
+static void icl_ddi_bigjoiner_pre_enable(struct intel_atomic_state *state,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *master = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_crtc_state *master_crtc_state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *conn;
+ struct intel_encoder *encoder = NULL;
+ int i;
+
+ if (crtc_state->bigjoiner_slave)
+ master = crtc_state->bigjoiner_linked_crtc;
+
+ master_crtc_state = intel_atomic_get_new_crtc_state(state, master);
+
+ for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
+ if (conn_state->crtc != &master->base)
+ continue;
+
+ encoder = to_intel_encoder(conn_state->best_encoder);
+ break;
+ }
+
+ if (!crtc_state->bigjoiner_slave) {
+ /* need to enable VDSC, which we skipped in pre-enable */
+ intel_dsc_enable(encoder, crtc_state);
+ } else {
+ /*
+ * Enable sequence steps 1-7 on bigjoiner master
+ */
+ intel_encoders_pre_pll_enable(state, master);
+ intel_enable_shared_dpll(master_crtc_state);
+ intel_encoders_pre_enable(state, master);
+
+ /* and DSC on slave */
+ intel_dsc_enable(NULL, crtc_state);
+ }
+}
+
static void hsw_crtc_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -7081,34 +7196,37 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (drm_WARN_ON(&dev_priv->drm, crtc->active))
return;
- intel_encoders_pre_pll_enable(state, crtc);
-
- if (new_crtc_state->shared_dpll)
- intel_enable_shared_dpll(new_crtc_state);
+ if (!new_crtc_state->bigjoiner) {
+ intel_encoders_pre_pll_enable(state, crtc);
- intel_encoders_pre_enable(state, crtc);
+ if (new_crtc_state->shared_dpll)
+ intel_enable_shared_dpll(new_crtc_state);
- if (!transcoder_is_dsi(cpu_transcoder))
- intel_set_pipe_timings(new_crtc_state);
+ intel_encoders_pre_enable(state, crtc);
+ } else {
+ icl_ddi_bigjoiner_pre_enable(state, new_crtc_state);
+ }
intel_set_pipe_src_size(new_crtc_state);
+ if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
+ bdw_set_pipemisc(new_crtc_state);
- if (cpu_transcoder != TRANSCODER_EDP &&
- !transcoder_is_dsi(cpu_transcoder))
- intel_de_write(dev_priv, PIPE_MULT(cpu_transcoder),
- new_crtc_state->pixel_multiplier - 1);
+ if (!new_crtc_state->bigjoiner_slave && !transcoder_is_dsi(cpu_transcoder)) {
+ intel_set_transcoder_timings(new_crtc_state);
- if (new_crtc_state->has_pch_encoder)
- intel_cpu_transcoder_set_m_n(new_crtc_state,
- &new_crtc_state->fdi_m_n, NULL);
+ if (cpu_transcoder != TRANSCODER_EDP)
+ intel_de_write(dev_priv, PIPE_MULT(cpu_transcoder),
+ new_crtc_state->pixel_multiplier - 1);
+
+ if (new_crtc_state->has_pch_encoder)
+ intel_cpu_transcoder_set_m_n(new_crtc_state,
+ &new_crtc_state->fdi_m_n, NULL);
- if (!transcoder_is_dsi(cpu_transcoder)) {
hsw_set_frame_start_delay(new_crtc_state);
- hsw_set_pipeconf(new_crtc_state);
}
- if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
- bdw_set_pipemisc(new_crtc_state);
+ if (!transcoder_is_dsi(cpu_transcoder))
+ hsw_set_pipeconf(new_crtc_state);
crtc->active = true;
@@ -7144,6 +7262,11 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (INTEL_GEN(dev_priv) >= 11)
icl_pipe_mbus_enable(crtc);
+ if (new_crtc_state->bigjoiner_slave) {
+ trace_intel_pipe_enable(crtc);
+ intel_crtc_vblank_on(new_crtc_state);
+ }
+
intel_encoders_enable(state, crtc);
if (psl_clkgate_wa) {
@@ -7273,9 +7396,9 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy)
{
if (phy == PHY_NONE)
return false;
- else if (IS_ROCKETLAKE(dev_priv))
+ else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
return phy <= PHY_D;
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
return phy <= PHY_C;
else if (INTEL_GEN(dev_priv) >= 11)
return phy <= PHY_B;
@@ -7285,11 +7408,11 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy)
bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy)
{
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
return false;
else if (INTEL_GEN(dev_priv) >= 12)
return phy >= PHY_D && phy <= PHY_I;
- else if (INTEL_GEN(dev_priv) >= 11 && !IS_ELKHARTLAKE(dev_priv))
+ else if (INTEL_GEN(dev_priv) >= 11 && !IS_JSL_EHL(dev_priv))
return phy >= PHY_C && phy <= PHY_F;
else
return false;
@@ -7297,23 +7420,23 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy)
enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port)
{
- if (IS_ROCKETLAKE(i915) && port >= PORT_D)
- return (enum phy)port - 1;
- else if (IS_ELKHARTLAKE(i915) && port == PORT_D)
+ if ((IS_DG1(i915) || IS_ROCKETLAKE(i915)) && port >= PORT_TC1)
+ return PHY_C + port - PORT_TC1;
+ else if (IS_JSL_EHL(i915) && port == PORT_D)
return PHY_A;
- return (enum phy)port;
+ return PHY_A + port - PORT_A;
}
enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, enum port port)
{
if (!intel_phy_is_tc(dev_priv, intel_port_to_phy(dev_priv, port)))
- return PORT_TC_NONE;
+ return TC_PORT_NONE;
if (INTEL_GEN(dev_priv) >= 12)
- return port - PORT_D;
-
- return port - PORT_C;
+ return TC_PORT_1 + port - PORT_TC1;
+ else
+ return TC_PORT_1 + port - PORT_C;
}
enum intel_display_power_domain intel_port_to_power_domain(enum port port)
@@ -7438,6 +7561,9 @@ static u64 get_crtc_power_domains(struct intel_crtc_state *crtc_state)
if (crtc_state->shared_dpll)
mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE);
+ if (crtc_state->dsc.compression_enable)
+ mask |= BIT_ULL(intel_dsc_power_domain(crtc_state));
+
return mask;
}
@@ -7484,7 +7610,7 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state,
if (intel_crtc_has_dp_encoder(new_crtc_state))
intel_dp_set_m_n(new_crtc_state, M1_N1);
- intel_set_pipe_timings(new_crtc_state);
+ intel_set_transcoder_timings(new_crtc_state);
intel_set_pipe_src_size(new_crtc_state);
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
@@ -7552,7 +7678,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state,
if (intel_crtc_has_dp_encoder(new_crtc_state))
intel_dp_set_m_n(new_crtc_state, M1_N1);
- intel_set_pipe_timings(new_crtc_state);
+ intel_set_transcoder_timings(new_crtc_state);
intel_set_pipe_src_size(new_crtc_state);
i9xx_set_pipeconf(new_crtc_state);
@@ -8026,7 +8152,7 @@ static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state)
{
- u32 pixel_rate = crtc_state->hw.adjusted_mode.crtc_clock;
+ u32 pixel_rate = crtc_state->hw.pipe_mode.crtc_clock;
unsigned int pipe_w, pipe_h, pfit_w, pfit_h;
/*
@@ -8056,6 +8182,27 @@ static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state)
pfit_w * pfit_h);
}
+static void intel_mode_from_crtc_timings(struct drm_display_mode *mode,
+ const struct drm_display_mode *timings)
+{
+ mode->hdisplay = timings->crtc_hdisplay;
+ mode->htotal = timings->crtc_htotal;
+ mode->hsync_start = timings->crtc_hsync_start;
+ mode->hsync_end = timings->crtc_hsync_end;
+
+ mode->vdisplay = timings->crtc_vdisplay;
+ mode->vtotal = timings->crtc_vtotal;
+ mode->vsync_start = timings->crtc_vsync_start;
+ mode->vsync_end = timings->crtc_vsync_end;
+
+ mode->flags = timings->flags;
+ mode->type = DRM_MODE_TYPE_DRIVER;
+
+ mode->clock = timings->crtc_clock;
+
+ drm_mode_set_name(mode);
+}
+
static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
@@ -8063,19 +8210,75 @@ static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
if (HAS_GMCH(dev_priv))
/* FIXME calculate proper pipe pixel rate for GMCH pfit */
crtc_state->pixel_rate =
- crtc_state->hw.adjusted_mode.crtc_clock;
+ crtc_state->hw.pipe_mode.crtc_clock;
else
crtc_state->pixel_rate =
ilk_pipe_pixel_rate(crtc_state);
}
+static void intel_crtc_readout_derived_state(struct intel_crtc_state *crtc_state)
+{
+ struct drm_display_mode *mode = &crtc_state->hw.mode;
+ struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
+ struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+
+ drm_mode_copy(pipe_mode, adjusted_mode);
+
+ if (crtc_state->bigjoiner) {
+ /*
+ * transcoder is programmed to the full mode,
+ * but pipe timings are half of the transcoder mode
+ */
+ pipe_mode->crtc_hdisplay /= 2;
+ pipe_mode->crtc_hblank_start /= 2;
+ pipe_mode->crtc_hblank_end /= 2;
+ pipe_mode->crtc_hsync_start /= 2;
+ pipe_mode->crtc_hsync_end /= 2;
+ pipe_mode->crtc_htotal /= 2;
+ pipe_mode->crtc_clock /= 2;
+ }
+
+ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
+ intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode);
+
+ intel_crtc_compute_pixel_rate(crtc_state);
+
+ drm_mode_copy(mode, adjusted_mode);
+ mode->hdisplay = crtc_state->pipe_src_w << crtc_state->bigjoiner;
+ mode->vdisplay = crtc_state->pipe_src_h;
+}
+
+static void intel_encoder_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ encoder->get_config(encoder, crtc_state);
+
+ intel_crtc_readout_derived_state(crtc_state);
+}
+
static int intel_crtc_compute_config(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
+ struct drm_display_mode *pipe_mode = &pipe_config->hw.pipe_mode;
int clock_limit = dev_priv->max_dotclk_freq;
+ drm_mode_copy(pipe_mode, &pipe_config->hw.adjusted_mode);
+
+ /* Adjust pipe_mode for bigjoiner, with half the horizontal mode */
+ if (pipe_config->bigjoiner) {
+ pipe_mode->crtc_clock /= 2;
+ pipe_mode->crtc_hdisplay /= 2;
+ pipe_mode->crtc_hblank_start /= 2;
+ pipe_mode->crtc_hblank_end /= 2;
+ pipe_mode->crtc_hsync_start /= 2;
+ pipe_mode->crtc_hsync_end /= 2;
+ pipe_mode->crtc_htotal /= 2;
+ pipe_config->pipe_src_w /= 2;
+ }
+
+ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
+
if (INTEL_GEN(dev_priv) < 4) {
clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
@@ -8084,16 +8287,16 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
* is > 90% of the (display) core speed.
*/
if (intel_crtc_supports_double_wide(crtc) &&
- adjusted_mode->crtc_clock > clock_limit) {
+ pipe_mode->crtc_clock > clock_limit) {
clock_limit = dev_priv->max_dotclk_freq;
pipe_config->double_wide = true;
}
}
- if (adjusted_mode->crtc_clock > clock_limit) {
+ if (pipe_mode->crtc_clock > clock_limit) {
drm_dbg_kms(&dev_priv->drm,
"requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
- adjusted_mode->crtc_clock, clock_limit,
+ pipe_mode->crtc_clock, clock_limit,
yesno(pipe_config->double_wide));
return -EINVAL;
}
@@ -8136,7 +8339,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
* WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
*/
if ((INTEL_GEN(dev_priv) > 4 || IS_G4X(dev_priv)) &&
- adjusted_mode->crtc_hsync_start == adjusted_mode->crtc_hdisplay)
+ pipe_mode->crtc_hsync_start == pipe_mode->crtc_hdisplay)
return -EINVAL;
intel_crtc_compute_pixel_rate(pipe_config);
@@ -8806,7 +9009,7 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
crtc_state->dpll_hw_state.dpll = dpll;
}
-static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state)
+static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -8892,8 +9095,8 @@ static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state)
return intel_de_read(dev_priv, PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK;
}
-static void intel_get_pipe_timings(struct intel_crtc *crtc,
- struct intel_crtc_state *pipe_config)
+static void intel_get_transcoder_timings(struct intel_crtc *crtc,
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
@@ -8947,30 +9150,6 @@ static void intel_get_pipe_src_size(struct intel_crtc *crtc,
tmp = intel_de_read(dev_priv, PIPESRC(crtc->pipe));
pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1;
-
- pipe_config->hw.mode.vdisplay = pipe_config->pipe_src_h;
- pipe_config->hw.mode.hdisplay = pipe_config->pipe_src_w;
-}
-
-void intel_mode_from_pipe_config(struct drm_display_mode *mode,
- struct intel_crtc_state *pipe_config)
-{
- mode->hdisplay = pipe_config->hw.adjusted_mode.crtc_hdisplay;
- mode->htotal = pipe_config->hw.adjusted_mode.crtc_htotal;
- mode->hsync_start = pipe_config->hw.adjusted_mode.crtc_hsync_start;
- mode->hsync_end = pipe_config->hw.adjusted_mode.crtc_hsync_end;
-
- mode->vdisplay = pipe_config->hw.adjusted_mode.crtc_vdisplay;
- mode->vtotal = pipe_config->hw.adjusted_mode.crtc_vtotal;
- mode->vsync_start = pipe_config->hw.adjusted_mode.crtc_vsync_start;
- mode->vsync_end = pipe_config->hw.adjusted_mode.crtc_vsync_end;
-
- mode->flags = pipe_config->hw.adjusted_mode.flags;
- mode->type = DRM_MODE_TYPE_DRIVER;
-
- mode->clock = pipe_config->hw.adjusted_mode.crtc_clock;
-
- drm_mode_set_name(mode);
}
static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state)
@@ -9516,7 +9695,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
if (INTEL_GEN(dev_priv) < 4)
pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
- intel_get_pipe_timings(crtc, pipe_config);
+ intel_get_transcoder_timings(crtc, pipe_config);
intel_get_pipe_src_size(crtc, pipe_config);
i9xx_get_pfit_config(pipe_config);
@@ -10537,6 +10716,7 @@ static void
skl_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
+ struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
@@ -10553,6 +10733,12 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
drm_WARN_ON(dev, pipe != crtc->pipe);
+ if (crtc_state->bigjoiner) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Unsupported bigjoiner configuration for initial FB\n");
+ return;
+ }
+
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb) {
drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");
@@ -10761,6 +10947,7 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
if (intel_de_read(dev_priv, PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
struct intel_shared_dpll *pll;
enum intel_dpll_id pll_id;
+ bool pll_active;
pipe_config->has_pch_encoder = true;
@@ -10788,8 +10975,9 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
intel_get_shared_dpll_by_id(dev_priv, pll_id);
pll = pipe_config->shared_dpll;
- drm_WARN_ON(dev, !pll->info->funcs->get_hw_state(dev_priv, pll,
- &pipe_config->dpll_hw_state));
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(dev, !pll_active);
tmp = pipe_config->dpll_hw_state.dpll;
pipe_config->pixel_multiplier =
@@ -10801,7 +10989,7 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
pipe_config->pixel_multiplier = 1;
}
- intel_get_pipe_timings(crtc, pipe_config);
+ intel_get_transcoder_timings(crtc, pipe_config);
intel_get_pipe_src_size(crtc, pipe_config);
ilk_get_pfit_config(pipe_config);
@@ -10837,19 +11025,32 @@ static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
return 0;
}
-static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
+static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
struct intel_crtc_state *pipe_config)
{
+ enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT;
+ enum phy phy = intel_port_to_phy(dev_priv, port);
+ struct icl_port_dpll *port_dpll;
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
- u32 temp;
+ bool pll_active;
+ u32 clk_sel;
- temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
- id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
+ clk_sel = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)) & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ id = DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy);
- if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2))
+ if (WARN_ON(id > DPLL_ID_DG1_DPLL3))
return;
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+ port_dpll = &pipe_config->icl_port_dplls[port_dpll_id];
+
+ port_dpll->pll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &port_dpll->hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
+
+ icl_set_active_port_dpll(pipe_config, port_dpll_id);
}
static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
@@ -10857,7 +11058,10 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
{
enum phy phy = intel_port_to_phy(dev_priv, port);
enum icl_port_dpll_id port_dpll_id;
+ struct icl_port_dpll *port_dpll;
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
+ bool pll_active;
u32 temp;
if (intel_phy_is_combo(dev_priv, phy)) {
@@ -10892,17 +11096,46 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
return;
}
- pipe_config->icl_port_dplls[port_dpll_id].pll =
- intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+ port_dpll = &pipe_config->icl_port_dplls[port_dpll_id];
+
+ port_dpll->pll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &port_dpll->hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
icl_set_active_port_dpll(pipe_config, port_dpll_id);
}
+static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
+ struct intel_crtc_state *pipe_config)
+{
+ struct intel_shared_dpll *pll;
+ enum intel_dpll_id id;
+ bool pll_active;
+ u32 temp;
+
+ temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+ id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
+
+ if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2))
+ return;
+
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
+}
+
static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_state *pipe_config)
{
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
+ bool pll_active;
switch (port) {
case PORT_A:
@@ -10919,13 +11152,20 @@ static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
return;
}
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
}
static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
struct intel_crtc_state *pipe_config)
{
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
+ bool pll_active;
u32 temp;
temp = intel_de_read(dev_priv, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
@@ -10934,14 +11174,21 @@ static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL3))
return;
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
}
static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
struct intel_crtc_state *pipe_config)
{
+ struct intel_shared_dpll *pll;
enum intel_dpll_id id;
u32 ddi_pll_sel = intel_de_read(dev_priv, PORT_CLK_SEL(port));
+ bool pll_active;
switch (ddi_pll_sel) {
case PORT_CLK_SEL_WRPLL1:
@@ -10969,7 +11216,12 @@ static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
return;
}
- pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+ pll = intel_get_shared_dpll_by_id(dev_priv, id);
+
+ pipe_config->shared_dpll = pll;
+ pll_active = intel_dpll_get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
+ drm_WARN_ON(&dev_priv->drm, !pll_active);
}
static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
@@ -11129,7 +11381,6 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc,
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
- struct intel_shared_dpll *pll;
enum port port;
u32 tmp;
@@ -11139,30 +11390,27 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc,
} else {
tmp = intel_de_read(dev_priv,
TRANS_DDI_FUNC_CTL(cpu_transcoder));
+ if (!(tmp & TRANS_DDI_FUNC_ENABLE))
+ return;
if (INTEL_GEN(dev_priv) >= 12)
port = TGL_TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp);
else
port = TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp);
}
- if (INTEL_GEN(dev_priv) >= 11)
+ if (IS_DG1(dev_priv))
+ dg1_get_ddi_pll(dev_priv, port, pipe_config);
+ else if (INTEL_GEN(dev_priv) >= 11)
icl_get_ddi_pll(dev_priv, port, pipe_config);
else if (IS_CANNONLAKE(dev_priv))
cnl_get_ddi_pll(dev_priv, port, pipe_config);
- else if (IS_GEN9_BC(dev_priv))
- skl_get_ddi_pll(dev_priv, port, pipe_config);
else if (IS_GEN9_LP(dev_priv))
bxt_get_ddi_pll(dev_priv, port, pipe_config);
+ else if (IS_GEN9_BC(dev_priv))
+ skl_get_ddi_pll(dev_priv, port, pipe_config);
else
hsw_get_ddi_pll(dev_priv, port, pipe_config);
- pll = pipe_config->shared_dpll;
- if (pll) {
- drm_WARN_ON(&dev_priv->drm,
- !pll->info->funcs->get_hw_state(dev_priv, pll,
- &pipe_config->dpll_hw_state));
- }
-
/*
* Haswell has only FDI/PCH transcoder A. It is which is connected to
* DDI E. So just check whether this pipe is wired to DDI E and whether
@@ -11212,13 +11460,22 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
active = true;
}
- if (!active)
- goto out;
+ intel_dsc_get_config(pipe_config);
- if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
+ if (!active) {
+ /* bigjoiner slave doesn't enable transcoder */
+ if (!pipe_config->bigjoiner_slave)
+ goto out;
+
+ active = true;
+ pipe_config->pixel_multiplier = 1;
+
+ /* we cannot read out most state, so don't bother.. */
+ pipe_config->quirks |= PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE;
+ } else if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
INTEL_GEN(dev_priv) >= 11) {
hsw_get_ddi_port_state(crtc, pipe_config);
- intel_get_pipe_timings(crtc, pipe_config);
+ intel_get_transcoder_timings(crtc, pipe_config);
}
intel_get_pipe_src_size(crtc, pipe_config);
@@ -11234,18 +11491,6 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
} else {
pipe_config->output_format =
bdw_get_pipemisc_output_format(crtc);
-
- /*
- * Currently there is no interface defined to
- * check user preference between RGB/YCBCR444
- * or YCBCR420. So the only possible case for
- * YCBCR444 usage is driving YCBCR420 output
- * with LSPCON, when pipe is configured for
- * YCBCR444 output and LSPCON takes care of
- * downsampling it.
- */
- pipe_config->lspcon_downsampling =
- pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR444;
}
pipe_config->gamma_mode = intel_de_read(dev_priv,
@@ -11302,7 +11547,10 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
}
}
- if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
+ if (pipe_config->bigjoiner_slave) {
+ /* Cannot be read out as a slave, set to 0. */
+ pipe_config->pixel_multiplier = 0;
+ } else if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
pipe_config->pixel_multiplier =
intel_de_read(dev_priv,
@@ -11319,6 +11567,21 @@ out:
return active;
}
+static bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+
+ if (!i915->display.get_pipe_config(crtc, crtc_state))
+ return false;
+
+ crtc_state->hw.active = true;
+
+ intel_crtc_readout_derived_state(crtc_state);
+
+ return true;
+}
+
static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
@@ -11424,6 +11687,8 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+ const struct drm_rect src = plane_state->uapi.src;
+ const struct drm_rect dst = plane_state->uapi.dst;
int ret;
if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
@@ -11431,17 +11696,16 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
return -EINVAL;
}
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true, true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ true);
if (ret)
return ret;
/* Use the unclipped src/dst rectangles, which we program to hw */
- plane_state->uapi.src = drm_plane_state_src(&plane_state->uapi);
- plane_state->uapi.dst = drm_plane_state_dest(&plane_state->uapi);
+ plane_state->uapi.src = src;
+ plane_state->uapi.dst = dst;
ret = intel_cursor_check_surface(plane_state);
if (ret)
@@ -11817,6 +12081,9 @@ static void i9xx_update_cursor(struct intel_plane *plane,
if (INTEL_GEN(dev_priv) >= 9)
skl_write_cursor_wm(plane, crtc_state);
+ if (!needs_modeset(crtc_state))
+ intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
+
if (plane->cursor.base != base ||
plane->cursor.size != fbc_ctl ||
plane->cursor.cntl != cntl) {
@@ -12312,15 +12579,15 @@ intel_encoder_current_mode(struct intel_encoder *encoder)
return NULL;
}
- if (!dev_priv->display.get_pipe_config(crtc, crtc_state)) {
+ if (!intel_crtc_get_pipe_config(crtc_state)) {
kfree(crtc_state);
kfree(mode);
return NULL;
}
- encoder->get_config(encoder, crtc_state);
+ intel_encoder_get_config(encoder, crtc_state);
- intel_mode_from_pipe_config(mode, crtc_state);
+ intel_mode_from_crtc_timings(mode, &crtc_state->hw.adjusted_mode);
kfree(crtc_state);
@@ -12506,7 +12773,7 @@ static bool encoders_cloneable(const struct intel_encoder *a,
b->cloneable & (1 << a->type));
}
-static bool check_single_encoder_cloning(struct drm_atomic_state *state,
+static bool check_single_encoder_cloning(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_encoder *encoder)
{
@@ -12515,7 +12782,7 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
struct drm_connector_state *connector_state;
int i;
- for_each_new_connector_in_state(state, connector, connector_state, i) {
+ for_each_new_connector_in_state(&state->base, connector, connector_state, i) {
if (connector_state->crtc != &crtc->base)
continue;
@@ -12630,7 +12897,7 @@ static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state)
memcpy(linked_state->color_plane, plane_state->color_plane,
sizeof(linked_state->color_plane));
- intel_plane_copy_uapi_to_hw_state(linked_state, plane_state);
+ intel_plane_copy_hw_state(linked_state, plane_state);
linked_state->uapi.src = plane_state->uapi.src;
linked_state->uapi.dst = plane_state->uapi.dst;
@@ -12664,15 +12931,15 @@ static bool c8_planes_changed(const struct intel_crtc_state *new_crtc_state)
static u16 hsw_linetime_wm(const struct intel_crtc_state *crtc_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
int linetime_wm;
if (!crtc_state->hw.enable)
return 0;
- linetime_wm = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
- adjusted_mode->crtc_clock);
+ linetime_wm = DIV_ROUND_CLOSEST(pipe_mode->crtc_htotal * 1000 * 8,
+ pipe_mode->crtc_clock);
return min(linetime_wm, 0x1ff);
}
@@ -12680,14 +12947,14 @@ static u16 hsw_linetime_wm(const struct intel_crtc_state *crtc_state)
static u16 hsw_ips_linetime_wm(const struct intel_crtc_state *crtc_state,
const struct intel_cdclk_state *cdclk_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
int linetime_wm;
if (!crtc_state->hw.enable)
return 0;
- linetime_wm = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
+ linetime_wm = DIV_ROUND_CLOSEST(pipe_mode->crtc_htotal * 1000 * 8,
cdclk_state->logical.cdclk);
return min(linetime_wm, 0x1ff);
@@ -12697,14 +12964,14 @@ static u16 skl_linetime_wm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ const struct drm_display_mode *pipe_mode =
+ &crtc_state->hw.pipe_mode;
int linetime_wm;
if (!crtc_state->hw.enable)
return 0;
- linetime_wm = DIV_ROUND_UP(adjusted_mode->crtc_htotal * 1000 * 8,
+ linetime_wm = DIV_ROUND_UP(pipe_mode->crtc_htotal * 1000 * 8,
crtc_state->pixel_rate);
/* Display WA #1135: BXT:ALL GLK:ALL */
@@ -12755,6 +13022,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
if (mode_changed && crtc_state->hw.enable &&
dev_priv->display.crtc_compute_clock &&
+ !crtc_state->bigjoiner_slave &&
!drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll)) {
ret = dev_priv->display.crtc_compute_clock(crtc, crtc_state);
if (ret)
@@ -12828,8 +13096,11 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
}
- if (!mode_changed)
- intel_psr2_sel_fetch_update(state, crtc);
+ if (!mode_changed) {
+ ret = intel_psr2_sel_fetch_update(state, crtc);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -13059,11 +13330,11 @@ static void intel_dump_plane_state(const struct intel_plane_state *plane_state)
}
drm_dbg_kms(&i915->drm,
- "[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %s, visible: %s\n",
+ "[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %s modifier = 0x%llx, visible: %s\n",
plane->base.base.id, plane->base.name,
fb->base.id, fb->width, fb->height,
drm_get_format_name(fb->format->format, &format_name),
- yesno(plane_state->uapi.visible));
+ fb->modifier, yesno(plane_state->uapi.visible));
drm_dbg_kms(&i915->drm, "\trotation: 0x%x, scaler: %d\n",
plane_state->hw.rotation, plane_state->scaler_id);
if (plane_state->uapi.visible)
@@ -13103,11 +13374,18 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
transcoder_name(pipe_config->cpu_transcoder),
pipe_config->pipe_bpp, pipe_config->dither);
+ drm_dbg_kms(&dev_priv->drm, "MST master transcoder: %s\n",
+ transcoder_name(pipe_config->mst_master_transcoder));
+
drm_dbg_kms(&dev_priv->drm,
"port sync: master transcoder: %s, slave transcoder bitmask = 0x%x\n",
transcoder_name(pipe_config->master_transcoder),
pipe_config->sync_mode_slaves_mask);
+ drm_dbg_kms(&dev_priv->drm, "bigjoiner: %s\n",
+ pipe_config->bigjoiner_slave ? "slave" :
+ pipe_config->bigjoiner ? "master" : "no");
+
if (pipe_config->has_pch_encoder)
intel_dump_m_n_config(pipe_config, "fdi",
pipe_config->fdi_lanes,
@@ -13155,6 +13433,9 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
drm_dbg_kms(&dev_priv->drm, "adjusted mode:\n");
drm_mode_debug_printmodeline(&pipe_config->hw.adjusted_mode);
intel_dump_crtc_timings(dev_priv, &pipe_config->hw.adjusted_mode);
+ drm_dbg_kms(&dev_priv->drm, "pipe mode:\n");
+ drm_mode_debug_printmodeline(&pipe_config->hw.pipe_mode);
+ intel_dump_crtc_timings(dev_priv, &pipe_config->hw.pipe_mode);
drm_dbg_kms(&dev_priv->drm,
"port clock: %d, pipe src size: %dx%d, pixel rate %d\n",
pipe_config->port_clock,
@@ -13200,8 +13481,11 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
pipe_config->csc_mode, pipe_config->gamma_mode,
pipe_config->gamma_enable, pipe_config->csc_enable);
- drm_dbg_kms(&dev_priv->drm, "MST master transcoder: %s\n",
- transcoder_name(pipe_config->mst_master_transcoder));
+ drm_dbg_kms(&dev_priv->drm, "degamma lut: %d entries, gamma lut: %d entries\n",
+ pipe_config->hw.degamma_lut ?
+ drm_color_lut_size(pipe_config->hw.degamma_lut) : 0,
+ pipe_config->hw.gamma_lut ?
+ drm_color_lut_size(pipe_config->hw.gamma_lut) : 0);
dump_planes:
if (!state)
@@ -13283,29 +13567,48 @@ static bool check_digital_port_conflicts(struct intel_atomic_state *state)
}
static void
-intel_crtc_copy_uapi_to_hw_state_nomodeset(struct intel_crtc_state *crtc_state)
+intel_crtc_copy_uapi_to_hw_state_nomodeset(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
- intel_crtc_copy_color_blobs(crtc_state);
+ const struct intel_crtc_state *from_crtc_state = crtc_state;
+
+ if (crtc_state->bigjoiner_slave) {
+ from_crtc_state = intel_atomic_get_new_crtc_state(state,
+ crtc_state->bigjoiner_linked_crtc);
+
+ /* No need to copy state if the master state is unchanged */
+ if (!from_crtc_state)
+ return;
+ }
+
+ intel_crtc_copy_color_blobs(crtc_state, from_crtc_state);
}
static void
-intel_crtc_copy_uapi_to_hw_state(struct intel_crtc_state *crtc_state)
+intel_crtc_copy_uapi_to_hw_state(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
crtc_state->hw.enable = crtc_state->uapi.enable;
crtc_state->hw.active = crtc_state->uapi.active;
crtc_state->hw.mode = crtc_state->uapi.mode;
crtc_state->hw.adjusted_mode = crtc_state->uapi.adjusted_mode;
- intel_crtc_copy_uapi_to_hw_state_nomodeset(crtc_state);
+ crtc_state->hw.scaling_filter = crtc_state->uapi.scaling_filter;
+
+ intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc_state);
}
static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state)
{
+ if (crtc_state->bigjoiner_slave)
+ return;
+
crtc_state->uapi.enable = crtc_state->hw.enable;
crtc_state->uapi.active = crtc_state->hw.active;
drm_WARN_ON(crtc_state->uapi.crtc->dev,
drm_atomic_set_mode_for_crtc(&crtc_state->uapi, &crtc_state->hw.mode) < 0);
crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
+ crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter;
/* copy color blobs to uapi */
drm_property_replace_blob(&crtc_state->uapi.degamma_lut,
@@ -13317,7 +13620,49 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state
}
static int
-intel_crtc_prepare_cleared_state(struct intel_crtc_state *crtc_state)
+copy_bigjoiner_crtc_state(struct intel_crtc_state *crtc_state,
+ const struct intel_crtc_state *from_crtc_state)
+{
+ struct intel_crtc_state *saved_state;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+ saved_state = kmemdup(from_crtc_state, sizeof(*saved_state), GFP_KERNEL);
+ if (!saved_state)
+ return -ENOMEM;
+
+ saved_state->uapi = crtc_state->uapi;
+ saved_state->scaler_state = crtc_state->scaler_state;
+ saved_state->shared_dpll = crtc_state->shared_dpll;
+ saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
+ saved_state->crc_enabled = crtc_state->crc_enabled;
+
+ intel_crtc_free_hw_state(crtc_state);
+ memcpy(crtc_state, saved_state, sizeof(*crtc_state));
+ kfree(saved_state);
+
+ /* Re-init hw state */
+ memset(&crtc_state->hw, 0, sizeof(saved_state->hw));
+ crtc_state->hw.enable = from_crtc_state->hw.enable;
+ crtc_state->hw.active = from_crtc_state->hw.active;
+ crtc_state->hw.pipe_mode = from_crtc_state->hw.pipe_mode;
+ crtc_state->hw.adjusted_mode = from_crtc_state->hw.adjusted_mode;
+
+ /* Some fixups */
+ crtc_state->uapi.mode_changed = from_crtc_state->uapi.mode_changed;
+ crtc_state->uapi.connectors_changed = from_crtc_state->uapi.connectors_changed;
+ crtc_state->uapi.active_changed = from_crtc_state->uapi.active_changed;
+ crtc_state->nv12_planes = crtc_state->c8_planes = crtc_state->update_planes = 0;
+ crtc_state->bigjoiner_linked_crtc = to_intel_crtc(from_crtc_state->uapi.crtc);
+ crtc_state->bigjoiner_slave = true;
+ crtc_state->cpu_transcoder = (enum transcoder)crtc->pipe;
+ crtc_state->has_audio = false;
+
+ return 0;
+}
+
+static int
+intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -13349,16 +13694,16 @@ intel_crtc_prepare_cleared_state(struct intel_crtc_state *crtc_state)
memcpy(crtc_state, saved_state, sizeof(*crtc_state));
kfree(saved_state);
- intel_crtc_copy_uapi_to_hw_state(crtc_state);
+ intel_crtc_copy_uapi_to_hw_state(state, crtc_state);
return 0;
}
static int
-intel_modeset_pipe_config(struct intel_crtc_state *pipe_config)
+intel_modeset_pipe_config(struct intel_atomic_state *state,
+ struct intel_crtc_state *pipe_config)
{
struct drm_crtc *crtc = pipe_config->uapi.crtc;
- struct drm_atomic_state *state = pipe_config->uapi.state;
struct drm_i915_private *i915 = to_i915(pipe_config->uapi.crtc->dev);
struct drm_connector *connector;
struct drm_connector_state *connector_state;
@@ -13400,7 +13745,7 @@ intel_modeset_pipe_config(struct intel_crtc_state *pipe_config)
&pipe_config->pipe_src_w,
&pipe_config->pipe_src_h);
- for_each_new_connector_in_state(state, connector, connector_state, i) {
+ for_each_new_connector_in_state(&state->base, connector, connector_state, i) {
struct intel_encoder *encoder =
to_intel_encoder(connector_state->best_encoder);
@@ -13438,7 +13783,7 @@ encoder_retry:
* adjust it according to limitations or connector properties, and also
* a chance to reject the mode entirely.
*/
- for_each_new_connector_in_state(state, connector, connector_state, i) {
+ for_each_new_connector_in_state(&state->base, connector, connector_state, i) {
struct intel_encoder *encoder =
to_intel_encoder(connector_state->best_encoder);
@@ -13898,21 +14243,53 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_X(output_types);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hdisplay);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_htotal);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_end);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_end);
-
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vdisplay);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vtotal);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_end);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_end);
-
- PIPE_CONF_CHECK_I(pixel_multiplier);
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE)) {
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hsync_end);
+
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vsync_end);
+
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_end);
+
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_end);
+
+ PIPE_CONF_CHECK_I(pixel_multiplier);
+
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_INTERLACE);
+
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_PHSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_NHSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_PVSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_NVSYNC);
+ }
+ }
+
PIPE_CONF_CHECK_I(output_format);
PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
@@ -13922,24 +14299,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(hdmi_scrambling);
PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio);
PIPE_CONF_CHECK_BOOL(has_infoframe);
- PIPE_CONF_CHECK_BOOL(fec_enable);
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE))
+ PIPE_CONF_CHECK_BOOL(fec_enable);
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_INTERLACE);
-
- if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_PHSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_NHSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_PVSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_NVSYNC);
- }
-
PIPE_CONF_CHECK_X(gmch_pfit.control);
/* pfit ratios are autocomputed by the hw on gen4+ */
if (INTEL_GEN(dev_priv) < 4)
@@ -13965,7 +14330,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
}
PIPE_CONF_CHECK_I(scaler_state.scaler_id);
- PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE))
+ PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
PIPE_CONF_CHECK_X(gamma_mode);
if (IS_CHERRYVIEW(dev_priv))
@@ -13986,48 +14353,53 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(double_wide);
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.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);
-
- PIPE_CONF_CHECK_X(dsi_pll.ctrl);
- PIPE_CONF_CHECK_X(dsi_pll.div);
-
- if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
- PIPE_CONF_CHECK_I(pipe_bpp);
-
- PIPE_CONF_CHECK_CLOCK_FUZZY(hw.adjusted_mode.crtc_clock);
- PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
-
- PIPE_CONF_CHECK_I(min_voltage_level);
+
+ /* FIXME do the readout properly and get rid of this quirk */
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE)) {
+ 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.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);
+
+ PIPE_CONF_CHECK_X(dsi_pll.ctrl);
+ PIPE_CONF_CHECK_X(dsi_pll.div);
+
+ if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
+ PIPE_CONF_CHECK_I(pipe_bpp);
+
+ PIPE_CONF_CHECK_CLOCK_FUZZY(hw.pipe_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(hw.adjusted_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
+
+ PIPE_CONF_CHECK_I(min_voltage_level);
+ }
PIPE_CONF_CHECK_X(infoframes.enable);
PIPE_CONF_CHECK_X(infoframes.gcp);
@@ -14039,6 +14411,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_X(sync_mode_slaves_mask);
PIPE_CONF_CHECK_I(master_transcoder);
+ PIPE_CONF_CHECK_BOOL(bigjoiner);
+ PIPE_CONF_CHECK_BOOL(bigjoiner_slave);
+ PIPE_CONF_CHECK_P(bigjoiner_linked_crtc);
PIPE_CONF_CHECK_I(dsc.compression_enable);
PIPE_CONF_CHECK_I(dsc.dsc_split);
@@ -14310,6 +14685,7 @@ verify_crtc_state(struct intel_crtc *crtc,
struct intel_encoder *encoder;
struct intel_crtc_state *pipe_config = old_crtc_state;
struct drm_atomic_state *state = old_crtc_state->uapi.state;
+ struct intel_crtc *master = crtc;
__drm_atomic_helper_crtc_destroy_state(&old_crtc_state->uapi);
intel_crtc_free_hw_state(old_crtc_state);
@@ -14321,8 +14697,7 @@ verify_crtc_state(struct intel_crtc *crtc,
pipe_config->hw.enable = new_crtc_state->hw.enable;
- pipe_config->hw.active =
- dev_priv->display.get_pipe_config(crtc, pipe_config);
+ intel_crtc_get_pipe_config(pipe_config);
/* we keep both pipes enabled on 830 */
if (IS_I830(dev_priv) && pipe_config->hw.active)
@@ -14338,7 +14713,10 @@ verify_crtc_state(struct intel_crtc *crtc,
"(expected %i, found %i)\n",
new_crtc_state->hw.active, crtc->active);
- for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+ if (new_crtc_state->bigjoiner_slave)
+ master = new_crtc_state->bigjoiner_linked_crtc;
+
+ for_each_encoder_on_crtc(dev, &master->base, encoder) {
enum pipe pipe;
bool active;
@@ -14348,16 +14726,14 @@ verify_crtc_state(struct intel_crtc *crtc,
encoder->base.base.id, active,
new_crtc_state->hw.active);
- I915_STATE_WARN(active && crtc->pipe != pipe,
+ I915_STATE_WARN(active && master->pipe != pipe,
"Encoder connected to wrong pipe %c\n",
pipe_name(pipe));
if (active)
- encoder->get_config(encoder, pipe_config);
+ intel_encoder_get_config(encoder, pipe_config);
}
- intel_crtc_compute_pixel_rate(pipe_config);
-
if (!new_crtc_state->hw.active)
return;
@@ -14398,7 +14774,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv,
drm_dbg_kms(&dev_priv->drm, "%s\n", pll->info->name);
- active = pll->info->funcs->get_hw_state(dev_priv, pll, &dpll_hw_state);
+ active = intel_dpll_get_hw_state(dev_priv, pll, &dpll_hw_state);
if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) {
I915_STATE_WARN(!pll->on && pll->active_mask,
@@ -14734,6 +15110,44 @@ static bool active_planes_affects_min_cdclk(struct drm_i915_private *dev_priv)
IS_IVYBRIDGE(dev_priv) || (INTEL_GEN(dev_priv) >= 11);
}
+static int intel_crtc_add_bigjoiner_planes(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_crtc *other)
+{
+ const struct intel_plane_state *plane_state;
+ struct intel_plane *plane;
+ u8 plane_ids = 0;
+ int i;
+
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+ if (plane->pipe == crtc->pipe)
+ plane_ids |= BIT(plane->id);
+ }
+
+ return intel_crtc_add_planes_to_state(state, other, plane_ids);
+}
+
+static int intel_bigjoiner_add_affected_planes(struct intel_atomic_state *state)
+{
+ const struct intel_crtc_state *crtc_state;
+ struct intel_crtc *crtc;
+ int i;
+
+ for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
+ int ret;
+
+ if (!crtc_state->bigjoiner)
+ continue;
+
+ ret = intel_crtc_add_bigjoiner_planes(state, crtc,
+ crtc_state->bigjoiner_linked_crtc);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int intel_atomic_check_planes(struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
@@ -14747,6 +15161,10 @@ static int intel_atomic_check_planes(struct intel_atomic_state *state)
if (ret)
return ret;
+ ret = intel_bigjoiner_add_affected_planes(state);
+ if (ret)
+ return ret;
+
for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
ret = intel_plane_atomic_check(state, plane);
if (ret) {
@@ -14853,8 +15271,10 @@ static int intel_atomic_check_crtcs(struct intel_atomic_state *state)
int i;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
- int ret = intel_crtc_atomic_check(state, crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ int ret;
+
+ ret = intel_crtc_atomic_check(state, crtc);
if (ret) {
drm_dbg_atomic(&i915->drm,
"[CRTC:%d:%s] atomic driver check failed\n",
@@ -14883,6 +15303,229 @@ static bool intel_cpu_transcoders_need_modeset(struct intel_atomic_state *state,
return false;
}
+static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_crtc_state *old_crtc_state,
+ struct intel_crtc_state *new_crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *slave_crtc_state, *master_crtc_state;
+ struct intel_crtc *slave, *master;
+
+ /* slave being enabled, is master is still claiming this crtc? */
+ if (old_crtc_state->bigjoiner_slave) {
+ slave = crtc;
+ master = old_crtc_state->bigjoiner_linked_crtc;
+ master_crtc_state = intel_atomic_get_new_crtc_state(state, master);
+ if (!master_crtc_state || !needs_modeset(master_crtc_state))
+ goto claimed;
+ }
+
+ if (!new_crtc_state->bigjoiner)
+ return 0;
+
+ if (1 + crtc->pipe >= INTEL_NUM_PIPES(dev_priv)) {
+ DRM_DEBUG_KMS("[CRTC:%d:%s] Big joiner configuration requires "
+ "CRTC + 1 to be used, doesn't exist\n",
+ crtc->base.base.id, crtc->base.name);
+ return -EINVAL;
+ }
+
+ slave = new_crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+ slave_crtc_state = intel_atomic_get_crtc_state(&state->base, slave);
+ master = crtc;
+ if (IS_ERR(slave_crtc_state))
+ return PTR_ERR(slave_crtc_state);
+
+ /* master being enabled, slave was already configured? */
+ if (slave_crtc_state->uapi.enable)
+ goto claimed;
+
+ DRM_DEBUG_KMS("[CRTC:%d:%s] Used as slave for big joiner\n",
+ slave->base.base.id, slave->base.name);
+
+ return copy_bigjoiner_crtc_state(slave_crtc_state, new_crtc_state);
+
+claimed:
+ DRM_DEBUG_KMS("[CRTC:%d:%s] Slave is enabled as normal CRTC, but "
+ "[CRTC:%d:%s] claiming this CRTC for bigjoiner.\n",
+ slave->base.base.id, slave->base.name,
+ master->base.base.id, master->base.name);
+ return -EINVAL;
+}
+
+static int kill_bigjoiner_slave(struct intel_atomic_state *state,
+ struct intel_crtc_state *master_crtc_state)
+{
+ struct intel_crtc_state *slave_crtc_state =
+ intel_atomic_get_crtc_state(&state->base,
+ master_crtc_state->bigjoiner_linked_crtc);
+
+ if (IS_ERR(slave_crtc_state))
+ return PTR_ERR(slave_crtc_state);
+
+ slave_crtc_state->bigjoiner = master_crtc_state->bigjoiner = false;
+ slave_crtc_state->bigjoiner_slave = master_crtc_state->bigjoiner_slave = false;
+ slave_crtc_state->bigjoiner_linked_crtc = master_crtc_state->bigjoiner_linked_crtc = NULL;
+ intel_crtc_copy_uapi_to_hw_state(state, slave_crtc_state);
+ return 0;
+}
+
+/**
+ * DOC: asynchronous flip implementation
+ *
+ * Asynchronous page flip is the implementation for the DRM_MODE_PAGE_FLIP_ASYNC
+ * flag. Currently async flip is only supported via the drmModePageFlip IOCTL.
+ * Correspondingly, support is currently added for primary plane only.
+ *
+ * Async flip can only change the plane surface address, so anything else
+ * changing is rejected from the intel_atomic_check_async() function.
+ * Once this check is cleared, flip done interrupt is enabled using
+ * the skl_enable_flip_done() function.
+ *
+ * As soon as the surface address register is written, flip done interrupt is
+ * generated and the requested events are sent to the usersapce in the interrupt
+ * handler itself. The timestamp and sequence sent during the flip done event
+ * correspond to the last vblank and have no relation to the actual time when
+ * the flip done event was sent.
+ */
+static int intel_atomic_check_async(struct intel_atomic_state *state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ const struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+ const struct intel_plane_state *new_plane_state, *old_plane_state;
+ struct intel_crtc *crtc;
+ struct intel_plane *plane;
+ int i;
+
+ for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+ new_crtc_state, i) {
+ if (needs_modeset(new_crtc_state)) {
+ drm_dbg_kms(&i915->drm, "Modeset Required. Async flip not supported\n");
+ return -EINVAL;
+ }
+
+ if (!new_crtc_state->hw.active) {
+ drm_dbg_kms(&i915->drm, "CRTC inactive\n");
+ return -EINVAL;
+ }
+ if (old_crtc_state->active_planes != new_crtc_state->active_planes) {
+ drm_dbg_kms(&i915->drm,
+ "Active planes cannot be changed during async flip\n");
+ return -EINVAL;
+ }
+ }
+
+ for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
+ new_plane_state, i) {
+ /*
+ * TODO: Async flip is only supported through the page flip IOCTL
+ * as of now. So support currently added for primary plane only.
+ * Support for other planes on platforms on which supports
+ * this(vlv/chv and icl+) should be added when async flip is
+ * enabled in the atomic IOCTL path.
+ */
+ if (plane->id != PLANE_PRIMARY)
+ return -EINVAL;
+
+ /*
+ * FIXME: This check is kept generic for all platforms.
+ * Need to verify this for all gen9 and gen10 platforms to enable
+ * this selectively if required.
+ */
+ switch (new_plane_state->hw.fb->modifier) {
+ case I915_FORMAT_MOD_X_TILED:
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Yf_TILED:
+ break;
+ default:
+ drm_dbg_kms(&i915->drm,
+ "Linear memory/CCS does not support async flips\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->color_plane[0].stride !=
+ new_plane_state->color_plane[0].stride) {
+ drm_dbg_kms(&i915->drm, "Stride cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.fb->modifier !=
+ new_plane_state->hw.fb->modifier) {
+ drm_dbg_kms(&i915->drm,
+ "Framebuffer modifiers cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.fb->format !=
+ new_plane_state->hw.fb->format) {
+ drm_dbg_kms(&i915->drm,
+ "Framebuffer format cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.rotation !=
+ new_plane_state->hw.rotation) {
+ drm_dbg_kms(&i915->drm, "Rotation cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (!drm_rect_equals(&old_plane_state->uapi.src, &new_plane_state->uapi.src) ||
+ !drm_rect_equals(&old_plane_state->uapi.dst, &new_plane_state->uapi.dst)) {
+ drm_dbg_kms(&i915->drm,
+ "Plane size/co-ordinates cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.alpha != new_plane_state->hw.alpha) {
+ drm_dbg_kms(&i915->drm, "Alpha value cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.pixel_blend_mode !=
+ new_plane_state->hw.pixel_blend_mode) {
+ drm_dbg_kms(&i915->drm,
+ "Pixel blend mode cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.color_encoding != new_plane_state->hw.color_encoding) {
+ drm_dbg_kms(&i915->drm,
+ "Color encoding cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+
+ if (old_plane_state->hw.color_range != new_plane_state->hw.color_range) {
+ drm_dbg_kms(&i915->drm, "Color range cannot be changed in async flip\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int intel_bigjoiner_add_affected_crtcs(struct intel_atomic_state *state)
+{
+ const struct intel_crtc_state *crtc_state;
+ struct intel_crtc *crtc;
+ int i;
+
+ for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
+ struct intel_crtc_state *linked_crtc_state;
+
+ if (!crtc_state->bigjoiner)
+ continue;
+
+ linked_crtc_state = intel_atomic_get_crtc_state(&state->base,
+ crtc_state->bigjoiner_linked_crtc);
+ if (IS_ERR(linked_crtc_state))
+ return PTR_ERR(linked_crtc_state);
+ }
+
+ return 0;
+}
+
/**
* intel_atomic_check - validate state object
* @dev: drm device
@@ -14908,23 +15551,44 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
goto fail;
+ ret = intel_bigjoiner_add_affected_crtcs(state);
+ if (ret)
+ goto fail;
+
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
if (!needs_modeset(new_crtc_state)) {
/* Light copy */
- intel_crtc_copy_uapi_to_hw_state_nomodeset(new_crtc_state);
+ intel_crtc_copy_uapi_to_hw_state_nomodeset(state, new_crtc_state);
+
+ continue;
+ }
+
+ /* Kill old bigjoiner link, we may re-establish afterwards */
+ if (old_crtc_state->bigjoiner && !old_crtc_state->bigjoiner_slave) {
+ ret = kill_bigjoiner_slave(state, new_crtc_state);
+ if (ret)
+ goto fail;
+ }
+ if (!new_crtc_state->uapi.enable) {
+ if (!new_crtc_state->bigjoiner_slave) {
+ intel_crtc_copy_uapi_to_hw_state(state, new_crtc_state);
+ any_ms = true;
+ }
continue;
}
- ret = intel_crtc_prepare_cleared_state(new_crtc_state);
+ ret = intel_crtc_prepare_cleared_state(state, new_crtc_state);
if (ret)
goto fail;
- if (!new_crtc_state->hw.enable)
- continue;
+ ret = intel_modeset_pipe_config(state, new_crtc_state);
+ if (ret)
+ goto fail;
- ret = intel_modeset_pipe_config(new_crtc_state);
+ ret = intel_atomic_check_bigjoiner(state, crtc, old_crtc_state,
+ new_crtc_state);
if (ret)
goto fail;
}
@@ -15051,6 +15715,12 @@ static int intel_atomic_check(struct drm_device *dev,
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
+ if (new_crtc_state->uapi.async_flip) {
+ ret = intel_atomic_check_async(state);
+ if (ret)
+ goto fail;
+ }
+
if (!needs_modeset(new_crtc_state) &&
!new_crtc_state->update_pipe)
continue;
@@ -15220,6 +15890,9 @@ static void intel_enable_crtc(struct intel_atomic_state *state,
dev_priv->display.crtc_enable(state, crtc);
+ if (new_crtc_state->bigjoiner_slave)
+ return;
+
/* vblanks work again, re-enable pipe CRC. */
intel_crtc_enable_pipe_crc(crtc);
}
@@ -15274,7 +15947,6 @@ static void intel_update_crtc(struct intel_atomic_state *state,
intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
}
-
static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *new_crtc_state,
@@ -15282,9 +15954,22 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ drm_WARN_ON(&dev_priv->drm, old_crtc_state->bigjoiner_slave);
+
intel_crtc_disable_planes(state, crtc);
/*
+ * We still need special handling for disabling bigjoiner master
+ * and slaves since for slave we do not have encoder or plls
+ * so we dont need to disable those.
+ */
+ if (old_crtc_state->bigjoiner) {
+ intel_crtc_disable_planes(state,
+ old_crtc_state->bigjoiner_linked_crtc);
+ old_crtc_state->bigjoiner_linked_crtc->active = false;
+ }
+
+ /*
* We need to disable pipe CRC before disabling the pipe,
* or we race against vblank off.
*/
@@ -15312,7 +15997,7 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
/* Only disable port sync and MST slaves */
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
- if (!needs_modeset(new_crtc_state))
+ if (!needs_modeset(new_crtc_state) || old_crtc_state->bigjoiner)
continue;
if (!old_crtc_state->hw.active)
@@ -15337,10 +16022,18 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
if (!needs_modeset(new_crtc_state) ||
- (handled & BIT(crtc->pipe)))
+ (handled & BIT(crtc->pipe)) ||
+ old_crtc_state->bigjoiner_slave)
continue;
intel_pre_plane_update(state, crtc);
+ if (old_crtc_state->bigjoiner) {
+ struct intel_crtc *slave =
+ old_crtc_state->bigjoiner_linked_crtc;
+
+ intel_pre_plane_update(state, slave);
+ }
+
if (old_crtc_state->hw.active)
intel_old_crtc_state_disables(state, old_crtc_state,
new_crtc_state, crtc);
@@ -15438,7 +16131,8 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
continue;
if (intel_dp_mst_is_slave_trans(new_crtc_state) ||
- is_trans_port_sync_master(new_crtc_state))
+ is_trans_port_sync_master(new_crtc_state) ||
+ (new_crtc_state->bigjoiner && !new_crtc_state->bigjoiner_slave))
continue;
modeset_pipes &= ~BIT(pipe);
@@ -15448,7 +16142,7 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
/*
* Then we enable all remaining pipes that depend on other
- * pipes: MST slaves and port sync masters.
+ * pipes: MST slaves and port sync masters, big joiner master
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
enum pipe pipe = crtc->pipe;
@@ -15616,6 +16310,11 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_dbuf_pre_plane_update(state);
+ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+ if (new_crtc_state->uapi.async_flip)
+ skl_enable_flip_done(crtc);
+ }
+
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
dev_priv->display.commit_modeset_enables(state);
@@ -15637,6 +16336,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
drm_atomic_helper_wait_for_flip_done(dev, &state->base);
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
+ if (new_crtc_state->uapi.async_flip)
+ skl_disable_flip_done(crtc);
+
if (new_crtc_state->hw.active &&
!needs_modeset(new_crtc_state) &&
!new_crtc_state->preload_luts &&
@@ -16232,9 +16934,11 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
/*
* When crtc is inactive or there is a modeset pending,
* wait for it to complete in the slowpath
+ *
+ * FIXME bigjoiner fastpath would be good
*/
if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
- crtc_state->update_pipe)
+ crtc_state->update_pipe || crtc_state->bigjoiner)
goto slow;
/*
@@ -16280,7 +16984,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
new_plane_state->uapi.crtc_w = crtc_w;
new_plane_state->uapi.crtc_h = crtc_h;
- intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state);
+ intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
old_plane_state, new_plane_state);
@@ -16751,6 +17455,11 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
}
+ if (INTEL_GEN(dev_priv) >= 10)
+ drm_crtc_create_scaling_filter_property(&crtc->base,
+ BIT(DRM_SCALING_FILTER_DEFAULT) |
+ BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
+
intel_color_init(crtc);
intel_crtc_crc_init(crtc);
@@ -16892,22 +17601,22 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
if (!HAS_DISPLAY(dev_priv))
return;
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) {
intel_ddi_init(dev_priv, PORT_A);
intel_ddi_init(dev_priv, PORT_B);
- intel_ddi_init(dev_priv, PORT_D); /* DDI TC1 */
- intel_ddi_init(dev_priv, PORT_E); /* DDI TC2 */
+ intel_ddi_init(dev_priv, PORT_TC1);
+ intel_ddi_init(dev_priv, PORT_TC2);
} else if (INTEL_GEN(dev_priv) >= 12) {
intel_ddi_init(dev_priv, PORT_A);
intel_ddi_init(dev_priv, PORT_B);
- intel_ddi_init(dev_priv, PORT_D);
- intel_ddi_init(dev_priv, PORT_E);
- intel_ddi_init(dev_priv, PORT_F);
- intel_ddi_init(dev_priv, PORT_G);
- intel_ddi_init(dev_priv, PORT_H);
- intel_ddi_init(dev_priv, PORT_I);
+ intel_ddi_init(dev_priv, PORT_TC1);
+ intel_ddi_init(dev_priv, PORT_TC2);
+ intel_ddi_init(dev_priv, PORT_TC3);
+ intel_ddi_init(dev_priv, PORT_TC4);
+ intel_ddi_init(dev_priv, PORT_TC5);
+ intel_ddi_init(dev_priv, PORT_TC6);
icl_dsi_init(dev_priv);
- } else if (IS_ELKHARTLAKE(dev_priv)) {
+ } else if (IS_JSL_EHL(dev_priv)) {
intel_ddi_init(dev_priv, PORT_A);
intel_ddi_init(dev_priv, PORT_B);
intel_ddi_init(dev_priv, PORT_C);
@@ -17432,7 +18141,8 @@ intel_mode_valid(struct drm_device *dev,
enum drm_mode_status
intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
- const struct drm_display_mode *mode)
+ const struct drm_display_mode *mode,
+ bool bigjoiner)
{
int plane_width_max, plane_height_max;
@@ -17449,7 +18159,7 @@ intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
* too big for that.
*/
if (INTEL_GEN(dev_priv) >= 11) {
- plane_width_max = 5120;
+ plane_width_max = 5120 << bigjoiner;
plane_height_max = 4320;
} else {
plane_width_max = 5120;
@@ -17742,6 +18452,8 @@ retry:
}
if (crtc_state->hw.active) {
+ struct intel_encoder *encoder;
+
/*
* We've not yet detected sink capabilities
* (audio,infoframes,etc.) and thus we don't want to
@@ -17763,22 +18475,15 @@ retry:
*/
crtc_state->uapi.color_mgmt_changed = true;
- /*
- * FIXME hack to force full modeset when DSC is being
- * used.
- *
- * As long as we do not have full state readout and
- * config comparison of crtc_state->dsc, we have no way
- * to ensure reliable fastset. Remove once we have
- * readout for DSC.
- */
- if (crtc_state->dsc.compression_enable) {
- ret = drm_atomic_add_affected_connectors(state,
- &crtc->base);
- if (ret)
- goto out;
- crtc_state->uapi.mode_changed = true;
- drm_dbg_kms(dev, "Force full modeset for DSC\n");
+ for_each_intel_encoder_mask(dev, encoder,
+ crtc_state->uapi.encoder_mask) {
+ if (encoder->initial_fastset_check &&
+ !encoder->initial_fastset_check(encoder, crtc_state)) {
+ ret = drm_atomic_add_affected_connectors(state,
+ &crtc->base);
+ if (ret)
+ goto out;
+ }
}
}
}
@@ -17817,6 +18522,9 @@ static void intel_mode_config_init(struct drm_i915_private *i915)
mode_config->funcs = &intel_mode_funcs;
+ if (INTEL_GEN(i915) >= 9)
+ mode_config->async_page_flip = true;
+
/*
* Maximum framebuffer dimensions, chosen to match
* the maximum render engine surface size on gen4+.
@@ -17992,7 +18700,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
for_each_intel_crtc(dev, crtc) {
struct intel_initial_plane_config plane_config = {};
- if (!crtc->active)
+ if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
continue;
/*
@@ -18050,11 +18758,10 @@ int intel_modeset_init(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);
intel_init_ipc(i915);
- intel_psr_set_force_mode_changed(i915->psr.dp);
-
return 0;
}
@@ -18304,7 +19011,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
/* Adjust the state of the output pipe according to whether we
* have active connectors/encoders. */
- if (crtc_state->hw.active && !intel_crtc_has_encoders(crtc))
+ if (crtc_state->hw.active && !intel_crtc_has_encoders(crtc) &&
+ !crtc_state->bigjoiner_slave)
intel_crtc_disable_noatomic(crtc, ctx);
if (crtc_state->hw.active || HAS_GMCH(dev_priv)) {
@@ -18483,8 +19191,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
intel_crtc_free_hw_state(crtc_state);
intel_crtc_state_reset(crtc_state, crtc);
- crtc_state->hw.active = crtc_state->hw.enable =
- dev_priv->display.get_pipe_config(crtc, crtc_state);
+ intel_crtc_get_pipe_config(crtc_state);
+
+ crtc_state->hw.enable = crtc_state->hw.active;
crtc->base.enabled = crtc_state->hw.enable;
crtc->active = crtc_state->hw.active;
@@ -18515,7 +19224,19 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
crtc_state = to_intel_crtc_state(crtc->base.state);
encoder->base.crtc = &crtc->base;
- encoder->get_config(encoder, crtc_state);
+ intel_encoder_get_config(encoder, crtc_state);
+ if (encoder->sync_state)
+ encoder->sync_state(encoder, crtc_state);
+
+ /* read out to slave crtc as well for bigjoiner */
+ if (crtc_state->bigjoiner) {
+ /* encoder should read be linked to bigjoiner master */
+ WARN_ON(crtc_state->bigjoiner_slave);
+
+ crtc = crtc_state->bigjoiner_linked_crtc;
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+ intel_encoder_get_config(encoder, crtc_state);
+ }
} else {
encoder->base.crtc = NULL;
}
@@ -18571,16 +19292,10 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
struct intel_plane *plane;
int min_cdclk = 0;
- if (crtc_state->hw.active) {
- struct drm_display_mode *mode = &crtc_state->hw.mode;
-
- intel_mode_from_pipe_config(&crtc_state->hw.adjusted_mode,
- crtc_state);
-
- *mode = crtc_state->hw.adjusted_mode;
- mode->hdisplay = crtc_state->pipe_src_w;
- mode->vdisplay = crtc_state->pipe_src_h;
+ if (crtc_state->bigjoiner_slave)
+ continue;
+ if (crtc_state->hw.active) {
/*
* The initial mode needs to be set in order to keep
* the atomic core happy. It wants a valid mode if the
@@ -18592,8 +19307,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
*/
crtc_state->inherited = true;
- intel_crtc_compute_pixel_rate(crtc_state);
-
intel_crtc_update_active_timings(crtc_state);
intel_crtc_copy_hw_to_uapi_state(crtc_state);
@@ -18642,6 +19355,39 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
intel_bw_crtc_update(bw_state, crtc_state);
intel_pipe_config_sanity_check(dev_priv, crtc_state);
+
+ /* discard our incomplete slave state, copy it from master */
+ if (crtc_state->bigjoiner && crtc_state->hw.active) {
+ struct intel_crtc *slave = crtc_state->bigjoiner_linked_crtc;
+ struct intel_crtc_state *slave_crtc_state =
+ to_intel_crtc_state(slave->base.state);
+
+ copy_bigjoiner_crtc_state(slave_crtc_state, crtc_state);
+ slave->base.mode = crtc->base.mode;
+
+ cdclk_state->min_cdclk[slave->pipe] = min_cdclk;
+ cdclk_state->min_voltage_level[slave->pipe] =
+ crtc_state->min_voltage_level;
+
+ for_each_intel_plane_on_crtc(&dev_priv->drm, slave, plane) {
+ const struct intel_plane_state *plane_state =
+ to_intel_plane_state(plane->base.state);
+
+ /*
+ * FIXME don't have the fb yet, so can't
+ * use intel_plane_data_rate() :(
+ */
+ if (plane_state->uapi.visible)
+ crtc_state->data_rate[plane->id] =
+ 4 * crtc_state->pixel_rate;
+ else
+ crtc_state->data_rate[plane->id] = 0;
+ }
+
+ intel_bw_crtc_update(bw_state, slave_crtc_state);
+ drm_calc_timestamping_constants(&slave->base,
+ &slave_crtc_state->hw.adjusted_mode);
+ }
}
}
@@ -18686,6 +19432,15 @@ static void intel_early_display_was(struct drm_i915_private *dev_priv)
intel_de_write(dev_priv, CHICKEN_PAR1_1,
intel_de_read(dev_priv, CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
}
+
+ if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv)) {
+ /* Display WA #1142:kbl,cfl,cml */
+ intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
+ KBL_ARB_FILL_SPARE_22, KBL_ARB_FILL_SPARE_22);
+ intel_de_rmw(dev_priv, CHICKEN_MISC_2,
+ KBL_ARB_FILL_SPARE_13 | KBL_ARB_FILL_SPARE_14,
+ KBL_ARB_FILL_SPARE_14);
+ }
}
static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index d10b7c8cde3f..5e0d42d82c11 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -28,6 +28,7 @@
#include <drm/drm_util.h>
enum link_m_n_set;
+enum drm_scaling_filter;
struct dpll;
struct drm_connector;
struct drm_device;
@@ -207,6 +208,14 @@ enum port {
PORT_H,
PORT_I,
+ /* tgl+ */
+ PORT_TC1 = PORT_D,
+ PORT_TC2,
+ PORT_TC3,
+ PORT_TC4,
+ PORT_TC5,
+ PORT_TC6,
+
I915_MAX_PORTS
};
@@ -243,14 +252,14 @@ static inline const char *port_identifier(enum port port)
}
enum tc_port {
- PORT_TC_NONE = -1,
+ TC_PORT_NONE = -1,
- PORT_TC1 = 0,
- PORT_TC2,
- PORT_TC3,
- PORT_TC4,
- PORT_TC5,
- PORT_TC6,
+ TC_PORT_1 = 0,
+ TC_PORT_2,
+ TC_PORT_3,
+ TC_PORT_4,
+ TC_PORT_5,
+ TC_PORT_6,
I915_MAX_TC_PORTS
};
@@ -282,6 +291,14 @@ enum aux_ch {
AUX_CH_G,
AUX_CH_H,
AUX_CH_I,
+
+ /* tgl+ */
+ AUX_CH_USBC1 = AUX_CH_D,
+ AUX_CH_USBC2,
+ AUX_CH_USBC3,
+ AUX_CH_USBC4,
+ AUX_CH_USBC5,
+ AUX_CH_USBC6,
};
#define aux_ch_name(a) ((a) + 'A')
@@ -496,7 +513,8 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
bool intel_plane_can_remap(const struct intel_plane_state *plane_state);
enum drm_mode_status
intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
- const struct drm_display_mode *mode);
+ const struct drm_display_mode *mode,
+ bool bigjoiner);
enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port);
bool is_trans_port_sync_mode(const struct intel_crtc_state *state);
@@ -573,8 +591,8 @@ void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe);
int lpt_get_iclkip(struct drm_i915_private *dev_priv);
bool intel_fuzzy_clock_check(int clock1, int clock2);
-void intel_prepare_reset(struct drm_i915_private *dev_priv);
-void intel_finish_reset(struct drm_i915_private *dev_priv);
+void intel_display_prepare_reset(struct drm_i915_private *dev_priv);
+void intel_display_finish_reset(struct drm_i915_private *dev_priv);
void intel_dp_get_m_n(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state,
@@ -592,13 +610,14 @@ enum intel_display_power_domain
intel_aux_power_domain(struct intel_digital_port *dig_port);
enum intel_display_power_domain
intel_legacy_aux_to_power_domain(enum aux_ch aux_ch);
-void intel_mode_from_pipe_config(struct drm_display_mode *mode,
- struct intel_crtc_state *pipe_config);
void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state);
u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_center);
void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state);
+u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set);
+void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
+ int id, int set, enum drm_scaling_filter filter);
void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 0bf31f9a8af5..ca41e8c00ad7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -518,8 +518,13 @@ static int i915_dmc_info(struct seq_file *m, void *unused)
CSR_VERSION_MINOR(csr->version));
if (INTEL_GEN(dev_priv) >= 12) {
- dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
- dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
+ if (IS_DGFX(dev_priv)) {
+ dc5_reg = DG1_DMC_DEBUG_DC5_COUNT;
+ } else {
+ dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
+ dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
+ }
+
/*
* NOTE: DMC_DEBUG3 is a general purpose reg.
* According to B.Specs:49196 DMC f/w reuses DC5/6 counter
@@ -750,6 +755,17 @@ static void plane_rotation(char *buf, size_t bufsize, unsigned int rotation)
rotation);
}
+static const char *plane_visibility(const struct intel_plane_state *plane_state)
+{
+ if (plane_state->uapi.visible)
+ return "visible";
+
+ if (plane_state->planar_slave)
+ return "planar-slave";
+
+ return "hidden";
+}
+
static void intel_plane_uapi_info(struct seq_file *m, struct intel_plane *plane)
{
const struct intel_plane_state *plane_state =
@@ -768,12 +784,19 @@ static void intel_plane_uapi_info(struct seq_file *m, struct intel_plane *plane)
plane_rotation(rot_str, sizeof(rot_str),
plane_state->uapi.rotation);
- seq_printf(m, "\t\tuapi: fb=%d,%s,%dx%d, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
+ seq_printf(m, "\t\tuapi: [FB:%d] %s,0x%llx,%dx%d, visible=%s, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
fb ? fb->base.id : 0, fb ? format_name.str : "n/a",
+ fb ? fb->modifier : 0,
fb ? fb->width : 0, fb ? fb->height : 0,
+ plane_visibility(plane_state),
DRM_RECT_FP_ARG(&src),
DRM_RECT_ARG(&dst),
rot_str);
+
+ if (plane_state->planar_linked_plane)
+ seq_printf(m, "\t\tplanar: Linked to [PLANE:%d:%s] as a %s\n",
+ plane_state->planar_linked_plane->base.base.id, plane_state->planar_linked_plane->base.name,
+ plane_state->planar_slave ? "slave" : "master");
}
static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane)
@@ -792,9 +815,9 @@ static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane)
plane_rotation(rot_str, sizeof(rot_str),
plane_state->hw.rotation);
- seq_printf(m, "\t\thw: fb=%d,%s,%dx%d, visible=%s, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
+ seq_printf(m, "\t\thw: [FB:%d] %s,0x%llx,%dx%d, visible=%s, src=" DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n",
fb->base.id, format_name.str,
- fb->width, fb->height,
+ fb->modifier, fb->width, fb->height,
yesno(plane_state->uapi.visible),
DRM_RECT_FP_ARG(&plane_state->uapi.src),
DRM_RECT_ARG(&plane_state->uapi.dst),
@@ -869,6 +892,12 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc)
intel_scaler_info(m, crtc);
}
+ if (crtc_state->bigjoiner)
+ seq_printf(m, "\tLinked to [CRTC:%d:%s] as a %s\n",
+ crtc_state->bigjoiner_linked_crtc->base.base.id,
+ crtc_state->bigjoiner_linked_crtc->base.name,
+ crtc_state->bigjoiner_slave ? "slave" : "master");
+
for_each_intel_encoder_mask(&dev_priv->drm, encoder,
crtc_state->uapi.encoder_mask)
intel_encoder_info(m, crtc, encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 7277e58b01f1..fe2d90bba536 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -1424,6 +1424,7 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
return;
intel_hpd_init(dev_priv);
+ intel_hpd_poll_disable(dev_priv);
/* Re-enable the ADPA, if we have one */
for_each_intel_encoder(&dev_priv->drm, encoder) {
@@ -1449,7 +1450,7 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
/* Prevent us from re-enabling polling on accident in late suspend */
if (!dev_priv->drm.dev->power.is_suspended)
- intel_hpd_poll_init(dev_priv);
+ intel_hpd_poll_enable(dev_priv);
}
static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
@@ -3650,7 +3651,7 @@ static const struct i915_power_well_desc cnl_power_wells[] = {
.name = "DDI F IO power well",
.domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = DISP_PW_ID_NONE,
+ .id = CNL_DISP_PW_DDI_F_IO,
{
.hsw.regs = &hsw_power_well_regs,
.hsw.idx = CNL_PW_CTL_IDX_DDI_F,
@@ -3660,7 +3661,7 @@ static const struct i915_power_well_desc cnl_power_wells[] = {
.name = "AUX F",
.domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = DISP_PW_ID_NONE,
+ .id = CNL_DISP_PW_DDI_F_AUX,
{
.hsw.regs = &hsw_power_well_regs,
.hsw.idx = CNL_PW_CTL_IDX_AUX_F,
@@ -4150,7 +4151,7 @@ static const struct i915_power_well_desc tgl_power_wells[] = {
.name = "TC cold off",
.domains = TGL_TC_COLD_OFF_POWER_DOMAINS,
.ops = &tgl_tc_cold_off_ops,
- .id = DISP_PW_ID_NONE,
+ .id = TGL_DISP_PW_TC_COLD_OFF,
},
{
.name = "AUX A",
@@ -4491,27 +4492,24 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
int requested_dc;
int max_dc;
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (IS_DG1(dev_priv))
+ max_dc = 3;
+ else if (INTEL_GEN(dev_priv) >= 12)
max_dc = 4;
- /*
- * DC9 has a separate HW flow from the rest of the DC states,
- * not depending on the DMC firmware. It's needed by system
- * suspend/resume, so allow it unconditionally.
- */
- mask = DC_STATE_EN_DC9;
- } else if (IS_GEN(dev_priv, 11)) {
- max_dc = 2;
- mask = DC_STATE_EN_DC9;
- } else if (IS_GEN(dev_priv, 10) || IS_GEN9_BC(dev_priv)) {
+ else if (INTEL_GEN(dev_priv) >= 10 || IS_GEN9_BC(dev_priv))
max_dc = 2;
- mask = 0;
- } else if (IS_GEN9_LP(dev_priv)) {
+ else if (IS_GEN9_LP(dev_priv))
max_dc = 1;
- mask = DC_STATE_EN_DC9;
- } else {
+ else
max_dc = 0;
- mask = 0;
- }
+
+ /*
+ * DC9 has a separate HW flow from the rest of the DC states,
+ * not depending on the DMC firmware. It's needed by system
+ * suspend/resume, so allow it unconditionally.
+ */
+ mask = IS_GEN9_LP(dev_priv) || INTEL_GEN(dev_priv) >= 11 ?
+ DC_STATE_EN_DC9 : 0;
if (!dev_priv->params.disable_power_well)
max_dc = 0;
@@ -4554,13 +4552,18 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
static int
__set_power_wells(struct i915_power_domains *power_domains,
const struct i915_power_well_desc *power_well_descs,
- int power_well_count)
+ int power_well_descs_sz, u64 skip_mask)
{
struct drm_i915_private *i915 = container_of(power_domains,
struct drm_i915_private,
power_domains);
u64 power_well_ids = 0;
- int i;
+ int power_well_count = 0;
+ int i, plt_idx = 0;
+
+ for (i = 0; i < power_well_descs_sz; i++)
+ if (!(BIT_ULL(power_well_descs[i].id) & skip_mask))
+ power_well_count++;
power_domains->power_well_count = power_well_count;
power_domains->power_wells =
@@ -4570,10 +4573,14 @@ __set_power_wells(struct i915_power_domains *power_domains,
if (!power_domains->power_wells)
return -ENOMEM;
- for (i = 0; i < power_well_count; i++) {
+ for (i = 0; i < power_well_descs_sz; i++) {
enum i915_power_well_id id = power_well_descs[i].id;
- power_domains->power_wells[i].desc = &power_well_descs[i];
+ if (BIT_ULL(id) & skip_mask)
+ continue;
+
+ power_domains->power_wells[plt_idx++].desc =
+ &power_well_descs[i];
if (id == DISP_PW_ID_NONE)
continue;
@@ -4586,9 +4593,12 @@ __set_power_wells(struct i915_power_domains *power_domains,
return 0;
}
-#define set_power_wells(power_domains, __power_well_descs) \
+#define set_power_wells_mask(power_domains, __power_well_descs, skip_mask) \
__set_power_wells(power_domains, __power_well_descs, \
- ARRAY_SIZE(__power_well_descs))
+ ARRAY_SIZE(__power_well_descs), skip_mask)
+
+#define set_power_wells(power_domains, __power_well_descs) \
+ set_power_wells_mask(power_domains, __power_well_descs, 0)
/**
* intel_power_domains_init - initializes the power domain structures
@@ -4622,23 +4632,21 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
* The enabling order will be from lower to higher indexed wells,
* the disabling order is reversed.
*/
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ err = set_power_wells_mask(power_domains, tgl_power_wells,
+ BIT_ULL(TGL_DISP_PW_TC_COLD_OFF));
+ } else if (IS_ROCKETLAKE(dev_priv)) {
err = set_power_wells(power_domains, rkl_power_wells);
} else if (IS_GEN(dev_priv, 12)) {
err = set_power_wells(power_domains, tgl_power_wells);
} else if (IS_GEN(dev_priv, 11)) {
err = set_power_wells(power_domains, icl_power_wells);
- } else if (IS_CANNONLAKE(dev_priv)) {
+ } else if (IS_CNL_WITH_PORT_F(dev_priv)) {
err = set_power_wells(power_domains, cnl_power_wells);
-
- /*
- * DDI and Aux IO are getting enabled for all ports
- * regardless the presence or use. So, in order to avoid
- * timeouts, lets remove them from the list
- * for the SKUs without port F.
- */
- if (!IS_CNL_WITH_PORT_F(dev_priv))
- power_domains->power_well_count -= 2;
+ } else if (IS_CANNONLAKE(dev_priv)) {
+ err = set_power_wells_mask(power_domains, cnl_power_wells,
+ BIT_ULL(CNL_DISP_PW_DDI_F_IO) |
+ BIT_ULL(CNL_DISP_PW_DDI_F_AUX));
} else if (IS_GEMINILAKE(dev_priv)) {
err = set_power_wells(power_domains, glk_power_wells);
} else if (IS_BROXTON(dev_priv)) {
@@ -4758,6 +4766,17 @@ static void gen9_dbuf_disable(struct drm_i915_private *dev_priv)
gen9_dbuf_slices_update(dev_priv, 0);
}
+static void gen12_dbuf_slices_config(struct drm_i915_private *dev_priv)
+{
+ const int num_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
+ enum dbuf_slice slice;
+
+ for (slice = DBUF_S1; slice < (DBUF_S1 + num_slices); slice++)
+ intel_de_rmw(dev_priv, DBUF_CTL_S(slice),
+ DBUF_TRACKER_STATE_SERVICE_MASK,
+ DBUF_TRACKER_STATE_SERVICE(8));
+}
+
static void icl_mbus_init(struct drm_i915_private *dev_priv)
{
unsigned long abox_regs = INTEL_INFO(dev_priv)->abox_mask;
@@ -5263,8 +5282,9 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv)
unsigned long abox_mask = INTEL_INFO(dev_priv)->abox_mask;
int config, i;
- if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0))
- /* Wa_1409767108: tgl */
+ if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0) ||
+ IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0))
+ /* Wa_1409767108:tgl,dg1 */
table = wa_1409767108_buddy_page_masks;
else
table = tgl_buddy_page_masks;
@@ -5326,6 +5346,9 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
/* 4. Enable CDCLK. */
intel_cdclk_init_hw(dev_priv);
+ if (INTEL_GEN(dev_priv) >= 12)
+ gen12_dbuf_slices_config(dev_priv);
+
/* 5. Enable DBUF. */
gen9_dbuf_enable(dev_priv);
@@ -5829,10 +5852,15 @@ static void intel_power_domains_verify_state(struct drm_i915_private *i915)
void intel_display_power_suspend_late(struct drm_i915_private *i915)
{
- if (INTEL_GEN(i915) >= 11 || IS_GEN9_LP(i915))
+ if (INTEL_GEN(i915) >= 11 || IS_GEN9_LP(i915)) {
bxt_enable_dc9(i915);
- else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
+ /* Tweaked Wa_14010685332:icp,jsp,mcc */
+ if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC)
+ intel_de_rmw(i915, SOUTH_CHICKEN1,
+ SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS);
+ } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
hsw_enable_pc8(i915);
+ }
}
void intel_display_power_resume_early(struct drm_i915_private *i915)
@@ -5840,6 +5868,10 @@ void intel_display_power_resume_early(struct drm_i915_private *i915)
if (INTEL_GEN(i915) >= 11 || IS_GEN9_LP(i915)) {
gen9_sanitize_dc_state(i915);
bxt_disable_dc9(i915);
+ /* Tweaked Wa_14010685332:icp,jsp,mcc */
+ if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC)
+ intel_de_rmw(i915, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, 0);
+
} else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
hsw_disable_pc8(i915);
}
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 54c20c76057e..4aa0a09cf14f 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -101,8 +101,11 @@ enum i915_power_well_id {
SKL_DISP_PW_MISC_IO,
SKL_DISP_PW_1,
SKL_DISP_PW_2,
+ CNL_DISP_PW_DDI_F_IO,
+ CNL_DISP_PW_DDI_F_AUX,
ICL_DISP_PW_3,
SKL_DISP_DC_OFF,
+ TGL_DISP_PW_TC_COLD_OFF,
};
#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 3d4bf9b6a0a2..ce82d654d0f2 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -187,6 +187,21 @@ struct intel_encoder {
* be set correctly before calling this function. */
void (*get_config)(struct intel_encoder *,
struct intel_crtc_state *pipe_config);
+
+ /*
+ * Optional hook called during init/resume to sync any state
+ * stored in the encoder (eg. DP link parameters) wrt. the HW state.
+ */
+ void (*sync_state)(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+
+ /*
+ * Optional hook, returning true if this encoder allows a fastset
+ * during the initial commit, false otherwise.
+ */
+ bool (*initial_fastset_check)(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state);
+
/*
* Acquires the power domains needed for an active encoder during
* hardware state readout.
@@ -199,6 +214,11 @@ struct intel_encoder {
* device interrupts are disabled.
*/
void (*suspend)(struct intel_encoder *);
+ /*
+ * Called during system reboot/shutdown after all the
+ * encoders have been disabled and suspended.
+ */
+ void (*shutdown)(struct intel_encoder *encoder);
enum hpd_pin hpd_pin;
enum intel_display_power_domain power_domain;
/* for communication with audio component; protected by av_mutex */
@@ -515,6 +535,7 @@ struct intel_plane_state {
unsigned int rotation;
enum drm_color_encoding color_encoding;
enum drm_color_range color_range;
+ enum drm_scaling_filter scaling_filter;
} hw;
struct i915_ggtt_view view;
@@ -665,6 +686,7 @@ struct skl_wm_level {
u8 plane_res_l;
bool plane_en;
bool ignore_lines;
+ bool can_sagv;
};
struct skl_plane_wm {
@@ -716,24 +738,35 @@ struct g4x_wm_state {
struct intel_crtc_wm_state {
union {
+ /*
+ * raw:
+ * The "raw" watermark values produced by the formula
+ * given the plane's current state. They do not consider
+ * how much FIFO is actually allocated for each plane.
+ *
+ * optimal:
+ * The "optimal" watermark values given the current
+ * state of the planes and the amount of FIFO
+ * allocated to each, ignoring any previous state
+ * of the planes.
+ *
+ * intermediate:
+ * The "intermediate" watermark values when transitioning
+ * between the old and new "optimal" values. Used when
+ * the watermark registers are single buffered and hence
+ * their state changes asynchronously with regards to the
+ * actual plane registers. These are essentially the
+ * worst case combination of the old and new "optimal"
+ * watermarks, which are therefore safe to use when the
+ * plane is in either its old or new state.
+ */
struct {
- /*
- * Intermediate watermarks; these can be
- * programmed immediately since they satisfy
- * both the current configuration we're
- * switching away from and the new
- * configuration we're switching to.
- */
struct intel_pipe_wm intermediate;
-
- /*
- * Optimal watermarks, programmed post-vblank
- * when this state is committed.
- */
struct intel_pipe_wm optimal;
} ilk;
struct {
+ struct skl_pipe_wm raw;
/* gen9+ only needs 1-step wm programming */
struct skl_pipe_wm optimal;
struct skl_ddb_entry ddb;
@@ -742,22 +775,15 @@ struct intel_crtc_wm_state {
} skl;
struct {
- /* "raw" watermarks (not inverted) */
- struct g4x_pipe_wm raw[NUM_VLV_WM_LEVELS];
- /* intermediate watermarks (inverted) */
- struct vlv_wm_state intermediate;
- /* optimal watermarks (inverted) */
- struct vlv_wm_state optimal;
- /* display FIFO split */
+ struct g4x_pipe_wm raw[NUM_VLV_WM_LEVELS]; /* not inverted */
+ struct vlv_wm_state intermediate; /* inverted */
+ struct vlv_wm_state optimal; /* inverted */
struct vlv_fifo_state fifo_state;
} vlv;
struct {
- /* "raw" watermarks */
struct g4x_pipe_wm raw[NUM_G4X_WM_LEVELS];
- /* intermediate watermarks */
struct g4x_wm_state intermediate;
- /* optimal watermarks */
struct g4x_wm_state optimal;
} g4x;
};
@@ -796,15 +822,23 @@ struct intel_crtc_state {
* The following members are used to verify the hardware state:
* - enable
* - active
- * - mode / adjusted_mode
+ * - mode / pipe_mode / adjusted_mode
* - color property blobs.
*
* During initial hw readout, they need to be copied to uapi.
+ *
+ * Bigjoiner will allow a transcoder mode that spans 2 pipes;
+ * Use the pipe_mode for calculations like watermarks, pipe
+ * scaler, and bandwidth.
+ *
+ * Use adjusted_mode for things that need to know the full
+ * mode on the transcoder, which spans all pipes.
*/
struct {
bool active, enable;
struct drm_property_blob *degamma_lut, *gamma_lut, *ctm;
- struct drm_display_mode mode, adjusted_mode;
+ struct drm_display_mode mode, pipe_mode, adjusted_mode;
+ enum drm_scaling_filter scaling_filter;
} hw;
/**
@@ -816,6 +850,7 @@ struct intel_crtc_state {
* accordingly.
*/
#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
+#define PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE (1<<1) /* bigjoiner slave, partial readout */
unsigned long quirks;
unsigned fb_bits; /* framebuffers to flip */
@@ -997,6 +1032,10 @@ struct intel_crtc_state {
u32 data_rate[I915_MAX_PLANES];
+ /* FIXME unify with data_rate[] */
+ u64 plane_data_rate[I915_MAX_PLANES];
+ u64 uv_plane_data_rate[I915_MAX_PLANES];
+
/* Gamma mode programmed on the pipe */
u32 gamma_mode;
@@ -1035,15 +1074,21 @@ struct intel_crtc_state {
/* Output format RGB/YCBCR etc */
enum intel_output_format output_format;
- /* Output down scaling is done in LSPCON device */
- bool lspcon_downsampling;
-
/* enable pipe gamma? */
bool gamma_enable;
/* enable pipe csc? */
bool csc_enable;
+ /* enable pipe big joiner? */
+ bool bigjoiner;
+
+ /* big joiner slave crtc? */
+ bool bigjoiner_slave;
+
+ /* linked crtc for bigjoiner, either slave or master */
+ struct intel_crtc *bigjoiner_linked_crtc;
+
/* Display Stream compression state */
struct {
bool compression_enable;
@@ -1170,6 +1215,15 @@ struct intel_plane {
* the intel_plane_state structure and accessed via plane_state.
*/
+ int (*min_width)(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation);
+ int (*max_width)(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation);
+ int (*max_height)(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation);
unsigned int (*max_stride)(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation);
@@ -1183,6 +1237,9 @@ struct intel_plane {
struct intel_plane_state *plane_state);
int (*min_cdclk)(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
+ void (*async_flip)(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state);
};
struct intel_watermark_params {
@@ -1270,7 +1327,6 @@ struct intel_dp {
int link_rate;
u8 lane_count;
u8 sink_count;
- bool link_mst;
bool link_trained;
bool has_hdmi_sink;
bool has_audio;
@@ -1280,6 +1336,8 @@ struct intel_dp {
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
+ u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
+ u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
u8 fec_capable;
/* source rates */
int num_source_rates;
@@ -1312,8 +1370,6 @@ struct intel_dp {
unsigned long last_backlight_off;
ktime_t panel_power_off_time;
- struct notifier_block edp_notifier;
-
/*
* Pipe whose power sequencer is currently locked into
* this port. Only relevant on VLV/CHV.
@@ -1336,14 +1392,6 @@ struct intel_dp {
bool is_mst;
int active_mst_links;
- /*
- * DP_TP_* registers may be either on port or transcoder register space.
- */
- struct {
- i915_reg_t dp_tp_ctl;
- i915_reg_t dp_tp_status;
- } regs;
-
/* connector directly attached - won't be use for modeset in mst world */
struct intel_connector *attached_connector;
@@ -1363,13 +1411,19 @@ struct intel_dp {
i915_reg_t (*aux_ch_data_reg)(struct intel_dp *dp, int index);
/* This is called before a link training is starterd */
- void (*prepare_link_retrain)(struct intel_dp *intel_dp);
- void (*set_link_train)(struct intel_dp *intel_dp, u8 dp_train_pat);
- void (*set_idle_link_train)(struct intel_dp *intel_dp);
- void (*set_signal_levels)(struct intel_dp *intel_dp);
+ void (*prepare_link_retrain)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+ void (*set_link_train)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ u8 dp_train_pat);
+ void (*set_idle_link_train)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+ void (*set_signal_levels)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
u8 (*preemph_max)(struct intel_dp *intel_dp);
- u8 (*voltage_max)(struct intel_dp *intel_dp);
+ u8 (*voltage_max)(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
/* Displayport compliance testing */
struct intel_dp_compliance compliance;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 9bc59fd2f95f..2165398d2c7c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -28,7 +28,6 @@
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -161,6 +160,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
162000, 270000, 540000, 810000
};
int i, max_rate;
+ int max_lttpr_rate;
if (drm_dp_has_quirk(&intel_dp->desc, 0,
DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
@@ -174,6 +174,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
}
max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+ 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);
for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
if (dp_rates[i] > max_rate)
@@ -219,6 +222,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
int source_max = dig_port->max_lanes;
int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
int fia_max = intel_tc_port_fia_max_lane_count(dig_port);
+ int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps);
+
+ if (lttpr_max)
+ sink_max = min(sink_max, lttpr_max);
return min3(source_max, sink_max, fia_max);
}
@@ -247,6 +254,17 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
return max_link_clock * max_lanes;
}
+bool intel_dp_can_bigjoiner(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;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ return INTEL_GEN(dev_priv) >= 12 ||
+ (INTEL_GEN(dev_priv) == 11 &&
+ encoder->port != PORT_A);
+}
+
static int cnl_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@@ -277,13 +295,20 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_phy_is_combo(dev_priv, phy) &&
- !IS_ELKHARTLAKE(dev_priv) &&
!intel_dp_is_edp(intel_dp))
return 540000;
return 810000;
}
+static int ehl_max_source_rate(struct intel_dp *intel_dp)
+{
+ if (intel_dp_is_edp(intel_dp))
+ return 540000;
+
+ return 810000;
+}
+
static void
intel_dp_set_source_rates(struct intel_dp *intel_dp)
{
@@ -318,6 +343,8 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
size = ARRAY_SIZE(cnl_rates);
if (IS_GEN(dev_priv, 10))
max_rate = cnl_max_source_rate(intel_dp);
+ else if (IS_JSL_EHL(dev_priv))
+ max_rate = ehl_max_source_rate(intel_dp);
else
max_rate = icl_max_source_rate(intel_dp);
} else if (IS_GEN9_LP(dev_priv)) {
@@ -503,7 +530,8 @@ small_joiner_ram_size_bits(struct drm_i915_private *i915)
static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
u32 link_clock, u32 lane_count,
- u32 mode_clock, u32 mode_hdisplay)
+ u32 mode_clock, u32 mode_hdisplay,
+ bool bigjoiner)
{
u32 bits_per_pixel, max_bpp_small_joiner_ram;
int i;
@@ -521,6 +549,10 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
/* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */
max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) /
mode_hdisplay;
+
+ if (bigjoiner)
+ max_bpp_small_joiner_ram *= 2;
+
drm_dbg_kms(&i915->drm, "Max small joiner bpp: %u\n",
max_bpp_small_joiner_ram);
@@ -530,6 +562,15 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
*/
bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram);
+ if (bigjoiner) {
+ u32 max_bpp_bigjoiner =
+ i915->max_cdclk_freq * 48 /
+ intel_dp_mode_to_fec_clock(mode_clock);
+
+ DRM_DEBUG_KMS("Max big joiner bpp: %u\n", max_bpp_bigjoiner);
+ bits_per_pixel = min(bits_per_pixel, max_bpp_bigjoiner);
+ }
+
/* Error out if the max bpp is less than smallest allowed valid bpp */
if (bits_per_pixel < valid_dsc_bpp[0]) {
drm_dbg_kms(&i915->drm, "Unsupported BPP %u, min %u\n",
@@ -552,7 +593,8 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
}
static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
- int mode_clock, int mode_hdisplay)
+ int mode_clock, int mode_hdisplay,
+ bool bigjoiner)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
u8 min_slice_count, i;
@@ -579,12 +621,18 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
/* Find the closest match to the valid slice count values */
for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) {
- if (valid_dsc_slicecount[i] >
- drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
- false))
+ u8 test_slice_count = valid_dsc_slicecount[i] << bigjoiner;
+
+ if (test_slice_count >
+ drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, false))
break;
- if (min_slice_count <= valid_dsc_slicecount[i])
- return valid_dsc_slicecount[i];
+
+ /* big joiner needs small joiner to be enabled */
+ if (bigjoiner && test_slice_count < 4)
+ continue;
+
+ if (min_slice_count <= test_slice_count)
+ return test_slice_count;
}
drm_dbg_kms(&i915->drm, "Unsupported Slice Count %d\n",
@@ -592,6 +640,54 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
return 0;
}
+static enum intel_output_format
+intel_dp_output_format(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector));
+ const struct drm_display_info *info = &connector->display_info;
+
+ if (!connector->ycbcr_420_allowed ||
+ !drm_mode_is_420_only(info, mode))
+ return INTEL_OUTPUT_FORMAT_RGB;
+
+ if (intel_dp->dfp.ycbcr_444_to_420)
+ return INTEL_OUTPUT_FORMAT_YCBCR444;
+ else
+ return INTEL_OUTPUT_FORMAT_YCBCR420;
+}
+
+int intel_dp_min_bpp(enum intel_output_format output_format)
+{
+ if (output_format == INTEL_OUTPUT_FORMAT_RGB)
+ return 6 * 3;
+ else
+ return 8 * 3;
+}
+
+static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp)
+{
+ /*
+ * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
+ * format of the number of bytes per pixel will be half the number
+ * of bytes of RGB pixel.
+ */
+ if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+ bpp /= 2;
+
+ return bpp;
+}
+
+static int
+intel_dp_mode_min_output_bpp(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ enum intel_output_format output_format =
+ intel_dp_output_format(connector, mode);
+
+ return intel_dp_output_bpp(output_format, intel_dp_min_bpp(output_format));
+}
+
static bool intel_dp_hdisplay_bad(struct drm_i915_private *dev_priv,
int hdisplay)
{
@@ -653,10 +749,14 @@ intel_dp_mode_valid(struct drm_connector *connector,
u16 dsc_max_output_bpp = 0;
u8 dsc_slice_count = 0;
enum drm_mode_status status;
+ bool dsc = false, bigjoiner = false;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ return MODE_H_ILLEGAL;
+
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
if (mode->hdisplay > fixed_mode->hdisplay)
return MODE_PANEL;
@@ -667,11 +767,23 @@ intel_dp_mode_valid(struct drm_connector *connector,
target_clock = fixed_mode->clock;
}
+ if (mode->clock < 10000)
+ return MODE_CLOCK_LOW;
+
+ if ((target_clock > max_dotclk || mode->hdisplay > 5120) &&
+ intel_dp_can_bigjoiner(intel_dp)) {
+ bigjoiner = true;
+ max_dotclk *= 2;
+ }
+ if (target_clock > max_dotclk)
+ return MODE_CLOCK_HIGH;
+
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);
- mode_rate = intel_dp_link_required(target_clock, 18);
+ mode_rate = intel_dp_link_required(target_clock,
+ intel_dp_mode_min_output_bpp(connector, mode));
if (intel_dp_hdisplay_bad(dev_priv, mode->hdisplay))
return MODE_H_ILLEGAL;
@@ -694,30 +806,31 @@ intel_dp_mode_valid(struct drm_connector *connector,
max_link_clock,
max_lanes,
target_clock,
- mode->hdisplay) >> 4;
+ mode->hdisplay,
+ bigjoiner) >> 4;
dsc_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
target_clock,
- mode->hdisplay);
+ mode->hdisplay,
+ bigjoiner);
}
+
+ dsc = dsc_max_output_bpp && dsc_slice_count;
}
- if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) ||
- target_clock > max_dotclk)
+ /* big joiner configuration needs DSC */
+ if (bigjoiner && !dsc)
return MODE_CLOCK_HIGH;
- if (mode->clock < 10000)
- return MODE_CLOCK_LOW;
-
- if (mode->flags & DRM_MODE_FLAG_DBLCLK)
- return MODE_H_ILLEGAL;
+ if (mode_rate > max_rate && !dsc)
+ return MODE_CLOCK_HIGH;
status = intel_dp_mode_valid_downstream(intel_connector,
mode, target_clock);
if (status != MODE_OK)
return status;
- return intel_mode_valid_max_plane_size(dev_priv, mode);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, bigjoiner);
}
u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
@@ -1143,41 +1256,6 @@ _pp_stat_reg(struct intel_dp *intel_dp)
return regs.pp_stat;
}
-/* Reboot notifier handler to shutdown panel power to guarantee T12 timing
- This function only applicable when panel PM state is not to be tracked */
-static int edp_notify_handler(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp),
- edp_notifier);
- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- intel_wakeref_t wakeref;
-
- if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART)
- return 0;
-
- with_pps_lock(intel_dp, wakeref) {
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
- i915_reg_t pp_ctrl_reg, pp_div_reg;
- u32 pp_div;
-
- pp_ctrl_reg = PP_CONTROL(pipe);
- pp_div_reg = PP_DIVISOR(pipe);
- pp_div = intel_de_read(dev_priv, pp_div_reg);
- pp_div &= PP_REFERENCE_DIVIDER_MASK;
-
- /* 0x1F write to PP_DIV_REG sets max cycle delay */
- intel_de_write(dev_priv, pp_div_reg, pp_div | 0x1F);
- intel_de_write(dev_priv, pp_ctrl_reg,
- PANEL_UNLOCK_REGS);
- msleep(intel_dp->panel_power_cycle_delay);
- }
- }
-
- return 0;
-}
-
static bool edp_have_panel_power(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1744,7 +1822,6 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
case AUX_CH_D:
case AUX_CH_E:
case AUX_CH_F:
- case AUX_CH_G:
return DP_AUX_CH_CTL(aux_ch);
default:
MISSING_CASE(aux_ch);
@@ -1765,7 +1842,52 @@ static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
case AUX_CH_D:
case AUX_CH_E:
case AUX_CH_F:
- case AUX_CH_G:
+ return DP_AUX_CH_DATA(aux_ch, index);
+ default:
+ MISSING_CASE(aux_ch);
+ return DP_AUX_CH_DATA(AUX_CH_A, index);
+ }
+}
+
+static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ enum aux_ch aux_ch = dig_port->aux_ch;
+
+ switch (aux_ch) {
+ case AUX_CH_A:
+ case AUX_CH_B:
+ case AUX_CH_C:
+ case AUX_CH_USBC1:
+ case AUX_CH_USBC2:
+ case AUX_CH_USBC3:
+ case AUX_CH_USBC4:
+ case AUX_CH_USBC5:
+ case AUX_CH_USBC6:
+ return DP_AUX_CH_CTL(aux_ch);
+ default:
+ MISSING_CASE(aux_ch);
+ return DP_AUX_CH_CTL(AUX_CH_A);
+ }
+}
+
+static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index)
+{
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ enum aux_ch aux_ch = dig_port->aux_ch;
+
+ switch (aux_ch) {
+ case AUX_CH_A:
+ case AUX_CH_B:
+ case AUX_CH_C:
+ case AUX_CH_USBC1:
+ case AUX_CH_USBC2:
+ case AUX_CH_USBC3:
+ case AUX_CH_USBC4:
+ case AUX_CH_USBC5:
+ case AUX_CH_USBC6:
return DP_AUX_CH_DATA(aux_ch, index);
default:
MISSING_CASE(aux_ch);
@@ -1785,8 +1907,12 @@ intel_dp_aux_init(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct intel_encoder *encoder = &dig_port->base;
+ enum aux_ch aux_ch = dig_port->aux_ch;
- if (INTEL_GEN(dev_priv) >= 9) {
+ if (INTEL_GEN(dev_priv) >= 12) {
+ intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg;
+ intel_dp->aux_ch_data_reg = tgl_aux_data_reg;
+ } else if (INTEL_GEN(dev_priv) >= 9) {
intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
intel_dp->aux_ch_data_reg = skl_aux_data_reg;
} else if (HAS_PCH_SPLIT(dev_priv)) {
@@ -1814,9 +1940,15 @@ intel_dp_aux_init(struct intel_dp *intel_dp)
drm_dp_aux_init(&intel_dp->aux);
/* Failure to allocate our preferred name is not critical */
- intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/port %c",
- aux_ch_name(dig_port->aux_ch),
- port_name(encoder->port));
+ if (INTEL_GEN(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1)
+ intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s",
+ aux_ch - AUX_CH_USBC1 + '1',
+ encoder->base.name);
+ else
+ intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
+ aux_ch_name(aux_ch),
+ encoder->base.name);
+
intel_dp->aux.transfer = intel_dp_aux_transfer;
}
@@ -1968,12 +2100,10 @@ static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
- struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-
- if (!intel_dp_is_edp(intel_dp) && !crtc_state->fec_enable)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP) && !crtc_state->fec_enable)
return false;
- return intel_dsc_source_support(encoder, crtc_state) &&
+ return intel_dsc_source_support(crtc_state) &&
drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
}
@@ -2095,19 +2225,6 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
}
}
-static int intel_dp_output_bpp(const struct intel_crtc_state *crtc_state, int bpp)
-{
- /*
- * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
- * format of the number of bytes per pixel will be half the number
- * of bytes of RGB pixel.
- */
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
- bpp /= 2;
-
- return bpp;
-}
-
/* Optimize link config in order: max bpp, min clock, min lanes */
static int
intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
@@ -2119,7 +2236,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
int mode_rate, link_clock, link_avail;
for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
- int output_bpp = intel_dp_output_bpp(pipe_config, bpp);
+ int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp);
mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
output_bpp);
@@ -2280,11 +2397,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
pipe_config->port_clock,
pipe_config->lane_count,
adjusted_mode->crtc_clock,
- adjusted_mode->crtc_hdisplay);
+ adjusted_mode->crtc_hdisplay,
+ pipe_config->bigjoiner);
dsc_dp_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
adjusted_mode->crtc_clock,
- adjusted_mode->crtc_hdisplay);
+ adjusted_mode->crtc_hdisplay,
+ pipe_config->bigjoiner);
if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
drm_dbg_kms(&dev_priv->drm,
"Compressed BPP/Slice Count not supported\n");
@@ -2300,14 +2419,15 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
* is greater than the maximum Cdclock and if slice count is even
* then we need to use 2 VDSC instances.
*/
- if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
- if (pipe_config->dsc.slice_count > 1) {
- pipe_config->dsc.dsc_split = true;
- } else {
+ if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq ||
+ pipe_config->bigjoiner) {
+ if (pipe_config->dsc.slice_count < 2) {
drm_dbg_kms(&dev_priv->drm,
"Cannot split stream to use 2 VDSC instances\n");
return -EINVAL;
}
+
+ pipe_config->dsc.dsc_split = true;
}
ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config);
@@ -2330,14 +2450,6 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
return 0;
}
-int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state)
-{
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
- return 6 * 3;
- else
- return 8 * 3;
-}
-
static int
intel_dp_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -2363,7 +2475,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
limits.min_lane_count = 1;
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
- limits.min_bpp = intel_dp_min_bpp(pipe_config);
+ limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format);
limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config);
if (intel_dp_is_edp(intel_dp)) {
@@ -2386,6 +2498,11 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
intel_dp->common_rates[limits.max_clock],
limits.max_bpp, adjusted_mode->crtc_clock);
+ if ((adjusted_mode->crtc_clock > i915->max_dotclk_freq ||
+ adjusted_mode->crtc_hdisplay > 5120) &&
+ intel_dp_can_bigjoiner(intel_dp))
+ pipe_config->bigjoiner = true;
+
/*
* Optimize for slow and wide. This is the place to add alternative
* optimization policy.
@@ -2394,7 +2511,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
/* enable compression if the mode doesn't fit available BW */
drm_dbg_kms(&i915->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en);
- if (ret || intel_dp->force_dsc_en) {
+ if (ret || intel_dp->force_dsc_en || pipe_config->bigjoiner) {
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
conn_state, &limits);
if (ret < 0)
@@ -2429,32 +2546,6 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
return 0;
}
-static int
-intel_dp_ycbcr420_config(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state)
-{
- struct drm_connector *connector = conn_state->connector;
- const struct drm_display_info *info = &connector->display_info;
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
-
- if (!connector->ycbcr_420_allowed)
- return 0;
-
- if (!drm_mode_is_420_only(info, adjusted_mode))
- return 0;
-
- if (intel_dp->dfp.ycbcr_444_to_420) {
- crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
- return 0;
- }
-
- crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
-
- return intel_pch_panel_fitting(crtc_state, conn_state);
-}
-
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
@@ -2693,7 +2784,6 @@ intel_dp_compute_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
enum port port = encoder->port;
struct intel_connector *intel_connector = intel_dp->attached_connector;
struct intel_digital_connector_state *intel_conn_state =
@@ -2705,15 +2795,14 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
pipe_config->has_pch_encoder = true;
- pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+ pipe_config->output_format = intel_dp_output_format(&intel_connector->base,
+ adjusted_mode);
- if (lspcon->active)
- lspcon_ycbcr420_config(&intel_connector->base, pipe_config);
- else
- ret = intel_dp_ycbcr420_config(intel_dp, pipe_config,
- conn_state);
- if (ret)
- return ret;
+ if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
+ ret = intel_pch_panel_fitting(pipe_config, conn_state);
+ if (ret)
+ return ret;
+ }
if (!intel_dp_port_has_audio(dev_priv, port))
pipe_config->has_audio = false;
@@ -2757,7 +2846,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (pipe_config->dsc.compression_enable)
output_bpp = pipe_config->dsc.compressed_bpp;
else
- output_bpp = intel_dp_output_bpp(pipe_config, pipe_config->pipe_bpp);
+ output_bpp = intel_dp_output_bpp(pipe_config->output_format,
+ pipe_config->pipe_bpp);
intel_link_compute_m_n(output_bpp,
pipe_config->lane_count,
@@ -2779,13 +2869,11 @@ intel_dp_compute_config(struct intel_encoder *encoder,
}
void intel_dp_set_link_params(struct intel_dp *intel_dp,
- int link_rate, u8 lane_count,
- bool link_mst)
+ int link_rate, int lane_count)
{
intel_dp->link_trained = false;
intel_dp->link_rate = link_rate;
intel_dp->lane_count = lane_count;
- intel_dp->link_mst = link_mst;
}
static void intel_dp_prepare(struct intel_encoder *encoder,
@@ -2797,10 +2885,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
- pipe_config->lane_count,
- intel_crtc_has_type(pipe_config,
- INTEL_OUTPUT_DP_MST));
+ intel_dp_set_link_params(intel_dp,
+ pipe_config->port_clock,
+ pipe_config->lane_count);
/*
* There are four kinds of DP registers:
@@ -3492,32 +3579,33 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
enable ? "enable" : "disable");
}
-/* If the sink supports it, try to set the power state appropriately */
-void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
+/* If the device supports it, try to set the power state appropriately */
+void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
int ret, i;
/* Should have a valid DPCD by this point */
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
return;
- if (mode != DRM_MODE_DPMS_ON) {
+ if (mode != DP_SET_POWER_D0) {
if (downstream_hpd_needs_d0(intel_dp))
return;
- ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
- DP_SET_POWER_D3);
+ ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode);
} else {
struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+ lspcon_resume(dp_to_dig_port(intel_dp));
+
/*
* When turning on, we need to retry for 1ms to give the sink
* time to wake up.
*/
for (i = 0; i < 3; i++) {
- ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
- DP_SET_POWER_D0);
+ ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode);
if (ret == 1)
break;
msleep(1);
@@ -3528,8 +3616,9 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
}
if (ret != 1)
- drm_dbg_kms(&i915->drm, "failed to %s sink power state\n",
- mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Set power to %s failed\n",
+ encoder->base.base.id, encoder->base.name,
+ mode == DP_SET_POWER_D0 ? "D0" : "D3");
}
static bool cpt_dp_port_selected(struct drm_i915_private *dev_priv,
@@ -3686,6 +3775,72 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
}
}
+static bool
+intel_dp_get_dpcd(struct intel_dp *intel_dp);
+
+/**
+ * intel_dp_sync_state - sync the encoder state during init/resume
+ * @encoder: intel encoder to sync
+ * @crtc_state: state for the CRTC connected to the encoder
+ *
+ * Sync any state stored in the encoder wrt. HW state during driver init
+ * and system resume.
+ */
+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);
+
+ /*
+ * 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)
+ intel_dp_get_dpcd(intel_dp);
+
+ intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
+ intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
+}
+
+bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ /*
+ * If BIOS has set an unsupported or non-standard link rate for some
+ * reason force an encoder recompute and full modeset.
+ */
+ if (intel_dp_rate_index(intel_dp->source_rates, intel_dp->num_source_rates,
+ crtc_state->port_clock) < 0) {
+ drm_dbg_kms(&i915->drm, "Forcing full modeset due to unsupported link rate\n");
+ crtc_state->uapi.connectors_changed = true;
+ return false;
+ }
+
+ /*
+ * FIXME hack to force full modeset when DSC is being used.
+ *
+ * As long as we do not have full state readout and config comparison
+ * of crtc_state->dsc, we have no way to ensure reliable fastset.
+ * Remove once we have readout for DSC.
+ */
+ if (crtc_state->dsc.compression_enable) {
+ drm_dbg_kms(&i915->drm, "Forcing full modeset due to DSC being enabled\n");
+ crtc_state->uapi.mode_changed = true;
+ return false;
+ }
+
+ if (CAN_PSR(i915) && intel_dp_is_edp(intel_dp)) {
+ drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n");
+ crtc_state->uapi.mode_changed = true;
+ return false;
+ }
+
+ return true;
+}
+
static void intel_disable_dp(struct intel_atomic_state *state,
struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
@@ -3703,7 +3858,7 @@ static void intel_disable_dp(struct intel_atomic_state *state,
* ensure that we have vdd while we switch off the panel. */
intel_edp_panel_vdd_on(intel_dp);
intel_edp_backlight_off(old_conn_state);
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D3);
intel_edp_panel_off(intel_dp);
}
@@ -3771,6 +3926,7 @@ static void chv_post_disable_dp(struct intel_atomic_state *state,
static void
cpt_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -3778,7 +3934,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
*DP &= ~DP_LINK_TRAIN_MASK_CPT;
- switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+ switch (intel_dp_training_pattern_symbol(dp_train_pat)) {
case DP_TRAINING_PATTERN_DISABLE:
*DP |= DP_LINK_TRAIN_OFF_CPT;
break;
@@ -3801,6 +3957,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
static void
g4x_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -3808,7 +3965,7 @@ g4x_set_link_train(struct intel_dp *intel_dp,
*DP &= ~DP_LINK_TRAIN_MASK;
- switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+ switch (intel_dp_training_pattern_symbol(dp_train_pat)) {
case DP_TRAINING_PATTERN_DISABLE:
*DP |= DP_LINK_TRAIN_OFF;
break;
@@ -3830,13 +3987,14 @@ g4x_set_link_train(struct intel_dp *intel_dp,
}
static void intel_dp_enable_port(struct intel_dp *intel_dp,
- const struct intel_crtc_state *old_crtc_state)
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
/* enable with pattern 1 (as per spec) */
- intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
+ intel_dp_program_link_training_pattern(intel_dp, crtc_state,
+ DP_TRAINING_PATTERN_1);
/*
* Magic for VLV/CHV. We _must_ first set up the register
@@ -3845,7 +4003,7 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp,
* fail when the power sequencer is freshly used for this port.
*/
intel_dp->DP |= DP_PORT_EN;
- if (old_crtc_state->has_audio)
+ if (crtc_state->has_audio)
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP);
@@ -3925,10 +4083,10 @@ static void intel_enable_dp(struct intel_atomic_state *state,
lane_mask);
}
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp);
- intel_dp_start_link_train(intel_dp);
- intel_dp_stop_link_train(intel_dp);
+ intel_dp_start_link_train(intel_dp, pipe_config);
+ intel_dp_stop_link_train(intel_dp, pipe_config);
if (pipe_config->has_audio) {
drm_dbg(&dev_priv->drm, "Enabling DP audio on pipe %c\n",
@@ -4126,38 +4284,30 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state,
chv_phy_post_pll_disable(encoder, old_crtc_state);
}
-/*
- * Fetch AUX CH registers 0x202 - 0x207 which contain
- * link status information
- */
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
-{
- return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
- DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
-}
-
-static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp)
+static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
}
-static u8 intel_dp_voltage_max_3(struct intel_dp *intel_dp)
+static u8 intel_dp_voltage_max_3(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
}
-static u8 intel_dp_pre_empemph_max_2(struct intel_dp *intel_dp)
+static u8 intel_dp_preemph_max_2(struct intel_dp *intel_dp)
{
return DP_TRAIN_PRE_EMPH_LEVEL_2;
}
-static u8 intel_dp_pre_empemph_max_3(struct intel_dp *intel_dp)
+static u8 intel_dp_preemph_max_3(struct intel_dp *intel_dp)
{
return DP_TRAIN_PRE_EMPH_LEVEL_3;
}
-static void vlv_set_signal_levels(struct intel_dp *intel_dp)
+static void vlv_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
unsigned long demph_reg_value, preemph_reg_value,
@@ -4237,11 +4387,13 @@ static void vlv_set_signal_levels(struct intel_dp *intel_dp)
return;
}
- vlv_set_phy_signal_level(encoder, demph_reg_value, preemph_reg_value,
+ vlv_set_phy_signal_level(encoder, crtc_state,
+ demph_reg_value, preemph_reg_value,
uniqtranscale_reg_value, 0);
}
-static void chv_set_signal_levels(struct intel_dp *intel_dp)
+static void chv_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
u32 deemph_reg_value, margin_reg_value;
@@ -4318,8 +4470,9 @@ static void chv_set_signal_levels(struct intel_dp *intel_dp)
return;
}
- chv_set_phy_signal_level(encoder, deemph_reg_value,
- margin_reg_value, uniq_trans_scale);
+ chv_set_phy_signal_level(encoder, crtc_state,
+ deemph_reg_value, margin_reg_value,
+ uniq_trans_scale);
}
static u32 g4x_signal_levels(u8 train_set)
@@ -4360,7 +4513,8 @@ static u32 g4x_signal_levels(u8 train_set)
}
static void
-g4x_set_signal_levels(struct intel_dp *intel_dp)
+g4x_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4407,7 +4561,8 @@ static u32 snb_cpu_edp_signal_levels(u8 train_set)
}
static void
-snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp)
+snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4458,7 +4613,8 @@ static u32 ivb_cpu_edp_signal_levels(u8 train_set)
}
static void
-ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp)
+ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4476,7 +4632,8 @@ ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp)
intel_de_posting_read(dev_priv, intel_dp->output_reg);
}
-void intel_dp_set_signal_levels(struct intel_dp *intel_dp)
+void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_set = intel_dp->train_set[0];
@@ -4490,28 +4647,23 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp)
train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ?
" (max)" : "");
- intel_dp->set_signal_levels(intel_dp);
+ intel_dp->set_signal_levels(intel_dp, crtc_state);
}
void
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
- if (dp_train_pat & train_pat_mask)
+ if ((intel_dp_training_pattern_symbol(dp_train_pat)) !=
+ DP_TRAINING_PATTERN_DISABLE)
drm_dbg_kms(&dev_priv->drm,
"Using DP training pattern TPS%d\n",
- dp_train_pat & train_pat_mask);
-
- intel_dp->set_link_train(intel_dp, dp_train_pat);
-}
+ intel_dp_training_pattern_symbol(dp_train_pat));
-void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
-{
- if (intel_dp->set_idle_link_train)
- intel_dp->set_idle_link_train(intel_dp);
+ intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat);
}
static void
@@ -4732,6 +4884,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
{
int ret;
+ intel_dp_lttpr_init(intel_dp);
+
if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd))
return false;
@@ -5404,33 +5558,14 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
return test_result;
}
-static u8 intel_dp_prepare_phytest(struct intel_dp *intel_dp)
-{
- struct drm_dp_phy_test_params *data =
- &intel_dp->compliance.test_data.phytest;
-
- if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) {
- DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
- return DP_TEST_NAK;
- }
-
- /*
- * link_mst is set to false to avoid executing mst related code
- * during compliance testing.
- */
- intel_dp->link_mst = false;
-
- return DP_TEST_ACK;
-}
-
-static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp)
+static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv =
to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
- struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_dp_phy_test_params *data =
&intel_dp->compliance.test_data.phytest;
- struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
u32 pattern_val;
@@ -5490,7 +5625,8 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp)
}
static void
-intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp)
+intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
@@ -5516,7 +5652,8 @@ intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp)
}
static void
-intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt)
+intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
@@ -5542,27 +5679,30 @@ intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt)
trans_ddi_func_ctl_value);
}
-void intel_dp_process_phy_request(struct intel_dp *intel_dp)
+static void intel_dp_process_phy_request(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_dp_phy_test_params *data =
&intel_dp->compliance.test_data.phytest;
u8 link_status[DP_LINK_STATUS_SIZE];
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
+ link_status) < 0) {
DRM_DEBUG_KMS("failed to get link status\n");
return;
}
/* retrieve vswing & pre-emphasis setting */
- intel_dp_get_adjust_train(intel_dp, link_status);
+ intel_dp_get_adjust_train(intel_dp, crtc_state, DP_PHY_DPRX,
+ link_status);
- intel_dp_autotest_phy_ddi_disable(intel_dp);
+ intel_dp_autotest_phy_ddi_disable(intel_dp, crtc_state);
- intel_dp_set_signal_levels(intel_dp);
+ intel_dp_set_signal_levels(intel_dp, crtc_state);
- intel_dp_phy_pattern_update(intel_dp);
+ intel_dp_phy_pattern_update(intel_dp, crtc_state);
- intel_dp_autotest_phy_ddi_enable(intel_dp, data->num_lanes);
+ intel_dp_autotest_phy_ddi_enable(intel_dp, crtc_state);
drm_dp_set_phy_test_pattern(&intel_dp->aux, data,
link_status[DP_DPCD_REV]);
@@ -5570,15 +5710,18 @@ void intel_dp_process_phy_request(struct intel_dp *intel_dp)
static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
{
- u8 test_result;
+ struct drm_dp_phy_test_params *data =
+ &intel_dp->compliance.test_data.phytest;
- test_result = intel_dp_prepare_phytest(intel_dp);
- if (test_result != DP_TEST_ACK)
- DRM_ERROR("Phy test preparation failed\n");
+ if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) {
+ DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
+ return DP_TEST_NAK;
+ }
- intel_dp_process_phy_request(intel_dp);
+ /* Set test active flag here so userspace doesn't interrupt things */
+ intel_dp->compliance.test_active = true;
- return test_result;
+ return DP_TEST_ACK;
}
static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
@@ -5709,12 +5852,17 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
if (intel_psr_enabled(intel_dp))
return false;
- if (!intel_dp_get_link_status(intel_dp, link_status))
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
+ link_status) < 0)
return false;
/*
* Validate the cached values of intel_dp->link_rate and
* intel_dp->lane_count before attempting to retrain.
+ *
+ * FIXME would be nice to user the crtc state here, but since
+ * we need to call this from the short HPD handler that seems
+ * a bit hard.
*/
if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
intel_dp->lane_count))
@@ -5848,8 +5996,20 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
intel_crtc_pch_transcoder(crtc), false);
}
- intel_dp_start_link_train(intel_dp);
- intel_dp_stop_link_train(intel_dp);
+ for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+
+ /* retrain on the MST master transcoder */
+ if (INTEL_GEN(dev_priv) >= 12 &&
+ intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) &&
+ !intel_dp_mst_is_master_trans(crtc_state))
+ continue;
+
+ intel_dp_start_link_train(intel_dp, crtc_state);
+ intel_dp_stop_link_train(intel_dp, crtc_state);
+ break;
+ }
for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) {
const struct intel_crtc_state *crtc_state =
@@ -5867,6 +6027,118 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
return 0;
}
+static int intel_dp_prep_phy_test(struct intel_dp *intel_dp,
+ struct drm_modeset_acquire_ctx *ctx,
+ u32 *crtc_mask)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct drm_connector_list_iter conn_iter;
+ struct intel_connector *connector;
+ int ret = 0;
+
+ *crtc_mask = 0;
+
+ drm_connector_list_iter_begin(&i915->drm, &conn_iter);
+ for_each_intel_connector_iter(connector, &conn_iter) {
+ struct drm_connector_state *conn_state =
+ connector->base.state;
+ struct intel_crtc_state *crtc_state;
+ struct intel_crtc *crtc;
+
+ if (!intel_dp_has_connector(intel_dp, conn_state))
+ continue;
+
+ crtc = to_intel_crtc(conn_state->crtc);
+ if (!crtc)
+ continue;
+
+ ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+ if (ret)
+ break;
+
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+
+ drm_WARN_ON(&i915->drm, !intel_crtc_has_dp_encoder(crtc_state));
+
+ if (!crtc_state->hw.active)
+ continue;
+
+ if (conn_state->commit &&
+ !try_wait_for_completion(&conn_state->commit->hw_done))
+ continue;
+
+ *crtc_mask |= drm_crtc_mask(&crtc->base);
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return ret;
+}
+
+static int intel_dp_do_phy_test(struct intel_encoder *encoder,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct intel_crtc *crtc;
+ u32 crtc_mask;
+ int ret;
+
+ ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
+ ctx);
+ if (ret)
+ return ret;
+
+ ret = intel_dp_prep_phy_test(intel_dp, ctx, &crtc_mask);
+ if (ret)
+ return ret;
+
+ if (crtc_mask == 0)
+ return 0;
+
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] PHY test\n",
+ encoder->base.base.id, encoder->base.name);
+
+ for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+
+ /* test on the MST master transcoder */
+ if (INTEL_GEN(dev_priv) >= 12 &&
+ intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) &&
+ !intel_dp_mst_is_master_trans(crtc_state))
+ continue;
+
+ intel_dp_process_phy_request(intel_dp, crtc_state);
+ break;
+ }
+
+ return 0;
+}
+
+static void intel_dp_phy_test(struct intel_encoder *encoder)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ int ret;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ for (;;) {
+ ret = intel_dp_do_phy_test(encoder, &ctx);
+
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ continue;
+ }
+
+ break;
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_WARN(encoder->base.dev, ret,
+ "Acquiring modeset locks failed with %i\n", ret);
+}
+
/*
* If display is now connected check links status,
* there has been known issues of link loss triggering
@@ -5883,10 +6155,18 @@ static enum intel_hotplug_state
intel_dp_hotplug(struct intel_encoder *encoder,
struct intel_connector *connector)
{
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_modeset_acquire_ctx ctx;
enum intel_hotplug_state state;
int ret;
+ if (intel_dp->compliance.test_active &&
+ intel_dp->compliance.test_type == DP_TEST_LINK_PHY_TEST_PATTERN) {
+ intel_dp_phy_test(encoder);
+ /* just do the PHY test and nothing else */
+ return INTEL_HOTPLUG_UNCHANGED;
+ }
+
state = intel_encoder_hotplug(encoder, connector);
drm_modeset_acquire_init(&ctx, 0);
@@ -5991,11 +6271,23 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
intel_psr_short_pulse(intel_dp);
- if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
+ switch (intel_dp->compliance.test_type) {
+ case DP_TEST_LINK_TRAINING:
drm_dbg_kms(&dev_priv->drm,
"Link Training Compliance Test requested\n");
/* Send a Hotplug Uevent to userspace to start modeset */
drm_kms_helper_hotplug_event(&dev_priv->drm);
+ break;
+ case DP_TEST_LINK_PHY_TEST_PATTERN:
+ drm_dbg_kms(&dev_priv->drm,
+ "PHY test pattern Compliance Test requested\n");
+ /*
+ * Schedule long hpd to do the test
+ *
+ * FIXME get rid of the ad-hoc phy test modeset code
+ * and properly incorporate it into the normal modeset.
+ */
+ return false;
}
return true;
@@ -6006,15 +6298,14 @@ static enum drm_connector_status
intel_dp_detect_dpcd(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
u8 *dpcd = intel_dp->dpcd;
u8 type;
if (drm_WARN_ON(&i915->drm, intel_dp_is_edp(intel_dp)))
return connector_status_connected;
- if (lspcon->active)
- lspcon_resume(lspcon);
+ lspcon_resume(dig_port);
if (!intel_dp_get_dpcd(intel_dp))
return connector_status_disconnected;
@@ -6220,7 +6511,9 @@ intel_dp_update_420(struct intel_dp *intel_dp)
ycbcr_420_passthrough =
drm_dp_downstream_420_passthrough(intel_dp->dpcd,
intel_dp->downstream_ports);
+ /* on-board LSPCON always assumed to support 4:4:4->4:2:0 conversion */
ycbcr_444_to_420 =
+ dp_to_dig_port(intel_dp)->lspcon.active ||
drm_dp_downstream_444_to_420_conversion(intel_dp->dpcd,
intel_dp->downstream_ports);
@@ -6523,11 +6816,6 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
*/
with_pps_lock(intel_dp, wakeref)
edp_panel_vdd_off_sync(intel_dp);
-
- if (intel_dp->edp_notifier.notifier_call) {
- unregister_reboot_notifier(&intel_dp->edp_notifier);
- intel_dp->edp_notifier.notifier_call = NULL;
- }
}
intel_dp_aux_fini(intel_dp);
@@ -6558,6 +6846,18 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
edp_panel_vdd_off_sync(intel_dp);
}
+void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder);
+ intel_wakeref_t wakeref;
+
+ if (!intel_dp_is_edp(intel_dp))
+ return;
+
+ with_pps_lock(intel_dp, wakeref)
+ wait_panel_power_cycle(intel_dp);
+}
+
static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -6598,15 +6898,11 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->dev);
struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder));
- struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
intel_wakeref_t wakeref;
if (!HAS_DDI(dev_priv))
intel_dp->DP = intel_de_read(dev_priv, intel_dp->output_reg);
- if (lspcon->active)
- lspcon_resume(lspcon);
-
intel_dp->reset_link_params = true;
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
@@ -7671,9 +7967,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
mutex_unlock(&dev->mode_config.mutex);
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- intel_dp->edp_notifier.notifier_call = edp_notify_handler;
- register_reboot_notifier(&intel_dp->edp_notifier);
-
/*
* Figure out the current pipe for the initial backlight setup.
* If the current pipe isn't valid, try the PPS pipe, and if that
@@ -7892,8 +8185,11 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
intel_encoder->compute_config = intel_dp_compute_config;
intel_encoder->get_hw_state = intel_dp_get_hw_state;
intel_encoder->get_config = intel_dp_get_config;
+ intel_encoder->sync_state = intel_dp_sync_state;
+ intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check;
intel_encoder->update_pipe = intel_panel_update_backlight;
intel_encoder->suspend = intel_dp_encoder_suspend;
+ intel_encoder->shutdown = intel_dp_encoder_shutdown;
if (IS_CHERRYVIEW(dev_priv)) {
intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
intel_encoder->pre_enable = chv_pre_enable_dp;
@@ -7933,17 +8229,15 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) ||
(HAS_PCH_SPLIT(dev_priv) && port != PORT_A)) {
- dig_port->dp.preemph_max = intel_dp_pre_empemph_max_3;
+ dig_port->dp.preemph_max = intel_dp_preemph_max_3;
dig_port->dp.voltage_max = intel_dp_voltage_max_3;
} else {
- dig_port->dp.preemph_max = intel_dp_pre_empemph_max_2;
+ dig_port->dp.preemph_max = intel_dp_preemph_max_2;
dig_port->dp.voltage_max = intel_dp_voltage_max_2;
}
dig_port->dp.output_reg = output_reg;
dig_port->max_lanes = 4;
- dig_port->dp.regs.dp_tp_ctl = DP_TP_CTL(port);
- dig_port->dp.regs.dp_tp_status = DP_TP_STATUS(port);
intel_encoder->type = INTEL_OUTPUT_DP;
intel_encoder->power_domain = intel_port_to_power_domain(port);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 08a1c0aa8b94..b871a09b6901 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -10,6 +10,7 @@
#include "i915_reg.h"
+enum intel_output_format;
enum pipe;
enum port;
struct drm_connector_state;
@@ -35,7 +36,7 @@ void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
struct link_config_limits *limits);
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(const struct intel_crtc_state *crtc_state);
+int intel_dp_min_bpp(enum intel_output_format output_format);
bool intel_dp_port_enabled(struct drm_i915_private *dev_priv,
i915_reg_t dp_reg, enum port port,
enum pipe *pipe);
@@ -44,19 +45,19 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg,
bool intel_dp_init_connector(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector);
void intel_dp_set_link_params(struct intel_dp *intel_dp,
- int link_rate, u8 lane_count,
- bool link_mst);
+ int link_rate, int lane_count);
int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
int link_rate, u8 lane_count);
int intel_dp_retrain_link(struct intel_encoder *encoder,
struct drm_modeset_acquire_ctx *ctx);
-void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
+void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp);
void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
bool enable);
void intel_dp_encoder_reset(struct drm_encoder *encoder);
void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
+void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder);
void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
int intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -92,20 +93,20 @@ void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
void
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
u8 dp_train_pat);
void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp);
-void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
+intel_dp_set_signal_levels(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
u8 *link_bw, u8 *rate_select);
bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
int intel_dp_link_required(int pixel_clock, int bpp);
int intel_dp_max_data_rate(int max_link_clock, int max_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,
@@ -122,7 +123,6 @@ void intel_read_dp_sdp(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
unsigned int type);
bool intel_digital_port_connected(struct intel_encoder *encoder);
-void intel_dp_process_phy_request(struct intel_dp *intel_dp);
static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
{
@@ -139,4 +139,9 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state,
int intel_dp_init_hdcp(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector);
+bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state);
+void intel_dp_sync_state(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+
#endif /* __INTEL_DP_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
index 036f504ac7db..51d27fc98d48 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
@@ -343,8 +343,7 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector)
* the panel can support backlight control over the aux channel
*/
if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
- (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) &&
- !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
+ (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) {
drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
return true;
}
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 f2c8b56be9ea..91d3979902d0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -34,6 +34,152 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
link_status[3], link_status[4], link_status[5]);
}
+static int intel_dp_lttpr_count(struct intel_dp *intel_dp)
+{
+ int count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps);
+
+ /*
+ * Pretend no LTTPRs in case of LTTPR detection error, or
+ * if too many (>8) LTTPRs are detected. This translates to link
+ * training in transparent mode.
+ */
+ return count <= 0 ? 0 : count;
+}
+
+static void intel_dp_reset_lttpr_count(struct intel_dp *intel_dp)
+{
+ intel_dp->lttpr_common_caps[DP_PHY_REPEATER_CNT -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV] = 0;
+}
+
+static const char *intel_dp_phy_name(enum drm_dp_phy dp_phy,
+ char *buf, size_t buf_size)
+{
+ if (dp_phy == DP_PHY_DPRX)
+ snprintf(buf, buf_size, "DPRX");
+ else
+ snprintf(buf, buf_size, "LTTPR %d", dp_phy - DP_PHY_LTTPR1 + 1);
+
+ return buf;
+}
+
+static u8 *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ return intel_dp->lttpr_phy_caps[dp_phy - DP_PHY_LTTPR1];
+}
+
+static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+ char phy_name[10];
+
+ intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name));
+
+ if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) {
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "failed to read the PHY caps for %s\n",
+ phy_name);
+ return;
+ }
+
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "%s PHY capabilities: %*ph\n",
+ phy_name,
+ (int)sizeof(intel_dp->lttpr_phy_caps[0]),
+ phy_caps);
+}
+
+static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp)
+{
+ if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
+ intel_dp->lttpr_common_caps) < 0) {
+ memset(intel_dp->lttpr_common_caps, 0,
+ sizeof(intel_dp->lttpr_common_caps));
+ return false;
+ }
+
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "LTTPR common capabilities: %*ph\n",
+ (int)sizeof(intel_dp->lttpr_common_caps),
+ intel_dp->lttpr_common_caps);
+
+ return true;
+}
+
+static bool
+intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
+{
+ u8 val = enable ? DP_PHY_REPEATER_MODE_TRANSPARENT :
+ DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
+
+ return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
+}
+
+/**
+ * intel_dp_lttpr_init - detect LTTPRs and init the LTTPR link training mode
+ * @intel_dp: Intel DP struct
+ *
+ * Read the LTTPR common capabilities, switch to non-transparent link training
+ * mode if any is detected and read the PHY capabilities for all detected
+ * LTTPRs. In case of an LTTPR detection error or if the number of
+ * LTTPRs is more than is supported (8), fall back to the no-LTTPR,
+ * transparent mode link training mode.
+ *
+ * Returns:
+ * >0 if LTTPRs were detected and the non-transparent LT mode was set
+ * 0 if no LTTPRs or more than 8 LTTPRs were detected or in case of a
+ * detection failure and the transparent LT mode was set
+ */
+int intel_dp_lttpr_init(struct intel_dp *intel_dp)
+{
+ int lttpr_count;
+ bool ret;
+ int i;
+
+ if (intel_dp_is_edp(intel_dp))
+ return 0;
+
+ ret = intel_dp_read_lttpr_common_caps(intel_dp);
+
+ /*
+ * See DP Standard v2.0 3.6.6.1. about the explicit disabling of
+ * non-transparent mode and the disable->enable non-transparent mode
+ * sequence.
+ */
+ intel_dp_set_lttpr_transparent_mode(intel_dp, true);
+
+ if (!ret)
+ return 0;
+
+ lttpr_count = intel_dp_lttpr_count(intel_dp);
+
+ /*
+ * In case of unsupported number of LTTPRs or failing to switch to
+ * non-transparent mode fall-back to transparent link training mode,
+ * still taking into account any LTTPR common lane- rate/count limits.
+ */
+ if (lttpr_count == 0)
+ return 0;
+
+ if (!intel_dp_set_lttpr_transparent_mode(intel_dp, false)) {
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "Switching to LTTPR non-transparent LT mode failed, fall-back to transparent mode\n");
+
+ intel_dp_set_lttpr_transparent_mode(intel_dp, true);
+ intel_dp_reset_lttpr_count(intel_dp);
+
+ return 0;
+ }
+
+ for (i = 0; i < lttpr_count; i++)
+ intel_dp_read_lttpr_phy_caps(intel_dp, DP_PHY_LTTPR(i));
+
+ return lttpr_count;
+}
+EXPORT_SYMBOL(intel_dp_lttpr_init);
+
static u8 dp_voltage_max(u8 preemph)
{
switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
@@ -49,36 +195,109 @@ static u8 dp_voltage_max(u8 preemph)
}
}
-void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
- const u8 link_status[DP_LINK_STATUS_SIZE])
+static u8 intel_dp_lttpr_voltage_max(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+ if (drm_dp_lttpr_voltage_swing_level_3_supported(phy_caps))
+ return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+ else
+ return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+}
+
+static u8 intel_dp_lttpr_preemph_max(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+ if (drm_dp_lttpr_pre_emphasis_level_3_supported(phy_caps))
+ return DP_TRAIN_PRE_EMPH_LEVEL_3;
+ else
+ return DP_TRAIN_PRE_EMPH_LEVEL_2;
+}
+
+static bool
+intel_dp_phy_is_downstream_of_source(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ int lttpr_count = intel_dp_lttpr_count(intel_dp);
+
+ drm_WARN_ON_ONCE(&i915->drm, lttpr_count == 0 && dp_phy != DP_PHY_DPRX);
+
+ return lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1);
+}
+
+static u8 intel_dp_phy_voltage_max(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ u8 voltage_max;
+
+ /*
+ * Get voltage_max from the DPTX_PHY (source or LTTPR) upstream from
+ * the DPRX_PHY we train.
+ */
+ if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
+ voltage_max = intel_dp->voltage_max(intel_dp, crtc_state);
+ else
+ voltage_max = intel_dp_lttpr_voltage_max(intel_dp, dp_phy + 1);
+
+ drm_WARN_ON_ONCE(&i915->drm,
+ voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
+ voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
+
+ return voltage_max;
+}
+
+static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ u8 preemph_max;
+
+ /*
+ * Get preemph_max from the DPTX_PHY (source or LTTPR) upstream from
+ * the DPRX_PHY we train.
+ */
+ if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
+ preemph_max = intel_dp->preemph_max(intel_dp);
+ else
+ preemph_max = intel_dp_lttpr_preemph_max(intel_dp, dp_phy + 1);
+
+ drm_WARN_ON_ONCE(&i915->drm,
+ preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
+ preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
+
+ return preemph_max;
+}
+
+void
+intel_dp_get_adjust_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
+ const u8 link_status[DP_LINK_STATUS_SIZE])
+{
u8 v = 0;
u8 p = 0;
int lane;
u8 voltage_max;
u8 preemph_max;
- for (lane = 0; lane < intel_dp->lane_count; lane++) {
+ for (lane = 0; lane < crtc_state->lane_count; lane++) {
v = max(v, drm_dp_get_adjust_request_voltage(link_status, lane));
p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane));
}
- preemph_max = intel_dp->preemph_max(intel_dp);
- drm_WARN_ON_ONCE(&i915->drm,
- preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
- preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
-
+ preemph_max = intel_dp_phy_preemph_max(intel_dp, dp_phy);
if (p >= preemph_max)
p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
v = min(v, dp_voltage_max(p));
- voltage_max = intel_dp->voltage_max(intel_dp);
- drm_WARN_ON_ONCE(&i915->drm,
- voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
- voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
-
+ voltage_max = intel_dp_phy_voltage_max(intel_dp, crtc_state, dp_phy);
if (v >= voltage_max)
v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
@@ -86,59 +305,70 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
intel_dp->train_set[lane] = v | p;
}
+static int intel_dp_training_pattern_set_reg(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ return dp_phy == DP_PHY_DPRX ?
+ DP_TRAINING_PATTERN_SET :
+ DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
+}
+
static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
u8 dp_train_pat)
{
+ int reg = intel_dp_training_pattern_set_reg(intel_dp, dp_phy);
u8 buf[sizeof(intel_dp->train_set) + 1];
- int ret, len;
+ int len;
- intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
+ intel_dp_program_link_training_pattern(intel_dp, crtc_state,
+ dp_train_pat);
buf[0] = dp_train_pat;
- if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
- DP_TRAINING_PATTERN_DISABLE) {
- /* don't write DP_TRAINING_LANEx_SET on disable */
- len = 1;
- } else {
- /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
- memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
- len = intel_dp->lane_count + 1;
- }
-
- ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
- buf, len);
+ /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
+ memcpy(buf + 1, intel_dp->train_set, crtc_state->lane_count);
+ len = crtc_state->lane_count + 1;
- return ret == len;
+ return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
}
static bool
intel_dp_reset_link_train(struct intel_dp *intel_dp,
- u8 dp_train_pat)
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
+ u8 dp_train_pat)
{
memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
- intel_dp_set_signal_levels(intel_dp);
- return intel_dp_set_link_train(intel_dp, dp_train_pat);
+ intel_dp_set_signal_levels(intel_dp, crtc_state);
+ return intel_dp_set_link_train(intel_dp, crtc_state, dp_phy, dp_train_pat);
}
static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp)
+intel_dp_update_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
+ int reg = dp_phy == DP_PHY_DPRX ?
+ DP_TRAINING_LANE0_SET :
+ DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
int ret;
- intel_dp_set_signal_levels(intel_dp);
+ intel_dp_set_signal_levels(intel_dp, crtc_state);
- ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
- intel_dp->train_set, intel_dp->lane_count);
+ ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
+ intel_dp->train_set, crtc_state->lane_count);
- return ret == intel_dp->lane_count;
+ return ret == crtc_state->lane_count;
}
-static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
int lane;
- for (lane = 0; lane < intel_dp->lane_count; lane++)
+ for (lane = 0; lane < crtc_state->lane_count; lane++)
if ((intel_dp->train_set[lane] &
DP_TRAIN_MAX_SWING_REACHED) == 0)
return false;
@@ -146,21 +376,22 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
return true;
}
-/* Enable corresponding port and start training pattern 1 */
+/*
+ * Prepare link training by configuring the link parameters. On DDI platforms
+ * also enable the port here.
+ */
static bool
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+intel_dp_prepare_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- u8 voltage;
- int voltage_tries, cr_tries, max_cr_tries;
- bool max_vswing_reached = false;
u8 link_config[2];
u8 link_bw, rate_select;
if (intel_dp->prepare_link_retrain)
- intel_dp->prepare_link_retrain(intel_dp);
+ intel_dp->prepare_link_retrain(intel_dp, crtc_state);
- intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
+ intel_dp_compute_rate(intel_dp, crtc_state->port_clock,
&link_bw, &rate_select);
if (link_bw)
@@ -172,7 +403,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
/* Write the link configuration data */
link_config[0] = link_bw;
- link_config[1] = intel_dp->lane_count;
+ link_config[1] = crtc_state->lane_count;
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
@@ -188,8 +419,34 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
intel_dp->DP |= DP_PORT_EN;
+ return true;
+}
+
+static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ if (dp_phy == DP_PHY_DPRX)
+ drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+ else
+ drm_dp_lttpr_link_train_clock_recovery_delay();
+}
+
+/*
+ * Perform the link training clock recovery phase on the given DP PHY using
+ * training pattern 1.
+ */
+static bool
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ u8 voltage;
+ int voltage_tries, cr_tries, max_cr_tries;
+ bool max_vswing_reached = false;
+
/* clock recovery */
- if (!intel_dp_reset_link_train(intel_dp,
+ if (!intel_dp_reset_link_train(intel_dp, crtc_state, dp_phy,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE)) {
drm_err(&i915->drm, "failed to enable link training\n");
@@ -213,14 +470,15 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
u8 link_status[DP_LINK_STATUS_SIZE];
- drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+ intel_dp_link_training_clock_recovery_delay(intel_dp, dp_phy);
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy,
+ link_status) < 0) {
drm_err(&i915->drm, "failed to get link status\n");
return false;
}
- if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+ if (drm_dp_clock_recovery_ok(link_status, crtc_state->lane_count)) {
drm_dbg_kms(&i915->drm, "clock recovery OK\n");
return true;
}
@@ -239,8 +497,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Update training set as requested by target */
- intel_dp_get_adjust_train(intel_dp, link_status);
- if (!intel_dp_update_link_train(intel_dp)) {
+ intel_dp_get_adjust_train(intel_dp, crtc_state, dp_phy,
+ link_status);
+ if (!intel_dp_update_link_train(intel_dp, crtc_state, dp_phy)) {
drm_err(&i915->drm,
"failed to update link training\n");
return false;
@@ -252,7 +511,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
else
voltage_tries = 1;
- if (intel_dp_link_max_vswing_reached(intel_dp))
+ if (intel_dp_link_max_vswing_reached(intel_dp, crtc_state))
max_vswing_reached = true;
}
@@ -266,7 +525,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
* or for 1.4 devices that support it, training Pattern 3 for HBR2
* or 1.2 devices that support it, Training Pattern 2 otherwise.
*/
-static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
+static u32 intel_dp_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
bool source_tps3, sink_tps3, source_tps4, sink_tps4;
@@ -275,12 +536,14 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
* for all downstream devices that support HBR3. There are no known eDP
* panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
* specification.
+ * LTTPRs must support TPS4.
*/
source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
- sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
+ sink_tps4 = dp_phy != DP_PHY_DPRX ||
+ drm_dp_tps4_supported(intel_dp->dpcd);
if (source_tps4 && sink_tps4) {
return DP_TRAINING_PATTERN_4;
- } else if (intel_dp->link_rate == 810000) {
+ } else if (crtc_state->port_clock == 810000) {
if (!source_tps4)
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
"8.1 Gbps link rate without source HBR3/TPS4 support\n");
@@ -294,10 +557,11 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
* all sinks follow the spec.
*/
source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
- sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
+ sink_tps3 = dp_phy != DP_PHY_DPRX ||
+ drm_dp_tps3_supported(intel_dp->dpcd);
if (source_tps3 && sink_tps3) {
return DP_TRAINING_PATTERN_3;
- } else if (intel_dp->link_rate >= 540000) {
+ } else if (crtc_state->port_clock >= 540000) {
if (!source_tps3)
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n");
@@ -309,8 +573,28 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
return DP_TRAINING_PATTERN_2;
}
+static void
+intel_dp_link_training_channel_equalization_delay(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ if (dp_phy == DP_PHY_DPRX) {
+ drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
+ } else {
+ const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+ drm_dp_lttpr_link_train_channel_eq_delay(phy_caps);
+ }
+}
+
+/*
+ * Perform the link training channel equalization phase on the given DP PHY
+ * using one of training pattern 2, 3 or 4 depending on the source and
+ * sink capabilities.
+ */
static bool
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int tries;
@@ -318,22 +602,23 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
u8 link_status[DP_LINK_STATUS_SIZE];
bool channel_eq = false;
- training_pattern = intel_dp_training_pattern(intel_dp);
+ training_pattern = intel_dp_training_pattern(intel_dp, crtc_state, dp_phy);
/* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
if (training_pattern != DP_TRAINING_PATTERN_4)
training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
/* channel equalization */
- if (!intel_dp_set_link_train(intel_dp,
+ if (!intel_dp_set_link_train(intel_dp, crtc_state, dp_phy,
training_pattern)) {
drm_err(&i915->drm, "failed to start channel equalization\n");
return false;
}
for (tries = 0; tries < 5; tries++) {
-
- drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ intel_dp_link_training_channel_equalization_delay(intel_dp,
+ dp_phy);
+ if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy,
+ link_status) < 0) {
drm_err(&i915->drm,
"failed to get link status\n");
break;
@@ -341,7 +626,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
/* Make sure clock is still ok */
if (!drm_dp_clock_recovery_ok(link_status,
- intel_dp->lane_count)) {
+ crtc_state->lane_count)) {
intel_dp_dump_link_status(link_status);
drm_dbg_kms(&i915->drm,
"Clock recovery check failed, cannot "
@@ -350,7 +635,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
}
if (drm_dp_channel_eq_ok(link_status,
- intel_dp->lane_count)) {
+ crtc_state->lane_count)) {
channel_eq = true;
drm_dbg_kms(&i915->drm, "Channel EQ done. DP Training "
"successful\n");
@@ -358,8 +643,9 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
}
/* Update training set as requested by target */
- intel_dp_get_adjust_train(intel_dp, link_status);
- if (!intel_dp_update_link_train(intel_dp)) {
+ intel_dp_get_adjust_train(intel_dp, crtc_state, dp_phy,
+ link_status);
+ if (!intel_dp_update_link_train(intel_dp, crtc_state, dp_phy)) {
drm_err(&i915->drm,
"failed to update link training\n");
break;
@@ -373,54 +659,142 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
"Channel equalization failed 5 times\n");
}
- intel_dp_set_idle_link_train(intel_dp);
-
return channel_eq;
+}
+static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
+ enum drm_dp_phy dp_phy)
+{
+ int reg = intel_dp_training_pattern_set_reg(intel_dp, dp_phy);
+ u8 val = DP_TRAINING_PATTERN_DISABLE;
+
+ return drm_dp_dpcd_write(&intel_dp->aux, reg, &val, 1) == 1;
}
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+/**
+ * intel_dp_stop_link_train - stop link training
+ * @intel_dp: DP struct
+ * @crtc_state: state for CRTC attached to the encoder
+ *
+ * Stop the link training of the @intel_dp port, disabling the test pattern
+ * symbol generation on the port and disabling the training pattern in
+ * the sink's DPCD.
+ *
+ * What symbols are output on the port after this point is
+ * platform specific: On DDI/VLV/CHV platforms it will be the idle pattern
+ * with the pipe being disabled, on older platforms it's HW specific if/how an
+ * idle pattern is generated, as the pipe is already enabled here for those.
+ *
+ * This function must be called after intel_dp_start_link_train().
+ */
+void intel_dp_stop_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
intel_dp->link_trained = true;
- intel_dp_set_link_train(intel_dp,
- DP_TRAINING_PATTERN_DISABLE);
+ intel_dp_program_link_training_pattern(intel_dp,
+ crtc_state,
+ DP_TRAINING_PATTERN_DISABLE);
+ intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX);
}
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
+static bool
+intel_dp_link_train_phy(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy)
{
struct intel_connector *intel_connector = intel_dp->attached_connector;
+ char phy_name[10];
+ bool ret = false;
- if (!intel_dp_link_training_clock_recovery(intel_dp))
- goto failure_handling;
- if (!intel_dp_link_training_channel_equalization(intel_dp))
- goto failure_handling;
+ if (!intel_dp_link_training_clock_recovery(intel_dp, crtc_state, dp_phy))
+ goto out;
- drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
- "[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
- intel_connector->base.base.id,
- intel_connector->base.name,
- intel_dp->link_rate, intel_dp->lane_count);
- return;
+ if (!intel_dp_link_training_channel_equalization(intel_dp, crtc_state, dp_phy))
+ goto out;
+
+ ret = true;
- failure_handling:
+out:
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
- "[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
+ "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s",
intel_connector->base.base.id,
intel_connector->base.name,
- intel_dp->link_rate, intel_dp->lane_count);
+ ret ? "passed" : "failed",
+ crtc_state->port_clock, crtc_state->lane_count,
+ intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
+
+ return ret;
+}
+
+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;
if (intel_dp->hobl_active) {
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
"Link Training failed with HOBL active, not enabling it from now on");
intel_dp->hobl_failed = true;
} else if (intel_dp_get_link_train_fallback_values(intel_dp,
- intel_dp->link_rate,
- intel_dp->lane_count)) {
+ crtc_state->port_clock,
+ crtc_state->lane_count)) {
return;
}
/* Schedule a Hotplug Uevent to userspace to start modeset */
schedule_work(&intel_connector->modeset_retry_work);
}
+
+/* Perform the link training on all LTTPRs and the DPRX on a link. */
+static bool
+intel_dp_link_train_all_phys(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ int lttpr_count)
+{
+ bool ret = true;
+ int i;
+
+ intel_dp_prepare_link_train(intel_dp, crtc_state);
+
+ for (i = lttpr_count - 1; i >= 0; i--) {
+ enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
+
+ ret = intel_dp_link_train_phy(intel_dp, crtc_state, dp_phy);
+ intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
+
+ if (!ret)
+ break;
+ }
+
+ if (ret)
+ intel_dp_link_train_phy(intel_dp, crtc_state, DP_PHY_DPRX);
+
+ if (intel_dp->set_idle_link_train)
+ intel_dp->set_idle_link_train(intel_dp, crtc_state);
+
+ return ret;
+}
+
+/**
+ * intel_dp_start_link_train - start link training
+ * @intel_dp: DP struct
+ * @crtc_state: state for CRTC attached to the encoder
+ *
+ * Start the link training of the @intel_dp port, scheduling a fallback
+ * retraining with reduced link rate/lane parameters if the link training
+ * fails.
+ * After calling this function intel_dp_stop_link_train() must be called.
+ */
+void intel_dp_start_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
+{
+ /*
+ * TODO: Reiniting LTTPRs here won't be needed once proper connector
+ * HW state readout is added.
+ */
+ int lttpr_count = intel_dp_lttpr_init(intel_dp);
+
+ if (!intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count))
+ intel_dp_schedule_fallback_link_training(intel_dp, crtc_state);
+}
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 01f1dabbb060..86905aa24db7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -8,11 +8,24 @@
#include <drm/drm_dp_helper.h>
+struct intel_crtc_state;
struct intel_dp;
+int intel_dp_lttpr_init(struct intel_dp *intel_dp);
+
void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ enum drm_dp_phy dp_phy,
const u8 link_status[DP_LINK_STATUS_SIZE]);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
-void intel_dp_stop_link_train(struct intel_dp *intel_dp);
+void intel_dp_start_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+void intel_dp_stop_link_train(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+
+/* Get the TPSx symbol type of the value programmed to DP_TRAINING_PATTERN_SET */
+static inline u8 intel_dp_training_pattern_symbol(u8 pattern)
+{
+ return pattern & ~DP_LINK_SCRAMBLING_DISABLE;
+}
#endif /* __INTEL_DP_LINK_TRAINING_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 64d885539e94..0c8684634fca 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -130,7 +130,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
limits.min_lane_count =
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
- limits.min_bpp = intel_dp_min_bpp(pipe_config);
+ limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format);
/*
* FIXME: If all the streams can't fit into the link with
* their current pipe_bpp we should reduce pipe_bpp across
@@ -318,19 +318,23 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
return ret;
}
-static void clear_act_sent(struct intel_dp *intel_dp)
+static void clear_act_sent(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
- intel_de_write(i915, intel_dp->regs.dp_tp_status,
+ intel_de_write(i915, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_ACT_SENT);
}
-static void wait_for_act_sent(struct intel_dp *intel_dp)
+static void wait_for_act_sent(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+ struct intel_dp *intel_dp = &intel_mst->primary->dp;
- if (intel_de_wait_for_set(i915, intel_dp->regs.dp_tp_status,
+ if (intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_ACT_SENT, 1))
drm_err(&i915->drm, "Timed out waiting for ACT sent\n");
@@ -392,7 +396,7 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
- clear_act_sent(intel_dp);
+ clear_act_sent(encoder, old_crtc_state);
val = intel_de_read(dev_priv,
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder));
@@ -401,7 +405,7 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
val);
- wait_for_act_sent(intel_dp);
+ wait_for_act_sent(encoder, old_crtc_state);
drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
@@ -488,7 +492,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state,
intel_dp->active_mst_links);
if (first_mst_stream)
- intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+ intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true);
@@ -535,7 +539,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder);
- clear_act_sent(intel_dp);
+ clear_act_sent(encoder, pipe_config);
intel_ddi_enable_transcoder_func(encoder, pipe_config);
@@ -549,7 +553,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
drm_dbg_kms(&dev_priv->drm, "active links %d\n",
intel_dp->active_mst_links);
- wait_for_act_sent(intel_dp);
+ wait_for_act_sent(encoder, pipe_config);
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
@@ -587,6 +591,15 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
intel_ddi_get_config(&dig_port->base, pipe_config);
}
+static bool intel_dp_mst_initial_fastset_check(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+ struct intel_digital_port *dig_port = intel_mst->primary;
+
+ return intel_dp_initial_fastset_check(&dig_port->base, crtc_state);
+}
+
static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -701,7 +714,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
return 0;
}
- *status = intel_mode_valid_max_plane_size(dev_priv, mode);
+ *status = intel_mode_valid_max_plane_size(dev_priv, mode, false);
return 0;
}
@@ -893,6 +906,7 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *dig_port, enum pipe
intel_encoder->enable = intel_mst_enable_dp;
intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
intel_encoder->get_config = intel_dp_mst_enc_get_config;
+ intel_encoder->initial_fastset_check = intel_dp_mst_initial_fastset_check;
return intel_mst;
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
index 7910522273b2..514c4a7adffc 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
@@ -644,16 +644,16 @@ bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
return mask;
}
-
void chv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 deemph_reg_value, u32 margin_reg_value,
bool uniq_trans_scale)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum dpio_channel ch = vlv_dig_port_to_channel(dig_port);
- enum pipe pipe = intel_crtc->pipe;
+ enum pipe pipe = crtc->pipe;
u32 val;
int i;
@@ -666,7 +666,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
- if (intel_crtc->config->lane_count > 2) {
+ if (crtc_state->lane_count > 2) {
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
@@ -679,7 +679,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val);
- if (intel_crtc->config->lane_count > 2) {
+ if (crtc_state->lane_count > 2) {
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
@@ -687,7 +687,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
}
/* Program swing deemph */
- for (i = 0; i < intel_crtc->config->lane_count; i++) {
+ for (i = 0; i < crtc_state->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
val &= ~DPIO_SWING_DEEMPH9P5_MASK;
val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT;
@@ -695,7 +695,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
}
/* Program swing margin */
- for (i = 0; i < intel_crtc->config->lane_count; i++) {
+ for (i = 0; i < crtc_state->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
val &= ~DPIO_SWING_MARGIN000_MASK;
@@ -718,7 +718,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
* For now, for this unique transition scale selection, set bit
* 27 for ch0 and ch1.
*/
- for (i = 0; i < intel_crtc->config->lane_count; i++) {
+ for (i = 0; i < crtc_state->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
if (uniq_trans_scale)
val |= DPIO_TX_UNIQ_TRANS_SCALE_EN;
@@ -732,7 +732,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder,
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
- if (intel_crtc->config->lane_count > 2) {
+ if (crtc_state->lane_count > 2) {
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
@@ -992,14 +992,15 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder,
}
void vlv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 demph_reg_value, u32 preemph_reg_value,
u32 uniqtranscale_reg_value, u32 tx3_demph)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum dpio_channel port = vlv_dig_port_to_channel(dig_port);
- enum pipe pipe = intel_crtc->pipe;
+ enum pipe pipe = crtc->pipe;
vlv_dpio_get(dev_priv);
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h
index f418aab90b7e..6473440e7457 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h
@@ -32,6 +32,7 @@ void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder);
void chv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 deemph_reg_value, u32 margin_reg_value,
bool uniq_trans_scale);
void chv_data_lane_soft_reset(struct intel_encoder *encoder,
@@ -46,6 +47,7 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state);
void vlv_set_phy_signal_level(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
u32 demph_reg_value, u32 preemph_reg_value,
u32 uniqtranscale_reg_value, u32 tx3_demph);
void vlv_phy_pre_pll_enable(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index e08684e34078..f6ad257a260e 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -141,7 +141,7 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
"asserting DPLL %s with no DPLL\n", onoff(state)))
return;
- cur_state = pll->info->funcs->get_hw_state(dev_priv, pll, &hw_state);
+ cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state);
I915_STATE_WARN(cur_state != state,
"%s assertion failure (expected %s, current %s)\n",
pll->info->name, onoff(state), onoff(cur_state));
@@ -151,14 +151,14 @@ static i915_reg_t
intel_combo_pll_enable_reg(struct drm_i915_private *i915,
struct intel_shared_dpll *pll)
{
-
- if (IS_ELKHARTLAKE(i915) && (pll->info->id == DPLL_ID_EHL_DPLL4))
+ if (IS_DG1(i915))
+ return DG1_DPLL_ENABLE(pll->info->id);
+ else if (IS_JSL_EHL(i915) && (pll->info->id == DPLL_ID_EHL_DPLL4))
return MG_PLL_ENABLE(0);
return CNL_DPLL_ENABLE(pll->info->id);
-
-
}
+
/**
* intel_prepare_shared_dpll - call a dpll's prepare hook
* @crtc_state: CRTC, and its state, which has a shared dpll
@@ -891,11 +891,12 @@ hsw_ddi_wrpll_get_dpll(struct intel_atomic_state *state,
}
static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int refclk;
int n, p, r;
- u32 wrpll = pll->state.hw_state.wrpll;
+ u32 wrpll = pll_state->wrpll;
switch (wrpll & WRPLL_REF_MASK) {
case WRPLL_REF_SPECIAL_HSW:
@@ -962,7 +963,8 @@ hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state)
}
static int hsw_ddi_lcpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
@@ -1002,11 +1004,12 @@ hsw_ddi_spll_get_dpll(struct intel_atomic_state *state,
}
static int hsw_ddi_spll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
- switch (pll->state.hw_state.spll & SPLL_FREQ_MASK) {
+ switch (pll_state->spll & SPLL_FREQ_MASK) {
case SPLL_FREQ_810MHz:
link_clock = 81000;
break;
@@ -1577,9 +1580,9 @@ static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
}
static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
int ref_clock = i915->dpll.ref_clks.nssc;
u32 p0, p1, p2, dco_freq;
@@ -1602,9 +1605,19 @@ static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
case DPLL_CFGCR2_PDIV_3:
p0 = 3;
break;
+ case DPLL_CFGCR2_PDIV_7_INVALID:
+ /*
+ * Incorrect ASUS-Z170M BIOS setting, the HW seems to ignore bit#0,
+ * handling it the same way as PDIV_7.
+ */
+ drm_dbg_kms(&i915->drm, "Invalid WRPLL PDIV divider value, fixing it.\n");
+ fallthrough;
case DPLL_CFGCR2_PDIV_7:
p0 = 7;
break;
+ default:
+ MISSING_CASE(p0);
+ return 0;
}
switch (p2) {
@@ -1620,6 +1633,9 @@ static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
case DPLL_CFGCR2_KDIV_1:
p2 = 1;
break;
+ default:
+ MISSING_CASE(p2);
+ return 0;
}
dco_freq = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK) *
@@ -1675,12 +1691,12 @@ skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
}
static int skl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
- switch ((pll->state.hw_state.ctrl1 &
- DPLL_CTRL1_LINK_RATE_MASK(0)) >>
+ switch ((pll_state->ctrl1 & DPLL_CTRL1_LINK_RATE_MASK(0)) >>
DPLL_CTRL1_LINK_RATE_SHIFT(0)) {
case DPLL_CTRL1_LINK_RATE_810:
link_clock = 81000;
@@ -1758,16 +1774,17 @@ static bool skl_get_dpll(struct intel_atomic_state *state,
}
static int skl_ddi_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
/*
* ctrl1 register is already shifted for each pll, just use 0 to get
* the internal shift for each field
*/
- if (pll->state.hw_state.ctrl1 & DPLL_CTRL1_HDMI_MODE(0))
- return skl_ddi_wrpll_get_freq(i915, pll);
+ if (pll_state->ctrl1 & DPLL_CTRL1_HDMI_MODE(0))
+ return skl_ddi_wrpll_get_freq(i915, pll, pll_state);
else
- return skl_ddi_lcpll_get_freq(i915, pll);
+ return skl_ddi_lcpll_get_freq(i915, pll, pll_state);
}
static void skl_update_dpll_ref_clks(struct drm_i915_private *i915)
@@ -2205,9 +2222,9 @@ bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
}
static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
struct dpll clock;
clock.m1 = 2;
@@ -2622,11 +2639,25 @@ static bool cnl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
return true;
}
+/*
+ * Display WA #22010492432: ehl, tgl
+ * Program half of the nominal DCO divider fraction value.
+ */
+static bool
+ehl_combo_pll_div_frac_wa_needed(struct drm_i915_private *i915)
+{
+ return ((IS_PLATFORM(i915, INTEL_ELKHARTLAKE) &&
+ IS_JSL_EHL_REVID(i915, EHL_REVID_B0, REVID_FOREVER)) ||
+ IS_TIGERLAKE(i915)) &&
+ i915->dpll.ref_clks.nssc == 38400;
+}
+
static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state,
int ref_clock)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
+ u32 dco_fraction;
u32 p0, p1, p2, dco_freq;
p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
@@ -2669,8 +2700,13 @@ static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) *
ref_clock;
- dco_freq += (((pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
- DPLL_CFGCR0_DCO_FRACTION_SHIFT) * ref_clock) / 0x8000;
+ dco_fraction = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
+ DPLL_CFGCR0_DCO_FRACTION_SHIFT;
+
+ if (ehl_combo_pll_div_frac_wa_needed(dev_priv))
+ dco_fraction *= 2;
+
+ dco_freq += (dco_fraction * ref_clock) / 0x8000;
if (drm_WARN_ON(&dev_priv->drm, p0 == 0 || p1 == 0 || p2 == 0))
return 0;
@@ -2679,9 +2715,11 @@ static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
}
static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- return __cnl_ddi_wrpll_get_freq(i915, pll, i915->dpll.ref_clks.nssc);
+ return __cnl_ddi_wrpll_get_freq(i915, pll, pll_state,
+ i915->dpll.ref_clks.nssc);
}
static bool
@@ -2730,11 +2768,12 @@ cnl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
}
static int cnl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
int link_clock = 0;
- switch (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_LINK_RATE_MASK) {
+ switch (pll_state->cfgcr0 & DPLL_CFGCR0_LINK_RATE_MASK) {
case DPLL_CFGCR0_LINK_RATE_810:
link_clock = 81000;
break;
@@ -2817,12 +2856,13 @@ static bool cnl_get_dpll(struct intel_atomic_state *state,
}
static int cnl_ddi_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- if (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_HDMI_MODE)
- return cnl_ddi_wrpll_get_freq(i915, pll);
+ if (pll_state->cfgcr0 & DPLL_CFGCR0_HDMI_MODE)
+ return cnl_ddi_wrpll_get_freq(i915, pll, pll_state);
else
- return cnl_ddi_lcpll_get_freq(i915, pll);
+ return cnl_ddi_lcpll_get_freq(i915, pll, pll_state);
}
static void cnl_update_dpll_ref_clks(struct drm_i915_private *i915)
@@ -2948,16 +2988,6 @@ static const struct skl_wrpll_params tgl_tbt_pll_24MHz_values = {
/* the following params are unused */
};
-/*
- * Display WA #22010492432: tgl
- * Divide the nominal .dco_fraction value by 2.
- */
-static const struct skl_wrpll_params tgl_tbt_pll_38_4MHz_values = {
- .dco_integer = 0x54, .dco_fraction = 0x1800,
- /* the following params are unused */
- .pdiv = 0, .kdiv = 0, .qdiv_mode = 0, .qdiv_ratio = 0,
-};
-
static bool icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
struct skl_wrpll_params *pll_params)
{
@@ -2991,14 +3021,12 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
MISSING_CASE(dev_priv->dpll.ref_clks.nssc);
fallthrough;
case 19200:
+ case 38400:
*pll_params = tgl_tbt_pll_19_2MHz_values;
break;
case 24000:
*pll_params = tgl_tbt_pll_24MHz_values;
break;
- case 38400:
- *pll_params = tgl_tbt_pll_38_4MHz_values;
- break;
}
} else {
switch (dev_priv->dpll.ref_clks.nssc) {
@@ -3019,7 +3047,8 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
}
static int icl_ddi_tbt_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
/*
* The PLL outputs multiple frequencies at the same time, selection is
@@ -3055,9 +3084,10 @@ icl_calc_wrpll(struct intel_crtc_state *crtc_state,
}
static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- return __cnl_ddi_wrpll_get_freq(i915, pll,
+ return __cnl_ddi_wrpll_get_freq(i915, pll, pll_state,
icl_wrpll_ref_clock(i915));
}
@@ -3065,9 +3095,14 @@ static void icl_calc_dpll_state(struct drm_i915_private *i915,
const struct skl_wrpll_params *pll_params,
struct intel_dpll_hw_state *pll_state)
{
+ u32 dco_fraction = pll_params->dco_fraction;
+
memset(pll_state, 0, sizeof(*pll_state));
- pll_state->cfgcr0 = DPLL_CFGCR0_DCO_FRACTION(pll_params->dco_fraction) |
+ if (ehl_combo_pll_div_frac_wa_needed(i915))
+ dco_fraction = DIV_ROUND_CLOSEST(dco_fraction, 2);
+
+ pll_state->cfgcr0 = DPLL_CFGCR0_DCO_FRACTION(dco_fraction) |
pll_params->dco_integer;
pll_state->cfgcr1 = DPLL_CFGCR1_QDIV_RATIO(pll_params->qdiv_ratio) |
@@ -3377,9 +3412,9 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
}
static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
- const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
u32 m1, m2_int, m2_frac, div1, div2, ref_clock;
u64 tmp;
@@ -3524,12 +3559,22 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ if (port == PORT_D || port == PORT_E) {
+ dpll_mask =
+ BIT(DPLL_ID_DG1_DPLL2) |
+ BIT(DPLL_ID_DG1_DPLL3);
+ } else {
+ dpll_mask =
+ BIT(DPLL_ID_DG1_DPLL0) |
+ BIT(DPLL_ID_DG1_DPLL1);
+ }
+ } else if (IS_ROCKETLAKE(dev_priv)) {
dpll_mask =
BIT(DPLL_ID_EHL_DPLL4) |
BIT(DPLL_ID_ICL_DPLL1) |
BIT(DPLL_ID_ICL_DPLL0);
- } else if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A) {
+ } else if (IS_JSL_EHL(dev_priv) && port != PORT_A) {
dpll_mask =
BIT(DPLL_ID_EHL_DPLL4) |
BIT(DPLL_ID_ICL_DPLL1) |
@@ -3820,7 +3865,10 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
if (!(val & PLL_ENABLE))
goto out;
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ hw_state->cfgcr0 = intel_de_read(dev_priv, DG1_DPLL_CFGCR0(id));
+ hw_state->cfgcr1 = intel_de_read(dev_priv, DG1_DPLL_CFGCR1(id));
+ } else if (IS_ROCKETLAKE(dev_priv)) {
hw_state->cfgcr0 = intel_de_read(dev_priv,
RKL_DPLL_CFGCR0(id));
hw_state->cfgcr1 = intel_de_read(dev_priv,
@@ -3831,7 +3879,7 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
hw_state->cfgcr1 = intel_de_read(dev_priv,
TGL_DPLL_CFGCR1(id));
} else {
- if (IS_ELKHARTLAKE(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
+ if (IS_JSL_EHL(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
hw_state->cfgcr0 = intel_de_read(dev_priv,
ICL_DPLL_CFGCR0(4));
hw_state->cfgcr1 = intel_de_read(dev_priv,
@@ -3873,14 +3921,17 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv,
const enum intel_dpll_id id = pll->info->id;
i915_reg_t cfgcr0_reg, cfgcr1_reg;
- if (IS_ROCKETLAKE(dev_priv)) {
+ if (IS_DG1(dev_priv)) {
+ cfgcr0_reg = DG1_DPLL_CFGCR0(id);
+ cfgcr1_reg = DG1_DPLL_CFGCR1(id);
+ } else if (IS_ROCKETLAKE(dev_priv)) {
cfgcr0_reg = RKL_DPLL_CFGCR0(id);
cfgcr1_reg = RKL_DPLL_CFGCR1(id);
} else if (INTEL_GEN(dev_priv) >= 12) {
cfgcr0_reg = TGL_DPLL_CFGCR0(id);
cfgcr1_reg = TGL_DPLL_CFGCR1(id);
} else {
- if (IS_ELKHARTLAKE(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
+ if (IS_JSL_EHL(dev_priv) && id == DPLL_ID_EHL_DPLL4) {
cfgcr0_reg = ICL_DPLL_CFGCR0(4);
cfgcr1_reg = ICL_DPLL_CFGCR1(4);
} else {
@@ -4054,7 +4105,7 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv,
{
i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
- if (IS_ELKHARTLAKE(dev_priv) &&
+ if (IS_JSL_EHL(dev_priv) &&
pll->info->id == DPLL_ID_EHL_DPLL4) {
/*
@@ -4167,7 +4218,7 @@ static void combo_pll_disable(struct drm_i915_private *dev_priv,
icl_pll_disable(dev_priv, pll, enable_reg);
- if (IS_ELKHARTLAKE(dev_priv) &&
+ if (IS_JSL_EHL(dev_priv) &&
pll->info->id == DPLL_ID_EHL_DPLL4)
intel_display_power_put(dev_priv, POWER_DOMAIN_DPLL_DC_OFF,
pll->wakeref);
@@ -4317,6 +4368,22 @@ static const struct intel_dpll_mgr rkl_pll_mgr = {
.dump_hw_state = icl_dump_hw_state,
};
+static const struct dpll_info dg1_plls[] = {
+ { "DPLL 0", &combo_pll_funcs, DPLL_ID_DG1_DPLL0, 0 },
+ { "DPLL 1", &combo_pll_funcs, DPLL_ID_DG1_DPLL1, 0 },
+ { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 },
+ { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 },
+ { },
+};
+
+static const struct intel_dpll_mgr dg1_pll_mgr = {
+ .dpll_info = dg1_plls,
+ .get_dplls = icl_get_dplls,
+ .put_dplls = icl_put_dplls,
+ .update_ref_clks = icl_update_dpll_ref_clks,
+ .dump_hw_state = icl_dump_hw_state,
+};
+
/**
* intel_shared_dpll_init - Initialize shared DPLLs
* @dev: drm device
@@ -4330,11 +4397,13 @@ void intel_shared_dpll_init(struct drm_device *dev)
const struct dpll_info *dpll_info;
int i;
- if (IS_ROCKETLAKE(dev_priv))
+ if (IS_DG1(dev_priv))
+ dpll_mgr = &dg1_pll_mgr;
+ else if (IS_ROCKETLAKE(dev_priv))
dpll_mgr = &rkl_pll_mgr;
else if (INTEL_GEN(dev_priv) >= 12)
dpll_mgr = &tgl_pll_mgr;
- else if (IS_ELKHARTLAKE(dev_priv))
+ else if (IS_JSL_EHL(dev_priv))
dpll_mgr = &ehl_pll_mgr;
else if (INTEL_GEN(dev_priv) >= 11)
dpll_mgr = &icl_pll_mgr;
@@ -4456,16 +4525,33 @@ void intel_update_active_dpll(struct intel_atomic_state *state,
* intel_dpll_get_freq - calculate the DPLL's output frequency
* @i915: i915 device
* @pll: DPLL for which to calculate the output frequency
+ * @pll_state: DPLL state from which to calculate the output frequency
*
- * Return the output frequency corresponding to @pll's current state.
+ * Return the output frequency corresponding to @pll's passed in @pll_state.
*/
int intel_dpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll)
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state)
{
if (drm_WARN_ON(&i915->drm, !pll->info->funcs->get_freq))
return 0;
- return pll->info->funcs->get_freq(i915, pll);
+ return pll->info->funcs->get_freq(i915, pll, pll_state);
+}
+
+/**
+ * intel_dpll_get_hw_state - readout the DPLL's hardware state
+ * @i915: i915 device
+ * @pll: DPLL for which to calculate the output frequency
+ * @hw_state: DPLL's hardware state
+ *
+ * Read out @pll's hardware state into @hw_state.
+ */
+bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ return pll->info->funcs->get_hw_state(i915, pll, hw_state);
}
static void readout_dpll_hw_state(struct drm_i915_private *i915,
@@ -4473,10 +4559,9 @@ static void readout_dpll_hw_state(struct drm_i915_private *i915,
{
struct intel_crtc *crtc;
- pll->on = pll->info->funcs->get_hw_state(i915, pll,
- &pll->state.hw_state);
+ pll->on = intel_dpll_get_hw_state(i915, pll, &pll->state.hw_state);
- if (IS_ELKHARTLAKE(i915) && pll->on &&
+ if (IS_JSL_EHL(i915) && pll->on &&
pll->info->id == DPLL_ID_EHL_DPLL4) {
pll->wakeref = intel_display_power_get(i915,
POWER_DOMAIN_DPLL_DC_OFF);
@@ -4531,7 +4616,7 @@ void intel_dpll_sanitize_state(struct drm_i915_private *i915)
}
/**
- * intel_shared_dpll_dump_hw_state - write hw_state to dmesg
+ * intel_dpll_dump_hw_state - write hw_state to dmesg
* @dev_priv: i915 drm device
* @hw_state: hw state to be written to the log
*
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index 5d9a2bc371e7..2eb7618ef957 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -154,6 +154,23 @@ enum intel_dpll_id {
* @DPLL_ID_TGL_MGPLL6: TGL TC PLL port 6 (TC6)
*/
DPLL_ID_TGL_MGPLL6 = 8,
+
+ /**
+ * @DPLL_ID_DG1_DPLL0: DG1 combo PHY DPLL0
+ */
+ DPLL_ID_DG1_DPLL0 = 0,
+ /**
+ * @DPLL_ID_DG1_DPLL1: DG1 combo PHY DPLL1
+ */
+ DPLL_ID_DG1_DPLL1 = 1,
+ /**
+ * @DPLL_ID_DG1_DPLL2: DG1 combo PHY DPLL2
+ */
+ DPLL_ID_DG1_DPLL2 = 2,
+ /**
+ * @DPLL_ID_DG1_DPLL3: DG1 combo PHY DPLL3
+ */
+ DPLL_ID_DG1_DPLL3 = 3,
};
#define I915_NUM_PLLS 9
@@ -283,10 +300,11 @@ struct intel_shared_dpll_funcs {
* @get_freq:
*
* Hook for calculating the pll's output frequency based on its
- * current state.
+ * passed in state.
*/
int (*get_freq)(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll);
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state);
};
/**
@@ -382,7 +400,11 @@ void intel_update_active_dpll(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_encoder *encoder);
int intel_dpll_get_freq(struct drm_i915_private *i915,
- const struct intel_shared_dpll *pll);
+ const struct intel_shared_dpll *pll,
+ const struct intel_dpll_hw_state *pll_state);
+bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c
index afa4e6817e8c..f453ceb8d149 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi.c
+++ b/drivers/gpu/drm/i915/display/intel_dsi.c
@@ -75,7 +75,7 @@ enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
return MODE_CLOCK_HIGH;
}
- return intel_mode_valid_max_plane_size(dev_priv, mode);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, false);
}
struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h
index 19f78a4022d3..625f2f1ae061 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi.h
+++ b/drivers/gpu/drm/i915/display/intel_dsi.h
@@ -167,6 +167,7 @@ static inline u16 intel_dsi_encoder_ports(struct intel_encoder *encoder)
/* icl_dsi.c */
void icl_dsi_init(struct drm_i915_private *dev_priv);
+void icl_dsi_frame_update(struct intel_crtc_state *crtc_state);
/* intel_dsi.c */
int intel_dsi_bitrate(const struct intel_dsi *intel_dsi);
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 135f5e8a4d70..a5b072816a7b 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -907,6 +907,13 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
return false;
}
+ /* Wa_22010751166: icl, ehl, tgl, dg1, rkl */
+ if (INTEL_GEN(dev_priv) >= 11 &&
+ (cache->plane.src_h + cache->plane.adjusted_y) % 4) {
+ fbc->no_fbc_reason = "plane height + offset is non-modulo of 4";
+ return false;
+ }
+
return true;
}
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index e6b8d6dfb598..b0d71bbbf2ad 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -90,11 +90,20 @@ static const struct gmbus_pin gmbus_pins_icp[] = {
[GMBUS_PIN_14_TC6_TGP] = { "tc6", GPIOO },
};
+static const struct gmbus_pin gmbus_pins_dg1[] = {
+ [GMBUS_PIN_1_BXT] = { "dpa", GPIOB },
+ [GMBUS_PIN_2_BXT] = { "dpb", GPIOC },
+ [GMBUS_PIN_3_BXT] = { "dpc", GPIOD },
+ [GMBUS_PIN_4_CNP] = { "dpd", GPIOE },
+};
+
/* pin is expected to be valid */
static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
unsigned int pin)
{
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ return &gmbus_pins_dg1[pin];
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
return &gmbus_pins_icp[pin];
else if (HAS_PCH_CNP(dev_priv))
return &gmbus_pins_cnp[pin];
@@ -113,7 +122,9 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
{
unsigned int size;
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ size = ARRAY_SIZE(gmbus_pins_dg1);
+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
size = ARRAY_SIZE(gmbus_pins_icp);
else if (HAS_PCH_CNP(dev_priv))
size = ARRAY_SIZE(gmbus_pins_cnp);
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 5492076d1ae0..b2a4bbcfdcd2 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -1445,10 +1445,9 @@ static int hdcp2_session_key_exchange(struct intel_connector *connector)
}
static
-int hdcp2_propagate_stream_management_info(struct intel_connector *connector)
+int _hdcp2_propagate_stream_management_info(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);
struct intel_hdcp *hdcp = &connector->hdcp;
union {
struct hdcp2_rep_stream_manage stream_manage;
@@ -1457,6 +1456,9 @@ int hdcp2_propagate_stream_management_info(struct intel_connector *connector)
const struct intel_hdcp_shim *shim = hdcp->shim;
int ret;
+ if (connector->hdcp.seq_num_m > HDCP_2_2_SEQ_NUM_MAX)
+ return -ERANGE;
+
/* Prepare RepeaterAuth_Stream_Manage msg */
msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE;
drm_hdcp_cpu_to_be24(msgs.stream_manage.seq_num_m, hdcp->seq_num_m);
@@ -1472,28 +1474,21 @@ int hdcp2_propagate_stream_management_info(struct intel_connector *connector)
ret = shim->write_2_2_msg(dig_port, &msgs.stream_manage,
sizeof(msgs.stream_manage));
if (ret < 0)
- return ret;
+ goto out;
ret = shim->read_2_2_msg(dig_port, HDCP_2_2_REP_STREAM_READY,
&msgs.stream_ready, sizeof(msgs.stream_ready));
if (ret < 0)
- return ret;
+ goto out;
hdcp->port_data.seq_num_m = hdcp->seq_num_m;
hdcp->port_data.streams[0].stream_type = hdcp->content_type;
-
ret = hdcp2_verify_mprime(connector, &msgs.stream_ready);
- if (ret < 0)
- return ret;
+out:
hdcp->seq_num_m++;
- if (hdcp->seq_num_m > HDCP_2_2_SEQ_NUM_MAX) {
- drm_dbg_kms(&i915->drm, "seq_num_m roll over.\n");
- return -1;
- }
-
- return 0;
+ return ret;
}
static
@@ -1564,17 +1559,6 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
return 0;
}
-static int hdcp2_authenticate_repeater(struct intel_connector *connector)
-{
- int ret;
-
- ret = hdcp2_authenticate_repeater_topology(connector);
- if (ret < 0)
- return ret;
-
- return hdcp2_propagate_stream_management_info(connector);
-}
-
static int hdcp2_authenticate_sink(struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
@@ -1611,7 +1595,7 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector)
}
if (hdcp->is_repeater) {
- ret = hdcp2_authenticate_repeater(connector);
+ ret = hdcp2_authenticate_repeater_topology(connector);
if (ret < 0) {
drm_dbg_kms(&i915->drm,
"Repeater Auth Failed. Err: %d\n", ret);
@@ -1619,11 +1603,6 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector)
}
}
- hdcp->port_data.streams[0].stream_type = hdcp->content_type;
- ret = hdcp2_authenticate_port(connector);
- if (ret < 0)
- return ret;
-
return ret;
}
@@ -1704,15 +1683,59 @@ static int hdcp2_disable_encryption(struct intel_connector *connector)
return ret;
}
+static int
+hdcp2_propagate_stream_management_info(struct intel_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ int i, tries = 3, ret;
+
+ if (!connector->hdcp.is_repeater)
+ return 0;
+
+ for (i = 0; i < tries; i++) {
+ ret = _hdcp2_propagate_stream_management_info(connector);
+ if (!ret)
+ break;
+
+ /* Lets restart the auth incase of seq_num_m roll over */
+ if (connector->hdcp.seq_num_m > HDCP_2_2_SEQ_NUM_MAX) {
+ drm_dbg_kms(&i915->drm,
+ "seq_num_m roll over.(%d)\n", ret);
+ break;
+ }
+
+ drm_dbg_kms(&i915->drm,
+ "HDCP2 stream management %d of %d Failed.(%d)\n",
+ i + 1, tries, ret);
+ }
+
+ return ret;
+}
+
static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_hdcp *hdcp = &connector->hdcp;
int ret, i, tries = 3;
for (i = 0; i < tries; i++) {
ret = hdcp2_authenticate_sink(connector);
- if (!ret)
- break;
+ if (!ret) {
+ ret = hdcp2_propagate_stream_management_info(connector);
+ if (ret) {
+ drm_dbg_kms(&i915->drm,
+ "Stream management failed.(%d)\n",
+ ret);
+ break;
+ }
+ hdcp->port_data.streams[0].stream_type =
+ hdcp->content_type;
+ ret = hdcp2_authenticate_port(connector);
+ if (!ret)
+ break;
+ drm_dbg_kms(&i915->drm, "HDCP2 port auth failed.(%d)\n",
+ ret);
+ }
/* Clearing the mei hdcp session */
drm_dbg_kms(&i915->drm, "HDCP2.2 Auth %d of %d Failed.(%d)\n",
@@ -1721,7 +1744,7 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
drm_dbg_kms(&i915->drm, "Port deauth failed.\n");
}
- if (i != tries) {
+ if (!ret) {
/*
* Ensuring the required 200mSec min time interval between
* Session Key Exchange and encryption.
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 3f2008d845c2..82674a8853c6 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2274,7 +2274,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
if (status != MODE_OK)
return status;
- return intel_mode_valid_max_plane_size(dev_priv, mode);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, false);
}
bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
@@ -2775,8 +2775,9 @@ static void vlv_hdmi_pre_enable(struct intel_atomic_state *state,
vlv_phy_pre_encoder_enable(encoder, pipe_config);
/* HDMI 1.0V-2dB */
- vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
- 0x2b247878);
+ vlv_set_phy_signal_level(encoder, pipe_config,
+ 0x2b245f5f, 0x00002000,
+ 0x5578b83a, 0x2b247878);
dig_port->set_infoframes(encoder,
pipe_config->has_infoframe,
@@ -2853,7 +2854,7 @@ static void chv_hdmi_pre_enable(struct intel_atomic_state *state,
/* FIXME: Program the support xxx V-dB */
/* Use 800mV-0dB */
- chv_set_phy_signal_level(encoder, 128, 102, false);
+ chv_set_phy_signal_level(encoder, pipe_config, 128, 102, false);
dig_port->set_infoframes(encoder,
pipe_config->has_infoframe,
@@ -3139,6 +3140,11 @@ static u8 rkl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
return GMBUS_PIN_1_BXT + phy;
}
+static u8 dg1_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
+{
+ return intel_port_to_phy(dev_priv, port) + 1;
+}
+
static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv,
enum port port)
{
@@ -3176,7 +3182,9 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder)
return ddc_pin;
}
- if (IS_ROCKETLAKE(dev_priv))
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
+ ddc_pin = dg1_port_to_ddc_pin(dev_priv, port);
+ else if (IS_ROCKETLAKE(dev_priv))
ddc_pin = rkl_port_to_ddc_pin(dev_priv, port);
else if (HAS_PCH_MCC(dev_priv))
ddc_pin = mcc_port_to_ddc_pin(dev_priv, port);
@@ -3214,7 +3222,7 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
dig_port->set_infoframes = g4x_set_infoframes;
dig_port->infoframes_enabled = g4x_infoframes_enabled;
} else if (HAS_DDI(dev_priv)) {
- if (dig_port->lspcon.active) {
+ if (intel_bios_is_lspcon_present(dev_priv, dig_port->base.port)) {
dig_port->write_infoframe = lspcon_write_infoframe;
dig_port->read_infoframe = lspcon_read_infoframe;
dig_port->set_infoframes = lspcon_set_infoframes;
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index 5c58c1ed6493..f46a1b7190b8 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -213,6 +213,12 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
}
}
+static void intel_hpd_irq_setup(struct drm_i915_private *i915)
+{
+ if (i915->display_irqs_enabled && i915->display.hpd_irq_setup)
+ i915->display.hpd_irq_setup(i915);
+}
+
static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
{
struct drm_i915_private *dev_priv =
@@ -248,8 +254,7 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
dev_priv->hotplug.stats[pin].state = HPD_ENABLED;
}
- if (dev_priv->display_irqs_enabled && dev_priv->display.hpd_irq_setup)
- dev_priv->display.hpd_irq_setup(dev_priv);
+ intel_hpd_irq_setup(dev_priv);
spin_unlock_irq(&dev_priv->irq_lock);
@@ -556,8 +561,8 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
* Disable any IRQs that storms were detected on. Polling enablement
* happens later in our hotplug work.
*/
- if (storm_detected && dev_priv->display_irqs_enabled)
- dev_priv->display.hpd_irq_setup(dev_priv);
+ if (storm_detected)
+ intel_hpd_irq_setup(dev_priv);
spin_unlock(&dev_priv->irq_lock);
/*
@@ -584,7 +589,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
* This is a separate step from interrupt enabling to simplify the locking rules
* in the driver load and resume code.
*
- * Also see: intel_hpd_poll_init(), which enables connector polling
+ * Also see: intel_hpd_poll_enable() and intel_hpd_poll_disable().
*/
void intel_hpd_init(struct drm_i915_private *dev_priv)
{
@@ -595,19 +600,13 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
dev_priv->hotplug.stats[i].state = HPD_ENABLED;
}
- WRITE_ONCE(dev_priv->hotplug.poll_enabled, false);
- schedule_work(&dev_priv->hotplug.poll_init_work);
-
/*
* Interrupt setup is already guaranteed to be single-threaded, this is
* just to make the assert_spin_locked checks happy.
*/
- if (dev_priv->display_irqs_enabled && dev_priv->display.hpd_irq_setup) {
- spin_lock_irq(&dev_priv->irq_lock);
- if (dev_priv->display_irqs_enabled)
- dev_priv->display.hpd_irq_setup(dev_priv);
- spin_unlock_irq(&dev_priv->irq_lock);
- }
+ spin_lock_irq(&dev_priv->irq_lock);
+ intel_hpd_irq_setup(dev_priv);
+ spin_unlock_irq(&dev_priv->irq_lock);
}
static void i915_hpd_poll_init_work(struct work_struct *work)
@@ -654,12 +653,12 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
}
/**
- * intel_hpd_poll_init - enables/disables polling for connectors with hpd
+ * intel_hpd_poll_enable - enable polling for connectors with hpd
* @dev_priv: i915 device instance
*
- * This function enables polling for all connectors, regardless of whether or
- * not they support hotplug detection. Under certain conditions HPD may not be
- * functional. On most Intel GPUs, this happens when we enter runtime suspend.
+ * This function enables polling for all connectors which support HPD.
+ * Under certain conditions HPD may not be functional. On most Intel GPUs,
+ * this happens when we enter runtime suspend.
* On Valleyview and Cherryview systems, this also happens when we shut off all
* of the powerwells.
*
@@ -667,9 +666,9 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
* dev->mode_config.mutex, we do the actual hotplug enabling in a seperate
* worker.
*
- * Also see: intel_hpd_init(), which restores hpd handling.
+ * Also see: intel_hpd_init() and intel_hpd_poll_disable().
*/
-void intel_hpd_poll_init(struct drm_i915_private *dev_priv)
+void intel_hpd_poll_enable(struct drm_i915_private *dev_priv)
{
WRITE_ONCE(dev_priv->hotplug.poll_enabled, true);
@@ -682,6 +681,31 @@ void intel_hpd_poll_init(struct drm_i915_private *dev_priv)
schedule_work(&dev_priv->hotplug.poll_init_work);
}
+/**
+ * intel_hpd_poll_disable - disable polling for connectors with hpd
+ * @dev_priv: i915 device instance
+ *
+ * This function disables polling for all connectors which support HPD.
+ * Under certain conditions HPD may not be functional. On most Intel GPUs,
+ * this happens when we enter runtime suspend.
+ * On Valleyview and Cherryview systems, this also happens when we shut off all
+ * of the powerwells.
+ *
+ * Since this function can get called in contexts where we're already holding
+ * dev->mode_config.mutex, we do the actual hotplug enabling in a seperate
+ * worker.
+ *
+ * Also used during driver init to initialize connector->polled
+ * appropriately for all connectors.
+ *
+ * Also see: intel_hpd_init() and intel_hpd_poll_enable().
+ */
+void intel_hpd_poll_disable(struct drm_i915_private *dev_priv)
+{
+ WRITE_ONCE(dev_priv->hotplug.poll_enabled, false);
+ schedule_work(&dev_priv->hotplug.poll_init_work);
+}
+
void intel_hpd_init_work(struct drm_i915_private *dev_priv)
{
INIT_DELAYED_WORK(&dev_priv->hotplug.hotplug_work,
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h
index a704d7c94d16..b87e95d606e6 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.h
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.h
@@ -14,7 +14,8 @@ struct intel_digital_port;
struct intel_encoder;
enum port;
-void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
+void intel_hpd_poll_enable(struct drm_i915_private *dev_priv);
+void intel_hpd_poll_disable(struct drm_i915_private *dev_priv);
enum intel_hotplug_state intel_encoder_hotplug(struct intel_encoder *encoder,
struct intel_connector *connector);
void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c
index dc1b35559afd..e37d45e531df 100644
--- a/drivers/gpu/drm/i915/display/intel_lspcon.c
+++ b/drivers/gpu/drm/i915/display/intel_lspcon.c
@@ -184,21 +184,6 @@ static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
return true;
}
-void lspcon_ycbcr420_config(struct drm_connector *connector,
- struct intel_crtc_state *crtc_state)
-{
- const struct drm_display_info *info = &connector->display_info;
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
-
- if (drm_mode_is_420_only(info, adjusted_mode) &&
- connector->ycbcr_420_allowed) {
- crtc_state->port_clock /= 2;
- crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
- crtc_state->lspcon_downsampling = true;
- }
-}
-
static bool lspcon_probe(struct intel_lspcon *lspcon)
{
int retry;
@@ -492,14 +477,19 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
return;
}
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
- if (crtc_state->lspcon_downsampling)
- frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
- else
- frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
- } else {
+ /*
+ * Currently there is no interface defined to
+ * check user preference between RGB/YCBCR444
+ * or YCBCR420. So the only possible case for
+ * YCBCR444 usage is driving YCBCR420 output
+ * with LSPCON, when pipe is configured for
+ * YCBCR444 output and LSPCON takes care of
+ * downsampling it.
+ */
+ if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
+ else
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
- }
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
conn_state->connector,
@@ -525,44 +515,17 @@ u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
return 0;
}
-void lspcon_resume(struct intel_lspcon *lspcon)
-{
- enum drm_lspcon_mode expected_mode;
-
- if (lspcon_wake_native_aux_ch(lspcon)) {
- expected_mode = DRM_LSPCON_MODE_PCON;
- lspcon_resume_in_pcon_wa(lspcon);
- } else {
- expected_mode = DRM_LSPCON_MODE_LS;
- }
-
- if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
- return;
-
- if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
- DRM_ERROR("LSPCON resume failed\n");
- else
- DRM_DEBUG_KMS("LSPCON resume success\n");
-}
-
void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
{
lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
}
-bool lspcon_init(struct intel_digital_port *dig_port)
+static bool lspcon_init(struct intel_digital_port *dig_port)
{
struct intel_dp *dp = &dig_port->dp;
struct intel_lspcon *lspcon = &dig_port->lspcon;
- struct drm_device *dev = dig_port->base.base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_connector *connector = &dp->attached_connector->base;
- if (!HAS_LSPCON(dev_priv)) {
- DRM_ERROR("LSPCON is not supported on this platform\n");
- return false;
- }
-
lspcon->active = false;
lspcon->mode = DRM_LSPCON_MODE_INVALID;
@@ -586,3 +549,37 @@ bool lspcon_init(struct intel_digital_port *dig_port)
DRM_DEBUG_KMS("Success: LSPCON init\n");
return true;
}
+
+void lspcon_resume(struct intel_digital_port *dig_port)
+{
+ struct intel_lspcon *lspcon = &dig_port->lspcon;
+ struct drm_device *dev = dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ enum drm_lspcon_mode expected_mode;
+
+ if (!intel_bios_is_lspcon_present(dev_priv, dig_port->base.port))
+ return;
+
+ if (!lspcon->active) {
+ if (!lspcon_init(dig_port)) {
+ DRM_ERROR("LSPCON init failed on port %c\n",
+ port_name(dig_port->base.port));
+ return;
+ }
+ }
+
+ if (lspcon_wake_native_aux_ch(lspcon)) {
+ expected_mode = DRM_LSPCON_MODE_PCON;
+ lspcon_resume_in_pcon_wa(lspcon);
+ } else {
+ expected_mode = DRM_LSPCON_MODE_LS;
+ }
+
+ if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
+ return;
+
+ if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
+ DRM_ERROR("LSPCON resume failed\n");
+ else
+ DRM_DEBUG_KMS("LSPCON resume success\n");
+}
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.h b/drivers/gpu/drm/i915/display/intel_lspcon.h
index 1cffe8a42a08..b03dcb7076d8 100644
--- a/drivers/gpu/drm/i915/display/intel_lspcon.h
+++ b/drivers/gpu/drm/i915/display/intel_lspcon.h
@@ -15,8 +15,7 @@ struct intel_digital_port;
struct intel_encoder;
struct intel_lspcon;
-bool lspcon_init(struct intel_digital_port *dig_port);
-void lspcon_resume(struct intel_lspcon *lspcon);
+void lspcon_resume(struct intel_digital_port *dig_port);
void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
void lspcon_write_infoframe(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
@@ -32,7 +31,5 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
const struct drm_connector_state *conn_state);
u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
const struct intel_crtc_state *pipe_config);
-void lspcon_ycbcr420_config(struct drm_connector *connector,
- struct intel_crtc_state *crtc_state);
#endif /* __INTEL_LSPCON_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index e65c2de522c3..c6c7c0b9989b 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -371,6 +371,15 @@ static void pch_post_disable_lvds(struct intel_atomic_state *state,
intel_disable_lvds(state, encoder, old_crtc_state, old_conn_state);
}
+static void intel_lvds_shutdown(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (intel_de_wait_for_clear(dev_priv, PP_STATUS(0), PP_CYCLE_DELAY_ACTIVE, 5000))
+ drm_err(&dev_priv->drm,
+ "timed out waiting for panel power cycle delay\n");
+}
+
static enum drm_mode_status
intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
@@ -897,6 +906,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
intel_encoder->get_config = intel_lvds_get_config;
intel_encoder->update_pipe = intel_panel_update_backlight;
+ intel_encoder->shutdown = intel_lvds_shutdown;
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector_attach_encoder(intel_connector, intel_encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
index de995362f428..4f77cf849171 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -1007,12 +1007,8 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
int ret;
ret = swsci(dev_priv, SWSCI_GBDA_PANEL_DETAILS, 0x0, &panel_details);
- if (ret) {
- drm_dbg_kms(&dev_priv->drm,
- "Failed to get panel details from OpRegion (%d)\n",
- ret);
+ if (ret)
return ret;
- }
ret = (panel_details >> 8) & 0xff;
if (ret > 0x10) {
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 40e9cb29233d..b3631b722de3 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -91,19 +91,14 @@ static bool psr_global_enabled(struct drm_i915_private *i915)
}
}
-static bool intel_psr2_enabled(struct drm_i915_private *dev_priv,
- const struct intel_crtc_state *crtc_state)
+static bool psr2_global_enabled(struct drm_i915_private *dev_priv)
{
- /* Cannot enable DSC and PSR2 simultaneously */
- drm_WARN_ON(&dev_priv->drm, crtc_state->dsc.compression_enable &&
- crtc_state->has_psr2);
-
switch (dev_priv->psr.debug & I915_PSR_DEBUG_MODE_MASK) {
case I915_PSR_DEBUG_DISABLE:
case I915_PSR_DEBUG_FORCE_PSR1:
return false;
default:
- return crtc_state->has_psr2;
+ return true;
}
}
@@ -729,6 +724,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
return false;
}
+ if (!psr2_global_enabled(dev_priv)) {
+ drm_dbg_kms(&dev_priv->drm, "PSR2 disabled by flag\n");
+ return false;
+ }
+
/*
* DSC and PSR2 cannot be enabled simultaneously. If a requested
* resolution requires DSC to be enabled, priority is given to DSC
@@ -817,8 +817,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
if (intel_dp != dev_priv->psr.dp)
return;
- if (!psr_global_enabled(dev_priv))
+ if (!psr_global_enabled(dev_priv)) {
+ drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
return;
+ }
+
/*
* HSW spec explicitly says PSR is tied to port A.
* BDW+ platforms have a instance of PSR registers per transcoder but
@@ -942,7 +945,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
intel_de_write(dev_priv, EXITLINE(cpu_transcoder), val);
}
- if (HAS_PSR_HW_TRACKING(dev_priv))
+ if (HAS_PSR_HW_TRACKING(dev_priv) && HAS_PSR2_SEL_FETCH(dev_priv))
intel_de_rmw(dev_priv, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING,
dev_priv->psr.psr2_sel_fetch_enabled ?
IGNORE_PSR2_HW_TRACKING : 0);
@@ -959,7 +962,7 @@ static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
drm_WARN_ON(&dev_priv->drm, dev_priv->psr.enabled);
- dev_priv->psr.psr2_enabled = intel_psr2_enabled(dev_priv, crtc_state);
+ dev_priv->psr.psr2_enabled = crtc_state->has_psr2;
dev_priv->psr.busy_frontbuffer_bits = 0;
dev_priv->psr.pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
dev_priv->psr.dc3co_enabled = !!crtc_state->dc3co_exitline;
@@ -1021,23 +1024,13 @@ void intel_psr_enable(struct intel_dp *intel_dp,
if (!CAN_PSR(dev_priv) || dev_priv->psr.dp != intel_dp)
return;
- dev_priv->psr.force_mode_changed = false;
-
if (!crtc_state->has_psr)
return;
drm_WARN_ON(&dev_priv->drm, dev_priv->drrs.dp);
mutex_lock(&dev_priv->psr.lock);
-
- if (!psr_global_enabled(dev_priv)) {
- drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
- goto unlock;
- }
-
intel_psr_enable_locked(dev_priv, crtc_state, conn_state);
-
-unlock:
mutex_unlock(&dev_priv->psr.lock);
}
@@ -1152,7 +1145,21 @@ void intel_psr_disable(struct intel_dp *intel_dp,
static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 9)
+ if (IS_TIGERLAKE(dev_priv))
+ /*
+ * Writes to CURSURFLIVE in TGL are causing IOMMU errors and
+ * visual glitches that are often reproduced when executing
+ * CPU intensive workloads while a eDP 4K panel is attached.
+ *
+ * Manually exiting PSR causes the frontbuffer to be updated
+ * without glitches and the IOMMU errors are also gone but
+ * this comes at the cost of less time with PSR active.
+ *
+ * So using this workaround until this issue is root caused
+ * and a better fix is found.
+ */
+ intel_psr_exit(dev_priv);
+ else if (INTEL_GEN(dev_priv) >= 9)
/*
* Display WA #0884: skl+
* This documented WA for bxt can be safely applied
@@ -1171,6 +1178,38 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv)
intel_psr_exit(dev_priv);
}
+void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state,
+ int color_plane)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ enum pipe pipe = plane->pipe;
+ u32 val;
+
+ if (!crtc_state->enable_psr2_sel_fetch)
+ return;
+
+ val = plane_state ? plane_state->ctl : 0;
+ val &= plane->id == PLANE_CURSOR ? val : PLANE_SEL_FETCH_CTL_ENABLE;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), val);
+ if (!val || plane->id == PLANE_CURSOR)
+ return;
+
+ val = plane_state->uapi.dst.y1 << 16 | plane_state->uapi.dst.x1;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_POS(pipe, plane->id), val);
+
+ val = plane_state->color_plane[color_plane].y << 16;
+ val |= plane_state->color_plane[color_plane].x;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_OFFSET(pipe, plane->id),
+ val);
+
+ /* Sizes are 0 based */
+ val = ((drm_rect_height(&plane_state->uapi.src) >> 16) - 1) << 16;
+ val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1;
+ intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val);
+}
+
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);
@@ -1185,16 +1224,91 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st
crtc_state->psr2_man_track_ctl);
}
-void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
+static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
+ struct drm_rect *clip, bool full_update)
+{
+ u32 val = PSR2_MAN_TRK_CTL_ENABLE;
+
+ if (full_update) {
+ val |= PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
+ goto exit;
+ }
+
+ if (clip->y1 == -1)
+ goto exit;
+
+ val |= PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE;
+ val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1 / 4 + 1);
+ val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(DIV_ROUND_UP(clip->y2, 4) + 1);
+exit:
+ crtc_state->psr2_man_track_ctl = val;
+}
+
+static void clip_area_update(struct drm_rect *overlap_damage_area,
+ struct drm_rect *damage_area)
+{
+ if (overlap_damage_area->y1 == -1) {
+ overlap_damage_area->y1 = damage_area->y1;
+ overlap_damage_area->y2 = damage_area->y2;
+ return;
+ }
+
+ if (damage_area->y1 < overlap_damage_area->y1)
+ overlap_damage_area->y1 = damage_area->y1;
+
+ if (damage_area->y2 > overlap_damage_area->y2)
+ overlap_damage_area->y2 = damage_area->y2;
+}
+
+int intel_psr2_sel_fetch_update(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, *old_plane_state;
+ struct drm_rect pipe_clip = { .y1 = -1 };
+ struct intel_plane *plane;
+ bool full_update = false;
+ int i, ret;
if (!crtc_state->enable_psr2_sel_fetch)
- return;
+ return 0;
- crtc_state->psr2_man_track_ctl = PSR2_MAN_TRK_CTL_ENABLE |
- PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
+ ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
+ if (ret)
+ return ret;
+
+ for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
+ new_plane_state, i) {
+ struct drm_rect temp;
+
+ if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+ continue;
+
+ /*
+ * TODO: Not clear how to handle planes with negative position,
+ * also planes are not updated if they have a negative X
+ * position so for now doing a full update in this cases
+ */
+ if (new_plane_state->uapi.dst.y1 < 0 ||
+ new_plane_state->uapi.dst.x1 < 0) {
+ full_update = true;
+ break;
+ }
+
+ if (!new_plane_state->uapi.visible)
+ continue;
+
+ /*
+ * For now doing a selective fetch in the whole plane area,
+ * optimizations will come in the future.
+ */
+ temp.y1 = new_plane_state->uapi.dst.y1;
+ temp.y2 = new_plane_state->uapi.dst.y2;
+ clip_area_update(&pipe_clip, &temp);
+ }
+
+ psr2_man_trk_ctl_calc(crtc_state, &pipe_clip, full_update);
+ return 0;
}
/**
@@ -1218,12 +1332,10 @@ void intel_psr_update(struct intel_dp *intel_dp,
if (!CAN_PSR(dev_priv) || READ_ONCE(psr->dp) != intel_dp)
return;
- dev_priv->psr.force_mode_changed = false;
-
mutex_lock(&dev_priv->psr.lock);
- enable = crtc_state->has_psr && psr_global_enabled(dev_priv);
- psr2_enable = intel_psr2_enabled(dev_priv, crtc_state);
+ enable = crtc_state->has_psr;
+ psr2_enable = crtc_state->has_psr2;
if (enable == psr->enabled && psr2_enable == psr->psr2_enabled) {
/* Force a PSR exit when enabling CRC to avoid CRC timeouts */
@@ -1320,11 +1432,12 @@ static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv)
static int intel_psr_fastset_force(struct drm_i915_private *dev_priv)
{
+ struct drm_connector_list_iter conn_iter;
struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx ctx;
struct drm_atomic_state *state;
- struct intel_crtc *crtc;
- int err;
+ struct drm_connector *conn;
+ int err = 0;
state = drm_atomic_state_alloc(dev);
if (!state)
@@ -1334,25 +1447,38 @@ static int intel_psr_fastset_force(struct drm_i915_private *dev_priv)
state->acquire_ctx = &ctx;
retry:
- for_each_intel_crtc(dev, crtc) {
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- err = PTR_ERR(crtc_state);
- goto error;
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(conn, &conn_iter) {
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+
+ if (conn->connector_type != DRM_MODE_CONNECTOR_eDP)
+ continue;
+
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ if (IS_ERR(conn_state)) {
+ err = PTR_ERR(conn_state);
+ break;
}
- if (crtc_state->hw.active && crtc_state->has_psr) {
- /* Mark mode as changed to trigger a pipe->update() */
- crtc_state->uapi.mode_changed = true;
+ if (!conn_state->crtc)
+ continue;
+
+ crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
+ if (IS_ERR(crtc_state)) {
+ err = PTR_ERR(crtc_state);
break;
}
+
+ /* Mark mode as changed to trigger a pipe->update() */
+ crtc_state->mode_changed = true;
}
+ drm_connector_list_iter_end(&conn_iter);
- err = drm_atomic_commit(state);
+ if (err == 0)
+ err = drm_atomic_commit(state);
-error:
if (err == -EDEADLK) {
drm_atomic_state_clear(state);
err = drm_modeset_backoff(&ctx);
@@ -1739,40 +1865,3 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
return ret;
}
-
-void intel_psr_atomic_check(struct drm_connector *connector,
- struct drm_connector_state *old_state,
- struct drm_connector_state *new_state)
-{
- struct drm_i915_private *dev_priv = to_i915(connector->dev);
- struct intel_connector *intel_connector;
- struct intel_digital_port *dig_port;
- struct drm_crtc_state *crtc_state;
-
- if (!CAN_PSR(dev_priv) || !new_state->crtc ||
- !dev_priv->psr.force_mode_changed)
- return;
-
- intel_connector = to_intel_connector(connector);
- dig_port = enc_to_dig_port(to_intel_encoder(new_state->best_encoder));
- if (dev_priv->psr.dp != &dig_port->dp)
- return;
-
- crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
- new_state->crtc);
- crtc_state->mode_changed = true;
-}
-
-void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp)
-{
- struct drm_i915_private *dev_priv;
-
- if (!intel_dp)
- return;
-
- dev_priv = dp_to_i915(intel_dp);
- if (!CAN_PSR(dev_priv) || intel_dp != dev_priv->psr.dp)
- return;
-
- dev_priv->psr.force_mode_changed = true;
-}
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
index 6a83c8e682e6..0a517978e8af 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -15,6 +15,8 @@ struct intel_crtc_state;
struct intel_dp;
struct intel_crtc;
struct intel_atomic_state;
+struct intel_plane_state;
+struct intel_plane;
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
void intel_psr_init_dpcd(struct intel_dp *intel_dp);
@@ -41,12 +43,12 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp);
int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state,
u32 *out_value);
bool intel_psr_enabled(struct intel_dp *intel_dp);
-void intel_psr_atomic_check(struct drm_connector *connector,
- struct drm_connector_state *old_state,
- struct drm_connector_state *new_state);
-void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp);
-void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
- struct intel_crtc *crtc);
+int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state);
+void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state,
+ int color_plane);
#endif /* __INTEL_PSR_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 63040cb0d4e1..019a2d6d807a 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -47,6 +47,7 @@
#include "intel_frontbuffer.h"
#include "intel_pm.h"
#include "intel_psr.h"
+#include "intel_dsi.h"
#include "intel_sprite.h"
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
@@ -93,6 +94,9 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
DEFINE_WAIT(wait);
u32 psr_status;
+ if (new_crtc_state->uapi.async_flip)
+ return;
+
vblank_start = adjusted_mode->crtc_vblank_start;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
vblank_start = DIV_ROUND_UP(vblank_start, 2);
@@ -200,8 +204,19 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
ktime_t end_vbl_time = ktime_get();
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ if (new_crtc_state->uapi.async_flip)
+ return;
+
trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end);
+ /*
+ * Incase of mipi dsi command mode, we need to set frame update
+ * request for every commit.
+ */
+ if (INTEL_GEN(dev_priv) >= 11 &&
+ intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI))
+ icl_dsi_frame_update(new_crtc_state);
+
/* We're still in the vblank-evade critical section, this can't race.
* Would be slightly nice to just grab the vblank count and arm the
* event outside of the critical section - the spinlock might spin for a
@@ -393,6 +408,134 @@ static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
return DIV_ROUND_UP(pixel_rate * num, den);
}
+static int skl_plane_max_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ int cpp = fb->format->cpp[color_plane];
+
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case I915_FORMAT_MOD_X_TILED:
+ /*
+ * Validated limit is 4k, but has 5k should
+ * work apart from the following features:
+ * - Ytile (already limited to 4k)
+ * - FP16 (already limited to 4k)
+ * - render compression (already limited to 4k)
+ * - KVMR sprite and cursor (don't care)
+ * - horizontal panning (TODO verify this)
+ * - pipe and plane scaling (TODO verify this)
+ */
+ if (cpp == 8)
+ return 4096;
+ else
+ return 5120;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+ /* FIXME AUX plane? */
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Yf_TILED:
+ if (cpp == 8)
+ return 2048;
+ else
+ return 4096;
+ default:
+ MISSING_CASE(fb->modifier);
+ return 2048;
+ }
+}
+
+static int glk_plane_max_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ int cpp = fb->format->cpp[color_plane];
+
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case I915_FORMAT_MOD_X_TILED:
+ if (cpp == 8)
+ return 4096;
+ else
+ return 5120;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ /* FIXME AUX plane? */
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Yf_TILED:
+ if (cpp == 8)
+ return 2048;
+ else
+ return 5120;
+ default:
+ MISSING_CASE(fb->modifier);
+ return 2048;
+ }
+}
+
+static int icl_plane_min_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ /* Wa_14011264657, Wa_14011050563: gen11+ */
+ switch (fb->format->format) {
+ case DRM_FORMAT_C8:
+ return 18;
+ case DRM_FORMAT_RGB565:
+ return 10;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_XVYU2101010:
+ case DRM_FORMAT_Y212:
+ case DRM_FORMAT_Y216:
+ return 6;
+ case DRM_FORMAT_NV12:
+ return 20;
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ return 12;
+ case DRM_FORMAT_XRGB16161616F:
+ case DRM_FORMAT_XBGR16161616F:
+ case DRM_FORMAT_ARGB16161616F:
+ case DRM_FORMAT_ABGR16161616F:
+ case DRM_FORMAT_XVYU12_16161616:
+ case DRM_FORMAT_XVYU16161616:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+static int icl_plane_max_width(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ return 5120;
+}
+
+static int skl_plane_max_height(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ return 4096;
+}
+
+static int icl_plane_max_height(const struct drm_framebuffer *fb,
+ int color_plane,
+ unsigned int rotation)
+{
+ return 4320;
+}
+
static unsigned int
skl_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
@@ -429,6 +572,7 @@ skl_program_scaler(struct intel_plane *plane,
u16 y_hphase, uv_rgb_hphase;
u16 y_vphase, uv_rgb_vphase;
int hscale, vscale;
+ u32 ps_ctrl;
hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
&plane_state->uapi.dst,
@@ -455,8 +599,13 @@ skl_program_scaler(struct intel_plane *plane,
uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
}
- intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id),
- PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode);
+ ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0);
+ ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode;
+
+ skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0,
+ plane_state->hw.scaling_filter);
+
+ intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl);
intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id),
PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id),
@@ -604,6 +753,29 @@ icl_program_input_csc(struct intel_plane *plane,
}
static void
+skl_plane_async_flip(struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ unsigned long irqflags;
+ enum plane_id plane_id = plane->id;
+ enum pipe pipe = plane->pipe;
+ u32 surf_addr = plane_state->color_plane[0].offset;
+ u32 plane_ctl = plane_state->ctl;
+
+ plane_ctl |= skl_plane_ctl_crtc(crtc_state);
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+ intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
+ intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
+ intel_plane_ggtt_offset(plane_state) + surf_addr);
+
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void
skl_program_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
@@ -617,8 +789,6 @@ skl_program_plane(struct intel_plane *plane,
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_plane = intel_main_to_aux_plane(fb, color_plane);
- u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
- u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
u32 x = plane_state->color_plane[color_plane].x;
@@ -626,7 +796,7 @@ skl_program_plane(struct intel_plane *plane,
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u8 alpha = plane_state->hw.alpha >> 8;
- u32 plane_color_ctl = 0;
+ u32 plane_color_ctl = 0, aux_dist = 0;
unsigned long irqflags;
u32 keymsk, keymax;
u32 plane_ctl = plane_state->ctl;
@@ -653,6 +823,13 @@ skl_program_plane(struct intel_plane *plane,
crtc_y = 0;
}
+ if (aux_plane) {
+ aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
+
+ if (INTEL_GEN(dev_priv) < 12)
+ aux_dist |= skl_plane_stride(plane_state, aux_plane);
+ }
+
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride);
@@ -661,8 +838,6 @@ skl_program_plane(struct intel_plane *plane,
intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
(src_h << 16) | src_w);
- if (INTEL_GEN(dev_priv) < 12)
- aux_dist |= aux_stride;
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist);
if (icl_is_hdr_plane(dev_priv, plane_id))
@@ -690,6 +865,9 @@ skl_program_plane(struct intel_plane *plane,
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id),
(plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x);
+ if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi))
+ intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane);
+
/*
* The control register self-arms if the plane was previously
* disabled. Try to make the plane enable atomic by writing
@@ -2009,10 +2187,8 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state,
}
}
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- min_scale, max_scale,
- true, true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ min_scale, max_scale, true);
if (ret)
return ret;
@@ -2067,11 +2243,10 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state,
if (ret)
return ret;
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true, true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ true);
if (ret)
return ret;
@@ -2278,10 +2453,8 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state,
max_scale = skl_plane_max_scale(dev_priv, fb);
}
- ret = drm_atomic_helper_check_plane_state(&plane_state->uapi,
- &crtc_state->uapi,
- min_scale, max_scale,
- true, true);
+ ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+ min_scale, max_scale, true);
if (ret)
return ret;
@@ -2842,8 +3015,8 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
- /* Wa_14010477008:tgl[a0..c0],rkl[all] */
- if (IS_ROCKETLAKE(dev_priv) ||
+ /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */
+ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) ||
IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0))
return false;
@@ -3083,12 +3256,25 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
}
+ if (INTEL_GEN(dev_priv) >= 11) {
+ plane->min_width = icl_plane_min_width;
+ plane->max_width = icl_plane_max_width;
+ plane->max_height = icl_plane_max_height;
+ } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
+ plane->max_width = glk_plane_max_width;
+ plane->max_height = skl_plane_max_height;
+ } else {
+ plane->max_width = skl_plane_max_width;
+ plane->max_height = skl_plane_max_height;
+ }
+
plane->max_stride = skl_plane_max_stride;
plane->update_plane = skl_update_plane;
plane->disable_plane = skl_disable_plane;
plane->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check;
plane->min_cdclk = skl_plane_min_cdclk;
+ plane->async_flip = skl_plane_async_flip;
if (INTEL_GEN(dev_priv) >= 11)
formats = icl_get_plane_formats(dev_priv, pipe,
@@ -3160,6 +3346,11 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
if (INTEL_GEN(dev_priv) >= 12)
drm_plane_enable_fb_damage_clips(&plane->base);
+ if (INTEL_GEN(dev_priv) >= 10)
+ drm_plane_create_scaling_filter_property(&plane->base,
+ BIT(DRM_SCALING_FILTER_DEFAULT) |
+ BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
+
drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
return plane;
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index 8f67aef18b2d..4346bc1a747a 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -228,9 +228,9 @@ static void tc_port_fixup_legacy_flag(struct intel_digital_port *dig_port,
return;
/* If live status mismatches the VBT flag, trust the live status. */
- drm_err(&i915->drm,
- "Port %s: live status %08x mismatches the legacy port flag, fix flag\n",
- dig_port->tc_port_name, live_status_mask);
+ drm_dbg_kms(&i915->drm,
+ "Port %s: live status %08x mismatches the legacy port flag %08x, fixing flag\n",
+ dig_port->tc_port_name, live_status_mask, valid_hpd_mask);
dig_port->tc_legacy_port = !dig_port->tc_legacy_port;
}
@@ -652,7 +652,7 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)
enum port port = dig_port->base.port;
enum tc_port tc_port = intel_port_to_tc(i915, port);
- if (drm_WARN_ON(&i915->drm, tc_port == PORT_TC_NONE))
+ if (drm_WARN_ON(&i915->drm, tc_port == TC_PORT_NONE))
return;
snprintf(dig_port->tc_port_name, sizeof(dig_port->tc_port_name),
diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
index 54bcc6a6947c..49b4b5fca941 100644
--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
@@ -782,7 +782,7 @@ struct lfp_backlight_data_entry {
u8 active_low_pwm:1;
u8 obsolete1:5;
u16 pwm_freq_hz;
- u8 min_brightness;
+ u8 min_brightness; /* Obsolete from 234+ */
u8 obsolete2;
u8 obsolete3;
} __packed;
@@ -792,11 +792,19 @@ struct lfp_backlight_control_method {
u8 controller:4;
} __packed;
+struct lfp_brightness_level {
+ u16 level;
+ u16 reserved;
+} __packed;
+
struct bdb_lfp_backlight_data {
u8 entry_size;
struct lfp_backlight_data_entry data[16];
- u8 level[16];
+ u8 level[16]; /* Obsolete from 234+ */
struct lfp_backlight_control_method backlight_control[16];
+ struct lfp_brightness_level brightness_level[16]; /* 234+ */
+ struct lfp_brightness_level brightness_min_level[16]; /* 234+ */
+ u8 brightness_precision_bits[16]; /* 236+ */
} __packed;
/*
@@ -827,6 +835,7 @@ struct bdb_lfp_power {
u16 lace_enabled_status;
struct agressiveness_profile_entry aggressivenes[16];
u16 hobl; /* 232+ */
+ u16 vrr_feature_enabled; /* 233+ */
} __packed;
/*
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index c5735c365659..e2716a67b281 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -332,11 +332,10 @@ static const struct rc_parameters *get_rc_params(u16 compressed_bpp,
return &rc_parameters[row_index][column_index];
}
-bool intel_dsc_source_support(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state)
{
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum pipe pipe = crtc->pipe;
@@ -490,11 +489,10 @@ intel_dsc_power_domain(const struct intel_crtc_state *crtc_state)
return POWER_DOMAIN_TRANSCODER_VDSC_PW2;
}
-static void intel_dsc_pps_configure(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+static void intel_dsc_pps_configure(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(encoder->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
enum pipe pipe = crtc->pipe;
u32 pps_val = 0;
@@ -503,6 +501,9 @@ static void intel_dsc_pps_configure(struct intel_encoder *encoder,
u8 num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1;
int i = 0;
+ if (crtc_state->bigjoiner)
+ num_vdsc_instances *= 2;
+
/* Populate PICTURE_PARAMETER_SET_0 registers */
pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor <<
DSC_VER_MIN_SHIFT |
@@ -973,55 +974,6 @@ static void intel_dsc_pps_configure(struct intel_encoder *encoder,
}
}
-void intel_dsc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state)
-{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- enum pipe pipe = crtc->pipe;
- enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
- u32 dss_ctl1, dss_ctl2, val;
-
- if (!intel_dsc_source_support(encoder, crtc_state))
- return;
-
- power_domain = intel_dsc_power_domain(crtc_state);
-
- wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
- if (!wakeref)
- return;
-
- if (!is_pipe_dsc(crtc_state)) {
- dss_ctl1 = intel_de_read(dev_priv, DSS_CTL1);
- dss_ctl2 = intel_de_read(dev_priv, DSS_CTL2);
- } else {
- dss_ctl1 = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL1(pipe));
- dss_ctl2 = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL2(pipe));
- }
-
- crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE;
- if (!crtc_state->dsc.compression_enable)
- goto out;
-
- crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) &&
- (dss_ctl1 & JOINER_ENABLE);
-
- /* FIXME: add more state readout as needed */
-
- /* PPS1 */
- if (!is_pipe_dsc(crtc_state))
- val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1);
- else
- val = intel_de_read(dev_priv,
- ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe));
- vdsc_cfg->bits_per_pixel = val;
- crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4;
-out:
- intel_display_power_put(dev_priv, power_domain, wakeref);
-}
-
static void intel_dsc_dsi_pps_write(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
@@ -1060,77 +1012,126 @@ static void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
sizeof(dp_dsc_pps_sdp));
}
+static i915_reg_t dss_ctl1_reg(const struct intel_crtc_state *crtc_state)
+{
+ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+ if (crtc_state->cpu_transcoder == TRANSCODER_EDP)
+ return DSS_CTL1;
+
+ return ICL_PIPE_DSS_CTL1(pipe);
+}
+
+static i915_reg_t dss_ctl2_reg(const struct intel_crtc_state *crtc_state)
+{
+ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+ if (crtc_state->cpu_transcoder == TRANSCODER_EDP)
+ return DSS_CTL2;
+
+ return ICL_PIPE_DSS_CTL2(pipe);
+}
+
void intel_dsc_enable(struct intel_encoder *encoder,
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(encoder->base.dev);
- enum pipe pipe = crtc->pipe;
- i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dss_ctl1_val = 0;
u32 dss_ctl2_val = 0;
if (!crtc_state->dsc.compression_enable)
return;
- /* Enable Power wells for VDSC/joining */
- intel_display_power_get(dev_priv,
- intel_dsc_power_domain(crtc_state));
-
- intel_dsc_pps_configure(encoder, crtc_state);
+ intel_dsc_pps_configure(crtc_state);
- if (encoder->type == INTEL_OUTPUT_DSI)
- intel_dsc_dsi_pps_write(encoder, crtc_state);
- else
- intel_dsc_dp_pps_write(encoder, crtc_state);
-
- if (!is_pipe_dsc(crtc_state)) {
- dss_ctl1_reg = DSS_CTL1;
- dss_ctl2_reg = DSS_CTL2;
- } else {
- dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
- dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+ if (!crtc_state->bigjoiner_slave) {
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
+ intel_dsc_dsi_pps_write(encoder, crtc_state);
+ else
+ intel_dsc_dp_pps_write(encoder, crtc_state);
}
+
dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE;
if (crtc_state->dsc.dsc_split) {
dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
dss_ctl1_val |= JOINER_ENABLE;
}
- intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1_val);
- intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2_val);
+ if (crtc_state->bigjoiner) {
+ dss_ctl1_val |= BIG_JOINER_ENABLE;
+ if (!crtc_state->bigjoiner_slave)
+ dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE;
+ }
+ intel_de_write(dev_priv, dss_ctl1_reg(crtc_state), dss_ctl1_val);
+ intel_de_write(dev_priv, dss_ctl2_reg(crtc_state), dss_ctl2_val);
}
void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
- i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
- u32 dss_ctl1_val = 0, dss_ctl2_val = 0;
if (!old_crtc_state->dsc.compression_enable)
return;
- if (!is_pipe_dsc(old_crtc_state)) {
- dss_ctl1_reg = DSS_CTL1;
- dss_ctl2_reg = DSS_CTL2;
- } else {
- dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
- dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+ intel_de_write(dev_priv, dss_ctl1_reg(old_crtc_state), 0);
+ intel_de_write(dev_priv, dss_ctl2_reg(old_crtc_state), 0);
+}
+
+void intel_dsc_get_config(struct intel_crtc_state *crtc_state)
+{
+ struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+ enum intel_display_power_domain power_domain;
+ intel_wakeref_t wakeref;
+ u32 dss_ctl1, dss_ctl2, val;
+
+ if (!intel_dsc_source_support(crtc_state))
+ return;
+
+ power_domain = intel_dsc_power_domain(crtc_state);
+
+ wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+ if (!wakeref)
+ return;
+
+ dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc_state));
+ dss_ctl2 = intel_de_read(dev_priv, dss_ctl2_reg(crtc_state));
+
+ crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE;
+ if (!crtc_state->dsc.compression_enable)
+ goto out;
+
+ crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) &&
+ (dss_ctl1 & JOINER_ENABLE);
+
+ if (dss_ctl1 & BIG_JOINER_ENABLE) {
+ crtc_state->bigjoiner = true;
+
+ if (!(dss_ctl1 & MASTER_BIG_JOINER_ENABLE)) {
+ crtc_state->bigjoiner_slave = true;
+ if (!WARN_ON(crtc->pipe == PIPE_A))
+ crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe - 1);
+ } else {
+ if (!WARN_ON(INTEL_NUM_PIPES(dev_priv) == crtc->pipe + 1))
+ crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+ }
}
- dss_ctl1_val = intel_de_read(dev_priv, dss_ctl1_reg);
- if (dss_ctl1_val & JOINER_ENABLE)
- dss_ctl1_val &= ~JOINER_ENABLE;
- intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1_val);
-
- dss_ctl2_val = intel_de_read(dev_priv, dss_ctl2_reg);
- if (dss_ctl2_val & LEFT_BRANCH_VDSC_ENABLE ||
- dss_ctl2_val & RIGHT_BRANCH_VDSC_ENABLE)
- dss_ctl2_val &= ~(LEFT_BRANCH_VDSC_ENABLE |
- RIGHT_BRANCH_VDSC_ENABLE);
- intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2_val);
-
- /* Disable Power wells for VDSC/joining */
- intel_display_power_put_unchecked(dev_priv,
- intel_dsc_power_domain(old_crtc_state));
+
+ /* FIXME: add more state readout as needed */
+
+ /* PPS1 */
+ if (!is_pipe_dsc(crtc_state))
+ val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1);
+ else
+ val = intel_de_read(dev_priv,
+ ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe));
+ vdsc_cfg->bits_per_pixel = val;
+ crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4;
+out:
+ intel_display_power_put(dev_priv, power_domain, wakeref);
}
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h
index e56a3254c214..65d301c23580 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.h
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.h
@@ -11,15 +11,13 @@
struct intel_encoder;
struct intel_crtc_state;
-bool intel_dsc_source_support(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state);
+bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state);
void intel_dsc_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
int intel_dsc_compute_params(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config);
-void intel_dsc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state);
+void intel_dsc_get_config(struct intel_crtc_state *crtc_state);
enum intel_display_power_domain
intel_dsc_power_domain(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index 5e5522923b1e..d52f9c177908 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -985,6 +985,13 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state,
intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
}
+static void intel_dsi_shutdown(struct intel_encoder *encoder)
+{
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+
+ intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
+}
+
static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
@@ -1843,6 +1850,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
intel_encoder->get_hw_state = intel_dsi_get_hw_state;
intel_encoder->get_config = intel_dsi_get_config;
intel_encoder->update_pipe = intel_panel_update_backlight;
+ intel_encoder->shutdown = intel_dsi_shutdown;
intel_connector->get_hw_state = intel_connector_get_hw_state;