diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
194 files changed, 3586 insertions, 2403 deletions
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 1852e0804942..3562a02ef7ad 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -50,7 +50,7 @@ config DRM_I915_DEBUG select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) select DRM_DEBUG_MM if DRM=y select DRM_EXPORT_FOR_TESTS if m - select DRM_DEBUG_SELFTEST + select DRM_KUNIT_TEST if KUNIT select DMABUF_SELFTESTS select SW_SYNC # signaling validation framework (igt/syncobj*) select DRM_I915_WERROR diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 853543443072..78a45a6681df 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -32,6 +32,7 @@ i915-y += \ i915_scatterlist.o \ i915_switcheroo.o \ i915_sysfs.o \ + i915_timer_util.o \ i915_utils.o \ intel_clock_gating.o \ intel_cpu_info.o \ @@ -280,6 +281,7 @@ i915-y += \ display/intel_modeset_setup.o \ display/intel_modeset_verify.o \ display/intel_overlay.o \ + display/intel_panic.o \ display/intel_pch.o \ display/intel_pch_display.o \ display/intel_pch_refclk.o \ @@ -298,6 +300,7 @@ i915-y += \ display/skl_scaler.o \ display/skl_universal_plane.o \ display/skl_watermark.o \ + display/vlv_clock.o \ display/vlv_sideband.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 87f6b9602b16..aa159f9ce12f 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -424,17 +424,6 @@ intel_dp_link_down(struct intel_encoder *encoder, drm_dbg_kms(display->drm, "\n"); - if ((display->platform.ivybridge && port == PORT_A) || - (HAS_PCH_CPT(display) && port != PORT_A)) { - intel_dp->DP &= ~DP_LINK_TRAIN_MASK_CPT; - intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE_CPT; - } else { - intel_dp->DP &= ~DP_LINK_TRAIN_MASK; - intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE; - } - intel_de_write(display, intel_dp->output_reg, intel_dp->DP); - intel_de_posting_read(display, intel_dp->output_reg); - intel_dp->DP &= ~DP_PORT_EN; intel_de_write(display, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(display, intel_dp->output_reg); @@ -612,6 +601,19 @@ cpt_set_link_train(struct intel_dp *intel_dp, } static void +cpt_set_idle_link_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(intel_dp); + + intel_dp->DP &= ~DP_LINK_TRAIN_MASK_CPT; + intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE_CPT; + + intel_de_write(display, intel_dp->output_reg, intel_dp->DP); + intel_de_posting_read(display, intel_dp->output_reg); +} + +static void g4x_set_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, u8 dp_train_pat) @@ -639,6 +641,19 @@ g4x_set_link_train(struct intel_dp *intel_dp, intel_de_posting_read(display, intel_dp->output_reg); } +static void +g4x_set_idle_link_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(intel_dp); + + intel_dp->DP &= ~DP_LINK_TRAIN_MASK; + intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE; + + intel_de_write(display, intel_dp->output_reg, intel_dp->DP); + intel_de_posting_read(display, intel_dp->output_reg); +} + static void intel_dp_enable_port(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { @@ -1285,12 +1300,10 @@ bool g4x_dp_init(struct intel_display *display, drm_dbg_kms(display->drm, "No VBT child device for DP-%c\n", port_name(port)); - dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL); + dig_port = intel_dig_port_alloc(); if (!dig_port) return false; - dig_port->aux_ch = AUX_CH_NONE; - intel_connector = intel_connector_alloc(); if (!intel_connector) goto err_connector_alloc; @@ -1300,8 +1313,6 @@ bool g4x_dp_init(struct intel_display *display, intel_encoder->devdata = devdata; - mutex_init(&dig_port->hdcp.mutex); - if (drm_encoder_init(display->drm, &intel_encoder->base, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS, "DP %c", port_name(port))) @@ -1342,10 +1353,13 @@ bool g4x_dp_init(struct intel_display *display, intel_encoder->audio_disable = g4x_dp_audio_disable; if ((display->platform.ivybridge && port == PORT_A) || - (HAS_PCH_CPT(display) && port != PORT_A)) + (HAS_PCH_CPT(display) && port != PORT_A)) { dig_port->dp.set_link_train = cpt_set_link_train; - else + dig_port->dp.set_idle_link_train = cpt_set_idle_link_train; + } else { dig_port->dp.set_link_train = g4x_set_link_train; + dig_port->dp.set_idle_link_train = g4x_set_idle_link_train; + } if (display->platform.cherryview) intel_encoder->set_signal_levels = chv_set_signal_levels; @@ -1368,7 +1382,6 @@ bool g4x_dp_init(struct intel_display *display, } dig_port->dp.output_reg = output_reg; - dig_port->max_lanes = 4; intel_encoder->type = INTEL_OUTPUT_DP; intel_encoder->power_domain = intel_display_power_ddi_lanes_domain(display, port); diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 2610f5702fb9..f6e2d1ed5639 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -19,7 +19,7 @@ #include "intel_display_types.h" #include "intel_dp_aux.h" #include "intel_dpio_phy.h" -#include "intel_fdi.h" +#include "intel_encoder.h" #include "intel_fifo_underrun.h" #include "intel_hdmi.h" #include "intel_hotplug.h" @@ -135,11 +135,8 @@ static int g4x_hdmi_compute_config(struct intel_encoder *encoder, struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - if (HAS_PCH_SPLIT(display)) { + if (HAS_PCH_SPLIT(display)) crtc_state->has_pch_encoder = true; - if (!intel_fdi_compute_pipe_bpp(crtc_state)) - return -EINVAL; - } if (display->platform.g4x) crtc_state->has_hdmi_sink = g4x_compute_has_hdmi_sink(state, crtc); @@ -690,12 +687,10 @@ bool g4x_hdmi_init(struct intel_display *display, drm_dbg_kms(display->drm, "No VBT child device for HDMI-%c\n", port_name(port)); - dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL); + dig_port = intel_dig_port_alloc(); if (!dig_port) return false; - dig_port->aux_ch = AUX_CH_NONE; - intel_connector = intel_connector_alloc(); if (!intel_connector) goto err_connector_alloc; @@ -704,8 +699,6 @@ bool g4x_hdmi_init(struct intel_display *display, intel_encoder->devdata = devdata; - mutex_init(&dig_port->hdcp.mutex); - if (drm_encoder_init(display->drm, &intel_encoder->base, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS, "HDMI %c", port_name(port))) @@ -767,8 +760,6 @@ bool g4x_hdmi_init(struct intel_display *display, intel_encoder->cloneable |= BIT(INTEL_OUTPUT_HDMI); dig_port->hdmi.hdmi_reg = hdmi_reg; - dig_port->dp.output_reg = INVALID_MMIO_REG; - dig_port->max_lanes = 4; intel_infoframe_init(dig_port); diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index f291ced989dc..407deb5dfb57 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -15,7 +15,6 @@ #include "i9xx_plane.h" #include "i9xx_plane_regs.h" #include "intel_atomic.h" -#include "intel_bo.h" #include "intel_de.h" #include "intel_display_irq.h" #include "intel_display_regs.h" @@ -23,6 +22,7 @@ #include "intel_fb.h" #include "intel_fbc.h" #include "intel_frontbuffer.h" +#include "intel_panic.h" #include "intel_plane.h" #include "intel_sprite.h" @@ -155,8 +155,7 @@ static bool i9xx_plane_has_windowing(struct intel_plane *plane) i9xx_plane == PLANE_C; } -static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 i9xx_plane_ctl(const struct intel_plane_state *plane_state) { struct intel_display *display = to_intel_display(plane_state); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -355,11 +354,24 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state); + plane_state->ctl = i9xx_plane_ctl(plane_state); return 0; } +static u32 i8xx_plane_surf_offset(const struct intel_plane_state *plane_state) +{ + int x = plane_state->view.color_plane[0].x; + int y = plane_state->view.color_plane[0].y; + + return intel_fb_xy_to_linear(x, y, plane_state, 0); +} + +u32 i965_plane_surf_offset(const struct intel_plane_state *plane_state) +{ + return plane_state->view.color_plane[0].offset; +} + static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -463,7 +475,7 @@ static void i9xx_plane_update_arm(struct intel_dsb *dsb, enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; int x = plane_state->view.color_plane[0].x; int y = plane_state->view.color_plane[0].y; - u32 dspcntr, dspaddr_offset, linear_offset; + u32 dspcntr; dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); @@ -472,13 +484,6 @@ static void i9xx_plane_update_arm(struct intel_dsb *dsb, crtc_state->async_flip_planes & BIT(plane->id)) dspcntr |= DISP_ASYNC_FLIP; - linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - - if (DISPLAY_VER(display) >= 4) - dspaddr_offset = plane_state->view.color_plane[0].offset; - else - dspaddr_offset = linear_offset; - if (display->platform.cherryview && i9xx_plane == PLANE_B) { int crtc_x = plane_state->uapi.dst.x1; int crtc_y = plane_state->uapi.dst.y1; @@ -498,7 +503,7 @@ static void i9xx_plane_update_arm(struct intel_dsb *dsb, DISP_OFFSET_Y(y) | DISP_OFFSET_X(x)); } else if (DISPLAY_VER(display) >= 4) { intel_de_write_fw(display, DSPLINOFF(display, i9xx_plane), - linear_offset); + intel_fb_xy_to_linear(x, y, plane_state, 0)); intel_de_write_fw(display, DSPTILEOFF(display, i9xx_plane), DISP_OFFSET_Y(y) | DISP_OFFSET_X(x)); } @@ -511,11 +516,9 @@ static void i9xx_plane_update_arm(struct intel_dsb *dsb, intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); if (DISPLAY_VER(display) >= 4) - intel_de_write_fw(display, DSPSURF(display, i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), plane_state->surf); else - intel_de_write_fw(display, DSPADDR(display, i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); + intel_de_write_fw(display, DSPADDR(display, i9xx_plane), plane_state->surf); } static void i830_plane_update_arm(struct intel_dsb *dsb, @@ -604,16 +607,13 @@ g4x_primary_async_flip(struct intel_dsb *dsb, { struct intel_display *display = to_intel_display(plane); u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); - u32 dspaddr_offset = plane_state->view.color_plane[0].offset; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; if (async_flip) dspcntr |= DISP_ASYNC_FLIP; intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); - - intel_de_write_fw(display, DSPSURF(display, i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), plane_state->surf); } static void @@ -624,11 +624,9 @@ vlv_primary_async_flip(struct intel_dsb *dsb, bool async_flip) { struct intel_display *display = to_intel_display(plane); - u32 dspaddr_offset = plane_state->view.color_plane[0].offset; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - intel_de_write_fw(display, DSPADDR_VLV(display, i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); + intel_de_write_fw(display, DSPADDR_VLV(display, i9xx_plane), plane_state->surf); } static void @@ -1037,6 +1035,11 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe) plane->get_hw_state = i9xx_plane_get_hw_state; plane->check_plane = i9xx_plane_check; + if (DISPLAY_VER(display) >= 4) + plane->surf_offset = i965_plane_surf_offset; + else + plane->surf_offset = i8xx_plane_surf_offset; + if (DISPLAY_VER(display) >= 5 || display->platform.g4x) plane->capture_error = g4x_primary_capture_error; else if (DISPLAY_VER(display) >= 4) @@ -1175,7 +1178,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, drm_WARN_ON(display->drm, pipe != crtc->pipe); - intel_fb = intel_bo_alloc_framebuffer(); + intel_fb = intel_framebuffer_alloc(); if (!intel_fb) { drm_dbg_kms(display->drm, "failed to alloc fb\n"); return; @@ -1254,24 +1257,21 @@ bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc, const struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - u32 base; if (!plane_state->uapi.visible) return false; - base = intel_plane_ggtt_offset(plane_state); - /* * We may have moved the surface to a different * part of ggtt, make the plane aware of that. */ - if (plane_config->base == base) + if (plane_config->base == plane_state->surf) return false; if (DISPLAY_VER(display) >= 4) - intel_de_write(display, DSPSURF(display, i9xx_plane), base); + intel_de_write(display, DSPSURF(display, i9xx_plane), plane_state->surf); else - intel_de_write(display, DSPADDR(display, i9xx_plane), base); + intel_de_write(display, DSPADDR(display, i9xx_plane), plane_state->surf); return true; } diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h index d90546d60855..565dab751301 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.h +++ b/drivers/gpu/drm/i915/display/i9xx_plane.h @@ -24,6 +24,7 @@ unsigned int vlv_plane_min_alignment(struct intel_plane *plane, const struct drm_framebuffer *fb, int colot_plane); int i9xx_check_plane_surface(struct intel_plane_state *plane_state); +u32 i965_plane_surf_offset(const struct intel_plane_state *plane_state); struct intel_plane * intel_primary_plane_create(struct intel_display *display, enum pipe pipe); diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index 1f9db5118777..fd3b7b35f351 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -3,6 +3,10 @@ * Copyright © 2023 Intel Corporation */ +#include <linux/iopoll.h> + +#include "soc/intel_dram.h" + #include "i915_drv.h" #include "i915_reg.h" #include "i9xx_wm.h" @@ -85,7 +89,8 @@ static const struct cxsr_latency cxsr_latency_table[] = { static const struct cxsr_latency *pnv_get_cxsr_latency(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); + const struct dram_info *dram_info = intel_dram_info(display->drm); + bool is_ddr3 = dram_info->type == INTEL_DRAM_DDR3; int i; for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) { @@ -93,15 +98,16 @@ static const struct cxsr_latency *pnv_get_cxsr_latency(struct intel_display *dis bool is_desktop = !display->platform.mobile; if (is_desktop == latency->is_desktop && - i915->is_ddr3 == latency->is_ddr3 && - DIV_ROUND_CLOSEST(i915->fsb_freq, 1000) == latency->fsb_freq && - DIV_ROUND_CLOSEST(i915->mem_freq, 1000) == latency->mem_freq) + is_ddr3 == latency->is_ddr3 && + DIV_ROUND_CLOSEST(dram_info->fsb_freq, 1000) == latency->fsb_freq && + DIV_ROUND_CLOSEST(dram_info->mem_freq, 1000) == latency->mem_freq) return latency; } drm_dbg_kms(display->drm, - "Could not find CxSR latency for DDR%s, FSB %u kHz, MEM %u kHz\n", - i915->is_ddr3 ? "3" : "2", i915->fsb_freq, i915->mem_freq); + "Could not find CxSR latency for %s, FSB %u kHz, MEM %u kHz\n", + intel_dram_type_str(dram_info->type), + dram_info->fsb_freq, dram_info->mem_freq); return NULL; } @@ -109,6 +115,7 @@ static const struct cxsr_latency *pnv_get_cxsr_latency(struct intel_display *dis static void chv_set_memory_dvfs(struct intel_display *display, bool enable) { u32 val; + int ret; vlv_punit_get(display->drm); @@ -121,8 +128,10 @@ static void chv_set_memory_dvfs(struct intel_display *display, bool enable) val |= FORCE_DDR_FREQ_REQ_ACK; vlv_punit_write(display->drm, PUNIT_REG_DDR_SETUP2, val); - if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2) & - FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) + ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2), + (val & FORCE_DDR_FREQ_REQ_ACK) == 0, + 500, 3000, false); + if (ret) drm_err(display->drm, "timed out waiting for Punit DDR DVFS request\n"); @@ -3902,6 +3911,7 @@ static void vlv_wm_get_hw_state(struct intel_display *display) struct vlv_wm_values *wm = &display->wm.vlv; struct intel_crtc *crtc; u32 val; + int ret; vlv_read_wm_values(display, wm); @@ -3928,8 +3938,10 @@ static void vlv_wm_get_hw_state(struct intel_display *display) val |= FORCE_DDR_FREQ_REQ_ACK; vlv_punit_write(display->drm, PUNIT_REG_DDR_SETUP2, val); - if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2) & - FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) { + ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2), + (val & FORCE_DDR_FREQ_REQ_ACK) == 0, + 500, 3000, false); + if (ret) { drm_dbg_kms(display->drm, "Punit not acking DDR DVFS request, " "assuming DDR DVFS is disabled\n"); diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 8d9cb73a93a7..37faa8f19f6e 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -25,6 +25,8 @@ * Jani Nikula <jani.nikula@intel.com> */ +#include <linux/iopoll.h> + #include <drm/display/drm_dsc_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fixed.h> @@ -72,8 +74,12 @@ static int payload_credits_available(struct intel_display *display, static bool wait_for_header_credits(struct intel_display *display, enum transcoder dsi_trans, int hdr_credit) { - if (wait_for_us(header_credits_available(display, dsi_trans) >= - hdr_credit, 100)) { + int ret, available; + + ret = poll_timeout_us(available = header_credits_available(display, dsi_trans), + available >= hdr_credit, + 10, 100, false); + if (ret) { drm_err(display->drm, "DSI header credits not released\n"); return false; } @@ -84,8 +90,12 @@ static bool wait_for_header_credits(struct intel_display *display, static bool wait_for_payload_credits(struct intel_display *display, enum transcoder dsi_trans, int payld_credit) { - if (wait_for_us(payload_credits_available(display, dsi_trans) >= - payld_credit, 100)) { + int ret, available; + + ret = poll_timeout_us(available = payload_credits_available(display, dsi_trans), + available >= payld_credit, + 10, 100, false); + if (ret) { drm_err(display->drm, "DSI payload credits not released\n"); return false; } @@ -137,8 +147,11 @@ static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder) /* wait for LP TX in progress bit to be cleared */ for_each_dsi_port(port, intel_dsi->ports) { dsi_trans = dsi_port_to_transcoder(port); - if (wait_for_us(!(intel_de_read(display, DSI_LP_MSG(dsi_trans)) & - LPTX_IN_PROGRESS), 20)) + + ret = intel_de_wait_custom(display, DSI_LP_MSG(dsi_trans), + LPTX_IN_PROGRESS, 0, + 20, 0, NULL); + if (ret) drm_err(display->drm, "LPTX bit not cleared\n"); } } @@ -516,13 +529,15 @@ static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder) struct intel_display *display = to_intel_display(encoder); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); enum port port; + int ret; for_each_dsi_port(port, intel_dsi->ports) { intel_de_rmw(display, DDI_BUF_CTL(port), 0, DDI_BUF_CTL_ENABLE); - if (wait_for_us(!(intel_de_read(display, DDI_BUF_CTL(port)) & - DDI_BUF_IS_IDLE), - 500)) + ret = intel_de_wait_custom(display, DDI_BUF_CTL(port), + DDI_BUF_IS_IDLE, 0, + 500, 0, NULL); + if (ret) drm_err(display->drm, "DDI port:%c buffer idle\n", port_name(port)); } @@ -838,9 +853,14 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder, /* wait for link ready */ for_each_dsi_port(port, intel_dsi->ports) { + int ret; + dsi_trans = dsi_port_to_transcoder(port); - if (wait_for_us((intel_de_read(display, DSI_TRANS_FUNC_CONF(dsi_trans)) & - LINK_READY), 2500)) + + ret = intel_de_wait_custom(display, DSI_TRANS_FUNC_CONF(dsi_trans), + LINK_READY, LINK_READY, + 2500, 0, NULL); + if (ret) drm_err(display->drm, "DSI link not ready\n"); } } @@ -1321,6 +1341,7 @@ static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) enum port port; enum transcoder dsi_trans; u32 tmp; + int ret; /* disable periodic update mode */ if (is_cmd_mode(intel_dsi)) { @@ -1337,9 +1358,10 @@ static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) tmp &= ~LINK_ULPS_TYPE_LP11; intel_de_write(display, DSI_LP_MSG(dsi_trans), tmp); - if (wait_for_us((intel_de_read(display, DSI_LP_MSG(dsi_trans)) & - LINK_IN_ULPS), - 10)) + ret = intel_de_wait_custom(display, DSI_LP_MSG(dsi_trans), + LINK_IN_ULPS, LINK_IN_ULPS, + 10, 0, NULL); + if (ret) drm_err(display->drm, "DSI link not in ULPS\n"); } @@ -1367,14 +1389,17 @@ static void gen11_dsi_disable_port(struct intel_encoder *encoder) struct intel_display *display = to_intel_display(encoder); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); enum port port; + int ret; gen11_dsi_ungate_clocks(encoder); for_each_dsi_port(port, intel_dsi->ports) { intel_de_rmw(display, DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE, 0); - if (wait_for_us((intel_de_read(display, DDI_BUF_CTL(port)) & - DDI_BUF_IS_IDLE), - 8)) + ret = intel_de_wait_custom(display, DDI_BUF_CTL(port), + DDI_BUF_IS_IDLE, DDI_BUF_IS_IDLE, + 8, 0, NULL); + + if (ret) drm_err(display->drm, "DDI port:%c buffer not idle\n", port_name(port)); diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c index dfdde8e4eabe..749119cc0b28 100644 --- a/drivers/gpu/drm/i915/display/intel_alpm.c +++ b/drivers/gpu/drm/i915/display/intel_alpm.c @@ -16,6 +16,14 @@ #include "intel_psr.h" #include "intel_psr_regs.h" +#define SILENCE_PERIOD_MIN_TIME 80 +#define SILENCE_PERIOD_MAX_TIME 180 +#define SILENCE_PERIOD_TIME (SILENCE_PERIOD_MIN_TIME + \ + (SILENCE_PERIOD_MAX_TIME - \ + SILENCE_PERIOD_MIN_TIME) / 2) + +#define LFPS_CYCLE_COUNT 10 + bool intel_alpm_aux_wake_supported(struct intel_dp *intel_dp) { return intel_dp->alpm_dpcd & DP_ALPM_CAP; @@ -44,72 +52,38 @@ void intel_alpm_init(struct intel_dp *intel_dp) mutex_init(&intel_dp->alpm_parameters.lock); } -/* - * See Bspec: 71632 for the table - * - * Silence_period = tSilence,Min + ((tSilence,Max - tSilence,Min) / 2) - * - * Half cycle duration: - * - * Link rates 1.62 - 4.32 and tLFPS_Cycle = 70 ns - * FLOOR( (Link Rate * tLFPS_Cycle) / (2 * 10) ) - * - * Link rates 5.4 - 8.1 - * PORT_ALPM_LFPS_CTL[ LFPS Cycle Count ] = 10 - * LFPS Period chosen is the mid-point of the min:max values from the table - * FLOOR( LFPS Period in Symbol clocks / - * (2 * PORT_ALPM_LFPS_CTL[ LFPS Cycle Count ]) ) - */ -static bool _lnl_get_silence_period_and_lfps_half_cycle(int link_rate, - int *silence_period, - int *lfps_half_cycle) +static int get_silence_period_symbols(const struct intel_crtc_state *crtc_state) { - switch (link_rate) { - case 162000: - *silence_period = 20; - *lfps_half_cycle = 5; - break; - case 216000: - *silence_period = 27; - *lfps_half_cycle = 7; - break; - case 243000: - *silence_period = 31; - *lfps_half_cycle = 8; - break; - case 270000: - *silence_period = 34; - *lfps_half_cycle = 9; - break; - case 324000: - *silence_period = 41; - *lfps_half_cycle = 11; - break; - case 432000: - *silence_period = 56; - *lfps_half_cycle = 15; - break; - case 540000: - *silence_period = 69; - *lfps_half_cycle = 12; - break; - case 648000: - *silence_period = 84; - *lfps_half_cycle = 15; - break; - case 675000: - *silence_period = 87; - *lfps_half_cycle = 15; - break; - case 810000: - *silence_period = 104; - *lfps_half_cycle = 19; - break; - default: - *silence_period = *lfps_half_cycle = -1; - return false; + return SILENCE_PERIOD_TIME * intel_dp_link_symbol_clock(crtc_state->port_clock) / + 1000 / 1000; +} + +static void get_lfps_cycle_min_max_time(const struct intel_crtc_state *crtc_state, + int *min, int *max) +{ + if (crtc_state->port_clock < 540000) { + *min = 65 * LFPS_CYCLE_COUNT; + *max = 75 * LFPS_CYCLE_COUNT; + } else { + *min = 140; + *max = 800; } - return true; +} + +static int get_lfps_cycle_time(const struct intel_crtc_state *crtc_state) +{ + int tlfps_cycle_min, tlfps_cycle_max; + + get_lfps_cycle_min_max_time(crtc_state, &tlfps_cycle_min, + &tlfps_cycle_max); + + return tlfps_cycle_min + (tlfps_cycle_max - tlfps_cycle_min) / 2; +} + +static int get_lfps_half_cycle_clocks(const struct intel_crtc_state *crtc_state) +{ + return get_lfps_cycle_time(crtc_state) * crtc_state->port_clock / 1000 / + 1000 / (2 * LFPS_CYCLE_COUNT); } /* @@ -131,21 +105,19 @@ static bool _lnl_get_silence_period_and_lfps_half_cycle(int link_rate, * tML_PHY_LOCK = TPS4 Length * ( 10 / (Link Rate in MHz) ) * TPS4 Length = 252 Symbols */ -static int _lnl_compute_aux_less_wake_time(int port_clock) +static int _lnl_compute_aux_less_wake_time(const struct intel_crtc_state *crtc_state) { int tphy2_p2_to_p0 = 12 * 1000; - int tlfps_period_max = 800; - int tsilence_max = 180; int t1 = 50 * 1000; int tps4 = 252; /* port_clock is link rate in 10kbit/s units */ - int tml_phy_lock = 1000 * 1000 * tps4 / port_clock; + int tml_phy_lock = 1000 * 1000 * tps4 / crtc_state->port_clock; int num_ml_phy_lock = 7 + DIV_ROUND_UP(6500, tml_phy_lock) + 1; int t2 = num_ml_phy_lock * tml_phy_lock; int tcds = 1 * t2; - return DIV_ROUND_UP(tphy2_p2_to_p0 + tlfps_period_max + tsilence_max + - t1 + tcds, 1000); + return DIV_ROUND_UP(tphy2_p2_to_p0 + get_lfps_cycle_time(crtc_state) + + SILENCE_PERIOD_TIME + t1 + tcds, 1000); } static int @@ -157,14 +129,12 @@ _lnl_compute_aux_less_alpm_params(struct intel_dp *intel_dp, lfps_half_cycle; aux_less_wake_time = - _lnl_compute_aux_less_wake_time(crtc_state->port_clock); + _lnl_compute_aux_less_wake_time(crtc_state); aux_less_wake_lines = intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, aux_less_wake_time); + silence_period = get_silence_period_symbols(crtc_state); - if (!_lnl_get_silence_period_and_lfps_half_cycle(crtc_state->port_clock, - &silence_period, - &lfps_half_cycle)) - return false; + lfps_half_cycle = get_lfps_half_cycle_clocks(crtc_state); if (aux_less_wake_lines > ALPM_CTL_AUX_LESS_WAKE_TIME_MASK || silence_period > PORT_ALPM_CTL_SILENCE_PERIOD_MASK || @@ -406,7 +376,7 @@ void intel_alpm_port_configure(struct intel_dp *intel_dp, PORT_ALPM_CTL_MAX_PHY_SWING_HOLD(0) | PORT_ALPM_CTL_SILENCE_PERIOD( intel_dp->alpm_parameters.silence_period_sym_clocks); - lfps_ctl_val = PORT_ALPM_LFPS_CTL_LFPS_CYCLE_COUNT(10) | + lfps_ctl_val = PORT_ALPM_LFPS_CTL_LFPS_CYCLE_COUNT(LFPS_CYCLE_COUNT) | PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION( intel_dp->alpm_parameters.lfps_half_cycle_num_of_syms) | PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION( diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index e007380e9a63..3b14f929825a 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -236,7 +236,8 @@ static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 struct intel_panel *panel = &connector->panel; u32 tmp, mask; - drm_WARN_ON(display->drm, panel->backlight.pwm_level_max == 0); + if (drm_WARN_ON(display->drm, panel->backlight.pwm_level_max == 0)) + return; if (panel->backlight.combination_mode) { struct pci_dev *pdev = to_pci_dev(display->drm->dev); diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 9c268bed091d..3596dce84c28 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -36,6 +36,7 @@ #include "soc/intel_rom.h" #include "i915_drv.h" +#include "i915_utils.h" #include "intel_display.h" #include "intel_display_core.h" #include "intel_display_rpm.h" @@ -1566,10 +1567,7 @@ parse_psr(struct intel_display *display, panel->vbt.psr.full_link = psr_table->full_link; panel->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; - - /* Allowed VBT values goes from 0 to 15 */ - panel->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : - psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames; + panel->vbt.psr.idle_frames = psr_table->idle_frames; /* * New psr options 0=500us, 1=100us, 2=2500us, 3=0us @@ -2480,6 +2478,25 @@ static int parse_bdb_216_dp_max_link_rate(const int vbt_max_link_rate) } } +static u32 edp_rate_override_mask(int rate) +{ + switch (rate) { + case 2000000: return BDB_263_VBT_EDP_LINK_RATE_20; + case 1350000: return BDB_263_VBT_EDP_LINK_RATE_13_5; + case 1000000: return BDB_263_VBT_EDP_LINK_RATE_10; + case 810000: return BDB_263_VBT_EDP_LINK_RATE_8_1; + case 675000: return BDB_263_VBT_EDP_LINK_RATE_6_75; + case 540000: return BDB_263_VBT_EDP_LINK_RATE_5_4; + case 432000: return BDB_263_VBT_EDP_LINK_RATE_4_32; + case 324000: return BDB_263_VBT_EDP_LINK_RATE_3_24; + case 270000: return BDB_263_VBT_EDP_LINK_RATE_2_7; + case 243000: return BDB_263_VBT_EDP_LINK_RATE_2_43; + case 216000: return BDB_263_VBT_EDP_LINK_RATE_2_16; + case 162000: return BDB_263_VBT_EDP_LINK_RATE_1_62; + default: return 0; + } +} + int intel_bios_dp_max_link_rate(const struct intel_bios_encoder_data *devdata) { if (!devdata || devdata->display->vbt.version < 216) @@ -2499,6 +2516,19 @@ int intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data *devdata) return devdata->child.dp_max_lane_count + 1; } +bool +intel_bios_encoder_reject_edp_rate(const struct intel_bios_encoder_data *devdata, + int rate) +{ + if (!devdata || devdata->display->vbt.version < 263) + return false; + + if (devdata->child.edp_data_rate_override == BDB_263_VBT_EDP_RATES_MASK) + return false; + + return devdata->child.edp_data_rate_override & edp_rate_override_mask(rate); +} + static void sanitize_device_type(struct intel_bios_encoder_data *devdata, enum port port) { @@ -2747,8 +2777,10 @@ static int child_device_expected_size(u16 version) { BUILD_BUG_ON(sizeof(struct child_device_config) < 40); - if (version > 256) + if (version > 263) return -ENOENT; + else if (version >= 263) + return 44; else if (version >= 256) return 40; else if (version >= 216) @@ -3743,8 +3775,6 @@ DEFINE_SHOW_ATTRIBUTE(intel_bios_vbt); void intel_bios_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; - - debugfs_create_file("i915_vbt", 0444, minor->debugfs_root, + debugfs_create_file("i915_vbt", 0444, display->drm->debugfs_root, display, &intel_bios_vbt_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index 6cd7a011b8c4..f9e438b2787b 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -50,180 +50,6 @@ enum intel_backlight_type { INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE, }; -/* - * MIPI Sequence Block definitions - * - * Note the VBT spec has AssertReset / DeassertReset swapped from their - * usual naming, we use the proper names here to avoid confusion when - * reading the code. - */ -enum mipi_seq { - MIPI_SEQ_END = 0, - MIPI_SEQ_DEASSERT_RESET, /* Spec says MipiAssertResetPin */ - MIPI_SEQ_INIT_OTP, - MIPI_SEQ_DISPLAY_ON, - MIPI_SEQ_DISPLAY_OFF, - MIPI_SEQ_ASSERT_RESET, /* Spec says MipiDeassertResetPin */ - MIPI_SEQ_BACKLIGHT_ON, /* sequence block v2+ */ - MIPI_SEQ_BACKLIGHT_OFF, /* sequence block v2+ */ - MIPI_SEQ_TEAR_ON, /* sequence block v2+ */ - MIPI_SEQ_TEAR_OFF, /* sequence block v3+ */ - MIPI_SEQ_POWER_ON, /* sequence block v3+ */ - MIPI_SEQ_POWER_OFF, /* sequence block v3+ */ - MIPI_SEQ_MAX -}; - -enum mipi_seq_element { - MIPI_SEQ_ELEM_END = 0, - MIPI_SEQ_ELEM_SEND_PKT, - MIPI_SEQ_ELEM_DELAY, - MIPI_SEQ_ELEM_GPIO, - MIPI_SEQ_ELEM_I2C, /* sequence block v2+ */ - MIPI_SEQ_ELEM_SPI, /* sequence block v3+ */ - MIPI_SEQ_ELEM_PMIC, /* sequence block v3+ */ - MIPI_SEQ_ELEM_MAX -}; - -#define MIPI_DSI_UNDEFINED_PANEL_ID 0 -#define MIPI_DSI_GENERIC_PANEL_ID 1 - -struct mipi_config { - u16 panel_id; - - /* General Params */ - u32 enable_dithering:1; - u32 rsvd1:1; - u32 is_bridge:1; - - u32 panel_arch_type:2; - u32 is_cmd_mode:1; - -#define NON_BURST_SYNC_PULSE 0x1 -#define NON_BURST_SYNC_EVENTS 0x2 -#define BURST_MODE 0x3 - u32 video_transfer_mode:2; - - u32 cabc_supported:1; -#define PPS_BLC_PMIC 0 -#define PPS_BLC_SOC 1 - u32 pwm_blc:1; - - /* Bit 13:10 */ -#define PIXEL_FORMAT_RGB565 0x1 -#define PIXEL_FORMAT_RGB666 0x2 -#define PIXEL_FORMAT_RGB666_LOOSELY_PACKED 0x3 -#define PIXEL_FORMAT_RGB888 0x4 - u32 videomode_color_format:4; - - /* Bit 15:14 */ -#define ENABLE_ROTATION_0 0x0 -#define ENABLE_ROTATION_90 0x1 -#define ENABLE_ROTATION_180 0x2 -#define ENABLE_ROTATION_270 0x3 - u32 rotation:2; - u32 bta_enabled:1; - u32 rsvd2:15; - - /* 2 byte Port Description */ -#define DUAL_LINK_NOT_SUPPORTED 0 -#define DUAL_LINK_FRONT_BACK 1 -#define DUAL_LINK_PIXEL_ALT 2 - u16 dual_link:2; - u16 lane_cnt:2; - u16 pixel_overlap:3; - u16 rgb_flip:1; -#define DL_DCS_PORT_A 0x00 -#define DL_DCS_PORT_C 0x01 -#define DL_DCS_PORT_A_AND_C 0x02 - u16 dl_dcs_cabc_ports:2; - u16 dl_dcs_backlight_ports:2; - u16 rsvd3:4; - - u16 rsvd4; - - u8 rsvd5; - u32 target_burst_mode_freq; - u32 dsi_ddr_clk; - u32 bridge_ref_clk; - -#define BYTE_CLK_SEL_20MHZ 0 -#define BYTE_CLK_SEL_10MHZ 1 -#define BYTE_CLK_SEL_5MHZ 2 - u8 byte_clk_sel:2; - - u8 rsvd6:6; - - /* DPHY Flags */ - u16 dphy_param_valid:1; - u16 eot_pkt_disabled:1; - u16 enable_clk_stop:1; - u16 rsvd7:13; - - u32 hs_tx_timeout; - u32 lp_rx_timeout; - u32 turn_around_timeout; - u32 device_reset_timer; - u32 master_init_timer; - u32 dbi_bw_timer; - u32 lp_byte_clk_val; - - /* 4 byte Dphy Params */ - u32 prepare_cnt:6; - u32 rsvd8:2; - u32 clk_zero_cnt:8; - u32 trail_cnt:5; - u32 rsvd9:3; - u32 exit_zero_cnt:6; - u32 rsvd10:2; - - u32 clk_lane_switch_cnt; - u32 hl_switch_cnt; - - u32 rsvd11[6]; - - /* timings based on dphy spec */ - u8 tclk_miss; - u8 tclk_post; - u8 rsvd12; - u8 tclk_pre; - u8 tclk_prepare; - u8 tclk_settle; - u8 tclk_term_enable; - u8 tclk_trail; - u16 tclk_prepare_clkzero; - u8 rsvd13; - u8 td_term_enable; - u8 teot; - u8 ths_exit; - u8 ths_prepare; - u16 ths_prepare_hszero; - u8 rsvd14; - u8 ths_settle; - u8 ths_skip; - u8 ths_trail; - u8 tinit; - u8 tlpx; - u8 rsvd15[3]; - - /* GPIOs */ - u8 panel_enable; - u8 bl_enable; - u8 pwm_enable; - u8 reset_r_n; - u8 pwr_down_r; - u8 stdby_r_n; - -} __packed; - -/* all delays have a unit of 100us */ -struct mipi_pps_data { - u16 panel_on_delay; - u16 bl_enable_delay; - u16 bl_disable_delay; - u16 panel_off_delay; - u16 panel_power_cycle_delay; -} __packed; - void intel_bios_init(struct intel_display *display); void intel_bios_init_panel_early(struct intel_display *display, struct intel_panel *panel, @@ -259,6 +85,8 @@ bool intel_bios_encoder_is_lspcon(const struct intel_bios_encoder_data *devdata) bool intel_bios_encoder_lane_reversal(const struct intel_bios_encoder_data *devdata); bool intel_bios_encoder_hpd_invert(const struct intel_bios_encoder_data *devdata); enum port intel_bios_encoder_port(const struct intel_bios_encoder_data *devdata); +bool intel_bios_encoder_reject_edp_rate(const struct intel_bios_encoder_data *devdata, + int rate); enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data *devdata); diff --git a/drivers/gpu/drm/i915/display/intel_bo.c b/drivers/gpu/drm/i915/display/intel_bo.c index 65d64f79a4bd..6ae1374d5c2b 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.c +++ b/drivers/gpu/drm/i915/display/intel_bo.c @@ -2,7 +2,7 @@ /* Copyright © 2024 Intel Corporation */ #include <drm/drm_panic.h> -#include "display/intel_display_types.h" + #include "gem/i915_gem_mman.h" #include "gem/i915_gem_object.h" #include "gem/i915_gem_object_frontbuffer.h" @@ -59,18 +59,3 @@ void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj) { i915_debugfs_describe_obj(m, to_intel_bo(obj)); } - -struct intel_framebuffer *intel_bo_alloc_framebuffer(void) -{ - return i915_gem_object_alloc_framebuffer(); -} - -int intel_bo_panic_setup(struct drm_scanout_buffer *sb) -{ - return i915_gem_object_panic_setup(sb); -} - -void intel_bo_panic_finish(struct intel_framebuffer *fb) -{ - return i915_gem_object_panic_finish(fb); -} diff --git a/drivers/gpu/drm/i915/display/intel_bo.h b/drivers/gpu/drm/i915/display/intel_bo.h index 97087a64d23b..48d87019e48a 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.h +++ b/drivers/gpu/drm/i915/display/intel_bo.h @@ -25,8 +25,5 @@ struct intel_frontbuffer *intel_bo_set_frontbuffer(struct drm_gem_object *obj, struct intel_frontbuffer *front); void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj); -struct intel_framebuffer *intel_bo_alloc_framebuffer(void); -int intel_bo_panic_setup(struct drm_scanout_buffer *sb); -void intel_bo_panic_finish(struct intel_framebuffer *fb); #endif /* __INTEL_BO__ */ diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index d29a755612de..ac6da20d9529 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -359,7 +359,7 @@ static int icl_get_qgv_points(struct intel_display *display, for (i = 0; i < qi->num_psf_points; i++) drm_dbg_kms(display->drm, - "PSF GV %d: CLK=%d \n", + "PSF GV %d: CLK=%d\n", i, qi->psf_points[i].clk); } diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 228aa64c1349..b54b1006aeb0 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -22,6 +22,7 @@ */ #include <linux/debugfs.h> +#include <linux/iopoll.h> #include <linux/time.h> #include <drm/drm_fixed.h> @@ -31,6 +32,7 @@ #include "hsw_ips.h" #include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_atomic.h" #include "intel_audio.h" #include "intel_bw.h" @@ -47,6 +49,7 @@ #include "intel_vdsc.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" +#include "vlv_clock.h" #include "vlv_dsi.h" #include "vlv_sideband.h" @@ -561,8 +564,7 @@ static void hsw_get_cdclk(struct intel_display *display, static int vlv_calc_cdclk(struct intel_display *display, int min_cdclk) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - int freq_320 = (dev_priv->hpll_freq << 1) % 320000 != 0 ? + int freq_320 = (vlv_clock_get_hpll_vco(display->drm) << 1) % 320000 != 0 ? 333333 : 320000; /* @@ -582,8 +584,6 @@ static int vlv_calc_cdclk(struct intel_display *display, int min_cdclk) static u8 vlv_calc_voltage_level(struct intel_display *display, int cdclk) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - if (display->platform.valleyview) { if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */ return 2; @@ -597,7 +597,7 @@ static u8 vlv_calc_voltage_level(struct intel_display *display, int cdclk) * hardware has shown that we just need to write the desired * CCK divider into the Punit register. */ - return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1; + return DIV_ROUND_CLOSEST(vlv_clock_get_hpll_vco(display->drm) << 1, cdclk) - 1; } } @@ -606,17 +606,12 @@ static void vlv_get_cdclk(struct intel_display *display, { u32 val; - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK) | BIT(VLV_IOSF_SB_PUNIT)); - - cdclk_config->vco = vlv_get_hpll_vco(display->drm); - cdclk_config->cdclk = vlv_get_cck_clock(display->drm, "cdclk", - CCK_DISPLAY_CLOCK_CONTROL, - cdclk_config->vco); + cdclk_config->vco = vlv_clock_get_hpll_vco(display->drm); + cdclk_config->cdclk = vlv_clock_get_cdclk(display->drm); + vlv_punit_get(display->drm); val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); - - vlv_iosf_sb_put(display->drm, - BIT(VLV_IOSF_SB_CCK) | BIT(VLV_IOSF_SB_PUNIT)); + vlv_punit_put(display->drm); if (display->platform.valleyview) cdclk_config->voltage_level = (val & DSPFREQGUAR_MASK) >> @@ -628,7 +623,6 @@ static void vlv_get_cdclk(struct intel_display *display, static void vlv_program_pfi_credits(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); unsigned int credits, default_credits; if (display->platform.cherryview) @@ -636,7 +630,7 @@ static void vlv_program_pfi_credits(struct intel_display *display) else default_credits = PFI_CREDIT(8); - if (display->cdclk.hw.cdclk >= dev_priv->czclk_freq) { + if (display->cdclk.hw.cdclk >= vlv_clock_get_czclk(display->drm)) { /* CHV suggested value is 31 or 63 */ if (display->platform.cherryview) credits = PFI_CREDIT_63; @@ -668,10 +662,10 @@ static void vlv_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { - struct drm_i915_private *dev_priv = to_i915(display->drm); int cdclk = cdclk_config->cdclk; u32 val, cmd = cdclk_config->voltage_level; intel_wakeref_t wakeref; + int ret; switch (cdclk) { case 400000: @@ -702,17 +696,17 @@ static void vlv_set_cdclk(struct intel_display *display, val &= ~DSPFREQGUAR_MASK; val |= (cmd << DSPFREQGUAR_SHIFT); vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val); - if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM) & - DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), - 50)) { - drm_err(display->drm, - "timed out waiting for CDclk change\n"); - } + + ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM), + (val & DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), + 500, 50 * 1000, false); + if (ret) + drm_err(display->drm, "timed out waiting for CDCLK change\n"); if (cdclk == 400000) { u32 divider; - divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, + divider = DIV_ROUND_CLOSEST(vlv_clock_get_hpll_vco(display->drm) << 1, cdclk) - 1; /* adjust cdclk divider */ @@ -721,11 +715,11 @@ static void vlv_set_cdclk(struct intel_display *display, val |= divider; vlv_cck_write(display->drm, CCK_DISPLAY_CLOCK_CONTROL, val); - if (wait_for((vlv_cck_read(display->drm, CCK_DISPLAY_CLOCK_CONTROL) & - CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT), - 50)) - drm_err(display->drm, - "timed out waiting for CDclk change\n"); + ret = poll_timeout_us(val = vlv_cck_read(display->drm, CCK_DISPLAY_CLOCK_CONTROL), + (val & CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT), + 500, 50 * 1000, false); + if (ret) + drm_err(display->drm, "timed out waiting for CDCLK change\n"); } /* adjust self-refresh exit latency value */ @@ -761,6 +755,7 @@ static void chv_set_cdclk(struct intel_display *display, int cdclk = cdclk_config->cdclk; u32 val, cmd = cdclk_config->voltage_level; intel_wakeref_t wakeref; + int ret; switch (cdclk) { case 333333: @@ -786,12 +781,12 @@ static void chv_set_cdclk(struct intel_display *display, val &= ~DSPFREQGUAR_MASK_CHV; val |= (cmd << DSPFREQGUAR_SHIFT_CHV); vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val); - if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM) & - DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV), - 50)) { - drm_err(display->drm, - "timed out waiting for CDclk change\n"); - } + + ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM), + (val & DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV), + 500, 50 * 1000, false); + if (ret) + drm_err(display->drm, "timed out waiting for CDCLK change\n"); vlv_punit_put(display->drm); @@ -903,8 +898,10 @@ static void bdw_set_cdclk(struct intel_display *display, * According to the spec, it should be enough to poll for this 1 us. * However, extensive testing shows that this can take longer. */ - if (wait_for_us(intel_de_read(display, LCPLL_CTL) & - LCPLL_CD_SOURCE_FCLK_DONE, 100)) + ret = intel_de_wait_custom(display, LCPLL_CTL, + LCPLL_CD_SOURCE_FCLK_DONE, LCPLL_CD_SOURCE_FCLK_DONE, + 100, 0, NULL); + if (ret) drm_err(display->drm, "Switching to FCLK failed\n"); intel_de_rmw(display, LCPLL_CTL, @@ -913,8 +910,10 @@ static void bdw_set_cdclk(struct intel_display *display, intel_de_rmw(display, LCPLL_CTL, LCPLL_CD_SOURCE_FCLK, 0); - if (wait_for_us((intel_de_read(display, LCPLL_CTL) & - LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) + ret = intel_de_wait_custom(display, LCPLL_CTL, + LCPLL_CD_SOURCE_FCLK_DONE, 0, + 1, 0, NULL); + if (ret) drm_err(display->drm, "Switching back to LCPLL failed\n"); intel_pcode_write(display->drm, HSW_PCODE_DE_WRITE_FREQ_REQ, @@ -3557,19 +3556,12 @@ static int pch_rawclk(struct intel_display *display) return (intel_de_read(display, PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000; } -static int vlv_hrawclk(struct intel_display *display) -{ - /* RAWCLK_FREQ_VLV register updated from power well code */ - return vlv_get_cck_clock_hpll(display->drm, "hrawclk", - CCK_DISPLAY_REF_CLOCK_CONTROL); -} - static int i9xx_hrawclk(struct intel_display *display) { struct drm_i915_private *i915 = to_i915(display->drm); /* hrawclock is 1/4 the FSB frequency */ - return DIV_ROUND_CLOSEST(i9xx_fsb_freq(i915), 4); + return DIV_ROUND_CLOSEST(intel_fsb_freq(i915), 4); } /** @@ -3597,7 +3589,7 @@ u32 intel_read_rawclk(struct intel_display *display) else if (HAS_PCH_SPLIT(display)) freq = pch_rawclk(display); else if (display->platform.valleyview || display->platform.cherryview) - freq = vlv_hrawclk(display); + freq = vlv_clock_get_hrawclk(display->drm); else if (DISPLAY_VER(display) >= 3) freq = i9xx_hrawclk(display); else @@ -3622,9 +3614,7 @@ DEFINE_SHOW_ATTRIBUTE(i915_cdclk_info); void intel_cdclk_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; - - debugfs_create_file("i915_cdclk_info", 0444, minor->debugfs_root, + debugfs_create_file("i915_cdclk_info", 0444, display->drm->debugfs_root, display, &i915_cdclk_info_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 671db6926e4c..51db70d07fae 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -2013,7 +2013,7 @@ void intel_color_prepare_commit(struct intel_atomic_state *state, if (crtc_state->use_dsb && intel_color_uses_chained_dsb(crtc_state)) { intel_vrr_send_push(crtc_state->dsb_color, crtc_state); - intel_dsb_wait_vblank_delay(state, crtc_state->dsb_color); + intel_dsb_wait_for_delayed_vblank(state, crtc_state->dsb_color); intel_vrr_check_push_sent(crtc_state->dsb_color, crtc_state); intel_dsb_interrupt(crtc_state->dsb_color); } diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index 42c923f416b3..6a55854db5b6 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -77,7 +77,7 @@ void intel_connector_cancel_modeset_retry_work(struct intel_connector *connector drm_connector_put(&connector->base); } -int intel_connector_init(struct intel_connector *connector) +static int intel_connector_init(struct intel_connector *connector) { struct intel_digital_connector_state *conn_state; diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h index aafb25a814fa..0aa86626e646 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.h +++ b/drivers/gpu/drm/i915/display/intel_connector.h @@ -14,7 +14,6 @@ struct i2c_adapter; struct intel_connector; struct intel_encoder; -int intel_connector_init(struct intel_connector *connector); struct intel_connector *intel_connector_alloc(void); void intel_connector_free(struct intel_connector *connector); void intel_connector_destroy(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 898c5d9e8f7a..31e68047f217 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -50,6 +50,7 @@ #include "intel_gmbus.h" #include "intel_hotplug.h" #include "intel_hotplug_irq.h" +#include "intel_link_bw.h" #include "intel_load_detect.h" #include "intel_pch_display.h" #include "intel_pch_refclk.h" @@ -421,7 +422,7 @@ static int pch_crt_compute_config(struct intel_encoder *encoder, return -EINVAL; crtc_state->has_pch_encoder = true; - if (!intel_fdi_compute_pipe_bpp(crtc_state)) + if (!intel_link_bw_compute_pipe_bpp(crtc_state)) return -EINVAL; crtc_state->output_format = INTEL_OUTPUT_FORMAT_RGB; @@ -446,7 +447,7 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder, return -EINVAL; crtc_state->has_pch_encoder = true; - if (!intel_fdi_compute_pipe_bpp(crtc_state)) + if (!intel_link_bw_compute_pipe_bpp(crtc_state)) return -EINVAL; crtc_state->output_format = INTEL_OUTPUT_FORMAT_RGB; diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 0c7f91046996..a14bcda4446c 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -289,10 +289,11 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_printf(&p, "scanline offset: %d\n", intel_crtc_scanline_offset(pipe_config)); - drm_printf(&p, "vblank delay: %d, framestart delay: %d, MSA timing delay: %d\n", + drm_printf(&p, "vblank delay: %d, framestart delay: %d, MSA timing delay: %d set context latency: %d\n", pipe_config->hw.adjusted_mode.crtc_vblank_start - pipe_config->hw.adjusted_mode.crtc_vdisplay, - pipe_config->framestart_delay, pipe_config->msa_timing_delay); + pipe_config->framestart_delay, pipe_config->msa_timing_delay, + pipe_config->set_context_latency); drm_printf(&p, "vrr: %s, fixed rr: %s, vmin: %d, vmax: %d, flipline: %d, pipeline full: %d, guardband: %d vsync start: %d, vsync end: %d\n", str_yes_no(pipe_config->vrr.enable), diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 198e69efe9ac..c47c84935871 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -33,17 +33,9 @@ static const u32 intel_cursor_formats[] = { DRM_FORMAT_ARGB8888, }; -static u32 intel_cursor_base(const struct intel_plane_state *plane_state) +static u32 intel_cursor_surf_offset(const struct intel_plane_state *plane_state) { - struct intel_display *display = to_intel_display(plane_state); - u32 base; - - if (DISPLAY_INFO(display)->cursor_needs_physical) - base = plane_state->phys_dma_addr; - else - base = intel_plane_ggtt_offset(plane_state); - - return base + plane_state->view.color_plane[0].offset; + return plane_state->view.color_plane[0].offset; } static u32 intel_cursor_position(const struct intel_crtc_state *crtc_state, @@ -213,8 +205,7 @@ static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state) return cntl; } -static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 i845_cursor_ctl(const struct intel_plane_state *plane_state) { return CURSOR_ENABLE | CURSOR_FORMAT_ARGB | @@ -274,7 +265,7 @@ static int i845_check_cursor(struct intel_crtc_state *crtc_state, return -EINVAL; } - plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state); + plane_state->ctl = i845_cursor_ctl(plane_state); return 0; } @@ -297,7 +288,7 @@ static void i845_cursor_update_arm(struct intel_dsb *dsb, size = CURSOR_HEIGHT(height) | CURSOR_WIDTH(width); - base = intel_cursor_base(plane_state); + base = plane_state->surf; pos = intel_cursor_position(crtc_state, plane_state, false); } @@ -406,8 +397,7 @@ static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state) return cntl; } -static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 i9xx_cursor_ctl(const struct intel_plane_state *plane_state) { struct intel_display *display = to_intel_display(plane_state); u32 cntl = 0; @@ -534,7 +524,7 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, return -EINVAL; } - plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state); + plane_state->ctl = i9xx_cursor_ctl(plane_state); return 0; } @@ -672,10 +662,10 @@ static void i9xx_cursor_update_arm(struct intel_dsb *dsb, cntl = plane_state->ctl | i9xx_cursor_ctl_crtc(crtc_state); - if (width != height) + if (DISPLAY_VER(display) < 14 && width != height) fbc_ctl = CUR_FBC_EN | CUR_FBC_HEIGHT(height - 1); - base = intel_cursor_base(plane_state); + base = plane_state->surf; pos = intel_cursor_position(crtc_state, plane_state, false); } @@ -1051,6 +1041,8 @@ intel_cursor_plane_create(struct intel_display *display, cursor->check_plane = i9xx_check_cursor; } + cursor->surf_offset = intel_cursor_surf_offset; + if (DISPLAY_VER(display) >= 5 || display->platform.g4x) cursor->capture_error = g4x_cursor_capture_error; else diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 801235a5bc0a..a2d2cecf7121 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -39,14 +39,12 @@ bool intel_encoder_is_c10phy(struct intel_encoder *encoder) struct intel_display *display = to_intel_display(encoder); enum phy phy = intel_encoder_to_phy(encoder); - /* PTL doesn't have a PHY connected to PORT B; as such, - * there will never be a case where PTL uses PHY B. - * WCL uses PORT A and B with the C10 PHY. - * Reusing the condition for WCL and extending it for PORT B - * should not cause any issues for PTL. - */ - if (display->platform.pantherlake && phy < PHY_C) - return true; + if (display->platform.pantherlake) { + if (display->platform.pantherlake_wildcatlake) + return phy <= PHY_B; + else + return phy == PHY_A; + } if ((display->platform.lunarlake || display->platform.meteorlake) && phy < PHY_C) return true; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 0405396c7750..c09aa759f4d4 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -26,6 +26,7 @@ */ #include <linux/iopoll.h> +#include <linux/seq_buf.h> #include <linux/string_helpers.h> #include <drm/display/drm_dp_helper.h> @@ -596,8 +597,9 @@ intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, enum transcoder master; master = crtc_state->mst_master_transcoder; - drm_WARN_ON(display->drm, - master == INVALID_TRANSCODER); + if (drm_WARN_ON(display->drm, + master == INVALID_TRANSCODER)) + master = TRANSCODER_A; temp |= TRANS_DDI_MST_TRANSPORT_SELECT(master); } } else { @@ -2166,7 +2168,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, { struct intel_display *display = to_intel_display(crtc_state); enum tc_port tc_port = intel_encoder_to_tc(&dig_port->base); - u32 ln0, ln1, pin_assignment; + enum intel_tc_pin_assignment pin_assignment; + u32 ln0, ln1; u8 width; if (DISPLAY_VER(display) >= 14) @@ -2188,11 +2191,11 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); /* DPPATC */ - pin_assignment = intel_tc_port_get_pin_assignment_mask(dig_port); + pin_assignment = intel_tc_port_get_pin_assignment(dig_port); width = crtc_state->lane_count; switch (pin_assignment) { - case 0x0: + case INTEL_TC_PIN_ASSIGNMENT_NONE: drm_WARN_ON(display->drm, !intel_tc_port_in_legacy_mode(dig_port)); if (width == 1) { @@ -2202,20 +2205,20 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, ln1 |= MG_DP_MODE_CFG_DP_X2_MODE; } break; - case 0x1: + case INTEL_TC_PIN_ASSIGNMENT_A: if (width == 4) { ln0 |= MG_DP_MODE_CFG_DP_X2_MODE; ln1 |= MG_DP_MODE_CFG_DP_X2_MODE; } break; - case 0x2: + case INTEL_TC_PIN_ASSIGNMENT_B: if (width == 2) { ln0 |= MG_DP_MODE_CFG_DP_X2_MODE; ln1 |= MG_DP_MODE_CFG_DP_X2_MODE; } break; - case 0x3: - case 0x5: + case INTEL_TC_PIN_ASSIGNMENT_C: + case INTEL_TC_PIN_ASSIGNMENT_E: if (width == 1) { ln0 |= MG_DP_MODE_CFG_DP_X1_MODE; ln1 |= MG_DP_MODE_CFG_DP_X1_MODE; @@ -2224,8 +2227,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, ln1 |= MG_DP_MODE_CFG_DP_X2_MODE; } break; - case 0x4: - case 0x6: + case INTEL_TC_PIN_ASSIGNMENT_D: + case INTEL_TC_PIN_ASSIGNMENT_F: if (width == 1) { ln0 |= MG_DP_MODE_CFG_DP_X1_MODE; ln1 |= MG_DP_MODE_CFG_DP_X1_MODE; @@ -2339,34 +2342,24 @@ static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, drm_dbg_kms(display->drm, "Failed to clear FEC detected flags\n"); } -static int read_fec_detected_status(struct drm_dp_aux *aux) -{ - int ret; - u8 status; - - ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status); - if (ret < 0) - return ret; - - return status; -} - static int wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled) { struct intel_display *display = to_intel_display(aux->drm_dev); int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED; - int status; - int err; + u8 status = 0; + int ret, err; - err = readx_poll_timeout(read_fec_detected_status, aux, status, - status & mask || status < 0, - 10000, 200000); + ret = poll_timeout_us(err = drm_dp_dpcd_read_byte(aux, DP_FEC_STATUS, &status), + err || (status & mask), + 10 * 1000, 200 * 1000, false); - if (err || status < 0) { + /* Either can be non-zero, but not both */ + ret = ret ?: err; + if (ret) { drm_dbg_kms(display->drm, - "Failed waiting for FEC %s to get detected: %d (status %d)\n", - str_enabled_disabled(enabled), err, status); - return err ? err : status; + "Failed waiting for FEC %s to get detected: %d (status 0x%02x)\n", + str_enabled_disabled(enabled), ret, status); + return ret; } return 0; @@ -2561,6 +2554,7 @@ mtl_ddi_enable_d2d(struct intel_encoder *encoder) enum port port = encoder->port; i915_reg_t reg; u32 set_bits, wait_bits; + int ret; if (DISPLAY_VER(display) < 14) return; @@ -2576,7 +2570,11 @@ mtl_ddi_enable_d2d(struct intel_encoder *encoder) } intel_de_rmw(display, reg, 0, set_bits); - if (wait_for_us(intel_de_read(display, reg) & wait_bits, 100)) { + + ret = intel_de_wait_custom(display, reg, + wait_bits, wait_bits, + 100, 0, NULL); + if (ret) { drm_err(display->drm, "Timeout waiting for D2D Link enable for DDI/PORT_BUF_CTL %c\n", port_name(port)); } @@ -3058,6 +3056,7 @@ mtl_ddi_disable_d2d(struct intel_encoder *encoder) enum port port = encoder->port; i915_reg_t reg; u32 clr_bits, wait_bits; + int ret; if (DISPLAY_VER(display) < 14) return; @@ -3073,7 +3072,11 @@ mtl_ddi_disable_d2d(struct intel_encoder *encoder) } intel_de_rmw(display, reg, clr_bits, 0); - if (wait_for_us(!(intel_de_read(display, reg) & wait_bits), 100)) + + ret = intel_de_wait_custom(display, reg, + wait_bits, 0, + 100, 0, NULL); + if (ret) drm_err(display->drm, "Timeout waiting for D2D Link disable for DDI/PORT_BUF_CTL %c\n", port_name(port)); } @@ -5066,11 +5069,45 @@ static bool port_in_use(struct intel_display *display, enum port port) return false; } +static const char *intel_ddi_encoder_name(struct intel_display *display, + enum port port, enum phy phy, + struct seq_buf *s) +{ + if (DISPLAY_VER(display) >= 13 && port >= PORT_D_XELPD) { + seq_buf_printf(s, "DDI %c/PHY %c", + port_name(port - PORT_D_XELPD + PORT_D), + phy_name(phy)); + } else if (DISPLAY_VER(display) >= 12) { + enum tc_port tc_port = intel_port_to_tc(display, port); + + seq_buf_printf(s, "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 (DISPLAY_VER(display) >= 11) { + enum tc_port tc_port = intel_port_to_tc(display, port); + + seq_buf_printf(s, "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 { + seq_buf_printf(s, "DDI %c/PHY %c", port_name(port), phy_name(phy)); + } + + drm_WARN_ON(display->drm, seq_buf_has_overflowed(s)); + + return seq_buf_str(s); +} + void intel_ddi_init(struct intel_display *display, const struct intel_bios_encoder_data *devdata) { struct intel_digital_port *dig_port; struct intel_encoder *encoder; + DECLARE_SEQ_BUF(encoder_name, 20); bool init_hdmi, init_dp; enum port port; enum phy phy; @@ -5148,52 +5185,19 @@ void intel_ddi_init(struct intel_display *display, phy_name(phy)); } - dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL); + dig_port = intel_dig_port_alloc(); if (!dig_port) return; - dig_port->aux_ch = AUX_CH_NONE; - encoder = &dig_port->base; encoder->devdata = devdata; - if (DISPLAY_VER(display) >= 13 && port >= PORT_D_XELPD) { - drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs, - DRM_MODE_ENCODER_TMDS, - "DDI %c/PHY %c", - port_name(port - PORT_D_XELPD + PORT_D), - phy_name(phy)); - } else if (DISPLAY_VER(display) >= 12) { - enum tc_port tc_port = intel_port_to_tc(display, port); - - drm_encoder_init(display->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 (DISPLAY_VER(display) >= 11) { - enum tc_port tc_port = intel_port_to_tc(display, port); - - drm_encoder_init(display->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(display->drm, &encoder->base, &intel_ddi_funcs, - DRM_MODE_ENCODER_TMDS, - "DDI %c/PHY %c", port_name(port), phy_name(phy)); - } + drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs, + DRM_MODE_ENCODER_TMDS, "%s", + intel_ddi_encoder_name(display, port, phy, &encoder_name)); intel_encoder_link_check_init(encoder, intel_ddi_link_check); - mutex_init(&dig_port->hdcp.mutex); - dig_port->hdcp.num_streams = 0; - encoder->hotplug = intel_ddi_hotplug; encoder->compute_output_type = intel_ddi_compute_output_type; encoder->compute_config = intel_ddi_compute_config; @@ -5331,7 +5335,6 @@ void intel_ddi_init(struct intel_display *display, dig_port->ddi_a_4_lanes = DISPLAY_VER(display) < 11 && ddi_buf_ctl & DDI_A_4_LANES; - dig_port->dp.output_reg = INVALID_MMIO_REG; dig_port->max_lanes = intel_ddi_max_lanes(dig_port); if (need_aux_ch(encoder, init_dp)) { diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 7035c1fc9033..b57efd870774 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -76,6 +76,7 @@ #include "intel_display_regs.h" #include "intel_display_rpm.h" #include "intel_display_types.h" +#include "intel_display_wa.h" #include "intel_dmc.h" #include "intel_dp.h" #include "intel_dp_link_training.h" @@ -128,11 +129,9 @@ #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" -#include "vlv_dpio_phy_regs.h" #include "vlv_dsi.h" #include "vlv_dsi_pll.h" #include "vlv_dsi_regs.h" -#include "vlv_sideband.h" 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); @@ -140,65 +139,6 @@ static void hsw_set_transconf(const struct intel_crtc_state *crtc_state); static void bdw_set_pipe_misc(struct intel_dsb *dsb, const struct intel_crtc_state *crtc_state); -/* returns HPLL frequency in kHz */ -int vlv_get_hpll_vco(struct drm_device *drm) -{ - int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - - /* Obtain SKU information */ - hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & - CCK_FUSE_HPLL_FREQ_MASK; - - return vco_freq[hpll_freq] * 1000; -} - -int vlv_get_cck_clock(struct drm_device *drm, - const char *name, u32 reg, int ref_freq) -{ - u32 val; - int divider; - - val = vlv_cck_read(drm, reg); - divider = val & CCK_FREQUENCY_VALUES; - - drm_WARN(drm, (val & CCK_FREQUENCY_STATUS) != - (divider << CCK_FREQUENCY_STATUS_SHIFT), - "%s change in progress\n", name); - - return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); -} - -int vlv_get_cck_clock_hpll(struct drm_device *drm, - const char *name, u32 reg) -{ - struct drm_i915_private *dev_priv = to_i915(drm); - int hpll; - - vlv_cck_get(drm); - - if (dev_priv->hpll_freq == 0) - dev_priv->hpll_freq = vlv_get_hpll_vco(drm); - - hpll = vlv_get_cck_clock(drm, name, reg, dev_priv->hpll_freq); - - vlv_cck_put(drm); - - return hpll; -} - -void intel_update_czclk(struct intel_display *display) -{ - struct drm_i915_private *dev_priv = to_i915(display->drm); - - if (!display->platform.valleyview && !display->platform.cherryview) - return; - - dev_priv->czclk_freq = vlv_get_cck_clock_hpll(display->drm, "czclk", - CCK_CZ_CLOCK_CONTROL); - - drm_dbg_kms(display->drm, "CZ clock rate: %d kHz\n", dev_priv->czclk_freq); -} - static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) { return (crtc_state->active_planes & @@ -1081,6 +1021,11 @@ static void intel_post_plane_update(struct intel_atomic_state *state, if (audio_enabling(old_crtc_state, new_crtc_state)) intel_encoders_audio_enable(state, crtc); + if (intel_display_wa(display, 14011503117)) { + if (old_crtc_state->pch_pfit.enabled != new_crtc_state->pch_pfit.enabled) + adl_scaler_ecc_unmask(new_crtc_state); + } + intel_alpm_post_plane_update(state, crtc); intel_psr_post_plane_update(state, crtc); @@ -2416,39 +2361,44 @@ static int intel_crtc_compute_pipe_mode(struct intel_crtc_state *crtc_state) return 0; } -static int intel_crtc_vblank_delay(const struct intel_crtc_state *crtc_state) +static int intel_crtc_set_context_latency(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - int vblank_delay = 0; + int set_context_latency = 0; if (!HAS_DSB(display)) return 0; - vblank_delay = max(vblank_delay, intel_psr_min_vblank_delay(crtc_state)); + set_context_latency = max(set_context_latency, + intel_psr_min_set_context_latency(crtc_state)); - return vblank_delay; + return set_context_latency; } -static int intel_crtc_compute_vblank_delay(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static int intel_crtc_compute_set_context_latency(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct intel_display *display = to_intel_display(state); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - int vblank_delay, max_vblank_delay; + int set_context_latency, max_vblank_delay; + + set_context_latency = intel_crtc_set_context_latency(crtc_state); - vblank_delay = intel_crtc_vblank_delay(crtc_state); max_vblank_delay = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start - 1; - if (vblank_delay > max_vblank_delay) { - drm_dbg_kms(display->drm, "[CRTC:%d:%s] vblank delay (%d) exceeds max (%d)\n", - crtc->base.base.id, crtc->base.name, vblank_delay, max_vblank_delay); + if (set_context_latency > max_vblank_delay) { + drm_dbg_kms(display->drm, "[CRTC:%d:%s] set context latency (%d) exceeds max (%d)\n", + crtc->base.base.id, crtc->base.name, + set_context_latency, + max_vblank_delay); return -EINVAL; } - adjusted_mode->crtc_vblank_start += vblank_delay; + crtc_state->set_context_latency = set_context_latency; + adjusted_mode->crtc_vblank_start += set_context_latency; return 0; } @@ -2460,7 +2410,7 @@ static int intel_crtc_compute_config(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); int ret; - ret = intel_crtc_compute_vblank_delay(state, crtc); + ret = intel_crtc_compute_set_context_latency(state, crtc); if (ret) return ret; @@ -2672,7 +2622,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta if (DISPLAY_VER(display) >= 13) { intel_de_write(display, TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder), - crtc_vblank_start - crtc_vdisplay); + crtc_state->set_context_latency); /* * VBLANK_START not used by hw, just clear it @@ -2762,7 +2712,7 @@ static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc if (DISPLAY_VER(display) >= 13) { intel_de_write(display, TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder), - crtc_vblank_start - crtc_vdisplay); + crtc_state->set_context_latency); /* * VBLANK_START not used by hw, just clear it @@ -2875,11 +2825,24 @@ static void intel_get_transcoder_timings(struct intel_crtc *crtc, adjusted_mode->crtc_vblank_end += 1; } - if (DISPLAY_VER(display) >= 13 && !transcoder_is_dsi(cpu_transcoder)) - adjusted_mode->crtc_vblank_start = - adjusted_mode->crtc_vdisplay + + if (DISPLAY_VER(display) >= 13 && !transcoder_is_dsi(cpu_transcoder)) { + pipe_config->set_context_latency = intel_de_read(display, TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder)); + adjusted_mode->crtc_vblank_start = + adjusted_mode->crtc_vdisplay + + pipe_config->set_context_latency; + } else if (DISPLAY_VER(display) == 12) { + /* + * TGL doesn't have a dedicated register for SCL. + * Instead, the hardware derives SCL from the difference between + * TRANS_VBLANK.vblank_start and TRANS_VTOTAL.vactive. + * To reflect the HW behaviour, readout the value for SCL as + * Vblank start - Vactive. + */ + pipe_config->set_context_latency = + adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; + } if (DISPLAY_VER(display) >= 30) pipe_config->min_hblank = intel_de_read(display, @@ -3946,6 +3909,20 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, intel_joiner_get_config(pipe_config); intel_dsc_get_config(pipe_config); + /* intel_vrr_get_config() depends on .framestart_delay */ + if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { + tmp = intel_de_read(display, CHICKEN_TRANS(display, pipe_config->cpu_transcoder)); + + pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; + } else { + /* no idea if this is correct */ + pipe_config->framestart_delay = 1; + } + + /* + * intel_vrr_get_config() depends on TRANS_SET_CONTEXT_LATENCY + * readout done by intel_get_transcoder_timings(). + */ if (!transcoder_is_dsi(pipe_config->cpu_transcoder) || DISPLAY_VER(display) >= 11) intel_get_transcoder_timings(crtc, pipe_config); @@ -3997,15 +3974,6 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, pipe_config->pixel_multiplier = 1; } - if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { - tmp = intel_de_read(display, CHICKEN_TRANS(display, pipe_config->cpu_transcoder)); - - pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; - } else { - /* no idea if this is correct */ - pipe_config->framestart_delay = 1; - } - out: intel_display_power_put_all_in_set(display, &crtc->hw_readout_power_domains); @@ -5437,6 +5405,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(vrr.guardband); } + PIPE_CONF_CHECK_I(set_context_latency); + #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_LLI @@ -7265,6 +7235,9 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, intel_psr_trigger_frame_change_event(new_crtc_state->dsb_commit, state, crtc); + intel_psr_wait_for_idle_dsb(new_crtc_state->dsb_commit, + new_crtc_state); + if (new_crtc_state->use_dsb) intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit); @@ -7298,7 +7271,7 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, intel_dsb_wait_vblanks(new_crtc_state->dsb_commit, 1); intel_vrr_send_push(new_crtc_state->dsb_commit, new_crtc_state); - intel_dsb_wait_vblank_delay(state, new_crtc_state->dsb_commit); + intel_dsb_wait_for_delayed_vblank(state, new_crtc_state->dsb_commit); intel_vrr_check_push_sent(new_crtc_state->dsb_commit, new_crtc_state); intel_dsb_interrupt(new_crtc_state->dsb_commit); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 37e2ab301a80..9a9a44b61f7f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -435,11 +435,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state); void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state); void i830_enable_pipe(struct intel_display *display, enum pipe pipe); void i830_disable_pipe(struct intel_display *display, enum pipe pipe); -int vlv_get_hpll_vco(struct drm_device *drm); -int vlv_get_cck_clock(struct drm_device *drm, - const char *name, u32 reg, int ref_freq); -int vlv_get_cck_clock_hpll(struct drm_device *drm, - const char *name, u32 reg); bool intel_has_pending_fb_unpin(struct intel_display *display); void intel_encoder_destroy(struct drm_encoder *encoder); struct drm_display_mode * @@ -528,7 +523,6 @@ void intel_init_display_hooks(struct intel_display *display); void intel_setup_outputs(struct intel_display *display); int intel_initial_commit(struct intel_display *display); void intel_panel_sanitize_ssc(struct intel_display *display); -void intel_update_czclk(struct intel_display *display); enum drm_mode_status intel_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode); int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, diff --git a/drivers/gpu/drm/i915/display/intel_display_conversion.c b/drivers/gpu/drm/i915/display/intel_display_conversion.c index 4d565935e2cc..d56065f22655 100644 --- a/drivers/gpu/drm/i915/display/intel_display_conversion.c +++ b/drivers/gpu/drm/i915/display/intel_display_conversion.c @@ -4,7 +4,7 @@ #include "i915_drv.h" #include "intel_display_conversion.h" -struct intel_display *__i915_to_display(struct drm_i915_private *i915) +static struct intel_display *__i915_to_display(struct drm_i915_private *i915) { return i915->display; } diff --git a/drivers/gpu/drm/i915/display/intel_display_conversion.h b/drivers/gpu/drm/i915/display/intel_display_conversion.h index 46c7208d42ba..d497bc58a73f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_conversion.h +++ b/drivers/gpu/drm/i915/display/intel_display_conversion.h @@ -9,20 +9,8 @@ #define __INTEL_DISPLAY_CONVERSION__ struct drm_device; -struct drm_i915_private; struct intel_display; -struct intel_display *__i915_to_display(struct drm_i915_private *i915); struct intel_display *__drm_to_display(struct drm_device *drm); -/* - * Transitional macro to optionally convert struct drm_i915_private * to struct - * intel_display *, also accepting the latter. - */ -#define __to_intel_display(p) \ - _Generic(p, \ - const struct drm_i915_private *: __i915_to_display((struct drm_i915_private *)(p)), \ - struct drm_i915_private *: __i915_to_display((struct drm_i915_private *)(p)), \ - const struct intel_display *: (p), \ - struct intel_display *: (p)) #endif /* __INTEL_DISPLAY_CONVERSION__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 8c226406c5cd..df4da52cbdb3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -475,7 +475,21 @@ struct intel_display { struct work_struct vblank_notify_work; - u32 de_irq_mask[I915_MAX_PIPES]; + /* + * Cached value of VLV/CHV IMR to avoid reads in updating the + * bitfield. + */ + u32 vlv_imr_mask; + /* + * Cached value of gen 5-7 DE IMR to avoid reads in updating the + * bitfield. + */ + u32 ilk_de_imr_mask; + /* + * Cached value of BDW+ DE pipe IMR to avoid reads in updating + * the bitfield. + */ + u32 de_pipe_imr_mask[I915_MAX_PIPES]; u32 pipestat_irq_mask[I915_MAX_PIPES]; } irq; @@ -568,6 +582,11 @@ struct intel_display { } state; struct { + unsigned int hpll_freq; + unsigned int czclk_freq; + } vlv_clock; + + struct { /* ordered wq for modesets */ struct workqueue_struct *modeset; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index ce3f9810c42d..10dddec3796f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -820,14 +820,14 @@ static const struct drm_info_list intel_display_debugfs_list[] = { void intel_display_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; + struct dentry *debugfs_root = display->drm->debugfs_root; - debugfs_create_file("i915_fifo_underrun_reset", 0644, minor->debugfs_root, + debugfs_create_file("i915_fifo_underrun_reset", 0644, debugfs_root, display, &i915_fifo_underrun_reset_ops); drm_debugfs_create_files(intel_display_debugfs_list, ARRAY_SIZE(intel_display_debugfs_list), - minor->debugfs_root, minor); + debugfs_root, display->drm->primary); intel_bios_debugfs_register(display); intel_cdclk_debugfs_register(display); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c index 88914a1f3f62..de62b774272d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c @@ -7,7 +7,6 @@ #include <linux/kernel.h> #include <drm/drm_drv.h> -#include <drm/drm_file.h> #include "intel_display_core.h" #include "intel_display_debugfs_params.h" @@ -154,14 +153,14 @@ intel_display_debugfs_create_uint(const char *name, umode_t mode, /* add a subdirectory with files for each intel display param */ void intel_display_debugfs_params(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; + struct dentry *debugfs_root = display->drm->debugfs_root; struct dentry *dir; char dirname[16]; snprintf(dirname, sizeof(dirname), "%s_params", display->drm->driver->name); - dir = debugfs_lookup(dirname, minor->debugfs_root); + dir = debugfs_lookup(dirname, debugfs_root); if (!dir) - dir = debugfs_create_dir(dirname, minor->debugfs_root); + dir = debugfs_create_dir(dirname, debugfs_root); if (IS_ERR(dir)) return; diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 089cffabbad5..f3f1f25b0f38 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1354,6 +1354,19 @@ static const struct intel_display_device_info xe2_lpd_display = { .__runtime_defaults.has_dbuf_overlap_detection = true, }; +static const struct intel_display_device_info wcl_display = { + XE_LPDP_FEATURES, + + .__runtime_defaults.cpu_transcoder_mask = + BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | BIT(TRANSCODER_C), + .__runtime_defaults.pipe_mask = + BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), + .__runtime_defaults.fbc_mask = + BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B) | BIT(INTEL_FBC_C), + .__runtime_defaults.port_mask = + BIT(PORT_A) | BIT(PORT_B) | BIT(PORT_TC1) | BIT(PORT_TC2), +}; + static const struct intel_display_device_info xe2_hpd_display = { XE_LPDP_FEATURES, .__runtime_defaults.port_mask = BIT(PORT_A) | @@ -1391,8 +1404,20 @@ static const struct platform_desc bmg_desc = { PLATFORM_GROUP(dgfx), }; +static const u16 wcl_ids[] = { + INTEL_WCL_IDS(ID), + 0 +}; + static const struct platform_desc ptl_desc = { PLATFORM(pantherlake), + .subplatforms = (const struct subplatform_desc[]) { + { + SUBPLATFORM(pantherlake, wildcatlake), + .pciidlist = wcl_ids, + }, + {}, + } }; __diag_pop(); @@ -1469,6 +1494,7 @@ static const struct { INTEL_LNL_IDS(INTEL_DISPLAY_DEVICE, &lnl_desc), INTEL_BMG_IDS(INTEL_DISPLAY_DEVICE, &bmg_desc), INTEL_PTL_IDS(INTEL_DISPLAY_DEVICE, &ptl_desc), + INTEL_WCL_IDS(INTEL_DISPLAY_DEVICE, &ptl_desc), }; static const struct { @@ -1480,7 +1506,7 @@ static const struct { { 14, 1, &xe2_hpd_display }, { 20, 0, &xe2_lpd_display }, { 30, 0, &xe2_lpd_display }, - { 30, 2, &xe2_lpd_display }, + { 30, 2, &wcl_display }, }; static const struct intel_display_device_info * @@ -1931,6 +1957,11 @@ void intel_display_device_info_print(const struct intel_display_device_info *inf drm_printf(p, "rawclk rate: %u kHz\n", runtime->rawclk_freq); } +bool intel_display_device_present(struct intel_display *display) +{ + return display && HAS_DISPLAY(display); +} + /* * Assuming the device has display hardware, should it be enabled? * diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 4308822f0415..0e062753cf9b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -9,7 +9,6 @@ #include <linux/bitops.h> #include <linux/types.h> -#include "intel_display_conversion.h" #include "intel_display_limits.h" struct drm_printer; @@ -102,7 +101,9 @@ struct pci_dev; /* Display ver 14.1 (based on GMD ID) */ \ func(battlemage) \ /* Display ver 30 (based on GMD ID) */ \ - func(pantherlake) + func(pantherlake) \ + func(pantherlake_wildcatlake) + #define __MEMBER(name) unsigned long name:1; #define __COUNT(x) 1 + @@ -156,7 +157,7 @@ struct intel_display_platforms { #define HAS_DISPLAY(__display) (DISPLAY_RUNTIME_INFO(__display)->pipe_mask != 0) #define HAS_DMC(__display) (DISPLAY_RUNTIME_INFO(__display)->has_dmc) #define HAS_DMC_WAKELOCK(__display) (DISPLAY_VER(__display) >= 20) -#define HAS_DOUBLE_BUFFERED_M_N(__display) (DISPLAY_VER(__display) >= 9 || (__display)->platform.broadwell) +#define HAS_DOUBLE_BUFFERED_M_N(__display) (IS_DISPLAY_VER((__display), 9, 14) || (__display)->platform.broadwell) #define HAS_DOUBLE_BUFFERED_LUT(__display) (DISPLAY_VER(__display) >= 30) #define HAS_DOUBLE_WIDE(__display) (DISPLAY_VER(__display) < 4) #define HAS_DP20(__display) ((__display)->platform.dg2 || DISPLAY_VER(__display) >= 14) @@ -224,8 +225,8 @@ struct intel_display_platforms { (IS_DISPLAY_VERx100((__display), (ipver), (ipver)) && \ IS_DISPLAY_STEP((__display), (from), (until))) -#define DISPLAY_INFO(__display) (__to_intel_display(__display)->info.__device_info) -#define DISPLAY_RUNTIME_INFO(__display) (&__to_intel_display(__display)->info.__runtime_info) +#define DISPLAY_INFO(__display) ((__display)->info.__device_info) +#define DISPLAY_RUNTIME_INFO(__display) (&(__display)->info.__runtime_info) #define DISPLAY_VER(__display) (DISPLAY_RUNTIME_INFO(__display)->ip.ver) #define DISPLAY_VERx100(__display) (DISPLAY_RUNTIME_INFO(__display)->ip.ver * 100 + \ @@ -236,7 +237,7 @@ struct intel_display_platforms { #define INTEL_DISPLAY_STEP(__display) (DISPLAY_RUNTIME_INFO(__display)->step) #define IS_DISPLAY_STEP(__display, since, until) \ - (drm_WARN_ON(__to_intel_display(__display)->drm, INTEL_DISPLAY_STEP(__display) == STEP_NONE), \ + (drm_WARN_ON((__display)->drm, INTEL_DISPLAY_STEP(__display) == STEP_NONE), \ INTEL_DISPLAY_STEP(__display) >= (since) && INTEL_DISPLAY_STEP(__display) < (until)) #define ARLS_HOST_BRIDGE_PCI_ID1 0x7D1C @@ -307,6 +308,7 @@ struct intel_display_device_info { } color; }; +bool intel_display_device_present(struct intel_display *display); bool intel_display_device_enabled(struct intel_display *display); struct intel_display *intel_display_device_probe(struct pci_dev *pdev); void intel_display_device_remove(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 8586ba102605..f84a0b26b7a6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -18,6 +18,7 @@ #include <drm/drm_vblank.h> #include "i915_drv.h" +#include "i915_utils.h" #include "i9xx_wm.h" #include "intel_acpi.h" #include "intel_atomic.h" @@ -481,7 +482,6 @@ int intel_display_driver_probe_nogem(struct intel_display *display) intel_dpll_init(display); intel_fdi_pll_freq_update(display); - intel_update_czclk(display); intel_display_driver_init_hw(display); intel_dpll_update_ref_clks(display); diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 68157f177b6a..e1a812f6159b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -140,14 +140,14 @@ void ilk_update_display_irq(struct intel_display *display, lockdep_assert_held(&display->irq.lock); drm_WARN_ON(display->drm, enabled_irq_mask & ~interrupt_mask); - new_val = dev_priv->irq_mask; + new_val = display->irq.ilk_de_imr_mask; new_val &= ~interrupt_mask; new_val |= (~enabled_irq_mask & interrupt_mask); - if (new_val != dev_priv->irq_mask && + if (new_val != display->irq.ilk_de_imr_mask && !drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv))) { - dev_priv->irq_mask = new_val; - intel_de_write(display, DEIMR, dev_priv->irq_mask); + display->irq.ilk_de_imr_mask = new_val; + intel_de_write(display, DEIMR, display->irq.ilk_de_imr_mask); intel_de_posting_read(display, DEIMR); } } @@ -215,13 +215,13 @@ static void bdw_update_pipe_irq(struct intel_display *display, if (drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv))) return; - new_val = display->irq.de_irq_mask[pipe]; + new_val = display->irq.de_pipe_imr_mask[pipe]; new_val &= ~interrupt_mask; new_val |= (~enabled_irq_mask & interrupt_mask); - if (new_val != display->irq.de_irq_mask[pipe]) { - display->irq.de_irq_mask[pipe] = new_val; - intel_de_write(display, GEN8_DE_PIPE_IMR(pipe), display->irq.de_irq_mask[pipe]); + if (new_val != display->irq.de_pipe_imr_mask[pipe]) { + display->irq.de_pipe_imr_mask[pipe] = new_val; + intel_de_write(display, GEN8_DE_PIPE_IMR(pipe), display->irq.de_pipe_imr_mask[pipe]); intel_de_posting_read(display, GEN8_DE_PIPE_IMR(pipe)); } } @@ -872,7 +872,7 @@ static void ilk_gtt_fault_irq_handler(struct intel_display *display) } } -void ilk_display_irq_handler(struct intel_display *display, u32 de_iir) +static void _ilk_display_irq_handler(struct intel_display *display, u32 de_iir) { enum pipe pipe; u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; @@ -923,7 +923,7 @@ void ilk_display_irq_handler(struct intel_display *display, u32 de_iir) ilk_display_rps_irq_handler(display); } -void ivb_display_irq_handler(struct intel_display *display, u32 de_iir) +static void _ivb_display_irq_handler(struct intel_display *display, u32 de_iir) { enum pipe pipe; u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; @@ -972,6 +972,53 @@ void ivb_display_irq_handler(struct intel_display *display, u32 de_iir) } } +void ilk_display_irq_master_disable(struct intel_display *display, u32 *de_ier, u32 *sde_ier) +{ + /* disable master interrupt before clearing iir */ + *de_ier = intel_de_read_fw(display, DEIER); + intel_de_write_fw(display, DEIER, *de_ier & ~DE_MASTER_IRQ_CONTROL); + + /* + * Disable south interrupts. We'll only write to SDEIIR once, so further + * interrupts will be stored on its back queue, and then we'll be able + * to process them after we restore SDEIER (as soon as we restore it, + * we'll get an interrupt if SDEIIR still has something to process due + * to its back queue). + */ + if (!HAS_PCH_NOP(display)) { + *sde_ier = intel_de_read_fw(display, SDEIER); + intel_de_write_fw(display, SDEIER, 0); + } else { + *sde_ier = 0; + } +} + +void ilk_display_irq_master_enable(struct intel_display *display, u32 de_ier, u32 sde_ier) +{ + intel_de_write_fw(display, DEIER, de_ier); + + if (sde_ier) + intel_de_write_fw(display, SDEIER, sde_ier); +} + +bool ilk_display_irq_handler(struct intel_display *display) +{ + u32 de_iir; + bool handled = false; + + de_iir = intel_de_read_fw(display, DEIIR); + if (de_iir) { + intel_de_write_fw(display, DEIIR, de_iir); + if (DISPLAY_VER(display) >= 7) + _ivb_display_irq_handler(display, de_iir); + else + _ilk_display_irq_handler(display, de_iir); + handled = true; + } + + return handled; +} + static u32 gen8_de_port_aux_mask(struct intel_display *display) { u32 mask; @@ -1865,8 +1912,6 @@ void vlv_display_error_irq_handler(struct intel_display *display, static void _vlv_display_irq_reset(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - if (display->platform.cherryview) intel_de_write(display, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); else @@ -1881,7 +1926,7 @@ static void _vlv_display_irq_reset(struct intel_display *display) i9xx_pipestat_irq_reset(display); intel_display_irq_regs_reset(display, VLV_IRQ_REGS); - dev_priv->irq_mask = ~0u; + display->irq.vlv_imr_mask = ~0u; } void vlv_display_irq_reset(struct intel_display *display) @@ -1902,6 +1947,22 @@ void i9xx_display_irq_reset(struct intel_display *display) i9xx_pipestat_irq_reset(display); } +u32 i9xx_display_irq_enable_mask(struct intel_display *display) +{ + u32 enable_mask; + + enable_mask = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + + if (DISPLAY_VER(display) >= 3) + enable_mask |= I915_ASLE_INTERRUPT; + + if (HAS_HOTPLUG(display)) + enable_mask |= I915_DISPLAY_PORT_INTERRUPT; + + return enable_mask; +} + void i915_display_irq_postinstall(struct intel_display *display) { /* @@ -1939,7 +2000,6 @@ static u32 vlv_error_mask(void) static void _vlv_display_irq_postinstall(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); u32 pipestat_mask; u32 enable_mask; enum pipe pipe; @@ -1973,11 +2033,11 @@ static void _vlv_display_irq_postinstall(struct intel_display *display) enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | I915_LPE_PIPE_C_INTERRUPT; - drm_WARN_ON(display->drm, dev_priv->irq_mask != ~0u); + drm_WARN_ON(display->drm, display->irq.vlv_imr_mask != ~0u); - dev_priv->irq_mask = ~enable_mask; + display->irq.vlv_imr_mask = ~enable_mask; - intel_display_irq_regs_init(display, VLV_IRQ_REGS, dev_priv->irq_mask, enable_mask); + intel_display_irq_regs_init(display, VLV_IRQ_REGS, display->irq.vlv_imr_mask, enable_mask); } void vlv_display_irq_postinstall(struct intel_display *display) @@ -1988,22 +2048,37 @@ void vlv_display_irq_postinstall(struct intel_display *display) spin_unlock_irq(&display->irq.lock); } -void ibx_display_irq_reset(struct intel_display *display) +static void ibx_display_irq_reset(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - - if (HAS_PCH_NOP(i915)) + if (HAS_PCH_NOP(display)) return; gen2_irq_reset(to_intel_uncore(display->drm), SDE_IRQ_REGS); - if (HAS_PCH_CPT(i915) || HAS_PCH_LPT(i915)) + if (HAS_PCH_CPT(display) || HAS_PCH_LPT(display)) intel_de_write(display, SERR_INT, 0xffffffff); } +void ilk_display_irq_reset(struct intel_display *display) +{ + struct intel_uncore *uncore = to_intel_uncore(display->drm); + + gen2_irq_reset(uncore, DE_IRQ_REGS); + display->irq.ilk_de_imr_mask = ~0u; + + if (DISPLAY_VER(display) == 7) + intel_de_write(display, GEN7_ERR_INT, 0xffffffff); + + if (display->platform.haswell) { + intel_de_write(display, EDP_PSR_IMR, 0xffffffff); + intel_de_write(display, EDP_PSR_IIR, 0xffffffff); + } + + ibx_display_irq_reset(display); +} + void gen8_display_irq_reset(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); enum pipe pipe; if (!HAS_DISPLAY(display)) @@ -2020,7 +2095,7 @@ void gen8_display_irq_reset(struct intel_display *display) intel_display_irq_regs_reset(display, GEN8_DE_PORT_IRQ_REGS); intel_display_irq_regs_reset(display, GEN8_DE_MISC_IRQ_REGS); - if (HAS_PCH_SPLIT(i915)) + if (HAS_PCH_SPLIT(display)) ibx_display_irq_reset(display); } @@ -2091,8 +2166,8 @@ void gen8_irq_power_well_post_enable(struct intel_display *display, for_each_pipe_masked(display, pipe, pipe_mask) intel_display_irq_regs_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe), - display->irq.de_irq_mask[pipe], - ~display->irq.de_irq_mask[pipe] | extra_ier); + display->irq.de_pipe_imr_mask[pipe], + ~display->irq.de_pipe_imr_mask[pipe] | extra_ier); spin_unlock_irq(&display->irq.lock); } @@ -2186,8 +2261,6 @@ out: void ilk_de_irq_postinstall(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - u32 display_mask, extra_mask; if (DISPLAY_VER(display) >= 7) { @@ -2219,11 +2292,11 @@ void ilk_de_irq_postinstall(struct intel_display *display) if (display->platform.ironlake && display->platform.mobile) extra_mask |= DE_PCU_EVENT; - i915->irq_mask = ~display_mask; + display->irq.ilk_de_imr_mask = ~display_mask; ibx_irq_postinstall(display); - intel_display_irq_regs_init(display, DE_IRQ_REGS, i915->irq_mask, + intel_display_irq_regs_init(display, DE_IRQ_REGS, display->irq.ilk_de_imr_mask, display_mask | extra_mask); } @@ -2308,12 +2381,12 @@ void gen8_de_irq_postinstall(struct intel_display *display) } for_each_pipe(display, pipe) { - display->irq.de_irq_mask[pipe] = ~de_pipe_masked; + display->irq.de_pipe_imr_mask[pipe] = ~de_pipe_masked; if (intel_display_power_is_enabled(display, POWER_DOMAIN_PIPE(pipe))) intel_display_irq_regs_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe), - display->irq.de_irq_mask[pipe], + display->irq.de_pipe_imr_mask[pipe], de_pipe_enables); } diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h index c66db3851da4..84acd31948cf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.h +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -47,8 +47,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 ivb_display_irq_handler(struct intel_display *display, u32 de_iir); -void ilk_display_irq_handler(struct intel_display *display, u32 de_iir); +void ilk_display_irq_master_disable(struct intel_display *display, u32 *de_ier, u32 *sde_ier); +void ilk_display_irq_master_enable(struct intel_display *display, u32 de_ier, u32 sde_ier); +bool ilk_display_irq_handler(struct intel_display *display); void gen8_de_irq_handler(struct intel_display *display, u32 master_ctl); void gen11_display_irq_handler(struct intel_display *display); @@ -56,11 +57,12 @@ u32 gen11_gu_misc_irq_ack(struct intel_display *display, const u32 master_ctl); void gen11_gu_misc_irq_handler(struct intel_display *display, const u32 iir); void i9xx_display_irq_reset(struct intel_display *display); -void ibx_display_irq_reset(struct intel_display *display); +void ilk_display_irq_reset(struct intel_display *display); void vlv_display_irq_reset(struct intel_display *display); void gen8_display_irq_reset(struct intel_display *display); void gen11_display_irq_reset(struct intel_display *display); +u32 i9xx_display_irq_enable_mask(struct intel_display *display); void i915_display_irq_postinstall(struct intel_display *display); void i965_display_irq_postinstall(struct intel_display *display); void vlv_display_irq_postinstall(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 75316247ee8a..2aed110c5b09 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -120,6 +120,9 @@ intel_display_param_named_unsafe(enable_psr, int, 0400, "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " "Default: -1 (use per-chip default)"); +intel_display_param_named_unsafe(enable_panel_replay, int, 0400, + "Enable Panel Replay (0=disabled, 1=enabled). Default: -1 (use per-chip default)"); + intel_display_param_named(psr_safest_params, bool, 0400, "Replace PSR VBT parameters by the safest and not optimal ones. This " "is helpful to detect if PSR issues are related to bad values set in " diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 784e6bae8615..b01bc5700c52 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -46,6 +46,7 @@ struct drm_printer; param(bool, enable_dp_mst, true, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ + param(int, enable_panel_replay, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ param(bool, enable_psr2_sel_fetch, true, 0400) \ param(int, enable_dmc_wl, -1, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 273054c22325..da4babfd6bcb 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -3,6 +3,7 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/iopoll.h> #include <linux/string_helpers.h> #include "soc/intel_dram.h" @@ -10,6 +11,7 @@ #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_backlight_regs.h" #include "intel_cdclk.h" #include "intel_clock_gating.h" @@ -1172,7 +1174,7 @@ static void icl_mbus_init(struct intel_display *display) if (DISPLAY_VER(display) == 12) abox_regs |= BIT(0); - for_each_set_bit(i, &abox_regs, sizeof(abox_regs)) + for_each_set_bit(i, &abox_regs, BITS_PER_TYPE(abox_regs)) intel_de_rmw(display, MBUS_ABOX_CTL(i), mask, val); } @@ -1278,6 +1280,7 @@ static void hsw_disable_lcpll(struct intel_display *display, bool switch_to_fclk, bool allow_power_down) { u32 val; + int ret; assert_can_disable_lcpll(display); @@ -1287,8 +1290,10 @@ static void hsw_disable_lcpll(struct intel_display *display, val |= LCPLL_CD_SOURCE_FCLK; intel_de_write(display, LCPLL_CTL, val); - if (wait_for_us(intel_de_read(display, LCPLL_CTL) & - LCPLL_CD_SOURCE_FCLK_DONE, 1)) + ret = intel_de_wait_custom(display, LCPLL_CTL, + LCPLL_CD_SOURCE_FCLK_DONE, LCPLL_CD_SOURCE_FCLK_DONE, + 1, 0, NULL); + if (ret) drm_err(display->drm, "Switching to FCLK failed\n"); val = intel_de_read(display, LCPLL_CTL); @@ -1306,8 +1311,10 @@ static void hsw_disable_lcpll(struct intel_display *display, hsw_write_dcomp(display, val); ndelay(100); - if (wait_for((hsw_read_dcomp(display) & - D_COMP_RCOMP_IN_PROGRESS) == 0, 1)) + ret = poll_timeout_us(val = hsw_read_dcomp(display), + (val & D_COMP_RCOMP_IN_PROGRESS) == 0, + 100, 1000, false); + if (ret) drm_err(display->drm, "D_COMP RCOMP still in progress\n"); if (allow_power_down) { @@ -1324,6 +1331,7 @@ static void hsw_restore_lcpll(struct intel_display *display) { struct drm_i915_private __maybe_unused *dev_priv = to_i915(display->drm); u32 val; + int ret; val = intel_de_read(display, LCPLL_CTL); @@ -1358,8 +1366,10 @@ static void hsw_restore_lcpll(struct intel_display *display) if (val & LCPLL_CD_SOURCE_FCLK) { intel_de_rmw(display, LCPLL_CTL, LCPLL_CD_SOURCE_FCLK, 0); - if (wait_for_us((intel_de_read(display, LCPLL_CTL) & - LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) + ret = intel_de_wait_custom(display, LCPLL_CTL, + LCPLL_CD_SOURCE_FCLK_DONE, 0, + 1, 0, NULL); + if (ret) drm_err(display->drm, "Switching back to LCPLL failed\n"); } @@ -1629,11 +1639,11 @@ static void tgl_bw_buddy_init(struct intel_display *display) if (table[config].page_mask == 0) { drm_dbg_kms(display->drm, "Unknown memory configuration; disabling address buddy logic.\n"); - for_each_set_bit(i, &abox_mask, sizeof(abox_mask)) + for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) intel_de_write(display, BW_BUDDY_CTL(i), BW_BUDDY_DISABLE); } else { - for_each_set_bit(i, &abox_mask, sizeof(abox_mask)) { + for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) { intel_de_write(display, BW_BUDDY_PAGE_MASK(i), table[config].page_mask); @@ -2155,8 +2165,6 @@ void intel_power_domains_resume(struct intel_display *display) power_domains->init_wakeref = intel_display_power_get(display, POWER_DOMAIN_INIT); } - - intel_power_domains_verify_state(display); } #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index 77268802b55e..39b71fffa2cd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -1717,6 +1717,59 @@ static const struct i915_power_well_desc_list xe3lpd_power_wells[] = { I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), }; +static const struct i915_power_well_desc wcl_power_wells_main[] = { + { + .instances = &I915_PW_INSTANCES( + I915_PW("PW_2", &xe3lpd_pwdoms_pw_2, + .hsw.idx = ICL_PW_CTL_IDX_PW_2, + .id = SKL_DISP_PW_2), + ), + .ops = &hsw_power_well_ops, + .has_vga = true, + .has_fuses = true, + }, { + .instances = &I915_PW_INSTANCES( + I915_PW("PW_A", &xelpd_pwdoms_pw_a, + .hsw.idx = XELPD_PW_CTL_IDX_PW_A), + ), + .ops = &hsw_power_well_ops, + .irq_pipe_mask = BIT(PIPE_A), + .has_fuses = true, + }, { + .instances = &I915_PW_INSTANCES( + I915_PW("PW_B", &xe3lpd_pwdoms_pw_b, + .hsw.idx = XELPD_PW_CTL_IDX_PW_B), + ), + .ops = &hsw_power_well_ops, + .irq_pipe_mask = BIT(PIPE_B), + .has_fuses = true, + }, { + .instances = &I915_PW_INSTANCES( + I915_PW("PW_C", &xe3lpd_pwdoms_pw_c, + .hsw.idx = XELPD_PW_CTL_IDX_PW_C), + ), + .ops = &hsw_power_well_ops, + .irq_pipe_mask = BIT(PIPE_C), + .has_fuses = true, + }, { + .instances = &I915_PW_INSTANCES( + I915_PW("AUX_A", &icl_pwdoms_aux_a, .xelpdp.aux_ch = AUX_CH_A), + I915_PW("AUX_B", &icl_pwdoms_aux_b, .xelpdp.aux_ch = AUX_CH_B), + I915_PW("AUX_TC1", &xelpdp_pwdoms_aux_tc1, .xelpdp.aux_ch = AUX_CH_USBC1), + I915_PW("AUX_TC2", &xelpdp_pwdoms_aux_tc2, .xelpdp.aux_ch = AUX_CH_USBC2), + ), + .ops = &xelpdp_aux_power_well_ops, + }, +}; + +static const struct i915_power_well_desc_list wcl_power_wells[] = { + I915_PW_DESCRIPTORS(i9xx_power_wells_always_on), + I915_PW_DESCRIPTORS(icl_power_wells_pw_1), + I915_PW_DESCRIPTORS(xe3lpd_power_wells_dcoff), + I915_PW_DESCRIPTORS(wcl_power_wells_main), + I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), +}; + static void init_power_well_domains(const struct i915_power_well_instance *inst, struct i915_power_well *power_well) { @@ -1824,7 +1877,9 @@ int intel_display_power_map_init(struct i915_power_domains *power_domains) return 0; } - if (DISPLAY_VER(display) >= 30) + if (DISPLAY_VERx100(display) == 3002) + return set_power_wells(power_domains, wcl_power_wells); + else if (DISPLAY_VER(display) >= 30) return set_power_wells(power_domains, xe3lpd_power_wells); else if (DISPLAY_VER(display) >= 20) return set_power_wells(power_domains, xe2lpd_power_wells); diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 48cac225a809..5e88b930f5aa 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -3,6 +3,8 @@ * Copyright © 2022 Intel Corporation */ +#include <linux/iopoll.h> + #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" @@ -499,7 +501,6 @@ static void icl_tc_port_assert_ref_held(struct intel_display *display, static void icl_tc_cold_exit(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); int ret, tries = 0; while (1) { @@ -514,7 +515,7 @@ static void icl_tc_cold_exit(struct intel_display *display) msleep(1); /* TODO: turn failure into a error as soon i915 CI updates ICL IFWI */ - drm_dbg_kms(&i915->drm, "TC cold block %s\n", ret ? "failed" : + drm_dbg_kms(display->drm, "TC cold block %s\n", ret ? "failed" : "succeeded"); } @@ -527,6 +528,8 @@ icl_tc_phy_aux_power_well_enable(struct intel_display *display, const struct i915_power_well_regs *regs = power_well->desc->ops->regs; bool is_tbt = power_well->desc->is_tc_tbt; bool timeout_expected; + u32 val; + int ret; icl_tc_port_assert_ref_held(display, power_well, dig_port); @@ -553,10 +556,11 @@ icl_tc_phy_aux_power_well_enable(struct intel_display *display, tc_port = TGL_AUX_PW_TO_TC_PORT(i915_power_well_instance(power_well)->hsw.idx); - if (wait_for(intel_dkl_phy_read(display, DKL_CMN_UC_DW_27(tc_port)) & - DKL_CMN_UC_DW27_UC_HEALTH, 1)) - drm_warn(display->drm, - "Timeout waiting TC uC health\n"); + ret = poll_timeout_us(val = intel_dkl_phy_read(display, DKL_CMN_UC_DW_27(tc_port)), + val & DKL_CMN_UC_DW27_UC_HEALTH, + 100, 1000, false); + if (ret) + drm_warn(display->drm, "Timeout waiting TC uC health\n"); } } @@ -1122,6 +1126,8 @@ static void vlv_set_power_well(struct intel_display *display, u32 mask; u32 state; u32 ctrl; + u32 val; + int ret; mask = PUNIT_PWRGT_MASK(pw_idx); state = enable ? PUNIT_PWRGT_PWR_ON(pw_idx) : @@ -1129,10 +1135,8 @@ static void vlv_set_power_well(struct intel_display *display, vlv_punit_get(display->drm); -#define COND \ - ((vlv_punit_read(display->drm, PUNIT_REG_PWRGT_STATUS) & mask) == state) - - if (COND) + val = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_STATUS); + if ((val & mask) == state) goto out; ctrl = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_CTRL); @@ -1140,14 +1144,15 @@ static void vlv_set_power_well(struct intel_display *display, ctrl |= state; vlv_punit_write(display->drm, PUNIT_REG_PWRGT_CTRL, ctrl); - if (wait_for(COND, 100)) + ret = poll_timeout_us(val = vlv_punit_read(display->drm, PUNIT_REG_PWRGT_STATUS), + (val & mask) == state, + 500, 100 * 1000, false); + if (ret) drm_err(display->drm, "timeout setting power well state %08x (%08x)\n", state, vlv_punit_read(display->drm, PUNIT_REG_PWRGT_CTRL)); -#undef COND - out: vlv_punit_put(display->drm); } @@ -1208,7 +1213,7 @@ static void vlv_init_display_clock_gating(struct intel_display *display) * (and never recovering) in this case. intel_dsi_post_disable() will * clear it when we turn off the display. */ - intel_de_rmw(display, DSPCLK_GATE_D(display), + intel_de_rmw(display, VLV_DSPCLK_GATE_D, ~DPOUNIT_CLOCK_GATE_DISABLE, VRHUNIT_CLOCK_GATE_DISABLE); /* @@ -1711,23 +1716,24 @@ static void chv_set_pipe_power_well(struct intel_display *display, enum pipe pipe = PIPE_A; u32 state; u32 ctrl; + int ret; state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe); vlv_punit_get(display->drm); -#define COND \ - ((vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM) & DP_SSS_MASK(pipe)) == state) - - if (COND) + ctrl = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); + if ((ctrl & DP_SSS_MASK(pipe)) == state) goto out; - ctrl = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); ctrl &= ~DP_SSC_MASK(pipe); ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe); vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, ctrl); - if (wait_for(COND, 100)) + ret = poll_timeout_us(ctrl = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM), + (ctrl & DP_SSS_MASK(pipe)) == state, + 500, 100 * 1000, false); + if (ret) drm_err(display->drm, "timeout setting power well state %08x (%08x)\n", state, @@ -1765,7 +1771,6 @@ static void chv_pipe_power_well_disable(struct intel_display *display, static void tgl_tc_cold_request(struct intel_display *display, bool block) { - struct drm_i915_private *i915 = to_i915(display->drm); u8 tries = 0; int ret; @@ -1798,10 +1803,9 @@ tgl_tc_cold_request(struct intel_display *display, bool block) } if (ret) - drm_err(&i915->drm, "TC cold %sblock failed\n", - block ? "" : "un"); + drm_err(display->drm, "TC cold %sblock failed\n", block ? "" : "un"); else - drm_dbg_kms(&i915->drm, "TC cold %sblock succeeded\n", + drm_dbg_kms(display->drm, "TC cold %sblock succeeded\n", block ? "" : "un"); } diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h index 7bd09d981cd2..9d71e26a4fa2 100644 --- a/drivers/gpu/drm/i915/display/intel_display_regs.h +++ b/drivers/gpu/drm/i915/display/intel_display_regs.h @@ -2890,6 +2890,7 @@ enum skl_power_gate { #define DP_PIN_ASSIGNMENT_SHIFT(idx) ((idx) * 4) #define DP_PIN_ASSIGNMENT_MASK(idx) (0xf << ((idx) * 4)) #define DP_PIN_ASSIGNMENT(idx, x) ((x) << ((idx) * 4)) +/* See enum intel_tc_pin_assignment for the pin assignment field values. */ #define _TCSS_DDI_STATUS_1 0x161500 #define _TCSS_DDI_STATUS_2 0x161504 @@ -2897,6 +2898,7 @@ enum skl_power_gate { _TCSS_DDI_STATUS_1, \ _TCSS_DDI_STATUS_2)) #define TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK REG_GENMASK(28, 25) +/* See enum intel_tc_pin_assignment for the pin assignment field values. */ #define TCSS_DDI_STATUS_READY REG_BIT(2) #define TCSS_DDI_STATUS_HPD_LIVE_STATUS_TBT REG_BIT(1) #define TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT REG_BIT(0) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index ce45261c4a8f..029c47743f8b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -50,15 +50,17 @@ #include "intel_display_limits.h" #include "intel_display_power.h" #include "intel_dpll_mgr.h" +#include "intel_dsi_vbt_defs.h" #include "intel_wm_types.h" struct cec_notifier; struct drm_printer; -struct __intel_global_objs_state; struct intel_connector; struct intel_ddi_buf_trans; struct intel_fbc; +struct intel_global_objs_state; struct intel_hdcp_shim; +struct intel_panic; struct intel_tc_port; /* @@ -148,6 +150,7 @@ struct intel_framebuffer { unsigned int vtd_guard; unsigned int (*panic_tiling)(unsigned int x, unsigned int y, unsigned int width); + struct intel_panic *panic; }; enum intel_hotplug_state { @@ -593,7 +596,7 @@ struct intel_atomic_state { struct ref_tracker *wakeref; - struct __intel_global_objs_state *global_objs; + struct intel_global_objs_state *global_objs; int num_global_objs; /* Internal commit, as opposed to userspace/client initiated one */ @@ -642,7 +645,6 @@ struct intel_plane_state { #define PLANE_HAS_FENCE BIT(0) struct intel_fb_view view; - u32 phys_dma_addr; /* for cursor_needs_physical */ /* for legacy cursor fb unpin */ struct drm_vblank_work unpin_work; @@ -665,6 +667,9 @@ struct intel_plane_state { /* chroma upsampler control register */ u32 cus_ctl; + /* surface address register */ + u32 surf; + /* * scaler_id * = -1 : not using a scaler @@ -941,10 +946,6 @@ struct intel_csc_matrix { u16 postoff[3]; }; -void intel_io_mmio_fw_write(void *ctx, i915_reg_t reg, u32 val); - -typedef void (*intel_io_reg_write)(void *ctx, i915_reg_t reg, u32 val); - struct intel_crtc_state { /* * uapi (drm) state. This is the software state shown to userspace. @@ -1122,6 +1123,7 @@ struct intel_crtc_state { bool req_psr2_sdp_prior_scanline; bool has_panel_replay; bool wm_level_disabled; + bool pkg_c_latency_used; u32 dc3co_exitline; u16 su_y_granularity; u8 active_non_psr_pipes; @@ -1339,6 +1341,9 @@ struct intel_crtc_state { /* LOBF flag */ bool has_lobf; + + /* W2 window or 'set context latency' lines */ + u16 set_context_latency; }; enum intel_pipe_crc_source { @@ -1534,6 +1539,7 @@ struct intel_plane { bool (*get_hw_state)(struct intel_plane *plane, enum pipe *pipe); int (*check_plane)(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state); + u32 (*surf_offset)(const 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_dsb *dsb, @@ -1683,6 +1689,7 @@ struct intel_psr { u8 entry_setup_frames; bool link_ok; + bool pkg_c_latency_used; u8 active_non_psr_pipes; }; diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c index f57280e9d041..31cd2c9cd488 100644 --- a/drivers/gpu/drm/i915/display/intel_display_wa.c +++ b/drivers/gpu/drm/i915/display/intel_display_wa.c @@ -3,6 +3,8 @@ * Copyright © 2023 Intel Corporation */ +#include <drm/drm_print.h> + #include "i915_reg.h" #include "intel_de.h" #include "intel_display_core.h" @@ -39,3 +41,36 @@ void intel_display_wa_apply(struct intel_display *display) else if (DISPLAY_VER(display) == 11) gen11_display_wa_apply(display); } + +/* + * Wa_16025573575: + * Fixes: Issue with bitbashing on Xe3 based platforms. + * Workaround: Set masks bits in GPIO CTL and preserve it during bitbashing sequence. + */ +static bool intel_display_needs_wa_16025573575(struct intel_display *display) +{ + return DISPLAY_VERx100(display) == 3000 || DISPLAY_VERx100(display) == 3002; +} + +/* + * Wa_14011503117: + * Fixes: Before enabling the scaler DE fatal error is masked + * Workaround: Unmask the DE fatal error register after enabling the scaler + * and after waiting of at least 1 frame. + */ +bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa, const char *name) +{ + switch (wa) { + case INTEL_DISPLAY_WA_16023588340: + return intel_display_needs_wa_16023588340(display); + case INTEL_DISPLAY_WA_16025573575: + return intel_display_needs_wa_16025573575(display); + case INTEL_DISPLAY_WA_14011503117: + return DISPLAY_VER(display) == 13; + default: + drm_WARN(display->drm, 1, "Missing Wa number: %s\n", name); + break; + } + + return false; +} diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.h b/drivers/gpu/drm/i915/display/intel_display_wa.h index babd9d16603d..abc1df83f066 100644 --- a/drivers/gpu/drm/i915/display/intel_display_wa.h +++ b/drivers/gpu/drm/i915/display/intel_display_wa.h @@ -21,4 +21,15 @@ static inline bool intel_display_needs_wa_16023588340(struct intel_display *disp bool intel_display_needs_wa_16023588340(struct intel_display *display); #endif +enum intel_display_wa { + INTEL_DISPLAY_WA_16023588340, + INTEL_DISPLAY_WA_16025573575, + INTEL_DISPLAY_WA_14011503117, +}; + +bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa, const char *name); + +#define intel_display_wa(__display, __wa) \ + __intel_display_wa((__display), INTEL_DISPLAY_WA_##__wa, __stringify(__wa)) + #endif diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 744f51c0eab8..517bebb0b4aa 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -1141,7 +1141,7 @@ parse_dmc_fw_package(struct intel_dmc *dmc, } num_entries = package_header->num_entries; - if (WARN_ON(package_header->num_entries > max_entries)) + if (WARN_ON(num_entries > max_entries)) num_entries = max_entries; fw_info = (const struct intel_fw_info *) @@ -1603,9 +1603,7 @@ DEFINE_SHOW_ATTRIBUTE(intel_dmc_debugfs_status); void intel_dmc_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; - - debugfs_create_file("i915_dmc_info", 0444, minor->debugfs_root, + debugfs_create_file("i915_dmc_info", 0444, display->drm->debugfs_root, display, &intel_dmc_debugfs_status_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7976fec88606..2eab591a8ef5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -27,6 +27,7 @@ #include <linux/export.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <linux/log2.h> #include <linux/math.h> #include <linux/notifier.h> @@ -174,7 +175,6 @@ int intel_dp_link_symbol_clock(int rate) static int max_dprx_rate(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; int max_rate; if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) @@ -183,16 +183,13 @@ static int max_dprx_rate(struct intel_dp *intel_dp) max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); /* - * Some broken eDP sinks illegally declare support for - * HBR3 without TPS4, and are unable to produce a stable - * output. Reject HBR3 when TPS4 is not available. + * Some platforms + eDP panels may not reliably support HBR3 + * due to signal integrity limitations, despite advertising it. + * Cap the link rate to HBR2 to avoid unstable configurations for the + * known machines. */ - if (max_rate >= 810000 && !drm_dp_tps4_supported(intel_dp->dpcd)) { - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] Rejecting HBR3 due to missing TPS4 support\n", - encoder->base.base.id, encoder->base.name); - max_rate = 540000; - } + if (intel_dp_is_edp(intel_dp) && intel_has_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2)) + max_rate = min(max_rate, 540000); return max_rate; } @@ -1418,6 +1415,7 @@ intel_dp_mode_valid(struct drm_connector *_connector, struct intel_display *display = to_intel_display(_connector->dev); struct intel_connector *connector = to_intel_connector(_connector); struct intel_dp *intel_dp = intel_attached_dp(connector); + enum intel_output_format sink_format, output_format; const struct drm_display_mode *fixed_mode; int target_clock = mode->clock; int max_rate, mode_rate, max_lanes, max_link_clock; @@ -1451,6 +1449,13 @@ intel_dp_mode_valid(struct drm_connector *_connector, mode->hdisplay, target_clock); max_dotclk *= num_joined_pipes; + sink_format = intel_dp_sink_format(connector, mode); + output_format = intel_dp_output_format(connector, sink_format); + + status = intel_pfit_mode_valid(display, mode, output_format, num_joined_pipes); + if (status != MODE_OK) + return status; + if (target_clock > max_dotclk) return MODE_CLOCK_HIGH; @@ -1466,11 +1471,8 @@ intel_dp_mode_valid(struct drm_connector *_connector, intel_dp_mode_min_output_bpp(connector, mode)); if (intel_dp_has_dsc(connector)) { - enum intel_output_format sink_format, output_format; int pipe_bpp; - sink_format = intel_dp_sink_format(connector, mode); - output_format = intel_dp_output_format(connector, sink_format); /* * TBD pass the connector BPC, * for now U8_MAX so that max BPC on that platform would be picked @@ -2535,13 +2537,15 @@ intel_dp_dsc_compute_pipe_bpp_limits(struct intel_dp *intel_dp, bool intel_dp_compute_config_limits(struct intel_dp *intel_dp, - struct intel_connector *connector, + struct drm_connector_state *conn_state, struct intel_crtc_state *crtc_state, bool respect_downstream_limits, bool dsc, struct link_config_limits *limits) { bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); + struct intel_connector *connector = + to_intel_connector(conn_state->connector); limits->min_rate = intel_dp_min_link_rate(intel_dp); limits->max_rate = intel_dp_max_link_rate(intel_dp); @@ -2551,7 +2555,8 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp, limits->min_lane_count = intel_dp_min_lane_count(intel_dp); limits->max_lane_count = intel_dp_max_lane_count(intel_dp); - limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format); + limits->pipe.min_bpp = intel_dp_in_hdr_mode(conn_state) ? 30 : + intel_dp_min_bpp(crtc_state->output_format); if (is_mst) { /* * FIXME: If all the streams can't fit into the link with their @@ -2650,7 +2655,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, joiner_needs_dsc = intel_dp_joiner_needs_dsc(display, num_joined_pipes); dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en || - !intel_dp_compute_config_limits(intel_dp, connector, pipe_config, + !intel_dp_compute_config_limits(intel_dp, conn_state, pipe_config, respect_downstream_limits, false, &limits); @@ -2684,7 +2689,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, str_yes_no(ret), str_yes_no(joiner_needs_dsc), str_yes_no(intel_dp->force_dsc_en)); - if (!intel_dp_compute_config_limits(intel_dp, connector, pipe_config, + if (!intel_dp_compute_config_limits(intel_dp, conn_state, pipe_config, respect_downstream_limits, true, &limits)) @@ -2916,6 +2921,19 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp, } } +bool +intel_dp_in_hdr_mode(const struct drm_connector_state *conn_state) +{ + struct hdr_output_metadata *hdr_metadata; + + if (!conn_state->hdr_output_metadata) + return false; + + hdr_metadata = conn_state->hdr_output_metadata->data; + + return hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084; +} + static void intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state, @@ -3181,7 +3199,26 @@ int intel_dp_compute_min_hblank(struct intel_crtc_state *crtc_state, */ min_hblank = min_hblank - 2; - min_hblank = min(10, min_hblank); + /* + * min_hblank formula is undergoing a change, to avoid underrun use the + * recomended value in spec to compare with the calculated one and use the + * minimum value + */ + if (intel_dp_is_uhbr(crtc_state)) { + /* + * Note: Bspec requires a min_hblank of 2 for YCBCR420 + * with compressed bpp 6, but the minimum compressed bpp + * supported by the driver is 8. + */ + drm_WARN_ON(display->drm, + (crtc_state->dsc.compression_enable && + crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 && + crtc_state->dsc.compressed_bpp_x16 < fxp_q4_from_int(8))); + min_hblank = min(3, min_hblank); + } else { + min_hblank = min(10, min_hblank); + } + crtc_state->min_hblank = min_hblank; return 0; @@ -3842,10 +3879,11 @@ static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) if (ret < 0) return ret; /* Wait for PCON to be FRL Ready */ - wait_for(is_active = drm_dp_pcon_is_frl_ready(&intel_dp->aux) == true, TIMEOUT_FRL_READY_MS); - - if (!is_active) - return -ETIMEDOUT; + ret = poll_timeout_us(is_active = drm_dp_pcon_is_frl_ready(&intel_dp->aux), + is_active, + 1000, TIMEOUT_FRL_READY_MS * 1000, false); + if (ret) + return ret; ret = drm_dp_pcon_frl_configure_1(&intel_dp->aux, max_frl_bw, DP_PCON_ENABLE_SEQUENTIAL_LINK); @@ -3862,12 +3900,11 @@ static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) * Wait for FRL to be completed * Check if the HDMI Link is up and active. */ - wait_for(is_active = - intel_dp_pcon_is_frl_trained(intel_dp, max_frl_bw_mask, &frl_trained_mask), - TIMEOUT_HDMI_LINK_ACTIVE_MS); - - if (!is_active) - return -ETIMEDOUT; + ret = poll_timeout_us(is_active = intel_dp_pcon_is_frl_trained(intel_dp, max_frl_bw_mask, &frl_trained_mask), + is_active, + 1000, TIMEOUT_HDMI_LINK_ACTIVE_MS * 1000, false); + if (ret) + return ret; frl_trained: drm_dbg(display->drm, "FRL_TRAINED_MASK = %u\n", frl_trained_mask); @@ -4277,10 +4314,26 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp) } static void +intel_edp_set_data_override_rates(struct intel_dp *intel_dp) +{ + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + int *sink_rates = intel_dp->sink_rates; + int i, count = 0; + + for (i = 0; i < intel_dp->num_sink_rates; i++) { + if (intel_bios_encoder_reject_edp_rate(encoder->devdata, + intel_dp->sink_rates[i])) + continue; + + sink_rates[count++] = intel_dp->sink_rates[i]; + } + intel_dp->num_sink_rates = count; +} + +static void intel_edp_set_sink_rates(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; intel_dp->num_sink_rates = 0; @@ -4306,16 +4359,13 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) break; /* - * Some broken eDP sinks illegally declare support for - * HBR3 without TPS4, and are unable to produce a stable - * output. Reject HBR3 when TPS4 is not available. + * Some platforms cannot reliably drive HBR3 rates due to PHY limitations, + * even if the sink advertises support. Reject any sink rates above HBR2 on + * the known machines for stable output. */ - if (rate >= 810000 && !drm_dp_tps4_supported(intel_dp->dpcd)) { - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] Rejecting HBR3 due to missing TPS4 support\n", - encoder->base.base.id, encoder->base.name); + if (rate > 540000 && + intel_has_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2)) break; - } intel_dp->sink_rates[i] = rate; } @@ -4330,6 +4380,8 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) intel_dp->use_rate_select = true; else intel_dp_set_sink_rates(intel_dp); + + intel_edp_set_data_override_rates(intel_dp); } static bool @@ -5611,14 +5663,9 @@ bool intel_digital_port_connected_locked(struct intel_encoder *encoder) intel_wakeref_t wakeref; with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) { - unsigned long wait_expires = jiffies + msecs_to_jiffies_timeout(4); - - do { - is_connected = dig_port->connected(encoder); - if (is_connected || is_glitch_free) - break; - usleep_range(10, 30); - } while (time_before(jiffies, wait_expires)); + poll_timeout_us(is_connected = dig_port->connected(encoder), + is_connected || is_glitch_free, + 30, 4000, false); } return is_connected; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 0657f5681196..f90cfd1dbbd0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -193,7 +193,7 @@ void intel_dp_wait_source_oui(struct intel_dp *intel_dp); int intel_dp_output_bpp(enum intel_output_format output_format, int bpp); bool intel_dp_compute_config_limits(struct intel_dp *intel_dp, - struct intel_connector *connector, + struct drm_connector_state *conn_state, struct intel_crtc_state *crtc_state, bool respect_downstream_limits, bool dsc, @@ -214,5 +214,6 @@ int intel_dp_compute_min_hblank(struct intel_crtc_state *crtc_state, int intel_dp_dsc_bpp_step_x16(const struct intel_connector *connector); void intel_dp_dpcd_set_probe(struct intel_dp *intel_dp, bool force_on_external); +bool intel_dp_in_hdr_mode(const struct drm_connector_state *conn_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 41228478b21c..eb05ef4bd9f6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -225,19 +225,6 @@ intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, connector->base.base.id, connector->base.name); } -static bool -intel_dp_in_hdr_mode(const struct drm_connector_state *conn_state) -{ - struct hdr_output_metadata *hdr_metadata; - - if (!conn_state->hdr_output_metadata) - return false; - - hdr_metadata = conn_state->hdr_output_metadata->data; - - return hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084; -} - static void intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32 level) { @@ -521,9 +508,6 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state struct intel_panel *panel = &connector->panel; struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); - if (panel->backlight.edp.vesa.luminance_control_support) - return; - drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info); if (!panel->backlight.edp.vesa.info.aux_enable) @@ -546,7 +530,7 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, luminance_range->max_luminance, panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, ¤t_level, ¤t_mode, - false); + panel->backlight.edp.vesa.luminance_control_support); if (ret < 0) return ret; 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 a479b63112ea..27f3716bdc1f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -22,6 +22,7 @@ */ #include <linux/debugfs.h> +#include <linux/iopoll.h> #include <drm/display/drm_dp_helper.h> #include <drm/drm_print.h> @@ -478,12 +479,13 @@ static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, _TRAIN_REQ_TX_FFE_ARGS(link_status, 2), \ _TRAIN_REQ_TX_FFE_ARGS(link_status, 3) -void +bool 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]) { + bool changed = false; int lane; if (intel_dp_is_uhbr(crtc_state)) { @@ -502,10 +504,17 @@ intel_dp_get_adjust_train(struct intel_dp *intel_dp, TRAIN_REQ_PREEMPH_ARGS(link_status)); } - for (lane = 0; lane < 4; lane++) - intel_dp->train_set[lane] = - intel_dp_get_lane_adjust_train(intel_dp, crtc_state, - dp_phy, link_status, lane); + for (lane = 0; lane < 4; lane++) { + u8 new = intel_dp_get_lane_adjust_train(intel_dp, crtc_state, + dp_phy, link_status, lane); + if (intel_dp->train_set[lane] == new) + continue; + + intel_dp->train_set[lane] = new; + changed = true; + } + + return changed; } static int intel_dp_training_pattern_set_reg(struct intel_dp *intel_dp, @@ -758,6 +767,63 @@ void intel_dp_link_training_set_bw(struct intel_dp *intel_dp, } } +/* + * Pick Training Pattern Sequence (TPS) for channel equalization. 128b/132b TPS2 + * for UHBR+, TPS4 for HBR3 or for 1.4 devices that support it, TPS3 for HBR2 or + * 1.2 devices that support it, TPS2 otherwise. + */ +static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy) +{ + struct intel_display *display = to_intel_display(intel_dp); + bool source_tps3, sink_tps3, source_tps4, sink_tps4; + + /* UHBR+ use separate 128b/132b TPS2 */ + if (intel_dp_is_uhbr(crtc_state)) + return DP_TRAINING_PATTERN_2; + + /* + * TPS4 support is mandatory 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_tps4(display); + 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 (crtc_state->port_clock == 810000) { + if (!source_tps4) + lt_dbg(intel_dp, dp_phy, + "8.1 Gbps link rate without source TPS4 support\n"); + if (!sink_tps4) + lt_dbg(intel_dp, dp_phy, + "8.1 Gbps link rate without sink TPS4 support\n"); + } + + /* + * TPS3 support is mandatory for downstream devices that + * support HBR2. However, not all sinks follow the spec. + */ + source_tps3 = intel_dp_source_supports_tps3(display); + 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 (crtc_state->port_clock >= 540000) { + if (!source_tps3) + lt_dbg(intel_dp, dp_phy, + ">=5.4/6.48 Gbps link rate without source TPS3 support\n"); + if (!sink_tps3) + lt_dbg(intel_dp, dp_phy, + ">=5.4/6.48 Gbps link rate without sink TPS3 support\n"); + } + + return DP_TRAINING_PATTERN_2; +} + static void intel_dp_update_link_bw_set(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, u8 link_bw, u8 rate_select) @@ -950,63 +1016,6 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, } /* - * Pick Training Pattern Sequence (TPS) for channel equalization. 128b/132b TPS2 - * for UHBR+, TPS4 for HBR3 or for 1.4 devices that support it, TPS3 for HBR2 or - * 1.2 devices that support it, TPS2 otherwise. - */ -static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - enum drm_dp_phy dp_phy) -{ - struct intel_display *display = to_intel_display(intel_dp); - bool source_tps3, sink_tps3, source_tps4, sink_tps4; - - /* UHBR+ use separate 128b/132b TPS2 */ - if (intel_dp_is_uhbr(crtc_state)) - return DP_TRAINING_PATTERN_2; - - /* - * TPS4 support is mandatory 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_tps4(display); - 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 (crtc_state->port_clock == 810000) { - if (!source_tps4) - lt_dbg(intel_dp, dp_phy, - "8.1 Gbps link rate without source TPS4 support\n"); - if (!sink_tps4) - lt_dbg(intel_dp, dp_phy, - "8.1 Gbps link rate without sink TPS4 support\n"); - } - - /* - * TPS3 support is mandatory for downstream devices that - * support HBR2. However, not all sinks follow the spec. - */ - source_tps3 = intel_dp_source_supports_tps3(display); - 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 (crtc_state->port_clock >= 540000) { - if (!source_tps3) - lt_dbg(intel_dp, dp_phy, - ">=5.4/6.48 Gbps link rate without source TPS3 support\n"); - if (!sink_tps3) - lt_dbg(intel_dp, dp_phy, - ">=5.4/6.48 Gbps link rate without sink TPS3 support\n"); - } - - return DP_TRAINING_PATTERN_2; -} - -/* * 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. @@ -1127,16 +1136,19 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp, { struct intel_display *display = to_intel_display(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + int ret; intel_dp->link.active = true; - intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX); intel_dp_program_link_training_pattern(intel_dp, crtc_state, DP_PHY_DPRX, DP_TRAINING_PATTERN_DISABLE); - if (intel_dp_is_uhbr(crtc_state) && - wait_for(intel_dp_128b132b_intra_hop(intel_dp, crtc_state) == 0, 500)) { - lt_dbg(intel_dp, DP_PHY_DPRX, "128b/132b intra-hop not clearing\n"); + if (intel_dp_is_uhbr(crtc_state)) { + ret = poll_timeout_us(ret = intel_dp_128b132b_intra_hop(intel_dp, crtc_state), + ret == 0, + 500, 500 * 1000, false); + if (ret) + lt_dbg(intel_dp, DP_PHY_DPRX, "128b/132b intra-hop not clearing\n"); } intel_hpd_unblock(encoder); @@ -1371,8 +1383,8 @@ intel_dp_link_train_all_phys(struct intel_dp *intel_dp, if (ret) 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); + intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX); + intel_dp->set_idle_link_train(intel_dp, crtc_state); return ret; } @@ -1574,8 +1586,12 @@ intel_dp_128b132b_link_train(struct intel_dp *intel_dp, int lttpr_count) { bool passed = false; + int ret; - if (wait_for(intel_dp_128b132b_intra_hop(intel_dp, crtc_state) == 0, 500)) { + ret = poll_timeout_us(ret = intel_dp_128b132b_intra_hop(intel_dp, crtc_state), + ret == 0, + 500, 500 * 1000, false); + if (ret) { lt_err(intel_dp, DP_PHY_DPRX, "128b/132b intra-hop not clear\n"); goto out; } @@ -1602,6 +1618,8 @@ out: intel_dp_program_link_training_pattern(intel_dp, crtc_state, DP_PHY_DPRX, DP_TRAINING_PATTERN_2); + intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX); + return passed; } 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 46614124569f..1ba22ed6db08 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -23,7 +23,7 @@ void intel_dp_link_training_set_bw(struct intel_dp *intel_dp, int link_bw, int rate_select, int lane_count, bool enhanced_framing); -void intel_dp_get_adjust_train(struct intel_dp *intel_dp, +bool 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]); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 74497c9a0554..352f7ef29c28 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -611,12 +611,15 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp, static bool mst_stream_compute_config_limits(struct intel_dp *intel_dp, - struct intel_connector *connector, + struct drm_connector_state *conn_state, struct intel_crtc_state *crtc_state, bool dsc, struct link_config_limits *limits) { - if (!intel_dp_compute_config_limits(intel_dp, connector, + struct intel_connector *connector = + to_intel_connector(conn_state->connector); + + if (!intel_dp_compute_config_limits(intel_dp, conn_state, crtc_state, false, dsc, limits)) return false; @@ -665,7 +668,7 @@ static int mst_stream_compute_config(struct intel_encoder *encoder, joiner_needs_dsc = intel_dp_joiner_needs_dsc(display, num_joined_pipes); dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en || - !mst_stream_compute_config_limits(intel_dp, connector, + !mst_stream_compute_config_limits(intel_dp, conn_state, pipe_config, false, &limits); if (!dsc_needed) { @@ -691,7 +694,7 @@ static int mst_stream_compute_config(struct intel_encoder *encoder, str_yes_no(intel_dp->force_dsc_en)); - if (!mst_stream_compute_config_limits(intel_dp, connector, + if (!mst_stream_compute_config_limits(intel_dp, conn_state, pipe_config, true, &limits)) return -EINVAL; diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.c b/drivers/gpu/drm/i915/display/intel_dp_test.c index 6ed5012c5fac..5cfa1dd411da 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_test.c +++ b/drivers/gpu/drm/i915/display/intel_dp_test.c @@ -6,7 +6,6 @@ #include <drm/display/drm_dp.h> #include <drm/display/drm_dp_helper.h> #include <drm/drm_edid.h> -#include <drm/drm_file.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -753,13 +752,12 @@ static const struct { void intel_dp_test_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; int i; for (i = 0; i < ARRAY_SIZE(intel_display_debugfs_files); i++) { debugfs_create_file(intel_display_debugfs_files[i].name, 0644, - minor->debugfs_root, + display->drm->debugfs_root, display, intel_display_debugfs_files[i].fops); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 33e0398120c8..8ea96cc524a1 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -2046,6 +2046,7 @@ static void bxt_ddi_pll_enable(struct intel_display *display, enum dpio_phy phy = DPIO_PHY0; enum dpio_channel ch = DPIO_CH0; u32 temp; + int ret; bxt_port_to_phy_channel(display, port, &phy, &ch); @@ -2056,8 +2057,10 @@ static void bxt_ddi_pll_enable(struct intel_display *display, intel_de_rmw(display, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_POWER_ENABLE); - if (wait_for_us((intel_de_read(display, BXT_PORT_PLL_ENABLE(port)) & - PORT_PLL_POWER_STATE), 200)) + ret = intel_de_wait_custom(display, BXT_PORT_PLL_ENABLE(port), + PORT_PLL_POWER_STATE, PORT_PLL_POWER_STATE, + 200, 0, NULL); + if (ret) drm_err(display->drm, "Power state not set for PLL:%d\n", port); } @@ -2119,8 +2122,10 @@ static void bxt_ddi_pll_enable(struct intel_display *display, intel_de_rmw(display, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_ENABLE); intel_de_posting_read(display, BXT_PORT_PLL_ENABLE(port)); - if (wait_for_us((intel_de_read(display, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK), - 200)) + ret = intel_de_wait_custom(display, BXT_PORT_PLL_ENABLE(port), + PORT_PLL_LOCK, PORT_PLL_LOCK, + 200, 0, NULL); + if (ret) drm_err(display->drm, "PLL %d not locked\n", port); if (display->platform.geminilake) { @@ -2144,6 +2149,7 @@ static void bxt_ddi_pll_disable(struct intel_display *display, struct intel_dpll *pll) { enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ + int ret; intel_de_rmw(display, BXT_PORT_PLL_ENABLE(port), PORT_PLL_ENABLE, 0); intel_de_posting_read(display, BXT_PORT_PLL_ENABLE(port)); @@ -2152,8 +2158,10 @@ static void bxt_ddi_pll_disable(struct intel_display *display, intel_de_rmw(display, BXT_PORT_PLL_ENABLE(port), PORT_PLL_POWER_ENABLE, 0); - if (wait_for_us(!(intel_de_read(display, BXT_PORT_PLL_ENABLE(port)) & - PORT_PLL_POWER_STATE), 200)) + ret = intel_de_wait_custom(display, BXT_PORT_PLL_ENABLE(port), + PORT_PLL_POWER_STATE, 0, + 200, 0, NULL); + if (ret) drm_err(display->drm, "Power state not reset for PLL:%d\n", port); } diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index aea249e2699f..c0a817018d08 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -33,8 +33,6 @@ i915_vm_to_dpt(struct i915_address_space *vm) return container_of(vm, struct i915_dpt, vm); } -#define dpt_total_entries(dpt) ((dpt)->vm.total >> PAGE_SHIFT) - static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) { writeq(pte, addr); @@ -322,5 +320,5 @@ void intel_dpt_destroy(struct i915_address_space *vm) u64 intel_dpt_offset(struct i915_vma *dpt_vma) { - return dpt_vma->node.start; + return i915_vma_offset(dpt_vma); } diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 53d8ae3a70e9..4ad4efbf9253 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -4,10 +4,11 @@ * */ +#include <linux/iopoll.h> + #include <drm/drm_print.h> #include <drm/drm_vblank.h> -#include "i915_utils.h" #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_regs.h" @@ -114,24 +115,6 @@ static bool pre_commit_is_vrr_active(struct intel_atomic_state *state, return old_crtc_state->vrr.enable && !intel_crtc_vrr_disabling(state, crtc); } -static int dsb_vblank_delay(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - const struct intel_crtc_state *crtc_state = - intel_pre_commit_crtc_state(state, crtc); - - if (pre_commit_is_vrr_active(state, crtc)) - /* - * When the push is sent during vblank it will trigger - * on the next scanline, hence we have up to one extra - * scanline until the delayed vblank occurs after - * TRANS_PUSH has been written. - */ - return intel_vrr_vblank_delay(crtc_state) + 1; - else - return intel_mode_vblank_delay(&crtc_state->hw.adjusted_mode); -} - static int dsb_vtotal(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -722,7 +705,7 @@ void intel_dsb_vblank_evade(struct intel_atomic_state *state, intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_OUT, 0, 0); if (pre_commit_is_vrr_active(state, crtc)) { - int vblank_delay = intel_vrr_vblank_delay(crtc_state); + int vblank_delay = crtc_state->set_context_latency; end = intel_vrr_vmin_vblank_start(crtc_state); start = end - vblank_delay - latency; @@ -814,16 +797,43 @@ void intel_dsb_chain(struct intel_atomic_state *state, wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0); } -void intel_dsb_wait_vblank_delay(struct intel_atomic_state *state, - struct intel_dsb *dsb) +void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, + struct intel_dsb *dsb) { struct intel_crtc *crtc = dsb->crtc; const struct intel_crtc_state *crtc_state = intel_pre_commit_crtc_state(state, crtc); - int usecs = intel_scanlines_to_usecs(&crtc_state->hw.adjusted_mode, - dsb_vblank_delay(state, crtc)); + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + int wait_scanlines; + + if (pre_commit_is_vrr_active(state, crtc)) { + /* + * If the push happened before the vmin decision boundary + * we don't know how far we are from the undelayed vblank. + * Wait until we're past the vmin safe window, at which + * point we're SCL lines away from the delayed vblank. + * + * If the push happened after the vmin decision boundary + * the hardware itself guarantees that we're SCL lines + * away from the delayed vblank, and we won't be inside + * the vmin safe window so this extra wait does nothing. + */ + intel_dsb_wait_scanline_out(state, dsb, + intel_vrr_safe_window_start(crtc_state), + intel_vrr_vmin_safe_window_end(crtc_state)); + /* + * When the push is sent during vblank it will trigger + * on the next scanline, hence we have up to one extra + * scanline until the delayed vblank occurs after + * TRANS_PUSH has been written. + */ + wait_scanlines = crtc_state->set_context_latency + 1; + } else { + wait_scanlines = intel_mode_vblank_delay(adjusted_mode); + } - intel_dsb_wait_usec(dsb, usecs); + intel_dsb_wait_usec(dsb, intel_scanlines_to_usecs(adjusted_mode, wait_scanlines)); } /** @@ -871,8 +881,13 @@ void intel_dsb_wait(struct intel_dsb *dsb) struct intel_crtc *crtc = dsb->crtc; struct intel_display *display = to_intel_display(crtc->base.dev); enum pipe pipe = crtc->pipe; + bool is_busy; + int ret; - if (wait_for(!is_dsb_busy(display, pipe, dsb->id), 1)) { + ret = poll_timeout_us(is_busy = is_dsb_busy(display, pipe, dsb->id), + !is_busy, + 100, 1000, false); + if (ret) { u32 offset = intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf); intel_de_write_fw(display, DSB_CTRL(pipe, dsb->id), diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h b/drivers/gpu/drm/i915/display/intel_dsb.h index c8f4499916eb..2f31f2c1d0c5 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.h +++ b/drivers/gpu/drm/i915/display/intel_dsb.h @@ -48,8 +48,8 @@ void intel_dsb_nonpost_end(struct intel_dsb *dsb); void intel_dsb_interrupt(struct intel_dsb *dsb); void intel_dsb_wait_usec(struct intel_dsb *dsb, int count); void intel_dsb_wait_vblanks(struct intel_dsb *dsb, int count); -void intel_dsb_wait_vblank_delay(struct intel_atomic_state *state, - struct intel_dsb *dsb); +void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, + struct intel_dsb *dsb); void intel_dsb_wait_scanline_in(struct intel_atomic_state *state, struct intel_dsb *dsb, int lower, int upper); diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index e6a851d276f8..23402408e172 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -777,7 +777,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->init_count = mipi_config->master_init_timer; intel_dsi->bw_timer = mipi_config->dbi_bw_timer; intel_dsi->video_frmt_cfg_bits = - mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0; + mipi_config->bta_disable ? DISABLE_VIDEO_BTA : 0; intel_dsi->bgr_enabled = mipi_config->rgb_flip; /* Starting point, adjusted depending on dual link and burst mode */ diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_dsi_vbt_defs.h new file mode 100644 index 000000000000..edc7331dcca2 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt_defs.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __INTEL_DSI_VBT_DEFS_H__ +#define __INTEL_DSI_VBT_DEFS_H__ + +#include <linux/types.h> + +/* + * MIPI Sequence Block definitions + * + * Note the VBT spec has AssertReset / DeassertReset swapped from their + * usual naming, we use the proper names here to avoid confusion when + * reading the code. + */ +enum mipi_seq { + MIPI_SEQ_END = 0, + MIPI_SEQ_DEASSERT_RESET, /* Spec says MipiAssertResetPin */ + MIPI_SEQ_INIT_OTP, + MIPI_SEQ_DISPLAY_ON, + MIPI_SEQ_DISPLAY_OFF, + MIPI_SEQ_ASSERT_RESET, /* Spec says MipiDeassertResetPin */ + MIPI_SEQ_BACKLIGHT_ON, /* sequence block v2+ */ + MIPI_SEQ_BACKLIGHT_OFF, /* sequence block v2+ */ + MIPI_SEQ_TEAR_ON, /* sequence block v2+ */ + MIPI_SEQ_TEAR_OFF, /* sequence block v3+ */ + MIPI_SEQ_POWER_ON, /* sequence block v3+ */ + MIPI_SEQ_POWER_OFF, /* sequence block v3+ */ + MIPI_SEQ_MAX +}; + +enum mipi_seq_element { + MIPI_SEQ_ELEM_END = 0, + MIPI_SEQ_ELEM_SEND_PKT, + MIPI_SEQ_ELEM_DELAY, + MIPI_SEQ_ELEM_GPIO, + MIPI_SEQ_ELEM_I2C, /* sequence block v2+ */ + MIPI_SEQ_ELEM_SPI, /* sequence block v3+ */ + MIPI_SEQ_ELEM_PMIC, /* sequence block v3+ */ + MIPI_SEQ_ELEM_MAX +}; + +#define MIPI_DSI_UNDEFINED_PANEL_ID 0 +#define MIPI_DSI_GENERIC_PANEL_ID 1 + +struct mipi_config { + u16 panel_id; + + /* General Params */ + struct { + u32 enable_dithering:1; + u32 rsvd1:1; + u32 is_bridge:1; + + u32 panel_arch_type:2; + u32 is_cmd_mode:1; + +#define NON_BURST_SYNC_PULSE 0x1 +#define NON_BURST_SYNC_EVENTS 0x2 +#define BURST_MODE 0x3 + u32 video_transfer_mode:2; + + u32 cabc_supported:1; +#define PPS_BLC_PMIC 0 +#define PPS_BLC_SOC 1 + u32 pwm_blc:1; + +#define PIXEL_FORMAT_RGB565 0x1 +#define PIXEL_FORMAT_RGB666 0x2 +#define PIXEL_FORMAT_RGB666_LOOSELY_PACKED 0x3 +#define PIXEL_FORMAT_RGB888 0x4 + u32 videomode_color_format:4; + +#define ENABLE_ROTATION_0 0x0 +#define ENABLE_ROTATION_90 0x1 +#define ENABLE_ROTATION_180 0x2 +#define ENABLE_ROTATION_270 0x3 + u32 rotation:2; + u32 bta_disable:1; + u32 rsvd2:15; + } __packed; + + /* Port Desc */ + struct { +#define DUAL_LINK_NOT_SUPPORTED 0 +#define DUAL_LINK_FRONT_BACK 1 +#define DUAL_LINK_PIXEL_ALT 2 + u16 dual_link:2; + u16 lane_cnt:2; + u16 pixel_overlap:3; + u16 rgb_flip:1; +#define DL_DCS_PORT_A 0x00 +#define DL_DCS_PORT_C 0x01 +#define DL_DCS_PORT_A_AND_C 0x02 + u16 dl_dcs_cabc_ports:2; + u16 dl_dcs_backlight_ports:2; + u16 port_sync:1; /* 219-230 */ + u16 rsvd3:3; + } __packed; + + /* DSI Controller Parameters */ + struct { + u16 dsi_usage:1; + u16 rsvd4:15; + } __packed; + + u8 rsvd5; + u32 target_burst_mode_freq; + u32 dsi_ddr_clk; + u32 bridge_ref_clk; + + /* LP Byte Clock */ + struct { +#define BYTE_CLK_SEL_20MHZ 0 +#define BYTE_CLK_SEL_10MHZ 1 +#define BYTE_CLK_SEL_5MHZ 2 + u8 byte_clk_sel:2; + u8 rsvd6:6; + } __packed; + + /* DPhy Flags */ + struct { + u16 dphy_param_valid:1; + u16 eot_pkt_disabled:1; + u16 enable_clk_stop:1; + u16 blanking_packets_during_bllp:1; /* 219+ */ + u16 lp_clock_during_lpm:1; /* 219+ */ + u16 rsvd7:11; + } __packed; + + u32 hs_tx_timeout; + u32 lp_rx_timeout; + u32 turn_around_timeout; + u32 device_reset_timer; + u32 master_init_timer; + u32 dbi_bw_timer; + u32 lp_byte_clk_val; + + /* DPhy Params */ + struct { + u32 prepare_cnt:6; + u32 rsvd8:2; + u32 clk_zero_cnt:8; + u32 trail_cnt:5; + u32 rsvd9:3; + u32 exit_zero_cnt:6; + u32 rsvd10:2; + } __packed; + + u32 clk_lane_switch_cnt; + u32 hl_switch_cnt; + + u32 rsvd11[6]; + + /* timings based on dphy spec */ + u8 tclk_miss; + u8 tclk_post; + u8 rsvd12; + u8 tclk_pre; + u8 tclk_prepare; + u8 tclk_settle; + u8 tclk_term_enable; + u8 tclk_trail; + u16 tclk_prepare_clkzero; + u8 rsvd13; + u8 td_term_enable; + u8 teot; + u8 ths_exit; + u8 ths_prepare; + u16 ths_prepare_hszero; + u8 rsvd14; + u8 ths_settle; + u8 ths_skip; + u8 ths_trail; + u8 tinit; + u8 tlpx; + u8 rsvd15[3]; + + /* GPIOs */ + u8 panel_enable; + u8 bl_enable; + u8 pwm_enable; + u8 reset_r_n; + u8 pwr_down_r; + u8 stdby_r_n; +} __packed; + +/* all delays have a unit of 100us */ +struct mipi_pps_data { + u16 panel_on_delay; + u16 bl_enable_delay; + u16 bl_disable_delay; + u16 panel_off_delay; + u16 panel_power_cycle_delay; +} __packed; + +#endif /* __INTEL_DSI_VBT_DEFS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_encoder.c b/drivers/gpu/drm/i915/display/intel_encoder.c index 0b7bd26f4339..2ffe1f251ef8 100644 --- a/drivers/gpu/drm/i915/display/intel_encoder.c +++ b/drivers/gpu/drm/i915/display/intel_encoder.c @@ -8,6 +8,7 @@ #include "intel_display_core.h" #include "intel_display_types.h" #include "intel_encoder.h" +#include "intel_hotplug.h" static void intel_encoder_link_check_work_fn(struct work_struct *work) { @@ -37,6 +38,28 @@ void intel_encoder_link_check_queue_work(struct intel_encoder *encoder, int dela &encoder->link_check_work, msecs_to_jiffies(delay_ms)); } +void intel_encoder_unblock_all_hpds(struct intel_display *display) +{ + struct intel_encoder *encoder; + + if (!HAS_DISPLAY(display)) + return; + + for_each_intel_encoder(display->drm, encoder) + intel_hpd_unblock(encoder); +} + +void intel_encoder_block_all_hpds(struct intel_display *display) +{ + struct intel_encoder *encoder; + + if (!HAS_DISPLAY(display)) + return; + + for_each_intel_encoder(display->drm, encoder) + intel_hpd_block(encoder); +} + void intel_encoder_suspend_all(struct intel_display *display) { struct intel_encoder *encoder; @@ -80,3 +103,21 @@ void intel_encoder_shutdown_all(struct intel_display *display) if (encoder->shutdown_complete) encoder->shutdown_complete(encoder); } + +struct intel_digital_port *intel_dig_port_alloc(void) +{ + struct intel_digital_port *dig_port; + + dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL); + if (!dig_port) + return NULL; + + dig_port->hdmi.hdmi_reg = INVALID_MMIO_REG; + dig_port->dp.output_reg = INVALID_MMIO_REG; + dig_port->aux_ch = AUX_CH_NONE; + dig_port->max_lanes = 4; + + mutex_init(&dig_port->hdcp.mutex); + + return dig_port; +} diff --git a/drivers/gpu/drm/i915/display/intel_encoder.h b/drivers/gpu/drm/i915/display/intel_encoder.h index 3fa5589f0b1c..ace0fe1a8f27 100644 --- a/drivers/gpu/drm/i915/display/intel_encoder.h +++ b/drivers/gpu/drm/i915/display/intel_encoder.h @@ -6,6 +6,7 @@ #ifndef __INTEL_ENCODER_H__ #define __INTEL_ENCODER_H__ +struct intel_digital_port; struct intel_display; struct intel_encoder; @@ -17,4 +18,9 @@ void intel_encoder_link_check_flush_work(struct intel_encoder *encoder); void intel_encoder_suspend_all(struct intel_display *display); void intel_encoder_shutdown_all(struct intel_display *display); +void intel_encoder_block_all_hpds(struct intel_display *display); +void intel_encoder_unblock_all_hpds(struct intel_display *display); + +struct intel_digital_port *intel_dig_port_alloc(void); + #endif /* __INTEL_ENCODER_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 0da842bd2f2f..69237dabdae8 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -11,6 +11,7 @@ #include <drm/drm_modeset_helper.h> #include "i915_drv.h" +#include "i915_utils.h" #include "intel_bo.h" #include "intel_display.h" #include "intel_display_core.h" @@ -19,6 +20,7 @@ #include "intel_fb.h" #include "intel_fb_bo.h" #include "intel_frontbuffer.h" +#include "intel_panic.h" #include "intel_plane.h" #define check_array_bounds(display, a, i) drm_WARN_ON((display)->drm, (i) >= ARRAY_SIZE(a)) @@ -562,11 +564,11 @@ static bool plane_has_modifier(struct intel_display *display, return false; if (md->modifier == I915_FORMAT_MOD_4_TILED_BMG_CCS && - (GRAPHICS_VER(i915) < 20 || !display->platform.dgfx)) + (DISPLAY_VER(display) < 14 || !display->platform.dgfx)) return false; if (md->modifier == I915_FORMAT_MOD_4_TILED_LNL_CCS && - (GRAPHICS_VER(i915) < 20 || display->platform.dgfx)) + (DISPLAY_VER(display) < 20 || display->platform.dgfx)) return false; return true; @@ -2342,6 +2344,26 @@ intel_user_framebuffer_create(struct drm_device *dev, return fb; } +struct intel_framebuffer *intel_framebuffer_alloc(void) +{ + struct intel_framebuffer *intel_fb; + struct intel_panic *panic; + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) + return NULL; + + panic = intel_panic_alloc(); + if (!panic) { + kfree(intel_fb); + return NULL; + } + + intel_fb->panic = panic; + + return intel_fb; +} + struct drm_framebuffer * intel_framebuffer_create(struct drm_gem_object *obj, const struct drm_format_info *info, @@ -2350,7 +2372,7 @@ intel_framebuffer_create(struct drm_gem_object *obj, struct intel_framebuffer *intel_fb; int ret; - intel_fb = intel_bo_alloc_framebuffer(); + intel_fb = intel_framebuffer_alloc(); if (!intel_fb) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index 403b8b63721a..22514d5f2bb6 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -104,6 +104,9 @@ int intel_framebuffer_init(struct intel_framebuffer *ifb, struct drm_gem_object *obj, const struct drm_format_info *info, struct drm_mode_fb_cmd2 *mode_cmd); + +struct intel_framebuffer *intel_framebuffer_alloc(void); + struct drm_framebuffer * intel_framebuffer_create(struct drm_gem_object *obj, const struct drm_format_info *info, diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index 5a0151775a3a..45af04cb0fb2 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -11,6 +11,7 @@ #include "gem/i915_gem_object.h" #include "i915_drv.h" +#include "i915_vma.h" #include "intel_display_core.h" #include "intel_display_rpm.h" #include "intel_display_types.h" @@ -151,7 +152,7 @@ intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, * happy to scanout from anywhere within its global aperture. */ pinctl = 0; - if (HAS_GMCH(dev_priv)) + if (HAS_GMCH(display)) pinctl |= PIN_MAPPABLE; i915_gem_ww_ctx_init(&ww, true); @@ -192,7 +193,7 @@ retry: * mode that matches the user configuration. */ ret = i915_vma_pin_fence(vma); - if (ret != 0 && DISPLAY_VER(dev_priv) < 4) { + if (ret != 0 && DISPLAY_VER(display) < 4) { i915_vma_unpin(vma); goto err_unpin; } @@ -260,6 +261,7 @@ intel_plane_fb_vtd_guard(const struct intel_plane_state *plane_state) int intel_plane_pin_fb(struct intel_plane_state *plane_state, const struct intel_plane_state *old_plane_state) { + struct intel_display *display = to_intel_display(plane_state); struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); @@ -277,17 +279,6 @@ int intel_plane_pin_fb(struct intel_plane_state *plane_state, plane_state->ggtt_vma = vma; - /* - * Pre-populate the dma address before we enter the vblank - * evade critical section as i915_gem_object_get_dma_address() - * will trigger might_sleep() even if it won't actually sleep, - * which is the case when the fb has already been pinned. - */ - if (intel_plane_needs_physical(plane)) { - struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base)); - - plane_state->phys_dma_addr = i915_gem_object_get_dma_address(obj, 0); - } } else { unsigned int alignment = intel_plane_fb_min_alignment(plane_state); @@ -309,6 +300,28 @@ int intel_plane_pin_fb(struct intel_plane_state *plane_state, plane_state->dpt_vma = vma; WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma); + + /* + * The DPT object contains only one vma, and there is no VT-d + * guard, so the VMA's offset within the DPT is always 0. + */ + drm_WARN_ON(display->drm, intel_dpt_offset(plane_state->dpt_vma)); + } + + /* + * Pre-populate the dma address before we enter the vblank + * evade critical section as i915_gem_object_get_dma_address() + * will trigger might_sleep() even if it won't actually sleep, + * which is the case when the fb has already been pinned. + */ + if (intel_plane_needs_physical(plane)) { + struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base)); + + plane_state->surf = i915_gem_object_get_dma_address(obj, 0) + + plane->surf_offset(plane_state); + } else { + plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma) + + plane->surf_offset(plane_state); } return 0; diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 685ac98bd001..0d380c825791 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -98,11 +98,7 @@ struct intel_fbc { struct intel_display *display; const struct intel_fbc_funcs *funcs; - /* - * This is always the inner lock when overlapping with - * struct_mutex and it's the outer lock when overlapping - * with stolen_lock. - */ + /* This is always the outer lock when overlapping with stolen_lock */ struct mutex lock; unsigned int busy_bits; @@ -383,11 +379,11 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc) struct drm_i915_private *i915 = to_i915(display->drm); drm_WARN_ON(display->drm, - range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), + range_end_overflows_t(u64, i915_gem_stolen_area_address(i915), i915_gem_stolen_node_offset(&fbc->compressed_fb), U32_MAX)); drm_WARN_ON(display->drm, - range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), + range_end_overflows_t(u64, i915_gem_stolen_area_address(i915), i915_gem_stolen_node_offset(&fbc->compressed_llb), U32_MAX)); intel_de_write(display, FBC_CFB_BASE, @@ -1460,7 +1456,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (intel_display_needs_wa_16023588340(display)) { + if (intel_display_wa(display, 16023588340)) { plane_state->no_fbc_reason = "Wa_16023588340"; return 0; } @@ -1550,14 +1546,14 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, * having a Y offset that isn't divisible by 4 causes FIFO underrun * and screen flicker. */ - if (DISPLAY_VER(display) >= 9 && + if (IS_DISPLAY_VER(display, 9, 12) && plane_state->view.color_plane[0].y & 3) { plane_state->no_fbc_reason = "plane start Y offset misaligned"; return 0; } /* Wa_22010751166: icl, ehl, tgl, dg1, rkl */ - if (DISPLAY_VER(display) >= 11 && + if (IS_DISPLAY_VER(display, 9, 12) && (plane_state->view.color_plane[0].y + (drm_rect_height(&plane_state->uapi.src) >> 16)) & 3) { plane_state->no_fbc_reason = "plane end Y offset misaligned"; @@ -2240,10 +2236,9 @@ void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc) /* FIXME: remove this once igt is on board with per-crtc stuff */ void intel_fbc_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; struct intel_fbc *fbc; fbc = display->fbc[INTEL_FBC_A]; if (fbc) - intel_fbc_debugfs_add(fbc, minor->debugfs_root); + intel_fbc_debugfs_add(fbc, display->drm->debugfs_root); } diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 7c4709d58aa3..3fbdf75415cc 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -207,6 +207,60 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_set_suspend = intelfb_set_suspend, }; +static void intel_fbdev_fill_mode_cmd(struct drm_fb_helper_surface_size *sizes, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + /* we don't do packed 24bpp */ + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; + + mode_cmd->width = sizes->surface_width; + mode_cmd->height = sizes->surface_height; + + mode_cmd->pitches[0] = ALIGN(mode_cmd->width * DIV_ROUND_UP(sizes->surface_bpp, 8), 64); + mode_cmd->pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); +} + +static struct intel_framebuffer * +__intel_fbdev_fb_alloc(struct intel_display *display, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct drm_framebuffer *fb; + struct drm_gem_object *obj; + int size; + + intel_fbdev_fill_mode_cmd(sizes, &mode_cmd); + + size = mode_cmd.pitches[0] * mode_cmd.height; + size = PAGE_ALIGN(size); + + obj = intel_fbdev_fb_bo_create(display->drm, size); + if (IS_ERR(obj)) { + fb = ERR_CAST(obj); + goto err; + } + + fb = intel_framebuffer_create(obj, + drm_get_format_info(display->drm, + mode_cmd.pixel_format, + mode_cmd.modifier[0]), + &mode_cmd); + if (IS_ERR(fb)) { + intel_fbdev_fb_bo_destroy(obj); + goto err; + } + + drm_gem_object_put(obj); + + return to_intel_framebuffer(fb); + +err: + return ERR_CAST(fb); + +} + int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { @@ -237,7 +291,8 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); - fb = intel_fbdev_fb_alloc(helper, sizes); + + fb = __intel_fbdev_fb_alloc(display, sizes); if (IS_ERR(fb)) return PTR_ERR(fb); } else { @@ -277,7 +332,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, obj = intel_fb_bo(&fb->base); - ret = intel_fbdev_fb_fill_info(display, info, obj, vma); + ret = intel_fbdev_fb_fill_info(display->drm, info, obj, vma); if (ret) goto out_unpin; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 210aee9ae88b..56b145841473 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -3,40 +3,17 @@ * Copyright © 2023 Intel Corporation */ -#include <drm/drm_fb_helper.h> +#include <linux/fb.h> #include "gem/i915_gem_lmem.h" #include "i915_drv.h" -#include "intel_display_core.h" -#include "intel_display_types.h" -#include "intel_fb.h" #include "intel_fbdev_fb.h" -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) +struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) { - struct intel_display *display = to_intel_display(helper->dev); - struct drm_i915_private *dev_priv = to_i915(display->drm); - struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd = {}; + struct drm_i915_private *dev_priv = to_i915(drm); struct drm_i915_gem_object *obj; - int size; - - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; - size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); if (HAS_LMEM(dev_priv)) { @@ -51,31 +28,29 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, * * Also skip stolen on MTL as Wa_22018444074 mitigation. */ - if (!display->platform.meteorlake && size * 2 < dev_priv->dsm.usable_size) + if (!IS_METEORLAKE(dev_priv) && size * 2 < dev_priv->dsm.usable_size) obj = i915_gem_object_create_stolen(dev_priv, size); if (IS_ERR(obj)) obj = i915_gem_object_create_shmem(dev_priv, size); } if (IS_ERR(obj)) { - drm_err(display->drm, "failed to allocate framebuffer (%pe)\n", obj); + drm_err(drm, "failed to allocate framebuffer (%pe)\n", obj); return ERR_PTR(-ENOMEM); } - fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), - drm_get_format_info(display->drm, - mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd); - i915_gem_object_put(obj); + return &obj->base; +} - return to_intel_framebuffer(fb); +void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) +{ + drm_gem_object_put(obj); } -int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, +int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, struct drm_gem_object *_obj, struct i915_vma *vma) { - struct drm_i915_private *i915 = to_i915(display->drm); + struct drm_i915_private *i915 = to_i915(drm); struct drm_i915_gem_object *obj = to_intel_bo(_obj); struct i915_gem_ww_ctx ww; void __iomem *vaddr; @@ -107,7 +82,7 @@ int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info vaddr = i915_vma_pin_iomap(vma); if (IS_ERR(vaddr)) { - drm_err(display->drm, + drm_err(drm, "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); ret = PTR_ERR(vaddr); continue; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index cb7957272715..1fa44ed28543 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -6,16 +6,15 @@ #ifndef __INTEL_FBDEV_FB_H__ #define __INTEL_FBDEV_FB_H__ -struct drm_fb_helper; -struct drm_fb_helper_surface_size; +struct drm_device; struct drm_gem_object; +struct drm_mode_fb_cmd2; struct fb_info; struct i915_vma; -struct intel_display; -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes); -int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, +struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); +void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj); +int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); #endif diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 8039a84671cc..59a36b3a22c1 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -292,34 +292,6 @@ int intel_fdi_link_freq(struct intel_display *display, return display->fdi.pll_freq; } -/** - * intel_fdi_compute_pipe_bpp - compute pipe bpp limited by max link bpp - * @crtc_state: the crtc state - * - * Compute the pipe bpp limited by the CRTC's maximum link bpp. Encoders can - * call this function during state computation in the simple case where the - * link bpp will always match the pipe bpp. This is the case for all non-DP - * encoders, while DP encoders will use a link bpp lower than pipe bpp in case - * of DSC compression. - * - * Returns %true in case of success, %false if pipe bpp would need to be - * reduced below its valid range. - */ -bool intel_fdi_compute_pipe_bpp(struct intel_crtc_state *crtc_state) -{ - int pipe_bpp = min(crtc_state->pipe_bpp, - fxp_q4_to_int(crtc_state->max_link_bpp_x16)); - - pipe_bpp = rounddown(pipe_bpp, 2 * 3); - - if (pipe_bpp < 6 * 3) - return false; - - crtc_state->pipe_bpp = pipe_bpp; - - return true; -} - int ilk_fdi_compute_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index ad5e103c38a8..1cd08df9b0c2 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -20,7 +20,6 @@ struct intel_link_bw_limits; int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state); int intel_fdi_link_freq(struct intel_display *display, const struct intel_crtc_state *pipe_config); -bool intel_fdi_compute_pipe_bpp(struct intel_crtc_state *crtc_state); int ilk_fdi_compute_config(struct intel_crtc *intel_crtc, struct intel_crtc_state *pipe_config); int intel_fdi_atomic_check_link(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c index 000a898c9480..30eff6009e87 100644 --- a/drivers/gpu/drm/i915/display/intel_global_state.c +++ b/drivers/gpu/drm/i915/display/intel_global_state.c @@ -13,6 +13,36 @@ #include "intel_display_types.h" #include "intel_global_state.h" +#define for_each_new_global_obj_in_state(__state, obj, new_obj_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_global_objs && \ + ((obj) = (__state)->global_objs[__i].ptr, \ + (new_obj_state) = (__state)->global_objs[__i].new_state, 1); \ + (__i)++) \ + for_each_if(obj) + +#define for_each_old_global_obj_in_state(__state, obj, old_obj_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_global_objs && \ + ((obj) = (__state)->global_objs[__i].ptr, \ + (old_obj_state) = (__state)->global_objs[__i].old_state, 1); \ + (__i)++) \ + for_each_if(obj) + +#define for_each_oldnew_global_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_global_objs && \ + ((obj) = (__state)->global_objs[__i].ptr, \ + (old_obj_state) = (__state)->global_objs[__i].old_state, \ + (new_obj_state) = (__state)->global_objs[__i].new_state, 1); \ + (__i)++) \ + for_each_if(obj) + +struct intel_global_objs_state { + struct intel_global_obj *ptr; + struct intel_global_state *state, *old_state, *new_state; +}; + struct intel_global_commit { struct kref ref; struct completion done; @@ -148,7 +178,7 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state, struct intel_display *display = to_intel_display(state); int index, num_objs, i; size_t size; - struct __intel_global_objs_state *arr; + struct intel_global_objs_state *arr; struct intel_global_state *obj_state; for (i = 0; i < state->num_global_objs; i++) diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h index d42fb2547ee9..e1efa530cc86 100644 --- a/drivers/gpu/drm/i915/display/intel_global_state.h +++ b/drivers/gpu/drm/i915/display/intel_global_state.h @@ -11,6 +11,7 @@ struct intel_atomic_state; struct intel_display; +struct intel_global_commit; struct intel_global_obj; struct intel_global_state; @@ -26,36 +27,6 @@ struct intel_global_obj { const struct intel_global_state_funcs *funcs; }; -#define intel_for_each_global_obj(obj, dev_priv) \ - list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head) - -#define for_each_new_global_obj_in_state(__state, obj, new_obj_state, __i) \ - for ((__i) = 0; \ - (__i) < (__state)->num_global_objs && \ - ((obj) = (__state)->global_objs[__i].ptr, \ - (new_obj_state) = (__state)->global_objs[__i].new_state, 1); \ - (__i)++) \ - for_each_if(obj) - -#define for_each_old_global_obj_in_state(__state, obj, old_obj_state, __i) \ - for ((__i) = 0; \ - (__i) < (__state)->num_global_objs && \ - ((obj) = (__state)->global_objs[__i].ptr, \ - (old_obj_state) = (__state)->global_objs[__i].old_state, 1); \ - (__i)++) \ - for_each_if(obj) - -#define for_each_oldnew_global_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \ - for ((__i) = 0; \ - (__i) < (__state)->num_global_objs && \ - ((obj) = (__state)->global_objs[__i].ptr, \ - (old_obj_state) = (__state)->global_objs[__i].old_state, \ - (new_obj_state) = (__state)->global_objs[__i].new_state, 1); \ - (__i)++) \ - for_each_if(obj) - -struct intel_global_commit; - struct intel_global_state { struct intel_global_obj *obj; struct intel_atomic_state *state; @@ -64,11 +35,6 @@ struct intel_global_state { bool changed, serialized; }; -struct __intel_global_objs_state { - struct intel_global_obj *ptr; - struct intel_global_state *state, *old_state, *new_state; -}; - void intel_atomic_global_obj_init(struct intel_display *display, struct intel_global_obj *obj, struct intel_global_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 0d73f32fe7f1..358210adb8f8 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -30,6 +30,7 @@ #include <linux/export.h> #include <linux/i2c-algo-bit.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <drm/display/drm_hdcp_helper.h> @@ -39,6 +40,7 @@ #include "intel_de.h" #include "intel_display_regs.h" #include "intel_display_types.h" +#include "intel_display_wa.h" #include "intel_gmbus.h" #include "intel_gmbus_regs.h" @@ -217,7 +219,7 @@ static void pnv_gmbus_clock_gating(struct intel_display *display, bool enable) { /* When using bit bashing for I2C, this bit needs to be set to 1 */ - intel_de_rmw(display, DSPCLK_GATE_D(display), + intel_de_rmw(display, DSPCLK_GATE_D, PNV_GMBUSUNIT_CLOCK_GATE_DISABLE, !enable ? PNV_GMBUSUNIT_CLOCK_GATE_DISABLE : 0); } @@ -240,14 +242,20 @@ static void bxt_gmbus_clock_gating(struct intel_display *display, static u32 get_reserved(struct intel_gmbus *bus) { struct intel_display *display = bus->display; - u32 reserved = 0; + u32 preserve_bits = 0; + + if (display->platform.i830 || display->platform.i845g) + return 0; /* On most chips, these bits must be preserved in software. */ - if (!display->platform.i830 && !display->platform.i845g) - reserved = intel_de_read_notrace(display, bus->gpio_reg) & - (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); + preserve_bits |= GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE; + + /* Wa_16025573575: the masks bits need to be preserved through out */ + if (intel_display_wa(display, 16025573575)) + preserve_bits |= GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK | + GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK; - return reserved; + return intel_de_read_notrace(display, bus->gpio_reg) & preserve_bits; } static int get_clock(void *data) @@ -308,6 +316,22 @@ static void set_data(void *data, int state_high) intel_de_posting_read(display, bus->gpio_reg); } +static void +ptl_handle_mask_bits(struct intel_gmbus *bus, bool set) +{ + struct intel_display *display = bus->display; + u32 reg_val = intel_de_read_notrace(display, bus->gpio_reg); + u32 mask_bits = GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK | + GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK; + if (set) + reg_val |= mask_bits; + else + reg_val &= ~mask_bits; + + intel_de_write_notrace(display, bus->gpio_reg, reg_val); + intel_de_posting_read(display, bus->gpio_reg); +} + static int intel_gpio_pre_xfer(struct i2c_adapter *adapter) { @@ -319,6 +343,9 @@ intel_gpio_pre_xfer(struct i2c_adapter *adapter) if (display->platform.pineview) pnv_gmbus_clock_gating(display, false); + if (intel_display_wa(display, 16025573575)) + ptl_handle_mask_bits(bus, true); + set_data(bus, 1); set_clock(bus, 1); udelay(I2C_RISEFALL_TIME); @@ -336,6 +363,9 @@ intel_gpio_post_xfer(struct i2c_adapter *adapter) if (display->platform.pineview) pnv_gmbus_clock_gating(display, true); + + if (intel_display_wa(display, 16025573575)) + ptl_handle_mask_bits(bus, false); } static void @@ -385,11 +415,14 @@ static int gmbus_wait(struct intel_display *display, u32 status, u32 irq_en) intel_de_write_fw(display, GMBUS4(display), irq_en); status |= GMBUS_SATOER; - ret = wait_for_us((gmbus2 = intel_de_read_fw(display, GMBUS2(display))) & status, - 2); + + ret = poll_timeout_us_atomic(gmbus2 = intel_de_read_fw(display, GMBUS2(display)), + gmbus2 & status, + 0, 2, false); if (ret) - ret = wait_for((gmbus2 = intel_de_read_fw(display, GMBUS2(display))) & status, - 50); + ret = poll_timeout_us(gmbus2 = intel_de_read_fw(display, GMBUS2(display)), + gmbus2 & status, + 500, 50 * 1000, false); intel_de_write_fw(display, GMBUS4(display), 0); remove_wait_queue(&display->gmbus.wait_queue, &wait); diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 42202c8bb066..531ee122bf82 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -11,6 +11,7 @@ #include <linux/component.h> #include <linux/debugfs.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <linux/random.h> #include <drm/display/drm_hdcp_helper.h> @@ -326,16 +327,13 @@ static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port, bool ksv_ready; /* Poll for ksv list ready (spec says max time allowed is 5s) */ - ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port, - &ksv_ready), - read_ret || ksv_ready, 5 * 1000 * 1000, 1000, - 100 * 1000); + ret = poll_timeout_us(read_ret = shim->read_ksv_ready(dig_port, &ksv_ready), + read_ret || ksv_ready, + 100 * 1000, 5 * 1000 * 1000, false); if (ret) return ret; if (read_ret) return read_ret; - if (!ksv_ready) - return -ETIMEDOUT; return 0; } @@ -817,6 +815,7 @@ static int intel_hdcp_auth(struct intel_connector *connector) enum port port = dig_port->base.port; unsigned long r0_prime_gen_start; int ret, i, tries = 2; + u32 val; union { u32 reg[2]; u8 shim[DRM_HDCP_AN_LEN]; @@ -905,8 +904,10 @@ static int intel_hdcp_auth(struct intel_connector *connector) HDCP_CONF_AUTH_AND_ENC); /* Wait for R0 ready */ - if (wait_for(intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port)) & - (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) { + ret = poll_timeout_us(val = intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port)), + val & (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), + 100, 1000, false); + if (ret) { drm_err(display->drm, "Timed out waiting for R0 ready\n"); return -ETIMEDOUT; } @@ -938,16 +939,16 @@ static int intel_hdcp_auth(struct intel_connector *connector) ri.reg); /* Wait for Ri prime match */ - if (!wait_for(intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port)) & - (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) + ret = poll_timeout_us(val = intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port)), + val & (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), + 100, 1000, false); + if (!ret) break; } if (i == tries) { drm_dbg_kms(display->drm, - "Timed out waiting for Ri prime match (%x)\n", - intel_de_read(display, - HDCP_STATUS(display, cpu_transcoder, port))); + "Timed out waiting for Ri prime match (%x)\n", val); return -ETIMEDOUT; } @@ -2446,12 +2447,6 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state, if (!hdcp->shim) return -ENOENT; - if (!connector->encoder) { - drm_err(display->drm, "[CONNECTOR:%d:%s] encoder is not initialized\n", - connector->base.base.id, connector->base.name); - return -ENODEV; - } - mutex_lock(&hdcp->mutex); mutex_lock(&dig_port->hdcp.mutex); drm_WARN_ON(display->drm, diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 9961ff259298..4ab7e2e3bfd4 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -29,6 +29,7 @@ #include <linux/delay.h> #include <linux/hdmi.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <linux/slab.h> #include <linux/string_helpers.h> @@ -60,6 +61,7 @@ #include "intel_hdcp_regs.h" #include "intel_hdcp_shim.h" #include "intel_hdmi.h" +#include "intel_link_bw.h" #include "intel_lspcon.h" #include "intel_panel.h" #include "intel_pfit.h" @@ -1582,9 +1584,9 @@ bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port, intel_de_write(display, HDCP_RPRIME(display, cpu_transcoder, port), ri.reg); /* Wait for Ri prime match */ - if (wait_for((intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port)) & - (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) == - (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) { + ret = intel_de_wait_for_set(display, HDCP_STATUS(display, cpu_transcoder, port), + HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC, 1); + if (ret) { drm_dbg_kms(display->drm, "Ri' mismatch detected (%x)\n", intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port))); @@ -1689,11 +1691,10 @@ intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, if (timeout < 0) return timeout; - ret = __wait_for(ret = hdcp2_detect_msg_availability(dig_port, - msg_id, &msg_ready, - &msg_sz), - !ret && msg_ready && msg_sz, timeout * 1000, - 1000, 5 * 1000); + ret = poll_timeout_us(ret = hdcp2_detect_msg_availability(dig_port, msg_id, + &msg_ready, &msg_sz), + !ret && msg_ready && msg_sz, + 4000, timeout * 1000, false); if (ret) drm_dbg_kms(display->drm, "msg_id: %d, ret: %d, timeout: %d\n", @@ -2053,6 +2054,10 @@ intel_hdmi_mode_valid(struct drm_connector *_connector, else sink_format = INTEL_OUTPUT_FORMAT_RGB; + status = intel_pfit_mode_valid(display, mode, sink_format, 0); + if (status != MODE_OK) + return status; + status = intel_hdmi_mode_clock_valid(&connector->base, clock, has_hdmi_sink, sink_format); if (status != MODE_OK) { if (ycbcr_420_only || @@ -2341,6 +2346,9 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) pipe_config->pixel_multiplier = 2; + if (!intel_link_bw_compute_pipe_bpp(pipe_config)) + return -EINVAL; + pipe_config->has_audio = intel_hdmi_has_audio(encoder, pipe_config, conn_state) && intel_audio_compute_config(encoder, pipe_config, conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 265aa97fcc75..4451a792600a 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -28,6 +28,7 @@ #include "i915_drv.h" #include "i915_irq.h" +#include "i915_utils.h" #include "intel_connector.h" #include "intel_display_power.h" #include "intel_display_core.h" @@ -971,8 +972,6 @@ void intel_hpd_cancel_work(struct intel_display *display) spin_lock_irq(&display->irq.lock); - drm_WARN_ON(display->drm, get_blocked_hpd_pin_mask(display)); - display->hotplug.long_hpd_pin_mask = 0; display->hotplug.short_hpd_pin_mask = 0; display->hotplug.event_bits = 0; @@ -1333,12 +1332,12 @@ static const struct file_operations i915_hpd_short_storm_ctl_fops = { void intel_hpd_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; + struct dentry *debugfs_root = display->drm->debugfs_root; - debugfs_create_file("i915_hpd_storm_ctl", 0644, minor->debugfs_root, + debugfs_create_file("i915_hpd_storm_ctl", 0644, debugfs_root, display, &i915_hpd_storm_ctl_fops); - debugfs_create_file("i915_hpd_short_storm_ctl", 0644, minor->debugfs_root, + debugfs_create_file("i915_hpd_short_storm_ctl", 0644, debugfs_root, display, &i915_hpd_short_storm_ctl_fops); - debugfs_create_bool("i915_ignore_long_hpd", 0644, minor->debugfs_root, + debugfs_create_bool("i915_ignore_long_hpd", 0644, debugfs_root, &display->hotplug.ignore_long_hpd); } diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 43aee70597bf..9a4da818ad61 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -420,6 +420,9 @@ u32 i9xx_hpd_irq_ack(struct intel_display *display) u32 hotplug_status = 0, hotplug_status_mask; int i; + if (!HAS_HOTPLUG(display)) + return 0; + if (display->platform.g4x || display->platform.valleyview || display->platform.cherryview) hotplug_status_mask = HOTPLUG_INT_STATUS_G4X | @@ -1025,7 +1028,7 @@ static void mtp_tc_hpd_enable_detection(struct intel_encoder *encoder) { struct intel_display *display = to_intel_display(encoder); - intel_de_rmw(display, SHOTPLUG_CTL_DDI, + intel_de_rmw(display, SHOTPLUG_CTL_TC, mtp_tc_hotplug_mask(encoder->hpd_pin), mtp_tc_hotplug_enables(encoder)); } diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index 3caef7f9c7c4..f52dee0ea412 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -165,6 +165,34 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, } /** + * intel_link_bw_compute_pipe_bpp - compute pipe bpp limited by max link bpp + * @crtc_state: the crtc state + * + * Compute the pipe bpp limited by the CRTC's maximum link bpp. Encoders can + * call this function during state computation in the simple case where the + * link bpp will always match the pipe bpp. This is the case for all non-DP + * encoders, while DP encoders will use a link bpp lower than pipe bpp in case + * of DSC compression. + * + * Returns %true in case of success, %false if pipe bpp would need to be + * reduced below its valid range. + */ +bool intel_link_bw_compute_pipe_bpp(struct intel_crtc_state *crtc_state) +{ + int pipe_bpp = min(crtc_state->pipe_bpp, + fxp_q4_to_int(crtc_state->max_link_bpp_x16)); + + pipe_bpp = rounddown(pipe_bpp, 2 * 3); + + if (pipe_bpp < 6 * 3) + return false; + + crtc_state->pipe_bpp = pipe_bpp; + + return true; +} + +/** * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum * @state: atomic state * @old_limits: link BW limits @@ -449,6 +477,7 @@ void intel_link_bw_connector_debugfs_add(struct intel_connector *connector) switch (connector->base.connector_type) { case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: + case DRM_MODE_CONNECTOR_HDMIA: break; case DRM_MODE_CONNECTOR_VGA: case DRM_MODE_CONNECTOR_SVIDEO: @@ -458,11 +487,6 @@ void intel_link_bw_connector_debugfs_add(struct intel_connector *connector) break; return; - case DRM_MODE_CONNECTOR_HDMIA: - if (HAS_FDI(display) && !HAS_DDI(display)) - break; - - return; default: return; } diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h index b499042e62b1..95ab7c50c61d 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.h +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h @@ -27,6 +27,7 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, struct intel_link_bw_limits *limits, u8 pipe_mask, const char *reason); +bool intel_link_bw_compute_pipe_bpp(struct intel_crtc_state *crtc_state); bool intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state, const struct intel_link_bw_limits *old_limits, struct intel_link_bw_limits *new_limits, diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c index 666148a14522..42284e9928f2 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c @@ -68,9 +68,9 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <drm/drm_print.h> #include <drm/intel/intel_lpe_audio.h> -#include "i915_drv.h" #include "i915_irq.h" #include "intel_audio_regs.h" #include "intel_de.h" @@ -170,14 +170,11 @@ static struct irq_chip lpe_audio_irqchip = { static int lpe_audio_irq_init(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); int irq = display->audio.lpe.irq; - drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv)); - irq_set_chip_and_handler_name(irq, - &lpe_audio_irqchip, - handle_simple_irq, - "hdmi_lpe_audio_irq_handler"); + irq_set_chip_and_handler_name(irq, &lpe_audio_irqchip, + handle_simple_irq, + "hdmi_lpe_audio_irq_handler"); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c index abc4b562083d..d56026c4efdd 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.c +++ b/drivers/gpu/drm/i915/display/intel_lspcon.c @@ -23,6 +23,8 @@ * */ +#include <linux/iopoll.h> + #include <drm/display/drm_dp_dual_mode_helper.h> #include <drm/display/drm_hdmi_helper.h> #include <drm/drm_atomic_helper.h> @@ -181,6 +183,8 @@ static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); struct intel_display *display = to_intel_display(intel_dp); enum drm_lspcon_mode current_mode; + int timeout_us; + int ret; current_mode = lspcon_get_current_mode(lspcon); if (current_mode == mode) @@ -189,9 +193,12 @@ static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, drm_dbg_kms(display->drm, "Waiting for LSPCON mode %s to settle\n", lspcon_mode_name(mode)); - wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, - lspcon_get_mode_settle_timeout(lspcon)); - if (current_mode != mode) + timeout_us = lspcon_get_mode_settle_timeout(lspcon) * 1000; + + ret = poll_timeout_us(current_mode = lspcon_get_current_mode(lspcon), + current_mode == mode, + 5000, timeout_us, false); + if (ret) drm_err(display->drm, "LSPCON mode hasn't settled\n"); out: diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 7e48a235c99f..48f4d8ed4f15 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -48,6 +48,7 @@ #include "intel_dpll.h" #include "intel_fdi.h" #include "intel_gmbus.h" +#include "intel_link_bw.h" #include "intel_lvds.h" #include "intel_lvds_regs.h" #include "intel_panel.h" @@ -433,7 +434,7 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(display)) { crtc_state->has_pch_encoder = true; - if (!intel_fdi_compute_pipe_bpp(crtc_state)) + if (!intel_link_bw_compute_pipe_bpp(crtc_state)) return -EINVAL; } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 81efdb17fc0c..cbc220310813 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -28,13 +28,13 @@ #include <linux/acpi.h> #include <linux/debugfs.h> #include <linux/dmi.h> +#include <linux/iopoll.h> #include <acpi/video.h> #include <drm/drm_edid.h> #include <drm/drm_file.h> #include <drm/drm_print.h> -#include "i915_utils.h" #include "intel_acpi.h" #include "intel_backlight.h" #include "intel_display_core.h" @@ -357,10 +357,12 @@ static int swsci(struct intel_display *display, pci_write_config_word(pdev, SWSCI, swsci_val); /* Poll for the result. */ -#define C (((scic = swsci->scic) & SWSCI_SCIC_INDICATOR) == 0) - if (wait_for(C, dslp)) { + ret = poll_timeout_us(scic = swsci->scic, + (scic & SWSCI_SCIC_INDICATOR) == 0, + 1000, dslp * 1000, false); + if (ret) { drm_dbg(display->drm, "SWSCI request timed out\n"); - return -ETIMEDOUT; + return ret; } scic = (scic & SWSCI_SCIC_EXIT_STATUS_MASK) >> @@ -1299,8 +1301,6 @@ DEFINE_SHOW_ATTRIBUTE(intel_opregion); void intel_opregion_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; - - debugfs_create_file("i915_opregion", 0444, minor->debugfs_root, + debugfs_create_file("i915_opregion", 0444, display->drm->debugfs_root, display, &intel_opregion_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 159a5f998ea0..272f9e7af4d4 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -217,10 +217,9 @@ static void i830_overlay_clock_gating(struct intel_display *display, /* WA_OVERLAY_CLKGATE:alm */ if (enable) - intel_de_write(display, DSPCLK_GATE_D(display), 0); + intel_de_write(display, DSPCLK_GATE_D, 0); else - intel_de_write(display, DSPCLK_GATE_D(display), - OVRUNIT_CLOCK_GATE_DISABLE); + intel_de_write(display, DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); /* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */ pci_bus_read_config_byte(pdev->bus, diff --git a/drivers/gpu/drm/i915/display/intel_panic.c b/drivers/gpu/drm/i915/display/intel_panic.c new file mode 100644 index 000000000000..7311ce4e8b6c --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_panic.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2025 Intel Corporation */ + +#include <drm/drm_panic.h> + +#include "gem/i915_gem_object.h" +#include "intel_display_types.h" +#include "intel_fb.h" +#include "intel_panic.h" + +struct intel_panic *intel_panic_alloc(void) +{ + return i915_gem_object_alloc_panic(); +} + +int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb) +{ + struct intel_framebuffer *fb = sb->private; + struct drm_gem_object *obj = intel_fb_bo(&fb->base); + + return i915_gem_object_panic_setup(panic, sb, obj, fb->panic_tiling); +} + +void intel_panic_finish(struct intel_panic *panic) +{ + return i915_gem_object_panic_finish(panic); +} diff --git a/drivers/gpu/drm/i915/display/intel_panic.h b/drivers/gpu/drm/i915/display/intel_panic.h new file mode 100644 index 000000000000..afb472e924aa --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_panic.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __INTEL_PANIC_H__ +#define __INTEL_PANIC_H__ + +struct drm_scanout_buffer; +struct intel_panic; + +struct intel_panic *intel_panic_alloc(void); +int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb); +void intel_panic_finish(struct intel_panic *panic); + +#endif /* __INTEL_PANIC_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_pch.h b/drivers/gpu/drm/i915/display/intel_pch.h index cf4dab1b98bf..19cac7412d0a 100644 --- a/drivers/gpu/drm/i915/display/intel_pch.h +++ b/drivers/gpu/drm/i915/display/intel_pch.h @@ -6,8 +6,6 @@ #ifndef __INTEL_PCH__ #define __INTEL_PCH__ -#include "intel_display_conversion.h" - struct intel_display; /* @@ -36,7 +34,7 @@ enum intel_pch { PCH_LNL, }; -#define INTEL_PCH_TYPE(_display) (__to_intel_display(_display)->pch_type) +#define INTEL_PCH_TYPE(_display) ((_display)->pch_type) #define HAS_PCH_DG2(display) (INTEL_PCH_TYPE(display) == PCH_DG2) #define HAS_PCH_ADP(display) (INTEL_PCH_TYPE(display) == PCH_ADP) #define HAS_PCH_DG1(display) (INTEL_PCH_TYPE(display) == PCH_DG1) diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.c b/drivers/gpu/drm/i915/display/intel_pch_refclk.c index d3c5255bf1a8..9ae53679a041 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_refclk.c +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.c @@ -17,16 +17,22 @@ static void lpt_fdi_reset_mphy(struct intel_display *display) { + int ret; + intel_de_rmw(display, SOUTH_CHICKEN2, 0, FDI_MPHY_IOSFSB_RESET_CTL); - if (wait_for_us(intel_de_read(display, SOUTH_CHICKEN2) & - FDI_MPHY_IOSFSB_RESET_STATUS, 100)) + ret = intel_de_wait_custom(display, SOUTH_CHICKEN2, + FDI_MPHY_IOSFSB_RESET_STATUS, FDI_MPHY_IOSFSB_RESET_STATUS, + 100, 0, NULL); + if (ret) drm_err(display->drm, "FDI mPHY reset assert timeout\n"); intel_de_rmw(display, SOUTH_CHICKEN2, FDI_MPHY_IOSFSB_RESET_CTL, 0); - if (wait_for_us((intel_de_read(display, SOUTH_CHICKEN2) & - FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100)) + ret = intel_de_wait_custom(display, SOUTH_CHICKEN2, + FDI_MPHY_IOSFSB_RESET_STATUS, 0, + 100, 0, NULL); + if (ret) drm_err(display->drm, "FDI mPHY reset de-assert timeout\n"); } diff --git a/drivers/gpu/drm/i915/display/intel_pfit.c b/drivers/gpu/drm/i915/display/intel_pfit.c index 13541be4d6df..68539e7c2a24 100644 --- a/drivers/gpu/drm/i915/display/intel_pfit.c +++ b/drivers/gpu/drm/i915/display/intel_pfit.c @@ -14,6 +14,7 @@ #include "intel_lvds_regs.h" #include "intel_pfit.h" #include "intel_pfit_regs.h" +#include "skl_scaler.h" static int intel_pch_pfit_check_dst_window(const struct intel_crtc_state *crtc_state) { @@ -546,6 +547,16 @@ out: return intel_gmch_pfit_check_timings(crtc_state); } +enum drm_mode_status +intel_pfit_mode_valid(struct intel_display *display, + const struct drm_display_mode *mode, + enum intel_output_format output_format, + int num_joined_pipes) +{ + return skl_scaler_mode_valid(display, mode, output_format, + num_joined_pipes); +} + int intel_pfit_compute_config(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { diff --git a/drivers/gpu/drm/i915/display/intel_pfit.h b/drivers/gpu/drm/i915/display/intel_pfit.h index ef34f9b49d09..c1bb0d1f344e 100644 --- a/drivers/gpu/drm/i915/display/intel_pfit.h +++ b/drivers/gpu/drm/i915/display/intel_pfit.h @@ -6,8 +6,12 @@ #ifndef __INTEL_PFIT_H__ #define __INTEL_PFIT_H__ +enum drm_mode_status; +struct drm_display_mode; struct drm_connector_state; struct intel_crtc_state; +struct intel_display; +enum intel_output_format; int intel_pfit_compute_config(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); @@ -17,5 +21,9 @@ void ilk_pfit_get_config(struct intel_crtc_state *crtc_state); void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state); void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state); void i9xx_pfit_get_config(struct intel_crtc_state *crtc_state); - +enum drm_mode_status +intel_pfit_mode_valid(struct intel_display *display, + const struct drm_display_mode *mode, + enum intel_output_format output_format, + int num_joined_pipes); #endif /* __INTEL_PFIT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index 36fb07471deb..19d4640c0e53 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -45,10 +45,7 @@ #include <drm/drm_panic.h> #include "gem/i915_gem_object.h" -#include "i915_scheduler_types.h" -#include "i915_vma.h" #include "i9xx_plane_regs.h" -#include "intel_bo.h" #include "intel_cdclk.h" #include "intel_cursor.h" #include "intel_display_rps.h" @@ -57,6 +54,7 @@ #include "intel_fb.h" #include "intel_fb_pin.h" #include "intel_fbdev.h" +#include "intel_panic.h" #include "intel_plane.h" #include "intel_psr.h" #include "skl_scaler.h" @@ -1173,7 +1171,6 @@ static int intel_prepare_plane_fb(struct drm_plane *_plane, struct drm_plane_state *_new_plane_state) { - struct i915_sched_attr attr = { .priority = I915_PRIORITY_DISPLAY }; struct intel_plane *plane = to_intel_plane(_plane); struct intel_display *display = to_intel_display(plane); struct intel_plane_state *new_plane_state = @@ -1222,8 +1219,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, goto unpin_fb; if (new_plane_state->uapi.fence) { - i915_gem_fence_wait_priority(new_plane_state->uapi.fence, - &attr); + i915_gem_fence_wait_priority_display(new_plane_state->uapi.fence); intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc, new_plane_state->uapi.fence); @@ -1327,7 +1323,7 @@ static void intel_panic_flush(struct drm_plane *plane) struct drm_framebuffer *fb = plane_state->hw.fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - intel_bo_panic_finish(intel_fb); + intel_panic_finish(intel_fb->panic); if (crtc_state->enable_psr2_sel_fetch) { /* Force a full update for psr2 */ @@ -1410,7 +1406,7 @@ static int intel_get_scanout_buffer(struct drm_plane *plane, return -EOPNOTSUPP; } sb->private = intel_fb; - ret = intel_bo_panic_setup(sb); + ret = intel_panic_setup(intel_fb->panic, sb); if (ret) return ret; } @@ -1749,8 +1745,3 @@ int intel_plane_atomic_check(struct intel_atomic_state *state) return 0; } - -u32 intel_plane_ggtt_offset(const struct intel_plane_state *plane_state) -{ - return i915_ggtt_offset(plane_state->ggtt_vma); -} diff --git a/drivers/gpu/drm/i915/display/intel_plane.h b/drivers/gpu/drm/i915/display/intel_plane.h index 4ef012c08fa4..8af41ccc0a69 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.h +++ b/drivers/gpu/drm/i915/display/intel_plane.h @@ -87,7 +87,6 @@ int intel_plane_add_affected(struct intel_atomic_state *state, struct intel_crtc *crtc); int intel_plane_atomic_check(struct intel_atomic_state *state); -u32 intel_plane_ggtt_offset(const struct intel_plane_state *plane_state); bool intel_plane_format_mod_supported_async(struct drm_plane *plane, u32 format, u64 modifier); diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 4246173ed311..a9f36b1b50c1 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -360,6 +360,8 @@ valid_fb: i915_vma_pin_fence(vma) == 0 && vma->fence) plane_state->flags |= PLANE_HAS_FENCE; + plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma); + plane_state->uapi.src_x = 0; plane_state->uapi.src_y = 0; plane_state->uapi.src_w = fb->width << 16; diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index b64d0b30f5b1..327e0de86f1e 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -4,6 +4,7 @@ */ #include <linux/debugfs.h> +#include <linux/iopoll.h> #include <drm/drm_print.h> @@ -608,6 +609,8 @@ static void wait_panel_status(struct intel_dp *intel_dp, struct intel_display *display = to_intel_display(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); i915_reg_t pp_stat_reg, pp_ctrl_reg; + int ret; + u32 val; lockdep_assert_held(&display->pps.mutex); @@ -624,13 +627,18 @@ static void wait_panel_status(struct intel_dp *intel_dp, intel_de_read(display, pp_stat_reg), intel_de_read(display, pp_ctrl_reg)); - if (intel_de_wait(display, pp_stat_reg, mask, value, 5000)) + ret = poll_timeout_us(val = intel_de_read(display, pp_stat_reg), + (val & mask) == value, + 10 * 1000, 5000 * 1000, true); + if (ret) { drm_err(display->drm, "[ENCODER:%d:%s] %s panel status timeout: PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", dig_port->base.base.base.id, dig_port->base.base.name, pps_name(intel_dp), intel_de_read(display, pp_stat_reg), intel_de_read(display, pp_ctrl_reg)); + return; + } drm_dbg_kms(display->drm, "Wait complete\n"); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 41988e193a41..49ccd0864c55 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -42,6 +42,7 @@ #include "intel_dmc.h" #include "intel_dp.h" #include "intel_dp_aux.h" +#include "intel_dsb.h" #include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_psr.h" @@ -233,16 +234,12 @@ bool intel_psr_needs_aux_io_power(struct intel_encoder *encoder, static bool psr_global_enabled(struct intel_dp *intel_dp) { - struct intel_display *display = to_intel_display(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DEFAULT: - if (display->params.enable_psr == -1) - return intel_dp_is_edp(intel_dp) ? - connector->panel.vbt.psr.enable : - true; - return display->params.enable_psr; + return intel_dp_is_edp(intel_dp) ? + connector->panel.vbt.psr.enable : true; case I915_PSR_DEBUG_DISABLE: return false; default: @@ -250,39 +247,23 @@ static bool psr_global_enabled(struct intel_dp *intel_dp) } } -static bool psr2_global_enabled(struct intel_dp *intel_dp) +static bool sel_update_global_enabled(struct intel_dp *intel_dp) { - struct intel_display *display = to_intel_display(intel_dp); - switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DISABLE: case I915_PSR_DEBUG_FORCE_PSR1: return false; default: - if (display->params.enable_psr == 1) - return false; return true; } } -static bool psr2_su_region_et_global_enabled(struct intel_dp *intel_dp) -{ - struct intel_display *display = to_intel_display(intel_dp); - - if (display->params.enable_psr != -1) - return false; - - return true; -} - static bool panel_replay_global_enabled(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - if ((display->params.enable_psr != -1) || - (intel_dp->psr.debug & I915_PSR_DEBUG_PANEL_REPLAY_DISABLE)) - return false; - return true; + return !(intel_dp->psr.debug & I915_PSR_DEBUG_PANEL_REPLAY_DISABLE) && + display->params.enable_panel_replay; } static u32 psr_irq_psr_error_bit_get(struct intel_dp *intel_dp) @@ -514,12 +495,14 @@ static u8 intel_dp_get_su_capability(struct intel_dp *intel_dp) { u8 su_capability = 0; - if (intel_dp->psr.sink_panel_replay_su_support) - drm_dp_dpcd_readb(&intel_dp->aux, - DP_PANEL_REPLAY_CAP_CAPABILITY, - &su_capability); - else + if (intel_dp->psr.sink_panel_replay_su_support) { + if (drm_dp_dpcd_read_byte(&intel_dp->aux, + DP_PANEL_REPLAY_CAP_CAPABILITY, + &su_capability) < 0) + return 0; + } else { su_capability = intel_dp->psr_dpcd[1]; + } return su_capability; } @@ -600,6 +583,16 @@ exit: static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); + int ret; + + ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PANEL_REPLAY_CAP_SUPPORT, + &intel_dp->pr_dpcd, sizeof(intel_dp->pr_dpcd)); + if (ret < 0) + return; + + if (!(intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] & + DP_PANEL_REPLAY_SUPPORT)) + return; if (intel_dp_is_edp(intel_dp)) { if (!intel_alpm_aux_less_wake_supported(intel_dp)) { @@ -631,6 +624,15 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) static void _psr_init_dpcd(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); + int ret; + + ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, + sizeof(intel_dp->psr_dpcd)); + if (ret < 0) + return; + + if (!intel_dp->psr_dpcd[0]) + return; drm_dbg_kms(display->drm, "eDP panel supports PSR version %x\n", intel_dp->psr_dpcd[0]); @@ -676,18 +678,9 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp) void intel_psr_init_dpcd(struct intel_dp *intel_dp) { - drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, - sizeof(intel_dp->psr_dpcd)); + _psr_init_dpcd(intel_dp); - drm_dp_dpcd_read(&intel_dp->aux, DP_PANEL_REPLAY_CAP_SUPPORT, - &intel_dp->pr_dpcd, sizeof(intel_dp->pr_dpcd)); - - if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] & - DP_PANEL_REPLAY_SUPPORT) - _panel_replay_init_dpcd(intel_dp); - - if (intel_dp->psr_dpcd[0]) - _psr_init_dpcd(intel_dp); + _panel_replay_init_dpcd(intel_dp); if (intel_dp->psr.sink_psr2_support || intel_dp->psr.sink_panel_replay_su_support) @@ -742,8 +735,7 @@ static bool psr2_su_region_et_valid(struct intel_dp *intel_dp, bool panel_replay return panel_replay ? intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] & DP_PANEL_REPLAY_EARLY_TRANSPORT_SUPPORT : - intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED && - psr2_su_region_et_global_enabled(intel_dp); + intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED; } static void _panel_replay_enable_sink(struct intel_dp *intel_dp, @@ -936,7 +928,7 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) /* Wa_16025596647 */ if ((DISPLAY_VER(display) == 20 || IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && - is_dc5_dc6_blocked(intel_dp)) + is_dc5_dc6_blocked(intel_dp) && intel_dp->psr.pkg_c_latency_used) intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(display, intel_dp->psr.pipe, true); @@ -1026,7 +1018,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) /* Wa_16025596647 */ if ((DISPLAY_VER(display) == 20 || IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && - is_dc5_dc6_blocked(intel_dp)) + is_dc5_dc6_blocked(intel_dp) && intel_dp->psr.pkg_c_latency_used) idle_frames = 0; else idle_frames = psr_compute_idle_frames(intel_dp); @@ -1423,7 +1415,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay; int psr_max_h = 0, psr_max_v = 0, max_bpp = 0; - if (!intel_dp->psr.sink_psr2_support) + if (!intel_dp->psr.sink_psr2_support || display->params.enable_psr == 1) return false; /* JSL and EHL only supports eDP 1.3 */ @@ -1528,7 +1520,7 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp, goto unsupported; } - if (!psr2_global_enabled(intel_dp)) { + if (!sel_update_global_enabled(intel_dp)) { drm_dbg_kms(display->drm, "Selective update disabled by flag\n"); goto unsupported; @@ -1576,7 +1568,7 @@ static bool _psr_compute_config(struct intel_dp *intel_dp, const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int entry_setup_frames; - if (!CAN_PSR(intel_dp)) + if (!CAN_PSR(intel_dp) || !display->params.enable_psr) return false; /* @@ -1808,6 +1800,8 @@ static void intel_psr_activate(struct intel_dp *intel_dp) drm_WARN_ON(display->drm, intel_dp->psr.active); + drm_WARN_ON(display->drm, !intel_dp->psr.enabled); + lockdep_assert_held(&intel_dp->psr.lock); /* psr1, psr2 and panel-replay are mutually exclusive.*/ @@ -2027,6 +2021,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, intel_dp->psr.req_psr2_sdp_prior_scanline = crtc_state->req_psr2_sdp_prior_scanline; intel_dp->psr.active_non_psr_pipes = crtc_state->active_non_psr_pipes; + intel_dp->psr.pkg_c_latency_used = crtc_state->pkg_c_latency_used; if (!psr_interrupt_error_check(intel_dp)) return; @@ -2103,8 +2098,9 @@ static void intel_psr_exit(struct intel_dp *intel_dp) drm_WARN_ON(display->drm, !(val & EDP_PSR2_ENABLE)); } else { - if (DISPLAY_VER(display) == 20 || - IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) + if ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + intel_dp->psr.pkg_c_latency_used) intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(display, intel_dp->psr.pipe, false); @@ -2207,6 +2203,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) intel_dp->psr.su_region_et_enabled = false; intel_dp->psr.psr2_sel_fetch_cff_enabled = false; intel_dp->psr.active_non_psr_pipes = 0; + intel_dp->psr.pkg_c_latency_used = 0; } /** @@ -2363,12 +2360,12 @@ void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb, } /** - * intel_psr_min_vblank_delay - Minimum vblank delay needed by PSR + * intel_psr_min_set_context_latency - Minimum 'set context latency' lines needed by PSR * @crtc_state: the crtc state * - * Return minimum vblank delay needed by PSR. + * Return minimum SCL lines/delay needed by PSR. */ -int intel_psr_min_vblank_delay(const struct intel_crtc_state *crtc_state) +int intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -3003,35 +3000,57 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, } } -static int _psr2_ready_for_pipe_update_locked(struct intel_dp *intel_dp) +/* + * From bspec: Panel Self Refresh (BDW+) + * Max. time for PSR to idle = Inverse of the refresh rate + 6 ms of + * exit training time + 1.5 ms of aux channel handshake. 50 ms is + * defensive enough to cover everything. + */ +#define PSR_IDLE_TIMEOUT_MS 50 + +static int +_psr2_ready_for_pipe_update_locked(const struct intel_crtc_state *new_crtc_state, + struct intel_dsb *dsb) { - struct intel_display *display = to_intel_display(intel_dp); - enum transcoder cpu_transcoder = intel_dp->psr.transcoder; + struct intel_display *display = to_intel_display(new_crtc_state); + enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder; /* * Any state lower than EDP_PSR2_STATUS_STATE_DEEP_SLEEP is enough. * As all higher states has bit 4 of PSR2 state set we can just wait for * EDP_PSR2_STATUS_STATE_DEEP_SLEEP to be cleared. */ + if (dsb) { + intel_dsb_poll(dsb, EDP_PSR2_STATUS(display, cpu_transcoder), + EDP_PSR2_STATUS_STATE_DEEP_SLEEP, 0, 200, + PSR_IDLE_TIMEOUT_MS * 1000 / 200); + return true; + } + return intel_de_wait_for_clear(display, EDP_PSR2_STATUS(display, cpu_transcoder), - EDP_PSR2_STATUS_STATE_DEEP_SLEEP, 50); + EDP_PSR2_STATUS_STATE_DEEP_SLEEP, + PSR_IDLE_TIMEOUT_MS); } -static int _psr1_ready_for_pipe_update_locked(struct intel_dp *intel_dp) +static int +_psr1_ready_for_pipe_update_locked(const struct intel_crtc_state *new_crtc_state, + struct intel_dsb *dsb) { - struct intel_display *display = to_intel_display(intel_dp); - enum transcoder cpu_transcoder = intel_dp->psr.transcoder; + struct intel_display *display = to_intel_display(new_crtc_state); + enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder; + + if (dsb) { + intel_dsb_poll(dsb, psr_status_reg(display, cpu_transcoder), + EDP_PSR_STATUS_STATE_MASK, 0, 200, + PSR_IDLE_TIMEOUT_MS * 1000 / 200); + return true; + } - /* - * From bspec: Panel Self Refresh (BDW+) - * Max. time for PSR to idle = Inverse of the refresh rate + 6 ms of - * exit training time + 1.5 ms of aux channel handshake. 50 ms is - * defensive enough to cover everything. - */ return intel_de_wait_for_clear(display, psr_status_reg(display, cpu_transcoder), - EDP_PSR_STATUS_STATE_MASK, 50); + EDP_PSR_STATUS_STATE_MASK, + PSR_IDLE_TIMEOUT_MS); } /** @@ -3060,9 +3079,11 @@ void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_stat continue; if (intel_dp->psr.sel_update_enabled) - ret = _psr2_ready_for_pipe_update_locked(intel_dp); + ret = _psr2_ready_for_pipe_update_locked(new_crtc_state, + NULL); else - ret = _psr1_ready_for_pipe_update_locked(intel_dp); + ret = _psr1_ready_for_pipe_update_locked(new_crtc_state, + NULL); if (ret) drm_err(display->drm, @@ -3070,6 +3091,18 @@ void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_stat } } +void intel_psr_wait_for_idle_dsb(struct intel_dsb *dsb, + const struct intel_crtc_state *new_crtc_state) +{ + if (!new_crtc_state->has_psr || new_crtc_state->has_panel_replay) + return; + + if (new_crtc_state->has_sel_update) + _psr2_ready_for_pipe_update_locked(new_crtc_state, dsb); + else + _psr1_ready_for_pipe_update_locked(new_crtc_state, dsb); +} + static bool __psr_wait_for_idle_locked(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); @@ -3099,7 +3132,7 @@ static bool __psr_wait_for_idle_locked(struct intel_dp *intel_dp) /* After the unlocked wait, verify that PSR is still wanted! */ mutex_lock(&intel_dp->psr.lock); - return err == 0 && intel_dp->psr.enabled; + return err == 0 && intel_dp->psr.enabled && !intel_dp->psr.pause_counter; } static int intel_psr_fastset_force(struct intel_display *display) @@ -3228,8 +3261,13 @@ static void intel_psr_work(struct work_struct *work) if (!intel_dp->psr.enabled) goto unlock; - if (READ_ONCE(intel_dp->psr.irq_aux_error)) + if (READ_ONCE(intel_dp->psr.irq_aux_error)) { intel_psr_handle_irq(intel_dp); + goto unlock; + } + + if (intel_dp->psr.pause_counter) + goto unlock; /* * We have to make sure PSR is ready for re-enable @@ -3723,7 +3761,7 @@ static void intel_psr_apply_underrun_on_idle_wa_locked(struct intel_dp *intel_dp struct intel_display *display = to_intel_display(intel_dp); bool dc5_dc6_blocked; - if (!intel_dp->psr.active) + if (!intel_dp->psr.active || !intel_dp->psr.pkg_c_latency_used) return; dc5_dc6_blocked = is_dc5_dc6_blocked(intel_dp); @@ -3748,7 +3786,8 @@ static void psr_dc5_dc6_wa_work(struct work_struct *work) mutex_lock(&intel_dp->psr.lock); - if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled) + if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled && + !intel_dp->psr.pkg_c_latency_used) intel_psr_apply_underrun_on_idle_wa_locked(intel_dp); mutex_unlock(&intel_dp->psr.lock); @@ -3826,7 +3865,8 @@ void intel_psr_notify_pipe_change(struct intel_atomic_state *state, goto unlock; if ((enable && intel_dp->psr.active_non_psr_pipes) || - (!enable && !intel_dp->psr.active_non_psr_pipes)) { + (!enable && !intel_dp->psr.active_non_psr_pipes) || + !intel_dp->psr.pkg_c_latency_used) { intel_dp->psr.active_non_psr_pipes = active_non_psr_pipes; goto unlock; } @@ -3861,7 +3901,7 @@ void intel_psr_notify_vblank_enable_disable(struct intel_display *display, break; } - if (intel_dp->psr.enabled) + if (intel_dp->psr.enabled && intel_dp->psr.pkg_c_latency_used) intel_psr_apply_underrun_on_idle_wa_locked(intel_dp); mutex_unlock(&intel_dp->psr.lock); @@ -4157,12 +4197,12 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops, void intel_psr_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; + struct dentry *debugfs_root = display->drm->debugfs_root; - debugfs_create_file("i915_edp_psr_debug", 0644, minor->debugfs_root, + debugfs_create_file("i915_edp_psr_debug", 0644, debugfs_root, display, &i915_edp_psr_debug_fops); - debugfs_create_file("i915_edp_psr_status", 0444, minor->debugfs_root, + debugfs_create_file("i915_edp_psr_status", 0444, debugfs_root, display, &i915_edp_psr_status_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 9b061a22361f..9147996d6c9e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -52,6 +52,8 @@ void intel_psr_get_config(struct intel_encoder *encoder, void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state); +void intel_psr_wait_for_idle_dsb(struct intel_dsb *dsb, + const struct intel_crtc_state *new_crtc_state); bool intel_psr_enabled(struct intel_dp *intel_dp); int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -75,7 +77,7 @@ void intel_psr_unlock(const struct intel_crtc_state *crtc_state); void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb, struct intel_atomic_state *state, struct intel_crtc *crtc); -int intel_psr_min_vblank_delay(const struct intel_crtc_state *crtc_state); +int intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state); void intel_psr_connector_debugfs_add(struct intel_connector *connector); void intel_psr_debugfs_register(struct intel_display *display); bool intel_psr_needs_alpm(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c index a32fae510ed2..d2e16b79d6be 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.c +++ b/drivers/gpu/drm/i915/display/intel_quirks.c @@ -80,6 +80,12 @@ static void quirk_fw_sync_len(struct intel_dp *intel_dp) drm_info(display->drm, "Applying Fast Wake sync pulse count quirk\n"); } +static void quirk_edp_limit_rate_hbr2(struct intel_display *display) +{ + intel_set_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2); + drm_info(display->drm, "Applying eDP Limit rate to HBR2 quirk\n"); +} + struct intel_quirk { int device; int subsystem_vendor; @@ -231,6 +237,9 @@ static struct intel_quirk intel_quirks[] = { { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time }, /* HP Notebook - 14-r206nv */ { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness }, + + /* Dell XPS 13 7390 2-in-1 */ + { 0x8a12, 0x1028, 0x08b0, quirk_edp_limit_rate_hbr2 }, }; static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h index cafdebda7535..06da0e286c67 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.h +++ b/drivers/gpu/drm/i915/display/intel_quirks.h @@ -20,6 +20,7 @@ enum intel_quirk_id { QUIRK_LVDS_SSC_DISABLE, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK, QUIRK_FW_SYNC_LEN, + QUIRK_EDP_LIMIT_RATE_HBR2, }; void intel_init_quirks(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 87aff2754f69..6c032d81e7ee 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -47,11 +47,11 @@ #include "intel_display_driver.h" #include "intel_display_regs.h" #include "intel_display_types.h" -#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hdmi.h" #include "intel_hotplug.h" +#include "intel_link_bw.h" #include "intel_panel.h" #include "intel_sdvo.h" #include "intel_sdvo_regs.h" @@ -1367,7 +1367,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(display)) { pipe_config->has_pch_encoder = true; - if (!intel_fdi_compute_pipe_bpp(pipe_config)) + if (!intel_link_bw_compute_pipe_bpp(pipe_config)) return -EINVAL; } @@ -2052,8 +2052,10 @@ static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder) { struct intel_sdvo *intel_sdvo = to_sdvo(encoder); - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, - &intel_sdvo->hotplug_active, 2); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, + &intel_sdvo->hotplug_active, 2)) + drm_warn(intel_sdvo->base.base.dev, + "Failed to enable hotplug on SDVO encoder\n"); } static enum intel_hotplug_state diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index e6844df837af..75bbaa923204 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -264,8 +264,7 @@ static u32 vlv_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state) return sprctl; } -static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 vlv_sprite_ctl(const struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int rotation = plane_state->hw.rotation; @@ -395,15 +394,12 @@ vlv_sprite_update_arm(struct intel_dsb *dsb, enum pipe pipe = plane->pipe; enum plane_id plane_id = plane->id; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 sprsurf_offset = plane_state->view.color_plane[0].offset; u32 x = plane_state->view.color_plane[0].x; u32 y = plane_state->view.color_plane[0].y; - u32 sprctl, linear_offset; + u32 sprctl; sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state); - linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - if (display->platform.cherryview && pipe == PIPE_B) chv_sprite_update_csc(plane_state); @@ -418,7 +414,8 @@ vlv_sprite_update_arm(struct intel_dsb *dsb, intel_de_write_fw(display, SPCONSTALPHA(pipe, plane_id), 0); - intel_de_write_fw(display, SPLINOFF(pipe, plane_id), linear_offset); + intel_de_write_fw(display, SPLINOFF(pipe, plane_id), + intel_fb_xy_to_linear(x, y, plane_state, 0)); intel_de_write_fw(display, SPTILEOFF(pipe, plane_id), SP_OFFSET_Y(y) | SP_OFFSET_X(x)); @@ -428,8 +425,7 @@ vlv_sprite_update_arm(struct intel_dsb *dsb, * the control register just before the surface register. */ intel_de_write_fw(display, SPCNTR(pipe, plane_id), sprctl); - intel_de_write_fw(display, SPSURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + sprsurf_offset); + intel_de_write_fw(display, SPSURF(pipe, plane_id), plane_state->surf); vlv_sprite_update_clrc(plane_state); vlv_sprite_update_gamma(plane_state); @@ -663,8 +659,7 @@ static bool ivb_need_sprite_gamma(const struct intel_plane_state *plane_state) (display->platform.ivybridge || display->platform.haswell); } -static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 ivb_sprite_ctl(const struct intel_plane_state *plane_state) { struct intel_display *display = to_intel_display(plane_state); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -830,15 +825,12 @@ ivb_sprite_update_arm(struct intel_dsb *dsb, struct intel_display *display = to_intel_display(plane); enum pipe pipe = plane->pipe; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 sprsurf_offset = plane_state->view.color_plane[0].offset; u32 x = plane_state->view.color_plane[0].x; u32 y = plane_state->view.color_plane[0].y; - u32 sprctl, linear_offset; + u32 sprctl; sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state); - linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - if (key->flags) { intel_de_write_fw(display, SPRKEYVAL(pipe), key->min_value); intel_de_write_fw(display, SPRKEYMSK(pipe), @@ -852,7 +844,8 @@ ivb_sprite_update_arm(struct intel_dsb *dsb, intel_de_write_fw(display, SPROFFSET(pipe), SPRITE_OFFSET_Y(y) | SPRITE_OFFSET_X(x)); } else { - intel_de_write_fw(display, SPRLINOFF(pipe), linear_offset); + intel_de_write_fw(display, SPRLINOFF(pipe), + intel_fb_xy_to_linear(x, y, plane_state, 0)); intel_de_write_fw(display, SPRTILEOFF(pipe), SPRITE_OFFSET_Y(y) | SPRITE_OFFSET_X(x)); } @@ -863,8 +856,7 @@ ivb_sprite_update_arm(struct intel_dsb *dsb, * the control register just before the surface register. */ intel_de_write_fw(display, SPRCTL(pipe), sprctl); - intel_de_write_fw(display, SPRSURF(pipe), - intel_plane_ggtt_offset(plane_state) + sprsurf_offset); + intel_de_write_fw(display, SPRSURF(pipe), plane_state->surf); ivb_sprite_update_gamma(plane_state); } @@ -1016,8 +1008,7 @@ static u32 g4x_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state) return dvscntr; } -static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 g4x_sprite_ctl(const struct intel_plane_state *plane_state) { struct intel_display *display = to_intel_display(plane_state); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -1181,15 +1172,12 @@ g4x_sprite_update_arm(struct intel_dsb *dsb, struct intel_display *display = to_intel_display(plane); enum pipe pipe = plane->pipe; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 dvssurf_offset = plane_state->view.color_plane[0].offset; u32 x = plane_state->view.color_plane[0].x; u32 y = plane_state->view.color_plane[0].y; - u32 dvscntr, linear_offset; + u32 dvscntr; dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state); - linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - if (key->flags) { intel_de_write_fw(display, DVSKEYVAL(pipe), key->min_value); intel_de_write_fw(display, DVSKEYMSK(pipe), @@ -1197,7 +1185,8 @@ g4x_sprite_update_arm(struct intel_dsb *dsb, intel_de_write_fw(display, DVSKEYMAX(pipe), key->max_value); } - intel_de_write_fw(display, DVSLINOFF(pipe), linear_offset); + intel_de_write_fw(display, DVSLINOFF(pipe), + intel_fb_xy_to_linear(x, y, plane_state, 0)); intel_de_write_fw(display, DVSTILEOFF(pipe), DVS_OFFSET_Y(y) | DVS_OFFSET_X(x)); @@ -1207,8 +1196,7 @@ g4x_sprite_update_arm(struct intel_dsb *dsb, * the control register just before the surface register. */ intel_de_write_fw(display, DVSCNTR(pipe), dvscntr); - intel_de_write_fw(display, DVSSURF(pipe), - intel_plane_ggtt_offset(plane_state) + dvssurf_offset); + intel_de_write_fw(display, DVSSURF(pipe), plane_state->surf); if (display->platform.g4x) g4x_sprite_update_gamma(plane_state); @@ -1387,9 +1375,9 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state, return ret; if (DISPLAY_VER(display) >= 7) - plane_state->ctl = ivb_sprite_ctl(crtc_state, plane_state); + plane_state->ctl = ivb_sprite_ctl(plane_state); else - plane_state->ctl = g4x_sprite_ctl(crtc_state, plane_state); + plane_state->ctl = g4x_sprite_ctl(plane_state); return 0; } @@ -1439,7 +1427,7 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - plane_state->ctl = vlv_sprite_ctl(crtc_state, plane_state); + plane_state->ctl = vlv_sprite_ctl(plane_state); return 0; } @@ -1624,6 +1612,7 @@ intel_sprite_plane_create(struct intel_display *display, plane->capture_error = vlv_sprite_capture_error; plane->get_hw_state = vlv_sprite_get_hw_state; plane->check_plane = vlv_sprite_check; + plane->surf_offset = i965_plane_surf_offset; plane->max_stride = i965_plane_max_stride; plane->min_alignment = vlv_plane_min_alignment; plane->min_cdclk = vlv_plane_min_cdclk; @@ -1648,6 +1637,7 @@ intel_sprite_plane_create(struct intel_display *display, plane->capture_error = ivb_sprite_capture_error; plane->get_hw_state = ivb_sprite_get_hw_state; plane->check_plane = g4x_sprite_check; + plane->surf_offset = i965_plane_surf_offset; if (display->platform.broadwell || display->platform.haswell) { plane->max_stride = hsw_sprite_max_stride; @@ -1673,6 +1663,7 @@ intel_sprite_plane_create(struct intel_display *display, plane->capture_error = g4x_sprite_capture_error; plane->get_hw_state = g4x_sprite_get_hw_state; plane->check_plane = g4x_sprite_check; + plane->surf_offset = i965_plane_surf_offset; plane->max_stride = g4x_sprite_max_stride; plane->min_alignment = g4x_sprite_min_alignment; plane->min_cdclk = g4x_sprite_min_cdclk; diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 668ef139391b..c4a5601c5107 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/iopoll.h> + #include <drm/drm_print.h> #include "i915_reg.h" @@ -23,11 +25,6 @@ #include "intel_modeset_lock.h" #include "intel_tc.h" -#define DP_PIN_ASSIGNMENT_NONE 0x0 -#define DP_PIN_ASSIGNMENT_C 0x3 -#define DP_PIN_ASSIGNMENT_D 0x4 -#define DP_PIN_ASSIGNMENT_E 0x5 - enum tc_port_mode { TC_PORT_DISCONNECTED, TC_PORT_TBT_ALT, @@ -66,6 +63,7 @@ struct intel_tc_port { enum tc_port_mode mode; enum tc_port_mode init_mode; enum phy_fia phy_fia; + enum intel_tc_pin_assignment pin_assignment; u8 phy_fia_idx; u8 max_lane_count; }; @@ -253,6 +251,9 @@ tc_port_power_domain(struct intel_tc_port *tc) { enum tc_port tc_port = intel_encoder_to_tc(&tc->dig_port->base); + if (tc_port == TC_PORT_NONE) + return POWER_DOMAIN_INVALID; + return POWER_DOMAIN_PORT_DDI_LANES_TC1 + tc_port - TC_PORT_1; } @@ -265,13 +266,14 @@ assert_tc_port_power_enabled(struct intel_tc_port *tc) !intel_display_power_is_enabled(display, tc_port_power_domain(tc))); } -static u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) +static u32 get_lane_mask(struct intel_tc_port *tc) { - struct intel_display *display = to_intel_display(dig_port); - struct intel_tc_port *tc = to_tc_port(dig_port); + struct intel_display *display = to_intel_display(tc->dig_port); + intel_wakeref_t wakeref; u32 lane_mask; - lane_mask = intel_de_read(display, PORT_TX_DFLEXDPSP(tc->phy_fia)); + with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) + lane_mask = intel_de_read(display, PORT_TX_DFLEXDPSP(tc->phy_fia)); drm_WARN_ON(display->drm, lane_mask == 0xffffffff); assert_tc_cold_blocked(tc); @@ -280,77 +282,87 @@ static u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) return lane_mask >> DP_LANE_ASSIGNMENT_SHIFT(tc->phy_fia_idx); } -u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) +static char pin_assignment_name(enum intel_tc_pin_assignment pin_assignment) { - struct intel_display *display = to_intel_display(dig_port); - struct intel_tc_port *tc = to_tc_port(dig_port); - u32 pin_mask; + if (pin_assignment == INTEL_TC_PIN_ASSIGNMENT_NONE) + return '-'; - pin_mask = intel_de_read(display, PORT_TX_DFLEXPA1(tc->phy_fia)); - - drm_WARN_ON(display->drm, pin_mask == 0xffffffff); - assert_tc_cold_blocked(tc); - - return (pin_mask & DP_PIN_ASSIGNMENT_MASK(tc->phy_fia_idx)) >> - DP_PIN_ASSIGNMENT_SHIFT(tc->phy_fia_idx); + return 'A' + pin_assignment - INTEL_TC_PIN_ASSIGNMENT_A; } -static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) +static enum intel_tc_pin_assignment +get_pin_assignment(struct intel_tc_port *tc) { - struct intel_display *display = to_intel_display(dig_port); - enum tc_port tc_port = intel_encoder_to_tc(&dig_port->base); + struct intel_display *display = to_intel_display(tc->dig_port); + enum tc_port tc_port = intel_encoder_to_tc(&tc->dig_port->base); + enum intel_tc_pin_assignment pin_assignment; intel_wakeref_t wakeref; - u32 val, pin_assignment; + i915_reg_t reg; + u32 mask; + u32 val; + + if (tc->mode == TC_PORT_TBT_ALT) + return INTEL_TC_PIN_ASSIGNMENT_NONE; + + if (DISPLAY_VER(display) >= 20) { + reg = TCSS_DDI_STATUS(tc_port); + mask = TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK; + } else { + reg = PORT_TX_DFLEXPA1(tc->phy_fia); + mask = DP_PIN_ASSIGNMENT_MASK(tc->phy_fia_idx); + } with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) - val = intel_de_read(display, TCSS_DDI_STATUS(tc_port)); + val = intel_de_read(display, reg); + + drm_WARN_ON(display->drm, val == 0xffffffff); + assert_tc_cold_blocked(tc); - pin_assignment = - REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val); + pin_assignment = (val & mask) >> (ffs(mask) - 1); switch (pin_assignment) { - case DP_PIN_ASSIGNMENT_NONE: - return 0; + case INTEL_TC_PIN_ASSIGNMENT_A: + case INTEL_TC_PIN_ASSIGNMENT_B: + case INTEL_TC_PIN_ASSIGNMENT_F: + drm_WARN_ON(display->drm, DISPLAY_VER(display) > 11); + break; + case INTEL_TC_PIN_ASSIGNMENT_NONE: + case INTEL_TC_PIN_ASSIGNMENT_C: + case INTEL_TC_PIN_ASSIGNMENT_D: + case INTEL_TC_PIN_ASSIGNMENT_E: + break; default: MISSING_CASE(pin_assignment); - fallthrough; - case DP_PIN_ASSIGNMENT_D: - return 2; - case DP_PIN_ASSIGNMENT_C: - case DP_PIN_ASSIGNMENT_E: - return 4; } + + return pin_assignment; } -static int mtl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) +static int mtl_get_max_lane_count(struct intel_tc_port *tc) { - struct intel_display *display = to_intel_display(dig_port); - intel_wakeref_t wakeref; - u32 pin_mask; + enum intel_tc_pin_assignment pin_assignment; - with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) - pin_mask = intel_tc_port_get_pin_assignment_mask(dig_port); + pin_assignment = get_pin_assignment(tc); - switch (pin_mask) { + switch (pin_assignment) { + case INTEL_TC_PIN_ASSIGNMENT_NONE: + return 0; default: - MISSING_CASE(pin_mask); + MISSING_CASE(pin_assignment); fallthrough; - case DP_PIN_ASSIGNMENT_D: + case INTEL_TC_PIN_ASSIGNMENT_D: return 2; - case DP_PIN_ASSIGNMENT_C: - case DP_PIN_ASSIGNMENT_E: + case INTEL_TC_PIN_ASSIGNMENT_C: + case INTEL_TC_PIN_ASSIGNMENT_E: return 4; } } -static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) +static int icl_get_max_lane_count(struct intel_tc_port *tc) { - struct intel_display *display = to_intel_display(dig_port); - intel_wakeref_t wakeref; u32 lane_mask = 0; - with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) - lane_mask = intel_tc_port_get_lane_mask(dig_port); + lane_mask = get_lane_mask(tc); switch (lane_mask) { default: @@ -372,41 +384,43 @@ static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) static int get_max_lane_count(struct intel_tc_port *tc) { struct intel_display *display = to_intel_display(tc->dig_port); - struct intel_digital_port *dig_port = tc->dig_port; if (tc->mode != TC_PORT_DP_ALT) return 4; - assert_tc_cold_blocked(tc); - - if (DISPLAY_VER(display) >= 20) - return lnl_tc_port_get_max_lane_count(dig_port); - if (DISPLAY_VER(display) >= 14) - return mtl_tc_port_get_max_lane_count(dig_port); + return mtl_get_max_lane_count(tc); - return intel_tc_port_get_max_lane_count(dig_port); + return icl_get_max_lane_count(tc); } static void read_pin_configuration(struct intel_tc_port *tc) { + tc->pin_assignment = get_pin_assignment(tc); tc->max_lane_count = get_max_lane_count(tc); } int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) { - struct intel_display *display = to_intel_display(dig_port); struct intel_tc_port *tc = to_tc_port(dig_port); if (!intel_encoder_is_tc(&dig_port->base)) return 4; - if (DISPLAY_VER(display) < 20) - return get_max_lane_count(tc); - return tc->max_lane_count; } +enum intel_tc_pin_assignment +intel_tc_port_get_pin_assignment(struct intel_digital_port *dig_port) +{ + struct intel_tc_port *tc = to_tc_port(dig_port); + + if (!intel_encoder_is_tc(&dig_port->base)) + return INTEL_TC_PIN_ASSIGNMENT_NONE; + + return tc->pin_assignment; +} + void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes) { @@ -1038,8 +1052,13 @@ static bool xelpdp_tc_phy_wait_for_tcss_power(struct intel_tc_port *tc, bool enabled) { struct intel_display *display = to_intel_display(tc->dig_port); + bool is_enabled; + int ret; - if (wait_for(xelpdp_tc_phy_tcss_power_is_enabled(tc) == enabled, 5)) { + ret = poll_timeout_us(is_enabled = xelpdp_tc_phy_tcss_power_is_enabled(tc), + is_enabled == enabled, + 200, 5000, false); + if (ret) { drm_dbg_kms(display->drm, "Port %s: timeout waiting for TCSS power to get %s\n", str_enabled_disabled(enabled), @@ -1320,8 +1339,13 @@ static bool tc_phy_is_connected(struct intel_tc_port *tc, static bool tc_phy_wait_for_ready(struct intel_tc_port *tc) { struct intel_display *display = to_intel_display(tc->dig_port); + bool is_ready; + int ret; - if (wait_for(tc_phy_is_ready(tc), 500)) { + ret = poll_timeout_us(is_ready = tc_phy_is_ready(tc), + is_ready, + 1000, 500 * 1000, false); + if (ret) { drm_err(display->drm, "Port %s: timeout waiting for PHY ready\n", tc->port_name); @@ -1509,10 +1533,13 @@ static void intel_tc_port_reset_mode(struct intel_tc_port *tc, if (!force_disconnect) tc_phy_connect(tc, required_lanes); - drm_dbg_kms(display->drm, "Port %s: TC port mode reset (%s -> %s)\n", + drm_dbg_kms(display->drm, + "Port %s: TC port mode reset (%s -> %s) pin assignment: %c max lanes: %d\n", tc->port_name, tc_port_mode_name(old_tc_mode), - tc_port_mode_name(tc->mode)); + tc_port_mode_name(tc->mode), + pin_assignment_name(tc->pin_assignment), + tc->max_lane_count); } static bool intel_tc_port_needs_reset(struct intel_tc_port *tc) @@ -1667,9 +1694,11 @@ void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port, __intel_tc_port_put_link(tc); } - drm_dbg_kms(display->drm, "Port %s: sanitize mode (%s)\n", + drm_dbg_kms(display->drm, "Port %s: sanitize mode (%s) pin assignment: %c max lanes: %d\n", tc->port_name, - tc_port_mode_name(tc->mode)); + tc_port_mode_name(tc->mode), + pin_assignment_name(tc->pin_assignment), + tc->max_lane_count); mutex_unlock(&tc->lock); } diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 26c4265368c1..fff8b96e4972 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -12,6 +12,75 @@ struct intel_crtc_state; struct intel_digital_port; struct intel_encoder; +/* + * The following enum values must stay fixed, as they match the corresponding + * pin assignment fields in the PORT_TX_DFLEXPA1 and TCSS_DDI_STATUS registers. + */ +enum intel_tc_pin_assignment { /* Lanes (a) Signal/ Cable Notes */ + /* DP USB Rate (b) type */ + INTEL_TC_PIN_ASSIGNMENT_NONE = 0, /* 4 - - - (c) */ + INTEL_TC_PIN_ASSIGNMENT_A, /* 2/4 0 GEN2 TC->TC (d,e) */ + INTEL_TC_PIN_ASSIGNMENT_B, /* 1/2 1 GEN2 TC->TC (d,f,g) */ + INTEL_TC_PIN_ASSIGNMENT_C, /* 4 0 DP2 TC->TC (h) */ + INTEL_TC_PIN_ASSIGNMENT_D, /* 2 1 DP2 TC->TC (h,g) */ + INTEL_TC_PIN_ASSIGNMENT_E, /* 4 0 DP2 TC->DP */ + INTEL_TC_PIN_ASSIGNMENT_F, /* 2 1 GEN1/DP1 TC->DP (d,g,i) */ + /* + * (a) - DP unidirectional lanes, each lane using 1 differential signal + * pair. + * - USB SuperSpeed bidirectional lane, using 2 differential (TX and + * RX) signal pairs. + * - USB 2.0 (HighSpeed) unidirectional lane, using 1 differential + * signal pair. Not indicated, this lane is always present on pin + * assignments A-D and never present on pin assignments E/F. + * (b) - GEN1: USB 3.1 GEN1 bit rate (5 Gbps) and signaling. This + * is used for transferring only a USB stream. + * - GEN2: USB 3.1 GEN2 bit rate (10 Gbps) and signaling. This + * allows transferring an HBR3 (8.1 Gbps) DP stream. + * - DP1: Display Port signaling defined by the DP v1.3 Standard, + * with a maximum bit rate of HBR3. + * - DP2: Display Port signaling defined by the DP v2.1 Standard, + * with a maximum bit rate defined by the DP Alt Mode + * v2.1a Standard depending on the cable type as follows: + * - Passive (Full-Featured) USB 3.2 GEN1 + * TC->TC cables (CC3G1-X) : UHBR10 + * - Passive (Full-Featured) USB 3.2/4 GEN2 and + * Thunderbolt Alt Mode GEN2 + * TC->TC cables (CC3G2-X) all : UHBR10 + * DP54 logo : UHBR13.5 + * - Passive (Full-Featured) USB4 GEN3+ and + * Thunderbolt Alt Mode GEN3+ + * TC->TC cables (CC4G3-X) all : UHBR13.5 + * DP80 logo : UHBR20 + * - Active Re-Timed or + * Active Linear Re-driven (LRD) + * USB3.2 GEN1/2 and USB4 GEN2+ + * TC->TC cables all : HBR3 + * with DP_BR CTS : UHBR10 + * DP54 logo : UHBR13.5 + * DP80 logo : UHBR20 + * - Passive/Active Re-Timed or + * Active Linear Re-driven (LRD) + * TC->DP cables with DP_BR CTS/DP8K logo : HBR3 + * with DP_BR CTS : UHBR10 + * DP54 logo : UHBR13.5 + * DP80 logo : UHBR20 + * (c) Used in TBT-alt/legacy modes and on LNL+ after the sink + * disconnected in DP-alt mode. + * (d) Only defined by the DP Alt Standard v1.0a, deprecated by v1.0b, + * only supported on ICL. + * (e) GEN2 passive 1 m cable: 4 DP lanes, GEN2 active cable: 2 DP lanes. + * (f) GEN2 passive 1 m cable: 2 DP lanes, GEN2 active cable: 1 DP lane. + * (g) These pin assignments are also referred to as (USB/DP) + * multifunction or Multifunction Display Port (MFD) modes. + * (h) Also used where one end of the cable is a captive connector, + * attached to a DP->HDMI/DVI/VGA converter. + * (i) The DP end of the cable is a captive connector attached to a + * (DP/USB) multifunction dock as defined by the DockPort v1.0a + * specification. + */ +}; + bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); @@ -19,7 +88,8 @@ bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); -u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port); +enum intel_tc_pin_assignment +intel_tc_port_get_pin_assignment(struct intel_digital_port *dig_port); int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port); void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes); diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index 70ba7aa26bf4..0b7fcc05e64c 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -3,9 +3,12 @@ * Copyright © 2022-2023 Intel Corporation */ +#include <linux/iopoll.h> + #include <drm/drm_vblank.h> #include "i915_drv.h" +#include "i915_utils.h" #include "intel_color.h" #include "intel_crtc.h" #include "intel_de.h" @@ -492,9 +495,14 @@ static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state) { struct intel_display *display = to_intel_display(crtc); enum pipe pipe = crtc->pipe; + bool is_moving; + int ret; /* Wait for the display line to settle/start moving */ - if (wait_for(pipe_scanline_is_moving(display, pipe) == state, 100)) + ret = poll_timeout_us(is_moving = pipe_scanline_is_moving(display, pipe), + is_moving == state, + 500, 100 * 1000, false); + if (ret) drm_err(display->drm, "pipe %c scanline %s wait timed out\n", pipe_name(pipe), str_on_off(state)); @@ -673,7 +681,7 @@ void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state, else evade->vblank_start = intel_vrr_vmax_vblank_start(crtc_state); - vblank_delay = intel_vrr_vblank_delay(crtc_state); + vblank_delay = crtc_state->set_context_latency; } else { evade->vblank_start = intel_mode_vblank_start(adjusted_mode); @@ -724,9 +732,9 @@ int intel_vblank_evade(struct intel_vblank_evade_ctx *evade) break; if (!timeout) { - drm_err(display->drm, - "Potential atomic update failure on pipe %c\n", - pipe_name(crtc->pipe)); + drm_dbg_kms(display->drm, + "Potential atomic update failure on pipe %c\n", + pipe_name(crtc->pipe)); break; } diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index 92c04811aa28..70e31520c560 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -37,7 +37,7 @@ #ifndef _INTEL_VBT_DEFS_H_ #define _INTEL_VBT_DEFS_H_ -#include "intel_bios.h" +#include "intel_dsi_vbt_defs.h" /* EDID derived structures */ struct bdb_edid_pnp_id { @@ -437,6 +437,22 @@ enum vbt_gmbus_ddi { #define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR13P5 6 #define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR20 7 +/* EDP link rate 263+ */ +#define BDB_263_VBT_EDP_LINK_RATE_1_62 BIT_U32(0) +#define BDB_263_VBT_EDP_LINK_RATE_2_16 BIT_U32(1) +#define BDB_263_VBT_EDP_LINK_RATE_2_43 BIT_U32(2) +#define BDB_263_VBT_EDP_LINK_RATE_2_7 BIT_U32(3) +#define BDB_263_VBT_EDP_LINK_RATE_3_24 BIT_U32(4) +#define BDB_263_VBT_EDP_LINK_RATE_4_32 BIT_U32(5) +#define BDB_263_VBT_EDP_LINK_RATE_5_4 BIT_U32(6) +#define BDB_263_VBT_EDP_LINK_RATE_6_75 BIT_U32(7) +#define BDB_263_VBT_EDP_LINK_RATE_8_1 BIT_U32(8) +#define BDB_263_VBT_EDP_LINK_RATE_10 BIT_U32(9) +#define BDB_263_VBT_EDP_LINK_RATE_13_5 BIT_U32(10) +#define BDB_263_VBT_EDP_LINK_RATE_20 BIT_U32(11) +#define BDB_263_VBT_EDP_NUM_RATES 12 +#define BDB_263_VBT_EDP_RATES_MASK GENMASK(BDB_263_VBT_EDP_NUM_RATES - 1, 0) + /* * The child device config, aka the display device data structure, provides a * description of a port and its configuration on the platform. @@ -547,6 +563,8 @@ struct child_device_config { u8 dp_max_link_rate:3; /* 216+ */ u8 dp_max_link_rate_reserved:5; /* 216+ */ u8 efp_index; /* 256+ */ + u32 edp_data_rate_override:12; /* 263+ */ + u32 edp_data_rate_override_reserved:20; /* 263+ */ } __packed; struct bdb_general_definitions { diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 3eed37f271b0..190c51be5cbc 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -79,12 +79,6 @@ intel_vrr_check_modeset(struct intel_atomic_state *state) } } -static int intel_vrr_real_vblank_delay(const struct intel_crtc_state *crtc_state) -{ - return crtc_state->hw.adjusted_mode.crtc_vblank_start - - crtc_state->hw.adjusted_mode.crtc_vdisplay; -} - static int intel_vrr_extra_vblank_delay(struct intel_display *display) { /* @@ -98,25 +92,36 @@ static int intel_vrr_extra_vblank_delay(struct intel_display *display) return DISPLAY_VER(display) < 13 ? 1 : 0; } -int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) +static int intel_vrr_vmin_flipline_offset(struct intel_display *display) { - struct intel_display *display = to_intel_display(crtc_state); - - return intel_vrr_real_vblank_delay(crtc_state) + - intel_vrr_extra_vblank_delay(display); + /* + * ICL/TGL hardware imposes flipline>=vmin+1 + * + * We reduce the vmin value to compensate when programming the + * hardware. This approach allows flipline to remain set at the + * original value, and thus the frame will have the desired + * minimum vtotal. + */ + return DISPLAY_VER(display) < 13 ? 1 : 0; } -static int intel_vrr_flipline_offset(struct intel_display *display) +static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) { - /* ICL/TGL hardware imposes flipline>=vmin+1 */ - return DISPLAY_VER(display) < 13 ? 1 : 0; + return crtc_state->vrr.vmin; } -static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) +static int intel_vrr_guardband_to_pipeline_full(const struct intel_crtc_state *crtc_state, + int guardband) { - struct intel_display *display = to_intel_display(crtc_state); + /* hardware imposes one extra scanline somewhere */ + return guardband - crtc_state->framestart_delay - 1; +} - return crtc_state->vrr.vmin + intel_vrr_flipline_offset(display); +static int intel_vrr_pipeline_full_to_guardband(const struct intel_crtc_state *crtc_state, + int pipeline_full) +{ + /* hardware imposes one extra scanline somewhere */ + return pipeline_full + crtc_state->framestart_delay + 1; } /* @@ -137,36 +142,18 @@ static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) */ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - - if (DISPLAY_VER(display) >= 13) - return crtc_state->vrr.guardband; - else - /* hardware imposes one extra scanline somewhere */ - return crtc_state->vrr.pipeline_full + crtc_state->framestart_delay + 1; + return crtc_state->vrr.guardband; } int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - /* Min vblank actually determined by flipline */ - if (DISPLAY_VER(display) >= 13) - return intel_vrr_vmin_flipline(crtc_state); - else - return intel_vrr_vmin_flipline(crtc_state) + - intel_vrr_real_vblank_delay(crtc_state); + return intel_vrr_vmin_flipline(crtc_state); } int intel_vrr_vmax_vtotal(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - - if (DISPLAY_VER(display) >= 13) - return crtc_state->vrr.vmax; - else - return crtc_state->vrr.vmax + - intel_vrr_real_vblank_delay(crtc_state); + return crtc_state->vrr.vmax; } int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state) @@ -250,42 +237,50 @@ void intel_vrr_compute_vrr_timings(struct intel_crtc_state *crtc_state) crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } +static int intel_vrr_hw_value(const struct intel_crtc_state *crtc_state, + int value) +{ + struct intel_display *display = to_intel_display(crtc_state); + + /* + * On TGL vmin/vmax/flipline also need to be + * adjusted by the SCL to maintain correct vtotals. + */ + if (DISPLAY_VER(display) >= 13) + return value; + else + return value - crtc_state->set_context_latency; +} + /* * For fixed refresh rate mode Vmin, Vmax and Flipline all are set to * Vtotal value. */ static -int intel_vrr_fixed_rr_vtotal(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vtotal(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - int crtc_vtotal = crtc_state->hw.adjusted_mode.crtc_vtotal; - - if (DISPLAY_VER(display) >= 13) - return crtc_vtotal; - else - return crtc_vtotal - - intel_vrr_real_vblank_delay(crtc_state); + return intel_vrr_hw_value(crtc_state, crtc_state->hw.adjusted_mode.crtc_vtotal); } static -int intel_vrr_fixed_rr_vmax(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vmax(const struct intel_crtc_state *crtc_state) { - return intel_vrr_fixed_rr_vtotal(crtc_state); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } static -int intel_vrr_fixed_rr_vmin(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vmin(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - return intel_vrr_fixed_rr_vtotal(crtc_state) - - intel_vrr_flipline_offset(display); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state) - + intel_vrr_vmin_flipline_offset(display); } static -int intel_vrr_fixed_rr_flipline(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_flipline(const struct intel_crtc_state *crtc_state) { - return intel_vrr_fixed_rr_vtotal(crtc_state); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) @@ -297,11 +292,11 @@ void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) return; intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), - intel_vrr_fixed_rr_vmin(crtc_state) - 1); + intel_vrr_fixed_rr_hw_vmin(crtc_state) - 1); intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), - intel_vrr_fixed_rr_vmax(crtc_state) - 1); + intel_vrr_fixed_rr_hw_vmax(crtc_state) - 1); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), - intel_vrr_fixed_rr_flipline(crtc_state) - 1); + intel_vrr_fixed_rr_hw_flipline(crtc_state) - 1); } static @@ -396,13 +391,6 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, else intel_vrr_compute_fixed_rr_timings(crtc_state); - /* - * flipline determines the min vblank length the hardware will - * generate, and on ICL/TGL flipline>=vmin+1, hence we reduce - * vmin by one to make sure we can get the actual min vblank length. - */ - crtc_state->vrr.vmin -= intel_vrr_flipline_offset(display); - if (HAS_AS_SDP(display)) { crtc_state->vrr.vsync_start = (crtc_state->hw.adjusted_mode.crtc_vtotal - @@ -413,6 +401,38 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, } } +static int +intel_vrr_max_hw_guardband(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + int max_pipeline_full = REG_FIELD_MAX(VRR_CTL_PIPELINE_FULL_MASK); + + if (DISPLAY_VER(display) >= 13) + return REG_FIELD_MAX(XELPD_VRR_CTL_VRR_GUARDBAND_MASK); + else + return intel_vrr_pipeline_full_to_guardband(crtc_state, + max_pipeline_full); +} + +static int +intel_vrr_max_vblank_guardband(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + + return crtc_state->vrr.vmin - + adjusted_mode->crtc_vdisplay - + crtc_state->set_context_latency - + intel_vrr_extra_vblank_delay(display); +} + +static int +intel_vrr_max_guardband(struct intel_crtc_state *crtc_state) +{ + return min(intel_vrr_max_hw_guardband(crtc_state), + intel_vrr_max_vblank_guardband(crtc_state)); +} + void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -421,23 +441,13 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) if (!intel_vrr_possible(crtc_state)) return; - if (DISPLAY_VER(display) >= 13) { - crtc_state->vrr.guardband = - crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; - } else { - /* hardware imposes one extra scanline somewhere */ - crtc_state->vrr.pipeline_full = - min(255, crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start - - crtc_state->framestart_delay - 1); + crtc_state->vrr.guardband = min(crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay, + intel_vrr_max_guardband(crtc_state)); - /* - * vmin/vmax/flipline also need to be adjusted by - * the vblank delay to maintain correct vtotals. - */ - crtc_state->vrr.vmin -= intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.vmax -= intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.flipline -= intel_vrr_real_vblank_delay(crtc_state); - } + if (DISPLAY_VER(display) < 13) + crtc_state->vrr.pipeline_full = + intel_vrr_guardband_to_pipeline_full(crtc_state, + crtc_state->vrr.guardband); } static u32 trans_vrr_ctl(const struct intel_crtc_state *crtc_state) @@ -595,6 +605,24 @@ void intel_vrr_set_db_point_and_transmission_line(const struct intel_crtc_state EMP_AS_SDP_DB_TL(crtc_state->vrr.vsync_start)); } +static int intel_vrr_hw_vmin(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmin) - + intel_vrr_vmin_flipline_offset(display); +} + +static int intel_vrr_hw_vmax(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmax); +} + +static int intel_vrr_hw_flipline(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.flipline); +} + void intel_vrr_enable(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -604,11 +632,11 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state) return; intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), - crtc_state->vrr.vmin - 1); + intel_vrr_hw_vmin(crtc_state) - 1); intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), - crtc_state->vrr.vmax - 1); + intel_vrr_hw_vmax(crtc_state) - 1); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), - crtc_state->vrr.flipline - 1); + intel_vrr_hw_flipline(crtc_state) - 1); intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), TRANS_PUSH_EN); @@ -627,6 +655,15 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state) } } +static void intel_vrr_wait_for_live_status_clear(struct intel_display *display, + enum transcoder cpu_transcoder) +{ + if (intel_de_wait_for_clear(display, + TRANS_VRR_STATUS(display, cpu_transcoder), + VRR_STATUS_VRR_EN_LIVE, 1000)) + drm_err(display->drm, "Timed out waiting for VRR live status to clear\n"); +} + void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) { struct intel_display *display = to_intel_display(old_crtc_state); @@ -638,9 +675,7 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) if (!intel_vrr_always_use_vrr_tg(display)) { intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), trans_vrr_ctl(old_crtc_state)); - intel_de_wait_for_clear(display, - TRANS_VRR_STATUS(display, cpu_transcoder), - VRR_STATUS_VRR_EN_LIVE, 1000); + intel_vrr_wait_for_live_status_clear(display, cpu_transcoder); intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); } @@ -686,8 +721,8 @@ void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state) intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), 0); - intel_de_wait_for_clear(display, TRANS_VRR_STATUS(display, cpu_transcoder), - VRR_STATUS_VRR_EN_LIVE, 1000); + intel_vrr_wait_for_live_status_clear(display, cpu_transcoder); + intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); } @@ -720,14 +755,20 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) TRANS_CMRR_M_HI(display, cpu_transcoder)); } - if (DISPLAY_VER(display) >= 13) + if (DISPLAY_VER(display) >= 13) { crtc_state->vrr.guardband = REG_FIELD_GET(XELPD_VRR_CTL_VRR_GUARDBAND_MASK, trans_vrr_ctl); - else - if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE) + } else { + if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE) { crtc_state->vrr.pipeline_full = REG_FIELD_GET(VRR_CTL_PIPELINE_FULL_MASK, trans_vrr_ctl); + crtc_state->vrr.guardband = + intel_vrr_pipeline_full_to_guardband(crtc_state, + crtc_state->vrr.pipeline_full); + } + } + if (trans_vrr_ctl & VRR_CTL_FLIP_LINE_EN) { crtc_state->vrr.flipline = intel_de_read(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder)) + 1; @@ -736,6 +777,15 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) crtc_state->vrr.vmin = intel_de_read(display, TRANS_VRR_VMIN(display, cpu_transcoder)) + 1; + if (DISPLAY_VER(display) < 13) { + /* undo what intel_vrr_hw_value() does when writing the values */ + crtc_state->vrr.flipline += crtc_state->set_context_latency; + crtc_state->vrr.vmax += crtc_state->set_context_latency; + crtc_state->vrr.vmin += crtc_state->set_context_latency; + + crtc_state->vrr.vmin += intel_vrr_vmin_flipline_offset(display); + } + /* * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal * bits are not filled. Since for these platforms TRAN_VMIN is always @@ -772,3 +822,20 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) if (crtc_state->vrr.enable) crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } + +int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (DISPLAY_VER(display) >= 30) + return crtc_state->hw.adjusted_mode.crtc_vdisplay - + crtc_state->set_context_latency; + else + return crtc_state->hw.adjusted_mode.crtc_vdisplay; +} + +int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_vmin_vblank_start(crtc_state) - + crtc_state->set_context_latency; +} diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index 38bf9996b883..7317f8730089 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -35,11 +35,12 @@ int intel_vrr_vmax_vtotal(const struct intel_crtc_state *crtc_state); int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state); int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state); int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state); -int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state); bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state); void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state); bool intel_vrr_always_use_vrr_tg(struct intel_display *display); +int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state); +int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_VRR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_wm.c b/drivers/gpu/drm/i915/display/intel_wm.c index bba82e888db2..f887a664fe22 100644 --- a/drivers/gpu/drm/i915/display/intel_wm.c +++ b/drivers/gpu/drm/i915/display/intel_wm.c @@ -5,7 +5,6 @@ #include <linux/debugfs.h> -#include <drm/drm_file.h> #include <drm/drm_print.h> #include "i9xx_wm.h" @@ -390,15 +389,15 @@ static const struct file_operations i915_cur_wm_latency_fops = { void intel_wm_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; + struct dentry *debugfs_root = display->drm->debugfs_root; - debugfs_create_file("i915_pri_wm_latency", 0644, minor->debugfs_root, + debugfs_create_file("i915_pri_wm_latency", 0644, debugfs_root, display, &i915_pri_wm_latency_fops); - debugfs_create_file("i915_spr_wm_latency", 0644, minor->debugfs_root, + debugfs_create_file("i915_spr_wm_latency", 0644, debugfs_root, display, &i915_spr_wm_latency_fops); - debugfs_create_file("i915_cur_wm_latency", 0644, minor->debugfs_root, + debugfs_create_file("i915_cur_wm_latency", 0644, debugfs_root, display, &i915_cur_wm_latency_fops); skl_watermark_debugfs_register(display); diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index d77798499c57..c6cccf170ff1 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -10,6 +10,7 @@ #include "intel_display_regs.h" #include "intel_display_trace.h" #include "intel_display_types.h" +#include "intel_display_wa.h" #include "intel_fb.h" #include "skl_scaler.h" #include "skl_universal_plane.h" @@ -91,11 +92,9 @@ static void skl_scaler_min_src_size(const struct drm_format_info *format, } } -static void skl_scaler_max_src_size(struct intel_crtc *crtc, +static void skl_scaler_max_src_size(struct intel_display *display, int *max_w, int *max_h) { - struct intel_display *display = to_intel_display(crtc); - if (DISPLAY_VER(display) >= 14) { *max_w = 4096; *max_h = 8192; @@ -134,6 +133,23 @@ static void skl_scaler_max_dst_size(struct intel_crtc *crtc, } } +enum drm_mode_status +skl_scaler_mode_valid(struct intel_display *display, + const struct drm_display_mode *mode, + enum intel_output_format output_format, + int num_joined_pipes) +{ + int max_h, max_w; + + if (num_joined_pipes < 2 && output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { + skl_scaler_max_src_size(display, &max_w, &max_h); + if (mode->hdisplay > max_h) + return MODE_NO_420; + } + + return MODE_OK; +} + static int skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, unsigned int scaler_user, int *scaler_id, @@ -201,7 +217,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, } skl_scaler_min_src_size(format, modifier, &min_src_w, &min_src_h); - skl_scaler_max_src_size(crtc, &max_src_w, &max_src_h); + skl_scaler_max_src_size(display, &max_src_w, &max_src_h); skl_scaler_min_dst_size(&min_dst_w, &min_dst_h); skl_scaler_max_dst_size(crtc, &max_dst_w, &max_dst_h); @@ -747,6 +763,9 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) crtc_state->scaler_state.scaler_id < 0)) return; + if (intel_display_wa(display, 14011503117)) + adl_scaler_ecc_mask(crtc_state); + drm_rect_init(&src, 0, 0, drm_rect_width(&crtc_state->pipe_src) << 16, drm_rect_height(&crtc_state->pipe_src) << 16); @@ -923,3 +942,29 @@ void skl_scaler_get_config(struct intel_crtc_state *crtc_state) else scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX); } + +void adl_scaler_ecc_mask(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (!crtc_state->pch_pfit.enabled) + return; + + intel_de_write(display, XELPD_DISPLAY_ERR_FATAL_MASK, ~0); +} + +void adl_scaler_ecc_unmask(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + const struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + + if (scaler_state->scaler_id < 0) + return; + + intel_de_write_fw(display, + SKL_PS_ECC_STAT(crtc->pipe, scaler_state->scaler_id), + 1); + intel_de_write(display, XELPD_DISPLAY_ERR_FATAL_MASK, 0); +} diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h b/drivers/gpu/drm/i915/display/skl_scaler.h index 355ea15260ca..12a19016c5f6 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.h +++ b/drivers/gpu/drm/i915/display/skl_scaler.h @@ -5,10 +5,14 @@ #ifndef INTEL_SCALER_H #define INTEL_SCALER_H +enum drm_mode_status; +struct drm_display_mode; struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; +struct intel_display; struct intel_dsb; +enum intel_output_format; struct intel_plane; struct intel_plane_state; @@ -32,4 +36,13 @@ void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); void skl_scaler_get_config(struct intel_crtc_state *crtc_state); +enum drm_mode_status +skl_scaler_mode_valid(struct intel_display *display, + const struct drm_display_mode *mode, + enum intel_output_format output_format, + int num_joined_pipes); + +void adl_scaler_ecc_mask(const struct intel_crtc_state *crtc_state); + +void adl_scaler_ecc_unmask(const struct intel_crtc_state *crtc_state); #endif diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index e20972ddfa09..e13fb781e7b2 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -10,6 +10,7 @@ #include "pxp/intel_pxp.h" #include "i915_drv.h" +#include "i915_utils.h" #include "intel_bo.h" #include "intel_de.h" #include "intel_display_irq.h" @@ -19,6 +20,7 @@ #include "intel_fb.h" #include "intel_fbc.h" #include "intel_frontbuffer.h" +#include "intel_panic.h" #include "intel_plane.h" #include "intel_psr.h" #include "intel_psr_regs.h" @@ -1166,8 +1168,7 @@ static u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) return plane_ctl; } -static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 skl_plane_ctl(const struct intel_plane_state *plane_state) { struct intel_display *display = to_intel_display(plane_state); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -1225,8 +1226,7 @@ static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state) return plane_color_ctl; } -static u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 glk_plane_color_ctl(const struct intel_plane_state *plane_state) { struct intel_display *display = to_intel_display(plane_state); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -1271,12 +1271,6 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state, u32 offset = plane_state->view.color_plane[color_plane].offset; if (intel_fb_uses_dpt(fb)) { - /* - * The DPT object contains only one vma, so the VMA's offset - * within the DPT is always 0. - */ - drm_WARN_ON(display->drm, plane_state->dpt_vma && - intel_dpt_offset(plane_state->dpt_vma)); drm_WARN_ON(display->drm, offset & 0x1fffff); return offset >> 9; } else { @@ -1285,13 +1279,20 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state, } } -static u32 skl_plane_surf(const struct intel_plane_state *plane_state, - int color_plane) +static int icl_plane_color_plane(const struct intel_plane_state *plane_state) +{ + if (plane_state->planar_linked_plane && !plane_state->is_y_plane) + return 1; + else + return 0; +} + +static u32 skl_plane_surf_offset(const struct intel_plane_state *plane_state) { + int color_plane = icl_plane_color_plane(plane_state); u32 plane_surf; - plane_surf = intel_plane_ggtt_offset(plane_state) + - skl_surf_address(plane_state, color_plane); + plane_surf = skl_surf_address(plane_state, color_plane); if (plane_state->decrypt) plane_surf |= PLANE_SURF_DECRYPT; @@ -1373,14 +1374,6 @@ static void icl_plane_csc_load_black(struct intel_dsb *dsb, intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 2), 0); } -static int icl_plane_color_plane(const struct intel_plane_state *plane_state) -{ - if (plane_state->planar_linked_plane && !plane_state->is_y_plane) - return 1; - else - return 0; -} - static void skl_plane_update_noarm(struct intel_dsb *dsb, struct intel_plane *plane, @@ -1476,7 +1469,7 @@ skl_plane_update_arm(struct intel_dsb *dsb, intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), plane_ctl); intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), - skl_plane_surf(plane_state, 0)); + plane_state->surf); } static void icl_plane_update_sel_fetch_noarm(struct intel_dsb *dsb, @@ -1632,7 +1625,6 @@ icl_plane_update_arm(struct intel_dsb *dsb, struct intel_display *display = to_intel_display(plane); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - int color_plane = icl_plane_color_plane(plane_state); u32 plane_ctl; plane_ctl = plane_state->ctl | @@ -1658,7 +1650,7 @@ icl_plane_update_arm(struct intel_dsb *dsb, intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), plane_ctl); intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), - skl_plane_surf(plane_state, color_plane)); + plane_state->surf); } static void skl_plane_capture_error(struct intel_crtc *crtc, @@ -1682,10 +1674,10 @@ skl_plane_async_flip(struct intel_dsb *dsb, struct intel_display *display = to_intel_display(plane); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - u32 plane_ctl = plane_state->ctl, plane_surf; + u32 plane_ctl = plane_state->ctl; + u32 plane_surf = plane_state->surf; plane_ctl |= skl_plane_ctl_crtc(crtc_state); - plane_surf = skl_plane_surf(plane_state, 0); if (async_flip) { if (DISPLAY_VER(display) >= 30) @@ -2363,11 +2355,10 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0); } - plane_state->ctl = skl_plane_ctl(crtc_state, plane_state); + plane_state->ctl = skl_plane_ctl(plane_state); if (DISPLAY_VER(display) >= 10) - plane_state->color_ctl = glk_plane_color_ctl(crtc_state, - plane_state); + plane_state->color_ctl = glk_plane_color_ctl(plane_state); if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && icl_is_hdr_plane(display, plane->id)) @@ -2814,7 +2805,7 @@ static void skl_disable_tiling(struct intel_plane *plane) intel_de_write_fw(display, PLANE_CTL(plane->pipe, plane->id), plane_ctl); intel_de_write_fw(display, PLANE_SURF(plane->pipe, plane->id), - skl_plane_surf(state, 0)); + state->surf); } struct intel_plane * @@ -2865,6 +2856,8 @@ skl_universal_plane_create(struct intel_display *display, } plane->disable_tiling = skl_disable_tiling; + plane->surf_offset = skl_plane_surf_offset; + if (DISPLAY_VER(display) >= 13) plane->max_stride = adl_plane_max_stride; else @@ -3036,7 +3029,7 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, return; } - intel_fb = intel_bo_alloc_framebuffer(); + intel_fb = intel_framebuffer_alloc(); if (!intel_fb) { drm_dbg_kms(display->drm, "failed to alloc fb\n"); return; @@ -3191,21 +3184,18 @@ bool skl_fixup_initial_plane_config(struct intel_crtc *crtc, to_intel_plane_state(plane->base.state); enum plane_id plane_id = plane->id; enum pipe pipe = crtc->pipe; - u32 base; if (!plane_state->uapi.visible) return false; - base = intel_plane_ggtt_offset(plane_state); - /* * We may have moved the surface to a different * part of ggtt, make the plane aware of that. */ - if (plane_config->base == base) + if (plane_config->base == plane_state->surf) return false; - intel_de_write(display, PLANE_SURF(pipe, plane_id), base); + intel_de_write(display, PLANE_SURF(pipe, plane_id), plane_state->surf); return true; } diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 222c069fdadb..9eb28d935757 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -6,7 +6,6 @@ #include <linux/debugfs.h> #include <drm/drm_blend.h> -#include <drm/drm_file.h> #include <drm/drm_print.h> #include "soc/intel_dram.h" @@ -1389,7 +1388,7 @@ skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, { u16 size, extra = 0; - if (data_rate) { + if (data_rate && iter->data_rate) { extra = min_t(u16, iter->size, DIV64_U64_ROUND_UP(iter->size * data_rate, iter->data_rate)); @@ -1879,18 +1878,21 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, } else { blocks++; } - - /* - * Make sure result blocks for higher latency levels are - * at least as high as level below the current level. - * Assumption in DDB algorithm optimization for special - * cases. Also covers Display WA #1125 for RC. - */ - if (result_prev->blocks > blocks) - blocks = result_prev->blocks; } } + /* + * Make sure result blocks for higher latency levels are + * at least as high as level below the current level. + * Assumption in DDB algorithm optimization for special + * cases. Also covers Display WA #1125 for RC. + * + * Let's always do this as the algorithm can give non + * monotonic results on any platform. + */ + blocks = max_t(u32, blocks, result_prev->blocks); + lines = max_t(u32, lines, result_prev->lines); + if (DISPLAY_VER(display) >= 11) { if (wp->y_tiled) { int extra_lines; @@ -2273,6 +2275,11 @@ static int skl_max_wm0_lines(const struct intel_crtc_state *crtc_state) return wm0_lines; } +/* + * TODO: In case we use PKG_C_LATENCY to allow C-states when the delayed vblank + * size is too small for the package C exit latency we need to notify PSR about + * the scenario to apply Wa_16025596647. + */ static int skl_max_wm_level_for_vblank(struct intel_crtc_state *crtc_state, int wm0_lines) { @@ -3170,12 +3177,53 @@ void skl_watermark_ipc_init(struct intel_display *display) skl_watermark_ipc_update(display); } -static void -adjust_wm_latency(struct intel_display *display, - u16 wm[], int num_levels, int read_latency) +static void multiply_wm_latency(struct intel_display *display, int mult) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; + + for (level = 0; level < num_levels; level++) + wm[level] *= mult; +} + +static void increase_wm_latency(struct intel_display *display, int inc) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; + + wm[0] += inc; + + for (level = 1; level < num_levels; level++) { + if (wm[level] == 0) + break; + + wm[level] += inc; + } +} + +static bool need_16gb_dimm_wa(struct intel_display *display) { const struct dram_info *dram_info = intel_dram_info(display->drm); - int i, level; + + return (display->platform.skylake || display->platform.kabylake || + display->platform.coffeelake || display->platform.cometlake || + DISPLAY_VER(display) == 11) && dram_info->has_16gb_dimms; +} + +static int wm_read_latency(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 14) + return 6; + else if (DISPLAY_VER(display) >= 12) + return 3; + else + return 2; +} + +static void sanitize_wm_latency(struct intel_display *display) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; /* * If a level n (n > 1) has a 0us latency, all levels m (m >= n) @@ -3183,14 +3231,38 @@ adjust_wm_latency(struct intel_display *display, * of the punit to satisfy this requirement. */ for (level = 1; level < num_levels; level++) { - if (wm[level] == 0) { - for (i = level + 1; i < num_levels; i++) - wm[i] = 0; + if (wm[level] == 0) + break; + } - num_levels = level; + for (level = level + 1; level < num_levels; level++) + wm[level] = 0; +} + +static void make_wm_latency_monotonic(struct intel_display *display) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; + + for (level = 1; level < num_levels; level++) { + if (wm[level] == 0) break; - } + + wm[level] = max(wm[level], wm[level-1]); } +} + +static void +adjust_wm_latency(struct intel_display *display) +{ + u16 *wm = display->wm.skl_latency; + + if (display->platform.dg2) + multiply_wm_latency(display, 2); + + sanitize_wm_latency(display); + + make_wm_latency_monotonic(display); /* * WaWmMemoryReadLatency @@ -3199,24 +3271,22 @@ adjust_wm_latency(struct intel_display *display, * to add proper adjustment to each valid level we retrieve * from the punit when level 0 response data is 0us. */ - if (wm[0] == 0) { - for (level = 0; level < num_levels; level++) - wm[level] += read_latency; - } + if (wm[0] == 0) + increase_wm_latency(display, wm_read_latency(display)); /* - * WA Level-0 adjustment for 16GB DIMMs: SKL+ + * WA Level-0 adjustment for 16Gb+ DIMMs: SKL+ * If we could not get dimm info enable this WA to prevent from - * any underrun. If not able to get Dimm info assume 16GB dimm + * any underrun. If not able to get DIMM info assume 16Gb+ DIMM * to avoid any underrun. */ - if (!display->platform.dg2 && dram_info->wm_lv_0_adjust_needed) - wm[0] += 1; + if (need_16gb_dimm_wa(display)) + increase_wm_latency(display, 1); } -static void mtl_read_wm_latency(struct intel_display *display, u16 wm[]) +static void mtl_read_wm_latency(struct intel_display *display) { - int num_levels = display->wm.num_levels; + u16 *wm = display->wm.skl_latency; u32 val; val = intel_de_read(display, MTL_LATENCY_LP0_LP1); @@ -3230,15 +3300,11 @@ static void mtl_read_wm_latency(struct intel_display *display, u16 wm[]) val = intel_de_read(display, MTL_LATENCY_LP4_LP5); wm[4] = REG_FIELD_GET(MTL_LATENCY_LEVEL_EVEN_MASK, val); wm[5] = REG_FIELD_GET(MTL_LATENCY_LEVEL_ODD_MASK, val); - - adjust_wm_latency(display, wm, num_levels, 6); } -static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) +static void skl_read_wm_latency(struct intel_display *display) { - int num_levels = display->wm.num_levels; - int read_latency = DISPLAY_VER(display) >= 12 ? 3 : 2; - int mult = display->platform.dg2 ? 2 : 1; + u16 *wm = display->wm.skl_latency; u32 val; int ret; @@ -3250,10 +3316,10 @@ static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) return; } - wm[0] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val) * mult; - wm[1] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val) * mult; - wm[2] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val) * mult; - wm[3] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val) * mult; + wm[0] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val); + wm[1] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val); + wm[2] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val); + wm[3] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val); /* read the second set of memory latencies[4:7] */ val = 1; /* data0 to be programmed to 1 for second set */ @@ -3263,12 +3329,10 @@ static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) return; } - wm[4] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val) * mult; - wm[5] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val) * mult; - wm[6] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val) * mult; - wm[7] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val) * mult; - - adjust_wm_latency(display, wm, num_levels, read_latency); + wm[4] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val); + wm[5] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val); + wm[6] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val); + wm[7] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val); } static void skl_setup_wm_latency(struct intel_display *display) @@ -3279,11 +3343,15 @@ static void skl_setup_wm_latency(struct intel_display *display) display->wm.num_levels = 8; if (DISPLAY_VER(display) >= 14) - mtl_read_wm_latency(display, display->wm.skl_latency); + mtl_read_wm_latency(display); else - skl_read_wm_latency(display, display->wm.skl_latency); + skl_read_wm_latency(display); + + intel_print_wm_latency(display, "original", display->wm.skl_latency); + + adjust_wm_latency(display); - intel_print_wm_latency(display, "Gen9 Plane", display->wm.skl_latency); + intel_print_wm_latency(display, "adjusted", display->wm.skl_latency); } static struct intel_global_state *intel_dbuf_duplicate_state(struct intel_global_obj *obj) @@ -4033,14 +4101,14 @@ DEFINE_SHOW_ATTRIBUTE(intel_sagv_status); void skl_watermark_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = display->drm->primary; + struct dentry *debugfs_root = display->drm->debugfs_root; if (HAS_IPC(display)) - debugfs_create_file("i915_ipc_status", 0644, minor->debugfs_root, + debugfs_create_file("i915_ipc_status", 0644, debugfs_root, display, &skl_watermark_ipc_status_fops); if (HAS_SAGV(display)) - debugfs_create_file("i915_sagv_status", 0444, minor->debugfs_root, + debugfs_create_file("i915_sagv_status", 0444, debugfs_root, display, &intel_sagv_status_fops); } diff --git a/drivers/gpu/drm/i915/display/vlv_clock.c b/drivers/gpu/drm/i915/display/vlv_clock.c new file mode 100644 index 000000000000..1abdae453514 --- /dev/null +++ b/drivers/gpu/drm/i915/display/vlv_clock.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2025 Intel Corporation */ + +#include <drm/drm_print.h> + +#include "intel_display_core.h" +#include "intel_display_types.h" +#include "vlv_clock.h" +#include "vlv_sideband.h" + +/* + * FIXME: The caching of hpll_freq and czclk_freq relies on the first calls + * occurring at a time when they can actually be read. This appears to be the + * case, but is somewhat fragile. Make the initialization explicit at a point + * where they can be reliably read. + */ + +/* returns HPLL frequency in kHz */ +int vlv_clock_get_hpll_vco(struct drm_device *drm) +{ + struct intel_display *display = to_intel_display(drm); + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + + if (!display->vlv_clock.hpll_freq) { + vlv_cck_get(drm); + /* Obtain SKU information */ + hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + vlv_cck_put(drm); + + display->vlv_clock.hpll_freq = vco_freq[hpll_freq] * 1000; + + drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", display->vlv_clock.hpll_freq); + } + + return display->vlv_clock.hpll_freq; +} + +static int vlv_clock_get_cck(struct drm_device *drm, + const char *name, u32 reg, int ref_freq) +{ + u32 val; + int divider; + + vlv_cck_get(drm); + val = vlv_cck_read(drm, reg); + vlv_cck_put(drm); + + divider = val & CCK_FREQUENCY_VALUES; + + drm_WARN(drm, (val & CCK_FREQUENCY_STATUS) != + (divider << CCK_FREQUENCY_STATUS_SHIFT), + "%s change in progress\n", name); + + return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); +} + +int vlv_clock_get_hrawclk(struct drm_device *drm) +{ + /* RAWCLK_FREQ_VLV register updated from power well code */ + return vlv_clock_get_cck(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); +} + +int vlv_clock_get_czclk(struct drm_device *drm) +{ + struct intel_display *display = to_intel_display(drm); + + if (!display->vlv_clock.czclk_freq) { + display->vlv_clock.czclk_freq = vlv_clock_get_cck(drm, "czclk", CCK_CZ_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); + drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", display->vlv_clock.czclk_freq); + } + + return display->vlv_clock.czclk_freq; +} + +int vlv_clock_get_cdclk(struct drm_device *drm) +{ + return vlv_clock_get_cck(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); +} + +int vlv_clock_get_gpll(struct drm_device *drm) +{ + return vlv_clock_get_cck(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, + vlv_clock_get_czclk(drm)); +} diff --git a/drivers/gpu/drm/i915/display/vlv_clock.h b/drivers/gpu/drm/i915/display/vlv_clock.h new file mode 100644 index 000000000000..5742ed3c628d --- /dev/null +++ b/drivers/gpu/drm/i915/display/vlv_clock.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __VLV_CLOCK_H__ +#define __VLV_CLOCK_H__ + +struct drm_device; + +#ifdef I915 +int vlv_clock_get_hpll_vco(struct drm_device *drm); +int vlv_clock_get_hrawclk(struct drm_device *drm); +int vlv_clock_get_czclk(struct drm_device *drm); +int vlv_clock_get_cdclk(struct drm_device *drm); +int vlv_clock_get_gpll(struct drm_device *drm); +#else +static inline int vlv_clock_get_hpll_vco(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_hrawclk(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_czclk(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_cdclk(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_gpll(struct drm_device *drm) +{ + return 0; +} +#endif + +#endif /* __VLV_CLOCK_H__ */ diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 6d9f3312de7e..c9a53fde79c4 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -761,7 +761,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, if (display->platform.valleyview || display->platform.cherryview) { /* Disable DPOunit clock gating, can stall pipe */ - intel_de_rmw(display, DSPCLK_GATE_D(display), + intel_de_rmw(display, VLV_DSPCLK_GATE_D, 0, DPOUNIT_CLOCK_GATE_DISABLE); } @@ -918,7 +918,7 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state, } else { vlv_dsi_pll_disable(encoder); - intel_de_rmw(display, DSPCLK_GATE_D(display), + intel_de_rmw(display, VLV_DSPCLK_GATE_D, DPOUNIT_CLOCK_GATE_DISABLE, 0); } diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c index d42b61e6f076..f078b9cda96c 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c @@ -25,12 +25,12 @@ * Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com> */ +#include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/string_helpers.h> #include <drm/drm_print.h> -#include "i915_utils.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsi.h" @@ -142,11 +142,9 @@ static int vlv_dsi_pclk(struct intel_encoder *encoder, pll_div &= DSI_PLL_M1_DIV_MASK; pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT; - while (pll_ctl) { - pll_ctl = pll_ctl >> 1; - p++; - } - p--; + p = fls(pll_ctl); + if (p) + p--; if (!p) { drm_err(display->drm, "wrong P1 divisor\n"); @@ -216,6 +214,8 @@ void vlv_dsi_pll_enable(struct intel_encoder *encoder, const struct intel_crtc_state *config) { struct intel_display *display = to_intel_display(encoder); + u32 val; + int ret; drm_dbg_kms(display->drm, "\n"); @@ -233,9 +233,10 @@ void vlv_dsi_pll_enable(struct intel_encoder *encoder, vlv_cck_write(display->drm, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl); - if (wait_for(vlv_cck_read(display->drm, CCK_REG_DSI_PLL_CONTROL) & - DSI_PLL_LOCK, 20)) { - + ret = poll_timeout_us(val = vlv_cck_read(display->drm, CCK_REG_DSI_PLL_CONTROL), + val & DSI_PLL_LOCK, + 500, 20 * 1000, false); + if (ret) { vlv_cck_put(display->drm); drm_err(display->drm, "DSI PLL lock failed\n"); return; @@ -262,6 +263,11 @@ void vlv_dsi_pll_disable(struct intel_encoder *encoder) vlv_cck_put(display->drm); } +static bool has_dsic_clock(struct intel_display *display) +{ + return display->platform.broxton; +} + bool bxt_dsi_pll_is_enabled(struct intel_display *display) { bool enabled; @@ -284,7 +290,7 @@ bool bxt_dsi_pll_is_enabled(struct intel_display *display) * causes a system hang. */ val = intel_de_read(display, BXT_DSI_PLL_CTL); - if (display->platform.geminilake) { + if (!has_dsic_clock(display)) { if (!(val & BXT_DSIA_16X_MASK)) { drm_dbg_kms(display->drm, "Invalid PLL divider (%08x)\n", val); @@ -358,6 +364,8 @@ u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, u32 pclk; config->dsi_pll.ctrl = intel_de_read(display, BXT_DSI_PLL_CTL); + if (!has_dsic_clock(display)) + config->dsi_pll.ctrl &= ~BXT_DSIC_16X_MASK; pclk = bxt_dsi_pclk(encoder, config); @@ -514,7 +522,9 @@ int bxt_dsi_pll_compute(struct intel_encoder *encoder, * Spec says both have to be programmed, even if one is not getting * used. Configure MIPI_CLOCK_CTL dividers in modeset */ - config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2; + config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2; + if (has_dsic_clock(display)) + config->dsi_pll.ctrl |= BXT_DSIC_16X_BY2; /* As per recommendation from hardware team, * Prog PVD ratio =1 if dsi ratio <= 50 diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 15835952352e..ed6599694835 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -2158,18 +2158,12 @@ static int set_context_image(struct i915_gem_context *ctx, goto out_ce; } - state = kmalloc(ce->engine->context_size, GFP_KERNEL); - if (!state) { - ret = -ENOMEM; + state = memdup_user(u64_to_user_ptr(user.image), ce->engine->context_size); + if (IS_ERR(state)) { + ret = PTR_ERR(state); goto out_ce; } - if (copy_from_user(state, u64_to_user_ptr(user.image), - ce->engine->context_size)) { - ret = -EFAULT; - goto out_state; - } - shmem_state = shmem_create_from_data(ce->engine->name, state, ce->engine->context_size); if (IS_ERR(shmem_state)) { diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index ca7e9216934a..39c7c32e1e74 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -182,7 +182,7 @@ enum { * the object. Simple! ... The relocation entries are stored in user memory * and so to access them we have to copy them into a local buffer. That copy * has to avoid taking any pagefaults as they may lead back to a GEM object - * requiring the struct_mutex (i.e. recursive deadlock). So once again we split + * requiring the vm->mutex (i.e. recursive deadlock). So once again we split * the relocation into multiple passes. First we try to do everything within an * atomic context (avoid the pagefaults) which requires that we never wait. If * we detect that we may wait, or if we need to fault, then we have to fallback @@ -1382,8 +1382,9 @@ static void clflush_write32(u32 *addr, u32 value, unsigned int flushes) */ if (flushes & CLFLUSH_AFTER) drm_clflush_virt_range(addr, sizeof(*addr)); - } else + } else { *addr = value; + } } static u64 @@ -1567,36 +1568,36 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev) do { u64 offset = eb_relocate_entry(eb, ev, r); - if (likely(offset == 0)) { - } else if ((s64)offset < 0) { + if (likely(offset == 0)) + continue; + + if ((s64)offset < 0) { remain = (int)offset; goto out; - } else { - /* - * Note that reporting an error now - * leaves everything in an inconsistent - * state as we have *already* changed - * the relocation value inside the - * object. As we have not changed the - * reloc.presumed_offset or will not - * change the execobject.offset, on the - * call we may not rewrite the value - * inside the object, leaving it - * dangling and causing a GPU hang. Unless - * userspace dynamically rebuilds the - * relocations on each execbuf rather than - * presume a static tree. - * - * We did previously check if the relocations - * were writable (access_ok), an error now - * would be a strange race with mprotect, - * having already demonstrated that we - * can read from this userspace address. - */ - offset = gen8_canonical_addr(offset & ~UPDATE); - __put_user(offset, - &urelocs[r - stack].presumed_offset); } + /* + * Note that reporting an error now + * leaves everything in an inconsistent + * state as we have *already* changed + * the relocation value inside the + * object. As we have not changed the + * reloc.presumed_offset or will not + * change the execobject.offset, on the + * call we may not rewrite the value + * inside the object, leaving it + * dangling and causing a GPU hang. Unless + * userspace dynamically rebuilds the + * relocations on each execbuf rather than + * presume a static tree. + * + * We did previously check if the relocations + * were writable (access_ok), an error now + * would be a strange race with mprotect, + * having already demonstrated that we + * can read from this userspace address. + */ + offset = gen8_canonical_addr(offset & ~UPDATE); + __put_user(offset, &urelocs[r - stack].presumed_offset); } while (r++, --count); urelocs += ARRAY_SIZE(stack); } while (remain); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 1f38e367c60b..478011e5ecb3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -459,8 +459,8 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj) atomic_inc(&i915->mm.free_count); /* - * Since we require blocking on struct_mutex to unbind the freed - * object from the GPU before releasing resources back to the + * Since we require blocking on drm_i915_gem_object->vma.lock to unbind + * the freed object from the GPU before releasing resources back to the * system, we can not do that directly from the RCU callback (which may * be a softirq context), but must instead then defer that work onto a * kthread. We use the RCU callback rather than move the freed object diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 565f8fa330db..8878539c10ed 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -16,9 +16,9 @@ #include "i915_gem_ww.h" #include "i915_vma_types.h" -struct drm_scanout_buffer; enum intel_region_id; -struct intel_framebuffer; +struct drm_scanout_buffer; +struct intel_panic; #define obj_to_i915(obj__) to_i915((obj__)->base.dev) @@ -693,9 +693,10 @@ i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj); int i915_gem_object_truncate(struct drm_i915_gem_object *obj); -struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void); -int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb); -void i915_gem_object_panic_finish(struct intel_framebuffer *fb); +struct intel_panic *i915_gem_object_alloc_panic(void); +int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, + struct drm_gem_object *_obj, bool panic_tiling); +void i915_gem_object_panic_finish(struct intel_panic *panic); /** * i915_gem_object_pin_map - return a contiguous mapping of the entire object @@ -801,6 +802,7 @@ static inline void __start_cpu_write(struct drm_i915_gem_object *obj) void i915_gem_fence_wait_priority(struct dma_fence *fence, const struct i915_sched_attr *attr); +void i915_gem_fence_wait_priority_display(struct dma_fence *fence); int i915_gem_object_wait(struct drm_i915_gem_object *obj, unsigned int flags, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index c16a57160b26..76d2178572b6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -357,23 +357,13 @@ static void *i915_gem_object_map_pfn(struct drm_i915_gem_object *obj, return vaddr ?: ERR_PTR(-ENOMEM); } -struct i915_panic_data { +struct intel_panic { struct page **pages; int page; void *vaddr; }; -struct i915_framebuffer { - struct intel_framebuffer base; - struct i915_panic_data panic; -}; - -static inline struct i915_panic_data *to_i915_panic_data(struct intel_framebuffer *fb) -{ - return &container_of_const(fb, struct i915_framebuffer, base)->panic; -} - -static void i915_panic_kunmap(struct i915_panic_data *panic) +static void i915_panic_kunmap(struct intel_panic *panic) { if (panic->vaddr) { drm_clflush_virt_range(panic->vaddr, PAGE_SIZE); @@ -420,7 +410,7 @@ static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int new_page; unsigned int offset; struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; - struct i915_panic_data *panic = to_i915_panic_data(fb); + struct intel_panic *panic = fb->panic; if (fb->panic_tiling) offset = fb->panic_tiling(sb->width, x, y); @@ -441,14 +431,13 @@ static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, } } -struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void) +struct intel_panic *i915_gem_object_alloc_panic(void) { - struct i915_framebuffer *i915_fb; + struct intel_panic *panic; + + panic = kzalloc(sizeof(*panic), GFP_KERNEL); - i915_fb = kzalloc(sizeof(*i915_fb), GFP_KERNEL); - if (i915_fb) - return &i915_fb->base; - return NULL; + return panic; } /* @@ -456,12 +445,11 @@ struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void) * Use current vaddr if it exists, or setup a list of pages. * pfn is not supported yet. */ -int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb) +int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, + struct drm_gem_object *_obj, bool panic_tiling) { enum i915_map_type has_type; - struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; - struct i915_panic_data *panic = to_i915_panic_data(fb); - struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base)); + struct drm_i915_gem_object *obj = to_intel_bo(_obj); void *ptr; ptr = page_unpack_bits(obj->mm.mapping, &has_type); @@ -471,7 +459,7 @@ int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb) else iosys_map_set_vaddr(&sb->map[0], ptr); - if (fb->panic_tiling) + if (panic_tiling) sb->set_pixel = i915_gem_object_panic_map_set_pixel; return 0; } @@ -486,10 +474,8 @@ int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb) return -EOPNOTSUPP; } -void i915_gem_object_panic_finish(struct intel_framebuffer *fb) +void i915_gem_object_panic_finish(struct intel_panic *panic) { - struct i915_panic_data *panic = to_i915_panic_data(fb); - i915_panic_kunmap(panic); panic->page = -1; kfree(panic->pages); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index e3d188455f67..26dda55a07ff 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -441,11 +441,20 @@ shmem_pwrite(struct drm_i915_gem_object *obj, written = file->f_op->write_iter(&kiocb, &iter); BUG_ON(written == -EIOCBQUEUED); - if (written != size) - return -EIO; - + /* + * First, check if write_iter returned a negative error. + * If the write failed, return the real error code immediately. + * This prevents it from being overwritten by the short write check below. + */ if (written < 0) return written; + /* + * Check for a short write (written bytes != requested size). + * Even if some data was written, return -EIO to indicate that the + * write was not fully completed. + */ + if (written != size) + return -EIO; return 0; } @@ -514,6 +523,13 @@ static int __create_shmem(struct drm_i915_private *i915, if (IS_ERR(filp)) return PTR_ERR(filp); + /* + * Prevent -EFBIG by allowing large writes beyond MAX_NON_LFS on shmem + * objects by setting O_LARGEFILE. + */ + if (force_o_largefile()) + filp->f_flags |= O_LARGEFILE; + obj->filp = filp; return 0; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c index b81e67504bbe..7a3e74a6676e 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c @@ -170,7 +170,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww, * Also note that although these lists do not hold a reference to * the object we can safely grab one here: The final object * unreferencing and the bound_list are both protected by the - * dev->struct_mutex and so we won't ever be able to observe an + * i915->mm.obj_lock and so we won't ever be able to observe an * object on the bound_list with a reference count equals 0. */ for (phase = phases; phase->list; phase++) { @@ -185,7 +185,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww, /* * We serialize our access to unreferenced objects through - * the use of the struct_mutex. While the objects are not + * the use of the obj_lock. While the objects are not * yet freed (due to RCU then a workqueue) we still want * to be able to shrink their pages, so they remain on * the unbound/bound list until actually freed. diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 1f4814968868..57bb111d65da 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1029,7 +1029,7 @@ static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj) { GEM_BUG_ON(!obj->ttm.created); - ttm_bo_put(i915_gem_to_ttm(obj)); + ttm_bo_fini(i915_gem_to_ttm(obj)); } static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) @@ -1325,7 +1325,7 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, * If this function fails, it will call the destructor, but * our caller still owns the object. So no freeing in the * destructor until obj->ttm.created is true. - * Similarly, in delayed_destroy, we can't call ttm_bo_put() + * Similarly, in delayed_destroy, we can't call ttm_bo_fini() * until successful initialization. */ ret = ttm_bo_init_reserved(&i915->bdev, i915_gem_to_ttm(obj), bo_type, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index 991666fd9f85..2893df65c359 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -138,6 +138,13 @@ void i915_gem_fence_wait_priority(struct dma_fence *fence, local_bh_enable(); /* kick the tasklets if queues were reprioritised */ } +void i915_gem_fence_wait_priority_display(struct dma_fence *fence) +{ + struct i915_sched_attr attr = { .priority = I915_PRIORITY_DISPLAY }; + + i915_gem_fence_wait_priority(fence, &attr); +} + int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj, unsigned int flags, @@ -217,10 +224,10 @@ static unsigned long to_wait_timeout(s64 timeout_ns) * * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any * non-zero timeout parameter the wait ioctl will wait for the given number of - * nanoseconds on an object becoming unbusy. Since the wait itself does so - * without holding struct_mutex the object may become re-busied before this - * function completes. A similar but shorter * race condition exists in the busy - * ioctl + * nanoseconds on an object becoming unbusy. Since the wait occurs without + * holding a global or exclusive lock the object may become re-busied before + * this function completes. A similar but shorter * race condition exists + * in the busy ioctl */ int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c index 86d9d2fcb6a6..539c620364e3 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c @@ -5,7 +5,7 @@ #include "i915_selftest.h" -#include "display/intel_display_core.h" +#include "display/intel_display_device.h" #include "gt/intel_context.h" #include "gt/intel_engine_regs.h" #include "gt/intel_engine_user.h" @@ -110,6 +110,7 @@ struct tiled_blits { static bool fastblit_supports_x_tiling(const struct drm_i915_private *i915) { + struct intel_display *display = i915->display; int gen = GRAPHICS_VER(i915); /* XY_FAST_COPY_BLT does not exist on pre-gen9 platforms */ @@ -121,7 +122,7 @@ static bool fastblit_supports_x_tiling(const struct drm_i915_private *i915) if (GRAPHICS_VER_FULL(i915) < IP_VER(12, 55)) return false; - return HAS_DISPLAY(i915); + return intel_display_device_present(display); } static bool fast_blit_ok(const struct blit_buffer *buf) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c index eb0158e43417..1330c0b431a7 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c @@ -962,13 +962,14 @@ emit_rpcs_query(struct drm_i915_gem_object *obj, if (IS_ERR(rpcs)) return PTR_ERR(rpcs); + i915_gem_ww_ctx_init(&ww, false); + batch = i915_vma_instance(rpcs, ce->vm, NULL); if (IS_ERR(batch)) { err = PTR_ERR(batch); goto err_put; } - i915_gem_ww_ctx_init(&ww, false); retry: err = i915_gem_object_lock(obj, &ww); if (!err) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index 9c3f17e51885..78734c404a6d 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -1096,32 +1096,20 @@ static int ___igt_mmap_migrate(struct drm_i915_private *i915, unsigned long addr, bool unfaultable) { - struct vm_area_struct *area; - int err = 0, i; + int i; pr_info("igt_mmap(%s, %d) @ %lx\n", obj->mm.region->name, I915_MMAP_TYPE_FIXED, addr); - mmap_read_lock(current->mm); - area = vma_lookup(current->mm, addr); - mmap_read_unlock(current->mm); - if (!area) { - pr_err("%s: Did not create a vm_area_struct for the mmap\n", - obj->mm.region->name); - err = -EINVAL; - goto out_unmap; - } - for (i = 0; i < obj->base.size / sizeof(u32); i++) { u32 __user *ux = u64_to_user_ptr((u64)(addr + i * sizeof(*ux))); u32 x; if (get_user(x, ux)) { - err = -EFAULT; if (!unfaultable) { pr_err("%s: Unable to read from mmap, offset:%zd\n", obj->mm.region->name, i * sizeof(x)); - goto out_unmap; + return -EFAULT; } continue; @@ -1130,37 +1118,29 @@ static int ___igt_mmap_migrate(struct drm_i915_private *i915, if (unfaultable) { pr_err("%s: Faulted unmappable memory\n", obj->mm.region->name); - err = -EINVAL; - goto out_unmap; + return -EINVAL; } if (x != expand32(POISON_INUSE)) { pr_err("%s: Read incorrect value from mmap, offset:%zd, found:%x, expected:%x\n", obj->mm.region->name, i * sizeof(x), x, expand32(POISON_INUSE)); - err = -EINVAL; - goto out_unmap; + return -EINVAL; } x = expand32(POISON_FREE); if (put_user(x, ux)) { pr_err("%s: Unable to write to mmap, offset:%zd\n", obj->mm.region->name, i * sizeof(x)); - err = -EFAULT; - goto out_unmap; + return -EFAULT; } } - if (unfaultable) { - if (err == -EFAULT) - err = 0; - } else { - obj->flags &= ~I915_BO_ALLOC_GPU_ONLY; - err = wc_check(obj); - } -out_unmap: - vm_munmap(addr, obj->base.size); - return err; + if (unfaultable) + return 0; + + obj->flags &= ~I915_BO_ALLOC_GPU_ONLY; + return wc_check(obj); } #define IGT_MMAP_MIGRATE_TOPDOWN (1 << 0) @@ -1176,6 +1156,7 @@ static int __igt_mmap_migrate(struct intel_memory_region **placements, struct drm_i915_private *i915 = placements[0]->i915; struct drm_i915_gem_object *obj; struct i915_request *rq = NULL; + struct vm_area_struct *area; unsigned long addr; LIST_HEAD(objects); u64 offset; @@ -1207,20 +1188,30 @@ static int __igt_mmap_migrate(struct intel_memory_region **placements, goto out_put; } + mmap_read_lock(current->mm); + area = vma_lookup(current->mm, addr); + mmap_read_unlock(current->mm); + if (!area) { + pr_err("%s: Did not create a vm_area_struct for the mmap\n", + obj->mm.region->name); + err = -EINVAL; + goto out_addr; + } + if (flags & IGT_MMAP_MIGRATE_FILL) { err = igt_fill_mappable(placements[0], &objects); if (err) - goto out_put; + goto out_addr; } err = i915_gem_object_lock(obj, NULL); if (err) - goto out_put; + goto out_addr; err = i915_gem_object_pin_pages(obj); if (err) { i915_gem_object_unlock(obj); - goto out_put; + goto out_addr; } err = intel_context_migrate_clear(to_gt(i915)->migrate.context, NULL, @@ -1228,7 +1219,7 @@ static int __igt_mmap_migrate(struct intel_memory_region **placements, i915_gem_object_is_lmem(obj), expand32(POISON_INUSE), &rq); i915_gem_object_unpin_pages(obj); - if (rq) { + if (rq && !err) { err = dma_resv_reserve_fences(obj->base.resv, 1); if (!err) dma_resv_add_fence(obj->base.resv, &rq->fence, @@ -1237,7 +1228,7 @@ static int __igt_mmap_migrate(struct intel_memory_region **placements, } i915_gem_object_unlock(obj); if (err) - goto out_put; + goto out_addr; if (flags & IGT_MMAP_MIGRATE_EVICTABLE) igt_make_evictable(&objects); @@ -1245,16 +1236,16 @@ static int __igt_mmap_migrate(struct intel_memory_region **placements, if (flags & IGT_MMAP_MIGRATE_FAIL_GPU) { err = i915_gem_object_lock(obj, NULL); if (err) - goto out_put; + goto out_addr; /* - * Ensure we only simulate the gpu failuire when faulting the + * Ensure we only simulate the gpu failure when faulting the * pages. */ err = i915_gem_object_wait_moving_fence(obj, true); i915_gem_object_unlock(obj); if (err) - goto out_put; + goto out_addr; i915_ttm_migrate_set_failure_modes(true, false); } @@ -1298,6 +1289,9 @@ static int __igt_mmap_migrate(struct intel_memory_region **placements, } } +out_addr: + vm_munmap(addr, obj->base.size); + out_put: i915_gem_object_put(obj); igt_close_objects(i915, &objects); diff --git a/drivers/gpu/drm/i915/gt/gen2_engine_cs.c b/drivers/gpu/drm/i915/gt/gen2_engine_cs.c index 8116fd5987e2..8c01fb6d4e7b 100644 --- a/drivers/gpu/drm/i915/gt/gen2_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen2_engine_cs.c @@ -292,15 +292,15 @@ int gen4_emit_bb_start(struct i915_request *rq, void gen2_irq_enable(struct intel_engine_cs *engine) { - engine->i915->irq_mask &= ~engine->irq_enable_mask; - intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->irq_mask); + engine->i915->gen2_imr_mask &= ~engine->irq_enable_mask; + intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->gen2_imr_mask); intel_uncore_posting_read_fw(engine->uncore, GEN2_IMR); } void gen2_irq_disable(struct intel_engine_cs *engine) { - engine->i915->irq_mask |= engine->irq_enable_mask; - intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->irq_mask); + engine->i915->gen2_imr_mask |= engine->irq_enable_mask; + intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->gen2_imr_mask); } void gen5_irq_enable(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 98c7f6052069..10070ee4d74c 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -14,7 +14,6 @@ #include "i915_active_types.h" #include "i915_sw_fence.h" -#include "i915_utils.h" #include "intel_engine_types.h" #include "intel_sseu.h" #include "intel_wakeref.h" diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 03baa7fa0a27..7f389cb0bde4 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -106,14 +106,18 @@ * preemption, but just sampling the new tail pointer). * */ + #include <linux/interrupt.h> #include <linux/string_helpers.h> +#include "gen8_engine_cs.h" #include "i915_drv.h" +#include "i915_list_util.h" #include "i915_reg.h" +#include "i915_timer_util.h" #include "i915_trace.h" #include "i915_vgpu.h" -#include "gen8_engine_cs.h" +#include "i915_wait_util.h" #include "intel_breadcrumbs.h" #include "intel_context.h" #include "intel_engine_heartbeat.h" diff --git a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c index 86b5a9ba323d..c7befc5c20d0 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c @@ -7,6 +7,7 @@ #include "gem/i915_gem_object.h" #include "i915_drv.h" +#include "i915_list_util.h" #include "intel_engine_pm.h" #include "intel_gt_buffer_pool.h" diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c index 6c499692d61e..88b147fa5cb1 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c @@ -148,7 +148,7 @@ static u32 gen4_read_clock_frequency(struct intel_uncore *uncore) * * Testing on actual hardware has shown there is no /16. */ - return DIV_ROUND_CLOSEST(i9xx_fsb_freq(uncore->i915), 4) * 1000; + return DIV_ROUND_CLOSEST(intel_fsb_freq(uncore->i915), 4) * 1000; } static u32 read_clock_frequency(struct intel_uncore *uncore) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c index 4dc23b8d3aa2..dcd40b30a96b 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c @@ -82,14 +82,15 @@ static void gt_debugfs_register(struct intel_gt *gt, struct dentry *root) void intel_gt_debugfs_register(struct intel_gt *gt) { + struct dentry *debugfs_root = gt->i915->drm.debugfs_root; struct dentry *root; char gtname[4]; - if (!gt->i915->drm.primary->debugfs_root) + if (!debugfs_root) return; snprintf(gtname, sizeof(gtname), "gt%u", gt->info.id); - root = debugfs_create_dir(gtname, gt->i915->drm.primary->debugfs_root); + root = debugfs_create_dir(gtname, debugfs_root); if (IS_ERR(root)) return; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index a60822e2b5d4..c3afa321fe30 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -4,6 +4,7 @@ */ #include "i915_drv.h" +#include "i915_wait_util.h" #include "intel_gt.h" #include "intel_gt_mcr.h" #include "intel_gt_print.h" diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index 9ca42589da4d..932f9f1b06b2 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -6,6 +6,7 @@ #include <linux/pm_runtime.h> #include <linux/string_helpers.h> +#include "display/vlv_clock.h" #include "gem/i915_gem_region.h" #include "i915_drv.h" #include "i915_reg.h" @@ -341,7 +342,7 @@ static int vlv_rc6_init(struct intel_rc6 *rc6) return PTR_ERR(pctx); } - GEM_BUG_ON(range_overflows_end_t(u64, + GEM_BUG_ON(range_end_overflows_t(u64, i915->dsm.stolen.start, pctx->stolen->start, U32_MAX)); @@ -802,7 +803,7 @@ u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, enum intel_rc6_res_type id) /* On VLV and CHV, residency time is in CZ units rather than 1.28us */ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { mul = 1000000; - div = i915->czclk_freq; + div = vlv_clock_get_czclk(&i915->drm); overflow_hw = BIT_ULL(40); time_hw = vlv_residency_raw(uncore, reg); } else { diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 4a1675dea1c7..41b5036dc538 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -9,18 +9,17 @@ #include "display/intel_display_reset.h" #include "display/intel_overlay.h" - #include "gem/i915_gem_context.h" - #include "gt/intel_gt_regs.h" - #include "gt/uc/intel_gsc_fw.h" +#include "uc/intel_guc.h" #include "i915_drv.h" #include "i915_file_private.h" #include "i915_gpu_error.h" #include "i915_irq.h" #include "i915_reg.h" +#include "i915_wait_util.h" #include "intel_breadcrumbs.h" #include "intel_engine_pm.h" #include "intel_engine_regs.h" @@ -32,8 +31,6 @@ #include "intel_pci_config.h" #include "intel_reset.h" -#include "uc/intel_guc.h" - #define RESET_MAX_RETRIES 3 static void client_mark_guilty(struct i915_gem_context *ctx, bool banned) diff --git a/drivers/gpu/drm/i915/gt/intel_reset_types.h b/drivers/gpu/drm/i915/gt/intel_reset_types.h index 4f5fd393af6f..ee4eb574a219 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset_types.h +++ b/drivers/gpu/drm/i915/gt/intel_reset_types.h @@ -20,7 +20,7 @@ struct intel_reset { * FENCE registers). * * #I915_RESET_ENGINE[num_engines] - Since the driver doesn't need to - * acquire the struct_mutex to reset an engine, we need an explicit + * acquire a global lock to reset an engine, we need an explicit * flag to prevent two concurrent reset attempts in the same engine. * As the number of engines continues to grow, allocate the flags from * the most significant bits. diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c index 2a6d79abf25b..8314a4b0505e 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c @@ -15,18 +15,19 @@ #include "i915_irq.h" #include "i915_mitigations.h" #include "i915_reg.h" +#include "i915_wait_util.h" #include "intel_breadcrumbs.h" #include "intel_context.h" +#include "intel_engine_heartbeat.h" +#include "intel_engine_pm.h" #include "intel_engine_regs.h" #include "intel_gt.h" #include "intel_gt_irq.h" +#include "intel_gt_print.h" #include "intel_gt_regs.h" #include "intel_reset.h" #include "intel_ring.h" #include "shmem_utils.h" -#include "intel_engine_heartbeat.h" -#include "intel_engine_pm.h" -#include "intel_gt_print.h" /* Rough estimate of the typical request size, performing a flush, * set-context and then emitting the batch. diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 0b35fdd461d4..b01c837ab646 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -7,11 +7,14 @@ #include <drm/intel/i915_drm.h> -#include "display/intel_display.h" #include "display/intel_display_rps.h" +#include "display/vlv_clock.h" +#include "soc/intel_dram.h" + #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" +#include "i915_wait_util.h" #include "intel_breadcrumbs.h" #include "intel_gt.h" #include "intel_gt_clock_utils.h" @@ -276,20 +279,24 @@ static void gen5_rps_init(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); + unsigned int fsb_freq, mem_freq; u8 fmax, fmin, fstart; u32 rgvmodectl; int c_m, i; - if (i915->fsb_freq <= 3200000) + fsb_freq = intel_fsb_freq(i915); + mem_freq = intel_mem_freq(i915); + + if (fsb_freq <= 3200000) c_m = 0; - else if (i915->fsb_freq <= 4800000) + else if (fsb_freq <= 4800000) c_m = 1; else c_m = 2; for (i = 0; i < ARRAY_SIZE(cparams); i++) { if (cparams[i].i == c_m && - cparams[i].t == DIV_ROUND_CLOSEST(i915->mem_freq, 1000)) { + cparams[i].t == DIV_ROUND_CLOSEST(mem_freq, 1000)) { rps->ips.m = cparams[i].m; rps->ips.c = cparams[i].c; break; @@ -1683,10 +1690,7 @@ static void vlv_init_gpll_ref_freq(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); - rps->gpll_ref_freq = - vlv_get_cck_clock(&i915->drm, "GPLL ref", - CCK_GPLL_CLOCK_CONTROL, - i915->czclk_freq); + rps->gpll_ref_freq = vlv_clock_get_gpll(&i915->drm); drm_dbg(&i915->drm, "GPLL reference freq: %d kHz\n", rps->gpll_ref_freq); @@ -1696,13 +1700,13 @@ static void vlv_rps_init(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); + vlv_init_gpll_ref_freq(rps); + vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_PUNIT) | BIT(VLV_IOSF_SB_NC) | BIT(VLV_IOSF_SB_CCK)); - vlv_init_gpll_ref_freq(rps); - rps->max_freq = vlv_rps_max_freq(rps); rps->rp0_freq = rps->max_freq; drm_dbg(&i915->drm, "max GPU freq: %d MHz (%u)\n", @@ -1730,13 +1734,13 @@ static void chv_rps_init(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); + vlv_init_gpll_ref_freq(rps); + vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_PUNIT) | BIT(VLV_IOSF_SB_NC) | BIT(VLV_IOSF_SB_CCK)); - vlv_init_gpll_ref_freq(rps); - rps->max_freq = chv_rps_max_freq(rps); rps->rp0_freq = rps->max_freq; drm_dbg(&i915->drm, "max GPU freq: %d MHz (%u)\n", @@ -1773,6 +1777,7 @@ static void vlv_c0_read(struct intel_uncore *uncore, struct intel_rps_ei *ei) static u32 vlv_wa_c0_ei(struct intel_rps *rps, u32 pm_iir) { + struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); const struct intel_rps_ei *prev = &rps->ei; struct intel_rps_ei now; @@ -1789,7 +1794,7 @@ static u32 vlv_wa_c0_ei(struct intel_rps *rps, u32 pm_iir) time = ktime_us_delta(now.ktime, prev->ktime); - time *= rps_to_i915(rps)->czclk_freq; + time *= vlv_clock_get_czclk(&i915->drm); /* Workload can be split between render + media, * e.g. SwapBuffers being blitted in X after being rendered in diff --git a/drivers/gpu/drm/i915/gt/intel_timeline.h b/drivers/gpu/drm/i915/gt/intel_timeline.h index 57308c4d664a..85b43f9b9d95 100644 --- a/drivers/gpu/drm/i915/gt/intel_timeline.h +++ b/drivers/gpu/drm/i915/gt/intel_timeline.h @@ -9,6 +9,7 @@ #include <linux/lockdep.h> #include "i915_active.h" +#include "i915_list_util.h" #include "i915_syncmap.h" #include "intel_timeline_types.h" diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 5a95f06900b5..7d486dfa2fc1 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -337,12 +337,26 @@ static void gen6_ctx_workarounds_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { wa_masked_en(wal, INSTPM, INSTPM_FORCE_ORDERING); + + /* WaDisable_RenderCache_OperationalFlush:snb */ + wa_masked_dis(wal, CACHE_MODE_0, RC_OP_FLUSH_ENABLE); } static void gen7_ctx_workarounds_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { wa_masked_en(wal, INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisable_RenderCache_OperationalFlush:ivb,vlv,hsw */ + wa_masked_dis(wal, CACHE_MODE_0_GEN7, RC_OP_FLUSH_ENABLE); + + /* + * BSpec says this must be set, even though + * WaDisable4x2SubspanOptimization:ivb,hsw + * WaDisable4x2SubspanOptimization isn't listed for VLV. + */ + wa_masked_en(wal, + CACHE_MODE_1, + PIXEL_SUBSPAN_COLLECT_OPT_DISABLE); } static void gen8_ctx_workarounds_init(struct intel_engine_cs *engine, @@ -2567,18 +2581,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) RING_MODE_GEN7(RENDER_RING_BASE), GFX_TLB_INVALIDATE_EXPLICIT | GFX_REPLAY_MODE); - /* WaDisable_RenderCache_OperationalFlush:ivb,vlv,hsw */ - wa_masked_dis(wal, CACHE_MODE_0_GEN7, RC_OP_FLUSH_ENABLE); - - /* - * BSpec says this must be set, even though - * WaDisable4x2SubspanOptimization:ivb,hsw - * WaDisable4x2SubspanOptimization isn't listed for VLV. - */ - wa_masked_en(wal, - CACHE_MODE_1, - PIXEL_SUBSPAN_COLLECT_OPT_DISABLE); - /* * BSpec recommends 8x4 when MSAA is used, * however in practice 16x4 seems fastest. @@ -2645,9 +2647,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4); - /* WaDisable_RenderCache_OperationalFlush:snb */ - wa_masked_dis(wal, CACHE_MODE_0, RC_OP_FLUSH_ENABLE); - /* * From the Sandybridge PRM, volume 1 part 3, page 24: * "If this bit is set, STCunit will have LRA as replacement diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c index f057c16410e7..4f252f704975 100644 --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c @@ -904,7 +904,7 @@ static void active_engine(struct kthread_work *work) arg->result = PTR_ERR(ce[count]); pr_err("[%s] Create context #%ld failed: %d!\n", engine->name, count, arg->result); - while (--count) + while (count--) intel_context_put(ce[count]); return; } diff --git a/drivers/gpu/drm/i915/gt/selftest_tlb.c b/drivers/gpu/drm/i915/gt/selftest_tlb.c index 69ed946a39e5..a5184f09d1de 100644 --- a/drivers/gpu/drm/i915/gt/selftest_tlb.c +++ b/drivers/gpu/drm/i915/gt/selftest_tlb.c @@ -3,17 +3,17 @@ * Copyright © 2022 Intel Corporation */ -#include "i915_selftest.h" - #include "gem/i915_gem_internal.h" #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" #include "gen8_engine_cs.h" #include "i915_gem_ww.h" +#include "i915_selftest.h" +#include "i915_wait_util.h" +#include "intel_context.h" #include "intel_engine_regs.h" #include "intel_gpu_commands.h" -#include "intel_context.h" #include "intel_gt.h" #include "intel_ring.h" diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c index aab2759067d2..4a81bc396b21 100644 --- a/drivers/gpu/drm/i915/gt/sysfs_engines.c +++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c @@ -7,6 +7,7 @@ #include <linux/sysfs.h> #include "i915_drv.h" +#include "i915_timer_util.h" #include "intel_engine.h" #include "intel_engine_heartbeat.h" #include "sysfs_engines.h" diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c index d8edd7c054c8..e7444ebc373e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c @@ -10,11 +10,13 @@ #include "gt/intel_gt.h" #include "gt/intel_gt_print.h" + +#include "i915_drv.h" +#include "i915_reg.h" +#include "i915_wait_util.h" #include "intel_gsc_proxy.h" #include "intel_gsc_uc.h" #include "intel_gsc_uc_heci_cmd_submit.h" -#include "i915_drv.h" -#include "i915_reg.h" /* * GSC proxy: diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c index 2fde5c360cff..9bd29be7656f 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c @@ -8,6 +8,8 @@ #include "gt/intel_gpu_commands.h" #include "gt/intel_gt.h" #include "gt/intel_ring.h" + +#include "i915_wait_util.h" #include "intel_gsc_uc_heci_cmd_submit.h" struct gsc_heci_pkt { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index f360f020d8f1..52ec4421a211 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -8,15 +8,17 @@ #include "gt/intel_gt_irq.h" #include "gt/intel_gt_pm_irq.h" #include "gt/intel_gt_regs.h" + +#include "i915_drv.h" +#include "i915_irq.h" +#include "i915_reg.h" +#include "i915_wait_util.h" #include "intel_guc.h" #include "intel_guc_ads.h" #include "intel_guc_capture.h" #include "intel_guc_print.h" #include "intel_guc_slpc.h" #include "intel_guc_submission.h" -#include "i915_drv.h" -#include "i915_irq.h" -#include "i915_reg.h" /** * DOC: 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 0d5197c0824a..3e7e5badcc2b 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -5,15 +5,16 @@ #include <linux/circ_buf.h> #include <linux/ktime.h> -#include <linux/time64.h> #include <linux/string_helpers.h> +#include <linux/time64.h> #include <linux/timekeeping.h> #include "i915_drv.h" +#include "i915_wait_util.h" #include "intel_guc_ct.h" #include "intel_guc_print.h" -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GUC) +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) enum { CT_DEAD_ALIVE = 0, CT_DEAD_SETUP, @@ -144,7 +145,7 @@ void intel_guc_ct_init_early(struct intel_guc_ct *ct) spin_lock_init(&ct->requests.lock); INIT_LIST_HEAD(&ct->requests.pending); INIT_LIST_HEAD(&ct->requests.incoming); -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GUC) +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) INIT_WORK(&ct->dead_ct_worker, ct_dead_ct_worker_func); #endif INIT_WORK(&ct->requests.worker, ct_incoming_request_worker_func); @@ -373,7 +374,7 @@ int intel_guc_ct_enable(struct intel_guc_ct *ct) ct->enabled = true; ct->stall_time = KTIME_MAX; -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GUC) +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) ct->dead_ct_reported = false; ct->dead_ct_reason = CT_DEAD_ALIVE; #endif @@ -1377,7 +1378,7 @@ void intel_guc_ct_print_info(struct intel_guc_ct *ct, ct->ctbs.recv.desc->tail); } -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GUC) +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) static void ct_dead_ct_worker_func(struct work_struct *w) { struct intel_guc_ct *ct = container_of(w, struct intel_guc_ct, dead_ct_worker); @@ -1386,6 +1387,9 @@ static void ct_dead_ct_worker_func(struct work_struct *w) if (ct->dead_ct_reported) return; + if (i915_error_injected()) + return; + ct->dead_ct_reported = true; guc_info(guc, "CTB is dead - reason=0x%X\n", ct->dead_ct_reason); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h index 2c4bb9a941be..e9a6ec4e6d38 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h @@ -97,7 +97,7 @@ struct intel_guc_ct { /** @stall_time: time of first time a CTB submission is stalled */ ktime_t stall_time; -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GUC) +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) int dead_ct_reason; bool dead_ct_reported; struct work_struct dead_ct_worker; 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 e7ccfa520df3..b1bda1b84f0a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -13,9 +13,11 @@ #include "gt/intel_gt_mcr.h" #include "gt/intel_gt_regs.h" #include "gt/intel_rps.h" + +#include "i915_drv.h" +#include "i915_wait_util.h" #include "intel_guc_fw.h" #include "intel_guc_print.h" -#include "i915_drv.h" static void guc_prepare_xfer(struct intel_gt *gt) { @@ -46,6 +48,14 @@ static void guc_prepare_xfer(struct intel_gt *gt) /* allows for 5us (in 10ns units) before GT can go to RC6 */ intel_uncore_write(uncore, GUC_ARAT_C6DIS, 0x1FF); } + + /* + * Starting from IP 12.50 we need to enable the mirroring of GuC + * internal state to debug registers. This is always enabled on previous + * IPs. + */ + if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 50)) + intel_uncore_rmw(uncore, GUC_SHIM_CONTROL2, 0, GUC_ENABLE_DEBUG_REG); } static int guc_xfer_rsa_mmio(struct intel_uc_fw *guc_fw, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c index 09a64f224c49..cdff48920ee6 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -6,6 +6,8 @@ #include <linux/debugfs.h> #include <linux/string_helpers.h> +#include <drm/drm_managed.h> + #include "gt/intel_gt.h" #include "i915_drv.h" #include "i915_irq.h" @@ -511,7 +513,11 @@ static void guc_log_relay_unmap(struct intel_guc_log *log) void intel_guc_log_init_early(struct intel_guc_log *log) { - mutex_init(&log->relay.lock); + struct intel_guc *guc = log_to_guc(log); + struct drm_i915_private *i915 = guc_to_i915(guc); + + drmm_mutex_init(&i915->drm, &log->relay.lock); + drmm_mutex_init(&i915->drm, &log->guc_lock); INIT_WORK(&log->relay.flush_work, copy_debug_logs_work); log->relay.started = false; } @@ -677,7 +683,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level) if (level < GUC_LOG_LEVEL_DISABLED || level > GUC_LOG_LEVEL_MAX) return -EINVAL; - mutex_lock(&i915->drm.struct_mutex); + mutex_lock(&log->guc_lock); if (log->level == level) goto out_unlock; @@ -695,7 +701,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level) log->level = level; out_unlock: - mutex_unlock(&i915->drm.struct_mutex); + mutex_unlock(&log->guc_lock); return ret; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h index 02127703be80..13cb93ad0710 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h @@ -42,6 +42,14 @@ enum { struct intel_guc_log { u32 level; + /* + * Protects concurrent access and modification of intel_guc_log->level. + * + * This lock replaces the legacy struct_mutex usage in + * intel_guc_log system. + */ + struct mutex guc_lock; + /* Allocation settings */ struct { s32 bytes; /* Size in bytes */ 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 3fd798837502..f73dab527547 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h @@ -96,6 +96,7 @@ #define GUC_GEN10_SHIM_WC_ENABLE (1<<21) #define GUC_SHIM_CONTROL2 _MMIO(0xc068) +#define GUC_ENABLE_DEBUG_REG (1<<11) #define GUC_IS_PRIVILEGED (1<<29) #define GSC_LOADS_HUC (1<<30) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index d5ee6e5e1443..fa9af08f9708 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -3,17 +3,20 @@ * Copyright © 2021 Intel Corporation */ -#include <drm/drm_cache.h> #include <linux/string_helpers.h> +#include <drm/drm_cache.h> + +#include "gt/intel_gt.h" +#include "gt/intel_gt_regs.h" +#include "gt/intel_rps.h" + #include "i915_drv.h" #include "i915_reg.h" -#include "intel_guc_slpc.h" +#include "i915_wait_util.h" #include "intel_guc_print.h" +#include "intel_guc_slpc.h" #include "intel_mchbar_regs.h" -#include "gt/intel_gt.h" -#include "gt/intel_gt_regs.h" -#include "gt/intel_rps.h" /** * DOC: SLPC - Dynamic Frequency management diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 127316d2c8aa..68f2b8d363ac 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -25,16 +25,16 @@ #include "gt/intel_mocs.h" #include "gt/intel_ring.h" +#include "i915_drv.h" +#include "i915_irq.h" +#include "i915_reg.h" +#include "i915_trace.h" +#include "i915_wait_util.h" #include "intel_guc_ads.h" #include "intel_guc_capture.h" #include "intel_guc_print.h" #include "intel_guc_submission.h" -#include "i915_drv.h" -#include "i915_reg.h" -#include "i915_irq.h" -#include "i915_trace.h" - /** * DOC: GuC-based command submission * diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index a91e23c22ea1..d432fdd69833 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -1921,7 +1921,7 @@ static int perform_bb_shadow(struct parser_exec_state *s) if (!bb) return -ENOMEM; - bb->ppgtt = (s->buf_addr_type == GTT_BUFFER) ? false : true; + bb->ppgtt = s->buf_addr_type != GTT_BUFFER; /* * The start_offset stores the batch buffer's start gma's diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c index 673534f061ef..415422b5943c 100644 --- a/drivers/gpu/drm/i915/gvt/debugfs.c +++ b/drivers/gpu/drm/i915/gvt/debugfs.c @@ -194,9 +194,9 @@ void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu) void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu) { struct intel_gvt *gvt = vgpu->gvt; - struct drm_minor *minor = gvt->gt->i915->drm.primary; + struct dentry *debugfs_root = gvt->gt->i915->drm.debugfs_root; - if (minor->debugfs_root && gvt->debugfs_root) { + if (debugfs_root && gvt->debugfs_root) { debugfs_remove_recursive(vgpu->debugfs); vgpu->debugfs = NULL; } @@ -208,9 +208,9 @@ void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu) */ void intel_gvt_debugfs_init(struct intel_gvt *gvt) { - struct drm_minor *minor = gvt->gt->i915->drm.primary; + struct dentry *debugfs_root = gvt->gt->i915->drm.debugfs_root; - gvt->debugfs_root = debugfs_create_dir("gvt", minor->debugfs_root); + gvt->debugfs_root = debugfs_create_dir("gvt", debugfs_root); debugfs_create_ulong("num_tracked_mmio", 0444, gvt->debugfs_root, &gvt->mmio.num_tracked_mmio); @@ -222,9 +222,9 @@ void intel_gvt_debugfs_init(struct intel_gvt *gvt) */ void intel_gvt_debugfs_clean(struct intel_gvt *gvt) { - struct drm_minor *minor = gvt->gt->i915->drm.primary; + struct dentry *debugfs_root = gvt->gt->i915->drm.debugfs_root; - if (minor->debugfs_root) { + if (debugfs_root) { debugfs_remove_recursive(gvt->debugfs_root); gvt->debugfs_root = NULL; } diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index da1135fa7cda..db5cd65100fe 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -49,7 +49,7 @@ * @gpa: guest physical address * * Returns: - * Zero on success, negative error code if failed + * The MMIO offset of the given GPA */ int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) { @@ -58,7 +58,7 @@ int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) } #define reg_is_mmio(gvt, reg) \ - (reg >= 0 && reg < gvt->device_info.mmio_size) + (reg < gvt->device_info.mmio_size) #define reg_is_gtt(gvt, reg) \ (reg >= gvt->device_info.gtt_start_offset \ diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 2f7208843367..0b810baad20a 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -33,14 +33,16 @@ * */ -#include "i915_drv.h" -#include "i915_reg.h" #include "gt/intel_context.h" #include "gt/intel_engine_regs.h" #include "gt/intel_gpu_commands.h" #include "gt/intel_gt_regs.h" #include "gt/intel_ring.h" + #include "gvt.h" +#include "i915_drv.h" +#include "i915_reg.h" +#include "i915_wait_util.h" #include "trace.h" #define GEN9_MOCS_SIZE 64 diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c index 0dbc4e289300..6b0c1162505a 100644 --- a/drivers/gpu/drm/i915/i915_active.c +++ b/drivers/gpu/drm/i915/i915_active.c @@ -257,10 +257,9 @@ static struct active_node *__active_lookup(struct i915_active *ref, u64 idx) * claimed the cache and we know that is does not match our * idx. If, and only if, the timeline is currently zero is it * worth competing to claim it atomically for ourselves (for - * only the winner of that race will cmpxchg return the old - * value of 0). + * only the winner of that race will cmpxchg succeed). */ - if (!cached && !cmpxchg64(&it->timeline, 0, idx)) + if (!cached && try_cmpxchg64(&it->timeline, &cached, idx)) return it; } diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 967c0501e91e..c2e38d4bcd01 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -26,11 +26,11 @@ * */ +#include <linux/debugfs.h> #include <linux/sched/mm.h> #include <linux/sort.h> #include <linux/string_helpers.h> -#include <linux/debugfs.h> #include <drm/drm_debugfs.h> #include "gem/i915_gem_context.h" @@ -54,6 +54,7 @@ #include "i915_irq.h" #include "i915_reg.h" #include "i915_scheduler.h" +#include "i915_wait_util.h" #include "intel_mchbar_regs.h" static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node) @@ -720,26 +721,24 @@ static const struct i915_debugfs_files { {"i915_gem_drop_caches", &i915_drop_caches_fops}, }; -void i915_debugfs_register(struct drm_i915_private *dev_priv) +void i915_debugfs_register(struct drm_i915_private *i915) { - struct drm_minor *minor = dev_priv->drm.primary; + struct dentry *debugfs_root = i915->drm.debugfs_root; int i; - i915_debugfs_params(dev_priv); + i915_debugfs_params(i915); - debugfs_create_file("i915_forcewake_user", S_IRUSR, minor->debugfs_root, - to_i915(minor->dev), &i915_forcewake_fops); + debugfs_create_file("i915_forcewake_user", S_IRUSR, debugfs_root, + i915, &i915_forcewake_fops); for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) { - debugfs_create_file(i915_debugfs_files[i].name, - S_IRUGO | S_IWUSR, - minor->debugfs_root, - to_i915(minor->dev), + debugfs_create_file(i915_debugfs_files[i].name, S_IRUGO | S_IWUSR, + debugfs_root, i915, i915_debugfs_files[i].fops); } drm_debugfs_create_files(i915_debugfs_list, ARRAY_SIZE(i915_debugfs_list), - minor->debugfs_root, minor); + debugfs_root, i915->drm.primary); - i915_gpu_error_debugfs_register(dev_priv); + i915_gpu_error_debugfs_register(i915); } diff --git a/drivers/gpu/drm/i915/i915_debugfs_params.c b/drivers/gpu/drm/i915/i915_debugfs_params.c index 33d2dcb0de65..89ab5eb14779 100644 --- a/drivers/gpu/drm/i915/i915_debugfs_params.c +++ b/drivers/gpu/drm/i915/i915_debugfs_params.c @@ -248,11 +248,11 @@ i915_debugfs_create_charp(const char *name, umode_t mode, /* add a subdirectory with files for each i915 param */ struct dentry *i915_debugfs_params(struct drm_i915_private *i915) { - struct drm_minor *minor = i915->drm.primary; + struct dentry *debugfs_root = i915->drm.debugfs_root; struct i915_params *params = &i915->params; struct dentry *dir; - dir = debugfs_create_dir("i915_params", minor->debugfs_root); + dir = debugfs_create_dir("i915_params", debugfs_root); if (IS_ERR(dir)) return dir; diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index c6263c6d3384..95165e45de74 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -51,13 +51,15 @@ #include "display/intel_bw.h" #include "display/intel_cdclk.h" #include "display/intel_crtc.h" -#include "display/intel_display_core.h" +#include "display/intel_display_device.h" #include "display/intel_display_driver.h" +#include "display/intel_display_power.h" #include "display/intel_dmc.h" #include "display/intel_dp.h" #include "display/intel_dpt.h" #include "display/intel_encoder.h" #include "display/intel_fbdev.h" +#include "display/intel_gmbus.h" #include "display/intel_hotplug.h" #include "display/intel_opregion.h" #include "display/intel_overlay.h" @@ -977,7 +979,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_power_domains_disable(display); drm_client_dev_suspend(&i915->drm, false); - if (HAS_DISPLAY(i915)) { + if (intel_display_device_present(display)) { drm_kms_helper_poll_disable(&i915->drm); intel_display_driver_disable_user_access(display); @@ -989,7 +991,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_irq_suspend(i915); intel_hpd_cancel_work(display); - if (HAS_DISPLAY(i915)) + if (intel_display_device_present(display)) intel_display_driver_suspend_access(display); intel_encoder_suspend_all(display); @@ -1051,7 +1053,6 @@ static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_display *display = dev_priv->display; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); pci_power_t opregion_target_state; disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); @@ -1060,19 +1061,17 @@ static int i915_drm_suspend(struct drm_device *dev) * properly. */ intel_power_domains_disable(display); drm_client_dev_suspend(dev, false); - if (HAS_DISPLAY(dev_priv)) { + if (intel_display_device_present(display)) { drm_kms_helper_poll_disable(dev); intel_display_driver_disable_user_access(display); } - pci_save_state(pdev); - intel_display_driver_suspend(display); intel_irq_suspend(dev_priv); intel_hpd_cancel_work(display); - if (HAS_DISPLAY(dev_priv)) + if (intel_display_device_present(display)) intel_display_driver_suspend_access(display); intel_encoder_suspend_all(display); @@ -1101,7 +1100,6 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_display *display = dev_priv->display; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; struct intel_gt *gt; int ret, i; @@ -1122,11 +1120,21 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) if (ret) { drm_err(&dev_priv->drm, "Suspend complete failed: %d\n", ret); intel_display_power_resume_early(display); - - goto out; } - pci_disable_device(pdev); + enable_rpm_wakeref_asserts(rpm); + + if (!dev_priv->uncore.user_forcewake_count) + intel_runtime_pm_driver_release(rpm); + + return ret; +} + +static int i915_drm_suspend_noirq(struct drm_device *dev, bool hibernation) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + /* * During hibernation on some platforms the BIOS may try to access * the device even though it's already in D3 and hang the machine. So @@ -1138,21 +1146,20 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) * Lenovo Thinkpad X301, X61s, X60, T60, X41 * Fujitsu FSC S7110 * Acer Aspire 1830T + * + * pci_save_state() prevents drivers/pci from + * automagically putting the device into D3. */ - if (!(hibernation && GRAPHICS_VER(dev_priv) < 6)) - pci_set_power_state(pdev, PCI_D3hot); + if (hibernation && GRAPHICS_VER(dev_priv) < 6) + pci_save_state(pdev); -out: - enable_rpm_wakeref_asserts(rpm); - if (!dev_priv->uncore.user_forcewake_count) - intel_runtime_pm_driver_release(rpm); - - return ret; + return 0; } int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, pm_message_t state) { + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int error; if (drm_WARN_ON_ONCE(&i915->drm, state.event != PM_EVENT_SUSPEND && @@ -1166,7 +1173,14 @@ int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, if (error) return error; - return i915_drm_suspend_late(&i915->drm, false); + error = i915_drm_suspend_late(&i915->drm, false); + if (error) + return error; + + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; } static int i915_drm_resume(struct drm_device *dev) @@ -1219,7 +1233,7 @@ static int i915_drm_resume(struct drm_device *dev) */ intel_irq_resume(dev_priv); - if (HAS_DISPLAY(dev_priv)) + if (intel_display_device_present(display)) drm_mode_config_reset(dev); i915_gem_resume(dev_priv); @@ -1228,14 +1242,14 @@ static int i915_drm_resume(struct drm_device *dev) intel_clock_gating_init(dev_priv); - if (HAS_DISPLAY(dev_priv)) + if (intel_display_device_present(display)) intel_display_driver_resume_access(display); intel_hpd_init(display); intel_display_driver_resume(display); - if (HAS_DISPLAY(dev_priv)) { + if (intel_display_device_present(display)) { intel_display_driver_enable_user_access(display); drm_kms_helper_poll_enable(dev); } @@ -1258,7 +1272,6 @@ static int i915_drm_resume_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_display *display = dev_priv->display; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct intel_gt *gt; int ret, i; @@ -1272,41 +1285,6 @@ static int i915_drm_resume_early(struct drm_device *dev) * similar so that power domains can be employed. */ - /* - * Note that we need to set the power state explicitly, since we - * powered off the device during freeze and the PCI core won't power - * it back up for us during thaw. Powering off the device during - * freeze is not a hard requirement though, and during the - * suspend/resume phases the PCI core makes sure we get here with the - * device powered on. So in case we change our freeze logic and keep - * the device powered we can also remove the following set power state - * call. - */ - ret = pci_set_power_state(pdev, PCI_D0); - if (ret) { - drm_err(&dev_priv->drm, - "failed to set PCI D0 power state (%d)\n", ret); - return ret; - } - - /* - * Note that pci_enable_device() first enables any parent bridge - * device and only then sets the power state for this device. The - * bridge enabling is a nop though, since bridge devices are resumed - * first. The order of enabling power and enabling the device is - * imposed by the PCI core as described above, so here we preserve the - * same order for the freeze/thaw phases. - * - * TODO: eventually we should remove pci_disable_device() / - * pci_enable_enable_device() from suspend/resume. Due to how they - * depend on the device enable refcount we can't anyway depend on them - * disabling/enabling the device. - */ - if (pci_enable_device(pdev)) - return -EIO; - - pci_set_master(pdev); - disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); ret = vlv_resume_prepare(dev_priv, false); @@ -1326,11 +1304,18 @@ static int i915_drm_resume_early(struct drm_device *dev) int i915_driver_resume_switcheroo(struct drm_i915_private *i915) { + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int ret; if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + ret = pci_set_power_state(pdev, PCI_D0); + if (ret) + return ret; + + pci_restore_state(pdev); + ret = i915_drm_resume_early(&i915->drm); if (ret) return ret; @@ -1387,6 +1372,16 @@ static int i915_pm_suspend_late(struct device *kdev) return i915_drm_suspend_late(&i915->drm, false); } +static int i915_pm_suspend_noirq(struct device *kdev) +{ + struct drm_i915_private *i915 = kdev_to_i915(kdev); + + if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + return i915_drm_suspend_noirq(&i915->drm, false); +} + static int i915_pm_poweroff_late(struct device *kdev) { struct drm_i915_private *i915 = kdev_to_i915(kdev); @@ -1397,6 +1392,16 @@ static int i915_pm_poweroff_late(struct device *kdev) return i915_drm_suspend_late(&i915->drm, true); } +static int i915_pm_poweroff_noirq(struct device *kdev) +{ + struct drm_i915_private *i915 = kdev_to_i915(kdev); + + if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + return i915_drm_suspend_noirq(&i915->drm, true); +} + static int i915_pm_resume_early(struct device *kdev) { struct drm_i915_private *i915 = kdev_to_i915(kdev); @@ -1662,24 +1667,25 @@ const struct dev_pm_ops i915_pm_ops = { .prepare = i915_pm_prepare, .suspend = i915_pm_suspend, .suspend_late = i915_pm_suspend_late, + .suspend_noirq = i915_pm_suspend_noirq, .resume_early = i915_pm_resume_early, .resume = i915_pm_resume, .complete = i915_pm_complete, /* * S4 event handlers - * @freeze, @freeze_late : called (1) before creating the - * hibernation image [PMSG_FREEZE] and - * (2) after rebooting, before restoring - * the image [PMSG_QUIESCE] - * @thaw, @thaw_early : called (1) after creating the hibernation - * image, before writing it [PMSG_THAW] - * and (2) after failing to create or - * restore the image [PMSG_RECOVER] - * @poweroff, @poweroff_late: called after writing the hibernation - * image, before rebooting [PMSG_HIBERNATE] - * @restore, @restore_early : called after rebooting and restoring the - * hibernation image [PMSG_RESTORE] + * @freeze* : called (1) before creating the + * hibernation image [PMSG_FREEZE] and + * (2) after rebooting, before restoring + * the image [PMSG_QUIESCE] + * @thaw* : called (1) after creating the hibernation + * image, before writing it [PMSG_THAW] + * and (2) after failing to create or + * restore the image [PMSG_RECOVER] + * @poweroff* : called after writing the hibernation + * image, before rebooting [PMSG_HIBERNATE] + * @restore* : called after rebooting and restoring the + * hibernation image [PMSG_RESTORE] */ .freeze = i915_pm_freeze, .freeze_late = i915_pm_freeze_late, @@ -1687,6 +1693,7 @@ const struct dev_pm_ops i915_pm_ops = { .thaw = i915_pm_thaw, .poweroff = i915_pm_suspend, .poweroff_late = i915_pm_poweroff_late, + .poweroff_noirq = i915_pm_poweroff_noirq, .restore_early = i915_pm_restore_early, .restore = i915_pm_restore, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4e4e89746aa6..03e497d2081e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -114,8 +114,7 @@ struct i915_gem_mm { struct intel_memory_region *stolen_region; /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; - /** Protects the usage of the GTT stolen memory allocator. This is - * always the inner lock when overlapping with struct_mutex. */ + /** Protects the usage of the GTT stolen memory allocator */ struct mutex stolen_lock; /* Protects bound_list/unbound_list and #drm_i915_gem_object.mm.link */ @@ -222,6 +221,9 @@ struct drm_i915_private { bool irqs_enabled; + /* LPT/WPT IOSF sideband protection */ + struct mutex sbi_lock; + /* VLV/CHV IOSF sideband */ struct { struct mutex lock; /* protect sideband access */ @@ -232,16 +234,11 @@ struct drm_i915_private { /* Sideband mailbox protection */ struct mutex sb_lock; - /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 irq_mask; + /* Cached value of gen 2-4 IMR to avoid reads in updating the bitfield */ + u32 gen2_imr_mask; bool preserve_bios_swizzle; - unsigned int fsb_freq, mem_freq, is_ddr3; - - unsigned int hpll_freq; - unsigned int czclk_freq; - /** * wq - Driver workqueue for GEM. * diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8c8d43451f35..e14a0c3db999 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -847,8 +847,7 @@ void i915_gem_runtime_suspend(struct drm_i915_private *i915) /* * Only called during RPM suspend. All users of the userfault_list * must be holding an RPM wakeref to ensure that this can not - * run concurrently with themselves (and use the struct_mutex for - * protection between themselves). + * run concurrently with themselves. */ list_for_each_entry_safe(obj, on, diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 0e4b832dff84..7582ef34bf3f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -685,6 +685,74 @@ static void err_print_guc_ctb(struct drm_i915_error_state_buf *m, ctb->head, ctb->tail, ctb->desc_offset, ctb->cmds_offset, ctb->size); } +/* This list includes registers that are useful in debugging GuC hangs. */ +const struct { + u32 start; + u32 count; +} guc_hw_reg_state[] = { + { 0xc0b0, 2 }, + { 0xc000, 65 }, + { 0xc140, 1 }, + { 0xc180, 16 }, + { 0xc1dc, 10 }, + { 0xc300, 79 }, + { 0xc4b4, 47 }, + { 0xc574, 1 }, + { 0xc57c, 1 }, + { 0xc584, 11 }, + { 0xc5c0, 8 }, + { 0xc5e4, 1 }, + { 0xc5ec, 103 }, + { 0xc7c0, 1 }, + { 0xc0b0, 2 } +}; + +static u32 print_range_line(struct drm_i915_error_state_buf *m, u32 start, u32 *dump, u32 count) +{ + if (count >= 8) { + err_printf(m, "[0x%04x] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + start, dump[0], dump[1], dump[2], dump[3], + dump[4], dump[5], dump[6], dump[7]); + return 8; + } else if (count >= 4) { + err_printf(m, "[0x%04x] 0x%08x 0x%08x 0x%08x 0x%08x\n", + start, dump[0], dump[1], dump[2], dump[3]); + return 4; + } else if (count >= 2) { + err_printf(m, "[0x%04x] 0x%08x 0x%08x\n", start, dump[0], dump[1]); + return 2; + } + + err_printf(m, "[0x%04x] 0x%08x\n", start, dump[0]); + return 1; +} + +static void err_print_guc_hw_state(struct drm_i915_error_state_buf *m, u32 *hw_state) +{ + u32 total = 0; + int i; + + if (!hw_state) + return; + + err_printf(m, "GuC Register State:\n"); + + for (i = 0; i < ARRAY_SIZE(guc_hw_reg_state); i++) { + u32 entry = 0; + + while (entry < guc_hw_reg_state[i].count) { + u32 start = guc_hw_reg_state[i].start + entry * sizeof(u32); + u32 count = guc_hw_reg_state[i].count - entry; + u32 *values = hw_state + total + entry; + + entry += print_range_line(m, start, values, count); + } + + GEM_BUG_ON(entry != guc_hw_reg_state[i].count); + total += entry; + } +} + static void err_print_uc(struct drm_i915_error_state_buf *m, const struct intel_uc_coredump *error_uc) { @@ -693,6 +761,7 @@ static void err_print_uc(struct drm_i915_error_state_buf *m, intel_uc_fw_dump(&error_uc->guc_fw, &p); intel_uc_fw_dump(&error_uc->huc_fw, &p); err_printf(m, "GuC timestamp: 0x%08x\n", error_uc->guc.timestamp); + err_print_guc_hw_state(m, error_uc->guc.hw_state); intel_gpu_error_print_vma(m, NULL, error_uc->guc.vma_log); err_printf(m, "GuC CTB fence: %d\n", error_uc->guc.last_fence); err_print_guc_ctb(m, "Send", error_uc->guc.ctb + 0); @@ -1025,6 +1094,7 @@ static void cleanup_uc(struct intel_uc_coredump *uc) kfree(uc->huc_fw.file_wanted.path); i915_vma_coredump_free(uc->guc.vma_log); i915_vma_coredump_free(uc->guc.vma_ctb); + kfree(uc->guc.hw_state); kfree(uc); } @@ -1721,6 +1791,37 @@ static void gt_record_guc_ctb(struct intel_ctb_coredump *saved, saved->cmds_offset = ((void *)ctb->cmds) - blob_ptr; } +static u32 read_guc_state_reg(struct intel_uncore *uncore, int range, int count) +{ + GEM_BUG_ON(range >= ARRAY_SIZE(guc_hw_reg_state)); + GEM_BUG_ON(count >= guc_hw_reg_state[range].count); + + return intel_uncore_read(uncore, + _MMIO(guc_hw_reg_state[range].start + count * sizeof(u32))); +} + +static void gt_record_guc_hw_state(struct intel_uncore *uncore, + struct intel_uc_coredump *error_uc) +{ + u32 *hw_state; + u32 count = 0; + int i, j; + + for (i = 0; i < ARRAY_SIZE(guc_hw_reg_state); i++) + count += guc_hw_reg_state[i].count; + + hw_state = kcalloc(count, sizeof(u32), ALLOW_FAIL); + if (!hw_state) + return; + + count = 0; + for (i = 0; i < ARRAY_SIZE(guc_hw_reg_state); i++) + for (j = 0; j < guc_hw_reg_state[i].count; j++) + hw_state[count++] = read_guc_state_reg(uncore, i, j); + + error_uc->guc.hw_state = hw_state; +} + static struct intel_uc_coredump * gt_record_uc(struct intel_gt_coredump *gt, struct i915_vma_compress *compress) @@ -1755,6 +1856,7 @@ gt_record_uc(struct intel_gt_coredump *gt, uc->guc.ct.ctbs.send.desc, (struct intel_guc *)&uc->guc); gt_record_guc_ctb(error_uc->guc.ctb + 1, &uc->guc.ct.ctbs.recv, uc->guc.ct.ctbs.send.desc, (struct intel_guc *)&uc->guc); + gt_record_guc_hw_state(gt->_gt->uncore, error_uc); return error_uc; } @@ -2445,11 +2547,11 @@ static const struct file_operations i915_error_state_fops = { void i915_gpu_error_debugfs_register(struct drm_i915_private *i915) { - struct drm_minor *minor = i915->drm.primary; + struct dentry *debugfs_root = i915->drm.debugfs_root; - debugfs_create_file("i915_error_state", 0644, minor->debugfs_root, i915, + debugfs_create_file("i915_error_state", 0644, debugfs_root, i915, &i915_error_state_fops); - debugfs_create_file("i915_gpu_info", 0644, minor->debugfs_root, i915, + debugfs_create_file("i915_gpu_info", 0644, debugfs_root, i915, &i915_gpu_info_fops); } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 182324979278..91b3df621a49 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -177,6 +177,7 @@ struct intel_gt_coredump { struct intel_ctb_coredump ctb[2]; struct i915_vma_coredump *vma_ctb; struct i915_vma_coredump *vma_log; + u32 *hw_state; u32 timestamp; u16 last_fence; bool is_guc_capture; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 191ed8bb1d9c..11a727b74849 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -38,7 +38,6 @@ #include "display/intel_hotplug.h" #include "display/intel_hotplug_irq.h" #include "display/intel_lpe_audio.h" -#include "display/intel_psr_regs.h" #include "gt/intel_breadcrumbs.h" #include "gt/intel_gt.h" @@ -163,11 +162,6 @@ static void ivb_parity_work(struct work_struct *work) u32 misccpctl; u8 slice = 0; - /* We must turn off DOP level clock gating to access the L3 registers. - * In order to prevent a get/put style interface, acquire struct mutex - * any time we access those registers. - */ - mutex_lock(&dev_priv->drm.struct_mutex); /* If we've screwed up tracking, just let the interrupt fire again */ if (drm_WARN_ON(&dev_priv->drm, !dev_priv->l3_parity.which_slice)) @@ -225,7 +219,6 @@ out: gen5_gt_enable_irq(gt, GT_PARITY_ERROR(dev_priv)); spin_unlock_irq(gt->irq_lock); - mutex_unlock(&dev_priv->drm.struct_mutex); } static irqreturn_t valleyview_irq_handler(int irq, void *arg) @@ -421,7 +414,7 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) struct drm_i915_private *i915 = arg; struct intel_display *display = i915->display; void __iomem * const regs = intel_uncore_regs(&i915->uncore); - u32 de_iir, gt_iir, de_ier, sde_ier = 0; + u32 gt_iir, de_ier = 0, sde_ier = 0; irqreturn_t ret = IRQ_NONE; if (unlikely(!intel_irqs_enabled(i915))) @@ -430,19 +423,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) /* IRQs are synced during runtime_suspend, we don't require a wakeref */ disable_rpm_wakeref_asserts(&i915->runtime_pm); - /* disable master interrupt before clearing iir */ - de_ier = raw_reg_read(regs, DEIER); - raw_reg_write(regs, DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); - - /* Disable south interrupts. We'll only write to SDEIIR once, so further - * interrupts will will be stored on its back queue, and then we'll be - * able to process them after we restore SDEIER (as soon as we restore - * it, we'll get an interrupt if SDEIIR still has something to process - * due to its back queue). */ - if (!HAS_PCH_NOP(i915)) { - sde_ier = raw_reg_read(regs, SDEIER); - raw_reg_write(regs, SDEIER, 0); - } + /* Disable master and south interrupts */ + ilk_display_irq_master_disable(display, &de_ier, &sde_ier); /* Find, clear, then process each source of interrupt */ @@ -456,15 +438,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; } - de_iir = raw_reg_read(regs, DEIIR); - if (de_iir) { - raw_reg_write(regs, DEIIR, de_iir); - if (DISPLAY_VER(i915) >= 7) - ivb_display_irq_handler(display, de_iir); - else - ilk_display_irq_handler(display, de_iir); + if (ilk_display_irq_handler(display)) ret = IRQ_HANDLED; - } if (GRAPHICS_VER(i915) >= 6) { u32 pm_iir = raw_reg_read(regs, GEN6_PMIIR); @@ -475,9 +450,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) } } - raw_reg_write(regs, DEIER, de_ier); - if (sde_ier) - raw_reg_write(regs, SDEIER, sde_ier); + /* Re-enable master and south interrupts */ + ilk_display_irq_master_enable(display, de_ier, sde_ier); pmu_irq_stats(i915, ret); @@ -662,22 +636,10 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) static void ilk_irq_reset(struct drm_i915_private *dev_priv) { struct intel_display *display = dev_priv->display; - struct intel_uncore *uncore = &dev_priv->uncore; - - gen2_irq_reset(uncore, DE_IRQ_REGS); - dev_priv->irq_mask = ~0u; - - if (GRAPHICS_VER(dev_priv) == 7) - intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff); - - if (IS_HASWELL(dev_priv)) { - intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); - intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); - } + /* The master interrupt enable is in DEIER, reset display irq first */ + ilk_display_irq_reset(display); gen5_gt_irq_reset(to_gt(dev_priv)); - - ibx_display_irq_reset(display); } static void valleyview_irq_reset(struct drm_i915_private *dev_priv) @@ -834,6 +796,7 @@ static void cherryview_irq_postinstall(struct drm_i915_private *dev_priv) static u32 i9xx_error_mask(struct drm_i915_private *i915) { + struct intel_display *display = i915->display; /* * On gen2/3 FBC generates (seemingly spurious) * display INVALID_GTT/INVALID_GTT_PTE table errors. @@ -846,7 +809,7 @@ static u32 i9xx_error_mask(struct drm_i915_private *i915) * Unfortunately we can't mask off individual PGTBL_ER bits, * so we just have to mask off all page table errors via EMR. */ - if (HAS_FBC(i915)) + if (HAS_FBC(display)) return I915_ERROR_MEMORY_REFRESH; else return I915_ERROR_PAGE_TABLE | @@ -902,7 +865,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv) gen2_error_reset(uncore, GEN2_ERROR_REGS); gen2_irq_reset(uncore, GEN2_IRQ_REGS); - dev_priv->irq_mask = ~0u; + dev_priv->gen2_imr_mask = ~0u; } static void i915_irq_postinstall(struct drm_i915_private *dev_priv) @@ -913,28 +876,14 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i9xx_error_mask(dev_priv)); - dev_priv->irq_mask = - ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT); + enable_mask = i9xx_display_irq_enable_mask(display) | + I915_MASTER_ERROR_INTERRUPT; - enable_mask = - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; - - if (DISPLAY_VER(dev_priv) >= 3) { - dev_priv->irq_mask &= ~I915_ASLE_INTERRUPT; - enable_mask |= I915_ASLE_INTERRUPT; - } + dev_priv->gen2_imr_mask = ~enable_mask; - if (HAS_HOTPLUG(dev_priv)) { - dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; - enable_mask |= I915_DISPLAY_PORT_INTERRUPT; - } + enable_mask |= I915_USER_INTERRUPT; - gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->irq_mask, enable_mask); + gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->gen2_imr_mask, enable_mask); i915_display_irq_postinstall(display); } @@ -963,8 +912,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; - if (HAS_HOTPLUG(dev_priv) && - iir & I915_DISPLAY_PORT_INTERRUPT) + if (iir & I915_DISPLAY_PORT_INTERRUPT) hotplug_status = i9xx_hpd_irq_ack(display); /* Call regardless, as some status bits might not be @@ -1004,7 +952,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv) gen2_error_reset(uncore, GEN2_ERROR_REGS); gen2_irq_reset(uncore, GEN2_IRQ_REGS); - dev_priv->irq_mask = ~0u; + dev_priv->gen2_imr_mask = ~0u; } static u32 i965_error_mask(struct drm_i915_private *i915) @@ -1034,25 +982,17 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i965_error_mask(dev_priv)); - dev_priv->irq_mask = - ~(I915_ASLE_INTERRUPT | - I915_DISPLAY_PORT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT); - - enable_mask = - I915_ASLE_INTERRUPT | - I915_DISPLAY_PORT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; + enable_mask = i9xx_display_irq_enable_mask(display) | + I915_MASTER_ERROR_INTERRUPT; + + dev_priv->gen2_imr_mask = ~enable_mask; + + enable_mask |= I915_USER_INTERRUPT; if (IS_G4X(dev_priv)) enable_mask |= I915_BSD_USER_INTERRUPT; - gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->irq_mask, enable_mask); + gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->gen2_imr_mask, enable_mask); i965_display_irq_postinstall(display); } diff --git a/drivers/gpu/drm/i915/i915_list_util.h b/drivers/gpu/drm/i915/i915_list_util.h new file mode 100644 index 000000000000..4e515dc8a3e0 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_list_util.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __I915_LIST_UTIL_H__ +#define __I915_LIST_UTIL_H__ + +#include <linux/list.h> +#include <asm/rwonce.h> + +static inline void __list_del_many(struct list_head *head, + struct list_head *first) +{ + first->prev = head; + WRITE_ONCE(head->next, first); +} + +static inline int list_is_last_rcu(const struct list_head *list, + const struct list_head *head) +{ + return READ_ONCE(list->next) == head; +} + +#endif /* __I915_LIST_UTIL_H__ */ diff --git a/drivers/gpu/drm/i915/i915_ptr_util.h b/drivers/gpu/drm/i915/i915_ptr_util.h new file mode 100644 index 000000000000..9f8931d7d99b --- /dev/null +++ b/drivers/gpu/drm/i915/i915_ptr_util.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __I915_PTR_UTIL_H__ +#define __I915_PTR_UTIL_H__ + +#include <linux/types.h> + +#define ptr_mask_bits(ptr, n) ({ \ + unsigned long __v = (unsigned long)(ptr); \ + (typeof(ptr))(__v & -BIT(n)); \ +}) + +#define ptr_unmask_bits(ptr, n) ((unsigned long)(ptr) & (BIT(n) - 1)) + +#define ptr_unpack_bits(ptr, bits, n) ({ \ + unsigned long __v = (unsigned long)(ptr); \ + *(bits) = __v & (BIT(n) - 1); \ + (typeof(ptr))(__v & -BIT(n)); \ +}) + +#define ptr_pack_bits(ptr, bits, n) ({ \ + unsigned long __bits = (bits); \ + GEM_BUG_ON(__bits & -BIT(n)); \ + ((typeof(ptr))((unsigned long)(ptr) | __bits)); \ +}) + +#define ptr_dec(ptr) ({ \ + unsigned long __v = (unsigned long)(ptr); \ + (typeof(ptr))(__v - 1); \ +}) + +#define ptr_inc(ptr) ({ \ + unsigned long __v = (unsigned long)(ptr); \ + (typeof(ptr))(__v + 1); \ +}) + +#define page_mask_bits(ptr) ptr_mask_bits(ptr, PAGE_SHIFT) +#define page_unmask_bits(ptr) ptr_unmask_bits(ptr, PAGE_SHIFT) +#define page_pack_bits(ptr, bits) ptr_pack_bits(ptr, bits, PAGE_SHIFT) +#define page_unpack_bits(ptr, bits) ptr_unpack_bits(ptr, bits, PAGE_SHIFT) + +static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b) +{ + return a - b; +} + +#define u64_to_ptr(T, x) ({ \ + typecheck(u64, x); \ + (T *)(uintptr_t)(x); \ +}) + +/* + * container_of_user: Extract the superclass from a pointer to a member. + * + * Exactly like container_of() with the exception that it plays nicely + * with sparse for __user @ptr. + */ +#define container_of_user(ptr, type, member) ({ \ + void __user *__mptr = (void __user *)(ptr); \ + BUILD_BUG_ON_MSG(!__same_type(*(ptr), typeof_member(type, member)) && \ + !__same_type(*(ptr), void), \ + "pointer type mismatch in container_of()"); \ + ((type __user *)(__mptr - offsetof(type, member))); }) + +#endif /* __I915_PTR_UTIL_H__ */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 03b895897f60..354ef75ef6a5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -412,9 +412,9 @@ #define FW_BLC _MMIO(0x20d8) #define FW_BLC2 _MMIO(0x20dc) #define FW_BLC_SELF _MMIO(0x20e0) /* 915+ only */ -#define FW_BLC_SELF_EN_MASK (1 << 31) -#define FW_BLC_SELF_FIFO_MASK (1 << 16) /* 945 only */ -#define FW_BLC_SELF_EN (1 << 15) /* 945 only */ +#define FW_BLC_SELF_EN_MASK REG_BIT(31) +#define FW_BLC_SELF_FIFO_MASK REG_BIT(16) /* 945 only */ +#define FW_BLC_SELF_EN REG_BIT(15) /* 945 only */ #define MM_BURST_LENGTH 0x00700000 #define MM_FIFO_WATERMARK 0x0001F000 #define LM_BURST_LENGTH 0x00000700 @@ -613,7 +613,8 @@ #define DSTATE_GFX_CLOCK_GATING (1 << 1) #define DSTATE_DOT_CLOCK_GATING (1 << 0) -#define DSPCLK_GATE_D(__i915) _MMIO(DISPLAY_MMIO_BASE(__i915) + 0x6200) +#define DSPCLK_GATE_D _MMIO(0x6200) +#define VLV_DSPCLK_GATE_D _MMIO(VLV_DISPLAY_BASE + 0x6200) # define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ # define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ # define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */ diff --git a/drivers/gpu/drm/i915/i915_reg_defs.h b/drivers/gpu/drm/i915/i915_reg_defs.h index bfe98cb9a038..e81fac8ab51b 100644 --- a/drivers/gpu/drm/i915/i915_reg_defs.h +++ b/drivers/gpu/drm/i915/i915_reg_defs.h @@ -174,6 +174,16 @@ */ #define REG_FIELD_GET8(__mask, __val) ((u8)FIELD_GET(__mask, __val)) +/** + * REG_FIELD_MAX() - produce the maximum value representable by a field + * @__mask: shifted mask defining the field's length and position + * + * Local wrapper for FIELD_MAX() to return the maximum bit value that can + * be held in the field specified by @_mask, cast to u32 for consistency + * with other macros. + */ +#define REG_FIELD_MAX(__mask) ((u32)FIELD_MAX(__mask)) + typedef struct { u32 reg; } i915_reg_t; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 5f7e8138ec14..b09135301f39 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -31,19 +31,20 @@ #include <linux/llist.h> #include <linux/lockdep.h> +#include <uapi/drm/i915_drm.h> + #include "gem/i915_gem_context_types.h" #include "gt/intel_context_types.h" #include "gt/intel_engine_types.h" #include "gt/intel_timeline_types.h" #include "i915_gem.h" +#include "i915_ptr_util.h" #include "i915_scheduler.h" #include "i915_selftest.h" #include "i915_sw_fence.h" #include "i915_vma_resource.h" -#include <uapi/drm/i915_drm.h> - struct drm_file; struct drm_i915_gem_object; struct drm_printer; diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c index 4c02a04be681..d5b6d8ab31a2 100644 --- a/drivers/gpu/drm/i915/i915_switcheroo.c +++ b/drivers/gpu/drm/i915/i915_switcheroo.c @@ -5,7 +5,7 @@ #include <linux/vga_switcheroo.h> -#include "display/intel_display_core.h" +#include "display/intel_display_device.h" #include "i915_driver.h" #include "i915_drv.h" @@ -15,13 +15,14 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { struct drm_i915_private *i915 = pdev_to_i915(pdev); + struct intel_display *display = i915 ? i915->display : NULL; pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (!i915) { dev_err(&pdev->dev, "DRM not initialized, aborting switch.\n"); return; } - if (!HAS_DISPLAY(i915)) { + if (!intel_display_device_present(display)) { dev_err(&pdev->dev, "Device state not initialized, aborting switch.\n"); return; } @@ -44,13 +45,15 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, static bool i915_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_i915_private *i915 = pdev_to_i915(pdev); + struct intel_display *display = i915 ? i915->display : NULL; /* * FIXME: open_count is protected by drm_global_mutex but that would lead to * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now. */ - return i915 && HAS_DISPLAY(i915) && atomic_read(&i915->drm.open_count) == 0; + return i915 && intel_display_device_present(display) && + atomic_read(&i915->drm.open_count) == 0; } static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { diff --git a/drivers/gpu/drm/i915/i915_timer_util.c b/drivers/gpu/drm/i915/i915_timer_util.c new file mode 100644 index 000000000000..ee4cfd8b3c07 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_timer_util.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2025 Intel Corporation */ + +#include <linux/jiffies.h> + +#include "i915_timer_util.h" + +void cancel_timer(struct timer_list *t) +{ + if (!timer_active(t)) + return; + + timer_delete(t); + WRITE_ONCE(t->expires, 0); +} + +void set_timer_ms(struct timer_list *t, unsigned long timeout) +{ + if (!timeout) { + cancel_timer(t); + return; + } + + timeout = msecs_to_jiffies(timeout); + + /* + * Paranoia to make sure the compiler computes the timeout before + * loading 'jiffies' as jiffies is volatile and may be updated in + * the background by a timer tick. All to reduce the complexity + * of the addition and reduce the risk of losing a jiffy. + */ + barrier(); + + /* Keep t->expires = 0 reserved to indicate a canceled timer. */ + mod_timer(t, jiffies + timeout ?: 1); +} diff --git a/drivers/gpu/drm/i915/i915_timer_util.h b/drivers/gpu/drm/i915/i915_timer_util.h new file mode 100644 index 000000000000..f35ad730820c --- /dev/null +++ b/drivers/gpu/drm/i915/i915_timer_util.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __I915_TIMER_UTIL_H__ +#define __I915_TIMER_UTIL_H__ + +#include <linux/timer.h> +#include <asm/rwonce.h> + +void cancel_timer(struct timer_list *t); +void set_timer_ms(struct timer_list *t, unsigned long timeout); + +static inline bool timer_active(const struct timer_list *t) +{ + return READ_ONCE(t->expires); +} + +static inline bool timer_expired(const struct timer_list *t) +{ + return timer_active(t) && !timer_pending(t); +} + +#endif /* __I915_TIMER_UTIL_H__ */ diff --git a/drivers/gpu/drm/i915/i915_utils.c b/drivers/gpu/drm/i915/i915_utils.c index b60c28fbd207..49f7ed413132 100644 --- a/drivers/gpu/drm/i915/i915_utils.c +++ b/drivers/gpu/drm/i915/i915_utils.c @@ -47,36 +47,6 @@ bool i915_error_injected(void) #endif -void cancel_timer(struct timer_list *t) -{ - if (!timer_active(t)) - return; - - timer_delete(t); - WRITE_ONCE(t->expires, 0); -} - -void set_timer_ms(struct timer_list *t, unsigned long timeout) -{ - if (!timeout) { - cancel_timer(t); - return; - } - - timeout = msecs_to_jiffies(timeout); - - /* - * Paranoia to make sure the compiler computes the timeout before - * loading 'jiffies' as jiffies is volatile and may be updated in - * the background by a timer tick. All to reduce the complexity - * of the addition and reduce the risk of losing a jiffy. - */ - barrier(); - - /* Keep t->expires = 0 reserved to indicate a canceled timer. */ - mod_timer(t, jiffies + timeout ?: 1); -} - bool i915_vtd_active(struct drm_i915_private *i915) { if (device_iommu_mapped(i915->drm.dev)) diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index f7fb40cfdb70..a0c892e4c40d 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -25,7 +25,6 @@ #ifndef __I915_UTILS_H #define __I915_UTILS_H -#include <linux/list.h> #include <linux/overflow.h> #include <linux/sched.h> #include <linux/string_helpers.h> @@ -38,7 +37,6 @@ #endif struct drm_i915_private; -struct timer_list; #define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ __stringify(x), (long)(x)) @@ -67,88 +65,12 @@ bool i915_error_injected(void); drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \ }) -#define range_overflows(start, size, max) ({ \ - typeof(start) start__ = (start); \ - typeof(size) size__ = (size); \ - typeof(max) max__ = (max); \ - (void)(&start__ == &size__); \ - (void)(&start__ == &max__); \ - start__ >= max__ || size__ > max__ - start__; \ -}) - -#define range_overflows_t(type, start, size, max) \ - range_overflows((type)(start), (type)(size), (type)(max)) - -#define range_overflows_end(start, size, max) ({ \ - typeof(start) start__ = (start); \ - typeof(size) size__ = (size); \ - typeof(max) max__ = (max); \ - (void)(&start__ == &size__); \ - (void)(&start__ == &max__); \ - start__ > max__ || size__ > max__ - start__; \ -}) - -#define range_overflows_end_t(type, start, size, max) \ - range_overflows_end((type)(start), (type)(size), (type)(max)) - -#define ptr_mask_bits(ptr, n) ({ \ - unsigned long __v = (unsigned long)(ptr); \ - (typeof(ptr))(__v & -BIT(n)); \ -}) - -#define ptr_unmask_bits(ptr, n) ((unsigned long)(ptr) & (BIT(n) - 1)) - -#define ptr_unpack_bits(ptr, bits, n) ({ \ - unsigned long __v = (unsigned long)(ptr); \ - *(bits) = __v & (BIT(n) - 1); \ - (typeof(ptr))(__v & -BIT(n)); \ -}) - -#define ptr_pack_bits(ptr, bits, n) ({ \ - unsigned long __bits = (bits); \ - GEM_BUG_ON(__bits & -BIT(n)); \ - ((typeof(ptr))((unsigned long)(ptr) | __bits)); \ -}) - -#define ptr_dec(ptr) ({ \ - unsigned long __v = (unsigned long)(ptr); \ - (typeof(ptr))(__v - 1); \ -}) - -#define ptr_inc(ptr) ({ \ - unsigned long __v = (unsigned long)(ptr); \ - (typeof(ptr))(__v + 1); \ -}) - -#define page_mask_bits(ptr) ptr_mask_bits(ptr, PAGE_SHIFT) -#define page_unmask_bits(ptr) ptr_unmask_bits(ptr, PAGE_SHIFT) -#define page_pack_bits(ptr, bits) ptr_pack_bits(ptr, bits, PAGE_SHIFT) -#define page_unpack_bits(ptr, bits) ptr_unpack_bits(ptr, bits, PAGE_SHIFT) - #define fetch_and_zero(ptr) ({ \ typeof(*ptr) __T = *(ptr); \ *(ptr) = (typeof(*ptr))0; \ __T; \ }) -static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b) -{ - return a - b; -} - -/* - * container_of_user: Extract the superclass from a pointer to a member. - * - * Exactly like container_of() with the exception that it plays nicely - * with sparse for __user @ptr. - */ -#define container_of_user(ptr, type, member) ({ \ - void __user *__mptr = (void __user *)(ptr); \ - BUILD_BUG_ON_MSG(!__same_type(*(ptr), typeof_member(type, member)) && \ - !__same_type(*(ptr), void), \ - "pointer type mismatch in container_of()"); \ - ((type __user *)(__mptr - offsetof(type, member))); }) - /* * check_user_mbz: Check that a user value exists and is zero * @@ -167,11 +89,6 @@ static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b) get_user(mbz__, (U)) ? -EFAULT : mbz__ ? -EINVAL : 0; \ }) -#define u64_to_ptr(T, x) ({ \ - typecheck(u64, x); \ - (T *)(uintptr_t)(x); \ -}) - #define __mask_next_bit(mask) ({ \ int __idx = ffs(mask) - 1; \ mask &= ~BIT(__idx); \ @@ -183,19 +100,6 @@ static inline bool is_power_of_2_u64(u64 n) return (n != 0 && ((n & (n - 1)) == 0)); } -static inline void __list_del_many(struct list_head *head, - struct list_head *first) -{ - first->prev = head; - WRITE_ONCE(head->next, first); -} - -static inline int list_is_last_rcu(const struct list_head *list, - const struct list_head *head) -{ - return READ_ONCE(list->next) == head; -} - static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m) { unsigned long j = msecs_to_jiffies(m); @@ -230,107 +134,6 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) } } -/* - * __wait_for - magic wait macro - * - * Macro to help avoid open coding check/wait/timeout patterns. Note that it's - * important that we check the condition again after having timed out, since the - * timeout could be due to preemption or similar and we've never had a chance to - * check the condition before the timeout. - */ -#define __wait_for(OP, COND, US, Wmin, Wmax) ({ \ - const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll * (US)); \ - long wait__ = (Wmin); /* recommended min for usleep is 10 us */ \ - int ret__; \ - might_sleep(); \ - for (;;) { \ - const bool expired__ = ktime_after(ktime_get_raw(), end__); \ - OP; \ - /* Guarantee COND check prior to timeout */ \ - barrier(); \ - if (COND) { \ - ret__ = 0; \ - break; \ - } \ - if (expired__) { \ - ret__ = -ETIMEDOUT; \ - break; \ - } \ - usleep_range(wait__, wait__ * 2); \ - if (wait__ < (Wmax)) \ - wait__ <<= 1; \ - } \ - ret__; \ -}) - -#define _wait_for(COND, US, Wmin, Wmax) __wait_for(, (COND), (US), (Wmin), \ - (Wmax)) -#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) - -/* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) && IS_ENABLED(CONFIG_PREEMPT_COUNT) -# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic()) -#else -# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0) -#endif - -#define _wait_for_atomic(COND, US, ATOMIC) \ -({ \ - int cpu, ret, timeout = (US) * 1000; \ - u64 base; \ - _WAIT_FOR_ATOMIC_CHECK(ATOMIC); \ - if (!(ATOMIC)) { \ - preempt_disable(); \ - cpu = smp_processor_id(); \ - } \ - base = local_clock(); \ - for (;;) { \ - u64 now = local_clock(); \ - if (!(ATOMIC)) \ - preempt_enable(); \ - /* Guarantee COND check prior to timeout */ \ - barrier(); \ - if (COND) { \ - ret = 0; \ - break; \ - } \ - if (now - base >= timeout) { \ - ret = -ETIMEDOUT; \ - break; \ - } \ - cpu_relax(); \ - if (!(ATOMIC)) { \ - preempt_disable(); \ - if (unlikely(cpu != smp_processor_id())) { \ - timeout -= now - base; \ - cpu = smp_processor_id(); \ - base = local_clock(); \ - } \ - } \ - } \ - ret; \ -}) - -#define wait_for_us(COND, US) \ -({ \ - int ret__; \ - BUILD_BUG_ON(!__builtin_constant_p(US)); \ - if ((US) > 10) \ - ret__ = _wait_for((COND), (US), 10, 10); \ - else \ - ret__ = _wait_for_atomic((COND), (US), 0); \ - ret__; \ -}) - -#define wait_for_atomic_us(COND, US) \ -({ \ - BUILD_BUG_ON(!__builtin_constant_p(US)); \ - BUILD_BUG_ON((US) > 50000); \ - _wait_for_atomic((COND), (US), 1); \ -}) - -#define wait_for_atomic(COND, MS) wait_for_atomic_us((COND), (MS) * 1000) - #define KHz(x) (1000 * (x)) #define MHz(x) KHz(1000 * (x)) @@ -346,19 +149,6 @@ static inline void __add_taint_for_CI(unsigned int taint) add_taint(taint, LOCKDEP_STILL_OK); } -void cancel_timer(struct timer_list *t); -void set_timer_ms(struct timer_list *t, unsigned long timeout); - -static inline bool timer_active(const struct timer_list *t) -{ - return READ_ONCE(t->expires); -} - -static inline bool timer_expired(const struct timer_list *t) -{ - return timer_active(t) && !timer_pending(t); -} - static inline bool i915_run_as_guest(void) { #if IS_ENABLED(CONFIG_X86) diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index 0f9eee6d18d2..8054047840aa 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -30,12 +30,12 @@ #include <drm/drm_mm.h> -#include "gt/intel_ggtt_fencing.h" #include "gem/i915_gem_object.h" - -#include "i915_gem_gtt.h" +#include "gt/intel_ggtt_fencing.h" #include "i915_active.h" +#include "i915_gem_gtt.h" +#include "i915_ptr_util.h" #include "i915_request.h" #include "i915_vma_resource.h" #include "i915_vma_types.h" diff --git a/drivers/gpu/drm/i915/i915_wait_util.h b/drivers/gpu/drm/i915/i915_wait_util.h new file mode 100644 index 000000000000..7376898e3bf8 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_wait_util.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __I915_WAIT_UTIL_H__ +#define __I915_WAIT_UTIL_H__ + +#include <linux/compiler.h> +#include <linux/delay.h> +#include <linux/ktime.h> +#include <linux/sched/clock.h> +#include <linux/smp.h> + +/* + * __wait_for - magic wait macro + * + * Macro to help avoid open coding check/wait/timeout patterns. Note that it's + * important that we check the condition again after having timed out, since the + * timeout could be due to preemption or similar and we've never had a chance to + * check the condition before the timeout. + */ +#define __wait_for(OP, COND, US, Wmin, Wmax) ({ \ + const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll * (US)); \ + long wait__ = (Wmin); /* recommended min for usleep is 10 us */ \ + int ret__; \ + might_sleep(); \ + for (;;) { \ + const bool expired__ = ktime_after(ktime_get_raw(), end__); \ + OP; \ + /* Guarantee COND check prior to timeout */ \ + barrier(); \ + if (COND) { \ + ret__ = 0; \ + break; \ + } \ + if (expired__) { \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + usleep_range(wait__, wait__ * 2); \ + if (wait__ < (Wmax)) \ + wait__ <<= 1; \ + } \ + ret__; \ +}) + +#define _wait_for(COND, US, Wmin, Wmax) __wait_for(, (COND), (US), (Wmin), \ + (Wmax)) +#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) + +/* + * If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. + * On PREEMPT_RT the context isn't becoming atomic because it is used in an + * interrupt handler or because a spinlock_t is acquired. This leads to + * warnings which don't occur otherwise and therefore the check is disabled. + */ +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) && IS_ENABLED(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT) +# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic()) +#else +# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0) +#endif + +#define _wait_for_atomic(COND, US, ATOMIC) \ +({ \ + int cpu, ret, timeout = (US) * 1000; \ + u64 base; \ + _WAIT_FOR_ATOMIC_CHECK(ATOMIC); \ + if (!(ATOMIC)) { \ + preempt_disable(); \ + cpu = smp_processor_id(); \ + } \ + base = local_clock(); \ + for (;;) { \ + u64 now = local_clock(); \ + if (!(ATOMIC)) \ + preempt_enable(); \ + /* Guarantee COND check prior to timeout */ \ + barrier(); \ + if (COND) { \ + ret = 0; \ + break; \ + } \ + if (now - base >= timeout) { \ + ret = -ETIMEDOUT; \ + break; \ + } \ + cpu_relax(); \ + if (!(ATOMIC)) { \ + preempt_disable(); \ + if (unlikely(cpu != smp_processor_id())) { \ + timeout -= now - base; \ + cpu = smp_processor_id(); \ + base = local_clock(); \ + } \ + } \ + } \ + ret; \ +}) + +#define wait_for_us(COND, US) \ +({ \ + int ret__; \ + BUILD_BUG_ON(!__builtin_constant_p(US)); \ + if ((US) > 10) \ + ret__ = _wait_for((COND), (US), 10, 10); \ + else \ + ret__ = _wait_for_atomic((COND), (US), 0); \ + ret__; \ +}) + +#define wait_for_atomic_us(COND, US) \ +({ \ + BUILD_BUG_ON(!__builtin_constant_p(US)); \ + BUILD_BUG_ON((US) > 50000); \ + _wait_for_atomic((COND), (US), 1); \ +}) + +#define wait_for_atomic(COND, MS) wait_for_atomic_us((COND), (MS) * 1000) + +#endif /* __I915_WAIT_UTIL_H__ */ diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c index f86a3629ae9e..467740969431 100644 --- a/drivers/gpu/drm/i915/intel_clock_gating.c +++ b/drivers/gpu/drm/i915/intel_clock_gating.c @@ -132,16 +132,17 @@ static void ibx_init_clock_gating(struct drm_i915_private *i915) static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv) { + struct intel_display *display = dev_priv->display; enum pipe pipe; - for_each_pipe(dev_priv, pipe) { - intel_uncore_rmw(&dev_priv->uncore, DSPCNTR(dev_priv, pipe), + for_each_pipe(display, pipe) { + intel_uncore_rmw(&dev_priv->uncore, DSPCNTR(display, pipe), 0, DISP_TRICKLE_FEED_DISABLE); - intel_uncore_rmw(&dev_priv->uncore, DSPSURF(dev_priv, pipe), + intel_uncore_rmw(&dev_priv->uncore, DSPSURF(display, pipe), 0, 0); intel_uncore_posting_read(&dev_priv->uncore, - DSPSURF(dev_priv, pipe)); + DSPSURF(display, pipe)); } } @@ -218,7 +219,7 @@ static void cpt_init_clock_gating(struct drm_i915_private *i915) /* The below fixes the weird display corruption, a few pixels shifted * downward, on (only) LVDS of some HP laptops with IVY. */ - for_each_pipe(i915, pipe) { + for_each_pipe(display, pipe) { val = intel_uncore_read(&i915->uncore, TRANS_CHICKEN2(pipe)); val |= TRANS_CHICKEN2_TIMING_OVERRIDE; val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; @@ -229,7 +230,7 @@ static void cpt_init_clock_gating(struct drm_i915_private *i915) intel_uncore_write(&i915->uncore, TRANS_CHICKEN2(pipe), val); } /* WADP0ClockGatingDisable */ - for_each_pipe(i915, pipe) { + for_each_pipe(display, pipe) { intel_uncore_write(&i915->uncore, TRANS_CHICKEN1(pipe), TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); } @@ -307,11 +308,13 @@ static void gen6_init_clock_gating(struct drm_i915_private *i915) static void lpt_init_clock_gating(struct drm_i915_private *i915) { + struct intel_display *display = i915->display; + /* * TODO: this bit should only be enabled when really needed, then * disabled when not needed anymore in order to save power. */ - if (HAS_PCH_LPT_LP(i915)) + if (HAS_PCH_LPT_LP(display)) intel_uncore_rmw(&i915->uncore, SOUTH_DSPCLK_GATE_D, 0, PCH_LP_PARTITION_LEVEL_DISABLE); @@ -355,7 +358,9 @@ static void dg2_init_clock_gating(struct drm_i915_private *i915) static void cnp_init_clock_gating(struct drm_i915_private *i915) { - if (!HAS_PCH_CNP(i915)) + struct intel_display *display = i915->display; + + if (!HAS_PCH_CNP(display)) return; /* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */ @@ -421,6 +426,7 @@ static void skl_init_clock_gating(struct drm_i915_private *i915) static void bdw_init_clock_gating(struct drm_i915_private *i915) { + struct intel_display *display = i915->display; enum pipe pipe; /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ @@ -432,7 +438,7 @@ static void bdw_init_clock_gating(struct drm_i915_private *i915) /* WaPsrDPAMaskVBlankInSRD:bdw */ intel_uncore_rmw(&i915->uncore, CHICKEN_PAR1_1, 0, HSW_MASK_VBL_TO_PIPE_IN_SRD); - for_each_pipe(i915, pipe) { + for_each_pipe(display, pipe) { /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ intel_uncore_rmw(&i915->uncore, CHICKEN_PIPESL_1(pipe), 0, BDW_UNMASK_VBL_TO_REGS_IN_SRD); @@ -468,6 +474,7 @@ static void bdw_init_clock_gating(struct drm_i915_private *i915) static void hsw_init_clock_gating(struct drm_i915_private *i915) { + struct intel_display *display = i915->display; enum pipe pipe; /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ @@ -476,7 +483,7 @@ static void hsw_init_clock_gating(struct drm_i915_private *i915) /* WaPsrDPAMaskVBlankInSRD:hsw */ intel_uncore_rmw(&i915->uncore, CHICKEN_PAR1_1, 0, HSW_MASK_VBL_TO_PIPE_IN_SRD); - for_each_pipe(i915, pipe) { + for_each_pipe(display, pipe) { /* WaPsrDPRSUnmaskVBlankInSRD:hsw */ intel_uncore_rmw(&i915->uncore, CHICKEN_PIPESL_1(pipe), 0, HSW_UNMASK_VBL_TO_REGS_IN_SRD); @@ -494,6 +501,8 @@ static void hsw_init_clock_gating(struct drm_i915_private *i915) static void ivb_init_clock_gating(struct drm_i915_private *i915) { + struct intel_display *display = i915->display; + intel_uncore_write(&i915->uncore, ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); /* WaFbcAsynchFlipDisableFbcQueue:ivb */ @@ -531,7 +540,7 @@ static void ivb_init_clock_gating(struct drm_i915_private *i915) intel_uncore_rmw(&i915->uncore, GEN6_MBCUNIT_SNPCR, GEN6_MBC_SNPCR_MASK, GEN6_MBC_SNPCR_MED); - if (!HAS_PCH_NOP(i915)) + if (!HAS_PCH_NOP(display)) cpt_init_clock_gating(i915); gen6_check_mch_setup(i915); @@ -611,7 +620,7 @@ static void g4x_init_clock_gating(struct drm_i915_private *i915) OVCUNIT_CLOCK_GATE_DISABLE; if (IS_GM45(i915)) dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; - intel_uncore_write(&i915->uncore, DSPCLK_GATE_D(i915), dspclk_gate); + intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, dspclk_gate); g4x_disable_trickle_feed(i915); } @@ -622,7 +631,7 @@ static void i965gm_init_clock_gating(struct drm_i915_private *i915) intel_uncore_write(uncore, RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); intel_uncore_write(uncore, RENCLK_GATE_D2, 0); - intel_uncore_write(uncore, DSPCLK_GATE_D(i915), 0); + intel_uncore_write(uncore, DSPCLK_GATE_D, 0); intel_uncore_write(uncore, RAMCLK_GATE_D, 0); intel_uncore_write16(uncore, DEUC, 0); intel_uncore_write(uncore, diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index 87ac4446d306..ca57a3dd3148 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -62,6 +62,7 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter) { struct drm_i915_private *dev_priv = iter->i915; + struct intel_display *display = dev_priv->display; MMIO_RING_D(RING_IMR); MMIO_D(SDEIMR); @@ -133,38 +134,38 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter) MMIO_D(_MMIO(0x650b4)); MMIO_D(_MMIO(0xc4040)); MMIO_D(DERRMR); - MMIO_D(PIPEDSL(dev_priv, PIPE_A)); - MMIO_D(PIPEDSL(dev_priv, PIPE_B)); - MMIO_D(PIPEDSL(dev_priv, PIPE_C)); - MMIO_D(PIPEDSL(dev_priv, _PIPE_EDP)); - MMIO_D(TRANSCONF(dev_priv, TRANSCODER_A)); - MMIO_D(TRANSCONF(dev_priv, TRANSCODER_B)); - MMIO_D(TRANSCONF(dev_priv, TRANSCODER_C)); - MMIO_D(TRANSCONF(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPESTAT(dev_priv, PIPE_A)); - MMIO_D(PIPESTAT(dev_priv, PIPE_B)); - MMIO_D(PIPESTAT(dev_priv, PIPE_C)); - MMIO_D(PIPESTAT(dev_priv, _PIPE_EDP)); - MMIO_D(PIPE_FLIPCOUNT_G4X(dev_priv, PIPE_A)); - MMIO_D(PIPE_FLIPCOUNT_G4X(dev_priv, PIPE_B)); - MMIO_D(PIPE_FLIPCOUNT_G4X(dev_priv, PIPE_C)); - MMIO_D(PIPE_FLIPCOUNT_G4X(dev_priv, _PIPE_EDP)); - MMIO_D(PIPE_FRMCOUNT_G4X(dev_priv, PIPE_A)); - MMIO_D(PIPE_FRMCOUNT_G4X(dev_priv, PIPE_B)); - MMIO_D(PIPE_FRMCOUNT_G4X(dev_priv, PIPE_C)); - MMIO_D(PIPE_FRMCOUNT_G4X(dev_priv, _PIPE_EDP)); - MMIO_D(CURCNTR(dev_priv, PIPE_A)); - MMIO_D(CURCNTR(dev_priv, PIPE_B)); - MMIO_D(CURCNTR(dev_priv, PIPE_C)); - MMIO_D(CURPOS(dev_priv, PIPE_A)); - MMIO_D(CURPOS(dev_priv, PIPE_B)); - MMIO_D(CURPOS(dev_priv, PIPE_C)); - MMIO_D(CURBASE(dev_priv, PIPE_A)); - MMIO_D(CURBASE(dev_priv, PIPE_B)); - MMIO_D(CURBASE(dev_priv, PIPE_C)); - MMIO_D(CUR_FBC_CTL(dev_priv, PIPE_A)); - MMIO_D(CUR_FBC_CTL(dev_priv, PIPE_B)); - MMIO_D(CUR_FBC_CTL(dev_priv, PIPE_C)); + MMIO_D(PIPEDSL(display, PIPE_A)); + MMIO_D(PIPEDSL(display, PIPE_B)); + MMIO_D(PIPEDSL(display, PIPE_C)); + MMIO_D(PIPEDSL(display, _PIPE_EDP)); + MMIO_D(TRANSCONF(display, TRANSCODER_A)); + MMIO_D(TRANSCONF(display, TRANSCODER_B)); + MMIO_D(TRANSCONF(display, TRANSCODER_C)); + MMIO_D(TRANSCONF(display, TRANSCODER_EDP)); + MMIO_D(PIPESTAT(display, PIPE_A)); + MMIO_D(PIPESTAT(display, PIPE_B)); + MMIO_D(PIPESTAT(display, PIPE_C)); + MMIO_D(PIPESTAT(display, _PIPE_EDP)); + MMIO_D(PIPE_FLIPCOUNT_G4X(display, PIPE_A)); + MMIO_D(PIPE_FLIPCOUNT_G4X(display, PIPE_B)); + MMIO_D(PIPE_FLIPCOUNT_G4X(display, PIPE_C)); + MMIO_D(PIPE_FLIPCOUNT_G4X(display, _PIPE_EDP)); + MMIO_D(PIPE_FRMCOUNT_G4X(display, PIPE_A)); + MMIO_D(PIPE_FRMCOUNT_G4X(display, PIPE_B)); + MMIO_D(PIPE_FRMCOUNT_G4X(display, PIPE_C)); + MMIO_D(PIPE_FRMCOUNT_G4X(display, _PIPE_EDP)); + MMIO_D(CURCNTR(display, PIPE_A)); + MMIO_D(CURCNTR(display, PIPE_B)); + MMIO_D(CURCNTR(display, PIPE_C)); + MMIO_D(CURPOS(display, PIPE_A)); + MMIO_D(CURPOS(display, PIPE_B)); + MMIO_D(CURPOS(display, PIPE_C)); + MMIO_D(CURBASE(display, PIPE_A)); + MMIO_D(CURBASE(display, PIPE_B)); + MMIO_D(CURBASE(display, PIPE_C)); + MMIO_D(CUR_FBC_CTL(display, PIPE_A)); + MMIO_D(CUR_FBC_CTL(display, PIPE_B)); + MMIO_D(CUR_FBC_CTL(display, PIPE_C)); MMIO_D(_MMIO(0x700ac)); MMIO_D(_MMIO(0x710ac)); MMIO_D(_MMIO(0x720ac)); @@ -172,32 +173,32 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter) MMIO_D(_MMIO(0x70094)); MMIO_D(_MMIO(0x70098)); MMIO_D(_MMIO(0x7009c)); - MMIO_D(DSPCNTR(dev_priv, PIPE_A)); - MMIO_D(DSPADDR(dev_priv, PIPE_A)); - MMIO_D(DSPSTRIDE(dev_priv, PIPE_A)); - MMIO_D(DSPPOS(dev_priv, PIPE_A)); - MMIO_D(DSPSIZE(dev_priv, PIPE_A)); - MMIO_D(DSPSURF(dev_priv, PIPE_A)); - MMIO_D(DSPOFFSET(dev_priv, PIPE_A)); - MMIO_D(DSPSURFLIVE(dev_priv, PIPE_A)); + MMIO_D(DSPCNTR(display, PIPE_A)); + MMIO_D(DSPADDR(display, PIPE_A)); + MMIO_D(DSPSTRIDE(display, PIPE_A)); + MMIO_D(DSPPOS(display, PIPE_A)); + MMIO_D(DSPSIZE(display, PIPE_A)); + MMIO_D(DSPSURF(display, PIPE_A)); + MMIO_D(DSPOFFSET(display, PIPE_A)); + MMIO_D(DSPSURFLIVE(display, PIPE_A)); MMIO_D(REG_50080(PIPE_A, PLANE_PRIMARY)); - MMIO_D(DSPCNTR(dev_priv, PIPE_B)); - MMIO_D(DSPADDR(dev_priv, PIPE_B)); - MMIO_D(DSPSTRIDE(dev_priv, PIPE_B)); - MMIO_D(DSPPOS(dev_priv, PIPE_B)); - MMIO_D(DSPSIZE(dev_priv, PIPE_B)); - MMIO_D(DSPSURF(dev_priv, PIPE_B)); - MMIO_D(DSPOFFSET(dev_priv, PIPE_B)); - MMIO_D(DSPSURFLIVE(dev_priv, PIPE_B)); + MMIO_D(DSPCNTR(display, PIPE_B)); + MMIO_D(DSPADDR(display, PIPE_B)); + MMIO_D(DSPSTRIDE(display, PIPE_B)); + MMIO_D(DSPPOS(display, PIPE_B)); + MMIO_D(DSPSIZE(display, PIPE_B)); + MMIO_D(DSPSURF(display, PIPE_B)); + MMIO_D(DSPOFFSET(display, PIPE_B)); + MMIO_D(DSPSURFLIVE(display, PIPE_B)); MMIO_D(REG_50080(PIPE_B, PLANE_PRIMARY)); - MMIO_D(DSPCNTR(dev_priv, PIPE_C)); - MMIO_D(DSPADDR(dev_priv, PIPE_C)); - MMIO_D(DSPSTRIDE(dev_priv, PIPE_C)); - MMIO_D(DSPPOS(dev_priv, PIPE_C)); - MMIO_D(DSPSIZE(dev_priv, PIPE_C)); - MMIO_D(DSPSURF(dev_priv, PIPE_C)); - MMIO_D(DSPOFFSET(dev_priv, PIPE_C)); - MMIO_D(DSPSURFLIVE(dev_priv, PIPE_C)); + MMIO_D(DSPCNTR(display, PIPE_C)); + MMIO_D(DSPADDR(display, PIPE_C)); + MMIO_D(DSPSTRIDE(display, PIPE_C)); + MMIO_D(DSPPOS(display, PIPE_C)); + MMIO_D(DSPSIZE(display, PIPE_C)); + MMIO_D(DSPSURF(display, PIPE_C)); + MMIO_D(DSPOFFSET(display, PIPE_C)); + MMIO_D(DSPSURFLIVE(display, PIPE_C)); MMIO_D(REG_50080(PIPE_C, PLANE_PRIMARY)); MMIO_D(SPRCTL(PIPE_A)); MMIO_D(SPRLINOFF(PIPE_A)); @@ -238,73 +239,73 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter) MMIO_D(SPRSCALE(PIPE_C)); MMIO_D(SPRSURFLIVE(PIPE_C)); MMIO_D(REG_50080(PIPE_C, PLANE_SPRITE0)); - MMIO_D(TRANS_HTOTAL(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_HBLANK(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_HSYNC(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_VTOTAL(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_VBLANK(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_VSYNC(dev_priv, TRANSCODER_A)); - MMIO_D(BCLRPAT(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_VSYNCSHIFT(dev_priv, TRANSCODER_A)); - MMIO_D(PIPESRC(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_HTOTAL(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_HBLANK(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_HSYNC(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_VTOTAL(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_VBLANK(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_VSYNC(dev_priv, TRANSCODER_B)); - MMIO_D(BCLRPAT(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_VSYNCSHIFT(dev_priv, TRANSCODER_B)); - MMIO_D(PIPESRC(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_HTOTAL(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_HBLANK(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_HSYNC(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_VTOTAL(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_VBLANK(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_VSYNC(dev_priv, TRANSCODER_C)); - MMIO_D(BCLRPAT(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_VSYNCSHIFT(dev_priv, TRANSCODER_C)); - MMIO_D(PIPESRC(dev_priv, TRANSCODER_C)); - MMIO_D(TRANS_HTOTAL(dev_priv, TRANSCODER_EDP)); - MMIO_D(TRANS_HBLANK(dev_priv, TRANSCODER_EDP)); - MMIO_D(TRANS_HSYNC(dev_priv, TRANSCODER_EDP)); - MMIO_D(TRANS_VTOTAL(dev_priv, TRANSCODER_EDP)); - MMIO_D(TRANS_VBLANK(dev_priv, TRANSCODER_EDP)); - MMIO_D(TRANS_VSYNC(dev_priv, TRANSCODER_EDP)); - MMIO_D(BCLRPAT(dev_priv, TRANSCODER_EDP)); - MMIO_D(TRANS_VSYNCSHIFT(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_DATA_M1(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_DATA_N1(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_DATA_M2(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_DATA_N2(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_LINK_M1(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_LINK_N1(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_LINK_M2(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_LINK_N2(dev_priv, TRANSCODER_A)); - MMIO_D(PIPE_DATA_M1(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_DATA_N1(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_DATA_M2(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_DATA_N2(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_LINK_M1(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_LINK_N1(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_LINK_M2(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_LINK_N2(dev_priv, TRANSCODER_B)); - MMIO_D(PIPE_DATA_M1(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_DATA_N1(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_DATA_M2(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_DATA_N2(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_LINK_M1(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_LINK_N1(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_LINK_M2(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_LINK_N2(dev_priv, TRANSCODER_C)); - MMIO_D(PIPE_DATA_M1(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_DATA_N1(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_DATA_M2(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_DATA_N2(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_LINK_M1(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_LINK_N1(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_LINK_M2(dev_priv, TRANSCODER_EDP)); - MMIO_D(PIPE_LINK_N2(dev_priv, TRANSCODER_EDP)); + MMIO_D(TRANS_HTOTAL(display, TRANSCODER_A)); + MMIO_D(TRANS_HBLANK(display, TRANSCODER_A)); + MMIO_D(TRANS_HSYNC(display, TRANSCODER_A)); + MMIO_D(TRANS_VTOTAL(display, TRANSCODER_A)); + MMIO_D(TRANS_VBLANK(display, TRANSCODER_A)); + MMIO_D(TRANS_VSYNC(display, TRANSCODER_A)); + MMIO_D(BCLRPAT(display, TRANSCODER_A)); + MMIO_D(TRANS_VSYNCSHIFT(display, TRANSCODER_A)); + MMIO_D(PIPESRC(display, TRANSCODER_A)); + MMIO_D(TRANS_HTOTAL(display, TRANSCODER_B)); + MMIO_D(TRANS_HBLANK(display, TRANSCODER_B)); + MMIO_D(TRANS_HSYNC(display, TRANSCODER_B)); + MMIO_D(TRANS_VTOTAL(display, TRANSCODER_B)); + MMIO_D(TRANS_VBLANK(display, TRANSCODER_B)); + MMIO_D(TRANS_VSYNC(display, TRANSCODER_B)); + MMIO_D(BCLRPAT(display, TRANSCODER_B)); + MMIO_D(TRANS_VSYNCSHIFT(display, TRANSCODER_B)); + MMIO_D(PIPESRC(display, TRANSCODER_B)); + MMIO_D(TRANS_HTOTAL(display, TRANSCODER_C)); + MMIO_D(TRANS_HBLANK(display, TRANSCODER_C)); + MMIO_D(TRANS_HSYNC(display, TRANSCODER_C)); + MMIO_D(TRANS_VTOTAL(display, TRANSCODER_C)); + MMIO_D(TRANS_VBLANK(display, TRANSCODER_C)); + MMIO_D(TRANS_VSYNC(display, TRANSCODER_C)); + MMIO_D(BCLRPAT(display, TRANSCODER_C)); + MMIO_D(TRANS_VSYNCSHIFT(display, TRANSCODER_C)); + MMIO_D(PIPESRC(display, TRANSCODER_C)); + MMIO_D(TRANS_HTOTAL(display, TRANSCODER_EDP)); + MMIO_D(TRANS_HBLANK(display, TRANSCODER_EDP)); + MMIO_D(TRANS_HSYNC(display, TRANSCODER_EDP)); + MMIO_D(TRANS_VTOTAL(display, TRANSCODER_EDP)); + MMIO_D(TRANS_VBLANK(display, TRANSCODER_EDP)); + MMIO_D(TRANS_VSYNC(display, TRANSCODER_EDP)); + MMIO_D(BCLRPAT(display, TRANSCODER_EDP)); + MMIO_D(TRANS_VSYNCSHIFT(display, TRANSCODER_EDP)); + MMIO_D(PIPE_DATA_M1(display, TRANSCODER_A)); + MMIO_D(PIPE_DATA_N1(display, TRANSCODER_A)); + MMIO_D(PIPE_DATA_M2(display, TRANSCODER_A)); + MMIO_D(PIPE_DATA_N2(display, TRANSCODER_A)); + MMIO_D(PIPE_LINK_M1(display, TRANSCODER_A)); + MMIO_D(PIPE_LINK_N1(display, TRANSCODER_A)); + MMIO_D(PIPE_LINK_M2(display, TRANSCODER_A)); + MMIO_D(PIPE_LINK_N2(display, TRANSCODER_A)); + MMIO_D(PIPE_DATA_M1(display, TRANSCODER_B)); + MMIO_D(PIPE_DATA_N1(display, TRANSCODER_B)); + MMIO_D(PIPE_DATA_M2(display, TRANSCODER_B)); + MMIO_D(PIPE_DATA_N2(display, TRANSCODER_B)); + MMIO_D(PIPE_LINK_M1(display, TRANSCODER_B)); + MMIO_D(PIPE_LINK_N1(display, TRANSCODER_B)); + MMIO_D(PIPE_LINK_M2(display, TRANSCODER_B)); + MMIO_D(PIPE_LINK_N2(display, TRANSCODER_B)); + MMIO_D(PIPE_DATA_M1(display, TRANSCODER_C)); + MMIO_D(PIPE_DATA_N1(display, TRANSCODER_C)); + MMIO_D(PIPE_DATA_M2(display, TRANSCODER_C)); + MMIO_D(PIPE_DATA_N2(display, TRANSCODER_C)); + MMIO_D(PIPE_LINK_M1(display, TRANSCODER_C)); + MMIO_D(PIPE_LINK_N1(display, TRANSCODER_C)); + MMIO_D(PIPE_LINK_M2(display, TRANSCODER_C)); + MMIO_D(PIPE_LINK_N2(display, TRANSCODER_C)); + MMIO_D(PIPE_DATA_M1(display, TRANSCODER_EDP)); + MMIO_D(PIPE_DATA_N1(display, TRANSCODER_EDP)); + MMIO_D(PIPE_DATA_M2(display, TRANSCODER_EDP)); + MMIO_D(PIPE_DATA_N2(display, TRANSCODER_EDP)); + MMIO_D(PIPE_LINK_M1(display, TRANSCODER_EDP)); + MMIO_D(PIPE_LINK_N1(display, TRANSCODER_EDP)); + MMIO_D(PIPE_LINK_M2(display, TRANSCODER_EDP)); + MMIO_D(PIPE_LINK_N2(display, TRANSCODER_EDP)); MMIO_D(PF_CTL(PIPE_A)); MMIO_D(PF_WIN_SZ(PIPE_A)); MMIO_D(PF_WIN_POS(PIPE_A)); @@ -513,12 +514,12 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter) MMIO_D(GAMMA_MODE(PIPE_A)); MMIO_D(GAMMA_MODE(PIPE_B)); MMIO_D(GAMMA_MODE(PIPE_C)); - MMIO_D(TRANS_MULT(dev_priv, TRANSCODER_A)); - MMIO_D(TRANS_MULT(dev_priv, TRANSCODER_B)); - MMIO_D(TRANS_MULT(dev_priv, TRANSCODER_C)); - MMIO_D(HSW_TVIDEO_DIP_CTL(dev_priv, TRANSCODER_A)); - MMIO_D(HSW_TVIDEO_DIP_CTL(dev_priv, TRANSCODER_B)); - MMIO_D(HSW_TVIDEO_DIP_CTL(dev_priv, TRANSCODER_C)); + MMIO_D(TRANS_MULT(display, TRANSCODER_A)); + MMIO_D(TRANS_MULT(display, TRANSCODER_B)); + MMIO_D(TRANS_MULT(display, TRANSCODER_C)); + MMIO_D(HSW_TVIDEO_DIP_CTL(display, TRANSCODER_A)); + MMIO_D(HSW_TVIDEO_DIP_CTL(display, TRANSCODER_B)); + MMIO_D(HSW_TVIDEO_DIP_CTL(display, TRANSCODER_C)); MMIO_D(SFUSE_STRAP); MMIO_D(SBI_ADDR); MMIO_D(SBI_DATA); @@ -1111,6 +1112,7 @@ static int iterate_skl_plus_mmio(struct intel_gvt_mmio_table_iter *iter) static int iterate_bxt_mmio(struct intel_gvt_mmio_table_iter *iter) { struct drm_i915_private *dev_priv = iter->i915; + struct intel_display *display = dev_priv->display; MMIO_F(_MMIO(0x80000), 0x3000); MMIO_D(GEN7_SAMPLER_INSTDONE); @@ -1242,9 +1244,9 @@ static int iterate_bxt_mmio(struct intel_gvt_mmio_table_iter *iter) MMIO_D(BXT_DSI_PLL_ENABLE); MMIO_D(GEN9_CLKGATE_DIS_0); MMIO_D(GEN9_CLKGATE_DIS_4); - MMIO_D(HSW_TVIDEO_DIP_GCP(dev_priv, TRANSCODER_A)); - MMIO_D(HSW_TVIDEO_DIP_GCP(dev_priv, TRANSCODER_B)); - MMIO_D(HSW_TVIDEO_DIP_GCP(dev_priv, TRANSCODER_C)); + MMIO_D(HSW_TVIDEO_DIP_GCP(display, TRANSCODER_A)); + MMIO_D(HSW_TVIDEO_DIP_GCP(display, TRANSCODER_B)); + MMIO_D(HSW_TVIDEO_DIP_GCP(display, TRANSCODER_C)); MMIO_D(RC6_CTX_BASE); MMIO_D(GEN8_PUSHBUS_CONTROL); MMIO_D(GEN8_PUSHBUS_ENABLE); diff --git a/drivers/gpu/drm/i915/intel_pcode.c b/drivers/gpu/drm/i915/intel_pcode.c index 81da75108c60..55ffedad2490 100644 --- a/drivers/gpu/drm/i915/intel_pcode.c +++ b/drivers/gpu/drm/i915/intel_pcode.c @@ -5,6 +5,7 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "i915_wait_util.h" #include "intel_pcode.h" static int gen6_check_mailbox_status(u32 mbox) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index c8e29fd72290..8cb59f8d1f4c 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -21,19 +21,20 @@ * IN THE SOFTWARE. */ -#include <drm/drm_managed.h> #include <linux/pm_runtime.h> -#include "display/intel_display_core.h" +#include <drm/drm_managed.h> -#include "gt/intel_gt.h" +#include "display/intel_display_core.h" #include "gt/intel_engine_regs.h" +#include "gt/intel_gt.h" #include "gt/intel_gt_regs.h" #include "i915_drv.h" #include "i915_iosf_mbi.h" #include "i915_reg.h" #include "i915_vgpu.h" +#include "i915_wait_util.h" #include "intel_uncore_trace.h" #define FORCEWAKE_ACK_TIMEOUT_MS 50 @@ -2502,6 +2503,7 @@ static int sanity_check_mmio_access(struct intel_uncore *uncore) int intel_uncore_init_mmio(struct intel_uncore *uncore) { struct drm_i915_private *i915 = uncore->i915; + struct intel_display *display = i915->display; int ret; ret = sanity_check_mmio_access(uncore); @@ -2536,7 +2538,7 @@ int intel_uncore_init_mmio(struct intel_uncore *uncore) GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.read_fw_domains); GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.write_fw_domains); - if (HAS_FPGA_DBG_UNCLAIMED(i915)) + if (HAS_FPGA_DBG_UNCLAIMED(display)) uncore->flags |= UNCORE_HAS_FPGA_DBG_UNCLAIMED; if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index f8da693ad3ce..27d545c4e6a5 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -2,15 +2,15 @@ /* * Copyright(c) 2020 Intel Corporation. */ + #include <linux/workqueue.h> #include "gem/i915_gem_context.h" - #include "gt/intel_context.h" #include "gt/intel_gt.h" #include "i915_drv.h" - +#include "i915_wait_util.h" #include "intel_pxp.h" #include "intel_pxp_gsccs.h" #include "intel_pxp_irq.h" diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c index e07c5b380789..545f79eb0cc5 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c @@ -69,17 +69,17 @@ DEFINE_SIMPLE_ATTRIBUTE(pxp_terminate_fops, pxp_terminate_get, pxp_terminate_set void intel_pxp_debugfs_register(struct intel_pxp *pxp) { - struct drm_minor *minor; + struct dentry *debugfs_root; struct dentry *pxproot; if (!intel_pxp_is_supported(pxp)) return; - minor = pxp->ctrl_gt->i915->drm.primary; - if (!minor->debugfs_root) + debugfs_root = pxp->ctrl_gt->i915->drm.debugfs_root; + if (!debugfs_root) return; - pxproot = debugfs_create_dir("pxp", minor->debugfs_root); + pxproot = debugfs_create_dir("pxp", debugfs_root); if (IS_ERR(pxproot)) return; diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 2fb7a9e7efec..48cd617247d1 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -22,14 +22,13 @@ * */ -#include <linux/prime_numbers.h> #include <linux/pm_qos.h> +#include <linux/prime_numbers.h> #include <linux/sort.h> #include "gem/i915_gem_internal.h" #include "gem/i915_gem_pm.h" #include "gem/selftests/mock_context.h" - #include "gt/intel_engine_heartbeat.h" #include "gt/intel_engine_pm.h" #include "gt/intel_engine_user.h" @@ -40,11 +39,11 @@ #include "i915_random.h" #include "i915_selftest.h" +#include "i915_wait_util.h" #include "igt_flush_test.h" #include "igt_live_test.h" #include "igt_spinner.h" #include "lib_sw_fence.h" - #include "mock_drm.h" #include "mock_gem_device.h" diff --git a/drivers/gpu/drm/i915/selftests/i915_selftest.c b/drivers/gpu/drm/i915/selftests/i915_selftest.c index 889281819c5b..9c276c9d0a75 100644 --- a/drivers/gpu/drm/i915/selftests/i915_selftest.c +++ b/drivers/gpu/drm/i915/selftests/i915_selftest.c @@ -31,7 +31,7 @@ #include "i915_driver.h" #include "i915_drv.h" #include "i915_selftest.h" - +#include "i915_wait_util.h" #include "igt_flush_test.h" struct i915_selftest i915_selftest __read_mostly = { diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c index 8c3e1f20e5a1..820364171ebe 100644 --- a/drivers/gpu/drm/i915/selftests/igt_spinner.c +++ b/drivers/gpu/drm/i915/selftests/igt_spinner.c @@ -3,12 +3,13 @@ * * Copyright © 2018 Intel Corporation */ -#include "gt/intel_gpu_commands.h" -#include "gt/intel_gt.h" #include "gem/i915_gem_internal.h" #include "gem/selftests/igt_gem_utils.h" +#include "gt/intel_gpu_commands.h" +#include "gt/intel_gt.h" +#include "i915_wait_util.h" #include "igt_spinner.h" int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt) diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 41eaa9b7f67d..58bcbdcef563 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -277,13 +277,15 @@ static int live_forcewake_domains(void *arg) #define FW_RANGE 0x40000 struct intel_gt *gt = arg; struct intel_uncore *uncore = gt->uncore; + struct drm_i915_private *i915 = gt->i915; + struct intel_display *display = i915->display; unsigned long *valid; u32 offset; int err; - if (!HAS_FPGA_DBG_UNCLAIMED(gt->i915) && - !IS_VALLEYVIEW(gt->i915) && - !IS_CHERRYVIEW(gt->i915)) + if (!HAS_FPGA_DBG_UNCLAIMED(display) && + !IS_VALLEYVIEW(i915) && + !IS_CHERRYVIEW(i915)) return 0; /* diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c index deb159548a09..8841cfe1cac8 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.c +++ b/drivers/gpu/drm/i915/soc/intel_dram.c @@ -11,6 +11,7 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_dram.h" #include "intel_mchbar_regs.h" #include "intel_pcode.h" @@ -30,10 +31,11 @@ struct dram_channel_info { #define DRAM_TYPE_STR(type) [INTEL_DRAM_ ## type] = #type -static const char *intel_dram_type_str(enum intel_dram_type type) +const char *intel_dram_type_str(enum intel_dram_type type) { static const char * const str[] = { DRAM_TYPE_STR(UNKNOWN), + DRAM_TYPE_STR(DDR2), DRAM_TYPE_STR(DDR3), DRAM_TYPE_STR(DDR4), DRAM_TYPE_STR(LPDDR3), @@ -54,9 +56,10 @@ static const char *intel_dram_type_str(enum intel_dram_type type) #undef DRAM_TYPE_STR -static bool pnv_is_ddr3(struct drm_i915_private *i915) +static enum intel_dram_type pnv_dram_type(struct drm_i915_private *i915) { - return intel_uncore_read(&i915->uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3; + return intel_uncore_read(&i915->uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ? + INTEL_DRAM_DDR3 : INTEL_DRAM_DDR2; } static unsigned int pnv_mem_freq(struct drm_i915_private *dev_priv) @@ -135,25 +138,21 @@ static unsigned int vlv_mem_freq(struct drm_i915_private *i915) return 0; } -static void detect_mem_freq(struct drm_i915_private *i915) +unsigned int intel_mem_freq(struct drm_i915_private *i915) { if (IS_PINEVIEW(i915)) - i915->mem_freq = pnv_mem_freq(i915); + return pnv_mem_freq(i915); else if (GRAPHICS_VER(i915) == 5) - i915->mem_freq = ilk_mem_freq(i915); + return ilk_mem_freq(i915); else if (IS_CHERRYVIEW(i915)) - i915->mem_freq = chv_mem_freq(i915); + return chv_mem_freq(i915); else if (IS_VALLEYVIEW(i915)) - i915->mem_freq = vlv_mem_freq(i915); - - if (IS_PINEVIEW(i915)) - i915->is_ddr3 = pnv_is_ddr3(i915); - - if (i915->mem_freq) - drm_dbg(&i915->drm, "DDR speed: %d kHz\n", i915->mem_freq); + return vlv_mem_freq(i915); + else + return 0; } -unsigned int i9xx_fsb_freq(struct drm_i915_private *i915) +static unsigned int i9xx_fsb_freq(struct drm_i915_private *i915) { u32 fsb; @@ -235,15 +234,30 @@ static unsigned int ilk_fsb_freq(struct drm_i915_private *dev_priv) } } -static void detect_fsb_freq(struct drm_i915_private *i915) +unsigned int intel_fsb_freq(struct drm_i915_private *i915) { if (GRAPHICS_VER(i915) == 5) - i915->fsb_freq = ilk_fsb_freq(i915); + return ilk_fsb_freq(i915); else if (GRAPHICS_VER(i915) == 3 || GRAPHICS_VER(i915) == 4) - i915->fsb_freq = i9xx_fsb_freq(i915); + return i9xx_fsb_freq(i915); + else + return 0; +} - if (i915->fsb_freq) - drm_dbg(&i915->drm, "FSB frequency: %d kHz\n", i915->fsb_freq); +static int i915_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) +{ + dram_info->fsb_freq = intel_fsb_freq(i915); + if (dram_info->fsb_freq) + drm_dbg(&i915->drm, "FSB frequency: %d kHz\n", dram_info->fsb_freq); + + dram_info->mem_freq = intel_mem_freq(i915); + if (dram_info->mem_freq) + drm_dbg(&i915->drm, "DDR speed: %d kHz\n", dram_info->mem_freq); + + if (IS_PINEVIEW(i915)) + dram_info->type = pnv_dram_type(i915); + + return 0; } static int intel_dimm_num_devices(const struct dram_dimm_info *dimm) @@ -321,7 +335,7 @@ static bool skl_is_16gb_dimm(const struct dram_dimm_info *dimm) { /* Convert total Gb to Gb per DRAM device */ - return dimm->size / (intel_dimm_num_devices(dimm) ?: 1) == 16; + return dimm->size / (intel_dimm_num_devices(dimm) ?: 1) >= 16; } static void @@ -340,7 +354,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, str_yes_no(skl_is_16gb_dimm(dimm))); } @@ -370,7 +384,7 @@ skl_dram_get_channel_info(struct drm_i915_private *i915, ch->is_16gb_dimm = skl_is_16gb_dimm(&ch->dimm_l) || skl_is_16gb_dimm(&ch->dimm_s); - drm_dbg_kms(&i915->drm, "CH%u ranks: %u, 16Gb DIMMs: %s\n", + drm_dbg_kms(&i915->drm, "CH%u ranks: %u, 16Gb+ DIMMs: %s\n", channel, ch->ranks, str_yes_no(ch->is_16gb_dimm)); return 0; @@ -392,6 +406,9 @@ skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram u32 val; int ret; + /* Assume 16Gb+ DIMMs are present until proven otherwise */ + dram_info->has_16gb_dimms = true; + val = intel_uncore_read(&i915->uncore, SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN); ret = skl_dram_get_channel_info(i915, &ch0, 0, val); @@ -414,13 +431,16 @@ skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram return -EINVAL; } - dram_info->wm_lv_0_adjust_needed = ch0.is_16gb_dimm || ch1.is_16gb_dimm; + dram_info->has_16gb_dimms = ch0.is_16gb_dimm || ch1.is_16gb_dimm; dram_info->symmetric_memory = intel_is_dram_symmetric(&ch0, &ch1); drm_dbg_kms(&i915->drm, "Memory configuration is symmetric? %s\n", str_yes_no(dram_info->symmetric_memory)); + drm_dbg_kms(&i915->drm, "16Gb+ DIMMs: %s\n", + str_yes_no(dram_info->has_16gb_dimms)); + return 0; } @@ -649,8 +669,9 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv, static int gen11_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - int ret = skl_get_dram_info(i915, dram_info); + int ret; + ret = skl_dram_get_channels_info(i915, dram_info); if (ret) return ret; @@ -659,8 +680,6 @@ static int gen11_get_dram_info(struct drm_i915_private *i915, struct dram_info * static int gen12_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - dram_info->wm_lv_0_adjust_needed = false; - return icl_pcode_read_mem_global_info(i915, dram_info); } @@ -709,13 +728,11 @@ static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info int intel_dram_detect(struct drm_i915_private *i915) { + struct intel_display *display = i915->display; struct dram_info *dram_info; int ret; - detect_fsb_freq(i915); - detect_mem_freq(i915); - - if (GRAPHICS_VER(i915) < 9 || IS_DG2(i915) || !HAS_DISPLAY(i915)) + if (IS_DG2(i915) || !intel_display_device_present(display)) return 0; dram_info = drmm_kzalloc(&i915->drm, sizeof(*dram_info), GFP_KERNEL); @@ -724,13 +741,7 @@ int intel_dram_detect(struct drm_i915_private *i915) i915->dram_info = dram_info; - /* - * Assume level 0 watermark latency adjustment is needed until proven - * otherwise, this w/a is not needed by bxt/glk. - */ - dram_info->wm_lv_0_adjust_needed = !IS_BROXTON(i915) && !IS_GEMINILAKE(i915); - - if (DISPLAY_VER(i915) >= 14) + if (DISPLAY_VER(display) >= 14) ret = xelpdp_get_dram_info(i915, dram_info); else if (GRAPHICS_VER(i915) >= 12) ret = gen12_get_dram_info(i915, dram_info); @@ -738,23 +749,23 @@ int intel_dram_detect(struct drm_i915_private *i915) ret = gen11_get_dram_info(i915, dram_info); else if (IS_BROXTON(i915) || IS_GEMINILAKE(i915)) ret = bxt_get_dram_info(i915, dram_info); - else + else if (GRAPHICS_VER(i915) >= 9) ret = skl_get_dram_info(i915, dram_info); + else + ret = i915_get_dram_info(i915, dram_info); drm_dbg_kms(&i915->drm, "DRAM type: %s\n", intel_dram_type_str(dram_info->type)); + drm_dbg_kms(&i915->drm, "DRAM channels: %u\n", dram_info->num_channels); + + drm_dbg_kms(&i915->drm, "Num QGV points %u\n", dram_info->num_qgv_points); + drm_dbg_kms(&i915->drm, "Num PSF GV points %u\n", dram_info->num_psf_gv_points); + /* TODO: Do we want to abort probe on dram detection failures? */ if (ret) return 0; - drm_dbg_kms(&i915->drm, "Num qgv points %u\n", dram_info->num_qgv_points); - - drm_dbg_kms(&i915->drm, "DRAM channels: %u\n", dram_info->num_channels); - - drm_dbg_kms(&i915->drm, "Watermark level 0 adjustment needed: %s\n", - str_yes_no(dram_info->wm_lv_0_adjust_needed)); - return 0; } diff --git a/drivers/gpu/drm/i915/soc/intel_dram.h b/drivers/gpu/drm/i915/soc/intel_dram.h index 2a696e03aad4..03a973f1c941 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.h +++ b/drivers/gpu/drm/i915/soc/intel_dram.h @@ -12,11 +12,9 @@ struct drm_i915_private; struct drm_device; struct dram_info { - bool wm_lv_0_adjust_needed; - u8 num_channels; - bool symmetric_memory; enum intel_dram_type { INTEL_DRAM_UNKNOWN, + INTEL_DRAM_DDR2, INTEL_DRAM_DDR3, INTEL_DRAM_DDR4, INTEL_DRAM_LPDDR3, @@ -27,13 +25,20 @@ struct dram_info { INTEL_DRAM_GDDR_ECC, __INTEL_DRAM_TYPE_MAX, } type; + unsigned int fsb_freq; + unsigned int mem_freq; + u8 num_channels; u8 num_qgv_points; u8 num_psf_gv_points; + bool symmetric_memory; + bool has_16gb_dimms; }; void intel_dram_edram_detect(struct drm_i915_private *i915); int intel_dram_detect(struct drm_i915_private *i915); -unsigned int i9xx_fsb_freq(struct drm_i915_private *i915); +unsigned int intel_fsb_freq(struct drm_i915_private *i915); +unsigned int intel_mem_freq(struct drm_i915_private *i915); const struct dram_info *intel_dram_info(struct drm_device *drm); +const char *intel_dram_type_str(enum intel_dram_type type); #endif /* __INTEL_DRAM_H__ */ diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.c b/drivers/gpu/drm/i915/soc/intel_gmch.c index 5346b8dda79a..f210c9655b53 100644 --- a/drivers/gpu/drm/i915/soc/intel_gmch.c +++ b/drivers/gpu/drm/i915/soc/intel_gmch.c @@ -148,7 +148,8 @@ void intel_gmch_bar_teardown(struct drm_i915_private *i915) int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode) { - unsigned int reg = DISPLAY_VER(i915) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; + struct intel_display *display = i915->display; + unsigned int reg = DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; u16 gmch_ctrl; if (pci_read_config_word(i915->gmch.pdev, reg, &gmch_ctrl)) { diff --git a/drivers/gpu/drm/i915/vlv_suspend.c b/drivers/gpu/drm/i915/vlv_suspend.c index fc9f311ea1db..221e4c0b2c58 100644 --- a/drivers/gpu/drm/i915/vlv_suspend.c +++ b/drivers/gpu/drm/i915/vlv_suspend.c @@ -8,16 +8,17 @@ #include <drm/drm_print.h> +#include "gt/intel_gt_regs.h" + #include "i915_drv.h" #include "i915_reg.h" #include "i915_trace.h" #include "i915_utils.h" +#include "i915_wait_util.h" #include "intel_clock_gating.h" #include "intel_uncore_trace.h" #include "vlv_suspend.h" -#include "gt/intel_gt_regs.h" - struct vlv_s0ix_state { /* GAM */ u32 wr_watermark; |