diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
133 files changed, 7438 insertions, 3056 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; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c index 272cf3ea68d5..44821d94544f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c @@ -202,12 +202,6 @@ retry: if (unlikely(err)) goto out_request; - if (w->ce->engine->emit_init_breadcrumb) { - err = w->ce->engine->emit_init_breadcrumb(rq); - if (unlikely(err)) - goto out_request; - } - /* * w->dma is already exported via (vma|obj)->resv we need only * keep track of the GPU activity within this vma/request, and @@ -217,9 +211,15 @@ retry: if (err) goto out_request; - err = w->ce->engine->emit_bb_start(rq, - batch->node.start, batch->node.size, - 0); + if (rq->engine->emit_init_breadcrumb) { + err = rq->engine->emit_init_breadcrumb(rq); + if (unlikely(err)) + goto out_request; + } + + err = rq->engine->emit_bb_start(rq, + batch->node.start, batch->node.size, + 0); out_request: if (unlikely(err)) { i915_request_set_error_once(rq, err); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 8dd295dbe241..0dd477e56573 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -77,14 +77,21 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, i915_gem_object_unpin_pages(obj); } -static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) +static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); + void *vaddr; - return i915_gem_object_pin_map(obj, I915_MAP_WB); + vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + + dma_buf_map_set_vaddr(map, vaddr); + + return 0; } -static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) +static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index c8421fd9d2dc..00d24000b5e8 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -39,9 +39,18 @@ static struct i915_global_object { struct kmem_cache *slab_objects; } global; +static const struct drm_gem_object_funcs i915_gem_object_funcs; + struct drm_i915_gem_object *i915_gem_object_alloc(void) { - return kmem_cache_zalloc(global.slab_objects, GFP_KERNEL); + struct drm_i915_gem_object *obj; + + obj = kmem_cache_zalloc(global.slab_objects, GFP_KERNEL); + if (!obj) + return NULL; + obj->base.funcs = &i915_gem_object_funcs; + + return obj; } void i915_gem_object_free(struct drm_i915_gem_object *obj) @@ -73,6 +82,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, obj->mm.madv = I915_MADV_WILLNEED; INIT_RADIX_TREE(&obj->mm.get_page.radix, GFP_KERNEL | __GFP_NOWARN); mutex_init(&obj->mm.get_page.lock); + INIT_RADIX_TREE(&obj->mm.get_dma_page.radix, GFP_KERNEL | __GFP_NOWARN); + mutex_init(&obj->mm.get_dma_page.lock); if (IS_ENABLED(CONFIG_LOCKDEP) && i915_gem_object_is_shrinkable(obj)) i915_gem_shrinker_taints_mutex(to_i915(obj->base.dev), @@ -101,7 +112,7 @@ void i915_gem_object_set_cache_coherency(struct drm_i915_gem_object *obj, !(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE); } -void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file) +static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file) { struct drm_i915_gem_object *obj = to_intel_bo(gem); struct drm_i915_file_private *fpriv = file->driver_priv; @@ -264,7 +275,7 @@ static void __i915_gem_free_work(struct work_struct *work) i915_gem_flush_free_objects(i915); } -void i915_gem_free_object(struct drm_gem_object *gem_obj) +static void i915_gem_free_object(struct drm_gem_object *gem_obj) { struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); struct drm_i915_private *i915 = to_i915(obj->base.dev); @@ -403,6 +414,12 @@ int __init i915_global_objects_init(void) return 0; } +static const struct drm_gem_object_funcs i915_gem_object_funcs = { + .free = i915_gem_free_object, + .close = i915_gem_close_object, + .export = i915_gem_prime_export, +}; + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/huge_gem_object.c" #include "selftests/huge_pages.c" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index d46db8d8f38e..be14486f63a7 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -38,9 +38,6 @@ void __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align); -void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file); -void i915_gem_free_object(struct drm_gem_object *obj); - void i915_gem_flush_free_objects(struct drm_i915_private *i915); struct sg_table * @@ -275,8 +272,26 @@ int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, unsigned int tiling, unsigned int stride); struct scatterlist * +__i915_gem_object_get_sg(struct drm_i915_gem_object *obj, + struct i915_gem_object_page_iter *iter, + unsigned int n, + unsigned int *offset); + +static inline struct scatterlist * i915_gem_object_get_sg(struct drm_i915_gem_object *obj, - unsigned int n, unsigned int *offset); + unsigned int n, + unsigned int *offset) +{ + return __i915_gem_object_get_sg(obj, &obj->mm.get_page, n, offset); +} + +static inline struct scatterlist * +i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj, + unsigned int n, + unsigned int *offset) +{ + return __i915_gem_object_get_sg(obj, &obj->mm.get_dma_page, n, offset); +} struct page * i915_gem_object_get_page(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index d6711caa7f39..e2d9b7e1e152 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -82,6 +82,14 @@ struct i915_mmap_offset { struct rb_node offset; }; +struct i915_gem_object_page_iter { + struct scatterlist *sg_pos; + unsigned int sg_idx; /* in pages, but 32bit eek! */ + + struct radix_tree_root radix; + struct mutex lock; /* protects this cache */ +}; + struct drm_i915_gem_object { struct drm_gem_object base; @@ -248,13 +256,8 @@ struct drm_i915_gem_object { I915_SELFTEST_DECLARE(unsigned int page_mask); - struct i915_gem_object_page_iter { - struct scatterlist *sg_pos; - unsigned int sg_idx; /* in pages, but 32bit eek! */ - - struct radix_tree_root radix; - struct mutex lock; /* protects this cache */ - } get_page; + struct i915_gem_object_page_iter get_page; + struct i915_gem_object_page_iter get_dma_page; /** * Element within i915->mm.unbound_list or i915->mm.bound_list, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index f60ca6dc911f..e2c7b2a7895f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -33,6 +33,8 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, obj->mm.get_page.sg_pos = pages->sgl; obj->mm.get_page.sg_idx = 0; + obj->mm.get_dma_page.sg_pos = pages->sgl; + obj->mm.get_dma_page.sg_idx = 0; obj->mm.pages = pages; @@ -155,6 +157,8 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj) rcu_read_lock(); radix_tree_for_each_slot(slot, &obj->mm.get_page.radix, &iter, 0) radix_tree_delete(&obj->mm.get_page.radix, iter.index); + radix_tree_for_each_slot(slot, &obj->mm.get_dma_page.radix, &iter, 0) + radix_tree_delete(&obj->mm.get_dma_page.radix, iter.index); rcu_read_unlock(); } @@ -438,11 +442,12 @@ void __i915_gem_object_release_map(struct drm_i915_gem_object *obj) } struct scatterlist * -i915_gem_object_get_sg(struct drm_i915_gem_object *obj, - unsigned int n, - unsigned int *offset) +__i915_gem_object_get_sg(struct drm_i915_gem_object *obj, + struct i915_gem_object_page_iter *iter, + unsigned int n, + unsigned int *offset) { - struct i915_gem_object_page_iter *iter = &obj->mm.get_page; + const bool dma = iter == &obj->mm.get_dma_page; struct scatterlist *sg; unsigned int idx, count; @@ -471,7 +476,7 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj, sg = iter->sg_pos; idx = iter->sg_idx; - count = __sg_page_count(sg); + count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg); while (idx + count <= n) { void *entry; @@ -499,7 +504,7 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj, idx += count; sg = ____sg_next(sg); - count = __sg_page_count(sg); + count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg); } scan: @@ -517,7 +522,7 @@ scan: while (idx + count <= n) { idx += count; sg = ____sg_next(sg); - count = __sg_page_count(sg); + count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg); } *offset = n - idx; @@ -584,7 +589,7 @@ i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, struct scatterlist *sg; unsigned int offset; - sg = i915_gem_object_get_sg(obj, n, &offset); + sg = i915_gem_object_get_sg_dma(obj, n, &offset); if (len) *len = sg_dma_len(sg) - (offset << PAGE_SHIFT); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 84b2707d8b17..29bffc6afcc1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -497,6 +497,43 @@ static int i915_gem_init_stolen(struct drm_i915_private *i915) return 0; } +static void dbg_poison(struct i915_ggtt *ggtt, + dma_addr_t addr, resource_size_t size, + u8 x) +{ +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) + if (!drm_mm_node_allocated(&ggtt->error_capture)) + return; + + if (ggtt->vm.bind_async_flags & I915_VMA_GLOBAL_BIND) + return; /* beware stop_machine() inversion */ + + GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE)); + + mutex_lock(&ggtt->error_mutex); + while (size) { + void __iomem *s; + + ggtt->vm.insert_page(&ggtt->vm, addr, + ggtt->error_capture.start, + I915_CACHE_NONE, 0); + mb(); + + s = io_mapping_map_wc(&ggtt->iomap, + ggtt->error_capture.start, + PAGE_SIZE); + memset_io(s, x, PAGE_SIZE); + io_mapping_unmap(s); + + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + mb(); + ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE); + mutex_unlock(&ggtt->error_mutex); +#endif +} + static struct sg_table * i915_pages_create_for_stolen(struct drm_device *dev, resource_size_t offset, resource_size_t size) @@ -540,6 +577,11 @@ static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj) if (IS_ERR(pages)) return PTR_ERR(pages); + dbg_poison(&to_i915(obj->base.dev)->ggtt, + sg_dma_address(pages->sgl), + sg_dma_len(pages->sgl), + POISON_INUSE); + __i915_gem_object_set_pages(obj, pages, obj->stolen->size); return 0; @@ -549,6 +591,12 @@ static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj, struct sg_table *pages) { /* Should only be called from i915_gem_object_release_stolen() */ + + dbg_poison(&to_i915(obj->base.dev)->ggtt, + sg_dma_address(pages->sgl), + sg_dma_len(pages->sgl), + POISON_FREE); + sg_free_table(pages); kfree(pages); } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index 0845ce1ae37c..b6d43880b0c1 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -82,6 +82,7 @@ static int igt_dmabuf_import(void *arg) struct drm_i915_gem_object *obj; struct dma_buf *dmabuf; void *obj_map, *dma_map; + struct dma_buf_map map; u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff }; int err, i; @@ -110,7 +111,8 @@ static int igt_dmabuf_import(void *arg) goto out_obj; } - dma_map = dma_buf_vmap(dmabuf); + err = dma_buf_vmap(dmabuf, &map); + dma_map = err ? NULL : map.vaddr; if (!dma_map) { pr_err("dma_buf_vmap failed\n"); err = -ENOMEM; @@ -150,7 +152,7 @@ static int igt_dmabuf_import(void *arg) err = 0; out_dma_map: - dma_buf_vunmap(dmabuf, dma_map); + dma_buf_vunmap(dmabuf, &map); out_obj: i915_gem_object_put(obj); out_dmabuf: @@ -163,6 +165,7 @@ static int igt_dmabuf_import_ownership(void *arg) struct drm_i915_private *i915 = arg; struct drm_i915_gem_object *obj; struct dma_buf *dmabuf; + struct dma_buf_map map; void *ptr; int err; @@ -170,7 +173,8 @@ static int igt_dmabuf_import_ownership(void *arg) if (IS_ERR(dmabuf)) return PTR_ERR(dmabuf); - ptr = dma_buf_vmap(dmabuf); + err = dma_buf_vmap(dmabuf, &map); + ptr = err ? NULL : map.vaddr; if (!ptr) { pr_err("dma_buf_vmap failed\n"); err = -ENOMEM; @@ -178,7 +182,7 @@ static int igt_dmabuf_import_ownership(void *arg) } memset(ptr, 0xc5, PAGE_SIZE); - dma_buf_vunmap(dmabuf, ptr); + dma_buf_vunmap(dmabuf, &map); obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf)); if (IS_ERR(obj)) { @@ -212,6 +216,7 @@ static int igt_dmabuf_export_vmap(void *arg) struct drm_i915_private *i915 = arg; struct drm_i915_gem_object *obj; struct dma_buf *dmabuf; + struct dma_buf_map map; void *ptr; int err; @@ -228,7 +233,8 @@ static int igt_dmabuf_export_vmap(void *arg) } i915_gem_object_put(obj); - ptr = dma_buf_vmap(dmabuf); + err = dma_buf_vmap(dmabuf, &map); + ptr = err ? NULL : map.vaddr; if (!ptr) { pr_err("dma_buf_vmap failed\n"); err = -ENOMEM; @@ -244,7 +250,7 @@ static int igt_dmabuf_export_vmap(void *arg) memset(ptr, 0xc5, dmabuf->size); err = 0; - dma_buf_vunmap(dmabuf, ptr); + dma_buf_vunmap(dmabuf, &map); out: dma_buf_put(dmabuf); return err; diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c index be30b27e2926..2855d11c7a51 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c @@ -61,18 +61,24 @@ static void mock_dmabuf_release(struct dma_buf *dma_buf) kfree(mock); } -static void *mock_dmabuf_vmap(struct dma_buf *dma_buf) +static int mock_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map) { struct mock_dmabuf *mock = to_mock(dma_buf); + void *vaddr; - return vm_map_ram(mock->pages, mock->npages, 0); + vaddr = vm_map_ram(mock->pages, mock->npages, 0); + if (!vaddr) + return -ENOMEM; + dma_buf_map_set_vaddr(map, vaddr); + + return 0; } -static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) +static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map) { struct mock_dmabuf *mock = to_mock(dma_buf); - vm_unmap_ram(vaddr, mock->npages); + vm_unmap_ram(map->vaddr, mock->npages); } static int mock_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c index c30adc05fa98..680bd9442eb0 100644 --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c @@ -131,17 +131,17 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, vaddr = kmap_atomic_px(i915_pt_entry(pd, act_pt)); do { - GEM_BUG_ON(iter.sg->length < I915_GTT_PAGE_SIZE); + GEM_BUG_ON(sg_dma_len(iter.sg) < I915_GTT_PAGE_SIZE); vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma); iter.dma += I915_GTT_PAGE_SIZE; if (iter.dma == iter.max) { iter.sg = __sg_next(iter.sg); - if (!iter.sg) + if (!iter.sg || sg_dma_len(iter.sg) == 0) break; iter.dma = sg_dma_address(iter.sg); - iter.max = iter.dma + iter.sg->length; + iter.max = iter.dma + sg_dma_len(iter.sg); } if (++act_pte == GEN6_PTES) { diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 38c7069b7749..a37c968ef8f7 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -372,19 +372,19 @@ gen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt, pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2)); vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1))); do { - GEM_BUG_ON(iter->sg->length < I915_GTT_PAGE_SIZE); + GEM_BUG_ON(sg_dma_len(iter->sg) < I915_GTT_PAGE_SIZE); vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma; iter->dma += I915_GTT_PAGE_SIZE; if (iter->dma >= iter->max) { iter->sg = __sg_next(iter->sg); - if (!iter->sg) { + if (!iter->sg || sg_dma_len(iter->sg) == 0) { idx = 0; break; } iter->dma = sg_dma_address(iter->sg); - iter->max = iter->dma + iter->sg->length; + iter->max = iter->dma + sg_dma_len(iter->sg); } if (gen8_pd_index(++idx, 0) == 0) { @@ -413,8 +413,8 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma, u32 flags) { const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags); + unsigned int rem = sg_dma_len(iter->sg); u64 start = vma->node.start; - dma_addr_t rem = iter->sg->length; GEM_BUG_ON(!i915_vm_is_4lvl(vma->vm)); @@ -456,7 +456,7 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma, } do { - GEM_BUG_ON(iter->sg->length < page_size); + GEM_BUG_ON(sg_dma_len(iter->sg) < page_size); vaddr[index++] = encode | iter->dma; start += page_size; @@ -467,7 +467,10 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma, if (!iter->sg) break; - rem = iter->sg->length; + rem = sg_dma_len(iter->sg); + if (!rem) + break; + iter->dma = sg_dma_address(iter->sg); iter->max = iter->dma + rem; @@ -525,7 +528,7 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma, } vma->page_sizes.gtt |= page_size; - } while (iter->sg); + } while (iter->sg && sg_dma_len(iter->sg)); } static void gen8_ppgtt_insert(struct i915_address_space *vm, diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index efdeb7b7b2a0..0b31670343f5 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -305,8 +305,9 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id) engine->i915 = i915; engine->gt = gt; engine->uncore = gt->uncore; - engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = __engine_mmio_base(i915, info->mmio_bases); + engine->hw_id = info->hw_id; + engine->guc_id = MAKE_GUC_ID(info->class, info->instance); engine->class = info->class; engine->instance = info->instance; @@ -1600,6 +1601,41 @@ static unsigned long list_count(struct list_head *list) return count; } +static unsigned long read_ul(void *p, size_t x) +{ + return *(unsigned long *)(p + x); +} + +static void print_properties(struct intel_engine_cs *engine, + struct drm_printer *m) +{ + static const struct pmap { + size_t offset; + const char *name; + } props[] = { +#define P(x) { \ + .offset = offsetof(typeof(engine->props), x), \ + .name = #x \ +} + P(heartbeat_interval_ms), + P(max_busywait_duration_ns), + P(preempt_timeout_ms), + P(stop_timeout_ms), + P(timeslice_duration_ms), + + {}, +#undef P + }; + const struct pmap *p; + + drm_printf(m, "\tProperties:\n"); + for (p = props; p->name; p++) + drm_printf(m, "\t\t%s: %lu [default %lu]\n", + p->name, + read_ul(&engine->props, p->offset), + read_ul(&engine->defaults, p->offset)); +} + void intel_engine_dump(struct intel_engine_cs *engine, struct drm_printer *m, const char *header, ...) @@ -1642,6 +1678,7 @@ void intel_engine_dump(struct intel_engine_cs *engine, drm_printf(m, "\tReset count: %d (global %d)\n", i915_reset_engine_count(error, engine), i915_reset_count(error)); + print_properties(engine, m); drm_printf(m, "\tRequests:\n"); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index 5067d0524d4b..9060385cd69e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -41,6 +41,8 @@ static void idle_pulse(struct intel_engine_cs *engine, struct i915_request *rq) { engine->wakeref_serial = READ_ONCE(engine->serial) + 1; i915_request_add_active_barriers(rq); + if (!engine->heartbeat.systole && intel_engine_has_heartbeat(engine)) + engine->heartbeat.systole = i915_request_get(rq); } static void show_heartbeat(const struct i915_request *rq, @@ -144,8 +146,6 @@ static void heartbeat(struct work_struct *wrk) goto unlock; idle_pulse(engine, rq); - if (engine->i915->params.enable_hangcheck) - engine->heartbeat.systole = i915_request_get(rq); __i915_request_commit(rq); __i915_request_queue(rq, &attr); @@ -153,7 +153,7 @@ static void heartbeat(struct work_struct *wrk) unlock: mutex_unlock(&ce->timeline->mutex); out: - if (!next_heartbeat(engine)) + if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine)) i915_request_put(fetch_and_zero(&engine->heartbeat.systole)); intel_engine_pm_put(engine); } diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c index f7b2e07e2229..499b09cb4acf 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -17,6 +17,25 @@ #include "intel_ring.h" #include "shmem_utils.h" +static void dbg_poison_ce(struct intel_context *ce) +{ + if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) + return; + + if (ce->state) { + struct drm_i915_gem_object *obj = ce->state->obj; + int type = i915_coherent_map_type(ce->engine->i915); + void *map; + + map = i915_gem_object_pin_map(obj, type); + if (!IS_ERR(map)) { + memset(map, CONTEXT_REDZONE, obj->base.size); + i915_gem_object_flush_map(obj); + i915_gem_object_unpin_map(obj); + } + } +} + static int __engine_unpark(struct intel_wakeref *wf) { struct intel_engine_cs *engine = @@ -32,20 +51,14 @@ static int __engine_unpark(struct intel_wakeref *wf) if (ce) { GEM_BUG_ON(test_bit(CONTEXT_VALID_BIT, &ce->flags)); + /* Flush all pending HW writes before we touch the context */ + while (unlikely(intel_context_inflight(ce))) + intel_engine_flush_submission(engine); + /* First poison the image to verify we never fully trust it */ - if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && ce->state) { - struct drm_i915_gem_object *obj = ce->state->obj; - int type = i915_coherent_map_type(engine->i915); - void *map; - - map = i915_gem_object_pin_map(obj, type); - if (!IS_ERR(map)) { - memset(map, CONTEXT_REDZONE, obj->base.size); - i915_gem_object_flush_map(obj); - i915_gem_object_unpin_map(obj); - } - } + dbg_poison_ce(ce); + /* Scrub the context image after our loss of control */ ce->ops->reset(ce); } diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 81c05f551b9c..cf94525be2c1 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -835,7 +835,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) u16 snb_gmch_ctl; /* TODO: We're not aware of mappable constraints on gen8 yet */ - if (!IS_DGFX(i915)) { + if (!HAS_LMEM(i915)) { ggtt->gmadr = pci_resource(pdev, 2); ggtt->mappable_end = resource_size(&ggtt->gmadr); } @@ -1383,7 +1383,7 @@ intel_partial_pages(const struct i915_ggtt_view *view, if (ret) goto err_sg_alloc; - iter = i915_gem_object_get_sg(obj, view->partial.offset, &offset); + iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset); GEM_BUG_ON(!iter); sg = st->sgl; @@ -1391,7 +1391,7 @@ intel_partial_pages(const struct i915_ggtt_view *view, do { unsigned int len; - len = min(iter->length - (offset << PAGE_SHIFT), + len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), count << PAGE_SHIFT); sg_set_page(sg, NULL, len, 0); sg_dma_address(sg) = diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 39b428c5049c..44f1d51e5ae5 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -614,6 +614,8 @@ void intel_gt_driver_remove(struct intel_gt *gt) void intel_gt_driver_unregister(struct intel_gt *gt) { + intel_wakeref_t wakeref; + intel_rps_driver_unregister(>->rps); /* @@ -622,16 +624,15 @@ void intel_gt_driver_unregister(struct intel_gt *gt) * resources. */ intel_gt_set_wedged(gt); + + /* Scrub all HW state upon release */ + with_intel_runtime_pm(gt->uncore->rpm, wakeref) + __intel_gt_reset(gt, ALL_ENGINES); } void intel_gt_driver_release(struct intel_gt *gt) { struct i915_address_space *vm; - intel_wakeref_t wakeref; - - /* Scrub all HW state upon release */ - with_intel_runtime_pm(gt->uncore->rpm, wakeref) - __intel_gt_reset(gt, ALL_ENGINES); vm = fetch_and_zero(>->vm); if (vm) /* FIXME being called twice on error paths :( */ diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 3f1114b58b01..7bfe9072be9a 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -324,7 +324,7 @@ static void cnl_setup_private_ppat(struct intel_uncore *uncore) GEN8_PPAT_WC | GEN8_PPAT_LLCELLC); intel_uncore_write(uncore, GEN10_PAT_INDEX(2), - GEN8_PPAT_WT | GEN8_PPAT_LLCELLC); + GEN8_PPAT_WB | GEN8_PPAT_ELLC_OVERRIDE); intel_uncore_write(uncore, GEN10_PAT_INDEX(3), GEN8_PPAT_UC); @@ -349,17 +349,23 @@ static void cnl_setup_private_ppat(struct intel_uncore *uncore) */ static void bdw_setup_private_ppat(struct intel_uncore *uncore) { + struct drm_i915_private *i915 = uncore->i915; u64 pat; pat = GEN8_PPAT(0, GEN8_PPAT_WB | GEN8_PPAT_LLC) | /* for normal objects, no eLLC */ GEN8_PPAT(1, GEN8_PPAT_WC | GEN8_PPAT_LLCELLC) | /* for something pointing to ptes? */ - GEN8_PPAT(2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC) | /* for scanout with eLLC */ GEN8_PPAT(3, GEN8_PPAT_UC) | /* Uncached objects, mostly for scanout */ GEN8_PPAT(4, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(0)) | GEN8_PPAT(5, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(1)) | GEN8_PPAT(6, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(2)) | GEN8_PPAT(7, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3)); + /* for scanout with eLLC */ + if (INTEL_GEN(i915) >= 9) + pat |= GEN8_PPAT(2, GEN8_PPAT_WB | GEN8_PPAT_ELLC_OVERRIDE); + else + pat |= GEN8_PPAT(2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC); + intel_uncore_write(uncore, GEN8_PRIVATE_PAT_LO, lower_32_bits(pat)); intel_uncore_write(uncore, GEN8_PRIVATE_PAT_HI, upper_32_bits(pat)); } diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index c13c650ced22..8a33940a71f3 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -580,7 +580,7 @@ static inline struct sgt_dma { struct scatterlist *sg = vma->pages->sgl; dma_addr_t addr = sg_dma_address(sg); - return (struct sgt_dma){ sg, addr, addr + sg->length }; + return (struct sgt_dma){ sg, addr, addr + sg_dma_len(sg) }; } #endif diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 724b2cb897d3..7614a3d24fca 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -1216,7 +1216,8 @@ static void intel_engine_context_out(struct intel_engine_cs *engine) static void execlists_check_context(const struct intel_context *ce, - const struct intel_engine_cs *engine) + const struct intel_engine_cs *engine, + const char *when) { const struct intel_ring *ring = ce->ring; u32 *regs = ce->lrc_reg_state; @@ -1251,7 +1252,7 @@ execlists_check_context(const struct intel_context *ce, valid = false; } - WARN_ONCE(!valid, "Invalid lrc state found before submission\n"); + WARN_ONCE(!valid, "Invalid lrc state found %s submission\n", when); } static void restore_default_state(struct intel_context *ce, @@ -1347,7 +1348,7 @@ __execlists_schedule_in(struct i915_request *rq) reset_active(rq, engine); if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) - execlists_check_context(ce, engine); + execlists_check_context(ce, engine, "before"); if (ce->tag) { /* Use a fixed tag for OA and friends */ @@ -1418,6 +1419,9 @@ __execlists_schedule_out(struct i915_request *rq, * refrain from doing non-trivial work here. */ + if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) + execlists_check_context(ce, engine, "after"); + /* * If we have just completed this context, the engine may now be * idle and we want to re-enter powersaving. @@ -2496,25 +2500,11 @@ invalidate_csb_entries(const u64 *first, const u64 *last) * bits 47-57: sw context id of the lrc the GT switched away from * bits 58-63: sw counter of the lrc the GT switched away from */ -static inline bool gen12_csb_parse(const u64 *csb) +static inline bool gen12_csb_parse(const u64 csb) { - bool ctx_away_valid; - bool new_queue; - u64 entry; - - /* HSD#22011248461 */ - entry = READ_ONCE(*csb); - if (unlikely(entry == -1)) { - preempt_disable(); - if (wait_for_atomic_us((entry = READ_ONCE(*csb)) != -1, 50)) - GEM_WARN_ON("50us CSB timeout"); - preempt_enable(); - } - WRITE_ONCE(*(u64 *)csb, -1); - - ctx_away_valid = GEN12_CSB_CTX_VALID(upper_32_bits(entry)); - new_queue = - lower_32_bits(entry) & GEN12_CTX_STATUS_SWITCHED_TO_NEW_QUEUE; + bool ctx_away_valid = GEN12_CSB_CTX_VALID(upper_32_bits(csb)); + bool new_queue = + lower_32_bits(csb) & GEN12_CTX_STATUS_SWITCHED_TO_NEW_QUEUE; /* * The context switch detail is not guaranteed to be 5 when a preemption @@ -2524,7 +2514,7 @@ static inline bool gen12_csb_parse(const u64 *csb) * would require some extra handling, but we don't support that. */ if (!ctx_away_valid || new_queue) { - GEM_BUG_ON(!GEN12_CSB_CTX_VALID(lower_32_bits(entry))); + GEM_BUG_ON(!GEN12_CSB_CTX_VALID(lower_32_bits(csb))); return true; } @@ -2533,19 +2523,79 @@ static inline bool gen12_csb_parse(const u64 *csb) * context switch on an unsuccessful wait instruction since we always * use polling mode. */ - GEM_BUG_ON(GEN12_CTX_SWITCH_DETAIL(upper_32_bits(entry))); + GEM_BUG_ON(GEN12_CTX_SWITCH_DETAIL(upper_32_bits(csb))); return false; } -static inline bool gen8_csb_parse(const u64 *csb) +static inline bool gen8_csb_parse(const u64 csb) +{ + return csb & (GEN8_CTX_STATUS_IDLE_ACTIVE | GEN8_CTX_STATUS_PREEMPTED); +} + +static noinline u64 +wa_csb_read(const struct intel_engine_cs *engine, u64 * const csb) { - return *csb & (GEN8_CTX_STATUS_IDLE_ACTIVE | GEN8_CTX_STATUS_PREEMPTED); + u64 entry; + + /* + * Reading from the HWSP has one particular advantage: we can detect + * a stale entry. Since the write into HWSP is broken, we have no reason + * to trust the HW at all, the mmio entry may equally be unordered, so + * we prefer the path that is self-checking and as a last resort, + * return the mmio value. + * + * tgl,dg1:HSDES#22011327657 + */ + preempt_disable(); + if (wait_for_atomic_us((entry = READ_ONCE(*csb)) != -1, 10)) { + int idx = csb - engine->execlists.csb_status; + int status; + + status = GEN8_EXECLISTS_STATUS_BUF; + if (idx >= 6) { + status = GEN11_EXECLISTS_STATUS_BUF2; + idx -= 6; + } + status += sizeof(u64) * idx; + + entry = intel_uncore_read64(engine->uncore, + _MMIO(engine->mmio_base + status)); + } + preempt_enable(); + + return entry; +} + +static inline u64 +csb_read(const struct intel_engine_cs *engine, u64 * const csb) +{ + u64 entry = READ_ONCE(*csb); + + /* + * Unfortunately, the GPU does not always serialise its write + * of the CSB entries before its write of the CSB pointer, at least + * from the perspective of the CPU, using what is known as a Global + * Observation Point. We may read a new CSB tail pointer, but then + * read the stale CSB entries, causing us to misinterpret the + * context-switch events, and eventually declare the GPU hung. + * + * icl:HSDES#1806554093 + * tgl:HSDES#22011248461 + */ + if (unlikely(entry == -1)) + entry = wa_csb_read(engine, csb); + + /* Consume this entry so that we can spot its future reuse. */ + WRITE_ONCE(*csb, -1); + + /* ELSP is an implicit wmb() before the GPU wraps and overwrites csb */ + return entry; } static void process_csb(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; - const u64 * const buf = execlists->csb_status; + u64 * const buf = execlists->csb_status; const u8 num_entries = execlists->csb_size; u8 head, tail; @@ -2603,6 +2653,7 @@ static void process_csb(struct intel_engine_cs *engine) rmb(); do { bool promote; + u64 csb; if (++head == num_entries) head = 0; @@ -2625,15 +2676,14 @@ static void process_csb(struct intel_engine_cs *engine) * status notifier. */ + csb = csb_read(engine, buf + head); ENGINE_TRACE(engine, "csb[%d]: status=0x%08x:0x%08x\n", - head, - upper_32_bits(buf[head]), - lower_32_bits(buf[head])); + head, upper_32_bits(csb), lower_32_bits(csb)); if (INTEL_GEN(engine->i915) >= 12) - promote = gen12_csb_parse(buf + head); + promote = gen12_csb_parse(csb); else - promote = gen8_csb_parse(buf + head); + promote = gen8_csb_parse(csb); if (promote) { struct i915_request * const *old = execlists->active; @@ -2991,6 +3041,8 @@ static struct execlists_capture *capture_regs(struct intel_engine_cs *engine) if (!cap->error->gt->engine) goto err_gt; + cap->error->gt->engine->hung = true; + return cap; err_gt: @@ -4053,6 +4105,8 @@ static void reset_csb_pointers(struct intel_engine_cs *engine) static void execlists_sanitize(struct intel_engine_cs *engine) { + GEM_BUG_ON(execlists_active(&engine->execlists)); + /* * Poison residual state on resume, in case the suspend didn't! * @@ -4382,6 +4436,7 @@ static void execlists_reset_cancel(struct intel_engine_cs *engine) /* Mark all executing requests as skipped. */ list_for_each_entry(rq, &engine->active.requests, sched.link) mark_eio(rq); + intel_engine_signal_breadcrumbs(engine); /* Flush the queued requests to the timeline list (for retiring). */ while ((rb = rb_first_cached(&execlists->queue))) { @@ -5974,18 +6029,6 @@ int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine, return 0; } -struct intel_engine_cs * -intel_virtual_engine_get_sibling(struct intel_engine_cs *engine, - unsigned int sibling) -{ - struct virtual_engine *ve = to_virtual_engine(engine); - - if (sibling >= ve->num_siblings) - return NULL; - - return ve->siblings[sibling]; -} - void intel_execlists_show_requests(struct intel_engine_cs *engine, struct drm_printer *m, void (*show_request)(struct drm_printer *m, diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.h b/drivers/gpu/drm/i915/gt/intel_lrc.h index 91fd8e452d9b..c2d287f25497 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.h +++ b/drivers/gpu/drm/i915/gt/intel_lrc.h @@ -121,10 +121,6 @@ int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine, const struct intel_engine_cs *master, const struct intel_engine_cs *sibling); -struct intel_engine_cs * -intel_virtual_engine_get_sibling(struct intel_engine_cs *engine, - unsigned int sibling); - bool intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine); diff --git a/drivers/gpu/drm/i915/gt/intel_lrc_reg.h b/drivers/gpu/drm/i915/gt/intel_lrc_reg.h index 93cb6c460508..1b51f7b9a5c3 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc_reg.h +++ b/drivers/gpu/drm/i915/gt/intel_lrc_reg.h @@ -49,4 +49,7 @@ #define GEN11_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x1A #define GEN12_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0xD +#define GEN8_EXECLISTS_STATUS_BUF 0x370 +#define GEN11_EXECLISTS_STATUS_BUF2 0x3c0 + #endif /* _INTEL_LRC_REG_H_ */ diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index 413dadfac2d1..ab6870242e18 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -108,7 +108,7 @@ struct drm_i915_mocs_table { * they will be initialized to PTE. Gen >= 12 onwards don't have a setting for * PTE and will be initialized to an invalid value. * - * The last two entries are reserved by the hardware. For ICL+ they + * The last few entries are reserved by the hardware. For ICL+ they * should be initialized according to bspec and never used, for older * platforms they should never be written to. * @@ -123,7 +123,7 @@ struct drm_i915_mocs_table { LE_1_UC | LE_TC_2_LLC_ELLC, \ L3_1_UC), \ MOCS_ENTRY(I915_MOCS_PTE, \ - LE_0_PAGETABLE | LE_TC_2_LLC_ELLC | LE_LRUM(3), \ + LE_0_PAGETABLE | LE_TC_0_PAGETABLE | LE_LRUM(3), \ L3_3_WB) static const struct drm_i915_mocs_entry skl_mocs_table[] = { @@ -292,12 +292,45 @@ static const struct drm_i915_mocs_entry icl_mocs_table[] = { L3_1_UC), /* Base - L3 + LeCC:PAT (Deprecated) */ MOCS_ENTRY(I915_MOCS_PTE, - LE_0_PAGETABLE | LE_TC_1_LLC, + LE_0_PAGETABLE | LE_TC_0_PAGETABLE, L3_3_WB), GEN11_MOCS_ENTRIES }; +static const struct drm_i915_mocs_entry dg1_mocs_table[] = { + /* Error */ + MOCS_ENTRY(0, 0, L3_0_DIRECT), + + /* UC */ + MOCS_ENTRY(1, 0, L3_1_UC), + + /* Reserved */ + MOCS_ENTRY(2, 0, L3_0_DIRECT), + MOCS_ENTRY(3, 0, L3_0_DIRECT), + MOCS_ENTRY(4, 0, L3_0_DIRECT), + + /* WB - L3 */ + MOCS_ENTRY(5, 0, L3_3_WB), + /* WB - L3 50% */ + MOCS_ENTRY(6, 0, L3_ESC(1) | L3_SCC(1) | L3_3_WB), + /* WB - L3 25% */ + MOCS_ENTRY(7, 0, L3_ESC(1) | L3_SCC(3) | L3_3_WB), + /* WB - L3 12.5% */ + MOCS_ENTRY(8, 0, L3_ESC(1) | L3_SCC(7) | L3_3_WB), + + /* HDC:L1 + L3 */ + MOCS_ENTRY(48, 0, L3_3_WB), + /* HDC:L1 */ + MOCS_ENTRY(49, 0, L3_1_UC), + + /* HW Reserved */ + MOCS_ENTRY(60, 0, L3_1_UC), + MOCS_ENTRY(61, 0, L3_1_UC), + MOCS_ENTRY(62, 0, L3_1_UC), + MOCS_ENTRY(63, 0, L3_1_UC), +}; + enum { HAS_GLOBAL_MOCS = BIT(0), HAS_ENGINE_MOCS = BIT(1), @@ -324,7 +357,11 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915, { unsigned int flags; - if (INTEL_GEN(i915) >= 12) { + if (IS_DG1(i915)) { + table->size = ARRAY_SIZE(dg1_mocs_table); + table->table = dg1_mocs_table; + table->n_entries = GEN9_NUM_MOCS_ENTRIES; + } else if (INTEL_GEN(i915) >= 12) { table->size = ARRAY_SIZE(tgl_mocs_table); table->table = tgl_mocs_table; table->n_entries = GEN9_NUM_MOCS_ENTRIES; diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index ac36b67fb46b..3654c955e6be 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -19,6 +19,7 @@ #include "intel_engine_pm.h" #include "intel_gt.h" #include "intel_gt_pm.h" +#include "intel_gt_requests.h" #include "intel_reset.h" #include "uc/intel_guc.h" @@ -1190,14 +1191,14 @@ static void intel_gt_reset_global(struct intel_gt *gt, /* Use a watchdog to ensure that our reset completes */ intel_wedge_on_timeout(&w, gt, 5 * HZ) { - intel_prepare_reset(gt->i915); + intel_display_prepare_reset(gt->i915); /* Flush everyone using a resource about to be clobbered */ synchronize_srcu_expedited(>->reset.backoff_srcu); intel_gt_reset(gt, engine_mask, reason); - intel_finish_reset(gt->i915); + intel_display_finish_reset(gt->i915); } if (!test_bit(I915_WEDGED, >->reset.flags)) @@ -1250,7 +1251,7 @@ void intel_gt_handle_error(struct intel_gt *gt, engine_mask &= gt->info.engine_mask; if (flags & I915_ERROR_CAPTURE) { - i915_capture_error_state(gt->i915); + i915_capture_error_state(gt, engine_mask); intel_gt_clear_error_registers(gt, engine_mask); } @@ -1370,6 +1371,7 @@ void intel_gt_set_wedged_on_fini(struct intel_gt *gt) { intel_gt_set_wedged(gt); set_bit(I915_WEDGED_ON_FINI, >->reset.flags); + intel_gt_retire_requests(gt); /* cleanup any wedged requests */ } void intel_gt_init_reset(struct intel_gt *gt) diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c index 16b48e72c369..a41b43f445b8 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c @@ -444,6 +444,7 @@ static void reset_cancel(struct intel_engine_cs *engine) i915_request_set_error_once(request, -EIO); i915_request_mark_complete(request); } + intel_engine_signal_breadcrumbs(engine); /* Remaining _unready_ requests will be nop'ed when submitted */ diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index c1c9cc0ad3b9..b629eeb14002 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -390,6 +390,16 @@ static void gen5_rps_update(struct intel_rps *rps) spin_unlock_irq(&mchdev_lock); } +static unsigned int gen5_invert_freq(struct intel_rps *rps, + unsigned int val) +{ + /* Invert the frequency bin into an ips delay */ + val = rps->max_freq - val; + val = rps->min_freq + val; + + return val; +} + static bool gen5_rps_set(struct intel_rps *rps, u8 val) { struct intel_uncore *uncore = rps_to_uncore(rps); @@ -404,8 +414,7 @@ static bool gen5_rps_set(struct intel_rps *rps, u8 val) } /* Invert the frequency bin into an ips delay */ - val = rps->max_freq - val; - val = rps->min_freq + val; + val = gen5_invert_freq(rps, val); rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | @@ -500,6 +509,7 @@ static unsigned int init_emon(struct intel_uncore *uncore) static bool gen5_rps_enable(struct intel_rps *rps) { + struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); u8 fstart, vstart; u32 rgvmodectl; @@ -557,6 +567,10 @@ static bool gen5_rps_enable(struct intel_rps *rps) rps->ips.last_count2 = intel_uncore_read(uncore, GFXEC); rps->ips.last_time2 = ktime_get_raw_ns(); + spin_lock(&i915->irq_lock); + ilk_enable_display_irq(i915, DE_PCU_EVENT); + spin_unlock(&i915->irq_lock); + spin_unlock_irq(&mchdev_lock); rps->ips.corr = init_emon(uncore); @@ -566,11 +580,16 @@ static bool gen5_rps_enable(struct intel_rps *rps) static void gen5_rps_disable(struct intel_rps *rps) { + struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); u16 rgvswctl; spin_lock_irq(&mchdev_lock); + spin_lock(&i915->irq_lock); + ilk_disable_display_irq(i915, DE_PCU_EVENT); + spin_unlock(&i915->irq_lock); + rgvswctl = intel_uncore_read16(uncore, MEMSWCTL); /* Ack interrupts, disable EFC interrupt */ @@ -578,11 +597,6 @@ static void gen5_rps_disable(struct intel_rps *rps) intel_uncore_read(uncore, MEMINTREN) & ~MEMINT_EVAL_CHG_EN); intel_uncore_write(uncore, MEMINTRSTS, MEMINT_EVAL_CHG); - intel_uncore_write(uncore, DEIER, - intel_uncore_read(uncore, DEIER) & ~DE_PCU_EVENT); - intel_uncore_write(uncore, DEIIR, DE_PCU_EVENT); - intel_uncore_write(uncore, DEIMR, - intel_uncore_read(uncore, DEIMR) | DE_PCU_EVENT); /* Go back to the starting frequency */ gen5_rps_set(rps, rps->idle_freq); @@ -1276,8 +1290,9 @@ static unsigned long __ips_gfx_val(struct intel_ips *ips) { struct intel_rps *rps = container_of(ips, typeof(*rps), ips); struct intel_uncore *uncore = rps_to_uncore(rps); - unsigned long t, corr, state1, corr2, state2; + unsigned int t, state1, state2; u32 pxvid, ext_v; + u64 corr, corr2; lockdep_assert_held(&mchdev_lock); @@ -1298,11 +1313,10 @@ static unsigned long __ips_gfx_val(struct intel_ips *ips) else /* < 50 */ corr = t * 301 + 1004; - corr = corr * 150142 * state1 / 10000 - 78642; - corr /= 100000; - corr2 = corr * ips->corr; + corr = div_u64(corr * 150142 * state1, 10000) - 78642; + corr2 = div_u64(corr, 100000) * ips->corr; - state2 = corr2 * state1 / 10000; + state2 = div_u64(corr2 * state1, 10000); state2 /= 100; /* convert to mW */ __gen5_ips_update(ips); @@ -1436,8 +1450,10 @@ int intel_gpu_freq(struct intel_rps *rps, int val) return chv_gpu_freq(rps, val); else if (IS_VALLEYVIEW(i915)) return byt_gpu_freq(rps, val); - else + else if (INTEL_GEN(i915) >= 6) return val * GT_FREQUENCY_MULTIPLIER; + else + return val; } int intel_freq_opcode(struct intel_rps *rps, int val) @@ -1451,8 +1467,10 @@ int intel_freq_opcode(struct intel_rps *rps, int val) return chv_freq_opcode(rps, val); else if (IS_VALLEYVIEW(i915)) return byt_freq_opcode(rps, val); - else + else if (INTEL_GEN(i915) >= 6) return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER); + else + return val; } static void vlv_init_gpll_ref_freq(struct intel_rps *rps) @@ -1868,8 +1886,11 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) cagf = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT; else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT; - else + else if (INTEL_GEN(i915) >= 6) cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT; + else + cagf = gen5_invert_freq(rps, (rpstat & MEMSTAT_PSTATE_MASK) >> + MEMSTAT_PSTATE_SHIFT); return cagf; } @@ -1877,14 +1898,17 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) static u32 read_cagf(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); + struct intel_uncore *uncore = rps_to_uncore(rps); u32 freq; if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { vlv_punit_get(i915); freq = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); vlv_punit_put(i915); + } else if (INTEL_GEN(i915) >= 6) { + freq = intel_uncore_read(uncore, GEN6_RPSTAT1); } else { - freq = intel_uncore_read(rps_to_uncore(rps), GEN6_RPSTAT1); + freq = intel_uncore_read(uncore, MEMSTAT_ILK); } return intel_rps_get_cagf(rps, freq); @@ -1953,7 +1977,7 @@ static struct drm_i915_private *mchdev_get(void) rcu_read_lock(); i915 = rcu_dereference(ips_mchdev); - if (!kref_get_unless_zero(&i915->drm.ref)) + if (i915 && !kref_get_unless_zero(&i915->drm.ref)) i915 = NULL; rcu_read_unlock(); diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c index f1c039e1b5ad..8a72e0fe34ca 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c @@ -169,7 +169,7 @@ static void gen11_sseu_info_init(struct intel_gt *gt) u8 eu_en; u8 s_en; - if (IS_ELKHARTLAKE(gt->i915)) + if (IS_JSL_EHL(gt->i915)) intel_sseu_set_info(sseu, 1, 4, 8); else intel_sseu_set_info(sseu, 1, 8, 8); diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 4a3bde7c9f21..adc9a8ea410a 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -674,6 +674,20 @@ static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine, 0); } +static void dg1_ctx_workarounds_init(struct intel_engine_cs *engine, + struct i915_wa_list *wal) +{ + gen12_ctx_workarounds_init(engine, wal); + + /* Wa_1409044764 */ + WA_CLR_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3, + DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN); + + /* Wa_22010493298 */ + WA_SET_BIT_MASKED(HIZ_CHICKEN, + DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE); +} + static void __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, struct i915_wa_list *wal, @@ -686,7 +700,9 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, wa_init_start(wal, name, engine->name); - if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) + if (IS_DG1(i915)) + dg1_ctx_workarounds_init(engine, wal); + else if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) tgl_ctx_workarounds_init(engine, wal); else if (IS_GEN(i915, 12)) gen12_ctx_workarounds_init(engine, wal); @@ -1214,7 +1230,7 @@ icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) /* Wa_1607087056:icl,ehl,jsl */ if (IS_ICELAKE(i915) || - IS_EHL_REVID(i915, EHL_REVID_A0, EHL_REVID_A0)) { + IS_JSL_EHL_REVID(i915, EHL_REVID_A0, EHL_REVID_A0)) { wa_write_or(wal, SLICE_UNIT_LEVEL_CLKGATE, L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); @@ -1247,9 +1263,35 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void +dg1_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +{ + gen12_gt_workarounds_init(i915, wal); + + /* Wa_1607087056:dg1 */ + if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0)) + wa_write_or(wal, + SLICE_UNIT_LEVEL_CLKGATE, + L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); + + /* Wa_1409420604:dg1 */ + if (IS_DG1(i915)) + wa_write_or(wal, + SUBSLICE_UNIT_LEVEL_CLKGATE2, + CPSSUNIT_CLKGATE_DIS); + + /* Wa_1408615072:dg1 */ + /* Empirical testing shows this register is unaffected by engine reset. */ + if (IS_DG1(i915)) + wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE2, + VSUNIT_CLKGATE_DIS_TGL); +} + +static void gt_init_workarounds(struct drm_i915_private *i915, struct i915_wa_list *wal) { - if (IS_TIGERLAKE(i915)) + if (IS_DG1(i915)) + dg1_gt_workarounds_init(i915, wal); + else if (IS_TIGERLAKE(i915)) tgl_gt_workarounds_init(i915, wal); else if (IS_GEN(i915, 12)) gen12_gt_workarounds_init(i915, wal); @@ -1614,6 +1656,20 @@ static void tgl_whitelist_build(struct intel_engine_cs *engine) } } +static void dg1_whitelist_build(struct intel_engine_cs *engine) +{ + struct i915_wa_list *w = &engine->whitelist; + + tgl_whitelist_build(engine); + + /* GEN:BUG:1409280441:dg1 */ + if (IS_DG1_REVID(engine->i915, DG1_REVID_A0, DG1_REVID_A0) && + (engine->class == RENDER_CLASS || + engine->class == COPY_ENGINE_CLASS)) + whitelist_reg_ext(w, RING_ID(engine->mmio_base), + RING_FORCE_TO_NONPRIV_ACCESS_RD); +} + void intel_engine_init_whitelist(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; @@ -1621,7 +1677,9 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine) wa_init_start(w, "whitelist", engine->name); - if (IS_GEN(i915, 12)) + if (IS_DG1(i915)) + dg1_whitelist_build(engine); + else if (IS_GEN(i915, 12)) tgl_whitelist_build(engine); else if (IS_GEN(i915, 11)) icl_whitelist_build(engine); @@ -1675,15 +1733,18 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { struct drm_i915_private *i915 = engine->i915; - if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) { + if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) || + IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) { /* - * Wa_1607138336:tgl - * Wa_1607063988:tgl + * Wa_1607138336:tgl[a0],dg1[a0] + * Wa_1607063988:tgl[a0],dg1[a0] */ wa_write_or(wal, GEN9_CTX_PREEMPT_REG, GEN12_DISABLE_POSH_BUSY_FF_DOP_CG); + } + if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) { /* * Wa_1606679103:tgl * (see also Wa_1606682166:icl) @@ -1697,35 +1758,41 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) VSUNIT_CLKGATE_DIS_TGL); } - if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { - /* Wa_1606931601:tgl,rkl */ + if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* Wa_1606931601:tgl,rkl,dg1 */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); - /* Wa_1409804808:tgl,rkl */ + /* + * Wa_1407928979:tgl A* + * Wa_18011464164:tgl[B0+],dg1[B0+] + * Wa_22010931296:tgl[B0+],dg1[B0+] + * Wa_14010919138:rkl, dg1 + */ + wa_write_or(wal, GEN7_FF_THREAD_MODE, + GEN12_FF_TESSELATION_DOP_GATE_DISABLE); + } + + if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) || + IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* Wa_1409804808:tgl,rkl,dg1[a0] */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_PUSH_CONST_DEREF_HOLD_DIS); /* * Wa_1409085225:tgl - * Wa_14010229206:tgl,rkl + * Wa_14010229206:tgl,rkl,dg1[a0] */ wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH); /* - * Wa_1407928979:tgl A* - * Wa_18011464164:tgl B0+ - * Wa_22010931296:tgl B0+ - * Wa_14010919138:rkl,tgl - */ - wa_write_or(wal, GEN7_FF_THREAD_MODE, - GEN12_FF_TESSELATION_DOP_GATE_DISABLE); - - /* * Wa_1607030317:tgl * Wa_1607186500:tgl - * Wa_1607297627:tgl,rkl there are multiple entries for this - * WA in the BSpec; some indicate this is an A0-only WA, - * others indicate it applies to all steppings. + * Wa_1607297627:tgl,rkl,dg1[a0] + * + * On TGL and RKL there are multiple entries for this WA in the + * BSpec; some indicate this is an A0-only WA, others indicate + * it applies to all steppings so we trust the "all steppings." + * For DG1 this only applies to A0. */ wa_masked_en(wal, GEN6_RC_SLEEP_PSMI_CONTROL, @@ -1841,7 +1908,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN12_FF_TESSELATION_DOP_GATE_DISABLE); /* Wa_22010271021:ehl */ - if (IS_ELKHARTLAKE(i915)) + if (IS_JSL_EHL(i915)) wa_masked_en(wal, GEN9_CS_DEBUG_MODE1, FF_DOP_CLOCK_GATE_DISABLE); @@ -2033,10 +2100,12 @@ err_obj: return ERR_PTR(err); } -static const struct { +struct mcr_range { u32 start; u32 end; -} mcr_ranges_gen8[] = { +}; + +static const struct mcr_range mcr_ranges_gen8[] = { { .start = 0x5500, .end = 0x55ff }, { .start = 0x7000, .end = 0x7fff }, { .start = 0x9400, .end = 0x97ff }, @@ -2045,11 +2114,25 @@ static const struct { {}, }; +static const struct mcr_range mcr_ranges_gen12[] = { + { .start = 0x8150, .end = 0x815f }, + { .start = 0x9520, .end = 0x955f }, + { .start = 0xb100, .end = 0xb3ff }, + { .start = 0xde80, .end = 0xe8ff }, + { .start = 0x24a00, .end = 0x24a7f }, + {}, +}; + static bool mcr_range(struct drm_i915_private *i915, u32 offset) { + const struct mcr_range *mcr_ranges; int i; - if (INTEL_GEN(i915) < 8) + if (INTEL_GEN(i915) >= 12) + mcr_ranges = mcr_ranges_gen12; + else if (INTEL_GEN(i915) >= 8) + mcr_ranges = mcr_ranges_gen8; + else return false; /* @@ -2057,9 +2140,9 @@ static bool mcr_range(struct drm_i915_private *i915, u32 offset) * which only controls CPU initiated MMIO. Routing does not * work for CS access so we cannot verify them on this path. */ - for (i = 0; mcr_ranges_gen8[i].start; i++) - if (offset >= mcr_ranges_gen8[i].start && - offset <= mcr_ranges_gen8[i].end) + for (i = 0; mcr_ranges[i].start; i++) + if (offset >= mcr_ranges[i].start && + offset <= mcr_ranges[i].end) return true; return false; diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c index dfd1cfb8a7ec..2f830017c51d 100644 --- a/drivers/gpu/drm/i915/gt/mock_engine.c +++ b/drivers/gpu/drm/i915/gt/mock_engine.c @@ -245,18 +245,39 @@ static void mock_reset_rewind(struct intel_engine_cs *engine, bool stalled) GEM_BUG_ON(stalled); } +static void mark_eio(struct i915_request *rq) +{ + if (i915_request_completed(rq)) + return; + + GEM_BUG_ON(i915_request_signaled(rq)); + + i915_request_set_error_once(rq, -EIO); + i915_request_mark_complete(rq); +} + static void mock_reset_cancel(struct intel_engine_cs *engine) { - struct i915_request *request; + struct mock_engine *mock = + container_of(engine, typeof(*mock), base); + struct i915_request *rq; unsigned long flags; + del_timer_sync(&mock->hw_delay); + spin_lock_irqsave(&engine->active.lock, flags); /* Mark all submitted requests as skipped. */ - list_for_each_entry(request, &engine->active.requests, sched.link) { - i915_request_set_error_once(request, -EIO); - i915_request_mark_complete(request); + list_for_each_entry(rq, &engine->active.requests, sched.link) + mark_eio(rq); + intel_engine_signal_breadcrumbs(engine); + + /* Cancel and submit all pending requests. */ + list_for_each_entry(rq, &mock->hw_queue, mock.link) { + mark_eio(rq); + __i915_request_submit(rq); } + INIT_LIST_HEAD(&mock->hw_queue); spin_unlock_irqrestore(&engine->active.lock, flags); } diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c index e73854dd2fe0..b88aa35ad75b 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c @@ -215,16 +215,17 @@ static int __live_heartbeat_fast(struct intel_engine_cs *engine) goto err_pm; for (i = 0; i < ARRAY_SIZE(times); i++) { - /* Manufacture a tick */ do { - while (READ_ONCE(engine->heartbeat.systole)) - flush_delayed_work(&engine->heartbeat.work); + /* Manufacture a tick */ + intel_engine_park_heartbeat(engine); + GEM_BUG_ON(engine->heartbeat.systole); + engine->serial++; /* pretend we are not idle! */ + intel_engine_unpark_heartbeat(engine); - engine->serial++; /* quick, pretend we are not idle! */ flush_delayed_work(&engine->heartbeat.work); if (!delayed_work_pending(&engine->heartbeat.work)) { - pr_err("%s: heartbeat did not start\n", - engine->name); + pr_err("%s: heartbeat %d did not start\n", + engine->name, i); err = -EINVAL; goto err_pm; } diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c index 3540ba9bd459..aa5675ecb5cc 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -219,7 +219,7 @@ int live_rps_clock_interval(void *arg) struct igt_spinner spin; int err = 0; - if (!intel_rps_is_enabled(rps)) + if (!intel_rps_is_enabled(rps) || INTEL_GEN(gt->i915) < 6) return 0; if (igt_spinner_init(&spin, gt)) @@ -1028,7 +1028,7 @@ int live_rps_interrupt(void *arg) * First, let's check whether or not we are receiving interrupts. */ - if (!intel_rps_has_interrupts(rps)) + if (!intel_rps_has_interrupts(rps) || INTEL_GEN(gt->i915) < 6) return 0; intel_gt_pm_get(gt); @@ -1133,7 +1133,7 @@ int live_rps_power(void *arg) * that theory. */ - if (!intel_rps_is_enabled(rps)) + if (!intel_rps_is_enabled(rps) || INTEL_GEN(gt->i915) < 6) return 0; if (!librapl_energy_uJ()) @@ -1237,7 +1237,7 @@ int live_rps_dynamic(void *arg) * moving parts into dynamic reclocking based on load. */ - if (!intel_rps_is_enabled(rps)) + if (!intel_rps_is_enabled(rps) || INTEL_GEN(gt->i915) < 6) return 0; if (igt_spinner_init(&spin, gt)) diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c index 19c2cb166e7c..2edf2b15885f 100644 --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c @@ -17,8 +17,9 @@ #include "../selftests/i915_random.h" #include "../i915_selftest.h" -#include "../selftests/igt_flush_test.h" -#include "../selftests/mock_gem_device.h" +#include "selftests/igt_flush_test.h" +#include "selftests/lib_sw_fence.h" +#include "selftests/mock_gem_device.h" #include "selftests/mock_timeline.h" static struct page *hwsp_page(struct intel_timeline *tl) @@ -755,6 +756,378 @@ out_free: return err; } +static int emit_read_hwsp(struct i915_request *rq, + u32 seqno, u32 hwsp, + u32 *addr) +{ + const u32 gpr = i915_mmio_reg_offset(GEN8_RING_CS_GPR(rq->engine->mmio_base, 0)); + u32 *cs; + + cs = intel_ring_begin(rq, 12); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT; + *cs++ = *addr; + *cs++ = 0; + *cs++ = seqno; + *addr += 4; + + *cs++ = MI_LOAD_REGISTER_MEM_GEN8 | MI_USE_GGTT; + *cs++ = gpr; + *cs++ = hwsp; + *cs++ = 0; + + *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT; + *cs++ = gpr; + *cs++ = *addr; + *cs++ = 0; + *addr += 4; + + intel_ring_advance(rq, cs); + + return 0; +} + +struct hwsp_watcher { + struct i915_vma *vma; + struct i915_request *rq; + u32 addr; + u32 *map; +}; + +static bool cmp_lt(u32 a, u32 b) +{ + return a < b; +} + +static bool cmp_gte(u32 a, u32 b) +{ + return a >= b; +} + +static int setup_watcher(struct hwsp_watcher *w, struct intel_gt *gt) +{ + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + + obj = i915_gem_object_create_internal(gt->i915, SZ_2M); + if (IS_ERR(obj)) + return PTR_ERR(obj); + + w->map = i915_gem_object_pin_map(obj, I915_MAP_WB); + if (IS_ERR(w->map)) { + i915_gem_object_put(obj); + return PTR_ERR(w->map); + } + + vma = i915_gem_object_ggtt_pin_ww(obj, NULL, NULL, 0, 0, 0); + if (IS_ERR(vma)) { + i915_gem_object_put(obj); + return PTR_ERR(vma); + } + + w->vma = vma; + w->addr = i915_ggtt_offset(vma); + return 0; +} + +static int create_watcher(struct hwsp_watcher *w, + struct intel_engine_cs *engine, + int ringsz) +{ + struct intel_context *ce; + struct intel_timeline *tl; + + ce = intel_context_create(engine); + if (IS_ERR(ce)) + return PTR_ERR(ce); + + ce->ring = __intel_context_ring_size(ringsz); + w->rq = intel_context_create_request(ce); + intel_context_put(ce); + if (IS_ERR(w->rq)) + return PTR_ERR(w->rq); + + w->addr = i915_ggtt_offset(w->vma); + tl = w->rq->context->timeline; + + /* some light mutex juggling required; think co-routines */ + lockdep_unpin_lock(&tl->mutex, w->rq->cookie); + mutex_unlock(&tl->mutex); + + return 0; +} + +static int check_watcher(struct hwsp_watcher *w, const char *name, + bool (*op)(u32 hwsp, u32 seqno)) +{ + struct i915_request *rq = fetch_and_zero(&w->rq); + struct intel_timeline *tl = rq->context->timeline; + u32 offset, end; + int err; + + GEM_BUG_ON(w->addr - i915_ggtt_offset(w->vma) > w->vma->size); + + i915_request_get(rq); + mutex_lock(&tl->mutex); + rq->cookie = lockdep_pin_lock(&tl->mutex); + i915_request_add(rq); + + if (i915_request_wait(rq, 0, HZ) < 0) { + err = -ETIME; + goto out; + } + + err = 0; + offset = 0; + end = (w->addr - i915_ggtt_offset(w->vma)) / sizeof(*w->map); + while (offset < end) { + if (!op(w->map[offset + 1], w->map[offset])) { + pr_err("Watcher '%s' found HWSP value %x for seqno %x\n", + name, w->map[offset + 1], w->map[offset]); + err = -EINVAL; + } + + offset += 2; + } + +out: + i915_request_put(rq); + return err; +} + +static void cleanup_watcher(struct hwsp_watcher *w) +{ + if (w->rq) { + struct intel_timeline *tl = w->rq->context->timeline; + + mutex_lock(&tl->mutex); + w->rq->cookie = lockdep_pin_lock(&tl->mutex); + + i915_request_add(w->rq); + } + + i915_vma_unpin_and_release(&w->vma, I915_VMA_RELEASE_MAP); +} + +static bool retire_requests(struct intel_timeline *tl) +{ + struct i915_request *rq, *rn; + + mutex_lock(&tl->mutex); + list_for_each_entry_safe(rq, rn, &tl->requests, link) + if (!i915_request_retire(rq)) + break; + mutex_unlock(&tl->mutex); + + return !i915_active_fence_isset(&tl->last_request); +} + +static struct i915_request *wrap_timeline(struct i915_request *rq) +{ + struct intel_context *ce = rq->context; + struct intel_timeline *tl = ce->timeline; + u32 seqno = rq->fence.seqno; + + while (tl->seqno >= seqno) { /* Cause a wrap */ + i915_request_put(rq); + rq = intel_context_create_request(ce); + if (IS_ERR(rq)) + return rq; + + i915_request_get(rq); + i915_request_add(rq); + } + + i915_request_put(rq); + rq = intel_context_create_request(ce); + if (IS_ERR(rq)) + return rq; + + i915_request_get(rq); + i915_request_add(rq); + + return rq; +} + +static int live_hwsp_read(void *arg) +{ + struct intel_gt *gt = arg; + struct hwsp_watcher watcher[2] = {}; + struct intel_engine_cs *engine; + struct intel_timeline *tl; + enum intel_engine_id id; + int err = 0; + int i; + + /* + * If we take a reference to the HWSP for reading on the GPU, that + * read may be arbitrarily delayed (either by foreign fence or + * priority saturation) and a wrap can happen within 30 minutes. + * When the GPU read is finally submitted it should be correct, + * even across multiple wraps. + */ + + if (INTEL_GEN(gt->i915) < 8) /* CS convenience [SRM/LRM] */ + return 0; + + tl = intel_timeline_create(gt); + if (IS_ERR(tl)) + return PTR_ERR(tl); + + if (!tl->hwsp_cacheline) + goto out_free; + + for (i = 0; i < ARRAY_SIZE(watcher); i++) { + err = setup_watcher(&watcher[i], gt); + if (err) + goto out; + } + + for_each_engine(engine, gt, id) { + struct intel_context *ce; + unsigned long count = 0; + IGT_TIMEOUT(end_time); + + /* Create a request we can use for remote reading of the HWSP */ + err = create_watcher(&watcher[1], engine, SZ_512K); + if (err) + goto out; + + do { + struct i915_sw_fence *submit; + struct i915_request *rq; + u32 hwsp; + + submit = heap_fence_create(GFP_KERNEL); + if (!submit) { + err = -ENOMEM; + goto out; + } + + err = create_watcher(&watcher[0], engine, SZ_4K); + if (err) + goto out; + + ce = intel_context_create(engine); + if (IS_ERR(ce)) { + err = PTR_ERR(ce); + goto out; + } + + /* Skip to the end, saving 30 minutes of nops */ + tl->seqno = -10u + 2 * (count & 3); + WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno); + ce->timeline = intel_timeline_get(tl); + + rq = intel_context_create_request(ce); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + intel_context_put(ce); + goto out; + } + + err = i915_sw_fence_await_dma_fence(&rq->submit, + &watcher[0].rq->fence, 0, + GFP_KERNEL); + if (err < 0) { + i915_request_add(rq); + intel_context_put(ce); + goto out; + } + + mutex_lock(&watcher[0].rq->context->timeline->mutex); + err = intel_timeline_read_hwsp(rq, watcher[0].rq, &hwsp); + if (err == 0) + err = emit_read_hwsp(watcher[0].rq, /* before */ + rq->fence.seqno, hwsp, + &watcher[0].addr); + mutex_unlock(&watcher[0].rq->context->timeline->mutex); + if (err) { + i915_request_add(rq); + intel_context_put(ce); + goto out; + } + + mutex_lock(&watcher[1].rq->context->timeline->mutex); + err = intel_timeline_read_hwsp(rq, watcher[1].rq, &hwsp); + if (err == 0) + err = emit_read_hwsp(watcher[1].rq, /* after */ + rq->fence.seqno, hwsp, + &watcher[1].addr); + mutex_unlock(&watcher[1].rq->context->timeline->mutex); + if (err) { + i915_request_add(rq); + intel_context_put(ce); + goto out; + } + + i915_request_get(rq); + i915_request_add(rq); + + rq = wrap_timeline(rq); + intel_context_put(ce); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto out; + } + + err = i915_sw_fence_await_dma_fence(&watcher[1].rq->submit, + &rq->fence, 0, + GFP_KERNEL); + if (err < 0) { + i915_request_put(rq); + goto out; + } + + err = check_watcher(&watcher[0], "before", cmp_lt); + i915_sw_fence_commit(submit); + heap_fence_put(submit); + if (err) { + i915_request_put(rq); + goto out; + } + count++; + + if (8 * watcher[1].rq->ring->emit > + 3 * watcher[1].rq->ring->size) { + i915_request_put(rq); + break; + } + + /* Flush the timeline before manually wrapping again */ + if (i915_request_wait(rq, + I915_WAIT_INTERRUPTIBLE, + HZ) < 0) { + err = -ETIME; + i915_request_put(rq); + goto out; + } + + retire_requests(tl); + i915_request_put(rq); + } while (!__igt_timeout(end_time, NULL)); + WRITE_ONCE(*(u32 *)tl->hwsp_seqno, 0xdeadbeef); + + pr_info("%s: simulated %lu wraps\n", engine->name, count); + err = check_watcher(&watcher[1], "after", cmp_gte); + if (err) + goto out; + } + +out: + for (i = 0; i < ARRAY_SIZE(watcher); i++) + cleanup_watcher(&watcher[i]); + + if (igt_flush_test(gt->i915)) + err = -EIO; + +out_free: + intel_timeline_put(tl); + return err; +} + static int live_hwsp_rollover_kernel(void *arg) { struct intel_gt *gt = arg; @@ -998,6 +1371,7 @@ int intel_timeline_live_selftests(struct drm_i915_private *i915) SUBTEST(live_hwsp_engine), SUBTEST(live_hwsp_alternate), SUBTEST(live_hwsp_wrap), + SUBTEST(live_hwsp_read), SUBTEST(live_hwsp_rollover_kernel), SUBTEST(live_hwsp_rollover_user), }; diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c index 535cc1169e54..967031056202 100644 --- a/drivers/gpu/drm/i915/gt/sysfs_engines.c +++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c @@ -79,14 +79,12 @@ static ssize_t repr_trim(char *buf, ssize_t len) static ssize_t __caps_show(struct intel_engine_cs *engine, - u32 caps, char *buf, bool show_unknown) + unsigned long caps, char *buf, bool show_unknown) { const char * const *repr; int count, n; ssize_t len; - BUILD_BUG_ON(!typecheck(typeof(caps), engine->uabi_capabilities)); - switch (engine->class) { case VIDEO_DECODE_CLASS: repr = vcs_caps; @@ -103,12 +101,10 @@ __caps_show(struct intel_engine_cs *engine, count = 0; break; } - GEM_BUG_ON(count > BITS_PER_TYPE(typeof(caps))); + GEM_BUG_ON(count > BITS_PER_LONG); len = 0; - for_each_set_bit(n, - (unsigned long *)&caps, - show_unknown ? BITS_PER_TYPE(typeof(caps)) : count) { + for_each_set_bit(n, &caps, show_unknown ? BITS_PER_LONG : count) { if (n >= count || !repr[n]) { if (GEM_WARN_ON(show_unknown)) len += snprintf(buf + len, PAGE_SIZE - len, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 942c7c187adb..2a343a977987 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -213,23 +213,6 @@ static u32 guc_ctl_feature_flags(struct intel_guc *guc) return flags; } -static u32 guc_ctl_ctxinfo_flags(struct intel_guc *guc) -{ - u32 flags = 0; - - if (intel_guc_submission_is_used(guc)) { - u32 ctxnum, base; - - base = intel_guc_ggtt_offset(guc, guc->stage_desc_pool); - ctxnum = GUC_MAX_STAGE_DESCRIPTORS / 16; - - base >>= PAGE_SHIFT; - flags |= (base << GUC_CTL_BASE_ADDR_SHIFT) | - (ctxnum << GUC_CTL_CTXNUM_IN16_SHIFT); - } - return flags; -} - static u32 guc_ctl_log_params_flags(struct intel_guc *guc) { u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT; @@ -291,7 +274,6 @@ static void guc_init_params(struct intel_guc *guc) BUILD_BUG_ON(sizeof(guc->params) != GUC_CTL_MAX_DWORDS * sizeof(u32)); - params[GUC_CTL_CTXINFO] = guc_ctl_ctxinfo_flags(guc); params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc); params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc); params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); @@ -312,18 +294,18 @@ void intel_guc_write_params(struct intel_guc *guc) int i; /* - * All SOFT_SCRATCH registers are in FORCEWAKE_BLITTER domain and + * All SOFT_SCRATCH registers are in FORCEWAKE_GT domain and * they are power context saved so it's ok to release forcewake * when we are done here and take it again at xfer time. */ - intel_uncore_forcewake_get(uncore, FORCEWAKE_BLITTER); + intel_uncore_forcewake_get(uncore, FORCEWAKE_GT); intel_uncore_write(uncore, SOFT_SCRATCH(0), 0); for (i = 0; i < GUC_CTL_MAX_DWORDS; i++) intel_uncore_write(uncore, SOFT_SCRATCH(1 + i), guc->params[i]); - intel_uncore_forcewake_put(uncore, FORCEWAKE_BLITTER); + intel_uncore_forcewake_put(uncore, FORCEWAKE_GT); } int intel_guc_init(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index d44061033f23..5212ff844292 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -10,11 +10,52 @@ /* * The Additional Data Struct (ADS) has pointers for different buffers used by - * the GuC. One single gem object contains the ADS struct itself (guc_ads), the - * scheduling policies (guc_policies), a structure describing a collection of - * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save - * its internal state for sleep. + * the GuC. One single gem object contains the ADS struct itself (guc_ads) and + * all the extra buffers indirectly linked via the ADS struct's entries. + * + * Layout of the ADS blob allocated for the GuC: + * + * +---------------------------------------+ <== base + * | guc_ads | + * +---------------------------------------+ + * | guc_policies | + * +---------------------------------------+ + * | guc_gt_system_info | + * +---------------------------------------+ + * | guc_clients_info | + * +---------------------------------------+ + * | guc_ct_pool_entry[size] | + * +---------------------------------------+ + * | padding | + * +---------------------------------------+ <== 4K aligned + * | private data | + * +---------------------------------------+ + * | padding | + * +---------------------------------------+ <== 4K aligned */ +struct __guc_ads_blob { + struct guc_ads ads; + struct guc_policies policies; + struct guc_gt_system_info system_info; + struct guc_clients_info clients_info; + struct guc_ct_pool_entry ct_pool[GUC_CT_POOL_SIZE]; +} __packed; + +static u32 guc_ads_private_data_size(struct intel_guc *guc) +{ + return PAGE_ALIGN(guc->fw.private_data_size); +} + +static u32 guc_ads_private_data_offset(struct intel_guc *guc) +{ + return PAGE_ALIGN(sizeof(struct __guc_ads_blob)); +} + +static u32 guc_ads_blob_size(struct intel_guc *guc) +{ + return guc_ads_private_data_offset(guc) + + guc_ads_private_data_size(guc); +} static void guc_policy_init(struct guc_policy *policy) { @@ -48,26 +89,37 @@ static void guc_ct_pool_entries_init(struct guc_ct_pool_entry *pool, u32 num) memset(pool, 0, num * sizeof(*pool)); } +static void guc_mapping_table_init(struct intel_gt *gt, + struct guc_gt_system_info *system_info) +{ + unsigned int i, j; + struct intel_engine_cs *engine; + enum intel_engine_id id; + + /* Table must be set to invalid values for entries not used */ + for (i = 0; i < GUC_MAX_ENGINE_CLASSES; ++i) + for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; ++j) + system_info->mapping_table[i][j] = + GUC_MAX_INSTANCES_PER_CLASS; + + for_each_engine(engine, gt, id) { + u8 guc_class = engine->class; + + system_info->mapping_table[guc_class][engine->instance] = + engine->instance; + } +} + /* * The first 80 dwords of the register state context, containing the * execlists and ppgtt registers. */ #define LR_HW_CONTEXT_SIZE (80 * sizeof(u32)) -/* The ads obj includes the struct itself and buffers passed to GuC */ -struct __guc_ads_blob { - struct guc_ads ads; - struct guc_policies policies; - struct guc_mmio_reg_state reg_state; - struct guc_gt_system_info system_info; - struct guc_clients_info clients_info; - struct guc_ct_pool_entry ct_pool[GUC_CT_POOL_SIZE]; - u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE]; -} __packed; - static void __guc_ads_init(struct intel_guc *guc) { struct intel_gt *gt = guc_to_gt(guc); + struct drm_i915_private *i915 = gt->i915; struct __guc_ads_blob *blob = guc->ads_blob; const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE; u32 base; @@ -99,13 +151,25 @@ static void __guc_ads_init(struct intel_guc *guc) } /* System info */ - blob->system_info.slice_enabled = hweight8(gt->info.sseu.slice_mask); - blob->system_info.rcs_enabled = 1; - blob->system_info.bcs_enabled = 1; + blob->system_info.engine_enabled_masks[RENDER_CLASS] = 1; + blob->system_info.engine_enabled_masks[COPY_ENGINE_CLASS] = 1; + blob->system_info.engine_enabled_masks[VIDEO_DECODE_CLASS] = VDBOX_MASK(gt); + blob->system_info.engine_enabled_masks[VIDEO_ENHANCEMENT_CLASS] = VEBOX_MASK(gt); + + blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED] = + hweight8(gt->info.sseu.slice_mask); + blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK] = + gt->info.vdbox_sfc_access; + + if (INTEL_GEN(i915) >= 12 && !IS_DGFX(i915)) { + u32 distdbreg = intel_uncore_read(gt->uncore, + GEN12_DIST_DBS_POPULATED); + blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI] = + ((distdbreg >> GEN12_DOORBELLS_PER_SQIDI_SHIFT) & + GEN12_DOORBELLS_PER_SQIDI) + 1; + } - blob->system_info.vdbox_enable_mask = VDBOX_MASK(gt); - blob->system_info.vebox_enable_mask = VEBOX_MASK(gt); - blob->system_info.vdbox_sfc_support_mask = gt->info.vdbox_sfc_access; + guc_mapping_table_init(guc_to_gt(guc), &blob->system_info); base = intel_guc_ggtt_offset(guc, guc->ads_vma); @@ -118,11 +182,12 @@ static void __guc_ads_init(struct intel_guc *guc) /* ADS */ blob->ads.scheduler_policies = base + ptr_offset(blob, policies); - blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer); - blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state); blob->ads.gt_system_info = base + ptr_offset(blob, system_info); blob->ads.clients_info = base + ptr_offset(blob, clients_info); + /* Private Data */ + blob->ads.private_data = base + guc_ads_private_data_offset(guc); + i915_gem_object_flush_map(guc->ads_vma->obj); } @@ -135,14 +200,15 @@ static void __guc_ads_init(struct intel_guc *guc) */ int intel_guc_ads_create(struct intel_guc *guc) { - const u32 size = PAGE_ALIGN(sizeof(struct __guc_ads_blob)); + u32 size; int ret; GEM_BUG_ON(guc->ads_vma); + size = guc_ads_blob_size(guc); + ret = intel_guc_allocate_and_map_vma(guc, size, &guc->ads_vma, (void **)&guc->ads_blob); - if (ret) return ret; @@ -154,6 +220,19 @@ int intel_guc_ads_create(struct intel_guc *guc) void intel_guc_ads_destroy(struct intel_guc *guc) { i915_vma_unpin_and_release(&guc->ads_vma, I915_VMA_RELEASE_MAP); + guc->ads_blob = NULL; +} + +static void guc_ads_private_data_reset(struct intel_guc *guc) +{ + u32 size; + + size = guc_ads_private_data_size(guc); + if (!size) + return; + + memset((void *)guc->ads_blob + guc_ads_private_data_offset(guc), 0, + size); } /** @@ -168,5 +247,8 @@ void intel_guc_ads_reset(struct intel_guc *guc) { if (!guc->ads_vma) return; + __guc_ads_init(guc); + + guc_ads_private_data_reset(guc); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 11742fca0e9e..fa9e048cc65f 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -210,6 +210,7 @@ void intel_guc_ct_fini(struct intel_guc_ct *ct) GEM_BUG_ON(ct->enabled); i915_vma_unpin_and_release(&ct->vma, I915_VMA_RELEASE_MAP); + memset(ct, 0, sizeof(*ct)); } /** diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c index d4a87f4c9421..f9d0907ea1a5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -76,6 +76,7 @@ static inline bool guc_ready(struct intel_uncore *uncore, u32 *status) static int guc_wait_ucode(struct intel_uncore *uncore) { + struct drm_device *drm = &uncore->i915->drm; u32 status; int ret; @@ -90,15 +91,27 @@ static int guc_wait_ucode(struct intel_uncore *uncore) ret = wait_for(guc_ready(uncore, &status), 100); DRM_DEBUG_DRIVER("GuC status %#x\n", status); - if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) { - DRM_ERROR("GuC firmware signature verification failed\n"); - ret = -ENOEXEC; - } - - if ((status & GS_UKERNEL_MASK) == GS_UKERNEL_EXCEPTION) { - DRM_ERROR("GuC firmware exception. EIP: %#x\n", - intel_uncore_read(uncore, SOFT_SCRATCH(13))); - ret = -ENXIO; + if (ret) { + drm_err(drm, "GuC load failed: status = 0x%08X\n", status); + drm_err(drm, "GuC load failed: status: Reset = %d, " + "BootROM = 0x%02X, UKernel = 0x%02X, " + "MIA = 0x%02X, Auth = 0x%02X\n", + REG_FIELD_GET(GS_MIA_IN_RESET, status), + REG_FIELD_GET(GS_BOOTROM_MASK, status), + REG_FIELD_GET(GS_UKERNEL_MASK, status), + REG_FIELD_GET(GS_MIA_MASK, status), + REG_FIELD_GET(GS_AUTH_STATUS_MASK, status)); + + if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) { + drm_err(drm, "GuC firmware signature verification failed\n"); + ret = -ENOEXEC; + } + + if ((status & GS_UKERNEL_MASK) == GS_UKERNEL_EXCEPTION) { + drm_err(drm, "GuC firmware exception. EIP: %#x\n", + intel_uncore_read(uncore, SOFT_SCRATCH(13))); + ret = -ENXIO; + } } return ret; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index a6b733c146c9..79c560d9c0b6 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -26,8 +26,8 @@ #define GUC_VIDEO_ENGINE2 4 #define GUC_MAX_ENGINES_NUM (GUC_VIDEO_ENGINE2 + 1) -#define GUC_MAX_ENGINE_CLASSES 5 -#define GUC_MAX_INSTANCES_PER_CLASS 16 +#define GUC_MAX_ENGINE_CLASSES 16 +#define GUC_MAX_INSTANCES_PER_CLASS 32 #define GUC_DOORBELL_INVALID 256 @@ -62,12 +62,7 @@ #define GUC_STAGE_DESC_ATTR_PCH BIT(6) #define GUC_STAGE_DESC_ATTR_TERMINATED BIT(7) -/* New GuC control data */ -#define GUC_CTL_CTXINFO 0 -#define GUC_CTL_CTXNUM_IN16_SHIFT 0 -#define GUC_CTL_BASE_ADDR_SHIFT 12 - -#define GUC_CTL_LOG_PARAMS 1 +#define GUC_CTL_LOG_PARAMS 0 #define GUC_LOG_VALID (1 << 0) #define GUC_LOG_NOTIFY_ON_HALF_FULL (1 << 1) #define GUC_LOG_ALLOC_IN_MEGABYTE (1 << 3) @@ -79,11 +74,11 @@ #define GUC_LOG_ISR_MASK (0x7 << GUC_LOG_ISR_SHIFT) #define GUC_LOG_BUF_ADDR_SHIFT 12 -#define GUC_CTL_WA 2 -#define GUC_CTL_FEATURE 3 +#define GUC_CTL_WA 1 +#define GUC_CTL_FEATURE 2 #define GUC_CTL_DISABLE_SCHEDULER (1 << 14) -#define GUC_CTL_DEBUG 4 +#define GUC_CTL_DEBUG 3 #define GUC_LOG_VERBOSITY_SHIFT 0 #define GUC_LOG_VERBOSITY_LOW (0 << GUC_LOG_VERBOSITY_SHIFT) #define GUC_LOG_VERBOSITY_MED (1 << GUC_LOG_VERBOSITY_SHIFT) @@ -97,12 +92,37 @@ #define GUC_LOG_DISABLED (1 << 6) #define GUC_PROFILE_ENABLED (1 << 7) -#define GUC_CTL_ADS 5 +#define GUC_CTL_ADS 4 #define GUC_ADS_ADDR_SHIFT 1 #define GUC_ADS_ADDR_MASK (0xFFFFF << GUC_ADS_ADDR_SHIFT) #define GUC_CTL_MAX_DWORDS (SOFT_SCRATCH_COUNT - 2) /* [1..14] */ +/* Generic GT SysInfo data types */ +#define GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED 0 +#define GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK 1 +#define GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI 2 +#define GUC_GENERIC_GT_SYSINFO_MAX 16 + +/* + * The class goes in bits [0..2] of the GuC ID, the instance in bits [3..6]. + * Bit 7 can be used for operations that apply to all engine classes&instances. + */ +#define GUC_ENGINE_CLASS_SHIFT 0 +#define GUC_ENGINE_CLASS_MASK (0x7 << GUC_ENGINE_CLASS_SHIFT) +#define GUC_ENGINE_INSTANCE_SHIFT 3 +#define GUC_ENGINE_INSTANCE_MASK (0xf << GUC_ENGINE_INSTANCE_SHIFT) +#define GUC_ENGINE_ALL_INSTANCES BIT(7) + +#define MAKE_GUC_ID(class, instance) \ + (((class) << GUC_ENGINE_CLASS_SHIFT) | \ + ((instance) << GUC_ENGINE_INSTANCE_SHIFT)) + +#define GUC_ID_TO_ENGINE_CLASS(guc_id) \ + (((guc_id) & GUC_ENGINE_CLASS_MASK) >> GUC_ENGINE_CLASS_SHIFT) +#define GUC_ID_TO_ENGINE_INSTANCE(guc_id) \ + (((guc_id) & GUC_ENGINE_INSTANCE_MASK) >> GUC_ENGINE_INSTANCE_SHIFT) + /* Work item for submitting workloads into work queue of GuC. */ struct guc_wq_item { u32 header; @@ -336,11 +356,6 @@ struct guc_policies { } __packed; /* GuC MMIO reg state struct */ - - -#define GUC_REGSET_MAX_REGISTERS 64 -#define GUC_S3_SAVE_SPACE_PAGES 10 - struct guc_mmio_reg { u32 offset; u32 value; @@ -348,28 +363,18 @@ struct guc_mmio_reg { #define GUC_REGSET_MASKED (1 << 0) } __packed; -struct guc_mmio_regset { - struct guc_mmio_reg registers[GUC_REGSET_MAX_REGISTERS]; - u32 values_valid; - u32 number_of_registers; -} __packed; - /* GuC register sets */ -struct guc_mmio_reg_state { - struct guc_mmio_regset engine_reg[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS]; - u32 reserved[98]; +struct guc_mmio_reg_set { + u32 address; + u16 count; + u16 reserved; } __packed; /* HW info */ struct guc_gt_system_info { - u32 slice_enabled; - u32 rcs_enabled; - u32 reserved0; - u32 bcs_enabled; - u32 vdbox_enable_mask; - u32 vdbox_sfc_support_mask; - u32 vebox_enable_mask; - u32 reserved[9]; + u8 mapping_table[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS]; + u32 engine_enabled_masks[GUC_MAX_ENGINE_CLASSES]; + u32 generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_MAX]; } __packed; /* Clients info */ @@ -390,15 +395,16 @@ struct guc_clients_info { /* GuC Additional Data Struct */ struct guc_ads { - u32 reg_state_addr; - u32 reg_state_buffer; + struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS]; + u32 reserved0; u32 scheduler_policies; u32 gt_system_info; u32 clients_info; u32 control_data; u32 golden_context_lrca[GUC_MAX_ENGINE_CLASSES]; u32 eng_state_size[GUC_MAX_ENGINE_CLASSES]; - u32 reserved[16]; + u32 private_data; + u32 reserved[15]; } __packed; /* GuC logging structures */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h index 1949346e714e..b37fc2ffaef2 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h @@ -118,6 +118,11 @@ struct guc_doorbell_info { #define GEN8_DRB_VALID (1<<0) #define GEN8_DRBREGU(x) _MMIO(0x1000 + (x) * 8 + 4) +#define GEN12_DIST_DBS_POPULATED _MMIO(0xd08) +#define GEN12_DOORBELLS_PER_SQIDI_SHIFT 16 +#define GEN12_DOORBELLS_PER_SQIDI (0xff) +#define GEN12_SQIDIS_DOORBELL_EXIST (0xffff) + #define DE_GUCRMR _MMIO(0x44054) #define GUC_BCS_RCS_IER _MMIO(0xC550) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index d6f55f70889d..4e6070e95fe9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -231,13 +231,15 @@ static int guc_enable_communication(struct intel_guc *guc) intel_guc_ct_event_handler(&guc->ct); spin_unlock_irq(&i915->irq_lock); - DRM_INFO("GuC communication enabled\n"); + drm_dbg(&i915->drm, "GuC communication enabled\n"); return 0; } static void guc_disable_communication(struct intel_guc *guc) { + struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + /* * Events generated during or after CT disable are logged by guc in * via mmio. Make sure the register is clear before disabling CT since @@ -257,7 +259,7 @@ static void guc_disable_communication(struct intel_guc *guc) */ guc_get_mmio_msg(guc); - DRM_INFO("GuC communication disabled\n"); + drm_dbg(&i915->drm, "GuC communication disabled\n"); } static void __uc_fetch_firmwares(struct intel_uc *uc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 80e8b6c3bc8c..180c23e2e25e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -44,23 +44,20 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, * List of required GuC and HuC binaries per-platform. * Must be ordered based on platform + revid, from newer to older. * - * TGL 35.2 is interface-compatible with 33.0 for previous Gens. The deltas - * between 33.0 and 35.2 are only related to new additions to support new Gen12 - * features. - * * Note that RKL uses the same firmware as TGL. */ #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \ - fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \ - fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \ - fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl, 9, 0, 0)) \ - fw_def(ICELAKE, 0, guc_def(icl, 33, 0, 0), huc_def(icl, 9, 0, 0)) \ - fw_def(COMETLAKE, 5, guc_def(cml, 33, 0, 0), huc_def(cml, 4, 0, 0)) \ - fw_def(COFFEELAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) \ - fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 4, 0, 0)) \ - fw_def(KABYLAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) \ - fw_def(BROXTON, 0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 2, 0, 0)) \ - fw_def(SKYLAKE, 0, guc_def(skl, 33, 0, 0), huc_def(skl, 2, 0, 0)) + fw_def(ROCKETLAKE, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \ + fw_def(TIGERLAKE, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \ + fw_def(JASPERLAKE, 0, guc_def(ehl, 49, 0, 1), huc_def(ehl, 9, 0, 0)) \ + fw_def(ELKHARTLAKE, 0, guc_def(ehl, 49, 0, 1), huc_def(ehl, 9, 0, 0)) \ + fw_def(ICELAKE, 0, guc_def(icl, 49, 0, 1), huc_def(icl, 9, 0, 0)) \ + fw_def(COMETLAKE, 5, guc_def(cml, 49, 0, 1), huc_def(cml, 4, 0, 0)) \ + fw_def(COFFEELAKE, 0, guc_def(kbl, 49, 0, 1), huc_def(kbl, 4, 0, 0)) \ + fw_def(GEMINILAKE, 0, guc_def(glk, 49, 0, 1), huc_def(glk, 4, 0, 0)) \ + fw_def(KABYLAKE, 0, guc_def(kbl, 49, 0, 1), huc_def(kbl, 4, 0, 0)) \ + fw_def(BROXTON, 0, guc_def(bxt, 49, 0, 1), huc_def(bxt, 2, 0, 0)) \ + fw_def(SKYLAKE, 0, guc_def(skl, 49, 0, 1), huc_def(skl, 2, 0, 0)) #define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_) \ "i915/" \ @@ -371,6 +368,9 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) } } + if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) + uc_fw->private_data_size = css->private_data_size; + obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size); if (IS_ERR(obj)) { err = PTR_ERR(obj); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h index 23d3a423ac0f..99bb1fe1af66 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h @@ -88,6 +88,8 @@ struct intel_uc_fw { u32 rsa_size; u32 ucode_size; + + u32 private_data_size; }; #ifdef CONFIG_DRM_I915_DEBUG_GUC diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h index 029214cdedd5..e41ffc7a7fbc 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h @@ -69,7 +69,11 @@ struct uc_css_header { #define CSS_SW_VERSION_UC_MAJOR (0xFF << 16) #define CSS_SW_VERSION_UC_MINOR (0xFF << 8) #define CSS_SW_VERSION_UC_PATCH (0xFF << 0) - u32 reserved[14]; + u32 reserved0[13]; + union { + u32 private_data_size; /* only applies to GuC */ + u32 reserved1; + }; u32 header_info; } __packed; static_assert(sizeof(struct uc_css_header) == 128); diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index d7898e87791f..a15f87539657 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -173,23 +173,164 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) int pipe; if (IS_BROXTON(dev_priv)) { - vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= ~(BXT_DE_PORT_HP_DDIA | - BXT_DE_PORT_HP_DDIB | - BXT_DE_PORT_HP_DDIC); + enum transcoder trans; + enum port port; + + /* Clear PIPE, DDI, PHY, HPD before setting new */ + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= + ~(GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) | + GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) | + GEN8_DE_PORT_HOTPLUG(HPD_PORT_C)); + + for_each_pipe(dev_priv, pipe) { + vgpu_vreg_t(vgpu, PIPECONF(pipe)) &= + ~(PIPECONF_ENABLE | I965_PIPECONF_ACTIVE); + vgpu_vreg_t(vgpu, DSPCNTR(pipe)) &= ~DISPLAY_PLANE_ENABLE; + vgpu_vreg_t(vgpu, SPRCTL(pipe)) &= ~SPRITE_ENABLE; + vgpu_vreg_t(vgpu, CURCNTR(pipe)) &= ~MCURSOR_MODE; + vgpu_vreg_t(vgpu, CURCNTR(pipe)) |= MCURSOR_MODE_DISABLE; + } + + for (trans = TRANSCODER_A; trans <= TRANSCODER_EDP; trans++) { + vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(trans)) &= + ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK | + TRANS_DDI_PORT_MASK | TRANS_DDI_FUNC_ENABLE); + } + vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &= + ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK | + TRANS_DDI_PORT_MASK); + + for (port = PORT_A; port <= PORT_C; port++) { + vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) &= + ~BXT_PHY_LANE_ENABLED; + vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) |= + (BXT_PHY_CMNLANE_POWERDOWN_ACK | + BXT_PHY_LANE_POWERDOWN_ACK); + + vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(port)) &= + ~(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE | + PORT_PLL_REF_SEL | PORT_PLL_LOCK | + PORT_PLL_ENABLE); + + vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) &= + ~(DDI_INIT_DISPLAY_DETECTED | + DDI_BUF_CTL_ENABLE); + vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) |= DDI_BUF_IS_IDLE; + } + + vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= ~(BIT(0) | BIT(1)); + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &= + ~PHY_POWER_GOOD; + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &= + ~PHY_POWER_GOOD; + vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= ~BIT(30); + vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= ~BIT(30); + + vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIB_DETECTED; + vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIC_DETECTED; + + /* + * Only 1 PIPE enabled in current vGPU display and PIPE_A is + * tied to TRANSCODER_A in HW, so it's safe to assume PIPE_A, + * TRANSCODER_A can be enabled. PORT_x depends on the input of + * setup_virtual_dp_monitor. + */ + vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE; + vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= I965_PIPECONF_ACTIVE; + + /* + * Golden M/N are calculated based on: + * 24 bpp, 4 lanes, 154000 pixel clk (from virtual EDID), + * DP link clk 1620 MHz and non-constant_n. + * TODO: calculate DP link symbol clk and stream clk m/n. + */ + vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) = 63 << TU_SIZE_SHIFT; + vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) |= 0x5b425e; + vgpu_vreg_t(vgpu, PIPE_DATA_N1(TRANSCODER_A)) = 0x800000; + vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A)) = 0x3cd6e; + vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)) = 0x80000; + /* Enable per-DDI/PORT vreg */ if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) { + vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(1); + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) |= + PHY_POWER_GOOD; + vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) |= + BIT(30); + vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |= + BXT_PHY_LANE_ENABLED; + vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &= + ~(BXT_PHY_CMNLANE_POWERDOWN_ACK | + BXT_PHY_LANE_POWERDOWN_ACK); + vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_A)) |= + (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE | + PORT_PLL_REF_SEL | PORT_PLL_LOCK | + PORT_PLL_ENABLE); + vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) |= + (DDI_BUF_CTL_ENABLE | DDI_INIT_DISPLAY_DETECTED); + vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) &= + ~DDI_BUF_IS_IDLE; + vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)) |= + (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST | + TRANS_DDI_FUNC_ENABLE); vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= - BXT_DE_PORT_HP_DDIA; + GEN8_DE_PORT_HOTPLUG(HPD_PORT_A); } if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) { + vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIB_DETECTED; + vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0); + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |= + PHY_POWER_GOOD; + vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |= + BIT(30); + vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |= + BXT_PHY_LANE_ENABLED; + vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &= + ~(BXT_PHY_CMNLANE_POWERDOWN_ACK | + BXT_PHY_LANE_POWERDOWN_ACK); + vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_B)) |= + (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE | + PORT_PLL_REF_SEL | PORT_PLL_LOCK | + PORT_PLL_ENABLE); + vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) |= + DDI_BUF_CTL_ENABLE; + vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) &= + ~DDI_BUF_IS_IDLE; + vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |= + (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST | + (PORT_B << TRANS_DDI_PORT_SHIFT) | + TRANS_DDI_FUNC_ENABLE); vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= - BXT_DE_PORT_HP_DDIB; + GEN8_DE_PORT_HOTPLUG(HPD_PORT_B); } if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) { + vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED; + vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0); + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |= + PHY_POWER_GOOD; + vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |= + BIT(30); + vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |= + BXT_PHY_LANE_ENABLED; + vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &= + ~(BXT_PHY_CMNLANE_POWERDOWN_ACK | + BXT_PHY_LANE_POWERDOWN_ACK); + vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_C)) |= + (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE | + PORT_PLL_REF_SEL | PORT_PLL_LOCK | + PORT_PLL_ENABLE); + vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) |= + DDI_BUF_CTL_ENABLE; + vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) &= + ~DDI_BUF_IS_IDLE; + vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |= + (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST | + (PORT_B << TRANS_DDI_PORT_SHIFT) | + TRANS_DDI_FUNC_ENABLE); vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= - BXT_DE_PORT_HP_DDIC; + GEN8_DE_PORT_HOTPLUG(HPD_PORT_C); } return; @@ -327,7 +468,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) { if (IS_BROADWELL(dev_priv)) vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= - GEN8_PORT_DP_A_HOTPLUG; + GEN8_DE_PORT_HOTPLUG(HPD_PORT_A); else vgpu_vreg_t(vgpu, SDEISR) |= SDE_PORTA_HOTPLUG_SPT; @@ -519,6 +660,45 @@ void intel_vgpu_emulate_hotplug(struct intel_vgpu *vgpu, bool connected) vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |= PORTD_HOTPLUG_STATUS_MASK; intel_vgpu_trigger_virtual_event(vgpu, DP_D_HOTPLUG); + } else if (IS_BROXTON(i915)) { + if (connected) { + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) { + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= + GEN8_DE_PORT_HOTPLUG(HPD_PORT_A); + } + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) { + vgpu_vreg_t(vgpu, SFUSE_STRAP) |= + SFUSE_STRAP_DDIB_DETECTED; + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= + GEN8_DE_PORT_HOTPLUG(HPD_PORT_B); + } + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) { + vgpu_vreg_t(vgpu, SFUSE_STRAP) |= + SFUSE_STRAP_DDIC_DETECTED; + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= + GEN8_DE_PORT_HOTPLUG(HPD_PORT_C); + } + } else { + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) { + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= + ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_A); + } + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) { + vgpu_vreg_t(vgpu, SFUSE_STRAP) &= + ~SFUSE_STRAP_DDIB_DETECTED; + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= + ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_B); + } + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) { + vgpu_vreg_t(vgpu, SFUSE_STRAP) &= + ~SFUSE_STRAP_DDIC_DETECTED; + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= + ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_C); + } + } + vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |= + PORTB_HOTPLUG_STATUS_MASK; + intel_vgpu_trigger_virtual_event(vgpu, DP_B_HOTPLUG); } } diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index a3a4305eda01..897c007ea96a 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -636,9 +636,18 @@ static void ggtt_set_host_entry(struct intel_vgpu_mm *mm, struct intel_gvt_gtt_entry *entry, unsigned long index) { struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops; + unsigned long offset = index; GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT); + if (vgpu_gmadr_is_aperture(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) { + offset -= (vgpu_aperture_gmadr_base(mm->vgpu) >> PAGE_SHIFT); + mm->ggtt_mm.host_ggtt_aperture[offset] = entry->val64; + } else if (vgpu_gmadr_is_hidden(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) { + offset -= (vgpu_hidden_gmadr_base(mm->vgpu) >> PAGE_SHIFT); + mm->ggtt_mm.host_ggtt_hidden[offset] = entry->val64; + } + pte_ops->set_entry(NULL, entry, index, false, 0, mm->vgpu); } @@ -1944,6 +1953,21 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu) return ERR_PTR(-ENOMEM); } + mm->ggtt_mm.host_ggtt_aperture = vzalloc((vgpu_aperture_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64)); + if (!mm->ggtt_mm.host_ggtt_aperture) { + vfree(mm->ggtt_mm.virtual_ggtt); + vgpu_free_mm(mm); + return ERR_PTR(-ENOMEM); + } + + mm->ggtt_mm.host_ggtt_hidden = vzalloc((vgpu_hidden_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64)); + if (!mm->ggtt_mm.host_ggtt_hidden) { + vfree(mm->ggtt_mm.host_ggtt_aperture); + vfree(mm->ggtt_mm.virtual_ggtt); + vgpu_free_mm(mm); + return ERR_PTR(-ENOMEM); + } + return mm; } @@ -1971,6 +1995,8 @@ void _intel_vgpu_mm_release(struct kref *mm_ref) invalidate_ppgtt_mm(mm); } else { vfree(mm->ggtt_mm.virtual_ggtt); + vfree(mm->ggtt_mm.host_ggtt_aperture); + vfree(mm->ggtt_mm.host_ggtt_hidden); } vgpu_free_mm(mm); @@ -2852,3 +2878,41 @@ void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu) intel_vgpu_destroy_all_ppgtt_mm(vgpu); intel_vgpu_reset_ggtt(vgpu, true); } + +/** + * intel_gvt_restore_ggtt - restore all vGPU's ggtt entries + * @gvt: intel gvt device + * + * This function is called at driver resume stage to restore + * GGTT entries of every vGPU. + * + */ +void intel_gvt_restore_ggtt(struct intel_gvt *gvt) +{ + struct intel_vgpu *vgpu; + struct intel_vgpu_mm *mm; + int id; + gen8_pte_t pte; + u32 idx, num_low, num_hi, offset; + + /* Restore dirty host ggtt for all vGPUs */ + idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) { + mm = vgpu->gtt.ggtt_mm; + + num_low = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT; + offset = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT; + for (idx = 0; idx < num_low; idx++) { + pte = mm->ggtt_mm.host_ggtt_aperture[idx]; + if (pte & _PAGE_PRESENT) + write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte); + } + + num_hi = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT; + offset = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT; + for (idx = 0; idx < num_hi; idx++) { + pte = mm->ggtt_mm.host_ggtt_hidden[idx]; + if (pte & _PAGE_PRESENT) + write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte); + } + } +} diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index 52d0d88abd86..b0e173f2d990 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -164,6 +164,9 @@ struct intel_vgpu_mm { } ppgtt_mm; struct { void *virtual_ggtt; + /* Save/restore for PM */ + u64 *host_ggtt_aperture; + u64 *host_ggtt_hidden; struct list_head partial_pte_list; } ggtt_mm; }; @@ -280,5 +283,6 @@ int intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, void *p_data, unsigned int bytes); void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu); +void intel_gvt_restore_ggtt(struct intel_gvt *gvt); #endif /* _GVT_GTT_H_ */ diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index c7c561237883..d1d8ee4a5f16 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -312,7 +312,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915) gvt_dbg_core("init gvt device\n"); - idr_init(&gvt->vgpu_idr); + idr_init_base(&gvt->vgpu_idr, 1); spin_lock_init(&gvt->scheduler.mmio_context_lock); mutex_init(&gvt->lock); mutex_init(&gvt->sched_lock); @@ -406,7 +406,16 @@ out_clean_idr: } int -intel_gvt_register_hypervisor(struct intel_gvt_mpt *m) +intel_gvt_pm_resume(struct intel_gvt *gvt) +{ + intel_gvt_restore_fence(gvt); + intel_gvt_restore_mmio(gvt); + intel_gvt_restore_ggtt(gvt); + return 0; +} + +int +intel_gvt_register_hypervisor(const struct intel_gvt_mpt *m) { int ret; void *gvt; diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index a81cf0f01e78..cf3578e3f4dd 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -56,7 +56,7 @@ struct intel_gvt_host { struct device *dev; bool initialized; int hypervisor_type; - struct intel_gvt_mpt *mpt; + const struct intel_gvt_mpt *mpt; }; extern struct intel_gvt_host intel_gvt_host; @@ -255,6 +255,8 @@ struct intel_gvt_mmio { #define F_CMD_ACCESS (1 << 3) /* This reg has been accessed by a VM */ #define F_ACCESSED (1 << 4) +/* This reg requires save & restore during host PM suspend/resume */ +#define F_PM_SAVE (1 << 5) /* This reg could be accessed by unaligned address */ #define F_UNALIGN (1 << 6) /* This reg is in GVT's mmio save-restor list and in hardware @@ -685,6 +687,7 @@ void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu); void intel_gvt_debugfs_init(struct intel_gvt *gvt); void intel_gvt_debugfs_clean(struct intel_gvt *gvt); +int intel_gvt_pm_resume(struct intel_gvt *gvt); #include "trace.h" #include "mpt.h" diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index eb342a759943..aa7e75cb3e6a 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -290,8 +290,8 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu, case FORCEWAKE_RENDER_GEN9_REG: ack_reg_offset = FORCEWAKE_ACK_RENDER_GEN9_REG; break; - case FORCEWAKE_BLITTER_GEN9_REG: - ack_reg_offset = FORCEWAKE_ACK_BLITTER_GEN9_REG; + case FORCEWAKE_GT_GEN9_REG: + ack_reg_offset = FORCEWAKE_ACK_GT_GEN9_REG; break; case FORCEWAKE_MEDIA_GEN9_REG: ack_reg_offset = FORCEWAKE_ACK_MEDIA_GEN9_REG; @@ -2238,9 +2238,9 @@ static int init_generic_mmio_info(struct intel_gvt *gvt) MMIO_D(PF_VSCALE(PIPE_C), D_ALL); MMIO_D(PF_HSCALE(PIPE_C), D_ALL); - MMIO_D(WM0_PIPEA_ILK, D_ALL); - MMIO_D(WM0_PIPEB_ILK, D_ALL); - MMIO_D(WM0_PIPEC_IVB, D_ALL); + MMIO_D(WM0_PIPE_ILK(PIPE_A), D_ALL); + MMIO_D(WM0_PIPE_ILK(PIPE_B), D_ALL); + MMIO_D(WM0_PIPE_ILK(PIPE_C), D_ALL); MMIO_D(WM1_LP_ILK, D_ALL); MMIO_D(WM2_LP_ILK, D_ALL); MMIO_D(WM3_LP_ILK, D_ALL); @@ -2930,8 +2930,8 @@ static int init_skl_mmio_info(struct intel_gvt *gvt) MMIO_DH(FORCEWAKE_RENDER_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write); MMIO_DH(FORCEWAKE_ACK_RENDER_GEN9, D_SKL_PLUS, NULL, NULL); - MMIO_DH(FORCEWAKE_BLITTER_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write); - MMIO_DH(FORCEWAKE_ACK_BLITTER_GEN9, D_SKL_PLUS, NULL, NULL); + MMIO_DH(FORCEWAKE_GT_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write); + MMIO_DH(FORCEWAKE_ACK_GT_GEN9, D_SKL_PLUS, NULL, NULL); MMIO_DH(FORCEWAKE_MEDIA_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write); MMIO_DH(FORCEWAKE_ACK_MEDIA_GEN9, D_SKL_PLUS, NULL, NULL); @@ -3120,9 +3120,10 @@ static int init_skl_mmio_info(struct intel_gvt *gvt) MMIO_DFH(TRVATTL3PTRDW(2), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); MMIO_DFH(TRVATTL3PTRDW(3), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); MMIO_DFH(TRVADR, D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(TRTTE, D_SKL_PLUS, F_CMD_ACCESS, - NULL, gen9_trtte_write); - MMIO_DH(_MMIO(0x4dfc), D_SKL_PLUS, NULL, gen9_trtt_chicken_write); + MMIO_DFH(TRTTE, D_SKL_PLUS, F_CMD_ACCESS | F_PM_SAVE, + NULL, gen9_trtte_write); + MMIO_DFH(_MMIO(0x4dfc), D_SKL_PLUS, F_PM_SAVE, + NULL, gen9_trtt_chicken_write); MMIO_D(_MMIO(0x46430), D_SKL_PLUS); @@ -3671,3 +3672,40 @@ default_rw: intel_vgpu_default_mmio_read(vgpu, offset, pdata, bytes) : intel_vgpu_default_mmio_write(vgpu, offset, pdata, bytes); } + +void intel_gvt_restore_fence(struct intel_gvt *gvt) +{ + struct intel_vgpu *vgpu; + int i, id; + + idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) { + mmio_hw_access_pre(gvt->gt); + for (i = 0; i < vgpu_fence_sz(vgpu); i++) + intel_vgpu_write_fence(vgpu, i, vgpu_vreg64(vgpu, fence_num_to_offset(i))); + mmio_hw_access_post(gvt->gt); + } +} + +static inline int mmio_pm_restore_handler(struct intel_gvt *gvt, + u32 offset, void *data) +{ + struct intel_vgpu *vgpu = data; + struct drm_i915_private *dev_priv = gvt->gt->i915; + + if (gvt->mmio.mmio_attribute[offset >> 2] & F_PM_SAVE) + I915_WRITE(_MMIO(offset), vgpu_vreg(vgpu, offset)); + + return 0; +} + +void intel_gvt_restore_mmio(struct intel_gvt *gvt) +{ + struct intel_vgpu *vgpu; + int id; + + idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) { + mmio_hw_access_pre(gvt->gt); + intel_gvt_for_each_tracked_mmio(gvt, mmio_pm_restore_handler, vgpu); + mmio_hw_access_post(gvt->gt); + } +} diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 778eb8cab610..60f1a386dd06 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -2101,7 +2101,7 @@ static bool kvmgt_is_valid_gfn(unsigned long handle, unsigned long gfn) return ret; } -static struct intel_gvt_mpt kvmgt_mpt = { +static const struct intel_gvt_mpt kvmgt_mpt = { .type = INTEL_GVT_HYPERVISOR_KVM, .host_init = kvmgt_host_init, .host_exit = kvmgt_host_exit, diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index b6811f6a230d..24210b1eaec5 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -280,6 +280,11 @@ void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr) vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |= BXT_PHY_CMNLANE_POWERDOWN_ACK | BXT_PHY_LANE_POWERDOWN_ACK; + vgpu_vreg_t(vgpu, SKL_FUSE_STATUS) |= + SKL_FUSE_DOWNLOAD_STATUS | + SKL_FUSE_PG_DIST_STATUS(SKL_PG0) | + SKL_FUSE_PG_DIST_STATUS(SKL_PG1) | + SKL_FUSE_PG_DIST_STATUS(SKL_PG2); } } else { #define GVT_GEN8_MMIO_RESET_OFFSET (0x44200) diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h index cc4812648bf4..9e862dc73579 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.h +++ b/drivers/gpu/drm/i915/gvt/mmio.h @@ -104,4 +104,8 @@ int intel_vgpu_mmio_reg_rw(struct intel_vgpu *vgpu, unsigned int offset, int intel_vgpu_mask_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes); + +void intel_gvt_restore_fence(struct intel_gvt *gvt); +void intel_gvt_restore_mmio(struct intel_gvt *gvt); + #endif diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h index 9ad224df9c68..6f92cde71971 100644 --- a/drivers/gpu/drm/i915/gvt/mpt.h +++ b/drivers/gpu/drm/i915/gvt/mpt.h @@ -392,7 +392,7 @@ static inline bool intel_gvt_hypervisor_is_valid_gfn( return intel_gvt_host.mpt->is_valid_gfn(vgpu->handle, gfn); } -int intel_gvt_register_hypervisor(struct intel_gvt_mpt *); +int intel_gvt_register_hypervisor(const struct intel_gvt_mpt *); void intel_gvt_unregister_hypervisor(void); #endif /* _GVT_MPT_H_ */ diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h index b88e033cbed4..b58860dee970 100644 --- a/drivers/gpu/drm/i915/gvt/reg.h +++ b/drivers/gpu/drm/i915/gvt/reg.h @@ -101,8 +101,8 @@ #define FORCEWAKE_RENDER_GEN9_REG 0xa278 #define FORCEWAKE_ACK_RENDER_GEN9_REG 0x0D84 -#define FORCEWAKE_BLITTER_GEN9_REG 0xa188 -#define FORCEWAKE_ACK_BLITTER_GEN9_REG 0x130044 +#define FORCEWAKE_GT_GEN9_REG 0xa188 +#define FORCEWAKE_ACK_GT_GEN9_REG 0x130044 #define FORCEWAKE_MEDIA_GEN9_REG 0xa270 #define FORCEWAKE_ACK_MEDIA_GEN9_REG 0x0D88 #define FORCEWAKE_ACK_HSW_REG 0x130044 diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 399582aeeefb..e49944fde333 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -393,7 +393,7 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, mutex_init(&vgpu->dmabuf_lock); INIT_LIST_HEAD(&vgpu->dmabuf_obj_list_head); INIT_RADIX_TREE(&vgpu->page_track_tree, GFP_KERNEL); - idr_init(&vgpu->object_idr); + idr_init_base(&vgpu->object_idr, 1); intel_vgpu_init_cfg_space(vgpu, param->primary); vgpu->d3_entered = false; diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index e88970256e8e..93265951fdbb 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1452,43 +1452,42 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, * space. Parsing should be faster in some cases this way. */ batch_end = cmd + batch_length / sizeof(*batch_end); - do { - u32 length; - - if (*cmd == MI_BATCH_BUFFER_END) - break; - - desc = find_cmd(engine, *cmd, desc, &default_desc); - if (!desc) { - DRM_DEBUG("CMD: Unrecognized command: 0x%08X\n", *cmd); - ret = -EINVAL; - break; - } + while (*cmd != MI_BATCH_BUFFER_END) { + u32 length = 1; + + if (*cmd != MI_NOOP) { /* MI_NOOP == 0 */ + desc = find_cmd(engine, *cmd, desc, &default_desc); + if (!desc) { + DRM_DEBUG("CMD: Unrecognized command: 0x%08X\n", *cmd); + ret = -EINVAL; + break; + } - if (desc->flags & CMD_DESC_FIXED) - length = desc->length.fixed; - else - length = (*cmd & desc->length.mask) + LENGTH_BIAS; + if (desc->flags & CMD_DESC_FIXED) + length = desc->length.fixed; + else + length = (*cmd & desc->length.mask) + LENGTH_BIAS; - if ((batch_end - cmd) < length) { - DRM_DEBUG("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", - *cmd, - length, - batch_end - cmd); - ret = -EINVAL; - break; - } + if ((batch_end - cmd) < length) { + DRM_DEBUG("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", + *cmd, + length, + batch_end - cmd); + ret = -EINVAL; + break; + } - if (!check_cmd(engine, desc, cmd, length)) { - ret = -EACCES; - break; - } + if (!check_cmd(engine, desc, cmd, length)) { + ret = -EACCES; + break; + } - if (cmd_desc_is(desc, MI_BATCH_BUFFER_START)) { - ret = check_bbstart(cmd, offset, length, batch_length, - batch_addr, shadow_addr, - jump_whitelist); - break; + if (cmd_desc_is(desc, MI_BATCH_BUFFER_START)) { + ret = check_bbstart(cmd, offset, length, batch_length, + batch_addr, shadow_addr, + jump_whitelist); + break; + } } if (!IS_ERR_OR_NULL(jump_whitelist)) @@ -1501,7 +1500,7 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, ret = -EINVAL; break; } - } while (1); + } if (trampoline) { /* diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ea469168cd44..77e76b665098 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -725,7 +725,7 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file) gpu = NULL; with_intel_runtime_pm(&i915->runtime_pm, wakeref) - gpu = i915_gpu_coredump(i915); + gpu = i915_gpu_coredump(&i915->gt, ALL_ENGINES); if (IS_ERR(gpu)) return PTR_ERR(gpu); @@ -786,7 +786,6 @@ static int i915_frequency_info(struct seq_file *m, void *unused) struct intel_uncore *uncore = &dev_priv->uncore; struct intel_rps *rps = &dev_priv->gt.rps; intel_wakeref_t wakeref; - int ret = 0; wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); @@ -1009,7 +1008,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "Max pixel clock frequency: %d kHz\n", dev_priv->max_dotclk_freq); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - return ret; + return 0; } static int i915_ring_freq_table(struct seq_file *m, void *unused) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index acc32066cec3..320856b665a1 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -84,9 +84,10 @@ #include "intel_gvt.h" #include "intel_memory_region.h" #include "intel_pm.h" +#include "intel_sideband.h" #include "vlv_suspend.h" -static struct drm_driver driver; +static const struct drm_driver driver; static int i915_get_bridge_dev(struct drm_i915_private *dev_priv) { @@ -616,6 +617,8 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) */ intel_dram_detect(dev_priv); + intel_pcode_init(dev_priv); + intel_bw_init_hw(dev_priv); return 0; @@ -668,7 +671,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) /* Reveal our presence to userspace */ if (drm_dev_register(dev, 0) == 0) { i915_debugfs_register(dev_priv); - intel_display_debugfs_register(dev_priv); + if (HAS_DISPLAY(dev_priv)) + intel_display_debugfs_register(dev_priv); i915_setup_sysfs(dev_priv); /* Depends on sysfs having been initialized */ @@ -840,9 +844,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i915->params.fake_lmem_start) { mkwrite_device_info(i915)->memory_regions = REGION_SMEM | REGION_LMEM | REGION_STOLEN; - mkwrite_device_info(i915)->is_dgfx = true; GEM_BUG_ON(!HAS_LMEM(i915)); - GEM_BUG_ON(!IS_DGFX(i915)); } } #endif @@ -1036,6 +1038,35 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv) drm_modeset_unlock_all(dev); } +static void intel_shutdown_encoders(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = &dev_priv->drm; + struct intel_encoder *encoder; + + drm_modeset_lock_all(dev); + for_each_intel_encoder(dev, encoder) + if (encoder->shutdown) + encoder->shutdown(encoder); + drm_modeset_unlock_all(dev); +} + +void i915_driver_shutdown(struct drm_i915_private *i915) +{ + i915_gem_suspend(i915); + + drm_kms_helper_poll_disable(&i915->drm); + + drm_atomic_helper_shutdown(&i915->drm); + + intel_dp_mst_suspend(i915); + + intel_runtime_pm_disable_interrupts(i915); + intel_hpd_cancel_work(i915); + + intel_suspend_encoders(i915); + intel_shutdown_encoders(i915); +} + static bool suspend_to_idle(struct drm_i915_private *dev_priv) { #if IS_ENABLED(CONFIG_ACPI_SLEEP) @@ -1089,7 +1120,7 @@ static int i915_drm_suspend(struct drm_device *dev) i915_ggtt_suspend(&dev_priv->ggtt); - i915_save_state(dev_priv); + i915_save_display(dev_priv); opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; intel_opregion_suspend(dev_priv, opregion_target_state); @@ -1202,7 +1233,7 @@ static int i915_drm_resume(struct drm_device *dev) intel_csr_ucode_resume(dev_priv); - i915_restore_state(dev_priv); + i915_restore_display(dev_priv); intel_pps_unlock_regs_wa(dev_priv); intel_init_pch_refclk(dev_priv); @@ -1225,32 +1256,23 @@ static int i915_drm_resume(struct drm_device *dev) intel_modeset_init_hw(dev_priv); intel_init_clock_gating(dev_priv); + intel_hpd_init(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); - + /* MST sideband requires HPD interrupts enabled */ intel_dp_mst_resume(dev_priv); - intel_display_resume(dev); + intel_hpd_poll_disable(dev_priv); drm_kms_helper_poll_enable(dev); - /* - * ... but also need to make sure that hotplug processing - * doesn't cause havoc. Like in the driver load code we don't - * bother with the tiny race here where we might lose hotplug - * notifications. - * */ - intel_hpd_init(dev_priv); - intel_opregion_resume(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); intel_power_domains_enable(dev_priv); + intel_gvt_resume(dev_priv); + enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); return 0; @@ -1556,7 +1578,7 @@ static int intel_runtime_suspend(struct device *kdev) assert_forcewakes_inactive(&dev_priv->uncore); if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) - intel_hpd_poll_init(dev_priv); + intel_hpd_poll_enable(dev_priv); drm_dbg_kms(&dev_priv->drm, "Device suspended\n"); return 0; @@ -1601,8 +1623,10 @@ static int intel_runtime_resume(struct device *kdev) * power well, so hpd is reinitialized from there. For * everyone else do it here. */ - if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) + if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) { intel_hpd_init(dev_priv); + intel_hpd_poll_disable(dev_priv); + } intel_enable_ipc(dev_priv); @@ -1737,7 +1761,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_VM_DESTROY, i915_gem_vm_destroy_ioctl, DRM_RENDER_ALLOW), }; -static struct drm_driver driver = { +static const struct drm_driver driver = { /* Don't use MTRRs here; the Xserver or userspace app should * deal with them for Intel hardware. */ @@ -1750,12 +1774,8 @@ static struct drm_driver driver = { .lastclose = i915_driver_lastclose, .postclose = i915_driver_postclose, - .gem_close_object = i915_gem_close_object, - .gem_free_object_unlocked = i915_gem_free_object, - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = i915_gem_prime_export, .gem_prime_import = i915_gem_prime_import, .dumb_create = i915_gem_dumb_create, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8426d5974669..15be8debae54 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -110,8 +110,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20200917" -#define DRIVER_TIMESTAMP 1600375437 +#define DRIVER_DATE "20201103" +#define DRIVER_TIMESTAMP 1604406085 struct drm_i915_gem_object; @@ -508,7 +508,6 @@ struct i915_psr { bool dc3co_enabled; u32 dc3co_exit_delay; struct delayed_work dc3co_work; - bool force_mode_changed; struct drm_dp_vsc_sdp vsc; }; @@ -1419,7 +1418,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_COMETLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_COMETLAKE) #define IS_CANNONLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_CANNONLAKE) #define IS_ICELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ICELAKE) -#define IS_ELKHARTLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE) +#define IS_JSL_EHL(dev_priv) (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE) || \ + IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE)) #define IS_TIGERLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_TIGERLAKE) #define IS_ROCKETLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ROCKETLAKE) #define IS_DG1(dev_priv) IS_PLATFORM(dev_priv, INTEL_DG1) @@ -1559,9 +1559,10 @@ extern const struct i915_rev_steppings kbl_revids[]; (IS_ICELAKE(p) && IS_REVID(p, since, until)) #define EHL_REVID_A0 0x0 +#define EHL_REVID_B0 0x1 -#define IS_EHL_REVID(p, since, until) \ - (IS_ELKHARTLAKE(p) && IS_REVID(p, since, until)) +#define IS_JSL_EHL_REVID(p, since, until) \ + (IS_JSL_EHL(p) && IS_REVID(p, since, until)) enum { TGL_REVID_A0, @@ -1640,8 +1641,7 @@ tgl_revids_get(struct drm_i915_private *dev_priv) #define HAS_SNOOP(dev_priv) (INTEL_INFO(dev_priv)->has_snoop) #define HAS_EDRAM(dev_priv) ((dev_priv)->edram_size_mb) #define HAS_SECURE_BATCHES(dev_priv) (INTEL_GEN(dev_priv) < 6) -#define HAS_WT(dev_priv) ((IS_HASWELL(dev_priv) || \ - IS_BROADWELL(dev_priv)) && HAS_EDRAM(dev_priv)) +#define HAS_WT(dev_priv) HAS_EDRAM(dev_priv) #define HWS_NEEDS_PHYSICAL(dev_priv) (INTEL_INFO(dev_priv)->hws_needs_physical) @@ -1783,6 +1783,7 @@ extern const struct dev_pm_ops i915_pm_ops; int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent); void i915_driver_remove(struct drm_i915_private *i915); +void i915_driver_shutdown(struct drm_i915_private *i915); int i915_resume_switcheroo(struct drm_i915_private *i915); int i915_suspend_switcheroo(struct drm_i915_private *i915, pm_message_t state); diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 6501939929d5..e1a66c8245b8 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -238,7 +238,7 @@ found: } /** - * i915_gem_evict_for_vma - Evict vmas to make room for binding a new one + * i915_gem_evict_for_node - Evict vmas to make room for binding a new one * @vm: address space to evict from * @target: range (and color) to evict for * @flags: additional flags to control the eviction algorithm diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index cf6e47adfde6..d8cac4c5881f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -570,6 +570,7 @@ static void error_print_engine(struct drm_i915_error_state_buf *m, ee->vm_info.pp_dir_base); } } + err_printf(m, " hung: %u\n", ee->hung); err_printf(m, " engine reset count: %u\n", ee->reset_count); for (n = 0; n < ee->num_ports; n++) { @@ -1026,6 +1027,7 @@ i915_vma_coredump_create(const struct intel_gt *gt, dma_addr_t dma; for_each_sgt_daddr(dma, iter, vma->pages) { + mutex_lock(&ggtt->error_mutex); ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); mb(); @@ -1035,6 +1037,10 @@ i915_vma_coredump_create(const struct intel_gt *gt, (void __force *)s, dst, true); io_mapping_unmap(s); + + mb(); + ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); + mutex_unlock(&ggtt->error_mutex); if (ret) break; } @@ -1451,6 +1457,7 @@ capture_engine(struct intel_engine_cs *engine, static void gt_record_engines(struct intel_gt_coredump *gt, + intel_engine_mask_t engine_mask, struct i915_vma_compress *compress) { struct intel_engine_cs *engine; @@ -1466,6 +1473,8 @@ gt_record_engines(struct intel_gt_coredump *gt, if (!ee) continue; + ee->hung = engine->mask & engine_mask; + gt->simulated |= ee->simulated; if (ee->simulated) { kfree(ee); @@ -1505,25 +1514,6 @@ gt_record_uc(struct intel_gt_coredump *gt, return error_uc; } -static void gt_capture_prepare(struct intel_gt_coredump *gt) -{ - struct i915_ggtt *ggtt = gt->_gt->ggtt; - - mutex_lock(&ggtt->error_mutex); -} - -static void gt_capture_finish(struct intel_gt_coredump *gt) -{ - struct i915_ggtt *ggtt = gt->_gt->ggtt; - - if (drm_mm_node_allocated(&ggtt->error_capture)) - ggtt->vm.clear_range(&ggtt->vm, - ggtt->error_capture.start, - PAGE_SIZE); - - mutex_unlock(&ggtt->error_mutex); -} - /* Capture all registers which don't fit into another category. */ static void gt_record_regs(struct intel_gt_coredump *gt) { @@ -1669,24 +1659,25 @@ static u32 generate_ecode(const struct intel_engine_coredump *ee) static const char *error_msg(struct i915_gpu_coredump *error) { struct intel_engine_coredump *first = NULL; + unsigned int hung_classes = 0; struct intel_gt_coredump *gt; - intel_engine_mask_t engines; int len; - engines = 0; for (gt = error->gt; gt; gt = gt->next) { struct intel_engine_coredump *cs; - if (gt->engine && !first) - first = gt->engine; - - for (cs = gt->engine; cs; cs = cs->next) - engines |= cs->engine->mask; + for (cs = gt->engine; cs; cs = cs->next) { + if (cs->hung) { + hung_classes |= BIT(cs->engine->uabi_class); + if (!first) + first = cs; + } + } } len = scnprintf(error->error_msg, sizeof(error->error_msg), "GPU HANG: ecode %d:%x:%08x", - INTEL_GEN(error->i915), engines, + INTEL_GEN(error->i915), hung_classes, generate_ecode(first)); if (first && first->context.pid) { /* Just show the first executing process, more is confusing */ @@ -1782,8 +1773,6 @@ i915_vma_capture_prepare(struct intel_gt_coredump *gt) return NULL; } - gt_capture_prepare(gt); - return compress; } @@ -1793,14 +1782,14 @@ void i915_vma_capture_finish(struct intel_gt_coredump *gt, if (!compress) return; - gt_capture_finish(gt); - compress_fini(compress); kfree(compress); } -struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915) +struct i915_gpu_coredump * +i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask) { + struct drm_i915_private *i915 = gt->i915; struct i915_gpu_coredump *error; /* Check if GPU capture has been disabled */ @@ -1812,7 +1801,7 @@ struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915) if (!error) return ERR_PTR(-ENOMEM); - error->gt = intel_gt_coredump_alloc(&i915->gt, ALLOW_FAIL); + error->gt = intel_gt_coredump_alloc(gt, ALLOW_FAIL); if (error->gt) { struct i915_vma_compress *compress; @@ -1824,7 +1813,7 @@ struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915) } gt_record_info(error->gt); - gt_record_engines(error->gt, compress); + gt_record_engines(error->gt, engine_mask, compress); if (INTEL_INFO(i915)->has_gt_uc) error->gt->uc = gt_record_uc(error->gt, compress); @@ -1871,20 +1860,23 @@ void i915_error_state_store(struct i915_gpu_coredump *error) /** * i915_capture_error_state - capture an error record for later analysis - * @i915: i915 device + * @gt: intel_gt which originated the hang + * @engine_mask: hung engines + * * * Should be called when an error is detected (either a hang or an error * interrupt) to capture error state from the time of the error. Fills * out a structure which becomes available in debugfs for user level tools * to pick up. */ -void i915_capture_error_state(struct drm_i915_private *i915) +void i915_capture_error_state(struct intel_gt *gt, + intel_engine_mask_t engine_mask) { struct i915_gpu_coredump *error; - error = i915_gpu_coredump(i915); + error = i915_gpu_coredump(gt, engine_mask); if (IS_ERR(error)) { - cmpxchg(&i915->gpu_error.first_error, NULL, error); + cmpxchg(>->i915->gpu_error.first_error, NULL, error); return; } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 0220b0992808..16bc42de4b84 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -59,6 +59,7 @@ struct i915_request_coredump { struct intel_engine_coredump { const struct intel_engine_cs *engine; + bool hung; bool simulated; u32 reset_count; @@ -218,8 +219,10 @@ struct drm_i915_error_state_buf { __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); -struct i915_gpu_coredump *i915_gpu_coredump(struct drm_i915_private *i915); -void i915_capture_error_state(struct drm_i915_private *i915); +struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt, + intel_engine_mask_t engine_mask); +void i915_capture_error_state(struct intel_gt *gt, + intel_engine_mask_t engine_mask); struct i915_gpu_coredump * i915_gpu_coredump_alloc(struct drm_i915_private *i915, gfp_t gfp); @@ -271,7 +274,8 @@ void i915_disable_error_state(struct drm_i915_private *i915, int err); #else -static inline void i915_capture_error_state(struct drm_i915_private *i915) +static inline void +i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask) { } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 759f523c6a6b..dc6febc63f1c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -61,6 +61,8 @@ */ typedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val); +typedef u32 (*hotplug_enables_func)(struct drm_i915_private *i915, + enum hpd_pin pin); static const u32 hpd_ilk[HPD_NUM_PINS] = { [HPD_PORT_A] = DE_DP_A_HOTPLUG, @@ -71,7 +73,7 @@ static const u32 hpd_ivb[HPD_NUM_PINS] = { }; static const u32 hpd_bdw[HPD_NUM_PINS] = { - [HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG, + [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A), }; static const u32 hpd_ibx[HPD_NUM_PINS] = { @@ -126,30 +128,37 @@ static const u32 hpd_status_i915[HPD_NUM_PINS] = { }; static const u32 hpd_bxt[HPD_NUM_PINS] = { - [HPD_PORT_A] = BXT_DE_PORT_HP_DDIA, - [HPD_PORT_B] = BXT_DE_PORT_HP_DDIB, - [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC, + [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A), + [HPD_PORT_B] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_B), + [HPD_PORT_C] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_C), }; static const u32 hpd_gen11[HPD_NUM_PINS] = { - [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(PORT_TC1) | GEN11_TBT_HOTPLUG(PORT_TC1), - [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(PORT_TC2) | GEN11_TBT_HOTPLUG(PORT_TC2), - [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(PORT_TC3) | GEN11_TBT_HOTPLUG(PORT_TC3), - [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(PORT_TC4) | GEN11_TBT_HOTPLUG(PORT_TC4), - [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(PORT_TC5) | GEN11_TBT_HOTPLUG(PORT_TC5), - [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(PORT_TC6) | GEN11_TBT_HOTPLUG(PORT_TC6), + [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(HPD_PORT_TC1) | GEN11_TBT_HOTPLUG(HPD_PORT_TC1), + [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(HPD_PORT_TC2) | GEN11_TBT_HOTPLUG(HPD_PORT_TC2), + [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(HPD_PORT_TC3) | GEN11_TBT_HOTPLUG(HPD_PORT_TC3), + [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(HPD_PORT_TC4) | GEN11_TBT_HOTPLUG(HPD_PORT_TC4), + [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(HPD_PORT_TC5) | GEN11_TBT_HOTPLUG(HPD_PORT_TC5), + [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(HPD_PORT_TC6) | GEN11_TBT_HOTPLUG(HPD_PORT_TC6), }; static const u32 hpd_icp[HPD_NUM_PINS] = { - [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(PORT_A), - [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B), - [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C), - [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(PORT_TC1), - [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(PORT_TC2), - [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(PORT_TC3), - [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(PORT_TC4), - [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(PORT_TC5), - [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(PORT_TC6), + [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A), + [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B), + [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C), + [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1), + [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2), + [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3), + [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4), + [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC5), + [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC6), +}; + +static const u32 hpd_sde_dg1[HPD_NUM_PINS] = { + [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A), + [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B), + [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C), + [HPD_PORT_D] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_D), }; static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) @@ -176,11 +185,14 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) else hpd->hpd = hpd_ilk; - if (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv)) + if ((INTEL_PCH_TYPE(dev_priv) < PCH_DG1) && + (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))) return; - if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) || - HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv)) + if (HAS_PCH_DG1(dev_priv)) + hpd->pch_hpd = hpd_sde_dg1; + else if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) || + HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv)) hpd->pch_hpd = hpd_icp; else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv)) hpd->pch_hpd = hpd_spt; @@ -337,17 +349,14 @@ void ilk_update_display_irq(struct drm_i915_private *dev_priv, u32 new_val; lockdep_assert_held(&dev_priv->irq_lock); - drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask); - if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv))) - return; - new_val = dev_priv->irq_mask; new_val &= ~interrupt_mask; new_val |= (~enabled_irq_mask & interrupt_mask); - if (new_val != dev_priv->irq_mask) { + if (new_val != dev_priv->irq_mask && + !drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv))) { dev_priv->irq_mask = new_val; I915_WRITE(DEIMR, dev_priv->irq_mask); POSTING_READ(DEIMR); @@ -682,8 +691,12 @@ u32 i915_get_vblank_counter(struct drm_crtc *crtc) u32 g4x_get_vblank_counter(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)]; enum pipe pipe = to_intel_crtc(crtc)->pipe; + if (!vblank->max_vblank_count) + return 0; + return I915_READ(PIPE_FRMCOUNT_G4X(pipe)); } @@ -1031,17 +1044,17 @@ static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { switch (pin) { case HPD_PORT_TC1: - return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1); + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC1); case HPD_PORT_TC2: - return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2); + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC2); case HPD_PORT_TC3: - return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3); + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC3); case HPD_PORT_TC4: - return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4); + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC4); case HPD_PORT_TC5: - return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC5); + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC5); case HPD_PORT_TC6: - return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC6); + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC6); default: return false; } @@ -1065,11 +1078,13 @@ static bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { switch (pin) { case HPD_PORT_A: - return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_A); + return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_A); case HPD_PORT_B: - return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_B); + return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_B); case HPD_PORT_C: - return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_C); + return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_C); + case HPD_PORT_D: + return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_D); default: return false; } @@ -1079,17 +1094,17 @@ static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { switch (pin) { case HPD_PORT_TC1: - return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1); + return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC1); case HPD_PORT_TC2: - return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2); + return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC2); case HPD_PORT_TC3: - return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3); + return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC3); case HPD_PORT_TC4: - return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4); + return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC4); case HPD_PORT_TC5: - return val & ICP_TC_HPD_LONG_DETECT(PORT_TC5); + return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC5); case HPD_PORT_TC6: - return val & ICP_TC_HPD_LONG_DETECT(PORT_TC6); + return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC6); default: return false; } @@ -1192,6 +1207,43 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv, } +static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv, + const u32 hpd[HPD_NUM_PINS]) +{ + struct intel_encoder *encoder; + u32 enabled_irqs = 0; + + for_each_intel_encoder(&dev_priv->drm, encoder) + if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED) + enabled_irqs |= hpd[encoder->hpd_pin]; + + return enabled_irqs; +} + +static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv, + const u32 hpd[HPD_NUM_PINS]) +{ + struct intel_encoder *encoder; + u32 hotplug_irqs = 0; + + for_each_intel_encoder(&dev_priv->drm, encoder) + hotplug_irqs |= hpd[encoder->hpd_pin]; + + return hotplug_irqs; +} + +static u32 intel_hpd_hotplug_enables(struct drm_i915_private *i915, + hotplug_enables_func hotplug_enables) +{ + struct intel_encoder *encoder; + u32 hotplug = 0; + + for_each_intel_encoder(&i915->drm, encoder) + hotplug |= hotplug_enables(i915, encoder->hpd_pin); + + return hotplug; +} + static void gmbus_irq_handler(struct drm_i915_private *dev_priv) { wake_up_all(&dev_priv->gmbus_wait_queue); @@ -1245,6 +1297,23 @@ display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, u32 crc4) {} #endif +static void flip_done_handler(struct drm_i915_private *i915, + enum pipe pipe) +{ + struct intel_crtc *crtc = intel_get_crtc_for_pipe(i915, pipe); + struct drm_crtc_state *crtc_state = crtc->base.state; + struct drm_pending_vblank_event *e = crtc_state->event; + struct drm_device *dev = &i915->drm; + unsigned long irqflags; + + spin_lock_irqsave(&dev->event_lock, irqflags); + + crtc_state->event = NULL; + + drm_crtc_send_vblank_event(&crtc->base, e); + + spin_unlock_irqrestore(&dev->event_lock, irqflags); +} static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, enum pipe pipe) @@ -1840,27 +1909,10 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) { - u32 ddi_hotplug_trigger, tc_hotplug_trigger; + u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP; + u32 tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_MASK_ICP; u32 pin_mask = 0, long_mask = 0; - if (HAS_PCH_TGP(dev_priv)) { - ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP; - tc_hotplug_trigger = pch_iir & SDE_TC_MASK_TGP; - } else if (HAS_PCH_JSP(dev_priv)) { - ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP; - tc_hotplug_trigger = 0; - } else if (HAS_PCH_MCC(dev_priv)) { - ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP; - tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1); - } else { - drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv), - "Unrecognized PCH type 0x%x\n", - INTEL_PCH_TYPE(dev_priv)); - - ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP; - tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP; - } - if (ddi_hotplug_trigger) { u32 dig_hotplug_reg; @@ -2237,6 +2289,63 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); } +static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, + u32 te_trigger) +{ + enum pipe pipe = INVALID_PIPE; + enum transcoder dsi_trans; + enum port port; + u32 val, tmp; + + /* + * Incase of dual link, TE comes from DSI_1 + * this is to check if dual link is enabled + */ + val = I915_READ(TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); + val &= PORT_SYNC_MODE_ENABLE; + + /* + * if dual link is enabled, then read DSI_0 + * transcoder registers + */ + port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? + PORT_A : PORT_B; + dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; + + /* Check if DSI configured in command mode */ + val = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)); + val = val & OP_MODE_MASK; + + if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { + drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); + return; + } + + /* Get PIPE for handling VBLANK event */ + val = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); + switch (val & TRANS_DDI_EDP_INPUT_MASK) { + case TRANS_DDI_EDP_INPUT_A_ON: + pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + pipe = PIPE_C; + break; + default: + drm_err(&dev_priv->drm, "Invalid PIPE\n"); + return; + } + + intel_handle_vblank(dev_priv, pipe); + + /* clear TE in dsi IIR */ + port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; + tmp = I915_READ(DSI_INTR_IDENT_REG(port)); + I915_WRITE(DSI_INTR_IDENT_REG(port), tmp); +} + static irqreturn_t gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) { @@ -2271,7 +2380,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) if (master_ctl & GEN8_DE_PORT_IRQ) { iir = I915_READ(GEN8_DE_PORT_IIR); if (iir) { - u32 tmp_mask; bool found = false; I915_WRITE(GEN8_DE_PORT_IIR, iir); @@ -2283,15 +2391,17 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) } if (IS_GEN9_LP(dev_priv)) { - tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK; - if (tmp_mask) { - bxt_hpd_irq_handler(dev_priv, tmp_mask); + u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; + + if (hotplug_trigger) { + bxt_hpd_irq_handler(dev_priv, hotplug_trigger); found = true; } } else if (IS_BROADWELL(dev_priv)) { - tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG; - if (tmp_mask) { - ilk_hpd_irq_handler(dev_priv, tmp_mask); + u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; + + if (hotplug_trigger) { + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); found = true; } } @@ -2301,6 +2411,15 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) found = true; } + if (INTEL_GEN(dev_priv) >= 11) { + u32 te_trigger = iir & (DSI0_TE | DSI1_TE); + + if (te_trigger) { + gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); + found = true; + } + } + if (!found) drm_err(&dev_priv->drm, "Unexpected DE Port interrupt\n"); @@ -2329,6 +2448,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) if (iir & GEN8_PIPE_VBLANK) intel_handle_vblank(dev_priv, pipe); + if (iir & GEN9_PIPE_PLANE1_FLIP_DONE) + flip_done_handler(dev_priv, pipe); + if (iir & GEN8_PIPE_CDCLK_CRC_DONE) hsw_pipe_crc_irq_handler(dev_priv, pipe); @@ -2631,12 +2753,47 @@ int ilk_enable_vblank(struct drm_crtc *crtc) return 0; } +static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, + bool enable) +{ + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + enum port port; + u32 tmp; + + if (!(intel_crtc->mode_flags & + (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) + return false; + + /* for dual link cases we consider TE from slave */ + if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) + port = PORT_B; + else + port = PORT_A; + + tmp = I915_READ(DSI_INTR_MASK_REG(port)); + if (enable) + tmp &= ~DSI_TE_EVENT; + else + tmp |= DSI_TE_EVENT; + + I915_WRITE(DSI_INTR_MASK_REG(port), tmp); + + tmp = I915_READ(DSI_INTR_IDENT_REG(port)); + I915_WRITE(DSI_INTR_IDENT_REG(port), tmp); + + return true; +} + int bdw_enable_vblank(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; unsigned long irqflags; + if (gen11_dsi_configure_te(intel_crtc, true)) + return 0; + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -2650,6 +2807,19 @@ int bdw_enable_vblank(struct drm_crtc *crtc) return 0; } +void skl_enable_flip_done(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&i915->irq_lock, irqflags); + + bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE); + + spin_unlock_irqrestore(&i915->irq_lock, irqflags); +} + /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ @@ -2702,14 +2872,31 @@ void ilk_disable_vblank(struct drm_crtc *crtc) void bdw_disable_vblank(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; unsigned long irqflags; + if (gen11_dsi_configure_te(intel_crtc, false)) + return; + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } +void skl_disable_flip_done(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&i915->irq_lock, irqflags); + + bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE); + + spin_unlock_irqrestore(&i915->irq_lock, irqflags); +} + static void ibx_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2723,24 +2910,6 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv) I915_WRITE(SERR_INT, 0xffffffff); } -/* - * SDEIER is also touched by the interrupt handler to work around missed PCH - * interrupts. Hence we can't update it after the interrupt handler is enabled - - * instead we unconditionally enable all PCH interrupt sources here, but then - * only unmask them as needed with SDEIMR. - * - * This function needs to be called before interrupts are enabled. - */ -static void ibx_irq_pre_postinstall(struct drm_i915_private *dev_priv) -{ - if (HAS_PCH_NOP(dev_priv)) - return; - - drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0); - I915_WRITE(SDEIER, 0xffffffff); - POSTING_READ(SDEIER); -} - static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2797,6 +2966,8 @@ static void ilk_irq_reset(struct drm_i915_private *dev_priv) struct intel_uncore *uncore = &dev_priv->uncore; GEN3_IRQ_RESET(uncore, DE); + dev_priv->irq_mask = ~0u; + if (IS_GEN(dev_priv, 7)) intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff); @@ -2887,8 +3058,10 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) GEN3_IRQ_RESET(uncore, SDE); - /* Wa_14010685332:icl,jsl,ehl,tgl,rkl */ - if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) { + /* Wa_14010685332:cnp/cmp,tgp,adp */ + if (INTEL_PCH_TYPE(dev_priv) == PCH_CNP || + (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP && + INTEL_PCH_TYPE(dev_priv) < PCH_DG1)) { intel_uncore_rmw(uncore, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS); intel_uncore_rmw(uncore, SOUTH_CHICKEN1, @@ -2920,6 +3093,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN; enum pipe pipe; + if (INTEL_GEN(dev_priv) >= 9) + extra_ier |= GEN9_PIPE_PLANE1_FLIP_DONE; + spin_lock_irq(&dev_priv->irq_lock); if (!intel_irqs_enabled(dev_priv)) { @@ -2974,29 +3150,29 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv, - const u32 hpd[HPD_NUM_PINS]) +static u32 ibx_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) { - struct intel_encoder *encoder; - u32 enabled_irqs = 0; - - for_each_intel_encoder(&dev_priv->drm, encoder) - if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED) - enabled_irqs |= hpd[encoder->hpd_pin]; - - return enabled_irqs; -} - -static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv, - const u32 hpd[HPD_NUM_PINS]) -{ - struct intel_encoder *encoder; - u32 hotplug_irqs = 0; - - for_each_intel_encoder(&dev_priv->drm, encoder) - hotplug_irqs |= hpd[encoder->hpd_pin]; - - return hotplug_irqs; + switch (pin) { + case HPD_PORT_A: + /* + * When CPU and PCH are on the same package, port A + * HPD must be enabled in both north and south. + */ + return HAS_PCH_LPT_LP(i915) ? + PORTA_HOTPLUG_ENABLE : 0; + case HPD_PORT_B: + return PORTB_HOTPLUG_ENABLE | + PORTB_PULSE_DURATION_2ms; + case HPD_PORT_C: + return PORTC_HOTPLUG_ENABLE | + PORTC_PULSE_DURATION_2ms; + case HPD_PORT_D: + return PORTD_HOTPLUG_ENABLE | + PORTD_PULSE_DURATION_2ms; + default: + return 0; + } } static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv) @@ -3009,18 +3185,14 @@ static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv) * The pulse duration bits are reserved on LPT+. */ hotplug = I915_READ(PCH_PORT_HOTPLUG); - hotplug &= ~(PORTB_PULSE_DURATION_MASK | + hotplug &= ~(PORTA_HOTPLUG_ENABLE | + PORTB_HOTPLUG_ENABLE | + PORTC_HOTPLUG_ENABLE | + PORTD_HOTPLUG_ENABLE | + PORTB_PULSE_DURATION_MASK | PORTC_PULSE_DURATION_MASK | PORTD_PULSE_DURATION_MASK); - hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms; - hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms; - hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; - /* - * When CPU and PCH are on the same package, port A - * HPD must be enabled in both north and south. - */ - if (HAS_PCH_LPT_LP(dev_priv)) - hotplug |= PORTA_HOTPLUG_ENABLE; + hotplug |= intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables); I915_WRITE(PCH_PORT_HOTPLUG, hotplug); } @@ -3036,28 +3208,65 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) ibx_hpd_detection_setup(dev_priv); } -static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv, - u32 enable_mask) +static u32 icp_ddi_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_A: + case HPD_PORT_B: + case HPD_PORT_C: + case HPD_PORT_D: + return SHOTPLUG_CTL_DDI_HPD_ENABLE(pin); + default: + return 0; + } +} + +static u32 icp_tc_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_TC1: + case HPD_PORT_TC2: + case HPD_PORT_TC3: + case HPD_PORT_TC4: + case HPD_PORT_TC5: + case HPD_PORT_TC6: + return ICP_TC_HPD_ENABLE(pin); + default: + return 0; + } +} + +static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 hotplug; hotplug = I915_READ(SHOTPLUG_CTL_DDI); - hotplug |= enable_mask; + hotplug &= ~(SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D)); + hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables); I915_WRITE(SHOTPLUG_CTL_DDI, hotplug); } -static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv, - u32 enable_mask) +static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 hotplug; hotplug = I915_READ(SHOTPLUG_CTL_TC); - hotplug |= enable_mask; + hotplug &= ~(ICP_TC_HPD_ENABLE(HPD_PORT_TC1) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC2) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC3) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC4) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC5) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC6)); + hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables); I915_WRITE(SHOTPLUG_CTL_TC, hotplug); } -static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv, - u32 ddi_enable_mask, u32 tc_enable_mask) +static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv) { u32 hotplug_irqs, enabled_irqs; @@ -3069,52 +3278,67 @@ static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv, ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); - icp_ddi_hpd_detection_setup(dev_priv, ddi_enable_mask); - if (tc_enable_mask) - icp_tc_hpd_detection_setup(dev_priv, tc_enable_mask); + icp_ddi_hpd_detection_setup(dev_priv); + icp_tc_hpd_detection_setup(dev_priv); } -/* - * EHL doesn't need most of gen11_hpd_irq_setup, it's handling only the - * equivalent of SDE. - */ -static void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv) +static u32 gen11_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) { - icp_hpd_irq_setup(dev_priv, - ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE(PORT_TC1)); + switch (pin) { + case HPD_PORT_TC1: + case HPD_PORT_TC2: + case HPD_PORT_TC3: + case HPD_PORT_TC4: + case HPD_PORT_TC5: + case HPD_PORT_TC6: + return GEN11_HOTPLUG_CTL_ENABLE(pin); + default: + return 0; + } } -/* - * JSP behaves exactly the same as MCC above except that port C is mapped to - * the DDI-C pins instead of the TC1 pins. This means we should follow TGP's - * masks & tables rather than ICP's masks & tables. - */ -static void jsp_hpd_irq_setup(struct drm_i915_private *dev_priv) +static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv) { - icp_hpd_irq_setup(dev_priv, - TGP_DDI_HPD_ENABLE_MASK, 0); + u32 val; + + val = I915_READ(SOUTH_CHICKEN1); + val |= (INVERT_DDIA_HPD | + INVERT_DDIB_HPD | + INVERT_DDIC_HPD | + INVERT_DDID_HPD); + I915_WRITE(SOUTH_CHICKEN1, val); + + icp_hpd_irq_setup(dev_priv); } -static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv) +static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 hotplug; hotplug = I915_READ(GEN11_TC_HOTPLUG_CTL); - hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6); + hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6)); + hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables); I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug); +} + +static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug; hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL); - hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) | - GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6); + hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6)); + hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables); I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug); } @@ -3132,14 +3356,39 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) I915_WRITE(GEN11_DE_HPD_IMR, val); POSTING_READ(GEN11_DE_HPD_IMR); - gen11_hpd_detection_setup(dev_priv); + gen11_tc_hpd_detection_setup(dev_priv); + gen11_tbt_hpd_detection_setup(dev_priv); - if (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP) - icp_hpd_irq_setup(dev_priv, - TGP_DDI_HPD_ENABLE_MASK, TGP_TC_HPD_ENABLE_MASK); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - icp_hpd_irq_setup(dev_priv, - ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE_MASK); + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + icp_hpd_irq_setup(dev_priv); +} + +static u32 spt_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_A: + return PORTA_HOTPLUG_ENABLE; + case HPD_PORT_B: + return PORTB_HOTPLUG_ENABLE; + case HPD_PORT_C: + return PORTC_HOTPLUG_ENABLE; + case HPD_PORT_D: + return PORTD_HOTPLUG_ENABLE; + default: + return 0; + } +} + +static u32 spt_hotplug2_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_E: + return PORTE_HOTPLUG_ENABLE; + default: + return 0; + } } static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) @@ -3156,14 +3405,16 @@ static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) /* Enable digital hotplug on the PCH */ hotplug = I915_READ(PCH_PORT_HOTPLUG); - hotplug |= PORTA_HOTPLUG_ENABLE | - PORTB_HOTPLUG_ENABLE | - PORTC_HOTPLUG_ENABLE | - PORTD_HOTPLUG_ENABLE; + hotplug &= ~(PORTA_HOTPLUG_ENABLE | + PORTB_HOTPLUG_ENABLE | + PORTC_HOTPLUG_ENABLE | + PORTD_HOTPLUG_ENABLE); + hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables); I915_WRITE(PCH_PORT_HOTPLUG, hotplug); hotplug = I915_READ(PCH_PORT_HOTPLUG2); - hotplug |= PORTE_HOTPLUG_ENABLE; + hotplug &= ~PORTE_HOTPLUG_ENABLE; + hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables); I915_WRITE(PCH_PORT_HOTPLUG2, hotplug); } @@ -3182,6 +3433,18 @@ static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv) spt_hpd_detection_setup(dev_priv); } +static u32 ilk_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_A: + return DIGITAL_PORTA_HOTPLUG_ENABLE | + DIGITAL_PORTA_PULSE_DURATION_2ms; + default: + return 0; + } +} + static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 hotplug; @@ -3192,9 +3455,9 @@ static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv) * The pulse duration bits are reserved on HSW+. */ hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL); - hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK; - hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE | - DIGITAL_PORTA_PULSE_DURATION_2ms; + hotplug &= ~(DIGITAL_PORTA_HOTPLUG_ENABLE | + DIGITAL_PORTA_PULSE_DURATION_MASK); + hotplug |= intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables); I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug); } @@ -3215,41 +3478,45 @@ static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv) ibx_hpd_irq_setup(dev_priv); } -static void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv, - u32 enabled_irqs) +static u32 bxt_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) { u32 hotplug; - hotplug = I915_READ(PCH_PORT_HOTPLUG); - hotplug |= PORTA_HOTPLUG_ENABLE | - PORTB_HOTPLUG_ENABLE | - PORTC_HOTPLUG_ENABLE; - - drm_dbg_kms(&dev_priv->drm, - "Invert bit setting: hp_ctl:%x hp_port:%x\n", - hotplug, enabled_irqs); - hotplug &= ~BXT_DDI_HPD_INVERT_MASK; - - /* - * For BXT invert bit has to be set based on AOB design - * for HPD detection logic, update it based on VBT fields. - */ - if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) && - intel_bios_is_port_hpd_inverted(dev_priv, PORT_A)) - hotplug |= BXT_DDIA_HPD_INVERT; - if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) && - intel_bios_is_port_hpd_inverted(dev_priv, PORT_B)) - hotplug |= BXT_DDIB_HPD_INVERT; - if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) && - intel_bios_is_port_hpd_inverted(dev_priv, PORT_C)) - hotplug |= BXT_DDIC_HPD_INVERT; - - I915_WRITE(PCH_PORT_HOTPLUG, hotplug); + switch (pin) { + case HPD_PORT_A: + hotplug = PORTA_HOTPLUG_ENABLE; + if (intel_bios_is_port_hpd_inverted(i915, PORT_A)) + hotplug |= BXT_DDIA_HPD_INVERT; + return hotplug; + case HPD_PORT_B: + hotplug = PORTB_HOTPLUG_ENABLE; + if (intel_bios_is_port_hpd_inverted(i915, PORT_B)) + hotplug |= BXT_DDIB_HPD_INVERT; + return hotplug; + case HPD_PORT_C: + hotplug = PORTC_HOTPLUG_ENABLE; + if (intel_bios_is_port_hpd_inverted(i915, PORT_C)) + hotplug |= BXT_DDIC_HPD_INVERT; + return hotplug; + default: + return 0; + } } static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv) { - __bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK); + u32 hotplug; + + hotplug = I915_READ(PCH_PORT_HOTPLUG); + hotplug &= ~(PORTA_HOTPLUG_ENABLE | + PORTB_HOTPLUG_ENABLE | + PORTC_HOTPLUG_ENABLE | + BXT_DDIA_HPD_INVERT | + BXT_DDIB_HPD_INVERT | + BXT_DDIC_HPD_INVERT); + hotplug |= intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables); + I915_WRITE(PCH_PORT_HOTPLUG, hotplug); } static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -3261,11 +3528,23 @@ static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); - __bxt_hpd_detection_setup(dev_priv, enabled_irqs); + bxt_hpd_detection_setup(dev_priv); } +/* + * SDEIER is also touched by the interrupt handler to work around missed PCH + * interrupts. Hence we can't update it after the interrupt handler is enabled - + * instead we unconditionally enable all PCH interrupt sources here, but then + * only unmask them as needed with SDEIMR. + * + * Note that we currently do this after installing the interrupt handler, + * but before we enable the master interrupt. That should be sufficient + * to avoid races with the irq handler, assuming we have MSI. Shared legacy + * interrupts could still race. + */ static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) { + struct intel_uncore *uncore = &dev_priv->uncore; u32 mask; if (HAS_PCH_NOP(dev_priv)) @@ -3278,14 +3557,7 @@ static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) else mask = SDE_GMBUS_CPT; - gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR); - I915_WRITE(SDEIMR, ~mask); - - if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) || - HAS_PCH_LPT(dev_priv)) - ibx_hpd_detection_setup(dev_priv); - else - spt_hpd_detection_setup(dev_priv); + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); } static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) @@ -3303,7 +3575,7 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | DE_POISON); - extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT | + extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | DE_DP_A_HOTPLUG); } @@ -3313,29 +3585,17 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) display_mask |= DE_EDP_PSR_INT_HSW; } - dev_priv->irq_mask = ~display_mask; + if (IS_IRONLAKE_M(dev_priv)) + extra_mask |= DE_PCU_EVENT; - ibx_irq_pre_postinstall(dev_priv); + dev_priv->irq_mask = ~display_mask; - GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask, - display_mask | extra_mask); + ibx_irq_postinstall(dev_priv); gen5_gt_irq_postinstall(&dev_priv->gt); - ilk_hpd_detection_setup(dev_priv); - - ibx_irq_postinstall(dev_priv); - - if (IS_IRONLAKE_M(dev_priv)) { - /* Enable PCU event interrupts - * - * spinlocking not required here for correctness since interrupt - * setup is guaranteed to run in single-threaded context. But we - * need it to make the assert_spin_locked happy. */ - spin_lock_irq(&dev_priv->irq_lock); - ilk_enable_display_irq(dev_priv, DE_PCU_EVENT); - spin_unlock_irq(&dev_priv->irq_lock); - } + GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask, + display_mask | extra_mask); } void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) @@ -3400,14 +3660,24 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) if (IS_GEN9_LP(dev_priv)) de_port_masked |= BXT_DE_PORT_GMBUS; + if (INTEL_GEN(dev_priv) >= 11) { + enum port port; + + if (intel_bios_is_dsi_present(dev_priv, &port)) + de_port_masked |= DSI0_TE | DSI1_TE; + } + de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN; + if (INTEL_GEN(dev_priv) >= 9) + de_pipe_enables |= GEN9_PIPE_PLANE1_FLIP_DONE; + de_port_enables = de_port_masked; if (IS_GEN9_LP(dev_priv)) de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; else if (IS_BROADWELL(dev_priv)) - de_port_enables |= GEN8_PORT_DP_A_HOTPLUG; + de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; if (INTEL_GEN(dev_priv) >= 12) { enum transcoder trans; @@ -3445,51 +3715,26 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, de_hpd_enables); - gen11_hpd_detection_setup(dev_priv); - } else if (IS_GEN9_LP(dev_priv)) { - bxt_hpd_detection_setup(dev_priv); - } else if (IS_BROADWELL(dev_priv)) { - ilk_hpd_detection_setup(dev_priv); } } static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) { if (HAS_PCH_SPLIT(dev_priv)) - ibx_irq_pre_postinstall(dev_priv); + ibx_irq_postinstall(dev_priv); gen8_gt_irq_postinstall(&dev_priv->gt); gen8_de_irq_postinstall(dev_priv); - if (HAS_PCH_SPLIT(dev_priv)) - ibx_irq_postinstall(dev_priv); - gen8_master_intr_enable(dev_priv->uncore.regs); } static void icp_irq_postinstall(struct drm_i915_private *dev_priv) { + struct intel_uncore *uncore = &dev_priv->uncore; u32 mask = SDE_GMBUS_ICP; - drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0); - I915_WRITE(SDEIER, 0xffffffff); - POSTING_READ(SDEIER); - - gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR); - I915_WRITE(SDEIMR, ~mask); - - if (HAS_PCH_TGP(dev_priv)) { - icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK); - icp_tc_hpd_detection_setup(dev_priv, TGP_TC_HPD_ENABLE_MASK); - } else if (HAS_PCH_JSP(dev_priv)) { - icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK); - } else if (HAS_PCH_MCC(dev_priv)) { - icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK); - icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE(PORT_TC1)); - } else { - icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK); - icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE_MASK); - } + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); } static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) @@ -3536,6 +3781,7 @@ static void i8xx_irq_reset(struct drm_i915_private *dev_priv) i9xx_pipestat_irq_reset(dev_priv); GEN2_IRQ_RESET(uncore); + dev_priv->irq_mask = ~0u; } static void i8xx_irq_postinstall(struct drm_i915_private *dev_priv) @@ -3705,6 +3951,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv) i9xx_pipestat_irq_reset(dev_priv); GEN3_IRQ_RESET(uncore, GEN2_); + dev_priv->irq_mask = ~0u; } static void i915_irq_postinstall(struct drm_i915_private *dev_priv) @@ -3811,6 +4058,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv) i9xx_pipestat_irq_reset(dev_priv); GEN3_IRQ_RESET(uncore, GEN2_); + dev_priv->irq_mask = ~0u; } static void i965_irq_postinstall(struct drm_i915_private *dev_priv) @@ -3958,10 +4206,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) struct drm_device *dev = &dev_priv->drm; int i; - intel_hpd_init_pins(dev_priv); - - intel_hpd_init_work(dev_priv); - INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work); for (i = 0; i < MAX_L3_SLICES; ++i) dev_priv->l3_parity.remap_info[i] = NULL; @@ -3970,6 +4214,13 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (HAS_GT_UC(dev_priv) && INTEL_GEN(dev_priv) < 11) dev_priv->gt.pm_guc_events = GUC_INTR_GUC2HOST << 16; + if (!HAS_DISPLAY(dev_priv)) + return; + + intel_hpd_init_pins(dev_priv); + + intel_hpd_init_work(dev_priv); + dev->vblank_disable_immediate = true; /* Most platforms treat the display irq block as an always-on @@ -3991,23 +4242,18 @@ void intel_irq_init(struct drm_i915_private *dev_priv) */ dev_priv->hotplug.hpd_short_storm_enabled = !HAS_DP_MST(dev_priv); - if (HAS_GMCH(dev_priv)) { - if (I915_HAS_HOTPLUG(dev_priv)) - dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; - } else { - if (HAS_PCH_JSP(dev_priv)) - dev_priv->display.hpd_irq_setup = jsp_hpd_irq_setup; - else if (HAS_PCH_MCC(dev_priv)) - dev_priv->display.hpd_irq_setup = mcc_hpd_irq_setup; - else if (INTEL_GEN(dev_priv) >= 11) - dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; - else if (IS_GEN9_LP(dev_priv)) - dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) - dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; - else - dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; - } + if (HAS_PCH_DG1(dev_priv)) + dev_priv->display.hpd_irq_setup = dg1_hpd_irq_setup; + else if (INTEL_GEN(dev_priv) >= 11) + dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; + else if (IS_GEN9_LP(dev_priv)) + dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) + dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; + else if (HAS_GMCH(dev_priv) && I915_HAS_HOTPLUG(dev_priv)) + dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; + else + dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; } /** diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h index 25f25cd95818..2efe609519ca 100644 --- a/drivers/gpu/drm/i915/i915_irq.h +++ b/drivers/gpu/drm/i915/i915_irq.h @@ -118,6 +118,9 @@ void i965_disable_vblank(struct drm_crtc *crtc); void ilk_disable_vblank(struct drm_crtc *crtc); void bdw_disable_vblank(struct drm_crtc *crtc); +void skl_enable_flip_done(struct intel_crtc *crtc); +void skl_disable_flip_done(struct intel_crtc *crtc); + void gen2_irq_reset(struct intel_uncore *uncore); void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr, i915_reg_t iir, i915_reg_t ier); diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index fb5e30de78c2..11fe790b1969 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -847,6 +847,14 @@ static const struct intel_device_info ehl_info = { .ppgtt_size = 36, }; +static const struct intel_device_info jsl_info = { + GEN11_FEATURES, + PLATFORM(INTEL_JASPERLAKE), + .require_force_probe = 1, + .platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(VCS0) | BIT(VECS0), + .ppgtt_size = 36, +}; + #define GEN12_FEATURES \ GEN11_FEATURES, \ GEN(12), \ @@ -901,6 +909,8 @@ static const struct intel_device_info rkl_info = { GEN12_FEATURES, \ .memory_regions = REGION_SMEM | REGION_LMEM, \ .has_master_unit_irq = 1, \ + .has_llc = 0, \ + .has_snoop = 1, \ .is_dgfx = 1 static const struct intel_device_info dg1_info __maybe_unused = { @@ -911,6 +921,8 @@ static const struct intel_device_info dg1_info __maybe_unused = { .platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0) | BIT(VCS2), + /* Wa_16011227922 */ + .ppgtt_size = 47, }; #undef GEN @@ -986,6 +998,7 @@ static const struct pci_device_id pciidlist[] = { INTEL_CNL_IDS(&cnl_info), INTEL_ICL_11_IDS(&icl_info), INTEL_EHL_IDS(&ehl_info), + INTEL_JSL_IDS(&jsl_info), INTEL_TGL_12_IDS(&tgl_info), INTEL_RKL_IDS(&rkl_info), {0, 0, 0} @@ -1091,11 +1104,19 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; } +static void i915_pci_shutdown(struct pci_dev *pdev) +{ + struct drm_i915_private *i915 = pci_get_drvdata(pdev); + + i915_driver_shutdown(i915); +} + static struct pci_driver i915_pci_driver = { .name = DRIVER_NAME, .id_table = pciidlist, .probe = i915_pci_probe, .remove = i915_pci_remove, + .shutdown = i915_pci_shutdown, .driver.pm = &i915_pm_ops, }; @@ -1130,9 +1151,13 @@ static int __init i915_init(void) return 0; } + i915_pmu_init(); + err = pci_register_driver(&i915_pci_driver); - if (err) + if (err) { + i915_pmu_exit(); return err; + } i915_perf_sysctl_register(); return 0; @@ -1146,6 +1171,7 @@ static void __exit i915_exit(void) i915_perf_sysctl_unregister(); pci_unregister_driver(&i915_pci_driver); i915_globals_exit(); + i915_pmu_exit(); } module_init(i915_init); diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 3640d0e229d2..3b12c8ff7182 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -625,7 +625,8 @@ static int append_oa_sample(struct i915_perf_stream *stream, } /** - * Copies all buffered OA reports into userspace read() buffer. + * gen8_append_oa_reports - Copies all buffered OA reports into + * userspace read() buffer. * @stream: An i915-perf stream opened for OA metrics * @buf: destination buffer given by userspace * @count: the number of bytes userspace wants to read @@ -922,7 +923,8 @@ static int gen8_oa_read(struct i915_perf_stream *stream, } /** - * Copies all buffered OA reports into userspace read() buffer. + * gen7_append_oa_reports - Copies all buffered OA reports into + * userspace read() buffer. * @stream: An i915-perf stream opened for OA metrics * @buf: destination buffer given by userspace * @count: the number of bytes userspace wants to read @@ -3232,7 +3234,7 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream, } /** - * i915_perf_ioctl - support ioctl() usage with i915 perf stream FDs + * i915_perf_ioctl_locked - support ioctl() usage with i915 perf stream FDs * @stream: An i915 perf stream * @cmd: the ioctl request * @arg: the ioctl data diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 69c0fa20eba1..cd786ad12be7 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -30,6 +30,7 @@ #define ENGINE_SAMPLE_BITS (1 << I915_PMU_SAMPLE_BITS) static cpumask_t i915_pmu_cpumask; +static unsigned int i915_pmu_target_cpu = -1; static u8 engine_config_sample(u64 config) { @@ -445,6 +446,8 @@ static void i915_pmu_event_destroy(struct perf_event *event) container_of(event->pmu, typeof(*i915), pmu.base); drm_WARN_ON(&i915->drm, event->parent); + + drm_dev_put(&i915->drm); } static int @@ -510,8 +513,12 @@ static int i915_pmu_event_init(struct perf_event *event) { struct drm_i915_private *i915 = container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = &i915->pmu; int ret; + if (pmu->closed) + return -ENODEV; + if (event->attr.type != event->pmu->type) return -ENOENT; @@ -536,8 +543,10 @@ static int i915_pmu_event_init(struct perf_event *event) if (ret) return ret; - if (!event->parent) + if (!event->parent) { + drm_dev_get(&i915->drm); event->destroy = i915_pmu_event_destroy; + } return 0; } @@ -594,9 +603,16 @@ static u64 __i915_pmu_event_read(struct perf_event *event) static void i915_pmu_event_read(struct perf_event *event) { + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); struct hw_perf_event *hwc = &event->hw; + struct i915_pmu *pmu = &i915->pmu; u64 prev, new; + if (pmu->closed) { + event->hw.state = PERF_HES_STOPPED; + return; + } again: prev = local64_read(&hwc->prev_count); new = __i915_pmu_event_read(event); @@ -724,6 +740,13 @@ static void i915_pmu_disable(struct perf_event *event) static void i915_pmu_event_start(struct perf_event *event, int flags) { + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = &i915->pmu; + + if (pmu->closed) + return; + i915_pmu_enable(event); event->hw.state = 0; } @@ -738,6 +761,13 @@ static void i915_pmu_event_stop(struct perf_event *event, int flags) static int i915_pmu_event_add(struct perf_event *event, int flags) { + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = &i915->pmu; + + if (pmu->closed) + return -ENODEV; + if (flags & PERF_EF_START) i915_pmu_event_start(event, flags); @@ -1020,25 +1050,39 @@ static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node) static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node) { struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node); - unsigned int target; + unsigned int target = i915_pmu_target_cpu; GEM_BUG_ON(!pmu->base.event_init); + /* + * Unregistering an instance generates a CPU offline event which we must + * ignore to avoid incorrectly modifying the shared i915_pmu_cpumask. + */ + if (pmu->closed) + return 0; + if (cpumask_test_and_clear_cpu(cpu, &i915_pmu_cpumask)) { target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu); + /* Migrate events if there is a valid target */ if (target < nr_cpu_ids) { cpumask_set_cpu(target, &i915_pmu_cpumask); - perf_pmu_migrate_context(&pmu->base, cpu, target); + i915_pmu_target_cpu = target; } } + if (target < nr_cpu_ids && target != pmu->cpuhp.cpu) { + perf_pmu_migrate_context(&pmu->base, cpu, target); + pmu->cpuhp.cpu = target; + } + return 0; } -static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu) +static enum cpuhp_state cpuhp_slot = CPUHP_INVALID; + +void i915_pmu_init(void) { - enum cpuhp_state slot; int ret; ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, @@ -1046,27 +1090,29 @@ static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu) i915_pmu_cpu_online, i915_pmu_cpu_offline); if (ret < 0) - return ret; + pr_notice("Failed to setup cpuhp state for i915 PMU! (%d)\n", + ret); + else + cpuhp_slot = ret; +} - slot = ret; - ret = cpuhp_state_add_instance(slot, &pmu->cpuhp.node); - if (ret) { - cpuhp_remove_multi_state(slot); - return ret; - } +void i915_pmu_exit(void) +{ + if (cpuhp_slot != CPUHP_INVALID) + cpuhp_remove_multi_state(cpuhp_slot); +} - pmu->cpuhp.slot = slot; - return 0; +static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu) +{ + if (cpuhp_slot == CPUHP_INVALID) + return -EINVAL; + + return cpuhp_state_add_instance(cpuhp_slot, &pmu->cpuhp.node); } static void i915_pmu_unregister_cpuhp_state(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); - - drm_WARN_ON(&i915->drm, pmu->cpuhp.slot == CPUHP_INVALID); - drm_WARN_ON(&i915->drm, cpuhp_state_remove_instance(pmu->cpuhp.slot, &pmu->cpuhp.node)); - cpuhp_remove_multi_state(pmu->cpuhp.slot); - pmu->cpuhp.slot = CPUHP_INVALID; + cpuhp_state_remove_instance(cpuhp_slot, &pmu->cpuhp.node); } static bool is_igp(struct drm_i915_private *i915) @@ -1100,7 +1146,7 @@ void i915_pmu_register(struct drm_i915_private *i915) spin_lock_init(&pmu->lock); hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); pmu->timer.function = i915_sample; - pmu->cpuhp.slot = CPUHP_INVALID; + pmu->cpuhp.cpu = -1; if (!is_igp(i915)) { pmu->name = kasprintf(GFP_KERNEL, @@ -1167,7 +1213,13 @@ void i915_pmu_unregister(struct drm_i915_private *i915) if (!pmu->base.event_init) return; - drm_WARN_ON(&i915->drm, pmu->enable); + /* + * "Disconnect" the PMU callbacks - since all are atomic synchronize_rcu + * ensures all currently executing ones will have exited before we + * proceed with unregistration. + */ + pmu->closed = true; + synchronize_rcu(); hrtimer_cancel(&pmu->timer); diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h index 941f0c14037c..a24885ab415c 100644 --- a/drivers/gpu/drm/i915/i915_pmu.h +++ b/drivers/gpu/drm/i915/i915_pmu.h @@ -43,13 +43,17 @@ struct i915_pmu { */ struct { struct hlist_node node; - enum cpuhp_state slot; + unsigned int cpu; } cpuhp; /** * @base: PMU base. */ struct pmu base; /** + * @closed: i915 is unregistering. + */ + bool closed; + /** * @name: Name as registered with perf core. */ const char *name; @@ -122,11 +126,15 @@ struct i915_pmu { }; #ifdef CONFIG_PERF_EVENTS +void i915_pmu_init(void); +void i915_pmu_exit(void); void i915_pmu_register(struct drm_i915_private *i915); void i915_pmu_unregister(struct drm_i915_private *i915); void i915_pmu_gt_parked(struct drm_i915_private *i915); void i915_pmu_gt_unparked(struct drm_i915_private *i915); #else +static inline void i915_pmu_init(void) {} +static inline void i915_pmu_exit(void) {} static inline void i915_pmu_register(struct drm_i915_private *i915) {} static inline void i915_pmu_unregister(struct drm_i915_private *i915) {} static inline void i915_pmu_gt_parked(struct drm_i915_private *i915) {} diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5cd83eac940c..5375b219cc3b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -230,19 +230,22 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b) #define _PORT(port, a, b) _PICK_EVEN(port, a, b) #define _PLL(pll, a, b) _PICK_EVEN(pll, a, b) +#define _PHY(phy, a, b) _PICK_EVEN(phy, a, b) #define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b)) #define _MMIO_PLANE(plane, a, b) _MMIO(_PLANE(plane, a, b)) #define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b)) #define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b)) #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b)) +#define _MMIO_PHY(phy, a, b) _MMIO(_PHY(phy, a, b)) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) #define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) #define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c)) -#define _MMIO_PLL3(pll, a, b, c) _MMIO(_PICK(pll, a, b, c)) +#define _MMIO_PLL3(pll, ...) _MMIO(_PICK(pll, __VA_ARGS__)) + /* * Device info offset array based helpers for groups of registers with unevenly @@ -2529,6 +2532,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define RING_PSMI_CTL(base) _MMIO((base) + 0x50) #define RING_MAX_IDLE(base) _MMIO((base) + 0x54) #define RING_HWS_PGA(base) _MMIO((base) + 0x80) +#define RING_ID(base) _MMIO((base) + 0x8c) #define RING_HWS_PGA_GEN6(base) _MMIO((base) + 0x2080) #define RING_RESET_CTL(base) _MMIO((base) + 0xd0) #define RESET_CTL_CAT_ERROR REG_BIT(2) @@ -4148,6 +4152,7 @@ enum { #define GEN9_CLKGATE_DIS_3 _MMIO(0x46538) #define TGL_VRH_GATING_DIS REG_BIT(31) +#define DPT_GATING_DIS REG_BIT(22) #define GEN9_CLKGATE_DIS_4 _MMIO(0x4653C) #define BXT_GMBUS_GATING_DIS (1 << 14) @@ -4620,6 +4625,110 @@ enum { #define PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME REG_BIT(2) #define PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE REG_BIT(1) +/* Icelake DSC Rate Control Range Parameter Registers */ +#define DSCA_RC_RANGE_PARAMETERS_0 _MMIO(0x6B240) +#define DSCA_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6B240 + 4) +#define DSCC_RC_RANGE_PARAMETERS_0 _MMIO(0x6BA40) +#define DSCC_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6BA40 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB (0x78208) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB (0x78208 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB (0x78308) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB (0x78308 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC (0x78408) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC (0x78408 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC (0x78508) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC (0x78508 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC) +#define RC_BPG_OFFSET_SHIFT 10 +#define RC_MAX_QP_SHIFT 5 +#define RC_MIN_QP_SHIFT 0 + +#define DSCA_RC_RANGE_PARAMETERS_1 _MMIO(0x6B248) +#define DSCA_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6B248 + 4) +#define DSCC_RC_RANGE_PARAMETERS_1 _MMIO(0x6BA48) +#define DSCC_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6BA48 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB (0x78210) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB (0x78210 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB (0x78310) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB (0x78310 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC (0x78410) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC (0x78410 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC (0x78510) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC (0x78510 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC) + +#define DSCA_RC_RANGE_PARAMETERS_2 _MMIO(0x6B250) +#define DSCA_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6B250 + 4) +#define DSCC_RC_RANGE_PARAMETERS_2 _MMIO(0x6BA50) +#define DSCC_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6BA50 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB (0x78218) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB (0x78218 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB (0x78318) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB (0x78318 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC (0x78418) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC (0x78418 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC (0x78518) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC (0x78518 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC) + +#define DSCA_RC_RANGE_PARAMETERS_3 _MMIO(0x6B258) +#define DSCA_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6B258 + 4) +#define DSCC_RC_RANGE_PARAMETERS_3 _MMIO(0x6BA58) +#define DSCC_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6BA58 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB (0x78220) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB (0x78220 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB (0x78320) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB (0x78320 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC (0x78420) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC (0x78420 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC (0x78520) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC (0x78520 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC) + /* VGA port control */ #define ADPA _MMIO(0x61100) #define PCH_ADPA _MMIO(0xe1100) @@ -6329,15 +6438,16 @@ enum { _MMIO(_PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe))) /* define the Watermark register on Ironlake */ -#define WM0_PIPEA_ILK _MMIO(0x45100) +#define _WM0_PIPEA_ILK 0x45100 +#define _WM0_PIPEB_ILK 0x45104 +#define _WM0_PIPEC_IVB 0x45200 +#define WM0_PIPE_ILK(pipe) _MMIO_PIPE3((pipe), _WM0_PIPEA_ILK, \ + _WM0_PIPEB_ILK, _WM0_PIPEC_IVB) #define WM0_PIPE_PLANE_MASK (0xffff << 16) #define WM0_PIPE_PLANE_SHIFT 16 #define WM0_PIPE_SPRITE_MASK (0xff << 8) #define WM0_PIPE_SPRITE_SHIFT 8 #define WM0_PIPE_CURSOR_MASK (0xff) - -#define WM0_PIPEB_ILK _MMIO(0x45104) -#define WM0_PIPEC_IVB _MMIO(0x45200) #define WM1_LP_ILK _MMIO(0x45108) #define WM1_LP_SR_EN (1 << 31) #define WM1_LP_LATENCY_SHIFT 24 @@ -6925,6 +7035,7 @@ enum { #define PLANE_CTL_TILED_X (1 << 10) #define PLANE_CTL_TILED_Y (4 << 10) #define PLANE_CTL_TILED_YF (5 << 10) +#define PLANE_CTL_ASYNC_FLIP (1 << 9) #define PLANE_CTL_FLIP_HORIZONTAL (1 << 8) #define PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE (1 << 4) /* TGL+ */ #define PLANE_CTL_ALPHA_MASK (0x3 << 4) /* Pre-GLK */ @@ -7381,6 +7492,7 @@ enum { #define PS_PLANE_SEL(plane) (((plane) + 1) << 25) #define PS_FILTER_MASK (3 << 23) #define PS_FILTER_MEDIUM (0 << 23) +#define PS_FILTER_PROGRAMMED (1 << 23) #define PS_FILTER_EDGE_ENHANCE (2 << 23) #define PS_FILTER_BILINEAR (3 << 23) #define PS_VERT3TAP (1 << 21) @@ -7395,6 +7507,10 @@ enum { #define PS_VADAPT_MODE_MOST_ADAPT (3 << 5) #define PS_PLANE_Y_SEL_MASK (7 << 5) #define PS_PLANE_Y_SEL(plane) (((plane) + 1) << 5) +#define PS_Y_VERT_FILTER_SELECT(set) ((set) << 4) +#define PS_Y_HORZ_FILTER_SELECT(set) ((set) << 3) +#define PS_UV_VERT_FILTER_SELECT(set) ((set) << 2) +#define PS_UV_HORZ_FILTER_SELECT(set) ((set) << 1) #define _PS_PWR_GATE_1A 0x68160 #define _PS_PWR_GATE_2A 0x68260 @@ -7457,6 +7573,17 @@ enum { #define _PS_ECC_STAT_2B 0x68AD0 #define _PS_ECC_STAT_1C 0x691D0 +#define _PS_COEF_SET0_INDEX_1A 0x68198 +#define _PS_COEF_SET0_INDEX_2A 0x68298 +#define _PS_COEF_SET0_INDEX_1B 0x68998 +#define _PS_COEF_SET0_INDEX_2B 0x68A98 +#define PS_COEE_INDEX_AUTO_INC (1 << 10) + +#define _PS_COEF_SET0_DATA_1A 0x6819C +#define _PS_COEF_SET0_DATA_2A 0x6829C +#define _PS_COEF_SET0_DATA_1B 0x6899C +#define _PS_COEF_SET0_DATA_2B 0x68A9C + #define _ID(id, a, b) _PICK_EVEN(id, a, b) #define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_1A_CTRL, _PS_2A_CTRL), \ @@ -7485,7 +7612,13 @@ enum { #define SKL_PS_ECC_STAT(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A), \ _ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B)) +#define CNL_PS_COEF_INDEX_SET(pipe, id, set) _MMIO_PIPE(pipe, \ + _ID(id, _PS_COEF_SET0_INDEX_1A, _PS_COEF_SET0_INDEX_2A) + (set) * 8, \ + _ID(id, _PS_COEF_SET0_INDEX_1B, _PS_COEF_SET0_INDEX_2B) + (set) * 8) +#define CNL_PS_COEF_DATA_SET(pipe, id, set) _MMIO_PIPE(pipe, \ + _ID(id, _PS_COEF_SET0_DATA_1A, _PS_COEF_SET0_DATA_2A) + (set) * 8, \ + _ID(id, _PS_COEF_SET0_DATA_1B, _PS_COEF_SET0_DATA_2B) + (set) * 8) /* legacy palette */ #define _LGC_PALETTE_A 0x4a000 #define _LGC_PALETTE_B 0x4a800 @@ -7534,6 +7667,7 @@ enum { #define BXT_CSR_DC3_DC5_COUNT _MMIO(0x80038) #define TGL_DMC_DEBUG_DC5_COUNT _MMIO(0x101084) #define TGL_DMC_DEBUG_DC6_COUNT _MMIO(0x101088) +#define DG1_DMC_DEBUG_DC5_COUNT _MMIO(0x134154) #define DMC_DEBUG3 _MMIO(0x101090) @@ -7683,6 +7817,9 @@ enum { (GEN9_DE_PIPE_IRQ_FAULT_ERRORS | \ GEN11_PIPE_PLANE5_FAULT) +#define _HPD_PIN_DDI(hpd_pin) ((hpd_pin) - HPD_PORT_A) +#define _HPD_PIN_TC(hpd_pin) ((hpd_pin) - HPD_PORT_TC1) + #define GEN8_DE_PORT_ISR _MMIO(0x44440) #define GEN8_DE_PORT_IMR _MMIO(0x44444) #define GEN8_DE_PORT_IIR _MMIO(0x44448) @@ -7696,13 +7833,11 @@ enum { #define GEN9_AUX_CHANNEL_B (1 << 25) #define DSI1_TE (1 << 24) #define DSI0_TE (1 << 23) -#define BXT_DE_PORT_HP_DDIC (1 << 5) -#define BXT_DE_PORT_HP_DDIB (1 << 4) -#define BXT_DE_PORT_HP_DDIA (1 << 3) -#define BXT_DE_PORT_HOTPLUG_MASK (BXT_DE_PORT_HP_DDIA | \ - BXT_DE_PORT_HP_DDIB | \ - BXT_DE_PORT_HP_DDIC) -#define GEN8_PORT_DP_A_HOTPLUG (1 << 3) +#define GEN8_DE_PORT_HOTPLUG(hpd_pin) REG_BIT(3 + _HPD_PIN_DDI(hpd_pin)) +#define BXT_DE_PORT_HOTPLUG_MASK (GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) | \ + GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) | \ + GEN8_DE_PORT_HOTPLUG(HPD_PORT_C)) +#define BDW_DE_PORT_HOTPLUG_MASK GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) #define BXT_DE_PORT_GMBUS (1 << 1) #define GEN8_AUX_CHANNEL_A (1 << 0) #define TGL_DE_PORT_AUX_USBC6 (1 << 13) @@ -7761,27 +7896,27 @@ enum { #define GEN11_DE_HPD_IMR _MMIO(0x44474) #define GEN11_DE_HPD_IIR _MMIO(0x44478) #define GEN11_DE_HPD_IER _MMIO(0x4447c) -#define GEN11_TC_HOTPLUG(tc_port) (1 << ((tc_port) + 16)) -#define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC_HOTPLUG(PORT_TC6) | \ - GEN11_TC_HOTPLUG(PORT_TC5) | \ - GEN11_TC_HOTPLUG(PORT_TC4) | \ - GEN11_TC_HOTPLUG(PORT_TC3) | \ - GEN11_TC_HOTPLUG(PORT_TC2) | \ - GEN11_TC_HOTPLUG(PORT_TC1)) -#define GEN11_TBT_HOTPLUG(tc_port) (1 << (tc_port)) -#define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT_HOTPLUG(PORT_TC6) | \ - GEN11_TBT_HOTPLUG(PORT_TC5) | \ - GEN11_TBT_HOTPLUG(PORT_TC4) | \ - GEN11_TBT_HOTPLUG(PORT_TC3) | \ - GEN11_TBT_HOTPLUG(PORT_TC2) | \ - GEN11_TBT_HOTPLUG(PORT_TC1)) +#define GEN11_TC_HOTPLUG(hpd_pin) REG_BIT(16 + _HPD_PIN_TC(hpd_pin)) +#define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC_HOTPLUG(HPD_PORT_TC6) | \ + GEN11_TC_HOTPLUG(HPD_PORT_TC5) | \ + GEN11_TC_HOTPLUG(HPD_PORT_TC4) | \ + GEN11_TC_HOTPLUG(HPD_PORT_TC3) | \ + GEN11_TC_HOTPLUG(HPD_PORT_TC2) | \ + GEN11_TC_HOTPLUG(HPD_PORT_TC1)) +#define GEN11_TBT_HOTPLUG(hpd_pin) REG_BIT(_HPD_PIN_TC(hpd_pin)) +#define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT_HOTPLUG(HPD_PORT_TC6) | \ + GEN11_TBT_HOTPLUG(HPD_PORT_TC5) | \ + GEN11_TBT_HOTPLUG(HPD_PORT_TC4) | \ + GEN11_TBT_HOTPLUG(HPD_PORT_TC3) | \ + GEN11_TBT_HOTPLUG(HPD_PORT_TC2) | \ + GEN11_TBT_HOTPLUG(HPD_PORT_TC1)) #define GEN11_TBT_HOTPLUG_CTL _MMIO(0x44030) #define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038) -#define GEN11_HOTPLUG_CTL_ENABLE(tc_port) (8 << (tc_port) * 4) -#define GEN11_HOTPLUG_CTL_LONG_DETECT(tc_port) (2 << (tc_port) * 4) -#define GEN11_HOTPLUG_CTL_SHORT_DETECT(tc_port) (1 << (tc_port) * 4) -#define GEN11_HOTPLUG_CTL_NO_DETECT(tc_port) (0 << (tc_port) * 4) +#define GEN11_HOTPLUG_CTL_ENABLE(hpd_pin) (8 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define GEN11_HOTPLUG_CTL_LONG_DETECT(hpd_pin) (2 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define GEN11_HOTPLUG_CTL_SHORT_DETECT(hpd_pin) (1 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define GEN11_HOTPLUG_CTL_NO_DETECT(hpd_pin) (0 << (_HPD_PIN_TC(hpd_pin) * 4)) #define GEN11_GT_INTR_DW0 _MMIO(0x190018) #define GEN11_CSME (31) @@ -7867,6 +8002,7 @@ enum { # define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) #define CHICKEN_PAR1_1 _MMIO(0x42080) +#define KBL_ARB_FILL_SPARE_22 REG_BIT(22) #define DIS_RAM_BYPASS_PSR2_MAN_TRACK (1 << 16) #define SKL_DE_COMPRESSED_HASH_MODE (1 << 15) #define DPA_MASK_VBLANK_SRD (1 << 15) @@ -7879,6 +8015,8 @@ enum { #define CHICKEN_MISC_2 _MMIO(0x42084) #define CNL_COMP_PWR_DOWN (1 << 23) +#define KBL_ARB_FILL_SPARE_14 REG_BIT(14) +#define KBL_ARB_FILL_SPARE_13 REG_BIT(13) #define GLK_CL2_PWR_DOWN (1 << 12) #define GLK_CL1_PWR_DOWN (1 << 11) #define GLK_CL0_PWR_DOWN (1 << 10) @@ -7921,11 +8059,15 @@ enum { #define DISP_ARB_CTL2 _MMIO(0x45004) #define DISP_DATA_PARTITION_5_6 (1 << 6) #define DISP_IPC_ENABLE (1 << 3) -#define _DBUF_CTL_S1 0x45008 -#define _DBUF_CTL_S2 0x44FE8 -#define DBUF_CTL_S(slice) _MMIO(_PICK_EVEN(slice, _DBUF_CTL_S1, _DBUF_CTL_S2)) -#define DBUF_POWER_REQUEST (1 << 31) -#define DBUF_POWER_STATE (1 << 30) + +#define _DBUF_CTL_S1 0x45008 +#define _DBUF_CTL_S2 0x44FE8 +#define DBUF_CTL_S(slice) _MMIO(_PICK_EVEN(slice, _DBUF_CTL_S1, _DBUF_CTL_S2)) +#define DBUF_POWER_REQUEST REG_BIT(31) +#define DBUF_POWER_STATE REG_BIT(30) +#define DBUF_TRACKER_STATE_SERVICE_MASK REG_GENMASK(23, 19) +#define DBUF_TRACKER_STATE_SERVICE(x) REG_FIELD_PREP(DBUF_TRACKER_STATE_SERVICE_MASK, x) + #define GEN7_MSG_CTL _MMIO(0x45010) #define WAIT_FOR_PCH_RESET_ACK (1 << 1) #define WAIT_FOR_PCH_FLR_ACK (1 << 0) @@ -8016,13 +8158,15 @@ enum { #define GEN8_L3CNTLREG _MMIO(0x7034) #define GEN8_ERRDETBCTRL (1 << 9) -#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) - #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC (1 << 11) - #define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE (1 << 9) +#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) + #define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12) + #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11) + #define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9) #define HIZ_CHICKEN _MMIO(0x7018) -# define CHV_HZ_8X8_MODE_IN_1X (1 << 15) -# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE (1 << 3) +# define CHV_HZ_8X8_MODE_IN_1X REG_BIT(15) +# define DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE REG_BIT(14) +# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE REG_BIT(3) #define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) #define DISABLE_PIXEL_MASK_CAMMING (1 << 14) @@ -8210,23 +8354,18 @@ enum { /* south display engine interrupt: ICP/TGP */ #define SDE_GMBUS_ICP (1 << 23) -#define SDE_TC_HOTPLUG_ICP(tc_port) (1 << ((tc_port) + 24)) -#define SDE_DDI_HOTPLUG_ICP(port) (1 << ((port) + 16)) -#define SDE_DDI_MASK_ICP (SDE_DDI_HOTPLUG_ICP(PORT_B) | \ - SDE_DDI_HOTPLUG_ICP(PORT_A)) -#define SDE_TC_MASK_ICP (SDE_TC_HOTPLUG_ICP(PORT_TC4) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC3) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC2) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC1)) -#define SDE_DDI_MASK_TGP (SDE_DDI_HOTPLUG_ICP(PORT_C) | \ - SDE_DDI_HOTPLUG_ICP(PORT_B) | \ - SDE_DDI_HOTPLUG_ICP(PORT_A)) -#define SDE_TC_MASK_TGP (SDE_TC_HOTPLUG_ICP(PORT_TC6) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC5) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC4) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC3) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC2) | \ - SDE_TC_HOTPLUG_ICP(PORT_TC1)) +#define SDE_TC_HOTPLUG_ICP(hpd_pin) REG_BIT(24 + _HPD_PIN_TC(hpd_pin)) +#define SDE_DDI_HOTPLUG_ICP(hpd_pin) REG_BIT(16 + _HPD_PIN_DDI(hpd_pin)) +#define SDE_DDI_HOTPLUG_MASK_ICP (SDE_DDI_HOTPLUG_ICP(HPD_PORT_D) | \ + SDE_DDI_HOTPLUG_ICP(HPD_PORT_C) | \ + SDE_DDI_HOTPLUG_ICP(HPD_PORT_B) | \ + SDE_DDI_HOTPLUG_ICP(HPD_PORT_A)) +#define SDE_TC_HOTPLUG_MASK_ICP (SDE_TC_HOTPLUG_ICP(HPD_PORT_TC6) | \ + SDE_TC_HOTPLUG_ICP(HPD_PORT_TC5) | \ + SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4) | \ + SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3) | \ + SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2) | \ + SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1)) #define SDEISR _MMIO(0xc4000) #define SDEIMR _MMIO(0xc4004) @@ -8294,139 +8433,21 @@ enum { */ #define SHOTPLUG_CTL_DDI _MMIO(0xc4030) -#define SHOTPLUG_CTL_DDI_HPD_ENABLE(port) (0x8 << (4 * (port))) -#define SHOTPLUG_CTL_DDI_HPD_STATUS_MASK(port) (0x3 << (4 * (port))) -#define SHOTPLUG_CTL_DDI_HPD_NO_DETECT(port) (0x0 << (4 * (port))) -#define SHOTPLUG_CTL_DDI_HPD_SHORT_DETECT(port) (0x1 << (4 * (port))) -#define SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(port) (0x2 << (4 * (port))) -#define SHOTPLUG_CTL_DDI_HPD_SHORT_LONG_DETECT(port) (0x3 << (4 * (port))) +#define SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin) (0x8 << (_HPD_PIN_DDI(hpd_pin) * 4)) +#define SHOTPLUG_CTL_DDI_HPD_STATUS_MASK(hpd_pin) (0x3 << (_HPD_PIN_DDI(hpd_pin) * 4)) +#define SHOTPLUG_CTL_DDI_HPD_NO_DETECT(hpd_pin) (0x0 << (_HPD_PIN_DDI(hpd_pin) * 4)) +#define SHOTPLUG_CTL_DDI_HPD_SHORT_DETECT(hpd_pin) (0x1 << (_HPD_PIN_DDI(hpd_pin) * 4)) +#define SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(hpd_pin) (0x2 << (_HPD_PIN_DDI(hpd_pin) * 4)) +#define SHOTPLUG_CTL_DDI_HPD_SHORT_LONG_DETECT(hpd_pin) (0x3 << (_HPD_PIN_DDI(hpd_pin) * 4)) #define SHOTPLUG_CTL_TC _MMIO(0xc4034) -#define ICP_TC_HPD_ENABLE(tc_port) (8 << (tc_port) * 4) +#define ICP_TC_HPD_ENABLE(hpd_pin) (8 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define ICP_TC_HPD_LONG_DETECT(hpd_pin) (2 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define ICP_TC_HPD_SHORT_DETECT(hpd_pin) (1 << (_HPD_PIN_TC(hpd_pin) * 4)) #define SHPD_FILTER_CNT _MMIO(0xc4038) #define SHPD_FILTER_CNT_500_ADJ 0x001D9 -/* Icelake DSC Rate Control Range Parameter Registers */ -#define DSCA_RC_RANGE_PARAMETERS_0 _MMIO(0x6B240) -#define DSCA_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6B240 + 4) -#define DSCC_RC_RANGE_PARAMETERS_0 _MMIO(0x6BA40) -#define DSCC_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6BA40 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB (0x78208) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB (0x78208 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB (0x78308) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB (0x78308 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC (0x78408) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC (0x78408 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC (0x78508) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC (0x78508 + 4) -#define ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC) -#define ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC) -#define RC_BPG_OFFSET_SHIFT 10 -#define RC_MAX_QP_SHIFT 5 -#define RC_MIN_QP_SHIFT 0 - -#define DSCA_RC_RANGE_PARAMETERS_1 _MMIO(0x6B248) -#define DSCA_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6B248 + 4) -#define DSCC_RC_RANGE_PARAMETERS_1 _MMIO(0x6BA48) -#define DSCC_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6BA48 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB (0x78210) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB (0x78210 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB (0x78310) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB (0x78310 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC (0x78410) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC (0x78410 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC (0x78510) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC (0x78510 + 4) -#define ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC) -#define ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC) - -#define DSCA_RC_RANGE_PARAMETERS_2 _MMIO(0x6B250) -#define DSCA_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6B250 + 4) -#define DSCC_RC_RANGE_PARAMETERS_2 _MMIO(0x6BA50) -#define DSCC_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6BA50 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB (0x78218) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB (0x78218 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB (0x78318) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB (0x78318 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC (0x78418) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC (0x78418 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC (0x78518) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC (0x78518 + 4) -#define ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC) -#define ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC) - -#define DSCA_RC_RANGE_PARAMETERS_3 _MMIO(0x6B258) -#define DSCA_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6B258 + 4) -#define DSCC_RC_RANGE_PARAMETERS_3 _MMIO(0x6BA58) -#define DSCC_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6BA58 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB (0x78220) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB (0x78220 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB (0x78320) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB (0x78320 + 4) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC (0x78420) -#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC (0x78420 + 4) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC (0x78520) -#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC (0x78520 + 4) -#define ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC) -#define ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB, \ - _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC) -#define ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB, \ - _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC) - -#define ICP_TC_HPD_LONG_DETECT(tc_port) (2 << (tc_port) * 4) -#define ICP_TC_HPD_SHORT_DETECT(tc_port) (1 << (tc_port) * 4) - -#define ICP_DDI_HPD_ENABLE_MASK (SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_B) | \ - SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_A)) -#define ICP_TC_HPD_ENABLE_MASK (ICP_TC_HPD_ENABLE(PORT_TC4) | \ - ICP_TC_HPD_ENABLE(PORT_TC3) | \ - ICP_TC_HPD_ENABLE(PORT_TC2) | \ - ICP_TC_HPD_ENABLE(PORT_TC1)) -#define TGP_DDI_HPD_ENABLE_MASK (SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_C) | \ - SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_B) | \ - SHOTPLUG_CTL_DDI_HPD_ENABLE(PORT_A)) -#define TGP_TC_HPD_ENABLE_MASK (ICP_TC_HPD_ENABLE(PORT_TC6) | \ - ICP_TC_HPD_ENABLE(PORT_TC5) | \ - ICP_TC_HPD_ENABLE_MASK) - #define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_B 0xc6018 #define PCH_DPLL(pll) _MMIO((pll) == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) @@ -8686,6 +8707,10 @@ enum { #define SOUTH_CHICKEN1 _MMIO(0xc2000) #define FDIA_PHASE_SYNC_SHIFT_OVR 19 #define FDIA_PHASE_SYNC_SHIFT_EN 18 +#define INVERT_DDID_HPD (1 << 18) +#define INVERT_DDIC_HPD (1 << 17) +#define INVERT_DDIB_HPD (1 << 16) +#define INVERT_DDIA_HPD (1 << 15) #define FDI_PHASE_SYNC_OVR(pipe) (1 << (FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) #define FDI_PHASE_SYNC_EN(pipe) (1 << (FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) #define FDI_BC_BIFURCATION_SELECT (1 << 12) @@ -8956,12 +8981,12 @@ enum { #define FORCEWAKE_MEDIA_VDBOX_GEN11(n) _MMIO(0xa540 + (n) * 4) #define FORCEWAKE_MEDIA_VEBOX_GEN11(n) _MMIO(0xa560 + (n) * 4) #define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278) -#define FORCEWAKE_BLITTER_GEN9 _MMIO(0xa188) +#define FORCEWAKE_GT_GEN9 _MMIO(0xa188) #define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0x0D88) #define FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(n) _MMIO(0x0D50 + (n) * 4) #define FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(n) _MMIO(0x0D70 + (n) * 4) #define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0x0D84) -#define FORCEWAKE_ACK_BLITTER_GEN9 _MMIO(0x130044) +#define FORCEWAKE_ACK_GT_GEN9 _MMIO(0x130044) #define FORCEWAKE_KERNEL BIT(0) #define FORCEWAKE_USER BIT(1) #define FORCEWAKE_KERNEL_FALLBACK BIT(15) @@ -9223,6 +9248,9 @@ enum { #define GEN9_SAGV_DISABLE 0x0 #define GEN9_SAGV_IS_DISABLED 0x1 #define GEN9_SAGV_ENABLE 0x3 +#define DG1_PCODE_STATUS 0x7E +#define DG1_UNCORE_GET_INIT_STATUS 0x0 +#define DG1_UNCORE_INIT_STATUS_COMPLETE 0x1 #define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23 #define GEN6_PCODE_DATA _MMIO(0x138128) #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 @@ -10257,6 +10285,7 @@ enum skl_power_gate { #define DPLL_CFGCR2_PDIV_2 (1 << 2) #define DPLL_CFGCR2_PDIV_3 (2 << 2) #define DPLL_CFGCR2_PDIV_7 (4 << 2) +#define DPLL_CFGCR2_PDIV_7_INVALID (5 << 2) #define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3) #define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR1) @@ -10273,12 +10302,13 @@ enum skl_power_gate { #define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) #define DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port) ((pll) << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) +/* ICL Clocks */ #define ICL_DPCLKA_CFGCR0 _MMIO(0x164280) #define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24)) #define RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT((phy) + 10) -#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < PORT_TC4 ? \ +#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < TC_PORT_4 ? \ (tc_port) + 12 : \ - (tc_port) - PORT_TC4 + 21)) + (tc_port) - TC_PORT_4 + 21)) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) ((phy) * 2) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (3 << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) @@ -10288,6 +10318,27 @@ enum skl_power_gate { #define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) \ ((pll) << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) +/* + * DG1 Clocks + * First registers controls the first A and B, while the second register + * controls the phy C and D. The bits on these registers are the + * same, but refer to different phys + */ +#define _DG1_DPCLKA_CFGCR0 0x164280 +#define _DG1_DPCLKA1_CFGCR0 0x16C280 +#define _DG1_DPCLKA_PHY_IDX(phy) ((phy) % 2) +#define _DG1_DPCLKA_PLL_IDX(pll) ((pll) % 2) +#define _DG1_PHY_DPLL_MAP(phy) ((phy) >= PHY_C ? DPLL_ID_DG1_DPLL2 : DPLL_ID_DG1_DPLL0) +#define DG1_DPCLKA_CFGCR0(phy) _MMIO_PHY((phy) / 2, \ + _DG1_DPCLKA_CFGCR0, \ + _DG1_DPCLKA1_CFGCR0) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT(_DG1_DPCLKA_PHY_IDX(phy) + 10) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) (_DG1_DPCLKA_PHY_IDX(phy) * 2) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) (_DG1_DPCLKA_PLL_IDX(pll) << DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (0x3 << DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy) \ + (((clk_sel) >> DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) + _DG1_PHY_DPLL_MAP(phy)) + /* CNL PLL */ #define DPLL0_ENABLE 0x46010 #define DPLL1_ENABLE 0x46014 @@ -10307,6 +10358,10 @@ enum skl_power_gate { #define MG_PLL_ENABLE(tc_port) _MMIO_PORT((tc_port), _MG_PLL1_ENABLE, \ _MG_PLL2_ENABLE) +/* DG1 PLL */ +#define DG1_DPLL_ENABLE(pll) _MMIO_PLL3(pll, DPLL0_ENABLE, DPLL1_ENABLE, \ + _MG_PLL1_ENABLE, _MG_PLL2_ENABLE) + #define _MG_REFCLKIN_CTL_PORT1 0x16892C #define _MG_REFCLKIN_CTL_PORT2 0x16992C #define _MG_REFCLKIN_CTL_PORT3 0x16A92C @@ -10523,6 +10578,20 @@ enum skl_power_gate { #define RKL_DPLL_CFGCR1(pll) _MMIO_PLL(pll, _TGL_DPLL0_CFGCR1, \ _TGL_DPLL1_CFGCR1) +#define _DG1_DPLL2_CFGCR0 0x16C284 +#define _DG1_DPLL3_CFGCR0 0x16C28C +#define DG1_DPLL_CFGCR0(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR0, \ + _TGL_DPLL1_CFGCR0, \ + _DG1_DPLL2_CFGCR0, \ + _DG1_DPLL3_CFGCR0) + +#define _DG1_DPLL2_CFGCR1 0x16C288 +#define _DG1_DPLL3_CFGCR1 0x16C290 +#define DG1_DPLL_CFGCR1(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR1, \ + _TGL_DPLL1_CFGCR1, \ + _DG1_DPLL2_CFGCR1, \ + _DG1_DPLL3_CFGCR1) + #define _DKL_PHY1_BASE 0x168000 #define _DKL_PHY2_BASE 0x169000 #define _DKL_PHY3_BASE 0x16A000 @@ -11003,14 +11072,17 @@ enum skl_power_gate { #define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C) #define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910) #define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000) +#define CGM_PIPE_DEGAMMA_RED_MASK REG_GENMASK(13, 0) +#define CGM_PIPE_DEGAMMA_GREEN_MASK REG_GENMASK(29, 16) +#define CGM_PIPE_DEGAMMA_BLUE_MASK REG_GENMASK(13, 0) #define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000) +#define CGM_PIPE_GAMMA_RED_MASK REG_GENMASK(9, 0) +#define CGM_PIPE_GAMMA_GREEN_MASK REG_GENMASK(25, 16) +#define CGM_PIPE_GAMMA_BLUE_MASK REG_GENMASK(9, 0) #define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00) #define CGM_PIPE_MODE_GAMMA (1 << 2) #define CGM_PIPE_MODE_CSC (1 << 1) #define CGM_PIPE_MODE_DEGAMMA (1 << 0) -#define CGM_PIPE_GAMMA_RED_MASK REG_GENMASK(9, 0) -#define CGM_PIPE_GAMMA_GREEN_MASK REG_GENMASK(25, 16) -#define CGM_PIPE_GAMMA_BLUE_MASK REG_GENMASK(9, 0) #define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900) #define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904) diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h index b7b59328cb76..9cb26a224034 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.h +++ b/drivers/gpu/drm/i915/i915_scatterlist.h @@ -27,13 +27,17 @@ static __always_inline struct sgt_iter { } __sgt_iter(struct scatterlist *sgl, bool dma) { struct sgt_iter s = { .sgp = sgl }; - if (s.sgp) { + if (dma && s.sgp && sg_dma_len(s.sgp) == 0) { + s.sgp = NULL; + } else if (s.sgp) { s.max = s.curr = s.sgp->offset; - s.max += s.sgp->length; - if (dma) + if (dma) { s.dma = sg_dma_address(s.sgp); - else + s.max += sg_dma_len(s.sgp); + } else { s.pfn = page_to_pfn(sg_page(s.sgp)); + s.max += s.sgp->length; + } } return s; @@ -44,6 +48,11 @@ static inline int __sg_page_count(const struct scatterlist *sg) return sg->length >> PAGE_SHIFT; } +static inline int __sg_dma_page_count(const struct scatterlist *sg) +{ + return sg_dma_len(sg) >> PAGE_SHIFT; +} + static inline struct scatterlist *____sg_next(struct scatterlist *sg) { ++sg; @@ -112,7 +121,7 @@ static inline unsigned int i915_sg_segment_size(void) unsigned int size = swiotlb_max_segment(); if (size == 0) - return SCATTERLIST_MAX_SEGMENT; + size = UINT_MAX; size = rounddown(size, PAGE_SIZE); /* swiotlb_max_segment_size can return 1 byte when it means one page. */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 7b64e7137270..db2111fc809e 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -32,45 +32,10 @@ #include "i915_reg.h" #include "i915_suspend.h" -static void i915_save_display(struct drm_i915_private *dev_priv) -{ - struct pci_dev *pdev = dev_priv->drm.pdev; - - /* Display arbitration control */ - if (INTEL_GEN(dev_priv) <= 4) - dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); - - if (IS_GEN(dev_priv, 4)) - pci_read_config_word(pdev, GCDGMBUS, - &dev_priv->regfile.saveGCDGMBUS); -} - -static void i915_restore_display(struct drm_i915_private *dev_priv) -{ - struct pci_dev *pdev = dev_priv->drm.pdev; - - if (IS_GEN(dev_priv, 4)) - pci_write_config_word(pdev, GCDGMBUS, - dev_priv->regfile.saveGCDGMBUS); - - /* Display arbitration */ - if (INTEL_GEN(dev_priv) <= 4) - I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); - - /* only restore FBC info on the platform that supports FBC*/ - intel_fbc_global_disable(dev_priv); - - intel_vga_redisable(dev_priv); - - intel_gmbus_reset(dev_priv); -} - -int i915_save_state(struct drm_i915_private *dev_priv) +static void intel_save_swf(struct drm_i915_private *dev_priv) { int i; - i915_save_display(dev_priv); - /* Scratch space */ if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) { for (i = 0; i < 7; i++) { @@ -90,16 +55,12 @@ int i915_save_state(struct drm_i915_private *dev_priv) for (i = 0; i < 3; i++) dev_priv->regfile.saveSWF3[i] = I915_READ(SWF3(i)); } - - return 0; } -int i915_restore_state(struct drm_i915_private *dev_priv) +static void intel_restore_swf(struct drm_i915_private *dev_priv) { int i; - i915_restore_display(dev_priv); - /* Scratch space */ if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) { for (i = 0; i < 7; i++) { @@ -119,6 +80,41 @@ int i915_restore_state(struct drm_i915_private *dev_priv) for (i = 0; i < 3; i++) I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]); } +} + +void i915_save_display(struct drm_i915_private *dev_priv) +{ + struct pci_dev *pdev = dev_priv->drm.pdev; + + /* Display arbitration control */ + if (INTEL_GEN(dev_priv) <= 4) + dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); - return 0; + if (IS_GEN(dev_priv, 4)) + pci_read_config_word(pdev, GCDGMBUS, + &dev_priv->regfile.saveGCDGMBUS); + + intel_save_swf(dev_priv); +} + +void i915_restore_display(struct drm_i915_private *dev_priv) +{ + struct pci_dev *pdev = dev_priv->drm.pdev; + + intel_restore_swf(dev_priv); + + if (IS_GEN(dev_priv, 4)) + pci_write_config_word(pdev, GCDGMBUS, + dev_priv->regfile.saveGCDGMBUS); + + /* Display arbitration */ + if (INTEL_GEN(dev_priv) <= 4) + I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); + + /* only restore FBC info on the platform that supports FBC*/ + intel_fbc_global_disable(dev_priv); + + intel_vga_redisable(dev_priv); + + intel_gmbus_reset(dev_priv); } diff --git a/drivers/gpu/drm/i915/i915_suspend.h b/drivers/gpu/drm/i915/i915_suspend.h index 3a36fb4ecc05..e5a611ee3d15 100644 --- a/drivers/gpu/drm/i915/i915_suspend.h +++ b/drivers/gpu/drm/i915/i915_suspend.h @@ -8,7 +8,7 @@ struct drm_i915_private; -int i915_save_state(struct drm_i915_private *i915); -int i915_restore_state(struct drm_i915_private *i915); +void i915_save_display(struct drm_i915_private *i915); +void i915_restore_display(struct drm_i915_private *i915); #endif /* __I915_SUSPEND_H__ */ diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index adc836f15fde..e67cec8fa2aa 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -62,6 +62,7 @@ static const char * const platform_names[] = { PLATFORM_NAME(CANNONLAKE), PLATFORM_NAME(ICELAKE), PLATFORM_NAME(ELKHARTLAKE), + PLATFORM_NAME(JASPERLAKE), PLATFORM_NAME(TIGERLAKE), PLATFORM_NAME(ROCKETLAKE), PLATFORM_NAME(DG1), diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 6a3d607218aa..d92fa041c700 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -79,6 +79,7 @@ enum intel_platform { /* gen11 */ INTEL_ICELAKE, INTEL_ELKHARTLAKE, + INTEL_JASPERLAKE, /* gen12 */ INTEL_TIGERLAKE, INTEL_ROCKETLAKE, diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index 8aa12cad93ce..4754296a250e 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -7,7 +7,8 @@ #include "intel_dram.h" struct dram_dimm_info { - u8 size, width, ranks; + u16 size; + u8 width, ranks; }; struct dram_channel_info { @@ -41,10 +42,10 @@ static int intel_dimm_num_devices(const struct dram_dimm_info *dimm) return dimm->ranks * 64 / (dimm->width ?: 1); } -/* Returns total GB for the whole DIMM */ +/* Returns total Gb for the whole DIMM */ static int skl_get_dimm_size(u16 val) { - return val & SKL_DRAM_SIZE_MASK; + return (val & SKL_DRAM_SIZE_MASK) * 8; } static int skl_get_dimm_width(u16 val) @@ -74,10 +75,10 @@ static int skl_get_dimm_ranks(u16 val) return val + 1; } -/* Returns total GB for the whole DIMM */ +/* Returns total Gb for the whole DIMM */ static int cnl_get_dimm_size(u16 val) { - return (val & CNL_DRAM_SIZE_MASK) / 2; + return (val & CNL_DRAM_SIZE_MASK) * 8 / 2; } static int cnl_get_dimm_width(u16 val) @@ -110,8 +111,8 @@ static int cnl_get_dimm_ranks(u16 val) static bool skl_is_16gb_dimm(const struct dram_dimm_info *dimm) { - /* Convert total GB to Gb per DRAM device */ - return 8 * dimm->size / (intel_dimm_num_devices(dimm) ?: 1) == 16; + /* Convert total Gb to Gb per DRAM device */ + return dimm->size / (intel_dimm_num_devices(dimm) ?: 1) == 16; } static void @@ -130,7 +131,7 @@ skl_dram_get_dimm_info(struct drm_i915_private *i915, } drm_dbg_kms(&i915->drm, - "CH%u DIMM %c size: %u GB, width: X%u, ranks: %u, 16Gb DIMMs: %s\n", + "CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb DIMMs: %s\n", channel, dimm_name, dimm->size, dimm->width, dimm->ranks, yesno(skl_is_16gb_dimm(dimm))); } @@ -354,9 +355,9 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val) /* * Size in register is Gb per DRAM device. Convert to total - * GB to match the way we report this for non-LP platforms. + * Gb to match the way we report this for non-LP platforms. */ - dimm->size = bxt_get_dimm_size(val) * intel_dimm_num_devices(dimm) / 8; + dimm->size = bxt_get_dimm_size(val) * intel_dimm_num_devices(dimm); } static int bxt_get_dram_info(struct drm_i915_private *i915) @@ -404,7 +405,7 @@ static int bxt_get_dram_info(struct drm_i915_private *i915) dram_info->type != type); drm_dbg_kms(&i915->drm, - "CH%u DIMM size: %u GB, width: X%u, ranks: %u, type: %s\n", + "CH%u DIMM size: %u Gb, width: X%u, ranks: %u, type: %s\n", i - BXT_D_CR_DRP0_DUNIT_START, dimm.size, dimm.width, dimm.ranks, intel_dram_type_str(type)); diff --git a/drivers/gpu/drm/i915/intel_gvt.c b/drivers/gpu/drm/i915/intel_gvt.c index 99fe8aef1c67..4e70c1a9ef2e 100644 --- a/drivers/gpu/drm/i915/intel_gvt.c +++ b/drivers/gpu/drm/i915/intel_gvt.c @@ -24,6 +24,7 @@ #include "i915_drv.h" #include "i915_vgpu.h" #include "intel_gvt.h" +#include "gvt/gvt.h" /** * DOC: Intel GVT-g host support @@ -147,3 +148,17 @@ void intel_gvt_driver_remove(struct drm_i915_private *dev_priv) intel_gvt_clean_device(dev_priv); } + +/** + * intel_gvt_resume - GVT resume routine wapper + * + * @dev_priv: drm i915 private * + * + * This function is called at the i915 driver resume stage to restore required + * HW status for GVT so that vGPU can continue running after resumed. + */ +void intel_gvt_resume(struct drm_i915_private *dev_priv) +{ + if (intel_gvt_active(dev_priv)) + intel_gvt_pm_resume(dev_priv->gvt); +} diff --git a/drivers/gpu/drm/i915/intel_gvt.h b/drivers/gpu/drm/i915/intel_gvt.h index 502fad8a8652..d7d3fb6186fd 100644 --- a/drivers/gpu/drm/i915/intel_gvt.h +++ b/drivers/gpu/drm/i915/intel_gvt.h @@ -33,6 +33,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv); void intel_gvt_clean_device(struct drm_i915_private *dev_priv); int intel_gvt_init_host(void); void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv); +void intel_gvt_resume(struct drm_i915_private *dev_priv); #else static inline int intel_gvt_init(struct drm_i915_private *dev_priv) { @@ -46,6 +47,10 @@ static inline void intel_gvt_driver_remove(struct drm_i915_private *dev_priv) static inline void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv) { } + +static inline void intel_gvt_resume(struct drm_i915_private *dev_priv) +{ +} #endif #endif /* _INTEL_GVT_H_ */ diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 180e1078ef7c..b326993a1026 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -114,7 +114,7 @@ __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem, n_pages -= BIT(order); block->private = mem; - list_add(&block->link, blocks); + list_add_tail(&block->link, blocks); if (!n_pages) break; diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/intel_pch.c index 6c97192e9ca8..f31c0dabd0cc 100644 --- a/drivers/gpu/drm/i915/intel_pch.c +++ b/drivers/gpu/drm/i915/intel_pch.c @@ -115,7 +115,7 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) return PCH_ICP; case INTEL_PCH_MCC_DEVICE_ID_TYPE: drm_dbg_kms(&dev_priv->drm, "Found Mule Creek Canyon PCH\n"); - drm_WARN_ON(&dev_priv->drm, !IS_ELKHARTLAKE(dev_priv)); + drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv)); return PCH_MCC; case INTEL_PCH_TGP_DEVICE_ID_TYPE: case INTEL_PCH_TGP2_DEVICE_ID_TYPE: @@ -126,7 +126,7 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) case INTEL_PCH_JSP_DEVICE_ID_TYPE: case INTEL_PCH_JSP2_DEVICE_ID_TYPE: drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n"); - drm_WARN_ON(&dev_priv->drm, !IS_ELKHARTLAKE(dev_priv)); + drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv)); return PCH_JSP; default: return PCH_NONE; @@ -157,7 +157,7 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv) if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) id = INTEL_PCH_TGP_DEVICE_ID_TYPE; - else if (IS_ELKHARTLAKE(dev_priv)) + else if (IS_JSL_EHL(dev_priv)) id = INTEL_PCH_MCC_DEVICE_ID_TYPE; else if (IS_ICELAKE(dev_priv)) id = INTEL_PCH_ICP_DEVICE_ID_TYPE; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cfb806767fc5..a20b5051f18c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -33,6 +33,7 @@ #include <drm/drm_plane_helper.h> #include "display/intel_atomic.h" +#include "display/intel_atomic_plane.h" #include "display/intel_bw.h" #include "display/intel_display_types.h" #include "display/intel_fbc.h" @@ -899,12 +900,12 @@ static void pnv_update_wm(struct intel_crtc *unused_crtc) crtc = single_enabled_crtc(dev_priv); if (crtc) { - const struct drm_display_mode *adjusted_mode = - &crtc->config->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc->config->hw.pipe_mode; const struct drm_framebuffer *fb = crtc->base.primary->state->fb; int cpp = fb->format->cpp[0]; - int clock = adjusted_mode->crtc_clock; + int clock = pipe_mode->crtc_clock; /* Display SR */ wm = intel_calculate_wm(clock, &pnv_display_wm, @@ -1135,8 +1136,8 @@ static u16 g4x_compute_wm(const struct intel_crtc_state *crtc_state, { 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_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc_state->hw.pipe_mode; unsigned int latency = dev_priv->wm.pri_latency[level] * 10; unsigned int clock, htotal, cpp, width, wm; @@ -1163,8 +1164,8 @@ static u16 g4x_compute_wm(const struct intel_crtc_state *crtc_state, level != G4X_WM_LEVEL_NORMAL) cpp = max(cpp, 4u); - clock = adjusted_mode->crtc_clock; - htotal = adjusted_mode->crtc_htotal; + clock = pipe_mode->crtc_clock; + htotal = pipe_mode->crtc_htotal; width = drm_rect_width(&plane_state->uapi.dst); @@ -1660,8 +1661,8 @@ static u16 vlv_compute_wm_level(const struct intel_crtc_state *crtc_state, { 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_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc_state->hw.pipe_mode; unsigned int clock, htotal, cpp, width, wm; if (dev_priv->wm.pri_latency[level] == 0) @@ -1671,8 +1672,8 @@ static u16 vlv_compute_wm_level(const struct intel_crtc_state *crtc_state, return 0; cpp = plane_state->hw.fb->format->cpp[0]; - clock = adjusted_mode->crtc_clock; - htotal = adjusted_mode->crtc_htotal; + clock = pipe_mode->crtc_clock; + htotal = pipe_mode->crtc_htotal; width = crtc_state->pipe_src_w; if (plane->id == PLANE_CURSOR) { @@ -2261,12 +2262,12 @@ static void i965_update_wm(struct intel_crtc *unused_crtc) if (crtc) { /* self-refresh has much higher latency */ static const int sr_latency_ns = 12000; - const struct drm_display_mode *adjusted_mode = - &crtc->config->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc->config->hw.pipe_mode; const struct drm_framebuffer *fb = crtc->base.primary->state->fb; - int clock = adjusted_mode->crtc_clock; - int htotal = adjusted_mode->crtc_htotal; + int clock = pipe_mode->crtc_clock; + int htotal = pipe_mode->crtc_htotal; int hdisplay = crtc->config->pipe_src_w; int cpp = fb->format->cpp[0]; int entries; @@ -2345,8 +2346,8 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_A); crtc = intel_get_crtc_for_plane(dev_priv, PLANE_A); if (intel_crtc_active(crtc)) { - const struct drm_display_mode *adjusted_mode = - &crtc->config->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc->config->hw.pipe_mode; const struct drm_framebuffer *fb = crtc->base.primary->state->fb; int cpp; @@ -2356,7 +2357,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) else cpp = fb->format->cpp[0]; - planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock, + planea_wm = intel_calculate_wm(pipe_mode->crtc_clock, wm_info, fifo_size, cpp, pessimal_latency_ns); enabled = crtc; @@ -2372,8 +2373,8 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B); crtc = intel_get_crtc_for_plane(dev_priv, PLANE_B); if (intel_crtc_active(crtc)) { - const struct drm_display_mode *adjusted_mode = - &crtc->config->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc->config->hw.pipe_mode; const struct drm_framebuffer *fb = crtc->base.primary->state->fb; int cpp; @@ -2383,7 +2384,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) else cpp = fb->format->cpp[0]; - planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock, + planeb_wm = intel_calculate_wm(pipe_mode->crtc_clock, wm_info, fifo_size, cpp, pessimal_latency_ns); if (enabled == NULL) @@ -2421,12 +2422,12 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) if (HAS_FW_BLC(dev_priv) && enabled) { /* self-refresh has much higher latency */ static const int sr_latency_ns = 6000; - const struct drm_display_mode *adjusted_mode = - &enabled->config->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &enabled->config->hw.pipe_mode; const struct drm_framebuffer *fb = enabled->base.primary->state->fb; - int clock = adjusted_mode->crtc_clock; - int htotal = adjusted_mode->crtc_htotal; + int clock = pipe_mode->crtc_clock; + int htotal = pipe_mode->crtc_htotal; int hdisplay = enabled->config->pipe_src_w; int cpp; int entries; @@ -2474,7 +2475,7 @@ static void i845_update_wm(struct intel_crtc *unused_crtc) { struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev); struct intel_crtc *crtc; - const struct drm_display_mode *adjusted_mode; + const struct drm_display_mode *pipe_mode; u32 fwater_lo; int planea_wm; @@ -2482,8 +2483,8 @@ static void i845_update_wm(struct intel_crtc *unused_crtc) if (crtc == NULL) return; - adjusted_mode = &crtc->config->hw.adjusted_mode; - planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock, + pipe_mode = &crtc->config->hw.pipe_mode; + planea_wm = intel_calculate_wm(pipe_mode->crtc_clock, &i845_wm_info, dev_priv->display.get_fifo_size(dev_priv, PLANE_A), 4, pessimal_latency_ns); @@ -2573,7 +2574,7 @@ static u32 ilk_compute_pri_wm(const struct intel_crtc_state *crtc_state, return method1; method2 = ilk_wm_method2(crtc_state->pixel_rate, - crtc_state->hw.adjusted_mode.crtc_htotal, + crtc_state->hw.pipe_mode.crtc_htotal, drm_rect_width(&plane_state->uapi.dst), cpp, mem_value); @@ -2601,7 +2602,7 @@ static u32 ilk_compute_spr_wm(const struct intel_crtc_state *crtc_state, method1 = ilk_wm_method1(crtc_state->pixel_rate, cpp, mem_value); method2 = ilk_wm_method2(crtc_state->pixel_rate, - crtc_state->hw.adjusted_mode.crtc_htotal, + crtc_state->hw.pipe_mode.crtc_htotal, drm_rect_width(&plane_state->uapi.dst), cpp, mem_value); return min(method1, method2); @@ -2626,7 +2627,7 @@ static u32 ilk_compute_cur_wm(const struct intel_crtc_state *crtc_state, cpp = plane_state->hw.fb->format->cpp[0]; return ilk_wm_method2(crtc_state->pixel_rate, - crtc_state->hw.adjusted_mode.crtc_htotal, + crtc_state->hw.pipe_mode.crtc_htotal, drm_rect_width(&plane_state->uapi.dst), cpp, mem_value); } @@ -3573,11 +3574,11 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv, _ilk_disable_lp_wm(dev_priv, dirty); if (dirty & WM_DIRTY_PIPE(PIPE_A)) - I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); + I915_WRITE(WM0_PIPE_ILK(PIPE_A), results->wm_pipe[0]); if (dirty & WM_DIRTY_PIPE(PIPE_B)) - I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]); + I915_WRITE(WM0_PIPE_ILK(PIPE_B), results->wm_pipe[1]); if (dirty & WM_DIRTY_PIPE(PIPE_C)) - I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]); + I915_WRITE(WM0_PIPE_ILK(PIPE_C), results->wm_pipe[2]); if (dirty & WM_DIRTY_DDB) { if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { @@ -3706,7 +3707,7 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) * - All planes can enable watermarks for latencies >= SAGV engine block time * - We're not using an interlaced display configuration */ -int +static int intel_enable_sagv(struct drm_i915_private *dev_priv) { int ret; @@ -3740,7 +3741,7 @@ intel_enable_sagv(struct drm_i915_private *dev_priv) return 0; } -int +static int intel_disable_sagv(struct drm_i915_private *dev_priv) { int ret; @@ -3873,9 +3874,7 @@ static bool skl_crtc_can_enable_sagv(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); - struct intel_plane *plane; - const struct intel_plane_state *plane_state; - int level, latency; + enum plane_id plane_id; if (!intel_has_sagv(dev_priv)) return false; @@ -3883,12 +3882,13 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) if (!crtc_state->hw.active) return true; - if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) + if (crtc_state->hw.pipe_mode.flags & DRM_MODE_FLAG_INTERLACE) return false; - intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { + for_each_plane_id_on_crtc(crtc, plane_id) { const struct skl_plane_wm *wm = - &crtc_state->wm.skl.optimal.planes[plane->id]; + &crtc_state->wm.skl.optimal.planes[plane_id]; + int level; /* Skip this plane if it's not enabled */ if (!wm->wm[0].plane_en) @@ -3899,19 +3899,12 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) !wm->wm[level].plane_en; --level) { } - latency = dev_priv->wm.skl_latency[level]; - - if (skl_needs_memory_bw_wa(dev_priv) && - plane_state->uapi.fb->modifier == - I915_FORMAT_MOD_X_TILED) - latency += 15; - /* * If any of the planes on this pipe don't enable wm levels that * incur memory latencies higher than sagv_block_time_us we * can't enable SAGV. */ - if (latency < dev_priv->sagv_block_time_us) + if (!wm->wm[level].can_sagv) return false; } @@ -4174,8 +4167,8 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, */ total_slice_mask = dbuf_slice_mask; for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) { - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *pipe_mode = + &crtc_state->hw.pipe_mode; enum pipe pipe = crtc->pipe; int hdisplay, vdisplay; u32 pipe_dbuf_slice_mask; @@ -4205,7 +4198,7 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, if (dbuf_slice_mask != pipe_dbuf_slice_mask) continue; - drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay); + drm_mode_get_hv_timing(pipe_mode, &hdisplay, &vdisplay); total_width_in_range += hdisplay; @@ -4704,50 +4697,63 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, } static u64 -skl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state, - u64 *plane_data_rate, - u64 *uv_plane_data_rate) +skl_get_total_relative_data_rate(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_plane *plane; + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); const struct intel_plane_state *plane_state; + struct intel_plane *plane; u64 total_data_rate = 0; + enum plane_id plane_id; + int i; /* Calculate and cache data rate for each plane */ - intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { - enum plane_id plane_id = plane->id; - u64 rate; + for_each_new_intel_plane_in_state(state, plane, plane_state, i) { + if (plane->pipe != crtc->pipe) + continue; + + plane_id = plane->id; /* packed/y */ - rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0); - plane_data_rate[plane_id] = rate; - total_data_rate += rate; + crtc_state->plane_data_rate[plane_id] = + skl_plane_relative_data_rate(crtc_state, plane_state, 0); /* uv-plane */ - rate = skl_plane_relative_data_rate(crtc_state, plane_state, 1); - uv_plane_data_rate[plane_id] = rate; - total_data_rate += rate; + crtc_state->uv_plane_data_rate[plane_id] = + skl_plane_relative_data_rate(crtc_state, plane_state, 1); + } + + for_each_plane_id_on_crtc(crtc, plane_id) { + total_data_rate += crtc_state->plane_data_rate[plane_id]; + total_data_rate += crtc_state->uv_plane_data_rate[plane_id]; } return total_data_rate; } static u64 -icl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state, - u64 *plane_data_rate) +icl_get_total_relative_data_rate(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_plane *plane; + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); const struct intel_plane_state *plane_state; + struct intel_plane *plane; u64 total_data_rate = 0; + enum plane_id plane_id; + int i; /* Calculate and cache data rate for each plane */ - intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { - enum plane_id plane_id = plane->id; - u64 rate; + for_each_new_intel_plane_in_state(state, plane, plane_state, i) { + if (plane->pipe != crtc->pipe) + continue; + + plane_id = plane->id; if (!plane_state->planar_linked_plane) { - rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0); - plane_data_rate[plane_id] = rate; - total_data_rate += rate; + crtc_state->plane_data_rate[plane_id] = + skl_plane_relative_data_rate(crtc_state, plane_state, 0); } else { enum plane_id y_plane_id; @@ -4762,17 +4768,18 @@ icl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state, continue; /* Y plane rate is calculated on the slave */ - rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0); y_plane_id = plane_state->planar_linked_plane->id; - plane_data_rate[y_plane_id] = rate; - total_data_rate += rate; + crtc_state->plane_data_rate[y_plane_id] = + skl_plane_relative_data_rate(crtc_state, plane_state, 0); - rate = skl_plane_relative_data_rate(crtc_state, plane_state, 1); - plane_data_rate[plane_id] = rate; - total_data_rate += rate; + crtc_state->plane_data_rate[plane_id] = + skl_plane_relative_data_rate(crtc_state, plane_state, 1); } } + for_each_plane_id_on_crtc(crtc, plane_id) + total_data_rate += crtc_state->plane_data_rate[plane_id]; + return total_data_rate; } @@ -4791,9 +4798,11 @@ skl_plane_wm_level(const struct intel_crtc_state *crtc_state, } static int -skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state) +skl_allocate_pipe_ddb(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct skl_ddb_entry *alloc = &crtc_state->wm.skl.ddb; u16 alloc_size, start = 0; @@ -4802,8 +4811,6 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state) u64 total_data_rate; enum plane_id plane_id; int num_active; - u64 plane_data_rate[I915_MAX_PLANES] = {}; - u64 uv_plane_data_rate[I915_MAX_PLANES] = {}; u32 blocks; int level; int ret; @@ -4843,13 +4850,10 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state) if (INTEL_GEN(dev_priv) >= 11) total_data_rate = - icl_get_total_relative_data_rate(crtc_state, - plane_data_rate); + icl_get_total_relative_data_rate(state, crtc); else total_data_rate = - skl_get_total_relative_data_rate(crtc_state, - plane_data_rate, - uv_plane_data_rate); + skl_get_total_relative_data_rate(state, crtc); ret = skl_ddb_get_pipe_allocation_limits(dev_priv, crtc_state, total_data_rate, @@ -4930,7 +4934,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state) if (total_data_rate == 0) break; - rate = plane_data_rate[plane_id]; + rate = crtc_state->plane_data_rate[plane_id]; extra = min_t(u16, alloc_size, DIV64_U64_ROUND_UP(alloc_size * rate, total_data_rate)); @@ -4941,7 +4945,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state) if (total_data_rate == 0) break; - rate = uv_plane_data_rate[plane_id]; + rate = crtc_state->uv_plane_data_rate[plane_id]; extra = min_t(u16, alloc_size, DIV64_U64_ROUND_UP(alloc_size * rate, total_data_rate)); @@ -5093,36 +5097,12 @@ intel_get_linetime_us(const struct intel_crtc_state *crtc_state) if (drm_WARN_ON(&dev_priv->drm, pixel_rate == 0)) return u32_to_fixed16(0); - crtc_htotal = crtc_state->hw.adjusted_mode.crtc_htotal; + crtc_htotal = crtc_state->hw.pipe_mode.crtc_htotal; linetime_us = div_fixed16(crtc_htotal * 1000, pixel_rate); return linetime_us; } -static u32 -skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - u64 adjusted_pixel_rate; - uint_fixed_16_16_t downscale_amount; - - /* Shouldn't reach here on disabled planes... */ - if (drm_WARN_ON(&dev_priv->drm, - !intel_wm_plane_visible(crtc_state, plane_state))) - return 0; - - /* - * Adjusted plane pixel rate is just the pipe's adjusted pixel rate - * with additional adjustments for plane-specific scaling. - */ - adjusted_pixel_rate = crtc_state->pixel_rate; - downscale_amount = skl_plane_downscale_amount(crtc_state, plane_state); - - return mul_round_up_u32_fixed16(adjusted_pixel_rate, - downscale_amount); -} - static int skl_compute_wm_params(const struct intel_crtc_state *crtc_state, int width, const struct drm_format_info *format, @@ -5235,7 +5215,7 @@ skl_compute_plane_wm_params(const struct intel_crtc_state *crtc_state, return skl_compute_wm_params(crtc_state, width, fb->format, fb->modifier, plane_state->hw.rotation, - skl_adjusted_plane_pixel_rate(crtc_state, plane_state), + intel_plane_pixel_rate(crtc_state, plane_state), wp, color_plane); } @@ -5282,14 +5262,14 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, method1 = skl_wm_method1(dev_priv, wp->plane_pixel_rate, wp->cpp, latency, wp->dbuf_block_size); method2 = skl_wm_method2(wp->plane_pixel_rate, - crtc_state->hw.adjusted_mode.crtc_htotal, + crtc_state->hw.pipe_mode.crtc_htotal, latency, wp->plane_blocks_per_line); if (wp->y_tiled) { selected_result = max_fixed16(method2, wp->y_tile_minimum); } else { - if ((wp->cpp * crtc_state->hw.adjusted_mode.crtc_htotal / + if ((wp->cpp * crtc_state->hw.pipe_mode.crtc_htotal / wp->dbuf_block_size < 1) && (wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) { selected_result = method2; @@ -5373,6 +5353,9 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, /* Bspec says: value >= plane ddb allocation -> invalid, hence the +1 here */ result->min_ddb_alloc = max(min_ddb_alloc, res_blocks) + 1; result->plane_en = true; + + if (INTEL_GEN(dev_priv) < 12) + result->can_sagv = latency >= dev_priv->sagv_block_time_us; } static void @@ -5478,7 +5461,7 @@ static int skl_build_plane_wm_single(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); - struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; + struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id]; struct skl_wm_params wm_params; int ret; @@ -5501,7 +5484,7 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, enum plane_id plane_id) { - struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; + struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id]; struct skl_wm_params wm_params; int ret; @@ -5522,10 +5505,13 @@ static int skl_build_plane_wm(struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; enum plane_id plane_id = plane->id; + struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id]; + const struct drm_framebuffer *fb = plane_state->hw.fb; int ret; + memset(wm, 0, sizeof(*wm)); + if (!intel_wm_plane_visible(crtc_state, plane_state)) return 0; @@ -5547,10 +5533,14 @@ static int skl_build_plane_wm(struct intel_crtc_state *crtc_state, static int icl_build_plane_wm(struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - enum plane_id plane_id = to_intel_plane(plane_state->uapi.plane)->id; + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id]; int ret; + memset(wm, 0, sizeof(*wm)); + /* Watermarks calculated in master */ if (plane_state->planar_slave) return 0; @@ -5583,22 +5573,24 @@ static int icl_build_plane_wm(struct intel_crtc_state *crtc_state, return 0; } -static int skl_build_pipe_wm(struct intel_crtc_state *crtc_state) +static int skl_build_pipe_wm(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; - struct intel_plane *plane; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); const struct intel_plane_state *plane_state; - int ret; - - /* - * We'll only calculate watermarks for planes that are actually - * enabled, so make sure all other planes are set as disabled. - */ - memset(pipe_wm->planes, 0, sizeof(pipe_wm->planes)); + struct intel_plane *plane; + int ret, i; - intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, - crtc_state) { + for_each_new_intel_plane_in_state(state, plane, plane_state, i) { + /* + * FIXME should perhaps check {old,new}_plane_crtc->hw.crtc + * instead but we don't populate that correctly for NV12 Y + * planes so for now hack this. + */ + if (plane->pipe != crtc->pipe) + continue; if (INTEL_GEN(dev_priv) >= 11) ret = icl_build_plane_wm(crtc_state, plane_state); @@ -5608,6 +5600,8 @@ static int skl_build_pipe_wm(struct intel_crtc_state *crtc_state) return ret; } + crtc_state->wm.skl.optimal = crtc_state->wm.skl.raw; + return 0; } @@ -5794,7 +5788,7 @@ skl_compute_ddb(struct intel_atomic_state *state) for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - ret = skl_allocate_pipe_ddb(new_crtc_state); + ret = skl_allocate_pipe_ddb(state, crtc); if (ret) return ret; @@ -6092,7 +6086,6 @@ skl_compute_wm(struct intel_atomic_state *state) { struct intel_crtc *crtc; struct intel_crtc_state *new_crtc_state; - struct intel_crtc_state *old_crtc_state; int ret, i; ret = skl_ddb_add_affected_pipes(state); @@ -6104,9 +6097,8 @@ skl_compute_wm(struct intel_atomic_state *state) * Note that skl_ddb_add_affected_pipes may have added more CRTC's that * weren't otherwise being modified if pipe allocations had to change. */ - for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, - new_crtc_state, i) { - ret = skl_build_pipe_wm(new_crtc_state); + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + ret = skl_build_pipe_wm(state, crtc); if (ret) return ret; } @@ -6124,8 +6116,7 @@ skl_compute_wm(struct intel_atomic_state *state) * based on how much ddb is available. Now we can actually * check if the final watermarks changed. */ - for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, - new_crtc_state, i) { + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { ret = skl_wm_add_affected_planes(state, crtc); if (ret) return ret; @@ -6271,6 +6262,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) crtc_state = to_intel_crtc_state(crtc->base.state); skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal); + crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal; } if (dev_priv->active_pipes) { @@ -6287,13 +6279,8 @@ static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc) struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct intel_pipe_wm *active = &crtc_state->wm.ilk.optimal; enum pipe pipe = crtc->pipe; - static const i915_reg_t wm0_pipe_reg[] = { - [PIPE_A] = WM0_PIPEA_ILK, - [PIPE_B] = WM0_PIPEB_ILK, - [PIPE_C] = WM0_PIPEC_IVB, - }; - hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]); + hw->wm_pipe[pipe] = I915_READ(WM0_PIPE_ILK(pipe)); memset(active, 0, sizeof(*active)); @@ -7132,6 +7119,14 @@ static void tgl_init_clock_gating(struct drm_i915_private *dev_priv) 0, DFR_DISABLE); } +static void dg1_init_clock_gating(struct drm_i915_private *dev_priv) +{ + /* Wa_1409836686:dg1[a0] */ + if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0)) + I915_WRITE(GEN9_CLKGATE_DIS_3, I915_READ(GEN9_CLKGATE_DIS_3) | + DPT_GATING_DIS); +} + static void cnp_init_clock_gating(struct drm_i915_private *dev_priv) { if (!HAS_PCH_CNP(dev_priv)) @@ -7184,6 +7179,10 @@ static void cfl_init_clock_gating(struct drm_i915_private *dev_priv) cnp_init_clock_gating(dev_priv); gen9_init_clock_gating(dev_priv); + /* WAC6entrylatency:cfl */ + I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) | + FBC_LLC_FULLY_OPEN); + /* * WaFbcTurnOffFbcWatermark:cfl * Display WA #0562: cfl @@ -7203,6 +7202,10 @@ static void kbl_init_clock_gating(struct drm_i915_private *dev_priv) { gen9_init_clock_gating(dev_priv); + /* WAC6entrylatency:kbl */ + I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) | + FBC_LLC_FULLY_OPEN); + /* WaDisableSDEUnitClockGating:kbl */ if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0)) I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | @@ -7577,7 +7580,9 @@ static void nop_init_clock_gating(struct drm_i915_private *dev_priv) */ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) { - if (IS_GEN(dev_priv, 12)) + if (IS_DG1(dev_priv)) + dev_priv->display.init_clock_gating = dg1_init_clock_gating; + else if (IS_GEN(dev_priv, 12)) dev_priv->display.init_clock_gating = tgl_init_clock_gating; else if (IS_GEN(dev_priv, 11)) dev_priv->display.init_clock_gating = icl_init_clock_gating; diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index a2473594c2db..eab83e251dd5 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -49,8 +49,6 @@ void g4x_wm_sanitize(struct drm_i915_private *dev_priv); void vlv_wm_sanitize(struct drm_i915_private *dev_priv); bool intel_can_enable_sagv(struct drm_i915_private *dev_priv, const struct intel_bw_state *bw_state); -int intel_enable_sagv(struct drm_i915_private *dev_priv); -int intel_disable_sagv(struct drm_i915_private *dev_priv); void intel_sagv_pre_plane_update(struct intel_atomic_state *state); void intel_sagv_post_plane_update(struct intel_atomic_state *state); bool skl_wm_level_equals(const struct skl_wm_level *l1, diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index 5b3279262123..02ebf5a04a9b 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -555,3 +555,18 @@ out: return ret ? ret : status; #undef COND } + +void intel_pcode_init(struct drm_i915_private *i915) +{ + int ret; + + if (!IS_DGFX(i915)) + return; + + ret = skl_pcode_request(i915, DG1_PCODE_STATUS, + DG1_UNCORE_GET_INIT_STATUS, + DG1_UNCORE_INIT_STATUS_COMPLETE, + DG1_UNCORE_INIT_STATUS_COMPLETE, 50); + if (ret) + drm_err(&i915->drm, "Pcode did not report uncore initialization completion!\n"); +} diff --git a/drivers/gpu/drm/i915/intel_sideband.h b/drivers/gpu/drm/i915/intel_sideband.h index 7fb95745a444..094c7b19c5d4 100644 --- a/drivers/gpu/drm/i915/intel_sideband.h +++ b/drivers/gpu/drm/i915/intel_sideband.h @@ -138,4 +138,6 @@ int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, u32 mbox, int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, u32 reply_mask, u32 reply, int timeout_base_ms); +void intel_pcode_init(struct drm_i915_private *i915); + #endif /* _INTEL_SIDEBAND_H */ diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 97ded2a59cf4..1c14a07eba7d 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1051,37 +1051,37 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = { /* *Must* be sorted by offset ranges! See intel_fw_table_check(). */ static const struct intel_forcewake_range __gen9_fw_ranges[] = { - GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_GT), GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */ GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_GT), GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT), GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8000, 0x812f, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8000, 0x812f, FORCEWAKE_GT), GEN_FW_RANGE(0x8130, 0x813f, FORCEWAKE_MEDIA), GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_GT), GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_GT), GEN_FW_RANGE(0x8800, 0x89ff, FORCEWAKE_MEDIA), - GEN_FW_RANGE(0x8a00, 0x8bff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8a00, 0x8bff, FORCEWAKE_GT), GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_GT), GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA), - GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_GT), GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER), - GEN_FW_RANGE(0xb480, 0xcfff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0xb480, 0xcfff, FORCEWAKE_GT), GEN_FW_RANGE(0xd000, 0xd7ff, FORCEWAKE_MEDIA), - GEN_FW_RANGE(0xd800, 0xdfff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0xd800, 0xdfff, FORCEWAKE_GT), GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0xe900, 0x11fff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0xe900, 0x11fff, FORCEWAKE_GT), GEN_FW_RANGE(0x12000, 0x13fff, FORCEWAKE_MEDIA), - GEN_FW_RANGE(0x14000, 0x19fff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x14000, 0x19fff, FORCEWAKE_GT), GEN_FW_RANGE(0x1a000, 0x1e9ff, FORCEWAKE_MEDIA), - GEN_FW_RANGE(0x1ea00, 0x243ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x1ea00, 0x243ff, FORCEWAKE_GT), GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x24800, 0x2ffff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x24800, 0x2ffff, FORCEWAKE_GT), GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_MEDIA), }; @@ -1089,33 +1089,33 @@ static const struct intel_forcewake_range __gen9_fw_ranges[] = { static const struct intel_forcewake_range __gen11_fw_ranges[] = { GEN_FW_RANGE(0x0, 0x1fff, 0), /* uncore range */ GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_GT), GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT), GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_GT), GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_GT), GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_GT), GEN_FW_RANGE(0x8800, 0x8bff, 0), GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8d00, 0x94cf, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8d00, 0x94cf, FORCEWAKE_GT), GEN_FW_RANGE(0x94d0, 0x955f, FORCEWAKE_RENDER), GEN_FW_RANGE(0x9560, 0x95ff, 0), - GEN_FW_RANGE(0x9600, 0xafff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x9600, 0xafff, FORCEWAKE_GT), GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER), - GEN_FW_RANGE(0xb480, 0xdeff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0xb480, 0xdeff, FORCEWAKE_GT), GEN_FW_RANGE(0xdf00, 0xe8ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0xe900, 0x16dff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0xe900, 0x16dff, FORCEWAKE_GT), GEN_FW_RANGE(0x16e00, 0x19fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x1a000, 0x23fff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x1a000, 0x23fff, FORCEWAKE_GT), GEN_FW_RANGE(0x24000, 0x2407f, 0), - GEN_FW_RANGE(0x24080, 0x2417f, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x24080, 0x2417f, FORCEWAKE_GT), GEN_FW_RANGE(0x24180, 0x242ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x24300, 0x243ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x24300, 0x243ff, FORCEWAKE_GT), GEN_FW_RANGE(0x24400, 0x24fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x25000, 0x3ffff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x25000, 0x3ffff, FORCEWAKE_GT), GEN_FW_RANGE(0x40000, 0x1bffff, 0), GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0), GEN_FW_RANGE(0x1c4000, 0x1c7fff, 0), @@ -1124,44 +1124,113 @@ static const struct intel_forcewake_range __gen11_fw_ranges[] = { GEN_FW_RANGE(0x1d4000, 0x1dbfff, 0) }; -/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */ +/* + * *Must* be sorted by offset ranges! See intel_fw_table_check(). + * + * Note that the spec lists several reserved/unused ranges that don't + * actually contain any registers. In the table below we'll combine those + * reserved ranges with either the preceding or following range to keep the + * table small and lookups fast. + */ static const struct intel_forcewake_range __gen12_fw_ranges[] = { - GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */ + GEN_FW_RANGE(0x0, 0x1fff, 0), /* + 0x0 - 0xaff: reserved + 0xb00 - 0x1fff: always on */ GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x2700, 0x27ff, FORCEWAKE_GT), + GEN_FW_RANGE(0x2800, 0x2aff, FORCEWAKE_RENDER), + GEN_FW_RANGE(0x2b00, 0x2fff, FORCEWAKE_GT), GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT), /* + 0x4000 - 0x48ff: gt + 0x4900 - 0x51ff: reserved */ + GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), /* + 0x5200 - 0x53ff: render + 0x5400 - 0x54ff: reserved + 0x5500 - 0x7fff: render */ + GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_GT), GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8160, 0x81ff, 0), /* + 0x8160 - 0x817f: reserved + 0x8180 - 0x81ff: always on */ + GEN_FW_RANGE(0x8200, 0x82ff, FORCEWAKE_GT), GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8500, 0x8bff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_ALL), - GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER), - GEN_FW_RANGE(0xb480, 0xdfff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0xe900, 0x147ff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x14800, 0x148ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x14900, 0x19fff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x1a000, 0x1a7ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x1a800, 0x1afff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x1b000, 0x1bfff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x1c000, 0x243ff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER), - GEN_FW_RANGE(0x24800, 0x3ffff, FORCEWAKE_BLITTER), + GEN_FW_RANGE(0x8500, 0x94cf, FORCEWAKE_GT), /* + 0x8500 - 0x87ff: gt + 0x8800 - 0x8fff: reserved + 0x9000 - 0x947f: gt + 0x9480 - 0x94cf: reserved */ + GEN_FW_RANGE(0x94d0, 0x955f, FORCEWAKE_RENDER), + GEN_FW_RANGE(0x9560, 0x97ff, 0), /* + 0x9560 - 0x95ff: always on + 0x9600 - 0x97ff: reserved */ + GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_GT), + GEN_FW_RANGE(0xb000, 0xb3ff, FORCEWAKE_RENDER), + GEN_FW_RANGE(0xb400, 0xcfff, FORCEWAKE_GT), /* + 0xb400 - 0xbf7f: gt + 0xb480 - 0xbfff: reserved + 0xc000 - 0xcfff: gt */ + GEN_FW_RANGE(0xd000, 0xd7ff, 0), + GEN_FW_RANGE(0xd800, 0xd8ff, FORCEWAKE_RENDER), + GEN_FW_RANGE(0xd900, 0xdbff, FORCEWAKE_GT), + GEN_FW_RANGE(0xdc00, 0xefff, FORCEWAKE_RENDER), /* + 0xdc00 - 0xddff: render + 0xde00 - 0xde7f: reserved + 0xde80 - 0xe8ff: render + 0xe900 - 0xefff: reserved */ + GEN_FW_RANGE(0xf000, 0x147ff, FORCEWAKE_GT), /* + 0xf000 - 0xffff: gt + 0x10000 - 0x147ff: reserved */ + GEN_FW_RANGE(0x14800, 0x1ffff, FORCEWAKE_RENDER), /* + 0x14800 - 0x14fff: render + 0x15000 - 0x16dff: reserved + 0x16e00 - 0x1bfff: render + 0x1c000 - 0x1ffff: reserved */ + GEN_FW_RANGE(0x20000, 0x20fff, FORCEWAKE_MEDIA_VDBOX0), + GEN_FW_RANGE(0x21000, 0x21fff, FORCEWAKE_MEDIA_VDBOX2), + GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_GT), + GEN_FW_RANGE(0x24000, 0x2417f, 0), /* + 0x24000 - 0x2407f: always on + 0x24080 - 0x2417f: reserved */ + GEN_FW_RANGE(0x24180, 0x249ff, FORCEWAKE_GT), /* + 0x24180 - 0x241ff: gt + 0x24200 - 0x249ff: reserved */ + GEN_FW_RANGE(0x24a00, 0x251ff, FORCEWAKE_RENDER), /* + 0x24a00 - 0x24a7f: render + 0x24a80 - 0x251ff: reserved */ + GEN_FW_RANGE(0x25200, 0x255ff, FORCEWAKE_GT), /* + 0x25200 - 0x252ff: gt + 0x25300 - 0x255ff: reserved */ + GEN_FW_RANGE(0x25600, 0x2567f, FORCEWAKE_MEDIA_VDBOX0), + GEN_FW_RANGE(0x25680, 0x259ff, FORCEWAKE_MEDIA_VDBOX2), /* + 0x25680 - 0x256ff: VD2 + 0x25700 - 0x259ff: reserved */ + GEN_FW_RANGE(0x25a00, 0x25a7f, FORCEWAKE_MEDIA_VDBOX0), + GEN_FW_RANGE(0x25a80, 0x2ffff, FORCEWAKE_MEDIA_VDBOX2), /* + 0x25a80 - 0x25aff: VD2 + 0x25b00 - 0x2ffff: reserved */ + GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT), GEN_FW_RANGE(0x40000, 0x1bffff, 0), - GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0), - GEN_FW_RANGE(0x1c4000, 0x1c7fff, FORCEWAKE_MEDIA_VDBOX1), - GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0), - GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_BLITTER), - GEN_FW_RANGE(0x1d0000, 0x1d3fff, FORCEWAKE_MEDIA_VDBOX2), - GEN_FW_RANGE(0x1d4000, 0x1d7fff, FORCEWAKE_MEDIA_VDBOX3), - GEN_FW_RANGE(0x1d8000, 0x1dbfff, FORCEWAKE_MEDIA_VEBOX1) + GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0), /* + 0x1c0000 - 0x1c2bff: VD0 + 0x1c2c00 - 0x1c2cff: reserved + 0x1c2d00 - 0x1c2dff: VD0 + 0x1c2e00 - 0x1c3eff: reserved + 0x1c3f00 - 0x1c3fff: VD0 */ + GEN_FW_RANGE(0x1c4000, 0x1c7fff, 0), + GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0), /* + 0x1c8000 - 0x1ca0ff: VE0 + 0x1ca100 - 0x1cbeff: reserved + 0x1cbf00 - 0x1cbfff: VE0 */ + GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_MEDIA_VDBOX0), /* + 0x1cc000 - 0x1ccfff: VD0 + 0x1cd000 - 0x1cffff: reserved */ + GEN_FW_RANGE(0x1d0000, 0x1d3fff, FORCEWAKE_MEDIA_VDBOX2), /* + 0x1d0000 - 0x1d2bff: VD2 + 0x1d2c00 - 0x1d2cff: reserved + 0x1d2d00 - 0x1d2dff: VD2 + 0x1d2e00 - 0x1d3eff: reserved + 0x1d3f00 - 0x1d3fff: VD2 */ }; static void @@ -1491,7 +1560,7 @@ static int __fw_domain_init(struct intel_uncore *uncore, d->id = domain_id; BUILD_BUG_ON(FORCEWAKE_RENDER != (1 << FW_DOMAIN_ID_RENDER)); - BUILD_BUG_ON(FORCEWAKE_BLITTER != (1 << FW_DOMAIN_ID_BLITTER)); + BUILD_BUG_ON(FORCEWAKE_GT != (1 << FW_DOMAIN_ID_GT)); BUILD_BUG_ON(FORCEWAKE_MEDIA != (1 << FW_DOMAIN_ID_MEDIA)); BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX0)); BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX1)); @@ -1560,9 +1629,9 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_RENDER_GEN9, FORCEWAKE_ACK_RENDER_GEN9); - fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER, - FORCEWAKE_BLITTER_GEN9, - FORCEWAKE_ACK_BLITTER_GEN9); + fw_domain_init(uncore, FW_DOMAIN_ID_GT, + FORCEWAKE_GT_GEN9, + FORCEWAKE_ACK_GT_GEN9); for (i = 0; i < I915_MAX_VCS; i++) { if (!__HAS_ENGINE(emask, _VCS(i))) @@ -1586,9 +1655,9 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_RENDER_GEN9, FORCEWAKE_ACK_RENDER_GEN9); - fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER, - FORCEWAKE_BLITTER_GEN9, - FORCEWAKE_ACK_BLITTER_GEN9); + fw_domain_init(uncore, FW_DOMAIN_ID_GT, + FORCEWAKE_GT_GEN9, + FORCEWAKE_ACK_GT_GEN9); fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA, FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9); } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { @@ -1723,11 +1792,15 @@ static int uncore_mmio_setup(struct intel_uncore *uncore) * clobbering the GTT which we want ioremap_wc instead. Fortunately, * the register BAR remains the same size for all the earlier * generations up to Ironlake. + * For dgfx chips register range is expanded to 4MB. */ if (INTEL_GEN(i915) < 5) mmio_size = 512 * 1024; + else if (IS_DGFX(i915)) + mmio_size = 4 * 1024 * 1024; else mmio_size = 2 * 1024 * 1024; + uncore->regs = pci_iomap(pdev, mmio_bar, mmio_size); if (uncore->regs == NULL) { drm_err(&i915->drm, "failed to map registers\n"); diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index c4b22d9d0b45..bd2467284295 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -46,7 +46,7 @@ struct intel_uncore_mmio_debug { enum forcewake_domain_id { FW_DOMAIN_ID_RENDER = 0, - FW_DOMAIN_ID_BLITTER, + FW_DOMAIN_ID_GT, /* also includes blitter engine */ FW_DOMAIN_ID_MEDIA, FW_DOMAIN_ID_MEDIA_VDBOX0, FW_DOMAIN_ID_MEDIA_VDBOX1, @@ -60,7 +60,7 @@ enum forcewake_domain_id { enum forcewake_domains { FORCEWAKE_RENDER = BIT(FW_DOMAIN_ID_RENDER), - FORCEWAKE_BLITTER = BIT(FW_DOMAIN_ID_BLITTER), + FORCEWAKE_GT = BIT(FW_DOMAIN_ID_GT), FORCEWAKE_MEDIA = BIT(FW_DOMAIN_ID_MEDIA), FORCEWAKE_MEDIA_VDBOX0 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX0), FORCEWAKE_MEDIA_VDBOX1 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX1), diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index b6c42fd872ad..e946bd2087d8 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -81,13 +81,10 @@ out: i915_params_free(&i915->params); } -static struct drm_driver mock_driver = { +static const struct drm_driver mock_driver = { .name = "mock", .driver_features = DRIVER_GEM, .release = mock_device_release, - - .gem_close_object = i915_gem_close_object, - .gem_free_object_unlocked = i915_gem_free_object, }; static void release_dev(struct device *dev) |