diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
100 files changed, 2788 insertions, 1183 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7c6075bc483c..853543443072 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -218,12 +218,11 @@ i915-$(CONFIG_HWMON) += \ # modesetting core code i915-y += \ display/hsw_ips.o \ - display/i9xx_plane.o \ display/i9xx_display_sr.o \ + display/i9xx_plane.o \ display/i9xx_wm.o \ display/intel_alpm.o \ display/intel_atomic.o \ - display/intel_atomic_plane.o \ display/intel_audio.o \ display/intel_bios.o \ display/intel_bo.o \ @@ -265,6 +264,7 @@ i915-y += \ display/intel_fbc.o \ display/intel_fdi.o \ display/intel_fifo_underrun.o \ + display/intel_flipq.o \ display/intel_frontbuffer.o \ display/intel_global_state.o \ display/intel_hdcp.o \ @@ -283,6 +283,7 @@ i915-y += \ display/intel_pch.o \ display/intel_pch_display.o \ display/intel_pch_refclk.o \ + display/intel_plane.o \ display/intel_plane_initial.o \ display/intel_pmdemand.o \ display/intel_psr.o \ diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index 0d33782f11be..927fe56aec77 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -5,8 +5,9 @@ #include <linux/debugfs.h> +#include <drm/drm_print.h> + #include "hsw_ips.h" -#include "i915_drv.h" #include "i915_reg.h" #include "intel_color_regs.h" #include "intel_de.h" @@ -18,8 +19,6 @@ static void hsw_ips_enable(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); - struct drm_i915_private *i915 = to_i915(crtc->base.dev); u32 val; if (!crtc_state->ips_enabled) @@ -40,8 +39,8 @@ static void hsw_ips_enable(const struct intel_crtc_state *crtc_state) if (display->platform.broadwell) { drm_WARN_ON(display->drm, - snb_pcode_write(&i915->uncore, DISPLAY_IPS_CONTROL, - val | IPS_PCODE_CONTROL)); + intel_pcode_write(display->drm, DISPLAY_IPS_CONTROL, + val | IPS_PCODE_CONTROL)); /* * Quoting Art Runyan: "its not safe to expect any particular * value in IPS_CTL bit 31 after enabling IPS through the @@ -66,8 +65,6 @@ static void hsw_ips_enable(const struct intel_crtc_state *crtc_state) bool hsw_ips_disable(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); - struct drm_i915_private *i915 = to_i915(crtc->base.dev); bool need_vblank_wait = false; if (!crtc_state->ips_enabled) @@ -75,7 +72,7 @@ bool hsw_ips_disable(const struct intel_crtc_state *crtc_state) if (display->platform.broadwell) { drm_WARN_ON(display->drm, - snb_pcode_write(&i915->uncore, DISPLAY_IPS_CONTROL, 0)); + intel_pcode_write(display->drm, DISPLAY_IPS_CONTROL, 0)); /* * Wait for PCODE to finish disabling IPS. The BSpec specified * 42ms timeout value leads to occasional timeouts so use 100ms @@ -268,7 +265,7 @@ int hsw_ips_compute_config(struct intel_atomic_state *state, return PTR_ERR(cdclk_state); /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (crtc_state->pixel_rate > cdclk_state->logical.cdclk * 95 / 100) + if (crtc_state->pixel_rate > intel_cdclk_logical(cdclk_state) * 95 / 100) return 0; } diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 8f15333a4b07..f291ced989dc 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -15,7 +15,7 @@ #include "i9xx_plane.h" #include "i9xx_plane_regs.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" +#include "intel_bo.h" #include "intel_de.h" #include "intel_display_irq.h" #include "intel_display_regs.h" @@ -23,6 +23,7 @@ #include "intel_fb.h" #include "intel_fbc.h" #include "intel_frontbuffer.h" +#include "intel_plane.h" #include "intel_sprite.h" /* Primary plane formats for gen <= 3 */ @@ -336,10 +337,10 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - i9xx_plane_has_windowing(plane)); + ret = intel_plane_check_clipping(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + i9xx_plane_has_windowing(plane)); if (ret) return ret; @@ -905,6 +906,27 @@ static const struct drm_plane_funcs i8xx_plane_funcs = { .format_mod_supported_async = intel_plane_format_mod_supported_async, }; +static void i9xx_disable_tiling(struct intel_plane *plane) +{ + struct intel_display *display = to_intel_display(plane); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + u32 dspcntr; + u32 reg; + + dspcntr = intel_de_read_fw(display, DSPCNTR(display, i9xx_plane)); + dspcntr &= ~DISP_TILED; + intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); + + if (DISPLAY_VER(display) >= 4) { + reg = intel_de_read_fw(display, DSPSURF(display, i9xx_plane)); + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), reg); + + } else { + reg = intel_de_read_fw(display, DSPADDR(display, i9xx_plane)); + intel_de_write_fw(display, DSPADDR(display, i9xx_plane), reg); + } +} + struct intel_plane * intel_primary_plane_create(struct intel_display *display, enum pipe pipe) { @@ -1047,6 +1069,8 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe) } } + plane->disable_tiling = i9xx_disable_tiling; + modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X); if (DISPLAY_VER(display) >= 5 || display->platform.g4x) @@ -1151,7 +1175,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, drm_WARN_ON(display->drm, pipe != crtc->pipe); - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + intel_fb = intel_bo_alloc_framebuffer(); if (!intel_fb) { drm_dbg_kms(display->drm, "failed to alloc fb\n"); return; diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index f85edb374c97..348b1655435e 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -26,7 +26,7 @@ * * The functions here implement the state management and hardware programming * dispatch required by the atomic modeset infrastructure. - * See intel_atomic_plane.c for the plane-specific atomic functionality. + * See intel_plane.c for the plane-specific atomic functionality. */ #include <drm/display/drm_dp_tunnel.h> diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 55af3a553c58..5bdaef38f13d 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -951,7 +951,7 @@ static int glk_force_audio_cdclk_commit(struct intel_atomic_state *state, if (IS_ERR(cdclk_state)) return PTR_ERR(cdclk_state); - cdclk_state->force_min_cdclk = enable ? 2 * 96000 : 0; + intel_cdclk_force_min_cdclk(cdclk_state, enable ? 2 * 96000 : 0); return drm_atomic_commit(&state->base); } diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 9ce41e689d50..9c268bed091d 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1939,7 +1939,7 @@ static int get_init_otp_deassert_fragment_len(struct intel_display *display, int index, len; if (drm_WARN_ON(display->drm, - !data || panel->vbt.dsi.seq_version != 1)) + !data || panel->vbt.dsi.seq_version >= 3)) return 0; /* index = 1 to skip sequence byte */ @@ -1962,7 +1962,7 @@ static int get_init_otp_deassert_fragment_len(struct intel_display *display, } /* - * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence. + * Some v1/v2 VBT MIPI sequences do the deassert in the init OTP sequence. * The deassert must be done before calling intel_dsi_device_ready, so for * these devices we split the init OTP sequence into a deassert sequence and * the actual init OTP part. @@ -1973,9 +1973,9 @@ static void vlv_fixup_mipi_sequences(struct intel_display *display, u8 *init_otp; int len; - /* Limit this to v1 vid-mode sequences */ + /* Limit this to v1/v2 vid-mode sequences */ if (panel->vbt.dsi.config->is_cmd_mode || - panel->vbt.dsi.seq_version != 1) + panel->vbt.dsi.seq_version >= 3) return; /* Only do this if there are otp and assert seqs and no deassert seq */ diff --git a/drivers/gpu/drm/i915/display/intel_bo.c b/drivers/gpu/drm/i915/display/intel_bo.c index fbd16d7b58d9..65d64f79a4bd 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.c +++ b/drivers/gpu/drm/i915/display/intel_bo.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT /* 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" @@ -57,3 +59,18 @@ 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 ea7a2253aaa5..97087a64d23b 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.h +++ b/drivers/gpu/drm/i915/display/intel_bo.h @@ -7,6 +7,8 @@ #include <linux/types.h> struct drm_gem_object; +struct drm_scanout_buffer; +struct intel_framebuffer; struct seq_file; struct vm_area_struct; @@ -23,5 +25,8 @@ 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 6c2ab2e0dc91..d29a755612de 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -18,8 +18,44 @@ #include "intel_display_types.h" #include "intel_mchbar_regs.h" #include "intel_pcode.h" +#include "intel_uncore.h" #include "skl_watermark.h" +struct intel_dbuf_bw { + unsigned int max_bw[I915_MAX_DBUF_SLICES]; + u8 active_planes[I915_MAX_DBUF_SLICES]; +}; + +struct intel_bw_state { + struct intel_global_state base; + struct intel_dbuf_bw dbuf_bw[I915_MAX_PIPES]; + + /* + * Contains a bit mask, used to determine, whether correspondent + * pipe allows SAGV or not. + */ + u8 pipe_sagv_reject; + + /* bitmask of active pipes */ + u8 active_pipes; + + /* + * From MTL onwards, to lock a QGV point, punit expects the peak BW of + * the selected QGV point as the parameter in multiples of 100MB/s + */ + u16 qgv_point_peakbw; + + /* + * Current QGV points mask, which restricts + * some particular SAGV states, not to confuse + * with pipe_sagv_mask. + */ + u16 qgv_points_mask; + + unsigned int data_rate[I915_MAX_PIPES]; + u8 num_active_planes[I915_MAX_PIPES]; +}; + /* Parameters for Qclk Geyserville (QGV) */ struct intel_qgv_point { u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd; @@ -82,14 +118,13 @@ static int icl_pcode_read_qgv_point_info(struct intel_display *display, struct intel_qgv_point *sp, int point) { - struct drm_i915_private *i915 = to_i915(display->drm); u32 val = 0, val2 = 0; u16 dclk; int ret; - ret = snb_pcode_read(&i915->uncore, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | - ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point), - &val, &val2); + ret = intel_pcode_read(display->drm, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | + ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point), + &val, &val2); if (ret) return ret; @@ -110,13 +145,12 @@ static int icl_pcode_read_qgv_point_info(struct intel_display *display, static int adls_pcode_read_psf_gv_point_info(struct intel_display *display, struct intel_psf_gv_point *points) { - struct drm_i915_private *i915 = to_i915(display->drm); u32 val = 0; int ret; int i; - ret = snb_pcode_read(&i915->uncore, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | - ADL_PCODE_MEM_SS_READ_PSF_GV_INFO, &val, NULL); + ret = intel_pcode_read(display->drm, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | + ADL_PCODE_MEM_SS_READ_PSF_GV_INFO, &val, NULL); if (ret) return ret; @@ -154,21 +188,20 @@ static bool is_sagv_enabled(struct intel_display *display, u16 points_mask) ICL_PCODE_REQ_QGV_PT_MASK); } -int icl_pcode_restrict_qgv_points(struct intel_display *display, - u32 points_mask) +static int icl_pcode_restrict_qgv_points(struct intel_display *display, + u32 points_mask) { - struct drm_i915_private *i915 = to_i915(display->drm); int ret; if (DISPLAY_VER(display) >= 14) return 0; /* bspec says to keep retrying for at least 1 ms */ - ret = skl_pcode_request(&i915->uncore, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG, - points_mask, - ICL_PCODE_REP_QGV_MASK | ADLS_PCODE_REP_PSF_MASK, - ICL_PCODE_REP_QGV_SAFE | ADLS_PCODE_REP_PSF_SAFE, - 1); + ret = intel_pcode_request(display->drm, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG, + points_mask, + ICL_PCODE_REP_QGV_MASK | ADLS_PCODE_REP_PSF_MASK, + ICL_PCODE_REP_QGV_SAFE | ADLS_PCODE_REP_PSF_SAFE, + 1); if (ret < 0) { drm_err(display->drm, @@ -420,6 +453,13 @@ static const struct intel_sa_info xe3lpd_sa_info = { .derating = 10, }; +static const struct intel_sa_info xe3lpd_3002_sa_info = { + .deburst = 32, + .deprogbwlimit = 22, /* GB/s */ + .displayrtids = 256, + .derating = 10, +}; + static int icl_get_bw_info(struct intel_display *display, const struct dram_info *dram_info, const struct intel_sa_info *sa) @@ -771,7 +811,9 @@ void intel_bw_init_hw(struct intel_display *display) if (!HAS_DISPLAY(display)) return; - if (DISPLAY_VER(display) >= 30) + if (DISPLAY_VERx100(display) >= 3002) + tgl_get_bw_info(display, dram_info, &xe3lpd_3002_sa_info); + else if (DISPLAY_VER(display) >= 30) tgl_get_bw_info(display, dram_info, &xe3lpd_sa_info); else if (DISPLAY_VERx100(display) >= 1401 && display->platform.dgfx && dram_info->type == INTEL_DRAM_GDDR_ECC) @@ -865,6 +907,11 @@ static unsigned int intel_bw_data_rate(struct intel_display *display, return data_rate; } +struct intel_bw_state *to_intel_bw_state(struct intel_global_state *obj_state) +{ + return container_of(obj_state, struct intel_bw_state, base); +} + struct intel_bw_state * intel_atomic_get_old_bw_state(struct intel_atomic_state *state) { @@ -974,6 +1021,70 @@ static void icl_force_disable_sagv(struct intel_display *display, icl_pcode_restrict_qgv_points(display, bw_state->qgv_points_mask); } +void icl_sagv_pre_plane_update(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + const struct intel_bw_state *old_bw_state = + intel_atomic_get_old_bw_state(state); + const struct intel_bw_state *new_bw_state = + intel_atomic_get_new_bw_state(state); + u16 old_mask, new_mask; + + if (!new_bw_state) + return; + + old_mask = old_bw_state->qgv_points_mask; + new_mask = old_bw_state->qgv_points_mask | new_bw_state->qgv_points_mask; + + if (old_mask == new_mask) + return; + + WARN_ON(!new_bw_state->base.changed); + + drm_dbg_kms(display->drm, "Restricting QGV points: 0x%x -> 0x%x\n", + old_mask, new_mask); + + /* + * Restrict required qgv points before updating the configuration. + * According to BSpec we can't mask and unmask qgv points at the same + * time. Also masking should be done before updating the configuration + * and unmasking afterwards. + */ + icl_pcode_restrict_qgv_points(display, new_mask); +} + +void icl_sagv_post_plane_update(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + const struct intel_bw_state *old_bw_state = + intel_atomic_get_old_bw_state(state); + const struct intel_bw_state *new_bw_state = + intel_atomic_get_new_bw_state(state); + u16 old_mask, new_mask; + + if (!new_bw_state) + return; + + old_mask = old_bw_state->qgv_points_mask | new_bw_state->qgv_points_mask; + new_mask = new_bw_state->qgv_points_mask; + + if (old_mask == new_mask) + return; + + WARN_ON(!new_bw_state->base.changed); + + drm_dbg_kms(display->drm, "Relaxing QGV points: 0x%x -> 0x%x\n", + old_mask, new_mask); + + /* + * Allow required qgv points after updating the configuration. + * According to BSpec we can't mask and unmask qgv points at the same + * time. Also masking should be done before updating the configuration + * and unmasking afterwards. + */ + icl_pcode_restrict_qgv_points(display, new_mask); +} + static int mtl_find_qgv_points(struct intel_display *display, unsigned int data_rate, unsigned int num_active_planes, @@ -994,7 +1105,7 @@ static int mtl_find_qgv_points(struct intel_display *display, * for qgv peak bw in PM Demand request. So assign UINT_MAX if SAGV is * not enabled. PM Demand code will clamp the value for the register */ - if (!intel_can_enable_sagv(display, new_bw_state)) { + if (!intel_bw_can_enable_sagv(display, new_bw_state)) { new_bw_state->qgv_point_peakbw = U16_MAX; drm_dbg_kms(display->drm, "No SAGV, use UINT_MAX as peak bw."); return 0; @@ -1107,7 +1218,7 @@ static int icl_find_qgv_points(struct intel_display *display, * we can't enable SAGV due to the increased memory latency it may * cause. */ - if (!intel_can_enable_sagv(display, new_bw_state)) { + if (!intel_bw_can_enable_sagv(display, new_bw_state)) { qgv_points = icl_max_bw_qgv_point_mask(display, num_active_planes); drm_dbg_kms(display->drm, "No SAGV, using single QGV point mask 0x%x\n", qgv_points); @@ -1357,12 +1468,12 @@ int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, * requirements. This can reduce back and forth * display blinking due to constant cdclk changes. */ - if (new_min_cdclk <= cdclk_state->bw_min_cdclk) + if (new_min_cdclk <= intel_cdclk_bw_min_cdclk(cdclk_state)) return 0; drm_dbg_kms(display->drm, "new bandwidth min cdclk (%d kHz) > old min cdclk (%d kHz)\n", - new_min_cdclk, cdclk_state->bw_min_cdclk); + new_min_cdclk, intel_cdclk_bw_min_cdclk(cdclk_state)); *need_cdclk_calc = true; return 0; @@ -1474,8 +1585,8 @@ static int intel_bw_check_sagv_mask(struct intel_atomic_state *state) if (!new_bw_state) return 0; - if (intel_can_enable_sagv(display, new_bw_state) != - intel_can_enable_sagv(display, old_bw_state)) { + if (intel_bw_can_enable_sagv(display, new_bw_state) != + intel_bw_can_enable_sagv(display, old_bw_state)) { ret = intel_atomic_serialize_global_state(&new_bw_state->base); if (ret) return ret; @@ -1521,8 +1632,8 @@ int intel_bw_atomic_check(struct intel_atomic_state *state, bool any_ms) new_bw_state = intel_atomic_get_new_bw_state(state); if (new_bw_state && - intel_can_enable_sagv(display, old_bw_state) != - intel_can_enable_sagv(display, new_bw_state)) + intel_bw_can_enable_sagv(display, old_bw_state) != + intel_bw_can_enable_sagv(display, new_bw_state)) changed = true; /* @@ -1644,3 +1755,32 @@ int intel_bw_init(struct intel_display *display) return 0; } + +bool intel_bw_pmdemand_needs_update(struct intel_atomic_state *state) +{ + const struct intel_bw_state *new_bw_state, *old_bw_state; + + new_bw_state = intel_atomic_get_new_bw_state(state); + old_bw_state = intel_atomic_get_old_bw_state(state); + + if (new_bw_state && + new_bw_state->qgv_point_peakbw != old_bw_state->qgv_point_peakbw) + return true; + + return false; +} + +bool intel_bw_can_enable_sagv(struct intel_display *display, + const struct intel_bw_state *bw_state) +{ + if (DISPLAY_VER(display) < 11 && + bw_state->active_pipes && !is_power_of_2(bw_state->active_pipes)) + return false; + + return bw_state->pipe_sagv_reject == 0; +} + +int intel_bw_qgv_point_peakbw(const struct intel_bw_state *bw_state) +{ + return bw_state->qgv_point_peakbw; +} diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index eb2cc883e9c1..d51f50c9d302 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -8,52 +8,14 @@ #include <drm/drm_atomic.h> -#include "intel_display_limits.h" -#include "intel_display_power.h" -#include "intel_global_state.h" - struct intel_atomic_state; +struct intel_bw_state; struct intel_crtc; struct intel_crtc_state; struct intel_display; +struct intel_global_state; -struct intel_dbuf_bw { - unsigned int max_bw[I915_MAX_DBUF_SLICES]; - u8 active_planes[I915_MAX_DBUF_SLICES]; -}; - -struct intel_bw_state { - struct intel_global_state base; - struct intel_dbuf_bw dbuf_bw[I915_MAX_PIPES]; - - /* - * Contains a bit mask, used to determine, whether correspondent - * pipe allows SAGV or not. - */ - u8 pipe_sagv_reject; - - /* bitmask of active pipes */ - u8 active_pipes; - - /* - * From MTL onwards, to lock a QGV point, punit expects the peak BW of - * the selected QGV point as the parameter in multiples of 100MB/s - */ - u16 qgv_point_peakbw; - - /* - * Current QGV points mask, which restricts - * some particular SAGV states, not to confuse - * with pipe_sagv_mask. - */ - u16 qgv_points_mask; - - unsigned int data_rate[I915_MAX_PIPES]; - u8 num_active_planes[I915_MAX_PIPES]; -}; - -#define to_intel_bw_state(global_state) \ - container_of_const((global_state), struct intel_bw_state, base) +struct intel_bw_state *to_intel_bw_state(struct intel_global_state *obj_state); struct intel_bw_state * intel_atomic_get_old_bw_state(struct intel_atomic_state *state); @@ -67,8 +29,6 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state); void intel_bw_init_hw(struct intel_display *display); int intel_bw_init(struct intel_display *display); int intel_bw_atomic_check(struct intel_atomic_state *state, bool any_ms); -int icl_pcode_restrict_qgv_points(struct intel_display *display, - u32 points_mask); int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, bool *need_cdclk_calc); int intel_bw_min_cdclk(struct intel_display *display, @@ -76,4 +36,11 @@ int intel_bw_min_cdclk(struct intel_display *display, void intel_bw_update_hw_state(struct intel_display *display); void intel_bw_crtc_disable_noatomic(struct intel_crtc *crtc); +bool intel_bw_pmdemand_needs_update(struct intel_atomic_state *state); +bool intel_bw_can_enable_sagv(struct intel_display *display, + const struct intel_bw_state *bw_state); +void icl_sagv_pre_plane_update(struct intel_atomic_state *state); +void icl_sagv_post_plane_update(struct intel_atomic_state *state); +int intel_bw_qgv_point_peakbw(const struct intel_bw_state *bw_state); + #endif /* __INTEL_BW_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 38b3094b37d7..228aa64c1349 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -32,7 +32,6 @@ #include "i915_drv.h" #include "i915_reg.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" #include "intel_audio.h" #include "intel_bw.h" #include "intel_cdclk.h" @@ -43,6 +42,7 @@ #include "intel_mchbar_regs.h" #include "intel_pci_config.h" #include "intel_pcode.h" +#include "intel_plane.h" #include "intel_psr.h" #include "intel_vdsc.h" #include "skl_watermark.h" @@ -114,6 +114,42 @@ * dividers can be programmed correctly. */ +struct intel_cdclk_state { + struct intel_global_state base; + + /* + * Logical configuration of cdclk (used for all scaling, + * watermark, etc. calculations and checks). This is + * computed as if all enabled crtcs were active. + */ + struct intel_cdclk_config logical; + + /* + * Actual configuration of cdclk, can be different from the + * logical configuration only when all crtc's are DPMS off. + */ + struct intel_cdclk_config actual; + + /* minimum acceptable cdclk to satisfy bandwidth requirements */ + int bw_min_cdclk; + /* minimum acceptable cdclk for each pipe */ + int min_cdclk[I915_MAX_PIPES]; + /* minimum acceptable voltage level for each pipe */ + u8 min_voltage_level[I915_MAX_PIPES]; + + /* pipe to which cd2x update is synchronized */ + enum pipe pipe; + + /* forced minimum cdclk for glk+ audio w/a */ + int force_min_cdclk; + + /* bitmask of active pipes */ + u8 active_pipes; + + /* update cdclk with pipes disabled */ + bool disable_pipes; +}; + struct intel_cdclk_funcs { void (*get_cdclk)(struct intel_display *display, struct intel_cdclk_config *cdclk_config); @@ -841,7 +877,6 @@ static void bdw_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; int ret; @@ -854,7 +889,7 @@ static void bdw_set_cdclk(struct intel_display *display, "trying to change cdclk frequency with cdclk not enabled\n")) return; - ret = snb_pcode_write(&dev_priv->uncore, BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0); + ret = intel_pcode_write(display->drm, BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0); if (ret) { drm_err(display->drm, "failed to inform pcode about cdclk change\n"); @@ -882,8 +917,8 @@ static void bdw_set_cdclk(struct intel_display *display, LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) drm_err(display->drm, "Switching back to LCPLL failed\n"); - snb_pcode_write(&dev_priv->uncore, HSW_PCODE_DE_WRITE_FREQ_REQ, - cdclk_config->voltage_level); + intel_pcode_write(display->drm, HSW_PCODE_DE_WRITE_FREQ_REQ, + cdclk_config->voltage_level); intel_de_write(display, CDCLK_FREQ, DIV_ROUND_CLOSEST(cdclk, 1000) - 1); @@ -1123,7 +1158,6 @@ static void skl_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; int vco = cdclk_config->vco; u32 freq_select, cdclk_ctl; @@ -1140,10 +1174,10 @@ static void skl_set_cdclk(struct intel_display *display, drm_WARN_ON_ONCE(display->drm, display->platform.skylake && vco == 8640000); - ret = skl_pcode_request(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, - SKL_CDCLK_PREPARE_FOR_CHANGE, - SKL_CDCLK_READY_FOR_CHANGE, - SKL_CDCLK_READY_FOR_CHANGE, 3); + ret = intel_pcode_request(display->drm, SKL_PCODE_CDCLK_CONTROL, + SKL_CDCLK_PREPARE_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, 3); if (ret) { drm_err(display->drm, "Failed to inform PCU about cdclk change (%d)\n", ret); @@ -1186,8 +1220,8 @@ static void skl_set_cdclk(struct intel_display *display, intel_de_posting_read(display, CDCLK_CTL); /* inform PCU of the change */ - snb_pcode_write(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, - cdclk_config->voltage_level); + intel_pcode_write(display->drm, SKL_PCODE_CDCLK_CONTROL, + cdclk_config->voltage_level); intel_update_cdclk(display); } @@ -2123,7 +2157,6 @@ static void bxt_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); struct intel_cdclk_config mid_cdclk_config; int cdclk = cdclk_config->cdclk; int ret = 0; @@ -2137,18 +2170,18 @@ static void bxt_set_cdclk(struct intel_display *display, if (DISPLAY_VER(display) >= 14 || display->platform.dg2) ; /* NOOP */ else if (DISPLAY_VER(display) >= 11) - ret = skl_pcode_request(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, - SKL_CDCLK_PREPARE_FOR_CHANGE, - SKL_CDCLK_READY_FOR_CHANGE, - SKL_CDCLK_READY_FOR_CHANGE, 3); + ret = intel_pcode_request(display->drm, SKL_PCODE_CDCLK_CONTROL, + SKL_CDCLK_PREPARE_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, 3); else /* * BSpec requires us to wait up to 150usec, but that leads to * timeouts; the 2ms used here is based on experiment. */ - ret = snb_pcode_write_timeout(&dev_priv->uncore, - HSW_PCODE_DE_WRITE_FREQ_REQ, - 0x80000000, 150, 2); + ret = intel_pcode_write_timeout(display->drm, + HSW_PCODE_DE_WRITE_FREQ_REQ, + 0x80000000, 2); if (ret) { drm_err(display->drm, @@ -2177,8 +2210,8 @@ static void bxt_set_cdclk(struct intel_display *display, * Display versions 14 and beyond */; else if (DISPLAY_VER(display) >= 11 && !display->platform.dg2) - ret = snb_pcode_write(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, - cdclk_config->voltage_level); + ret = intel_pcode_write(display->drm, SKL_PCODE_CDCLK_CONTROL, + cdclk_config->voltage_level); if (DISPLAY_VER(display) < 11) { /* * The timeout isn't specified, the 2ms used here is based on @@ -2186,10 +2219,9 @@ static void bxt_set_cdclk(struct intel_display *display, * FIXME: Waiting for the request completion could be delayed * until the next PCODE request based on BSpec. */ - ret = snb_pcode_write_timeout(&dev_priv->uncore, - HSW_PCODE_DE_WRITE_FREQ_REQ, - cdclk_config->voltage_level, - 150, 2); + ret = intel_pcode_write_timeout(display->drm, + HSW_PCODE_DE_WRITE_FREQ_REQ, + cdclk_config->voltage_level, 2); } if (ret) { drm_err(display->drm, @@ -2475,7 +2507,6 @@ static void intel_pcode_notify(struct intel_display *display, bool cdclk_update_valid, bool pipe_count_update_valid) { - struct drm_i915_private *i915 = to_i915(display->drm); int ret; u32 update_mask = 0; @@ -2490,11 +2521,11 @@ static void intel_pcode_notify(struct intel_display *display, if (pipe_count_update_valid) update_mask |= DISPLAY_TO_PCODE_PIPE_COUNT_VALID; - ret = skl_pcode_request(&i915->uncore, SKL_PCODE_CDCLK_CONTROL, - SKL_CDCLK_PREPARE_FOR_CHANGE | - update_mask, - SKL_CDCLK_READY_FOR_CHANGE, - SKL_CDCLK_READY_FOR_CHANGE, 3); + ret = intel_pcode_request(display->drm, SKL_PCODE_CDCLK_CONTROL, + SKL_CDCLK_PREPARE_FOR_CHANGE | + update_mask, + SKL_CDCLK_READY_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, 3); if (ret) drm_err(display->drm, "Failed to inform PCU about display config (err %d)\n", @@ -3386,7 +3417,9 @@ static int intel_compute_max_dotclk(struct intel_display *display) */ void intel_update_max_cdclk(struct intel_display *display) { - if (DISPLAY_VER(display) >= 30) { + if (DISPLAY_VERx100(display) >= 3002) { + display->cdclk.max_cdclk_freq = 480000; + } else if (DISPLAY_VER(display) >= 30) { display->cdclk.max_cdclk_freq = 691200; } else if (display->platform.jasperlake || display->platform.elkhartlake) { if (display->cdclk.hw.ref == 24000) @@ -3837,3 +3870,60 @@ void intel_init_cdclk_hooks(struct intel_display *display) "Unknown platform. Assuming i830\n")) display->funcs.cdclk = &i830_cdclk_funcs; } + +int intel_cdclk_logical(const struct intel_cdclk_state *cdclk_state) +{ + return cdclk_state->logical.cdclk; +} + +int intel_cdclk_actual(const struct intel_cdclk_state *cdclk_state) +{ + return cdclk_state->actual.cdclk; +} + +int intel_cdclk_actual_voltage_level(const struct intel_cdclk_state *cdclk_state) +{ + return cdclk_state->actual.voltage_level; +} + +int intel_cdclk_min_cdclk(const struct intel_cdclk_state *cdclk_state, enum pipe pipe) +{ + return cdclk_state->min_cdclk[pipe]; +} + +int intel_cdclk_bw_min_cdclk(const struct intel_cdclk_state *cdclk_state) +{ + return cdclk_state->bw_min_cdclk; +} + +bool intel_cdclk_pmdemand_needs_update(struct intel_atomic_state *state) +{ + const struct intel_cdclk_state *new_cdclk_state, *old_cdclk_state; + + new_cdclk_state = intel_atomic_get_new_cdclk_state(state); + old_cdclk_state = intel_atomic_get_old_cdclk_state(state); + + if (new_cdclk_state && + (new_cdclk_state->actual.cdclk != old_cdclk_state->actual.cdclk || + new_cdclk_state->actual.voltage_level != old_cdclk_state->actual.voltage_level)) + return true; + + return false; +} + +void intel_cdclk_force_min_cdclk(struct intel_cdclk_state *cdclk_state, int force_min_cdclk) +{ + cdclk_state->force_min_cdclk = force_min_cdclk; +} + +void intel_cdclk_read_hw(struct intel_display *display) +{ + struct intel_cdclk_state *cdclk_state; + + cdclk_state = to_intel_cdclk_state(display->cdclk.obj.state); + + intel_update_cdclk(display); + intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK"); + cdclk_state->actual = display->cdclk.hw; + cdclk_state->logical = display->cdclk.hw; +} diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h index a1cefd455d92..cacee598af0e 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.h +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h @@ -8,10 +8,9 @@ #include <linux/types.h> -#include "intel_display_limits.h" -#include "intel_global_state.h" - +enum pipe; struct intel_atomic_state; +struct intel_cdclk_state; struct intel_crtc; struct intel_crtc_state; struct intel_display; @@ -23,42 +22,6 @@ struct intel_cdclk_config { bool joined_mbus; }; -struct intel_cdclk_state { - struct intel_global_state base; - - /* - * Logical configuration of cdclk (used for all scaling, - * watermark, etc. calculations and checks). This is - * computed as if all enabled crtcs were active. - */ - struct intel_cdclk_config logical; - - /* - * Actual configuration of cdclk, can be different from the - * logical configuration only when all crtc's are DPMS off. - */ - struct intel_cdclk_config actual; - - /* minimum acceptable cdclk to satisfy bandwidth requirements */ - int bw_min_cdclk; - /* minimum acceptable cdclk for each pipe */ - int min_cdclk[I915_MAX_PIPES]; - /* minimum acceptable voltage level for each pipe */ - u8 min_voltage_level[I915_MAX_PIPES]; - - /* pipe to which cd2x update is synchronized */ - enum pipe pipe; - - /* forced minimum cdclk for glk+ audio w/a */ - int force_min_cdclk; - - /* bitmask of active pipes */ - u8 active_pipes; - - /* update cdclk with pipes disabled */ - bool disable_pipes; -}; - void intel_cdclk_init_hw(struct intel_display *display); void intel_cdclk_uninit_hw(struct intel_display *display); void intel_init_cdclk_hooks(struct intel_display *display); @@ -97,4 +60,13 @@ void intel_cdclk_crtc_disable_noatomic(struct intel_crtc *crtc); int intel_cdclk_init(struct intel_display *display); void intel_cdclk_debugfs_register(struct intel_display *display); +int intel_cdclk_logical(const struct intel_cdclk_state *cdclk_state); +int intel_cdclk_actual(const struct intel_cdclk_state *cdclk_state); +int intel_cdclk_actual_voltage_level(const struct intel_cdclk_state *cdclk_state); +int intel_cdclk_min_cdclk(const struct intel_cdclk_state *cdclk_state, enum pipe pipe); +int intel_cdclk_bw_min_cdclk(const struct intel_cdclk_state *cdclk_state); +bool intel_cdclk_pmdemand_needs_update(struct intel_atomic_state *state); +void intel_cdclk_force_min_cdclk(struct intel_cdclk_state *cdclk_state, int force_min_cdclk); +void intel_cdclk_read_hw(struct intel_display *display); + #endif /* __INTEL_CDCLK_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index 2867d76d1a5e..42c923f416b3 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -64,10 +64,10 @@ static void intel_connector_modeset_retry_work_fn(struct work_struct *work) void intel_connector_queue_modeset_retry_work(struct intel_connector *connector) { - struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_display *display = to_intel_display(connector); drm_connector_get(&connector->base); - if (!queue_work(i915->unordered_wq, &connector->modeset_retry_work)) + if (!queue_work(display->wq.unordered, &connector->modeset_retry_work)) drm_connector_put(&connector->base); } diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index a88317ea4e9c..a187db6df2d3 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -17,7 +17,6 @@ #include "i9xx_plane.h" #include "icl_dsi.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" #include "intel_color.h" #include "intel_crtc.h" #include "intel_cursor.h" @@ -29,6 +28,7 @@ #include "intel_dsi.h" #include "intel_fifo_underrun.h" #include "intel_pipe_crc.h" +#include "intel_plane.h" #include "intel_psr.h" #include "intel_sprite.h" #include "intel_vblank.h" diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 6bd4f6a28cae..198e69efe9ac 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -14,7 +14,6 @@ #include "i915_utils.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" #include "intel_cursor.h" #include "intel_cursor_regs.h" #include "intel_de.h" @@ -23,6 +22,7 @@ #include "intel_fb.h" #include "intel_fb_pin.h" #include "intel_frontbuffer.h" +#include "intel_plane.h" #include "intel_psr.h" #include "intel_psr_regs.h" #include "intel_vblank.h" @@ -158,10 +158,10 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state, return -EINVAL; } - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - true); + ret = intel_plane_check_clipping(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + true); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 83c8df9dbc0c..801235a5bc0a 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -39,7 +39,13 @@ 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); - if (display->platform.pantherlake && phy == PHY_A) + /* 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.lunarlake || display->platform.meteorlake) && phy < PHY_C) @@ -3233,14 +3239,22 @@ void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(encoder); - u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(encoder); - bool enable = intel_alpm_is_alpm_aux_less(enc_to_intel_dp(encoder), - crtc_state); + intel_wakeref_t wakeref; int i; + u8 owned_lane_mask; - if (DISPLAY_VER(display) < 20) + if (DISPLAY_VER(display) < 20 || + !intel_alpm_is_alpm_aux_less(enc_to_intel_dp(encoder), crtc_state)) return; + owned_lane_mask = intel_cx0_get_owned_lane_mask(encoder); + + wakeref = intel_cx0_phy_transaction_begin(encoder); + + if (intel_encoder_is_c10phy(encoder)) + intel_cx0_rmw(encoder, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, + C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); + for (i = 0; i < 4; i++) { int tx = i % 2 + 1; u8 lane_mask = i < 2 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; @@ -3250,9 +3264,10 @@ void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder, intel_cx0_rmw(encoder, lane_mask, PHY_CMN1_CONTROL(tx, 0), CONTROL0_MAC_TRANSMIT_LFPS, - enable ? CONTROL0_MAC_TRANSMIT_LFPS : 0, - MB_WRITE_COMMITTED); + CONTROL0_MAC_TRANSMIT_LFPS, MB_WRITE_COMMITTED); } + + intel_cx0_phy_transaction_end(encoder, wakeref); } static u8 cx0_power_control_disable_val(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index cbd1060e9664..0405396c7750 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -73,11 +73,13 @@ #include "intel_lspcon.h" #include "intel_mg_phy_regs.h" #include "intel_modeset_lock.h" +#include "intel_panel.h" #include "intel_pfit.h" #include "intel_pps.h" #include "intel_psr.h" #include "intel_quirks.h" #include "intel_snps_phy.h" +#include "intel_step.h" #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vdsc_regs.h" @@ -1394,6 +1396,21 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < 2; ln++) { int level; + /* Wa_16011342517:adl-p */ + if (display->platform.alderlake_p && + IS_DISPLAY_STEP(display, STEP_A0, STEP_D0)) { + if ((intel_encoder_is_hdmi(encoder) && + crtc_state->port_clock == 594000) || + (intel_encoder_is_dp(encoder) && + crtc_state->port_clock == 162000)) { + intel_dkl_phy_rmw(display, DKL_TX_DPCNTL2(tc_port, ln), + LOADGEN_SHARING_PMD_DISABLE, 1); + } else { + intel_dkl_phy_rmw(display, DKL_TX_DPCNTL2(tc_port, ln), + LOADGEN_SHARING_PMD_DISABLE, 0); + } + } + intel_dkl_phy_write(display, DKL_TX_PMD_LANE_SUS(tc_port, ln), 0); level = intel_ddi_level(encoder, crtc_state, 2*ln+0); @@ -3355,6 +3372,8 @@ static void intel_ddi_enable_dp(struct intel_atomic_state *state, drm_connector_update_privacy_screen(conn_state); intel_edp_backlight_on(crtc_state, conn_state); + intel_panel_prepare(crtc_state, conn_state); + if (!intel_lspcon_active(dig_port) || intel_dp_has_hdmi_sink(&dig_port->dp)) intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); @@ -3552,6 +3571,7 @@ static void intel_ddi_disable_dp(struct intel_atomic_state *state, intel_dp->link.active = false; + intel_panel_unprepare(old_conn_state); intel_psr_disable(intel_dp, old_crtc_state); intel_alpm_disable(intel_dp); intel_edp_backlight_off(old_conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 6ec786198f43..7035c1fc9033 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -57,7 +57,6 @@ #include "i9xx_wm.h" #include "intel_alpm.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" #include "intel_audio.h" #include "intel_bo.h" #include "intel_bw.h" @@ -94,6 +93,7 @@ #include "intel_fbc.h" #include "intel_fdi.h" #include "intel_fifo_underrun.h" +#include "intel_flipq.h" #include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_hotplug.h" @@ -108,6 +108,7 @@ #include "intel_pch_refclk.h" #include "intel_pfit.h" #include "intel_pipe_crc.h" +#include "intel_plane.h" #include "intel_plane_initial.h" #include "intel_pmdemand.h" #include "intel_pps.h" @@ -1659,8 +1660,12 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, if (drm_WARN_ON(display->drm, crtc->active)) return; - for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) - intel_dmc_enable_pipe(display, pipe_crtc->pipe); + for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) { + const struct intel_crtc_state *new_pipe_crtc_state = + intel_atomic_get_new_crtc_state(state, pipe_crtc); + + intel_dmc_enable_pipe(new_pipe_crtc_state); + } intel_encoders_pre_pll_enable(state, crtc); @@ -1798,8 +1803,12 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, intel_encoders_post_pll_disable(state, crtc); - for_each_pipe_crtc_modeset_disable(display, pipe_crtc, old_crtc_state, i) - intel_dmc_disable_pipe(display, pipe_crtc->pipe); + for_each_pipe_crtc_modeset_disable(display, pipe_crtc, old_crtc_state, i) { + const struct intel_crtc_state *old_pipe_crtc_state = + intel_atomic_get_old_crtc_state(state, pipe_crtc); + + intel_dmc_disable_pipe(old_pipe_crtc_state); + } } /* Prefer intel_encoder_is_combo() */ @@ -4160,7 +4169,7 @@ static u16 hsw_ips_linetime_wm(const struct intel_crtc_state *crtc_state, return 0; linetime_wm = DIV_ROUND_CLOSEST(pipe_mode->crtc_htotal * 1000 * 8, - cdclk_state->logical.cdclk); + intel_cdclk_logical(cdclk_state)); return min(linetime_wm, 0x1ff); } @@ -5479,7 +5488,7 @@ static int intel_modeset_pipe(struct intel_atomic_state *state, if (ret) return ret; - ret = intel_atomic_add_affected_planes(state, crtc); + ret = intel_plane_add_affected(state, crtc); if (ret) return ret; @@ -6195,7 +6204,7 @@ static int intel_joiner_add_affected_crtcs(struct intel_atomic_state *state) if (ret) return ret; - ret = intel_atomic_add_affected_planes(state, crtc); + ret = intel_plane_add_affected(state, crtc); if (ret) return ret; } @@ -6447,7 +6456,7 @@ int intel_atomic_check(struct drm_device *dev, goto fail; } - ret = intel_atomic_check_planes(state); + ret = intel_plane_atomic_check(state); if (ret) goto fail; @@ -6611,7 +6620,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); bool modeset = intel_crtc_needs_modeset(new_crtc_state); - drm_WARN_ON(display->drm, new_crtc_state->use_dsb); + drm_WARN_ON(display->drm, new_crtc_state->use_dsb || new_crtc_state->use_flipq); /* * During modesets pipe configuration was programmed as the @@ -6641,7 +6650,7 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); bool modeset = intel_crtc_needs_modeset(new_crtc_state); - drm_WARN_ON(display->drm, new_crtc_state->use_dsb); + drm_WARN_ON(display->drm, new_crtc_state->use_dsb || new_crtc_state->use_flipq); /* * Disable the scaler(s) after the plane(s) so that we don't @@ -6730,10 +6739,10 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state, if (!modeset && intel_crtc_needs_color_update(new_crtc_state) && - !new_crtc_state->use_dsb) + !new_crtc_state->use_dsb && !new_crtc_state->use_flipq) intel_color_commit_noarm(NULL, new_crtc_state); - if (!new_crtc_state->use_dsb) + if (!new_crtc_state->use_dsb && !new_crtc_state->use_flipq) intel_crtc_planes_update_noarm(NULL, state, crtc); } @@ -6745,7 +6754,14 @@ static void intel_update_crtc(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - if (new_crtc_state->use_dsb) { + if (new_crtc_state->use_flipq) { + intel_flipq_enable(new_crtc_state); + + intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->flipq_event); + + intel_flipq_add(crtc, INTEL_FLIPQ_PLANE_1, 0, INTEL_DSB_0, + new_crtc_state->dsb_commit); + } else if (new_crtc_state->use_dsb) { intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->dsb_event); intel_dsb_commit(new_crtc_state->dsb_commit); @@ -7076,7 +7092,8 @@ static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_stat struct drm_i915_private *i915 = to_i915(intel_state->base.dev); struct drm_plane *plane; struct drm_plane_state *new_plane_state; - int ret, i; + long ret; + int i; for_each_new_plane_in_state(&intel_state->base, plane, new_plane_state, i) { if (new_plane_state->fence) { @@ -7183,7 +7200,17 @@ static void intel_atomic_dsb_prepare(struct intel_atomic_state *state, return; /* FIXME deal with everything */ + new_crtc_state->use_flipq = + intel_flipq_supported(display) && + !new_crtc_state->do_async_flip && + !new_crtc_state->vrr.enable && + !new_crtc_state->has_psr && + !intel_crtc_needs_modeset(new_crtc_state) && + !intel_crtc_needs_fastset(new_crtc_state) && + !intel_crtc_needs_color_update(new_crtc_state); + new_crtc_state->use_dsb = + !new_crtc_state->use_flipq && !new_crtc_state->do_async_flip && (DISPLAY_VER(display) >= 20 || !new_crtc_state->has_psr) && !intel_crtc_needs_modeset(new_crtc_state) && @@ -7199,7 +7226,9 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - if (!new_crtc_state->use_dsb && !new_crtc_state->dsb_color) + if (!new_crtc_state->use_flipq && + !new_crtc_state->use_dsb && + !new_crtc_state->dsb_color) return; /* @@ -7208,14 +7237,20 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, * Double that for pipe stuff and other overhead. */ new_crtc_state->dsb_commit = intel_dsb_prepare(state, crtc, INTEL_DSB_0, - new_crtc_state->use_dsb ? 1024 : 16); + new_crtc_state->use_dsb || + new_crtc_state->use_flipq ? 1024 : 16); if (!new_crtc_state->dsb_commit) { + new_crtc_state->use_flipq = false; new_crtc_state->use_dsb = false; intel_color_cleanup_commit(new_crtc_state); return; } - if (new_crtc_state->use_dsb) { + if (new_crtc_state->use_flipq || new_crtc_state->use_dsb) { + /* Wa_18034343758 */ + if (new_crtc_state->use_flipq) + intel_flipq_wait_dmc_halt(new_crtc_state->dsb_commit, crtc); + if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_noarm(new_crtc_state->dsb_commit, new_crtc_state); @@ -7230,7 +7265,8 @@ 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_dsb_vblank_evade(state, new_crtc_state->dsb_commit); + if (new_crtc_state->use_dsb) + intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit); if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_arm(new_crtc_state->dsb_commit, @@ -7245,6 +7281,10 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, if (DISPLAY_VER(display) >= 9) skl_detach_scalers(new_crtc_state->dsb_commit, new_crtc_state); + + /* Wa_18034343758 */ + if (new_crtc_state->use_flipq) + intel_flipq_unhalt_dmc(new_crtc_state->dsb_commit, crtc); } if (intel_color_uses_chained_dsb(new_crtc_state)) @@ -7385,6 +7425,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) /* Now enable the clocks, plane, pipe, and connectors that we set up. */ display->funcs.display->commit_modeset_enables(state); + /* FIXME probably need to sequence this properly */ intel_program_dpkgc_latency(state); intel_wait_for_vblank_workers(state); @@ -7408,6 +7449,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) if (!state->base.legacy_cursor_update && !new_crtc_state->use_dsb) intel_vrr_check_push_sent(NULL, new_crtc_state); + + if (new_crtc_state->use_flipq) + intel_flipq_disable(new_crtc_state); } /* diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 32cb0e59c81e..8c226406c5cd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -480,6 +480,12 @@ struct intel_display { } irq; struct { + /* protected by wm.wm_mutex */ + u16 linetime[I915_MAX_PIPES]; + bool disable[I915_MAX_PIPES]; + } pkgc; + + struct { wait_queue_head_t waitqueue; /* mutex to protect pmdemand programming sequence */ @@ -570,6 +576,9 @@ struct intel_display { /* hipri wq for commit cleanups */ struct workqueue_struct *cleanup; + + /* unordered workqueue for all display unordered work */ + struct workqueue_struct *unordered; } wq; /* Grouping using named structs. Keep sorted. */ diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index a4070f40e26f..089cffabbad5 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1480,6 +1480,7 @@ static const struct { { 14, 1, &xe2_hpd_display }, { 20, 0, &xe2_lpd_display }, { 30, 0, &xe2_lpd_display }, + { 30, 2, &xe2_lpd_display }, }; static const struct intel_display_device_info * diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 0ac5484c0043..4308822f0415 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -192,9 +192,8 @@ struct intel_display_platforms { #define HAS_TRANSCODER(__display, trans) ((DISPLAY_RUNTIME_INFO(__display)->cpu_transcoder_mask & \ BIT(trans)) != 0) #define HAS_UNCOMPRESSED_JOINER(__display) (DISPLAY_VER(__display) >= 13) -#define HAS_ULTRAJOINER(__display) ((DISPLAY_VER(__display) >= 20 || \ - ((__display)->platform.dgfx && DISPLAY_VER(__display) == 14)) && \ - HAS_DSC(__display)) +#define HAS_ULTRAJOINER(__display) (((__display)->platform.dgfx && \ + DISPLAY_VER(__display) == 14) && HAS_DSC(__display)) #define HAS_VRR(__display) (DISPLAY_VER(__display) >= 11) #define INTEL_NUM_PIPES(__display) (hweight8(DISPLAY_RUNTIME_INFO(__display)->pipe_mask)) #define OVERLAY_NEEDS_PHYSICAL(__display) (DISPLAY_INFO(__display)->overlay_needs_physical) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index ec799a1773e4..8586ba102605 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -44,6 +44,7 @@ #include "intel_fbc.h" #include "intel_fbdev.h" #include "intel_fdi.h" +#include "intel_flipq.h" #include "intel_gmbus.h" #include "intel_hdcp.h" #include "intel_hotplug.h" @@ -84,16 +85,10 @@ bool intel_display_driver_probe_defer(struct pci_dev *pdev) void intel_display_driver_init_hw(struct intel_display *display) { - struct intel_cdclk_state *cdclk_state; - if (!HAS_DISPLAY(display)) return; - cdclk_state = to_intel_cdclk_state(display->cdclk.obj.state); - - intel_update_cdclk(display); - intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK"); - cdclk_state->logical = cdclk_state->actual = display->cdclk.hw; + intel_cdclk_read_hw(display); intel_display_wa_apply(display); } @@ -242,8 +237,6 @@ int intel_display_driver_probe_noirq(struct intel_display *display) if (!HAS_DISPLAY(display)) return 0; - intel_dmc_init(display); - display->hotplug.dp_wq = alloc_ordered_workqueue("intel-dp", 0); if (!display->hotplug.dp_wq) { ret = -ENOMEM; @@ -269,27 +262,35 @@ int intel_display_driver_probe_noirq(struct intel_display *display) goto cleanup_wq_flip; } + display->wq.unordered = alloc_workqueue("display_unordered", 0, 0); + if (!display->wq.unordered) { + ret = -ENOMEM; + goto cleanup_wq_cleanup; + } + + intel_dmc_init(display); + intel_mode_config_init(display); ret = intel_cdclk_init(display); if (ret) - goto cleanup_wq_cleanup; + goto cleanup_wq_unordered; ret = intel_color_init(display); if (ret) - goto cleanup_wq_cleanup; + goto cleanup_wq_unordered; ret = intel_dbuf_init(display); if (ret) - goto cleanup_wq_cleanup; + goto cleanup_wq_unordered; ret = intel_bw_init(display); if (ret) - goto cleanup_wq_cleanup; + goto cleanup_wq_unordered; ret = intel_pmdemand_init(display); if (ret) - goto cleanup_wq_cleanup; + goto cleanup_wq_unordered; intel_init_quirks(display); @@ -297,6 +298,8 @@ int intel_display_driver_probe_noirq(struct intel_display *display) return 0; +cleanup_wq_unordered: + destroy_workqueue(display->wq.unordered); cleanup_wq_cleanup: destroy_workqueue(display->wq.cleanup); cleanup_wq_flip: @@ -535,6 +538,8 @@ int intel_display_driver_probe(struct intel_display *display) */ intel_hdcp_component_init(display); + intel_flipq_init(display); + /* * Force all active planes to recompute their states. So that on * mode_setcrtc after probe, all the intel_plane_state variables @@ -600,6 +605,7 @@ void intel_display_driver_remove(struct intel_display *display) flush_workqueue(display->wq.flip); flush_workqueue(display->wq.modeset); flush_workqueue(display->wq.cleanup); + flush_workqueue(display->wq.unordered); /* * MST topology needs to be suspended so we don't have any calls to @@ -612,8 +618,6 @@ void intel_display_driver_remove(struct intel_display *display) /* part #2: call after irq uninstall */ void intel_display_driver_remove_noirq(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - if (!HAS_DISPLAY(display)) return; @@ -628,7 +632,7 @@ void intel_display_driver_remove_noirq(struct intel_display *display) intel_unregister_dsm_handler(); /* flush any delayed tasks or pending work */ - flush_workqueue(i915->unordered_wq); + flush_workqueue(display->wq.unordered); intel_hdcp_component_fini(display); @@ -644,6 +648,7 @@ void intel_display_driver_remove_noirq(struct intel_display *display) destroy_workqueue(display->wq.flip); destroy_workqueue(display->wq.modeset); destroy_workqueue(display->wq.cleanup); + destroy_workqueue(display->wq.unordered); intel_fbc_cleanup(display); } diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 8d0dcf252bed..68157f177b6a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -9,7 +9,6 @@ #include "i915_irq.h" #include "i915_reg.h" #include "icl_dsi_regs.h" -#include "intel_atomic_plane.h" #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_irq.h" @@ -27,6 +26,7 @@ #include "intel_gmbus.h" #include "intel_hotplug_irq.h" #include "intel_pipe_crc_regs.h" +#include "intel_plane.h" #include "intel_pmdemand.h" #include "intel_psr.h" #include "intel_psr_regs.h" @@ -1506,10 +1506,14 @@ u32 gen11_gu_misc_irq_ack(struct intel_display *display, const u32 master_ctl) if (!(master_ctl & GEN11_GU_MISC_IRQ)) return 0; + intel_display_rpm_assert_block(display); + iir = intel_de_read(display, GEN11_GU_MISC_IIR); if (likely(iir)) intel_de_write(display, GEN11_GU_MISC_IIR, iir); + intel_display_rpm_assert_unblock(display); + return iir; } diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index c4f1ab43fc0c..75316247ee8a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -62,6 +62,9 @@ intel_display_param_named_unsafe(enable_dpt, bool, 0400, intel_display_param_named_unsafe(enable_dsb, bool, 0400, "Enable display state buffer (DSB) (default: true)"); +intel_display_param_named_unsafe(enable_flipq, bool, 0400, + "Enable DMC flip queue (default: false)"); + intel_display_param_named_unsafe(enable_sagv, bool, 0400, "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 5317138e6044..784e6bae8615 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -31,6 +31,7 @@ struct drm_printer; param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ param(bool, enable_dsb, true, 0600) \ + param(bool, enable_flipq, false, 0600) \ param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ param(bool, enable_ips, true, 0600) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index fe3a8e90b97a..273054c22325 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1257,10 +1257,8 @@ static u32 hsw_read_dcomp(struct intel_display *display) static void hsw_write_dcomp(struct intel_display *display, u32 val) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - if (display->platform.haswell) { - if (snb_pcode_write(&dev_priv->uncore, GEN6_PCODE_WRITE_D_COMP, val)) + if (intel_pcode_write(display->drm, GEN6_PCODE_WRITE_D_COMP, val)) drm_dbg_kms(display->drm, "Failed to write to D_COMP\n"); } else { intel_de_write(display, D_COMP_BDW, val); 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 cba96f920fd2..48cac225a809 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -34,6 +34,18 @@ #include "vlv_iosf_sb_reg.h" #include "vlv_sideband.h" +/* + * PG0 is HW controlled, so doesn't have a corresponding power well control knob + * + * {ICL,SKL}_DISP_PW1_IDX..{ICL,SKL}_DISP_PW4_IDX -> PG1..PG4 + */ +static enum skl_power_gate pw_idx_to_pg(struct intel_display *display, int pw_idx) +{ + int pw1_idx = DISPLAY_VER(display) >= 11 ? ICL_PW_CTL_IDX_PW_1 : SKL_PW_CTL_IDX_PW_1; + + return pw_idx - pw1_idx + SKL_PG1; +} + struct i915_power_well_regs { i915_reg_t bios; i915_reg_t driver; @@ -308,8 +320,8 @@ static void hsw_wait_for_power_well_disable(struct intel_display *display, { const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = i915_power_well_instance(power_well)->hsw.idx; - bool disabled; u32 reqs; + int ret; /* * Bspec doesn't require waiting for PWs to get disabled, but still do @@ -320,12 +332,18 @@ static void hsw_wait_for_power_well_disable(struct intel_display *display, * Skip the wait in case any of the request bits are set and print a * diagnostic message. */ - wait_for((disabled = !(intel_de_read(display, regs->driver) & - HSW_PWR_WELL_CTL_STATE(pw_idx))) || - (reqs = hsw_power_well_requesters(display, regs, pw_idx)), 1); - if (disabled) + reqs = hsw_power_well_requesters(display, regs, pw_idx); + + ret = intel_de_wait_for_clear(display, regs->driver, + HSW_PWR_WELL_CTL_STATE(pw_idx), + reqs ? 0 : 1); + if (!ret) return; + /* Refresh requesters in case they popped up during the wait. */ + if (!reqs) + reqs = hsw_power_well_requesters(display, regs, pw_idx); + drm_dbg_kms(display->drm, "%s forced on (bios:%d driver:%d kvmr:%d debug:%d)\n", intel_power_well_name(power_well), @@ -350,8 +368,7 @@ static void hsw_power_well_enable(struct intel_display *display, if (power_well->desc->has_fuses) { enum skl_power_gate pg; - pg = DISPLAY_VER(display) >= 11 ? ICL_PW_CTL_IDX_TO_PG(pw_idx) : - SKL_PW_CTL_IDX_TO_PG(pw_idx); + pg = pw_idx_to_pg(display, pw_idx); /* Wa_16013190616:adlp */ if (display->platform.alderlake_p && pg == SKL_PG1) @@ -375,8 +392,8 @@ static void hsw_power_well_enable(struct intel_display *display, if (power_well->desc->has_fuses) { enum skl_power_gate pg; - pg = DISPLAY_VER(display) >= 11 ? ICL_PW_CTL_IDX_TO_PG(pw_idx) : - SKL_PW_CTL_IDX_TO_PG(pw_idx); + pg = pw_idx_to_pg(display, pw_idx); + gen9_wait_for_power_well_fuses(display, pg); } @@ -486,8 +503,7 @@ static void icl_tc_cold_exit(struct intel_display *display) int ret, tries = 0; while (1) { - ret = snb_pcode_write_timeout(&i915->uncore, ICL_PCODE_EXIT_TCCOLD, 0, - 250, 1); + ret = intel_pcode_write(display->drm, ICL_PCODE_EXIT_TCCOLD, 0); if (ret != -EAGAIN || ++tries == 3) break; msleep(1); @@ -829,7 +845,7 @@ static void assert_can_enable_dc5(struct intel_display *display) assert_display_rpm_held(display); - assert_dmc_loaded(display); + assert_main_dmc_loaded(display); } void gen9_enable_dc5(struct intel_display *display) @@ -860,7 +876,7 @@ static void assert_can_enable_dc6(struct intel_display *display) DC_STATE_EN_UPTO_DC6), "DC6 already programmed to be enabled.\n"); - assert_dmc_loaded(display); + assert_main_dmc_loaded(display); } void skl_enable_dc6(struct intel_display *display) @@ -1766,7 +1782,7 @@ tgl_tc_cold_request(struct intel_display *display, bool block) * Spec states that we should timeout the request after 200us * but the function below will timeout after 500us */ - ret = snb_pcode_read(&i915->uncore, TGL_PCODE_TCCOLD, &low_val, &high_val); + ret = intel_pcode_read(display->drm, TGL_PCODE_TCCOLD, &low_val, &high_val); if (ret == 0) { if (block && (low_val & TGL_PCODE_EXIT_TCCOLD_DATA_L_EXIT_FAILED)) diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h index e101105da4af..7bd09d981cd2 100644 --- a/drivers/gpu/drm/i915/display/intel_display_regs.h +++ b/drivers/gpu/drm/i915/display/intel_display_regs.h @@ -2195,20 +2195,17 @@ #define HSW_PWR_WELL_FORCE_ON (1 << 19) #define HSW_PWR_WELL_CTL6 _MMIO(0x45414) +/* SKL Fuse Status */ +enum skl_power_gate { + SKL_PG0, + SKL_PG1, + SKL_PG2, + ICL_PG3, + ICL_PG4, +}; + #define SKL_FUSE_STATUS _MMIO(0x42000) #define SKL_FUSE_DOWNLOAD_STATUS (1 << 31) -/* - * PG0 is HW controlled, so doesn't have a corresponding power well control knob - * SKL_DISP_PW1_IDX..SKL_DISP_PW2_IDX -> PG1..PG2 - */ -#define SKL_PW_CTL_IDX_TO_PG(pw_idx) \ - ((pw_idx) - SKL_PW_CTL_IDX_PW_1 + SKL_PG1) -/* - * PG0 is HW controlled, so doesn't have a corresponding power well control knob - * ICL_DISP_PW1_IDX..ICL_DISP_PW4_IDX -> PG1..PG4 - */ -#define ICL_PW_CTL_IDX_TO_PG(pw_idx) \ - ((pw_idx) - ICL_PW_CTL_IDX_PW_1 + SKL_PG1) #define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) /* Per-pipe DDI Function Control */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 30c7315fc25e..ce45261c4a8f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -146,6 +146,8 @@ struct intel_framebuffer { unsigned int min_alignment; unsigned int vtd_guard; + + unsigned int (*panic_tiling)(unsigned int x, unsigned int y, unsigned int width); }; enum intel_hotplug_state { @@ -1303,6 +1305,7 @@ struct intel_crtc_state { /* For DSB based pipe updates */ struct intel_dsb *dsb_color, *dsb_commit; bool use_dsb; + bool use_flipq; u32 psr2_man_track_ctl; @@ -1369,6 +1372,21 @@ struct intel_pipe_crc { enum intel_pipe_crc_source source; }; +enum intel_flipq_id { + INTEL_FLIPQ_PLANE_1, + INTEL_FLIPQ_PLANE_2, + INTEL_FLIPQ_PLANE_3, + INTEL_FLIPQ_GENERAL, + INTEL_FLIPQ_FAST, + MAX_INTEL_FLIPQ, +}; + +struct intel_flipq { + u32 start_mmioaddr; + enum intel_flipq_id flipq_id; + u8 tail; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -1395,11 +1413,15 @@ struct intel_crtc { struct drm_pending_vblank_event *flip_done_event; /* armed event for DSB based updates */ struct drm_pending_vblank_event *dsb_event; + /* armed event for flip queue based updates */ + struct drm_pending_vblank_event *flipq_event; /* Access to these should be protected by display->irq.lock. */ bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; + struct intel_flipq flipq[MAX_INTEL_FLIPQ]; + /* per-pipe watermark state */ struct { /* watermarks currently being used */ @@ -1521,6 +1543,8 @@ struct intel_plane { bool async_flip); void (*enable_flip_done)(struct intel_plane *plane); void (*disable_flip_done)(struct intel_plane *plane); + /* For drm_panic */ + void (*disable_tiling)(struct intel_plane *plane); }; #define to_intel_atomic_state(x) container_of(x, struct intel_atomic_state, base) diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h index 3d8fa667cc73..f8ffeec29e93 100644 --- a/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h @@ -153,6 +153,7 @@ struct intel_dkl_phy_reg { #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK, (val)) #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK REG_GENMASK(6, 5) #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, (val)) +#define LOADGEN_SHARING_PMD_DISABLE REG_BIT(12) #define _DKL_TX_FW_CALIB_LN0 0x02F8 #define _DKL_TX_FW_CALIB_LN1 0x12F8 diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index a10e56e7cf31..744f51c0eab8 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -24,9 +24,13 @@ #include <linux/debugfs.h> #include <linux/firmware.h> +#include <drm/drm_vblank.h> + +#include <drm/drm_file.h> +#include <drm/drm_print.h> -#include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_power_well.h" @@ -35,6 +39,7 @@ #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dmc_regs.h" +#include "intel_flipq.h" #include "intel_step.h" /** @@ -179,7 +184,8 @@ static const char *dmc_firmware_default(struct intel_display *display, u32 *size const char *fw_path = NULL; u32 max_fw_size = 0; - if (DISPLAY_VERx100(display) == 3000) { + if (DISPLAY_VERx100(display) == 3002 || + DISPLAY_VERx100(display) == 3000) { fw_path = XE3LPD_DMC_PATH; max_fw_size = XE2LPD_DMC_MAX_FW_SIZE; } else if (DISPLAY_VERx100(display) == 2000) { @@ -432,25 +438,22 @@ static void disable_event_handler(struct intel_display *display, intel_de_write(display, htp_reg, 0); } -static void disable_all_event_handlers(struct intel_display *display) +static void disable_all_event_handlers(struct intel_display *display, + enum intel_dmc_id dmc_id) { - enum intel_dmc_id dmc_id; + int handler; /* TODO: disable the event handlers on pre-GEN12 platforms as well */ if (DISPLAY_VER(display) < 12) return; - for_each_dmc_id(dmc_id) { - int handler; - - if (!has_dmc_id_fw(display, dmc_id)) - continue; + if (!has_dmc_id_fw(display, dmc_id)) + return; - for (handler = 0; handler < DMC_EVENT_HANDLER_COUNT_GEN12; handler++) - disable_event_handler(display, - DMC_EVT_CTL(display, dmc_id, handler), - DMC_EVT_HTP(display, dmc_id, handler)); - } + for (handler = 0; handler < DMC_EVENT_HANDLER_COUNT_GEN12; handler++) + disable_event_handler(display, + DMC_EVT_CTL(display, dmc_id, handler), + DMC_EVT_HTP(display, dmc_id, handler)); } static void adlp_pipedmc_clock_gating_wa(struct intel_display *display, bool enable) @@ -482,12 +485,13 @@ static void mtl_pipedmc_clock_gating_wa(struct intel_display *display) * for pipe A and B. */ intel_de_rmw(display, GEN9_CLKGATE_DIS_0, 0, - MTL_PIPEDMC_GATING_DIS_A | MTL_PIPEDMC_GATING_DIS_B); + MTL_PIPEDMC_GATING_DIS(PIPE_A) | + MTL_PIPEDMC_GATING_DIS(PIPE_B)); } static void pipedmc_clock_gating_wa(struct intel_display *display, bool enable) { - if (DISPLAY_VER(display) >= 14 && enable) + if (display->platform.meteorlake && enable) mtl_pipedmc_clock_gating_wa(display); else if (DISPLAY_VER(display) == 13) adlp_pipedmc_clock_gating_wa(display, enable); @@ -500,46 +504,11 @@ static u32 pipedmc_interrupt_mask(struct intel_display *display) * triggering it during the first DC state transition. Figure * out what is going on... */ - return PIPEDMC_GTT_FAULT | + return PIPEDMC_FLIPQ_PROG_DONE | + PIPEDMC_GTT_FAULT | PIPEDMC_ATS_FAULT; } -void intel_dmc_enable_pipe(struct intel_display *display, enum pipe pipe) -{ - enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe); - - if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id)) - return; - - if (DISPLAY_VER(display) >= 20) { - intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display)); - intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~pipedmc_interrupt_mask(display)); - } - - if (DISPLAY_VER(display) >= 14) - intel_de_rmw(display, MTL_PIPEDMC_CONTROL, 0, PIPEDMC_ENABLE_MTL(pipe)); - else - intel_de_rmw(display, PIPEDMC_CONTROL(pipe), 0, PIPEDMC_ENABLE); -} - -void intel_dmc_disable_pipe(struct intel_display *display, enum pipe pipe) -{ - enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe); - - if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id)) - return; - - if (DISPLAY_VER(display) >= 14) - intel_de_rmw(display, MTL_PIPEDMC_CONTROL, PIPEDMC_ENABLE_MTL(pipe), 0); - else - intel_de_rmw(display, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0); - - if (DISPLAY_VER(display) >= 20) { - intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~0); - intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display)); - } -} - static u32 dmc_evt_ctl_disable(void) { return REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, @@ -577,6 +546,238 @@ static bool is_event_handler(struct intel_display *display, REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == event_id; } +static bool disable_dmc_evt(struct intel_display *display, + enum intel_dmc_id dmc_id, + i915_reg_t reg, u32 data) +{ + if (!is_dmc_evt_ctl_reg(display, dmc_id, reg)) + return false; + + /* keep all pipe DMC events disabled by default */ + if (dmc_id != DMC_FW_MAIN) + return true; + + /* also disable the flip queue event on the main DMC on TGL */ + if (display->platform.tigerlake && + is_event_handler(display, dmc_id, MAINDMC_EVENT_CLK_MSEC, reg, data)) + return true; + + /* also disable the HRR event on the main DMC on TGL/ADLS */ + if ((display->platform.tigerlake || display->platform.alderlake_s) && + is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg, data)) + return true; + + return false; +} + +static u32 dmc_mmiodata(struct intel_display *display, + struct intel_dmc *dmc, + enum intel_dmc_id dmc_id, int i) +{ + if (disable_dmc_evt(display, dmc_id, + dmc->dmc_info[dmc_id].mmioaddr[i], + dmc->dmc_info[dmc_id].mmiodata[i])) + return dmc_evt_ctl_disable(); + else + return dmc->dmc_info[dmc_id].mmiodata[i]; +} + +static void dmc_load_mmio(struct intel_display *display, enum intel_dmc_id dmc_id) +{ + struct intel_dmc *dmc = display_to_dmc(display); + int i; + + for (i = 0; i < dmc->dmc_info[dmc_id].mmio_count; i++) { + intel_de_write(display, dmc->dmc_info[dmc_id].mmioaddr[i], + dmc_mmiodata(display, dmc, dmc_id, i)); + } +} + +static void dmc_load_program(struct intel_display *display, enum intel_dmc_id dmc_id) +{ + struct intel_dmc *dmc = display_to_dmc(display); + int i; + + disable_all_event_handlers(display, dmc_id); + + preempt_disable(); + + for (i = 0; i < dmc->dmc_info[dmc_id].dmc_fw_size; i++) { + intel_de_write_fw(display, + DMC_PROGRAM(dmc->dmc_info[dmc_id].start_mmioaddr, i), + dmc->dmc_info[dmc_id].payload[i]); + } + + preempt_enable(); + + dmc_load_mmio(display, dmc_id); +} + +static void assert_dmc_loaded(struct intel_display *display, + enum intel_dmc_id dmc_id) +{ + struct intel_dmc *dmc = display_to_dmc(display); + u32 expected, found; + int i; + + if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id)) + return; + + found = intel_de_read(display, DMC_PROGRAM(dmc->dmc_info[dmc_id].start_mmioaddr, 0)); + expected = dmc->dmc_info[dmc_id].payload[0]; + + drm_WARN(display->drm, found != expected, + "DMC %d program storage start incorrect (expected 0x%x, current 0x%x)\n", + dmc_id, expected, found); + + for (i = 0; i < dmc->dmc_info[dmc_id].mmio_count; i++) { + i915_reg_t reg = dmc->dmc_info[dmc_id].mmioaddr[i]; + + found = intel_de_read(display, reg); + expected = dmc_mmiodata(display, dmc, dmc_id, i); + + /* once set DMC_EVT_CTL_ENABLE can't be cleared :/ */ + if (is_dmc_evt_ctl_reg(display, dmc_id, reg)) { + found &= ~DMC_EVT_CTL_ENABLE; + expected &= ~DMC_EVT_CTL_ENABLE; + } + + drm_WARN(display->drm, found != expected, + "DMC %d mmio[%d]/0x%x incorrect (expected 0x%x, current 0x%x)\n", + dmc_id, i, i915_mmio_reg_offset(reg), expected, found); + } +} + +void assert_main_dmc_loaded(struct intel_display *display) +{ + assert_dmc_loaded(display, DMC_FW_MAIN); +} + +static bool need_pipedmc_load_program(struct intel_display *display) +{ + /* On TGL/derivatives pipe DMC state is lost when PG1 is disabled */ + return DISPLAY_VER(display) == 12; +} + +static bool need_pipedmc_load_mmio(struct intel_display *display, enum pipe pipe) +{ + /* + * PTL: + * - pipe A/B DMC doesn't need save/restore + * - pipe C/D DMC is in PG0, needs manual save/restore + */ + if (DISPLAY_VER(display) == 30) + return pipe >= PIPE_C; + + /* + * FIXME LNL unclear, main DMC firmware has the pipe DMC A/B PG0 + * save/restore, but so far unable to see the loss of pipe DMC state + * in action. Are we just failing to turn off PG0 due to some other + * SoC level stuff? + */ + if (DISPLAY_VER(display) == 20) + return false; + + /* + * FIXME BMG untested, main DMC firmware has the + * pipe DMC A/B PG0 save/restore... + */ + if (display->platform.battlemage) + return false; + + /* + * DG2: + * - Pipe DMCs presumably in PG0? + * - No DC6, and even DC9 doesn't seem to result + * in loss of DMC state for whatever reason + */ + if (display->platform.dg2) + return false; + + /* + * ADL/MTL: + * - pipe A/B DMC is in PG0, saved/restored by the main DMC + * - pipe C/D DMC is in PG0, needs manual save/restore + */ + if (IS_DISPLAY_VER(display, 13, 14)) + return pipe >= PIPE_C; + + return false; +} + +static bool can_enable_pipedmc(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + /* + * On TGL/derivatives pipe DMC state is lost when PG1 is disabled. + * Do not even enable the pipe DMC when that can happen outside + * of driver control (PSR+DC5/6). + */ + if (DISPLAY_VER(display) == 12 && crtc_state->has_psr) + return false; + + return true; +} + +void intel_dmc_enable_pipe(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); + enum pipe pipe = crtc->pipe; + enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe); + + if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id)) + return; + + if (!can_enable_pipedmc(crtc_state)) { + intel_dmc_disable_pipe(crtc_state); + return; + } + + if (need_pipedmc_load_program(display)) + dmc_load_program(display, dmc_id); + else if (need_pipedmc_load_mmio(display, pipe)) + dmc_load_mmio(display, dmc_id); + + assert_dmc_loaded(display, dmc_id); + + if (DISPLAY_VER(display) >= 20) { + intel_flipq_reset(display, pipe); + + intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display)); + intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~pipedmc_interrupt_mask(display)); + } + + if (DISPLAY_VER(display) >= 14) + intel_de_rmw(display, MTL_PIPEDMC_CONTROL, 0, PIPEDMC_ENABLE_MTL(pipe)); + else + intel_de_rmw(display, PIPEDMC_CONTROL(pipe), 0, PIPEDMC_ENABLE); +} + +void intel_dmc_disable_pipe(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); + enum pipe pipe = crtc->pipe; + enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe); + + if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id)) + return; + + if (DISPLAY_VER(display) >= 14) + intel_de_rmw(display, MTL_PIPEDMC_CONTROL, PIPEDMC_ENABLE_MTL(pipe), 0); + else + intel_de_rmw(display, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0); + + if (DISPLAY_VER(display) >= 20) { + intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~0); + intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display)); + + intel_flipq_reset(display, pipe); + } +} + static void dmc_configure_event(struct intel_display *display, enum intel_dmc_id dmc_id, unsigned int event_id, @@ -637,42 +838,6 @@ void intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(struct intel_display dmc_configure_event(display, dmc_id, PIPEDMC_EVENT_VBLANK, enable); } -static bool disable_dmc_evt(struct intel_display *display, - enum intel_dmc_id dmc_id, - i915_reg_t reg, u32 data) -{ - if (!is_dmc_evt_ctl_reg(display, dmc_id, reg)) - return false; - - /* keep all pipe DMC events disabled by default */ - if (dmc_id != DMC_FW_MAIN) - return true; - - /* also disable the flip queue event on the main DMC on TGL */ - if (display->platform.tigerlake && - is_event_handler(display, dmc_id, MAINDMC_EVENT_CLK_MSEC, reg, data)) - return true; - - /* also disable the HRR event on the main DMC on TGL/ADLS */ - if ((display->platform.tigerlake || display->platform.alderlake_s) && - is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg, data)) - return true; - - return false; -} - -static u32 dmc_mmiodata(struct intel_display *display, - struct intel_dmc *dmc, - enum intel_dmc_id dmc_id, int i) -{ - if (disable_dmc_evt(display, dmc_id, - dmc->dmc_info[dmc_id].mmioaddr[i], - dmc->dmc_info[dmc_id].mmiodata[i])) - return dmc_evt_ctl_disable(); - else - return dmc->dmc_info[dmc_id].mmiodata[i]; -} - /** * intel_dmc_load_program() - write the firmware from memory to register. * @display: display instance @@ -684,37 +849,26 @@ static u32 dmc_mmiodata(struct intel_display *display, void intel_dmc_load_program(struct intel_display *display) { struct i915_power_domains *power_domains = &display->power.domains; - struct intel_dmc *dmc = display_to_dmc(display); enum intel_dmc_id dmc_id; - u32 i; if (!intel_dmc_has_payload(display)) return; - pipedmc_clock_gating_wa(display, true); - - disable_all_event_handlers(display); - assert_display_rpm_held(display); - preempt_disable(); + pipedmc_clock_gating_wa(display, true); for_each_dmc_id(dmc_id) { - for (i = 0; i < dmc->dmc_info[dmc_id].dmc_fw_size; i++) { - intel_de_write_fw(display, - DMC_PROGRAM(dmc->dmc_info[dmc_id].start_mmioaddr, i), - dmc->dmc_info[dmc_id].payload[i]); - } + dmc_load_program(display, dmc_id); + assert_dmc_loaded(display, dmc_id); } - preempt_enable(); - - for_each_dmc_id(dmc_id) { - for (i = 0; i < dmc->dmc_info[dmc_id].mmio_count; i++) { - intel_de_write(display, dmc->dmc_info[dmc_id].mmioaddr[i], - dmc_mmiodata(display, dmc, dmc_id, i)); - } - } + if (DISPLAY_VER(display) >= 20) + intel_de_write(display, DMC_FQ_W2_PTS_CFG_SEL, + PIPE_D_DMC_W2_PTS_CONFIG_SELECT(PIPE_D) | + PIPE_C_DMC_W2_PTS_CONFIG_SELECT(PIPE_C) | + PIPE_B_DMC_W2_PTS_CONFIG_SELECT(PIPE_B) | + PIPE_A_DMC_W2_PTS_CONFIG_SELECT(PIPE_A)); power_domains->dc_state = 0; @@ -732,26 +886,17 @@ void intel_dmc_load_program(struct intel_display *display) */ void intel_dmc_disable_program(struct intel_display *display) { + enum intel_dmc_id dmc_id; + if (!intel_dmc_has_payload(display)) return; pipedmc_clock_gating_wa(display, true); - disable_all_event_handlers(display); - pipedmc_clock_gating_wa(display, false); -} -void assert_dmc_loaded(struct intel_display *display) -{ - struct intel_dmc *dmc = display_to_dmc(display); + for_each_dmc_id(dmc_id) + disable_all_event_handlers(display, dmc_id); - drm_WARN_ONCE(display->drm, !dmc, "DMC not initialized\n"); - drm_WARN_ONCE(display->drm, dmc && - !intel_de_read(display, DMC_PROGRAM(dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)), - "DMC program storage start is NULL\n"); - drm_WARN_ONCE(display->drm, !intel_de_read(display, DMC_SSP_BASE), - "DMC SSP Base Not fine\n"); - drm_WARN_ONCE(display->drm, !intel_de_read(display, DMC_HTP_SKL), - "DMC HTP Not fine\n"); + pipedmc_clock_gating_wa(display, false); } static bool fw_info_matches_stepping(const struct intel_fw_info *fw_info, @@ -1170,7 +1315,6 @@ out: */ void intel_dmc_init(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); struct intel_dmc *dmc; if (!HAS_DMC(display)) @@ -1213,7 +1357,7 @@ void intel_dmc_init(struct intel_display *display) display->dmc.dmc = dmc; drm_dbg_kms(display->drm, "Loading %s\n", dmc->fw_path); - queue_work(i915->unordered_wq, &dmc->work); + queue_work(display->wq.unordered, &dmc->work); return; @@ -1244,6 +1388,17 @@ void intel_dmc_suspend(struct intel_display *display) intel_dmc_runtime_pm_put(display); } +void intel_dmc_wait_fw_load(struct intel_display *display) +{ + struct intel_dmc *dmc = display_to_dmc(display); + + if (!HAS_DMC(display)) + return; + + if (dmc) + flush_work(&dmc->work); +} + /** * intel_dmc_resume() - init DMC firmware during system resume * @display: display instance @@ -1457,12 +1612,29 @@ void intel_dmc_debugfs_register(struct intel_display *display) void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe) { struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); - u32 tmp; + u32 tmp = 0, int_vector; if (DISPLAY_VER(display) >= 20) { tmp = intel_de_read(display, PIPEDMC_INTERRUPT(pipe)); intel_de_write(display, PIPEDMC_INTERRUPT(pipe), tmp); + if (tmp & PIPEDMC_FLIPQ_PROG_DONE) { + spin_lock(&display->drm->event_lock); + + if (crtc->flipq_event) { + /* + * Update vblank counter/timestamp in case it + * hasn't been done yet for this frame. + */ + drm_crtc_accurate_vblank_count(&crtc->base); + + drm_crtc_send_vblank_event(&crtc->base, crtc->flipq_event); + crtc->flipq_event = NULL; + } + + spin_unlock(&display->drm->event_lock); + } + if (tmp & PIPEDMC_ATS_FAULT) drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC ATS fault\n", crtc->base.base.id, crtc->base.name); @@ -1474,8 +1646,35 @@ void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe) crtc->base.base.id, crtc->base.name); } - tmp = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK; - if (tmp) + int_vector = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK; + if (tmp == 0 && int_vector != 0) drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n", crtc->base.base.id, crtc->base.name, tmp); } + +void intel_pipedmc_enable_event(struct intel_crtc *crtc, + enum pipedmc_event_id event) +{ + struct intel_display *display = to_intel_display(crtc); + enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(crtc->pipe); + + dmc_configure_event(display, dmc_id, event, true); +} + +void intel_pipedmc_disable_event(struct intel_crtc *crtc, + enum pipedmc_event_id event) +{ + struct intel_display *display = to_intel_display(crtc); + enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(crtc->pipe); + + dmc_configure_event(display, dmc_id, event, false); +} + +u32 intel_pipedmc_start_mmioaddr(struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc); + struct intel_dmc *dmc = display_to_dmc(display); + enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(crtc->pipe); + + return dmc ? dmc->dmc_info[dmc_id].start_mmioaddr : 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_dmc.h b/drivers/gpu/drm/i915/display/intel_dmc.h index a98e8deff13a..40e9dcb033cc 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.h +++ b/drivers/gpu/drm/i915/display/intel_dmc.h @@ -9,15 +9,19 @@ #include <linux/types.h> enum pipe; +enum pipedmc_event_id; struct drm_printer; +struct intel_crtc; +struct intel_crtc_state; struct intel_display; struct intel_dmc_snapshot; void intel_dmc_init(struct intel_display *display); void intel_dmc_load_program(struct intel_display *display); +void intel_dmc_wait_fw_load(struct intel_display *display); void intel_dmc_disable_program(struct intel_display *display); -void intel_dmc_enable_pipe(struct intel_display *display, enum pipe pipe); -void intel_dmc_disable_pipe(struct intel_display *display, enum pipe pipe); +void intel_dmc_enable_pipe(const struct intel_crtc_state *crtc_state); +void intel_dmc_disable_pipe(const struct intel_crtc_state *crtc_state); void intel_dmc_block_pkgc(struct intel_display *display, enum pipe pipe, bool block); void intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(struct intel_display *display, @@ -32,7 +36,15 @@ struct intel_dmc_snapshot *intel_dmc_snapshot_capture(struct intel_display *disp void intel_dmc_snapshot_print(const struct intel_dmc_snapshot *snapshot, struct drm_printer *p); void intel_dmc_update_dc6_allowed_count(struct intel_display *display, bool start_tracking); -void assert_dmc_loaded(struct intel_display *display); +void assert_main_dmc_loaded(struct intel_display *display); + +void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe); + +u32 intel_pipedmc_start_mmioaddr(struct intel_crtc *crtc); +void intel_pipedmc_enable_event(struct intel_crtc *crtc, + enum pipedmc_event_id event); +void intel_pipedmc_disable_event(struct intel_crtc *crtc, + enum pipedmc_event_id event); void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe); diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h index 6f406315dd65..c5aa49921cb9 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h @@ -287,6 +287,17 @@ enum pipedmc_event_id { #define MTL_PIPEDMC_CONTROL _MMIO(0x45250) #define PIPEDMC_ENABLE_MTL(pipe) REG_BIT(((pipe) - PIPE_A) * 4) +#define _PIPEDMC_LOAD_HTP_A 0x5f000 +#define _PIPEDMC_LOAD_HTP_B 0x5f400 +#define PIPEDMC_LOAD_HTP(pipe) _MMIO_PIPE((pipe), _PIPEDMC_LOAD_HTP_A, _PIPEDMC_LOAD_HTP_B) + +#define _PIPEDMC_CTL_A 0x5f064 +#define _PIPEDMC_CTL_B 0x5f464 +#define PIPEDMC_CTL(pipe) _MMIO_PIPE((pipe), _PIPEDMC_CTL_A, _PIPEDMC_CTL_B) +#define PIPEDMC_HALT REG_BIT(31) +#define PIPEDMC_STEP REG_BIT(27) +#define PIPEDMC_CLOCKGATE REG_BIT(23) + #define _PIPEDMC_STATUS_A 0x5f06c #define _PIPEDMC_STATUS_B 0x5f46c #define PIPEDMC_STATUS(pipe) _MMIO_PIPE((pipe), _PIPEDMC_STATUS_A, _PIPEDMC_STATUS_B) @@ -298,6 +309,138 @@ enum pipedmc_event_id { #define PIPEDMC_INT_VECTOR_FLIPQ_PROG_DONE REG_FIELD_PREP(PIPEDMC_INT_VECTOR_MASK, 0xff) /* Wa_16018781658:lnl[a0] */ #define PIPEDMC_EVT_PENDING REG_GENMASK(7, 0) +#define _PIPEDMC_FQ_CTRL_A 0x5f078 +#define _PIPEDMC_FQ_CTRL_B 0x5f478 +#define PIPEDMC_FQ_CTRL(pipe) _MMIO_PIPE((pipe), _PIPEDMC_FQ_CTRL_A, _PIPEDMC_FQ_CTRL_B) +#define PIPEDMC_FQ_CTRL_ENABLE REG_BIT(31) +#define PIPEDMC_FQ_CTRL_ASYNC REG_BIT(29) +#define PIPEDMC_FQ_CTRL_PREEMPT REG_BIT(0) + +#define _PIPEDMC_FQ_STATUS_A 0x5f098 +#define _PIPEDMC_FQ_STATUS_B 0x5f498 +#define PIPEDMC_FQ_STATUS(pipe) _MMIO_PIPE((pipe), _PIPEDMC_FQ_STATUS_A, _PIPEDMC_FQ_STATUS_B) +#define PIPEDMC_FQ_STATUS_BUSY REG_BIT(31) +#define PIPEDMC_FQ_STATUS_W2_LIVE_STATUS REG_BIT(1) +#define PIPEDMC_FQ_STATUS_W1_LIVE_STATUS REG_BIT(0) + +#define _PIPEDMC_FPQ_ATOMIC_TP_A 0x5f0a0 +#define _PIPEDMC_FPQ_ATOMIC_TP_B 0x5f4a0 +#define PIPEDMC_FPQ_ATOMIC_TP(pipe) _MMIO_PIPE((pipe), _PIPEDMC_FPQ_ATOMIC_TP_A, _PIPEDMC_FPQ_ATOMIC_TP_B) +#define PIPEDMC_FPQ_PLANEQ_3_TP_MASK REG_GENMASK(31, 26) +#define PIPEDMC_FPQ_PLANEQ_3_TP(tail) REG_FIELD_PREP(PIPEDMC_FPQ_PLANEQ_3_TP_MASK, (tail)) +#define PIPEDMC_FPQ_PLANEQ_2_TP_MASK REG_GENMASK(24, 19) +#define PIPEDMC_FPQ_PLANEQ_2_TP(tail) REG_FIELD_PREP(PIPEDMC_FPQ_PLANEQ_2_TP_MASK, (tail)) +#define PIPEDMC_FPQ_PLANEQ_1_TP_MASK REG_GENMASK(17, 12) +#define PIPEDMC_FPQ_PLANEQ_1_TP(tail) REG_FIELD_PREP(PIPEDMC_FPQ_PLANEQ_1_TP_MASK, (tail)) +#define PIPEDMC_FPQ_FASTQ_TP_MASK REG_GENMASK(10, 6) +#define PIPEDMC_FPQ_FASTQ_TP(tail) REG_FIELD_PREP(PIPEDMC_FPQ_FASTQ_TP_MASK, (tail)) +#define PIPEDMC_FPQ_GENERALQ_TP_MASK REG_GENMASK(4, 0) +#define PIPEDMC_FPQ_GENERALQ_TP(tail) REG_FIELD_PREP(PIPEDMC_FPQ_GENERALQ_TP_MASK, (tail)) + +#define _PIPEDMC_FPQ_LINES_TO_W1_A 0x5f0a4 +#define _PIPEDMC_FPQ_LINES_TO_W1_B 0x5f4a4 +#define PIPEDMC_FPQ_LINES_TO_W1 _MMIO_PIPE((pipe), _PIPEDMC_FPQ_LINES_TO_W1_A, _PIPEDMC_FPQ_LINES_TO_W1_B) + +#define _PIPEDMC_FPQ_LINES_TO_W2_A 0x5f0a8 +#define _PIPEDMC_FPQ_LINES_TO_W2_B 0x5f4a8 +#define PIPEDMC_FPQ_LINES_TO_W2 _MMIO_PIPE((pipe), _PIPEDMC_FPQ_LINES_TO_W2_A, _PIPEDMC_FPQ_LINES_TO_W2_B) + +#define _PIPEDMC_SCANLINECMP_A 0x5f11c +#define _PIPEDMC_SCANLINECMP_B 0x5f51c +#define PIPEDMC_SCANLINECMP(pipe) _MMIO_PIPE((pipe), _PIPEDMC_SCANLINECMP_A, _PIPEDMC_SCANLINECMP_B) +#define PIPEDMC_SCANLINECMP_EN REG_BIT(31) +#define PIPEDMC_SCANLINE_NUMBER REG_GENMASK(20, 0) + +#define _PIPEDMC_SCANLINECMPLOWER_A 0x5f120 +#define _PIPEDMC_SCANLINECMPLOWER_B 0x5f520 +#define PIPEDMC_SCANLINECMPLOWER(pipe) _MMIO_PIPE((pipe), _PIPEDMC_SCANLINECMPLOWER_A, _PIPEDMC_SCANLINECMPLOWER_B) +#define PIPEDMC_SCANLINEINRANGECMP_EN REG_BIT(31) +#define PIPEDMC_SCANLINEOUTRANGECMP_EN REG_BIT(30) +#define PIPEDMC_SCANLINE_LOWER_MASK REG_GENMASK(20, 0) +#define PIPEDMC_SCANLINE_LOWER(scanline) REG_FIELD_PREP(PIPEDMC_SCANLINE_LOWER_MASK, (scanline)) + +#define _PIPEDMC_SCANLINECMPUPPER_A 0x5f124 +#define _PIPEDMC_SCANLINECMPUPPER_B 0x5f524 +#define PIPEDMC_SCANLINECMPUPPER(pipe) _MMIO_PIPE((pipe), _PIPEDMC_SCANLINECMPUPPER_A, _PIPEDMC_SCANLINECMPUPPER_B) +#define PIPEDMC_SCANLINE_UPPER_MASK REG_GENMASK(20, 0) +#define PIPEDMC_SCANLINE_UPPER(scanline) REG_FIELD_PREP(PIPEDMC_SCANLINE_UPPER_MASK, (scanline)) + +#define _MMIO_PIPEDMC_FPQ(pipe, fq_id, \ + reg_fpq1_a, reg_fpq2_a, reg_fpq3_a, reg_fpq4_a, \ + reg_fpq1_b, reg_fpq2_b, reg_fpq3_b, reg_fpq4_b) \ + _MMIO(_PICK_EVEN_2RANGES((fq_id), INTEL_FLIPQ_PLANE_3, \ + _PIPE((pipe), (reg_fpq1_a), (reg_fpq1_b)), \ + _PIPE((pipe), (reg_fpq2_a), (reg_fpq2_b)), \ + _PIPE((pipe), (reg_fpq3_a), (reg_fpq3_b)), \ + _PIPE((pipe), (reg_fpq4_a), (reg_fpq4_b)))) + +#define _PIPEDMC_FPQ1_HP_A 0x5f128 +#define _PIPEDMC_FPQ2_HP_A 0x5f138 +#define _PIPEDMC_FPQ3_HP_A 0x5f168 +#define _PIPEDMC_FPQ4_HP_A 0x5f174 +#define _PIPEDMC_FPQ5_HP_A 0x5f180 +#define _PIPEDMC_FPQ1_HP_B 0x5f528 +#define _PIPEDMC_FPQ2_HP_B 0x5f538 +#define _PIPEDMC_FPQ3_HP_B 0x5f568 +#define _PIPEDMC_FPQ4_HP_B 0x5f574 +#define _PIPEDMC_FPQ5_HP_B 0x5f580 +#define PIPEDMC_FPQ_HP(pipe, fq_id) _MMIO_PIPEDMC_FPQ((pipe), (fq_id), \ + _PIPEDMC_FPQ1_HP_A, _PIPEDMC_FPQ2_HP_A, \ + _PIPEDMC_FPQ3_HP_A, _PIPEDMC_FPQ4_HP_A, \ + _PIPEDMC_FPQ1_HP_B, _PIPEDMC_FPQ2_HP_B, \ + _PIPEDMC_FPQ3_HP_B, _PIPEDMC_FPQ4_HP_B) + +#define _PIPEDMC_FPQ1_TP_A 0x5f12c +#define _PIPEDMC_FPQ2_TP_A 0x5f13c +#define _PIPEDMC_FPQ3_TP_A 0x5f16c +#define _PIPEDMC_FPQ4_TP_A 0x5f178 +#define _PIPEDMC_FPQ5_TP_A 0x5f184 +#define _PIPEDMC_FPQ1_TP_B 0x5f52c +#define _PIPEDMC_FPQ2_TP_B 0x5f53c +#define _PIPEDMC_FPQ3_TP_B 0x5f56c +#define _PIPEDMC_FPQ4_TP_B 0x5f578 +#define _PIPEDMC_FPQ5_TP_B 0x5f584 +#define PIPEDMC_FPQ_TP(pipe, fq_id) _MMIO_PIPEDMC_FPQ((pipe), (fq_id), \ + _PIPEDMC_FPQ1_TP_A, _PIPEDMC_FPQ2_TP_A, \ + _PIPEDMC_FPQ3_TP_A, _PIPEDMC_FPQ4_TP_A, \ + _PIPEDMC_FPQ1_TP_B, _PIPEDMC_FPQ2_TP_B, \ + _PIPEDMC_FPQ3_TP_B, _PIPEDMC_FPQ4_TP_B) + +#define _PIPEDMC_FPQ1_CHP_A 0x5f130 +#define _PIPEDMC_FPQ2_CHP_A 0x5f140 +#define _PIPEDMC_FPQ3_CHP_A 0x5f170 +#define _PIPEDMC_FPQ4_CHP_A 0x5f17c +#define _PIPEDMC_FPQ5_CHP_A 0x5f188 +#define _PIPEDMC_FPQ1_CHP_B 0x5f530 +#define _PIPEDMC_FPQ2_CHP_B 0x5f540 +#define _PIPEDMC_FPQ3_CHP_B 0x5f570 +#define _PIPEDMC_FPQ4_CHP_B 0x5f57c +#define _PIPEDMC_FPQ5_CHP_B 0x5f588 +#define PIPEDMC_FPQ_CHP(pipe, fq_id) _MMIO_PIPEDMC_FPQ((pipe), (fq_id), \ + _PIPEDMC_FPQ1_CHP_A, _PIPEDMC_FPQ2_CHP_A, \ + _PIPEDMC_FPQ3_CHP_A, _PIPEDMC_FPQ4_CHP_A, \ + _PIPEDMC_FPQ1_CHP_B, _PIPEDMC_FPQ2_CHP_B, \ + _PIPEDMC_FPQ3_CHP_B, _PIPEDMC_FPQ4_CHP_B) + +#define _PIPEDMC_FPQ_TS_A 0x5f134 +#define _PIPEDMC_FPQ_TS_B 0x5f534 +#define PIPEDMC_FPQ_TS(pipe) _MMIO_PIPE((pipe), _PIPEDMC_FPQ_TS_A, _PIPEDMC_FPQ_TS_B) + +#define _PIPEDMC_SCANLINE_RO_A 0x5f144 +#define _PIPEDMC_SCANLINE_RO_B 0x5f544 +#define PIPEDMC_SCANLINE_RO(pipe) _MMIO_PIPE((pipe), _PIPEDMC_SCANLINE_RO_A, _PIPEDMC_SCANLINE_RO_B) + +#define _PIPEDMC_FPQ_CTL1_A 0x5f160 +#define _PIPEDMC_FPQ_CTL1_B 0x5f560 +#define PIPEDMC_FPQ_CTL1(pipe) _MMIO_PIPE((pipe), _PIPEDMC_FPQ_CTL1_A, _PIPEDMC_FPQ_CTL1_B) +#define PIPEDMC_SW_DMC_WAKE REG_BIT(0) + +#define _PIPEDMC_FPQ_CTL2_A 0x5f164 +#define _PIPEDMC_FPQ_CTL2_B 0x5f564 +#define PIPEDMC_FPQ_CTL2(pipe) _MMIO_PIPE((pipe), _PIPEDMC_FPQ_CTL2_A, _PIPEDMC_FPQ_CTL2_B) +#define PIPEDMC_DMC_INT_AT_DELAYED_VBLANK REG_BIT(1) +#define PIPEDMC_W1_DMC_WAKE REG_BIT(0) + #define _PIPEDMC_INTERRUPT_A 0x5f190 /* lnl+ */ #define _PIPEDMC_INTERRUPT_B 0x5f590 /* lnl+ */ #define PIPEDMC_INTERRUPT(pipe) _MMIO_PIPE((pipe), _PIPEDMC_INTERRUPT_A, _PIPEDMC_INTERRUPT_B) @@ -394,4 +537,51 @@ enum pipedmc_event_id { #define DMC_WAKELOCK_CTL_REQ REG_BIT(31) #define DMC_WAKELOCK_CTL_ACK REG_BIT(15) +#define DMC_FQ_W2_PTS_CFG_SEL _MMIO(0x8f240) +#define PIPE_D_DMC_W2_PTS_CONFIG_SELECT_MASK REG_GENMASK(26, 24) +#define PIPE_D_DMC_W2_PTS_CONFIG_SELECT(pipe) REG_FIELD_PREP(PIPE_D_DMC_W2_PTS_CONFIG_SELECT_MASK, (pipe)) +#define PIPE_C_DMC_W2_PTS_CONFIG_SELECT_MASK REG_GENMASK(18, 16) +#define PIPE_C_DMC_W2_PTS_CONFIG_SELECT(pipe) REG_FIELD_PREP(PIPE_C_DMC_W2_PTS_CONFIG_SELECT_MASK, (pipe)) +#define PIPE_B_DMC_W2_PTS_CONFIG_SELECT_MASK REG_GENMASK(10, 8) +#define PIPE_B_DMC_W2_PTS_CONFIG_SELECT(pipe) REG_FIELD_PREP(PIPE_B_DMC_W2_PTS_CONFIG_SELECT_MASK, (pipe)) +#define PIPE_A_DMC_W2_PTS_CONFIG_SELECT_MASK REG_GENMASK(2, 0) +#define PIPE_A_DMC_W2_PTS_CONFIG_SELECT(pipe) REG_FIELD_PREP(PIPE_A_DMC_W2_PTS_CONFIG_SELECT_MASK, (pipe)) + +/* plane/general flip queue entries */ +#define PIPEDMC_FQ_RAM(start_mmioaddr, i) _MMIO((start_mmioaddr) + (i) * 4) +/* LNL */ +/* DW0 pts */ +/* DW1 head */ +/* DW2 size/etc. */ +#define LNL_FQ_INTERRUPT REG_BIT(31) +#define LNL_FQ_DSB_ID_MASK REG_GENMASK(30, 29) +#define LNL_FQ_DSB_ID(dsb_id) REG_FIELD_PREP(LNL_FQ_DSB_ID_MASK, (dsb_id)) +#define LNL_FQ_EXECUTED REG_BIT(28) +#define LNL_FQ_DSB_SIZE_MASK REG_GENMASK(15, 0) +#define LNL_FQ_DSB_SIZE(size) REG_FIELD_PREP(LNL_FQ_DSB_SIZE_MASK, (size)) +/* DW3 reserved (plane queues) */ +/* DW3 second DSB head (general queue) */ +/* DW4 second DSB size/etc. (general queue) */ +/* DW5 reserved (general queue) */ + +/* PTL+ */ +/* DW0 pts */ +/* DW1 reserved */ +/* DW2 size/etc. */ +#define PTL_FQ_INTERRUPT REG_BIT(31) +#define PTL_FQ_NEED_PUSH REG_BIT(30) +#define PTL_FQ_BLOCK_PUSH REG_BIT(29) +#define PTL_FQ_EXECUTED REG_BIT(28) +#define PTL_FQ_DSB_ID_MASK REG_GENMASK(25, 24) +#define PTL_FQ_DSB_ID(dsb_id) REG_FIELD_PREP(PTL_FQ_DSB_ID_MASK, (dsb_id)) +#define PTL_FQ_DSB_SIZE_MASK REG_GENMASK(15, 0) +#define PTL_FQ_DSB_SIZE(size) REG_FIELD_PREP(PTL_FQ_DSB_SIZE_MASK, (size)) +/* DW3 head */ +/* DW4 second DSB size/etc. (general queue) */ +/* DW5 second DSB head (general queue) */ + +/* undocumented magic DMC variables */ +#define PTL_PIPEDMC_EXEC_TIME_LINES(start_mmioaddr) _MMIO((start_mmioaddr) + 0x6b8) +#define PTL_PIPEDMC_END_OF_EXEC_GB(start_mmioaddr) _MMIO((start_mmioaddr) + 0x6c0) + #endif /* __INTEL_DMC_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl.c b/drivers/gpu/drm/i915/display/intel_dmc_wl.c index 44b3ee5c9be4..b3bb89ba34f9 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_wl.c +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl.c @@ -7,7 +7,6 @@ #include <drm/drm_print.h> -#include "i915_drv.h" #include "intel_de.h" #include "intel_display_regs.h" #include "intel_dmc_regs.h" @@ -155,12 +154,11 @@ static const struct intel_dmc_wl_range xe3lpd_dc3co_dmc_ranges[] = { static void __intel_dmc_wl_release(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); struct intel_dmc_wl *wl = &display->wl; WARN_ON(refcount_read(&wl->refcount)); - queue_delayed_work(i915->unordered_wq, &wl->work, + queue_delayed_work(display->wq.unordered, &wl->work, msecs_to_jiffies(DMC_WAKELOCK_HOLD_TIME)); } diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 277b40b13948..7976fec88606 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1606,6 +1606,12 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, u8 *link_bw, u8 *rate_select) { + struct intel_display *display = to_intel_display(intel_dp); + + /* FIXME g4x can't generate an exact 2.7GHz with the 96MHz non-SSC refclk */ + if (display->platform.g4x && port_clock == 268800) + port_clock = 270000; + /* eDP 1.4 rate select method. */ if (intel_dp->use_rate_select) { *link_bw = 0; @@ -3726,6 +3732,9 @@ static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp) memset(intel_dp->pcon_dsc_dpcd, 0, sizeof(intel_dp->pcon_dsc_dpcd)); + if (!drm_dp_is_branch(intel_dp->dpcd)) + return; + if (drm_dp_dpcd_read(&intel_dp->aux, DP_PCON_DSC_ENCODER, intel_dp->pcon_dsc_dpcd, sizeof(intel_dp->pcon_dsc_dpcd)) < 0) 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 5537136c367a..41228478b21c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -475,31 +475,6 @@ static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, en return connector->panel.backlight.level; } -static int -intel_dp_aux_vesa_set_luminance(struct intel_connector *connector, u32 level) -{ - struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); - u8 buf[3]; - int ret; - - level = level * 1000; - level &= 0xffffff; - buf[0] = (level & 0x0000ff); - buf[1] = (level & 0x00ff00) >> 8; - buf[2] = (level & 0xff0000) >> 16; - - ret = drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, - buf, sizeof(buf)); - if (ret != sizeof(buf)) { - drm_err(intel_dp->aux.drm_dev, - "%s: Failed to set VESA Aux Luminance: %d\n", - intel_dp->aux.name, ret); - return -EINVAL; - } else { - return 0; - } -} - static void intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level) { @@ -507,11 +482,6 @@ intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u3 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) { - if (!intel_dp_aux_vesa_set_luminance(connector, level)) - return; - } - if (!panel->backlight.edp.vesa.info.aux_set) { const u32 pwm_level = intel_backlight_level_to_pwm(connector, level); @@ -528,18 +498,6 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, struct intel_connector *connector = to_intel_connector(conn_state->connector); struct intel_panel *panel = &connector->panel; struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); - int ret; - - if (panel->backlight.edp.vesa.luminance_control_support) { - ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, - DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE); - - if (ret == 1) - return; - - if (!intel_dp_aux_vesa_set_luminance(connector, level)) - return; - } if (!panel->backlight.edp.vesa.info.aux_enable) { u32 pwm_level; @@ -580,13 +538,41 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, &connector->base.display_info.luminance_range; struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_panel *panel = &connector->panel; - u16 current_level; + u32 current_level; u8 current_mode; int ret; - if (panel->backlight.edp.vesa.luminance_control_support) { + ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, + luminance_range->max_luminance, + panel->vbt.backlight.pwm_freq_hz, + intel_dp->edp_dpcd, ¤t_level, ¤t_mode, + false); + if (ret < 0) + return ret; + + drm_dbg_kms(display->drm, + "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n", + connector->base.base.id, connector->base.name, + dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable)); + drm_dbg_kms(display->drm, + "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n", + connector->base.base.id, connector->base.name, + dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set)); + + if (!panel->backlight.edp.vesa.info.aux_set || + !panel->backlight.edp.vesa.info.aux_enable) { + ret = panel->backlight.pwm_funcs->setup(connector, pipe); + if (ret < 0) { + drm_err(display->drm, + "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n", + connector->base.base.id, connector->base.name, ret); + return ret; + } + } + + if (panel->backlight.edp.vesa.info.luminance_set) { if (luminance_range->max_luminance) { - panel->backlight.max = luminance_range->max_luminance; + panel->backlight.max = panel->backlight.edp.vesa.info.max; panel->backlight.min = luminance_range->min_luminance; } else { panel->backlight.max = 512; @@ -597,54 +583,26 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n", connector->base.base.id, connector->base.name); - } else { - ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, - panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, - ¤t_level, ¤t_mode); - if (ret < 0) - return ret; - - drm_dbg_kms(display->drm, - "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n", - connector->base.base.id, connector->base.name, - dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable)); - drm_dbg_kms(display->drm, - "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n", - connector->base.base.id, connector->base.name, - dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set)); - - if (!panel->backlight.edp.vesa.info.aux_set || - !panel->backlight.edp.vesa.info.aux_enable) { - ret = panel->backlight.pwm_funcs->setup(connector, pipe); - if (ret < 0) { - drm_err(display->drm, - "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n", - connector->base.base.id, connector->base.name, ret); - return ret; - } + } else if (panel->backlight.edp.vesa.info.aux_set) { + panel->backlight.max = panel->backlight.edp.vesa.info.max; + panel->backlight.min = 0; + if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { + panel->backlight.level = current_level; + panel->backlight.enabled = panel->backlight.level != 0; + } else { + panel->backlight.level = panel->backlight.max; + panel->backlight.enabled = false; } - - if (panel->backlight.edp.vesa.info.aux_set) { - panel->backlight.max = panel->backlight.edp.vesa.info.max; - panel->backlight.min = 0; - if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { - panel->backlight.level = current_level; - panel->backlight.enabled = panel->backlight.level != 0; - } else { - panel->backlight.level = panel->backlight.max; - panel->backlight.enabled = false; - } + } else { + panel->backlight.max = panel->backlight.pwm_level_max; + panel->backlight.min = panel->backlight.pwm_level_min; + if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) { + panel->backlight.level = + panel->backlight.pwm_funcs->get(connector, pipe); + panel->backlight.enabled = panel->backlight.pwm_enabled; } else { - panel->backlight.max = panel->backlight.pwm_level_max; - panel->backlight.min = panel->backlight.pwm_level_min; - if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) { - panel->backlight.level = - panel->backlight.pwm_funcs->get(connector, pipe); - panel->backlight.enabled = panel->backlight.pwm_enabled; - } else { - panel->backlight.level = panel->backlight.max; - panel->backlight.enabled = false; - } + panel->backlight.level = panel->backlight.max; + panel->backlight.enabled = false; } } diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index 7bd775fb65a0..bd757db85927 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -805,10 +805,16 @@ intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector, enum pipe pipe = (enum pipe)cpu_transcoder; enum port port = dig_port->base.port; int ret; + u32 val; + u8 stream_type; - drm_WARN_ON(display->drm, enable && - !!(intel_de_read(display, HDCP2_AUTH_STREAM(display, cpu_transcoder, port)) - & AUTH_STREAM_TYPE) != data->streams[0].stream_type); + if (DISPLAY_VER(display) < 30) { + val = intel_de_read(display, + HDCP2_AUTH_STREAM(display, cpu_transcoder, port)); + stream_type = REG_FIELD_GET(AUTH_STREAM_TYPE_MASK, val); + drm_WARN_ON(display->drm, enable && + stream_type != data->streams[0].stream_type); + } ret = intel_dp_mst_toggle_hdcp_stream_select(connector, enable); if (ret) @@ -824,6 +830,14 @@ intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector, return -ETIMEDOUT; } + if (DISPLAY_VER(display) >= 30) { + val = intel_de_read(display, + HDCP2_STREAM_STATUS(display, cpu_transcoder, port)); + stream_type = REG_FIELD_GET(STREAM_TYPE_STATUS_MASK, val); + drm_WARN_ON(display->drm, enable && + stream_type != data->streams[0].stream_type); + } + return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 3fa94510458d..0fdb32ef241c 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -5,7 +5,8 @@ #include <linux/debugfs.h> -#include "i915_drv.h" +#include <drm/drm_print.h> + #include "intel_atomic.h" #include "intel_de.h" #include "intel_display_regs.h" @@ -123,9 +124,9 @@ static void intel_drrs_set_state(struct intel_crtc *crtc, static void intel_drrs_schedule_work(struct intel_crtc *crtc) { - struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct intel_display *display = to_intel_display(crtc); - mod_delayed_work(i915->unordered_wq, &crtc->drrs.work, msecs_to_jiffies(1000)); + mod_delayed_work(display->wq.unordered, &crtc->drrs.work, msecs_to_jiffies(1000)); } static unsigned int intel_drrs_frontbuffer_bits(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_encoder.c b/drivers/gpu/drm/i915/display/intel_encoder.c index bad452ad979a..0b7bd26f4339 100644 --- a/drivers/gpu/drm/i915/display/intel_encoder.c +++ b/drivers/gpu/drm/i915/display/intel_encoder.c @@ -5,7 +5,6 @@ #include <linux/workqueue.h> -#include "i915_drv.h" #include "intel_display_core.h" #include "intel_display_types.h" #include "intel_encoder.h" @@ -32,9 +31,9 @@ void intel_encoder_link_check_flush_work(struct intel_encoder *encoder) void intel_encoder_link_check_queue_work(struct intel_encoder *encoder, int delay_ms) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_display *display = to_intel_display(encoder); - mod_delayed_work(i915->unordered_wq, + mod_delayed_work(display->wq.unordered, &encoder->link_check_work, msecs_to_jiffies(delay_ms)); } diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index a5906cb4900c..0da842bd2f2f 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -11,7 +11,6 @@ #include <drm/drm_modeset_helper.h> #include "i915_drv.h" -#include "intel_atomic_plane.h" #include "intel_bo.h" #include "intel_display.h" #include "intel_display_core.h" @@ -20,6 +19,7 @@ #include "intel_fb.h" #include "intel_fb_bo.h" #include "intel_frontbuffer.h" +#include "intel_plane.h" #define check_array_bounds(display, a, i) drm_WARN_ON((display)->drm, (i) >= ARRAY_SIZE(a)) @@ -422,21 +422,22 @@ unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) /** * intel_fb_get_format_info: Get a modifier specific format information - * @cmd: FB add command structure + * @pixel_format: pixel format + * @modifier: modifier * * Returns: - * Returns the format information for @cmd->pixel_format specific to @cmd->modifier[0], + * Returns the format information for @pixel_format specific to @modifier, * or %NULL if the modifier doesn't override the format. */ const struct drm_format_info * -intel_fb_get_format_info(const struct drm_mode_fb_cmd2 *cmd) +intel_fb_get_format_info(u32 pixel_format, u64 modifier) { - const struct intel_modifier_desc *md = lookup_modifier_or_null(cmd->modifier[0]); + const struct intel_modifier_desc *md = lookup_modifier_or_null(modifier); if (!md || !md->formats) return NULL; - return lookup_format_info(md->formats, md->format_count, cmd->pixel_format); + return lookup_format_info(md->formats, md->format_count, pixel_format); } static bool plane_caps_contain_any(u8 caps, u8 mask) @@ -1286,10 +1287,10 @@ bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) { + struct intel_display *display = to_intel_display(plane_state); struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - return DISPLAY_VER(dev_priv) < 4 || + return DISPLAY_VER(display) < 4 || (plane->fbc && !plane_state->no_fbc_reason && plane_state->view.gtt.type == I915_GTT_VIEW_NORMAL); } @@ -2206,6 +2207,7 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { int intel_framebuffer_init(struct intel_framebuffer *intel_fb, struct drm_gem_object *obj, + const struct drm_format_info *info, struct drm_mode_fb_cmd2 *mode_cmd) { struct intel_display *display = to_intel_display(obj->dev); @@ -2253,7 +2255,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, goto err_frontbuffer_put; } - drm_helper_mode_fill_fb_struct(display->drm, fb, mode_cmd); + drm_helper_mode_fill_fb_struct(display->drm, fb, info, mode_cmd); for (i = 0; i < fb->format->num_planes; i++) { unsigned int stride_alignment; @@ -2323,6 +2325,7 @@ err: struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, + const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *user_mode_cmd) { struct drm_framebuffer *fb; @@ -2333,7 +2336,7 @@ intel_user_framebuffer_create(struct drm_device *dev, if (IS_ERR(obj)) return ERR_CAST(obj); - fb = intel_framebuffer_create(obj, &mode_cmd); + fb = intel_framebuffer_create(obj, info, &mode_cmd); drm_gem_object_put(obj); return fb; @@ -2341,16 +2344,17 @@ intel_user_framebuffer_create(struct drm_device *dev, struct drm_framebuffer * intel_framebuffer_create(struct drm_gem_object *obj, + const struct drm_format_info *info, struct drm_mode_fb_cmd2 *mode_cmd) { struct intel_framebuffer *intel_fb; int ret; - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + intel_fb = intel_bo_alloc_framebuffer(); if (!intel_fb) return ERR_PTR(-ENOMEM); - ret = intel_framebuffer_init(intel_fb, obj, mode_cmd); + ret = intel_framebuffer_init(intel_fb, obj, info, mode_cmd); if (ret) goto err; diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index bdd76b372957..403b8b63721a 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -47,7 +47,7 @@ u64 *intel_fb_plane_get_modifiers(struct intel_display *display, bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier); const struct drm_format_info * -intel_fb_get_format_info(const struct drm_mode_fb_cmd2 *cmd); +intel_fb_get_format_info(u32 pixel_format, u64 modifier); bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, @@ -102,13 +102,16 @@ void intel_add_fb_offsets(int *x, int *y, 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 drm_framebuffer * intel_framebuffer_create(struct drm_gem_object *obj, + const struct drm_format_info *info, struct drm_mode_fb_cmd2 *mode_cmd); struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, + const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *user_mode_cmd); bool intel_fb_modifier_uses_dpt(struct intel_display *display, u64 modifier); diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index 98a61a7b0b93..5a0151775a3a 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -11,13 +11,13 @@ #include "gem/i915_gem_object.h" #include "i915_drv.h" -#include "intel_atomic_plane.h" #include "intel_display_core.h" #include "intel_display_rpm.h" #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" #include "intel_fb_pin.h" +#include "intel_plane.h" static struct i915_vma * intel_fb_pin_to_dpt(const struct drm_framebuffer *fb, @@ -334,3 +334,8 @@ void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) intel_dpt_unpin_from_ggtt(fb->dpt_vm); } } + +void intel_fb_get_map(struct i915_vma *vma, struct iosys_map *map) +{ + iosys_map_set_vaddr_iomem(map, i915_vma_get_iomap(vma)); +} diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.h b/drivers/gpu/drm/i915/display/intel_fb_pin.h index 01770dbba2e0..81ab79da1af7 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.h +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.h @@ -12,6 +12,7 @@ struct drm_framebuffer; struct i915_vma; struct intel_plane_state; struct i915_gtt_view; +struct iosys_map; struct i915_vma * intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, @@ -27,5 +28,6 @@ void intel_fb_unpin_vma(struct i915_vma *vma, unsigned long flags); int intel_plane_pin_fb(struct intel_plane_state *new_plane_state, const struct intel_plane_state *old_plane_state); void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state); +void intel_fb_get_map(struct i915_vma *vma, struct iosys_map *map); #endif diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index ec1ef8694c35..685ac98bd001 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -552,10 +552,6 @@ static void ilk_fbc_deactivate(struct intel_fbc *fbc) if (dpfc_ctl & DPFC_CTL_EN) { dpfc_ctl &= ~DPFC_CTL_EN; intel_de_write(display, ILK_DPFC_CONTROL(fbc->id), dpfc_ctl); - - /* wa_18038517565 Enable DPFC clock gating after FBC disable */ - if (display->platform.dg2 || DISPLAY_VER(display) >= 14) - fbc_compressor_clkgate_disable_wa(fbc, false); } } @@ -1576,7 +1572,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, if (IS_ERR(cdclk_state)) return PTR_ERR(cdclk_state); - if (crtc_state->pixel_rate >= cdclk_state->logical.cdclk * 95 / 100) { + if (crtc_state->pixel_rate >= intel_cdclk_logical(cdclk_state) * 95 / 100) { plane_state->no_fbc_reason = "pixel rate too high"; return 0; } @@ -1710,6 +1706,10 @@ static void __intel_fbc_disable(struct intel_fbc *fbc) __intel_fbc_cleanup_cfb(fbc); + /* wa_18038517565 Enable DPFC clock gating after FBC disable */ + if (display->platform.dg2 || DISPLAY_VER(display) >= 14) + fbc_compressor_clkgate_disable_wa(fbc, false); + fbc->state.plane = NULL; fbc->flip_pending = false; fbc->busy_bits = 0; @@ -2011,7 +2011,7 @@ void intel_fbc_reset_underrun(struct intel_display *display) static void __intel_fbc_handle_fifo_underrun_irq(struct intel_fbc *fbc) { - struct drm_i915_private *i915 = to_i915(fbc->display->drm); + struct intel_display *display = fbc->display; /* * There's no guarantee that underrun_detected won't be set to true @@ -2024,7 +2024,7 @@ static void __intel_fbc_handle_fifo_underrun_irq(struct intel_fbc *fbc) if (READ_ONCE(fbc->underrun_detected)) return; - queue_work(i915->unordered_wq, &fbc->underrun_work); + queue_work(display->wq.unordered, &fbc->underrun_work); } /** diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 2dc4029d71ed..7c4709d58aa3 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -512,3 +512,8 @@ struct i915_vma *intel_fbdev_vma_pointer(struct intel_fbdev *fbdev) { return fbdev ? fbdev->vma : NULL; } + +void intel_fbdev_get_map(struct intel_fbdev *fbdev, struct iosys_map *map) +{ + intel_fb_get_map(fbdev->vma, map); +} diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.h b/drivers/gpu/drm/i915/display/intel_fbdev.h index a15e3e222a0c..150cc5f45bb3 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev.h @@ -13,6 +13,7 @@ struct drm_fb_helper_surface_size; struct intel_display; struct intel_fbdev; struct intel_framebuffer; +struct iosys_map; #ifdef CONFIG_DRM_FBDEV_EMULATION int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, @@ -22,7 +23,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, void intel_fbdev_setup(struct intel_display *display); struct intel_framebuffer *intel_fbdev_framebuffer(struct intel_fbdev *fbdev); struct i915_vma *intel_fbdev_vma_pointer(struct intel_fbdev *fbdev); - +void intel_fbdev_get_map(struct intel_fbdev *fbdev, struct iosys_map *map); #else #define INTEL_FBDEV_DRIVER_OPS \ .fbdev_probe = NULL @@ -39,6 +40,9 @@ static inline struct i915_vma *intel_fbdev_vma_pointer(struct intel_fbdev *fbdev return NULL; } +static inline void intel_fbdev_get_map(struct intel_fbdev *fbdev, struct iosys_map *map) +{ +} #endif #endif /* __INTEL_FBDEV_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 8db3af36b2f2..210aee9ae88b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -62,7 +62,11 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, return ERR_PTR(-ENOMEM); } - fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), &mode_cmd); + 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 to_intel_framebuffer(fb); diff --git a/drivers/gpu/drm/i915/display/intel_flipq.c b/drivers/gpu/drm/i915/display/intel_flipq.c new file mode 100644 index 000000000000..6ab2272ab2df --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_flipq.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Intel Corporation + */ + +#include <linux/pci.h> + +#include <drm/drm_print.h> + +#include "i915_utils.h" +#include "intel_step.h" +#include "intel_crtc.h" +#include "intel_de.h" +#include "intel_display_core.h" +#include "intel_display_types.h" +#include "intel_flipq.h" +#include "intel_dmc.h" +#include "intel_dmc_regs.h" +#include "intel_dsb.h" +#include "intel_vblank.h" +#include "intel_vrr.h" + +/** + * DOC: DMC Flip Queue + * + * A flip queue is a ring buffer implemented by the pipe DMC firmware. + * The driver inserts entries into the queues to be executed by the + * pipe DMC at a specified presentation timestamp (PTS). + * + * Each pipe DMC provides several queues: + * + * - 1 general queue (two DSB buffers executed per entry) + * - 3 plane queues (one DSB buffer executed per entry) + * - 1 fast queue (deprecated) + */ + +#define for_each_flipq(flipq_id) \ + for ((flipq_id) = INTEL_FLIPQ_PLANE_1; (flipq_id) < MAX_INTEL_FLIPQ; (flipq_id)++) + +static int intel_flipq_offset(enum intel_flipq_id flipq_id) +{ + switch (flipq_id) { + case INTEL_FLIPQ_PLANE_1: + return 0x008; + case INTEL_FLIPQ_PLANE_2: + return 0x108; + case INTEL_FLIPQ_PLANE_3: + return 0x208; + case INTEL_FLIPQ_GENERAL: + return 0x308; + case INTEL_FLIPQ_FAST: + return 0x3c8; + default: + MISSING_CASE(flipq_id); + return 0; + } +} + +static int intel_flipq_size_dw(enum intel_flipq_id flipq_id) +{ + switch (flipq_id) { + case INTEL_FLIPQ_PLANE_1: + case INTEL_FLIPQ_PLANE_2: + case INTEL_FLIPQ_PLANE_3: + return 64; + case INTEL_FLIPQ_GENERAL: + case INTEL_FLIPQ_FAST: + return 48; + default: + MISSING_CASE(flipq_id); + return 1; + } +} + +static int intel_flipq_elem_size_dw(enum intel_flipq_id flipq_id) +{ + switch (flipq_id) { + case INTEL_FLIPQ_PLANE_1: + case INTEL_FLIPQ_PLANE_2: + case INTEL_FLIPQ_PLANE_3: + return 4; + case INTEL_FLIPQ_GENERAL: + case INTEL_FLIPQ_FAST: + return 6; + default: + MISSING_CASE(flipq_id); + return 1; + } +} + +static int intel_flipq_size_entries(enum intel_flipq_id flipq_id) +{ + return intel_flipq_size_dw(flipq_id) / intel_flipq_elem_size_dw(flipq_id); +} + +static void intel_flipq_crtc_init(struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc); + enum intel_flipq_id flipq_id; + + for_each_flipq(flipq_id) { + struct intel_flipq *flipq = &crtc->flipq[flipq_id]; + + flipq->start_mmioaddr = intel_pipedmc_start_mmioaddr(crtc) + intel_flipq_offset(flipq_id); + flipq->flipq_id = flipq_id; + + drm_dbg_kms(display->drm, "[CRTC:%d:%s] FQ %d: start 0x%x\n", + crtc->base.base.id, crtc->base.name, + flipq_id, flipq->start_mmioaddr); + } +} + +bool intel_flipq_supported(struct intel_display *display) +{ + if (!display->params.enable_flipq) + return false; + + if (!display->dmc.dmc) + return false; + + if (DISPLAY_VER(display) == 20) + return true; + + /* DMC firmware expects VRR timing generator to be used */ + return DISPLAY_VER(display) >= 30 && intel_vrr_always_use_vrr_tg(display); +} + +void intel_flipq_init(struct intel_display *display) +{ + struct intel_crtc *crtc; + + intel_dmc_wait_fw_load(display); + + for_each_intel_crtc(display->drm, crtc) + intel_flipq_crtc_init(crtc); +} + +static int cdclk_factor(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 30) + return 120; + else + return 280; +} + +int intel_flipq_exec_time_us(struct intel_display *display) +{ + return intel_dsb_exec_time_us() + + DIV_ROUND_UP(display->cdclk.hw.cdclk * cdclk_factor(display), 540000) + + display->sagv.block_time_us; +} + +static int intel_flipq_preempt_timeout_ms(struct intel_display *display) +{ + return DIV_ROUND_UP(intel_flipq_exec_time_us(display), 1000); +} + +static void intel_flipq_preempt(struct intel_crtc *crtc, bool preempt) +{ + struct intel_display *display = to_intel_display(crtc); + + intel_de_rmw(display, PIPEDMC_FQ_CTRL(crtc->pipe), + PIPEDMC_FQ_CTRL_PREEMPT, preempt ? PIPEDMC_FQ_CTRL_PREEMPT : 0); + + if (preempt && + intel_de_wait_for_clear(display, + PIPEDMC_FQ_STATUS(crtc->pipe), + PIPEDMC_FQ_STATUS_BUSY, + intel_flipq_preempt_timeout_ms(display))) + drm_err(display->drm, "[CRTC:%d:%s] flip queue preempt timeout\n", + crtc->base.base.id, crtc->base.name); +} + +static int intel_flipq_current_head(struct intel_crtc *crtc, enum intel_flipq_id flipq_id) +{ + struct intel_display *display = to_intel_display(crtc); + + return intel_de_read(display, PIPEDMC_FPQ_CHP(crtc->pipe, flipq_id)); +} + +static void intel_flipq_write_tail(struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc); + + intel_de_write(display, PIPEDMC_FPQ_ATOMIC_TP(crtc->pipe), + PIPEDMC_FPQ_PLANEQ_3_TP(crtc->flipq[INTEL_FLIPQ_PLANE_3].tail) | + PIPEDMC_FPQ_PLANEQ_2_TP(crtc->flipq[INTEL_FLIPQ_PLANE_2].tail) | + PIPEDMC_FPQ_PLANEQ_1_TP(crtc->flipq[INTEL_FLIPQ_PLANE_1].tail) | + PIPEDMC_FPQ_FASTQ_TP(crtc->flipq[INTEL_FLIPQ_FAST].tail) | + PIPEDMC_FPQ_GENERALQ_TP(crtc->flipq[INTEL_FLIPQ_GENERAL].tail)); +} + +static void intel_flipq_sw_dmc_wake(struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc); + + intel_de_write(display, PIPEDMC_FPQ_CTL1(crtc->pipe), PIPEDMC_SW_DMC_WAKE); +} + +static int intel_flipq_exec_time_lines(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + return intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, + intel_flipq_exec_time_us(display)); +} + +void intel_flipq_dump(struct intel_crtc *crtc, + enum intel_flipq_id flipq_id) +{ + struct intel_display *display = to_intel_display(crtc); + struct intel_flipq *flipq = &crtc->flipq[flipq_id]; + u32 tmp; + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] FQ %d @ 0x%x: ", + crtc->base.base.id, crtc->base.name, flipq_id, + flipq->start_mmioaddr); + for (int i = 0 ; i < intel_flipq_size_dw(flipq_id); i++) { + printk(KERN_CONT " 0x%08x", + intel_de_read(display, PIPEDMC_FQ_RAM(flipq->start_mmioaddr, i))); + if (i % intel_flipq_elem_size_dw(flipq_id) == intel_flipq_elem_size_dw(flipq_id) - 1) + printk(KERN_CONT "\n"); + } + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] FQ %d: chp=0x%x, hp=0x%x\n", + crtc->base.base.id, crtc->base.name, flipq_id, + intel_de_read(display, PIPEDMC_FPQ_CHP(crtc->pipe, flipq_id)), + intel_de_read(display, PIPEDMC_FPQ_HP(crtc->pipe, flipq_id))); + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] FQ %d: current head %d\n", + crtc->base.base.id, crtc->base.name, flipq_id, + intel_flipq_current_head(crtc, flipq_id)); + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] flip queue timestamp: 0x%x\n", + crtc->base.base.id, crtc->base.name, + intel_de_read(display, PIPEDMC_FPQ_TS(crtc->pipe))); + + tmp = intel_de_read(display, PIPEDMC_FPQ_ATOMIC_TP(crtc->pipe)); + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] flip queue atomic tails: P3 %d, P2 %d, P1 %d, G %d, F %d\n", + crtc->base.base.id, crtc->base.name, + REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_3_TP_MASK, tmp), + REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_2_TP_MASK, tmp), + REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_1_TP_MASK, tmp), + REG_FIELD_GET(PIPEDMC_FPQ_GENERALQ_TP_MASK, tmp), + REG_FIELD_GET(PIPEDMC_FPQ_FASTQ_TP_MASK, tmp)); +} + +void intel_flipq_reset(struct intel_display *display, enum pipe pipe) +{ + struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); + enum intel_flipq_id flipq_id; + + intel_de_write(display, PIPEDMC_FQ_CTRL(pipe), 0); + + intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(pipe), 0); + intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(pipe), 0); + + for_each_flipq(flipq_id) { + struct intel_flipq *flipq = &crtc->flipq[flipq_id]; + + intel_de_write(display, PIPEDMC_FPQ_HP(pipe, flipq_id), 0); + intel_de_write(display, PIPEDMC_FPQ_CHP(pipe, flipq_id), 0); + + flipq->tail = 0; + } + + intel_de_write(display, PIPEDMC_FPQ_ATOMIC_TP(pipe), 0); +} + +static enum pipedmc_event_id flipq_event_id(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 30) + return PIPEDMC_EVENT_FULL_FQ_WAKE_TRIGGER; + else + return PIPEDMC_EVENT_SCANLINE_INRANGE_FQ_TRIGGER; +} + +void intel_flipq_enable(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); + /* FIXME what to do with VRR? */ + int scanline = intel_mode_vblank_start(&crtc_state->hw.adjusted_mode) - + intel_flipq_exec_time_lines(crtc_state); + + if (DISPLAY_VER(display) >= 30) { + u32 start_mmioaddr = intel_pipedmc_start_mmioaddr(crtc); + + /* undocumented magic DMC variables */ + intel_de_write(display, PTL_PIPEDMC_EXEC_TIME_LINES(start_mmioaddr), + intel_flipq_exec_time_lines(crtc_state)); + intel_de_write(display, PTL_PIPEDMC_END_OF_EXEC_GB(start_mmioaddr), + 100); + } + + intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(crtc->pipe), + PIPEDMC_SCANLINE_UPPER(scanline)); + intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(crtc->pipe), + PIPEDMC_SCANLINEINRANGECMP_EN | + PIPEDMC_SCANLINE_LOWER(scanline - 2)); + + intel_pipedmc_enable_event(crtc, flipq_event_id(display)); + + intel_de_write(display, PIPEDMC_FQ_CTRL(crtc->pipe), PIPEDMC_FQ_CTRL_ENABLE); +} + +void intel_flipq_disable(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); + + intel_flipq_preempt(crtc, true); + + intel_de_write(display, PIPEDMC_FQ_CTRL(crtc->pipe), 0); + + intel_pipedmc_disable_event(crtc, flipq_event_id(display)); + + intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(crtc->pipe), 0); + intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(crtc->pipe), 0); +} + +static bool assert_flipq_has_room(struct intel_crtc *crtc, + enum intel_flipq_id flipq_id) +{ + struct intel_display *display = to_intel_display(crtc); + struct intel_flipq *flipq = &crtc->flipq[flipq_id]; + int head, size = intel_flipq_size_entries(flipq_id); + + head = intel_flipq_current_head(crtc, flipq_id); + + return !drm_WARN(display->drm, + (flipq->tail + size - head) % size >= size - 1, + "[CRTC:%d:%s] FQ %d overflow (head %d, tail %d, size %d)\n", + crtc->base.base.id, crtc->base.name, flipq_id, + head, flipq->tail, size); +} + +static void intel_flipq_write(struct intel_display *display, + struct intel_flipq *flipq, u32 data, int i) +{ + intel_de_write(display, PIPEDMC_FQ_RAM(flipq->start_mmioaddr, flipq->tail * + intel_flipq_elem_size_dw(flipq->flipq_id) + i), data); +} + +static void lnl_flipq_add(struct intel_display *display, + struct intel_flipq *flipq, + unsigned int pts, + enum intel_dsb_id dsb_id, + struct intel_dsb *dsb) +{ + int i = 0; + + switch (flipq->flipq_id) { + case INTEL_FLIPQ_GENERAL: + intel_flipq_write(display, flipq, pts, i++); + intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); + intel_flipq_write(display, flipq, LNL_FQ_INTERRUPT | + LNL_FQ_DSB_ID(dsb_id) | + LNL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); + intel_flipq_write(display, flipq, 0, i++); + intel_flipq_write(display, flipq, 0, i++); /* head for second DSB */ + intel_flipq_write(display, flipq, 0, i++); /* DSB engine + size for second DSB */ + break; + case INTEL_FLIPQ_PLANE_1: + case INTEL_FLIPQ_PLANE_2: + case INTEL_FLIPQ_PLANE_3: + intel_flipq_write(display, flipq, pts, i++); + intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); + intel_flipq_write(display, flipq, LNL_FQ_INTERRUPT | + LNL_FQ_DSB_ID(dsb_id) | + LNL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); + intel_flipq_write(display, flipq, 0, i++); + break; + default: + MISSING_CASE(flipq->flipq_id); + return; + } +} + +static void ptl_flipq_add(struct intel_display *display, + struct intel_flipq *flipq, + unsigned int pts, + enum intel_dsb_id dsb_id, + struct intel_dsb *dsb) +{ + int i = 0; + + switch (flipq->flipq_id) { + case INTEL_FLIPQ_GENERAL: + intel_flipq_write(display, flipq, pts, i++); + intel_flipq_write(display, flipq, 0, i++); + intel_flipq_write(display, flipq, PTL_FQ_INTERRUPT | + PTL_FQ_DSB_ID(dsb_id) | + PTL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); + intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); + intel_flipq_write(display, flipq, 0, i++); /* DSB engine + size for second DSB */ + intel_flipq_write(display, flipq, 0, i++); /* head for second DSB */ + break; + case INTEL_FLIPQ_PLANE_1: + case INTEL_FLIPQ_PLANE_2: + case INTEL_FLIPQ_PLANE_3: + intel_flipq_write(display, flipq, pts, i++); + intel_flipq_write(display, flipq, 0, i++); + intel_flipq_write(display, flipq, PTL_FQ_INTERRUPT | + PTL_FQ_DSB_ID(dsb_id) | + PTL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); + intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); + break; + default: + MISSING_CASE(flipq->flipq_id); + return; + } +} + +void intel_flipq_add(struct intel_crtc *crtc, + enum intel_flipq_id flipq_id, + unsigned int pts, + enum intel_dsb_id dsb_id, + struct intel_dsb *dsb) +{ + struct intel_display *display = to_intel_display(crtc); + struct intel_flipq *flipq = &crtc->flipq[flipq_id]; + + if (!assert_flipq_has_room(crtc, flipq_id)) + return; + + pts += intel_de_read(display, PIPEDMC_FPQ_TS(crtc->pipe)); + + intel_flipq_preempt(crtc, true); + + if (DISPLAY_VER(display) >= 30) + ptl_flipq_add(display, flipq, pts, dsb_id, dsb); + else + lnl_flipq_add(display, flipq, pts, dsb_id, dsb); + + flipq->tail = (flipq->tail + 1) % intel_flipq_size_entries(flipq->flipq_id); + intel_flipq_write_tail(crtc); + + intel_flipq_preempt(crtc, false); + + intel_flipq_sw_dmc_wake(crtc); +} + +/* Wa_18034343758 */ +static bool need_dmc_halt_wa(struct intel_display *display) +{ + return DISPLAY_VER(display) == 20 || + (display->platform.pantherlake && + IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)); +} + +void intel_flipq_wait_dmc_halt(struct intel_dsb *dsb, struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc); + + if (need_dmc_halt_wa(display)) + intel_dsb_wait_usec(dsb, 2); +} + +void intel_flipq_unhalt_dmc(struct intel_dsb *dsb, struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc); + + if (need_dmc_halt_wa(display)) + intel_dsb_reg_write(dsb, PIPEDMC_CTL(crtc->pipe), 0); +} diff --git a/drivers/gpu/drm/i915/display/intel_flipq.h b/drivers/gpu/drm/i915/display/intel_flipq.h new file mode 100644 index 000000000000..012e3e9a6bcb --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_flipq.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef __INTEL_FLIPQ_H__ +#define __INTEL_FLIPQ_H__ + +#include <linux/types.h> + +enum intel_dsb_id; +enum intel_flipq_id; +enum pipe; +struct intel_crtc; +struct intel_crtc_state; +struct intel_display; +struct intel_dsb; + +bool intel_flipq_supported(struct intel_display *display); +void intel_flipq_init(struct intel_display *display); +void intel_flipq_reset(struct intel_display *display, enum pipe pipe); + +void intel_flipq_enable(const struct intel_crtc_state *crtc_state); +void intel_flipq_disable(const struct intel_crtc_state *old_crtc_state); + +void intel_flipq_add(struct intel_crtc *crtc, + enum intel_flipq_id flip_queue_id, + unsigned int pts, + enum intel_dsb_id dsb_id, + struct intel_dsb *dsb); +int intel_flipq_exec_time_us(struct intel_display *display); +void intel_flipq_wait_dmc_halt(struct intel_dsb *dsb, struct intel_crtc *crtc); +void intel_flipq_unhalt_dmc(struct intel_dsb *dsb, struct intel_crtc *crtc); +void intel_flipq_dump(struct intel_crtc *crtc, + enum intel_flipq_id flip_queue_id); + +#endif /* __INTEL_FLIPQ_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 5235e4162555..42202c8bb066 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -14,10 +14,11 @@ #include <linux/random.h> #include <drm/display/drm_hdcp_helper.h> +#include <drm/drm_print.h> #include <drm/intel/i915_component.h> -#include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_connector.h" #include "intel_de.h" #include "intel_display_power.h" @@ -32,6 +33,7 @@ #include "intel_hdcp_regs.h" #include "intel_hdcp_shim.h" #include "intel_pcode.h" +#include "intel_step.h" #define USE_HDCP_GSC(__display) (DISPLAY_VER(__display) >= 14) @@ -374,7 +376,6 @@ static void intel_hdcp_clear_keys(struct intel_display *display) static int intel_hdcp_load_keys(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); int ret; u32 val; @@ -399,7 +400,7 @@ static int intel_hdcp_load_keys(struct intel_display *display) * Mailbox interface. */ if (DISPLAY_VER(display) == 9 && !display->platform.broxton) { - ret = snb_pcode_write(&i915->uncore, SKL_PCODE_LOAD_HDCP_KEYS, 1); + ret = intel_pcode_write(display->drm, SKL_PCODE_LOAD_HDCP_KEYS, 1); if (ret) { drm_err(display->drm, "Failed to initiate HDCP key load (%d)\n", @@ -1089,7 +1090,6 @@ static void intel_hdcp_update_value(struct intel_connector *connector, u64 value, bool update_property) { struct intel_display *display = to_intel_display(connector); - struct drm_i915_private *i915 = to_i915(display->drm); struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct intel_hdcp *hdcp = &connector->hdcp; @@ -1110,7 +1110,7 @@ static void intel_hdcp_update_value(struct intel_connector *connector, hdcp->value = value; if (update_property) { drm_connector_get(&connector->base); - if (!queue_work(i915->unordered_wq, &hdcp->prop_work)) + if (!queue_work(display->wq.unordered, &hdcp->prop_work)) drm_connector_put(&connector->base); } } @@ -2237,16 +2237,15 @@ static void intel_hdcp_check_work(struct work_struct *work) check_work); struct intel_connector *connector = intel_hdcp_to_connector(hdcp); struct intel_display *display = to_intel_display(connector); - struct drm_i915_private *i915 = to_i915(display->drm); if (drm_connector_is_unregistered(&connector->base)) return; if (!intel_hdcp2_check_link(connector)) - queue_delayed_work(i915->unordered_wq, &hdcp->check_work, + queue_delayed_work(display->wq.unordered, &hdcp->check_work, DRM_HDCP2_CHECK_PERIOD_MS); else if (!intel_hdcp_check_link(connector)) - queue_delayed_work(i915->unordered_wq, &hdcp->check_work, + queue_delayed_work(display->wq.unordered, &hdcp->check_work, DRM_HDCP_CHECK_PERIOD_MS); } @@ -2437,7 +2436,6 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { struct intel_display *display = to_intel_display(encoder); - struct drm_i915_private *i915 = to_i915(display->drm); struct intel_connector *connector = to_intel_connector(conn_state->connector); struct intel_digital_port *dig_port = intel_attached_dig_port(connector); @@ -2496,7 +2494,7 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state, } if (!ret) { - queue_delayed_work(i915->unordered_wq, &hdcp->check_work, + queue_delayed_work(display->wq.unordered, &hdcp->check_work, check_link_interval); intel_hdcp_update_value(connector, DRM_MODE_CONTENT_PROTECTION_ENABLED, @@ -2567,7 +2565,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, to_intel_connector(conn_state->connector); struct intel_hdcp *hdcp = &connector->hdcp; bool content_protection_type_changed, desired_and_not_enabled = false; - struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_display *display = to_intel_display(connector); if (!connector->hdcp.shim) return; @@ -2594,7 +2592,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, mutex_lock(&hdcp->mutex); hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; drm_connector_get(&connector->base); - if (!queue_work(i915->unordered_wq, &hdcp->prop_work)) + if (!queue_work(display->wq.unordered, &hdcp->prop_work)) drm_connector_put(&connector->base); mutex_unlock(&hdcp->mutex); } @@ -2612,7 +2610,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, */ if (!desired_and_not_enabled && !content_protection_type_changed) { drm_connector_get(&connector->base); - if (!queue_work(i915->unordered_wq, &hdcp->prop_work)) + if (!queue_work(display->wq.unordered, &hdcp->prop_work)) drm_connector_put(&connector->base); } @@ -2736,7 +2734,6 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp; struct intel_display *display = to_intel_display(connector); - struct drm_i915_private *i915 = to_i915(display->drm); if (!hdcp->shim) return; @@ -2744,7 +2741,7 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector) atomic_inc(&connector->hdcp.cp_irq_count); wake_up_all(&connector->hdcp.cp_irq_queue); - queue_delayed_work(i915->unordered_wq, &hdcp->check_work, 0); + queue_delayed_work(display->wq.unordered, &hdcp->check_work, 0); } static void __intel_hdcp_info(struct seq_file *m, struct intel_connector *connector, diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h index f590d7f48ba7..112ce8c896d6 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h @@ -247,7 +247,7 @@ _TRANSA_HDCP2_STREAM_STATUS, \ _TRANSB_HDCP2_STREAM_STATUS) #define STREAM_ENCRYPTION_STATUS REG_BIT(31) -#define STREAM_TYPE_STATUS REG_BIT(30) +#define STREAM_TYPE_STATUS_MASK REG_GENMASK(30, 30) #define HDCP2_STREAM_STATUS(dev_priv, trans, port) \ (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_STREAM_STATUS(trans) : \ @@ -263,7 +263,7 @@ #define TRANS_HDCP2_AUTH_STREAM(trans) _MMIO_TRANS(trans, \ _TRANSA_HDCP2_AUTH_STREAM, \ _TRANSB_HDCP2_AUTH_STREAM) -#define AUTH_STREAM_TYPE REG_BIT(31) +#define AUTH_STREAM_TYPE_MASK REG_GENMASK(31, 31) #define HDCP2_AUTH_STREAM(dev_priv, trans, port) \ (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_AUTH_STREAM(trans) : \ diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 901fda434af1..265aa97fcc75 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -193,40 +193,34 @@ static bool detection_work_enabled(struct intel_display *display) static bool mod_delayed_detection_work(struct intel_display *display, struct delayed_work *work, int delay) { - struct drm_i915_private *i915 = to_i915(display->drm); - lockdep_assert_held(&display->irq.lock); if (!detection_work_enabled(display)) return false; - return mod_delayed_work(i915->unordered_wq, work, delay); + return mod_delayed_work(display->wq.unordered, work, delay); } static bool queue_delayed_detection_work(struct intel_display *display, struct delayed_work *work, int delay) { - struct drm_i915_private *i915 = to_i915(display->drm); - lockdep_assert_held(&display->irq.lock); if (!detection_work_enabled(display)) return false; - return queue_delayed_work(i915->unordered_wq, work, delay); + return queue_delayed_work(display->wq.unordered, work, delay); } static bool queue_detection_work(struct intel_display *display, struct work_struct *work) { - struct drm_i915_private *i915 = to_i915(display->drm); - lockdep_assert_held(&display->irq.lock); if (!detection_work_enabled(display)) return false; - return queue_work(i915->unordered_wq, work); + return queue_work(display->wq.unordered, work); } static void diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index 05e1b309ba2c..8415f3d703ed 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -961,7 +961,7 @@ void intel_modeset_setup_hw_state(struct intel_display *display, drm_crtc_vblank_reset(&crtc->base); if (crtc_state->hw.active) { - intel_dmc_enable_pipe(display, crtc->pipe); + intel_dmc_enable_pipe(crtc_state); intel_crtc_vblank_on(crtc_state); } } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 5535cb799431..81efdb17fc0c 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -31,8 +31,10 @@ #include <acpi/video.h> #include <drm/drm_edid.h> +#include <drm/drm_file.h> +#include <drm/drm_print.h> -#include "i915_drv.h" +#include "i915_utils.h" #include "intel_acpi.h" #include "intel_backlight.h" #include "intel_display_core.h" @@ -665,11 +667,10 @@ bool intel_opregion_asle_present(struct intel_display *display) void intel_opregion_asle_intr(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); struct intel_opregion *opregion = display->opregion; if (opregion && opregion->asle) - queue_work(i915->unordered_wq, &opregion->asle_work); + queue_work(display->wq.unordered, &opregion->asle_work); } #define ACPI_EV_DISPLAY_SWITCH (1<<0) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index f956919dc648..2a20aaaaac39 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -502,7 +502,7 @@ static void intel_panel_sync_state(struct intel_connector *connector) drm_modeset_unlock(&display->drm->mode_config.connection_mutex); } -const struct drm_panel_funcs dummy_panel_funcs = { +static const struct drm_panel_funcs dummy_panel_funcs = { }; int intel_panel_register(struct intel_connector *connector) @@ -515,7 +515,8 @@ int intel_panel_register(struct intel_connector *connector) if (ret) return ret; - if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI || + connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) { struct device *dev = connector->base.kdev; struct drm_panel *base; diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index 15ede7678636..36fb07471deb 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -33,19 +33,22 @@ #include <linux/dma-fence-chain.h> #include <linux/dma-resv.h> +#include <linux/iosys-map.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> +#include <drm/drm_cache.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem.h> #include <drm/drm_gem_atomic_helper.h> +#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_atomic_plane.h" +#include "intel_bo.h" #include "intel_cdclk.h" #include "intel_cursor.h" #include "intel_display_rps.h" @@ -53,6 +56,9 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fb_pin.h" +#include "intel_fbdev.h" +#include "intel_plane.h" +#include "intel_psr.h" #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" @@ -333,7 +339,7 @@ int intel_plane_calc_min_cdclk(struct intel_atomic_state *state, * display blinking due to constant cdclk changes. */ if (new_crtc_state->min_cdclk[plane->id] <= - cdclk_state->min_cdclk[crtc->pipe]) + intel_cdclk_min_cdclk(cdclk_state, crtc->pipe)) return 0; drm_dbg_kms(display->drm, @@ -341,7 +347,7 @@ int intel_plane_calc_min_cdclk(struct intel_atomic_state *state, plane->base.base.id, plane->base.name, new_crtc_state->min_cdclk[plane->id], crtc->base.base.id, crtc->base.name, - cdclk_state->min_cdclk[crtc->pipe]); + intel_cdclk_min_cdclk(cdclk_state, crtc->pipe)); *need_cdclk_calc = true; return 0; @@ -734,8 +740,8 @@ intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id) return NULL; } -int intel_plane_atomic_check(struct intel_atomic_state *state, - struct intel_plane *plane) +static int plane_atomic_check(struct intel_atomic_state *state, + struct intel_plane *plane) { struct intel_display *display = to_intel_display(state); struct intel_plane_state *new_plane_state = @@ -983,10 +989,10 @@ void intel_crtc_planes_update_arm(struct intel_dsb *dsb, i9xx_crtc_planes_update_arm(dsb, state, crtc); } -int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state, - struct intel_crtc_state *crtc_state, - int min_scale, int max_scale, - bool can_position) +int intel_plane_check_clipping(struct intel_plane_state *plane_state, + struct intel_crtc_state *crtc_state, + int min_scale, int max_scale, + bool can_position) { struct intel_display *display = to_intel_display(plane_state); struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); @@ -1085,7 +1091,8 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) /* Wa_16023981245 */ if ((DISPLAY_VERx100(display) == 2000 || - DISPLAY_VERx100(display) == 3000) && + DISPLAY_VERx100(display) == 3000 || + DISPLAY_VERx100(display) == 3002) && src_x % 2 != 0) hsub = 2; } else { @@ -1266,14 +1273,176 @@ intel_cleanup_plane_fb(struct drm_plane *plane, intel_plane_unpin_fb(old_plane_state); } +/* Handle Y-tiling, only if DPT is enabled (otherwise disabling tiling is easier) + * All DPT hardware have 128-bytes width tiling, so Y-tile dimension is 32x32 + * pixels for 32bits pixels. + */ +#define YTILE_WIDTH 32 +#define YTILE_HEIGHT 32 +#define YTILE_SIZE (YTILE_WIDTH * YTILE_HEIGHT * 4) + +static unsigned int intel_ytile_get_offset(unsigned int width, unsigned int x, unsigned int y) +{ + u32 offset; + unsigned int swizzle; + unsigned int width_in_blocks = DIV_ROUND_UP(width, 32); + + /* Block offset */ + offset = ((y / YTILE_HEIGHT) * width_in_blocks + (x / YTILE_WIDTH)) * YTILE_SIZE; + + x = x % YTILE_WIDTH; + y = y % YTILE_HEIGHT; + + /* bit order inside a block is x4 x3 x2 y4 y3 y2 y1 y0 x1 x0 */ + swizzle = (x & 3) | ((y & 0x1f) << 2) | ((x & 0x1c) << 5); + offset += swizzle * 4; + return offset; +} + +static unsigned int intel_4tile_get_offset(unsigned int width, unsigned int x, unsigned int y) +{ + u32 offset; + unsigned int swizzle; + unsigned int width_in_blocks = DIV_ROUND_UP(width, 32); + + /* Block offset */ + offset = ((y / YTILE_HEIGHT) * width_in_blocks + (x / YTILE_WIDTH)) * YTILE_SIZE; + + x = x % YTILE_WIDTH; + y = y % YTILE_HEIGHT; + + /* bit order inside a block is y4 y3 x4 y2 x3 x2 y1 y0 x1 x0 */ + swizzle = (x & 3) | ((y & 3) << 2) | ((x & 0xc) << 2) | (y & 4) << 4 | + ((x & 0x10) << 3) | ((y & 0x18) << 5); + offset += swizzle * 4; + return offset; +} + +static void intel_panic_flush(struct drm_plane *plane) +{ + struct intel_plane_state *plane_state = to_intel_plane_state(plane->state); + struct intel_crtc_state *crtc_state = to_intel_crtc_state(plane->state->crtc->state); + struct intel_plane *iplane = to_intel_plane(plane); + struct intel_display *display = to_intel_display(iplane); + struct drm_framebuffer *fb = plane_state->hw.fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + + intel_bo_panic_finish(intel_fb); + + if (crtc_state->enable_psr2_sel_fetch) { + /* Force a full update for psr2 */ + intel_psr2_panic_force_full_update(display, crtc_state); + } + + /* Flush the cache and don't disable tiling if it's the fbdev framebuffer.*/ + if (intel_fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) { + struct iosys_map map; + + intel_fbdev_get_map(display->fbdev.fbdev, &map); + drm_clflush_virt_range(map.vaddr, fb->pitches[0] * fb->height); + return; + } + + if (fb->modifier && iplane->disable_tiling) + iplane->disable_tiling(iplane); +} + +static unsigned int (*intel_get_tiling_func(u64 fb_modifier))(unsigned int width, + unsigned int x, + unsigned int y) +{ + switch (fb_modifier) { + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + return intel_ytile_get_offset; + case I915_FORMAT_MOD_4_TILED: + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS: + case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS: + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC: + case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS: + case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC: + case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS: + case I915_FORMAT_MOD_4_TILED_BMG_CCS: + case I915_FORMAT_MOD_4_TILED_LNL_CCS: + return intel_4tile_get_offset; + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Yf_TILED: + case I915_FORMAT_MOD_Yf_TILED_CCS: + default: + /* Not supported yet */ + return NULL; + } +} + +static int intel_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct intel_plane_state *plane_state; + struct drm_gem_object *obj; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + struct intel_display *display = to_intel_display(plane->dev); + + if (!plane->state || !plane->state->fb || !plane->state->visible) + return -ENODEV; + + plane_state = to_intel_plane_state(plane->state); + fb = plane_state->hw.fb; + intel_fb = to_intel_framebuffer(fb); + + obj = intel_fb_bo(fb); + if (!obj) + return -ENODEV; + + if (intel_fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) { + intel_fbdev_get_map(display->fbdev.fbdev, &sb->map[0]); + } else { + int ret; + /* Can't disable tiling if DPT is in use */ + if (intel_fb_uses_dpt(fb)) { + if (fb->format->cpp[0] != 4) + return -EOPNOTSUPP; + intel_fb->panic_tiling = intel_get_tiling_func(fb->modifier); + if (!intel_fb->panic_tiling) + return -EOPNOTSUPP; + } + sb->private = intel_fb; + ret = intel_bo_panic_setup(sb); + if (ret) + return ret; + } + sb->width = fb->width; + sb->height = fb->height; + /* Use the generic linear format, because tiling, RC, CCS, CC + * will be disabled in disable_tiling() + */ + sb->format = drm_format_info(fb->format->format); + sb->pitch[0] = fb->pitches[0]; + + return 0; +} + static const struct drm_plane_helper_funcs intel_plane_helper_funcs = { .prepare_fb = intel_prepare_plane_fb, .cleanup_fb = intel_cleanup_plane_fb, }; +static const struct drm_plane_helper_funcs intel_primary_plane_helper_funcs = { + .prepare_fb = intel_prepare_plane_fb, + .cleanup_fb = intel_cleanup_plane_fb, + .get_scanout_buffer = intel_get_scanout_buffer, + .panic_flush = intel_panic_flush, +}; + void intel_plane_helper_add(struct intel_plane *plane) { - drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); + if (plane->base.type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(&plane->base, &intel_primary_plane_helper_funcs); + else + drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); } void intel_plane_init_cursor_vblank_work(struct intel_plane_state *old_plane_state, @@ -1433,8 +1602,8 @@ static int intel_crtc_add_planes_to_state(struct intel_atomic_state *state, return 0; } -int intel_atomic_add_affected_planes(struct intel_atomic_state *state, - struct intel_crtc *crtc) +int intel_plane_add_affected(struct intel_atomic_state *state, + struct intel_crtc *crtc) { const struct intel_crtc_state *old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); @@ -1528,7 +1697,7 @@ static int intel_add_affected_planes(struct intel_atomic_state *state) return 0; } -int intel_atomic_check_planes(struct intel_atomic_state *state) +int intel_plane_atomic_check(struct intel_atomic_state *state) { struct intel_display *display = to_intel_display(state); struct intel_crtc_state *old_crtc_state, *new_crtc_state; @@ -1542,7 +1711,7 @@ int intel_atomic_check_planes(struct intel_atomic_state *state) return ret; for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - ret = intel_plane_atomic_check(state, plane); + ret = plane_atomic_check(state, plane); if (ret) { drm_dbg_atomic(display->drm, "[PLANE:%d:%s] atomic driver check failed\n", diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_plane.h index 317320c32285..4ef012c08fa4 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h +++ b/drivers/gpu/drm/i915/display/intel_plane.h @@ -3,8 +3,8 @@ * Copyright © 2019 Intel Corporation */ -#ifndef __INTEL_ATOMIC_PLANE_H__ -#define __INTEL_ATOMIC_PLANE_H__ +#ifndef __INTEL_PLANE_H__ +#define __INTEL_PLANE_H__ #include <linux/types.h> @@ -69,15 +69,13 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ struct intel_crtc_state *crtc_state, const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state); -int intel_plane_atomic_check(struct intel_atomic_state *state, - struct intel_plane *plane); int intel_plane_calc_min_cdclk(struct intel_atomic_state *state, struct intel_plane *plane, bool *need_cdclk_calc); -int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state, - struct intel_crtc_state *crtc_state, - int min_scale, int max_scale, - bool can_position); +int intel_plane_check_clipping(struct intel_plane_state *plane_state, + struct intel_crtc_state *crtc_state, + int min_scale, int max_scale, + bool can_position); int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state); void intel_plane_set_invisible(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state); @@ -85,13 +83,13 @@ void intel_plane_helper_add(struct intel_plane *plane); bool intel_plane_needs_physical(struct intel_plane *plane); void intel_plane_init_cursor_vblank_work(struct intel_plane_state *old_plane_state, struct intel_plane_state *new_plane_state); -int intel_atomic_add_affected_planes(struct intel_atomic_state *state, - struct intel_crtc *crtc); -int intel_atomic_check_planes(struct intel_atomic_state *state); +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); -#endif /* __INTEL_ATOMIC_PLANE_H__ */ +#endif /* __INTEL_PLANE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 8800a657cd21..4246173ed311 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -6,13 +6,13 @@ #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" #include "i915_drv.h" -#include "intel_atomic_plane.h" #include "intel_crtc.h" #include "intel_display.h" #include "intel_display_core.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_frontbuffer.h" +#include "intel_plane.h" #include "intel_plane_initial.h" void intel_plane_initial_vblank_wait(struct intel_crtc *crtc) @@ -289,7 +289,8 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, mode_cmd.flags = DRM_MODE_FB_MODIFIERS; if (intel_framebuffer_init(to_intel_framebuffer(fb), - intel_bo_to_drm_bo(vma->obj), &mode_cmd)) { + intel_bo_to_drm_bo(vma->obj), + fb->format, &mode_cmd)) { drm_dbg_kms(display->drm, "intel fb init failed\n"); goto err_vma; } diff --git a/drivers/gpu/drm/i915/display/intel_pmdemand.c b/drivers/gpu/drm/i915/display/intel_pmdemand.c index 93d5ee36fff1..d806c15db7ce 100644 --- a/drivers/gpu/drm/i915/display/intel_pmdemand.c +++ b/drivers/gpu/drm/i915/display/intel_pmdemand.c @@ -294,40 +294,17 @@ intel_pmdemand_connector_needs_update(struct intel_atomic_state *state) static bool intel_pmdemand_needs_update(struct intel_atomic_state *state) { - struct intel_display *display = to_intel_display(state); - const struct intel_bw_state *new_bw_state, *old_bw_state; - const struct intel_cdclk_state *new_cdclk_state, *old_cdclk_state; const struct intel_crtc_state *new_crtc_state, *old_crtc_state; - const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; struct intel_crtc *crtc; int i; - new_bw_state = intel_atomic_get_new_bw_state(state); - old_bw_state = intel_atomic_get_old_bw_state(state); - if (new_bw_state && new_bw_state->qgv_point_peakbw != - old_bw_state->qgv_point_peakbw) + if (intel_bw_pmdemand_needs_update(state)) return true; - new_dbuf_state = intel_atomic_get_new_dbuf_state(state); - old_dbuf_state = intel_atomic_get_old_dbuf_state(state); - if (new_dbuf_state && - new_dbuf_state->active_pipes != old_dbuf_state->active_pipes) + if (intel_dbuf_pmdemand_needs_update(state)) return true; - if (DISPLAY_VER(display) < 30) { - if (new_dbuf_state && - new_dbuf_state->enabled_slices != - old_dbuf_state->enabled_slices) - return true; - } - - new_cdclk_state = intel_atomic_get_new_cdclk_state(state); - old_cdclk_state = intel_atomic_get_old_cdclk_state(state); - if (new_cdclk_state && - (new_cdclk_state->actual.cdclk != - old_cdclk_state->actual.cdclk || - new_cdclk_state->actual.voltage_level != - old_cdclk_state->actual.voltage_level)) + if (intel_cdclk_pmdemand_needs_update(state)) return true; for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, @@ -362,7 +339,7 @@ int intel_pmdemand_atomic_check(struct intel_atomic_state *state) /* firmware will calculate the qclk_gv_index, requirement is set to 0 */ new_pmdemand_state->params.qclk_gv_index = 0; - new_pmdemand_state->params.qclk_gv_bw = new_bw_state->qgv_point_peakbw; + new_pmdemand_state->params.qclk_gv_bw = intel_bw_qgv_point_peakbw(new_bw_state); new_dbuf_state = intel_atomic_get_dbuf_state(state); if (IS_ERR(new_dbuf_state)) @@ -370,12 +347,12 @@ int intel_pmdemand_atomic_check(struct intel_atomic_state *state) if (DISPLAY_VER(display) < 30) { new_pmdemand_state->params.active_dbufs = - min_t(u8, hweight8(new_dbuf_state->enabled_slices), 3); + min_t(u8, intel_dbuf_num_enabled_slices(new_dbuf_state), 3); new_pmdemand_state->params.active_pipes = - min_t(u8, hweight8(new_dbuf_state->active_pipes), 3); + min_t(u8, intel_dbuf_num_active_pipes(new_dbuf_state), 3); } else { new_pmdemand_state->params.active_pipes = - min_t(u8, hweight8(new_dbuf_state->active_pipes), INTEL_NUM_PIPES(display)); + min_t(u8, intel_dbuf_num_active_pipes(new_dbuf_state), INTEL_NUM_PIPES(display)); } new_cdclk_state = intel_atomic_get_cdclk_state(state); @@ -383,9 +360,9 @@ int intel_pmdemand_atomic_check(struct intel_atomic_state *state) return PTR_ERR(new_cdclk_state); new_pmdemand_state->params.voltage_index = - new_cdclk_state->actual.voltage_level; + intel_cdclk_actual_voltage_level(new_cdclk_state); new_pmdemand_state->params.cdclk_freq_mhz = - DIV_ROUND_UP(new_cdclk_state->actual.cdclk, 1000); + DIV_ROUND_UP(intel_cdclk_actual(new_cdclk_state), 1000); intel_pmdemand_update_max_ddiclk(display, state, new_pmdemand_state); diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index bff81fb5c316..b64d0b30f5b1 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -5,9 +5,11 @@ #include <linux/debugfs.h> +#include <drm/drm_print.h> + #include "g4x_dp.h" -#include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_de.h" #include "intel_display_power_well.h" #include "intel_display_regs.h" @@ -892,7 +894,6 @@ static void edp_panel_vdd_work(struct work_struct *__work) static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *i915 = to_i915(display->drm); unsigned long delay; /* @@ -908,7 +909,7 @@ static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp) * operations. */ delay = msecs_to_jiffies(intel_dp->pps.panel_power_cycle_delay * 5); - queue_delayed_work(i915->unordered_wq, + queue_delayed_work(display->wq.unordered, &intel_dp->pps.panel_vdd_work, delay); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 8bee2f592ae7..41988e193a41 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -28,7 +28,6 @@ #include <drm/drm_debugfs.h> #include <drm/drm_vblank.h> -#include "i915_drv.h" #include "i915_reg.h" #include "intel_alpm.h" #include "intel_atomic.h" @@ -48,6 +47,7 @@ #include "intel_psr.h" #include "intel_psr_regs.h" #include "intel_snps_phy.h" +#include "intel_step.h" #include "intel_vblank.h" #include "intel_vrr.h" #include "skl_universal_plane.h" @@ -448,7 +448,6 @@ static void psr_event_print(struct intel_display *display, void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; ktime_t time_ns = ktime_get(); @@ -493,7 +492,7 @@ void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) intel_de_rmw(display, psr_imr_reg(display, cpu_transcoder), 0, psr_irq_psr_error_bit_get(intel_dp)); - queue_work(dev_priv->unordered_wq, &intel_dp->psr.work); + queue_work(display->wq.unordered, &intel_dp->psr.work); } } @@ -2889,6 +2888,26 @@ skip_sel_fetch_set_loop: return 0; } +void intel_psr2_panic_force_full_update(struct intel_display *display, + struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 val = man_trk_ctl_enable_bit_get(display); + + /* SF partial frame enable has to be set even on full update */ + val |= man_trk_ctl_partial_frame_bit_get(display); + val |= man_trk_ctl_continuos_full_frame(display); + + /* Directly write the register */ + intel_de_write_fw(display, PSR2_MAN_TRK_CTL(display, cpu_transcoder), val); + + if (!crtc_state->enable_psr2_su_region_et) + return; + + intel_de_write_fw(display, PIPE_SRCSZ_ERLY_TPT(crtc->pipe), 0); +} + void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -3256,7 +3275,9 @@ static void intel_psr_configure_full_frame_update(struct intel_dp *intel_dp) static void _psr_invalidate_handle(struct intel_dp *intel_dp) { - if (intel_dp->psr.psr2_sel_fetch_enabled) { + struct intel_display *display = to_intel_display(intel_dp); + + if (DISPLAY_VER(display) < 20 && intel_dp->psr.psr2_sel_fetch_enabled) { if (!intel_dp->psr.psr2_sel_fetch_cff_enabled) { intel_dp->psr.psr2_sel_fetch_cff_enabled = true; intel_psr_configure_full_frame_update(intel_dp); @@ -3320,7 +3341,6 @@ tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, enum fb_op_origin origin) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *i915 = to_i915(display->drm); if (!intel_dp->psr.dc3co_exitline || !intel_dp->psr.sel_update_enabled || !intel_dp->psr.active) @@ -3335,16 +3355,15 @@ tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, return; tgl_psr2_enable_dc3co(intel_dp); - mod_delayed_work(i915->unordered_wq, &intel_dp->psr.dc3co_work, + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, intel_dp->psr.dc3co_exit_delay); } static void _psr_flush_handle(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); - if (intel_dp->psr.psr2_sel_fetch_enabled) { + if (DISPLAY_VER(display) < 20 && intel_dp->psr.psr2_sel_fetch_enabled) { if (intel_dp->psr.psr2_sel_fetch_cff_enabled) { /* can we turn CFF off? */ if (intel_dp->psr.busy_frontbuffer_bits == 0) @@ -3361,13 +3380,15 @@ static void _psr_flush_handle(struct intel_dp *intel_dp) * existing SU configuration */ intel_psr_configure_full_frame_update(intel_dp); - } - intel_psr_force_update(intel_dp); + intel_psr_force_update(intel_dp); + } else { + intel_psr_exit(intel_dp); + } - if (!intel_dp->psr.psr2_sel_fetch_enabled && !intel_dp->psr.active && + if ((!intel_dp->psr.psr2_sel_fetch_enabled || DISPLAY_VER(display) >= 20) && !intel_dp->psr.busy_frontbuffer_bits) - queue_work(dev_priv->unordered_wq, &intel_dp->psr.work); + queue_work(display->wq.unordered, &intel_dp->psr.work); } /** diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 0cf53184f13f..9b061a22361f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -57,6 +57,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_psr2_program_trans_man_trk_ctl(struct intel_dsb *dsb, const struct intel_crtc_state *crtc_state); +void intel_psr2_panic_force_full_update(struct intel_display *display, + struct intel_crtc_state *crtc_state); void intel_psr_pause(struct intel_dp *intel_dp); void intel_psr_resume(struct intel_dp *intel_dp); bool intel_psr_needs_vblank_notification(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c index 74bb3bedf30f..7fe6b4a18213 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c +++ b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c @@ -103,10 +103,10 @@ static void get_ana_cp_int_prop(u64 vco_clk, DIV_ROUND_DOWN_ULL(curve_1_interpolated, CURVE0_MULTIPLIER))); ana_cp_int_temp = - DIV_ROUND_CLOSEST_ULL(DIV_ROUND_DOWN_ULL(adjusted_vco_clk1, curve_2_scaled1), - CURVE2_MULTIPLIER); + DIV64_U64_ROUND_CLOSEST(DIV_ROUND_DOWN_ULL(adjusted_vco_clk1, curve_2_scaled1), + CURVE2_MULTIPLIER); - *ana_cp_int = max(1, min(ana_cp_int_temp, 127)); + *ana_cp_int = clamp(ana_cp_int_temp, 1, 127); curve_2_scaled_int = curve_2_scaled1 * (*ana_cp_int); @@ -125,7 +125,7 @@ static void get_ana_cp_int_prop(u64 vco_clk, curve_1_interpolated); *ana_cp_prop = DIV64_U64_ROUND_UP(adjusted_vco_clk2, curve_2_scaled2); - *ana_cp_prop = max(1, min(*ana_cp_prop, 127)); + *ana_cp_prop = clamp(*ana_cp_prop, 1, 127); } static void compute_hdmi_tmds_pll(u64 pixel_clock, u32 refclk, diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index fd92e6b89b43..e6844df837af 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -41,11 +41,11 @@ #include "i915_utils.h" #include "i9xx_plane.h" -#include "intel_atomic_plane.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_frontbuffer.h" +#include "intel_plane.h" #include "intel_sprite.h" #include "intel_sprite_regs.h" @@ -1366,8 +1366,8 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state, } } - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - min_scale, max_scale, true); + ret = intel_plane_check_clipping(plane_state, crtc_state, + min_scale, max_scale, true); if (ret) return ret; @@ -1421,10 +1421,10 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - true); + ret = intel_plane_check_clipping(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + true); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 3bc57579fe53..668ef139391b 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -23,6 +23,7 @@ #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 @@ -66,6 +67,7 @@ struct intel_tc_port { enum tc_port_mode init_mode; enum phy_fia phy_fia; u8 phy_fia_idx; + u8 max_lane_count; }; static enum intel_display_power_domain @@ -307,6 +309,8 @@ static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val); switch (pin_assignment) { + case DP_PIN_ASSIGNMENT_NONE: + return 0; default: MISSING_CASE(pin_assignment); fallthrough; @@ -365,12 +369,12 @@ static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) } } -int intel_tc_port_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(dig_port); - struct intel_tc_port *tc = to_tc_port(dig_port); + struct intel_display *display = to_intel_display(tc->dig_port); + struct intel_digital_port *dig_port = tc->dig_port; - if (!intel_encoder_is_tc(&dig_port->base) || tc->mode != TC_PORT_DP_ALT) + if (tc->mode != TC_PORT_DP_ALT) return 4; assert_tc_cold_blocked(tc); @@ -384,6 +388,25 @@ int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) return intel_tc_port_get_max_lane_count(dig_port); } +static void read_pin_configuration(struct intel_tc_port *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; +} + void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes) { @@ -596,9 +619,12 @@ static void icl_tc_phy_get_hw_state(struct intel_tc_port *tc) tc_cold_wref = __tc_cold_block(tc, &domain); tc->mode = tc_phy_get_current_mode(tc); - if (tc->mode != TC_PORT_DISCONNECTED) + if (tc->mode != TC_PORT_DISCONNECTED) { tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + } + __tc_cold_unblock(tc, domain, tc_cold_wref); } @@ -656,8 +682,11 @@ static bool icl_tc_phy_connect(struct intel_tc_port *tc, tc->lock_wakeref = tc_cold_block(tc); - if (tc->mode == TC_PORT_TBT_ALT) + if (tc->mode == TC_PORT_TBT_ALT) { + read_pin_configuration(tc); + return true; + } if ((!tc_phy_is_ready(tc) || !icl_tc_phy_take_ownership(tc, true)) && @@ -668,6 +697,7 @@ static bool icl_tc_phy_connect(struct intel_tc_port *tc, goto out_unblock_tc_cold; } + read_pin_configuration(tc); if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes)) goto out_release_phy; @@ -858,9 +888,12 @@ static void adlp_tc_phy_get_hw_state(struct intel_tc_port *tc) port_wakeref = intel_display_power_get(display, port_power_domain); tc->mode = tc_phy_get_current_mode(tc); - if (tc->mode != TC_PORT_DISCONNECTED) + if (tc->mode != TC_PORT_DISCONNECTED) { tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + } + intel_display_power_put(display, port_power_domain, port_wakeref); } @@ -873,6 +906,9 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes) if (tc->mode == TC_PORT_TBT_ALT) { tc->lock_wakeref = tc_cold_block(tc); + + read_pin_configuration(tc); + return true; } @@ -894,6 +930,8 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes) tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes)) goto out_unblock_tc_cold; @@ -1124,9 +1162,18 @@ static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc) tc_cold_wref = __tc_cold_block(tc, &domain); tc->mode = tc_phy_get_current_mode(tc); - if (tc->mode != TC_PORT_DISCONNECTED) + if (tc->mode != TC_PORT_DISCONNECTED) { tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + /* + * Set a valid lane count value for a DP-alt sink which got + * disconnected. The driver can only disable the output on this PHY. + */ + if (tc->max_lane_count == 0) + tc->max_lane_count = 4; + } + drm_WARN_ON(display->drm, (tc->mode == TC_PORT_DP_ALT || tc->mode == TC_PORT_LEGACY) && !xelpdp_tc_phy_tcss_power_is_enabled(tc)); @@ -1138,14 +1185,19 @@ static bool xelpdp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes) { tc->lock_wakeref = tc_cold_block(tc); - if (tc->mode == TC_PORT_TBT_ALT) + if (tc->mode == TC_PORT_TBT_ALT) { + read_pin_configuration(tc); + return true; + } if (!xelpdp_tc_phy_enable_tcss_power(tc, true)) goto out_unblock_tccold; xelpdp_tc_phy_take_ownership(tc, true); + read_pin_configuration(tc); + if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes)) goto out_release_phy; @@ -1226,14 +1278,19 @@ static void tc_phy_get_hw_state(struct intel_tc_port *tc) tc->phy_ops->get_hw_state(tc); } -static bool tc_phy_is_ready_and_owned(struct intel_tc_port *tc, - bool phy_is_ready, bool phy_is_owned) +/* Is the PHY owned by display i.e. is it in legacy or DP-alt mode? */ +static bool tc_phy_owned_by_display(struct intel_tc_port *tc, + bool phy_is_ready, bool phy_is_owned) { struct intel_display *display = to_intel_display(tc->dig_port); - drm_WARN_ON(display->drm, phy_is_owned && !phy_is_ready); + if (DISPLAY_VER(display) < 20) { + drm_WARN_ON(display->drm, phy_is_owned && !phy_is_ready); - return phy_is_ready && phy_is_owned; + return phy_is_ready && phy_is_owned; + } else { + return phy_is_owned; + } } static bool tc_phy_is_connected(struct intel_tc_port *tc, @@ -1244,7 +1301,7 @@ static bool tc_phy_is_connected(struct intel_tc_port *tc, bool phy_is_owned = tc_phy_is_owned(tc); bool is_connected; - if (tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) + if (tc_phy_owned_by_display(tc, phy_is_ready, phy_is_owned)) is_connected = port_pll_type == ICL_PORT_DPLL_MG_PHY; else is_connected = port_pll_type == ICL_PORT_DPLL_DEFAULT; @@ -1352,7 +1409,7 @@ tc_phy_get_current_mode(struct intel_tc_port *tc) phy_is_ready = tc_phy_is_ready(tc); phy_is_owned = tc_phy_is_owned(tc); - if (!tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) { + if (!tc_phy_owned_by_display(tc, phy_is_ready, phy_is_owned)) { mode = get_tc_mode_in_phy_not_owned_state(tc, live_mode); } else { drm_WARN_ON(display->drm, live_mode == TC_PORT_TBT_ALT); @@ -1441,11 +1498,11 @@ static void intel_tc_port_reset_mode(struct intel_tc_port *tc, intel_display_power_flush_work(display); if (!intel_tc_cold_requires_aux_pw(dig_port)) { enum intel_display_power_domain aux_domain; - bool aux_powered; aux_domain = intel_aux_power_domain(dig_port); - aux_powered = intel_display_power_is_enabled(display, aux_domain); - drm_WARN_ON(display->drm, aux_powered); + if (intel_display_power_is_enabled(display, aux_domain)) + drm_dbg_kms(display->drm, "Port %s: AUX unexpectedly powered\n", + tc->port_name); } tc_phy_disconnect(tc); diff --git a/drivers/gpu/drm/i915/display/intel_vrr_regs.h b/drivers/gpu/drm/i915/display/intel_vrr_regs.h index 09cdd50d6187..ba9b9215dc11 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_vrr_regs.h @@ -8,126 +8,119 @@ #include "intel_display_reg_defs.h" -/* VRR registers */ #define _TRANS_VRR_CTL_A 0x60420 #define _TRANS_VRR_CTL_B 0x61420 #define _TRANS_VRR_CTL_C 0x62420 #define _TRANS_VRR_CTL_D 0x63420 -#define TRANS_VRR_CTL(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_VRR_CTL_A) -#define VRR_CTL_VRR_ENABLE REG_BIT(31) -#define VRR_CTL_IGN_MAX_SHIFT REG_BIT(30) -#define VRR_CTL_FLIP_LINE_EN REG_BIT(29) -#define VRR_CTL_PIPELINE_FULL_MASK REG_GENMASK(10, 3) -#define VRR_CTL_PIPELINE_FULL(x) REG_FIELD_PREP(VRR_CTL_PIPELINE_FULL_MASK, (x)) -#define VRR_CTL_PIPELINE_FULL_OVERRIDE REG_BIT(0) -#define XELPD_VRR_CTL_VRR_GUARDBAND_MASK REG_GENMASK(15, 0) -#define XELPD_VRR_CTL_VRR_GUARDBAND(x) REG_FIELD_PREP(XELPD_VRR_CTL_VRR_GUARDBAND_MASK, (x)) +#define TRANS_VRR_CTL(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_CTL_A) +#define VRR_CTL_VRR_ENABLE REG_BIT(31) +#define VRR_CTL_IGN_MAX_SHIFT REG_BIT(30) +#define VRR_CTL_FLIP_LINE_EN REG_BIT(29) +#define VRR_CTL_CMRR_ENABLE REG_BIT(27) +#define VRR_CTL_PIPELINE_FULL_MASK REG_GENMASK(10, 3) +#define VRR_CTL_PIPELINE_FULL(x) REG_FIELD_PREP(VRR_CTL_PIPELINE_FULL_MASK, (x)) +#define VRR_CTL_PIPELINE_FULL_OVERRIDE REG_BIT(0) +#define XELPD_VRR_CTL_VRR_GUARDBAND_MASK REG_GENMASK(15, 0) +#define XELPD_VRR_CTL_VRR_GUARDBAND(x) REG_FIELD_PREP(XELPD_VRR_CTL_VRR_GUARDBAND_MASK, (x)) #define _TRANS_VRR_VMAX_A 0x60424 #define _TRANS_VRR_VMAX_B 0x61424 #define _TRANS_VRR_VMAX_C 0x62424 #define _TRANS_VRR_VMAX_D 0x63424 -#define TRANS_VRR_VMAX(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_VRR_VMAX_A) -#define VRR_VMAX_MASK REG_GENMASK(19, 0) +#define TRANS_VRR_VMAX(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_VMAX_A) +#define VRR_VMAX_MASK REG_GENMASK(19, 0) #define _TRANS_VRR_VMIN_A 0x60434 #define _TRANS_VRR_VMIN_B 0x61434 #define _TRANS_VRR_VMIN_C 0x62434 #define _TRANS_VRR_VMIN_D 0x63434 -#define TRANS_VRR_VMIN(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_VRR_VMIN_A) -#define VRR_VMIN_MASK REG_GENMASK(15, 0) +#define TRANS_VRR_VMIN(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_VMIN_A) +#define VRR_VMIN_MASK REG_GENMASK(15, 0) #define _TRANS_VRR_VMAXSHIFT_A 0x60428 #define _TRANS_VRR_VMAXSHIFT_B 0x61428 #define _TRANS_VRR_VMAXSHIFT_C 0x62428 #define _TRANS_VRR_VMAXSHIFT_D 0x63428 -#define TRANS_VRR_VMAXSHIFT(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, \ - _TRANS_VRR_VMAXSHIFT_A) -#define VRR_VMAXSHIFT_DEC_MASK REG_GENMASK(29, 16) -#define VRR_VMAXSHIFT_DEC REG_BIT(16) -#define VRR_VMAXSHIFT_INC_MASK REG_GENMASK(12, 0) +#define TRANS_VRR_VMAXSHIFT(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_VMAXSHIFT_A) +#define VRR_VMAXSHIFT_DEC_MASK REG_GENMASK(29, 16) +#define VRR_VMAXSHIFT_DEC REG_BIT(16) +#define VRR_VMAXSHIFT_INC_MASK REG_GENMASK(12, 0) #define _TRANS_VRR_STATUS_A 0x6042c #define _TRANS_VRR_STATUS_B 0x6142c #define _TRANS_VRR_STATUS_C 0x6242c #define _TRANS_VRR_STATUS_D 0x6342c -#define TRANS_VRR_STATUS(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_VRR_STATUS_A) -#define VRR_STATUS_VMAX_REACHED REG_BIT(31) -#define VRR_STATUS_NOFLIP_TILL_BNDR REG_BIT(30) -#define VRR_STATUS_FLIP_BEF_BNDR REG_BIT(29) -#define VRR_STATUS_NO_FLIP_FRAME REG_BIT(28) -#define VRR_STATUS_VRR_EN_LIVE REG_BIT(27) -#define VRR_STATUS_FLIPS_SERVICED REG_BIT(26) -#define VRR_STATUS_VBLANK_MASK REG_GENMASK(22, 20) -#define STATUS_FSM_IDLE REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 0) -#define STATUS_FSM_WAIT_TILL_FDB REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 1) -#define STATUS_FSM_WAIT_TILL_FS REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 2) -#define STATUS_FSM_WAIT_TILL_FLIP REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 3) -#define STATUS_FSM_PIPELINE_FILL REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 4) -#define STATUS_FSM_ACTIVE REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 5) -#define STATUS_FSM_LEGACY_VBLANK REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 6) +#define TRANS_VRR_STATUS(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_STATUS_A) +#define VRR_STATUS_VMAX_REACHED REG_BIT(31) +#define VRR_STATUS_NOFLIP_TILL_BNDR REG_BIT(30) +#define VRR_STATUS_FLIP_BEF_BNDR REG_BIT(29) +#define VRR_STATUS_NO_FLIP_FRAME REG_BIT(28) +#define VRR_STATUS_VRR_EN_LIVE REG_BIT(27) +#define VRR_STATUS_FLIPS_SERVICED REG_BIT(26) +#define VRR_STATUS_VBLANK_MASK REG_GENMASK(22, 20) +#define STATUS_FSM_IDLE REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 0) +#define STATUS_FSM_WAIT_TILL_FDB REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 1) +#define STATUS_FSM_WAIT_TILL_FS REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 2) +#define STATUS_FSM_WAIT_TILL_FLIP REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 3) +#define STATUS_FSM_PIPELINE_FILL REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 4) +#define STATUS_FSM_ACTIVE REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 5) +#define STATUS_FSM_LEGACY_VBLANK REG_FIELD_PREP(VRR_STATUS_VBLANK_MASK, 6) #define _TRANS_VRR_VTOTAL_PREV_A 0x60480 #define _TRANS_VRR_VTOTAL_PREV_B 0x61480 #define _TRANS_VRR_VTOTAL_PREV_C 0x62480 #define _TRANS_VRR_VTOTAL_PREV_D 0x63480 -#define TRANS_VRR_VTOTAL_PREV(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, \ - _TRANS_VRR_VTOTAL_PREV_A) -#define VRR_VTOTAL_FLIP_BEFR_BNDR REG_BIT(31) -#define VRR_VTOTAL_FLIP_AFTER_BNDR REG_BIT(30) -#define VRR_VTOTAL_FLIP_AFTER_DBLBUF REG_BIT(29) -#define VRR_VTOTAL_PREV_FRAME_MASK REG_GENMASK(19, 0) +#define TRANS_VRR_VTOTAL_PREV(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_VTOTAL_PREV_A) +#define VRR_VTOTAL_FLIP_BEFR_BNDR REG_BIT(31) +#define VRR_VTOTAL_FLIP_AFTER_BNDR REG_BIT(30) +#define VRR_VTOTAL_FLIP_AFTER_DBLBUF REG_BIT(29) +#define VRR_VTOTAL_PREV_FRAME_MASK REG_GENMASK(19, 0) #define _TRANS_VRR_FLIPLINE_A 0x60438 #define _TRANS_VRR_FLIPLINE_B 0x61438 #define _TRANS_VRR_FLIPLINE_C 0x62438 #define _TRANS_VRR_FLIPLINE_D 0x63438 -#define TRANS_VRR_FLIPLINE(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, \ - _TRANS_VRR_FLIPLINE_A) -#define VRR_FLIPLINE_MASK REG_GENMASK(19, 0) +#define TRANS_VRR_FLIPLINE(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_FLIPLINE_A) +#define VRR_FLIPLINE_MASK REG_GENMASK(19, 0) #define _TRANS_VRR_STATUS2_A 0x6043c #define _TRANS_VRR_STATUS2_B 0x6143c #define _TRANS_VRR_STATUS2_C 0x6243c #define _TRANS_VRR_STATUS2_D 0x6343c -#define TRANS_VRR_STATUS2(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_VRR_STATUS2_A) -#define VRR_STATUS2_VERT_LN_CNT_MASK REG_GENMASK(19, 0) +#define TRANS_VRR_STATUS2(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_STATUS2_A) +#define VRR_STATUS2_VERT_LN_CNT_MASK REG_GENMASK(19, 0) #define _TRANS_PUSH_A 0x60a70 #define _TRANS_PUSH_B 0x61a70 #define _TRANS_PUSH_C 0x62a70 #define _TRANS_PUSH_D 0x63a70 -#define TRANS_PUSH(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_PUSH_A) -#define TRANS_PUSH_EN REG_BIT(31) -#define TRANS_PUSH_SEND REG_BIT(30) +#define TRANS_PUSH(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_PUSH_A) +#define TRANS_PUSH_EN REG_BIT(31) +#define TRANS_PUSH_SEND REG_BIT(30) #define _TRANS_VRR_VSYNC_A 0x60078 -#define TRANS_VRR_VSYNC(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_VRR_VSYNC_A) -#define VRR_VSYNC_END_MASK REG_GENMASK(28, 16) -#define VRR_VSYNC_END(vsync_end) REG_FIELD_PREP(VRR_VSYNC_END_MASK, (vsync_end)) -#define VRR_VSYNC_START_MASK REG_GENMASK(12, 0) -#define VRR_VSYNC_START(vsync_start) REG_FIELD_PREP(VRR_VSYNC_START_MASK, (vsync_start)) +#define TRANS_VRR_VSYNC(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_VSYNC_A) +#define VRR_VSYNC_END_MASK REG_GENMASK(28, 16) +#define VRR_VSYNC_END(vsync_end) REG_FIELD_PREP(VRR_VSYNC_END_MASK, (vsync_end)) +#define VRR_VSYNC_START_MASK REG_GENMASK(12, 0) +#define VRR_VSYNC_START(vsync_start) REG_FIELD_PREP(VRR_VSYNC_START_MASK, (vsync_start)) /* Common register for HDMI EMP and DP AS SDP */ #define _EMP_AS_SDP_TL_A 0x60204 -#define EMP_AS_SDP_DB_TL_MASK REG_GENMASK(12, 0) -#define EMP_AS_SDP_TL(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _EMP_AS_SDP_TL_A) -#define EMP_AS_SDP_DB_TL(db_transmit_line) REG_FIELD_PREP(EMP_AS_SDP_DB_TL_MASK, (db_transmit_line)) - -/*CMRR Registers*/ +#define EMP_AS_SDP_TL(display, trans) _MMIO_TRANS2((display), (trans), _EMP_AS_SDP_TL_A) +#define EMP_AS_SDP_DB_TL_MASK REG_GENMASK(12, 0) +#define EMP_AS_SDP_DB_TL(db_transmit_line) REG_FIELD_PREP(EMP_AS_SDP_DB_TL_MASK, (db_transmit_line)) #define _TRANS_CMRR_M_LO_A 0x604F0 -#define TRANS_CMRR_M_LO(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_CMRR_M_LO_A) +#define TRANS_CMRR_M_LO(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_CMRR_M_LO_A) #define _TRANS_CMRR_M_HI_A 0x604F4 -#define TRANS_CMRR_M_HI(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_CMRR_M_HI_A) +#define TRANS_CMRR_M_HI(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_CMRR_M_HI_A) #define _TRANS_CMRR_N_LO_A 0x604F8 -#define TRANS_CMRR_N_LO(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_CMRR_N_LO_A) +#define TRANS_CMRR_N_LO(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_CMRR_N_LO_A) #define _TRANS_CMRR_N_HI_A 0x604FC -#define TRANS_CMRR_N_HI(dev_priv, trans) _MMIO_TRANS2(dev_priv, trans, _TRANS_CMRR_N_HI_A) - -#define VRR_CTL_CMRR_ENABLE REG_BIT(27) +#define TRANS_CMRR_N_HI(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_CMRR_N_HI_A) #endif /* __INTEL_VRR_REGS__ */ diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 2aa64482d44b..e20972ddfa09 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -9,9 +9,7 @@ #include <drm/drm_fourcc.h> #include "pxp/intel_pxp.h" - #include "i915_drv.h" -#include "intel_atomic_plane.h" #include "intel_bo.h" #include "intel_de.h" #include "intel_display_irq.h" @@ -21,6 +19,7 @@ #include "intel_fb.h" #include "intel_fbc.h" #include "intel_frontbuffer.h" +#include "intel_plane.h" #include "intel_psr.h" #include "intel_psr_regs.h" #include "skl_scaler.h" @@ -2328,8 +2327,8 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, max_scale = skl_plane_max_scale(display, fb); } - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - min_scale, max_scale, true); + ret = intel_plane_check_clipping(plane_state, crtc_state, + min_scale, max_scale, true); if (ret) return ret; @@ -2792,6 +2791,32 @@ static u8 tgl_plane_caps(struct intel_display *display, return caps; } +static void skl_disable_tiling(struct intel_plane *plane) +{ + struct intel_plane_state *state = to_intel_plane_state(plane->base.state); + struct intel_display *display = to_intel_display(plane); + const struct drm_framebuffer *fb = state->hw.fb; + u32 plane_ctl; + + plane_ctl = intel_de_read(display, PLANE_CTL(plane->pipe, plane->id)); + + if (intel_fb_uses_dpt(fb)) { + /* if DPT is enabled, keep tiling, but disable compression */ + plane_ctl &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; + } else { + /* if DPT is not supported, disable tiling, and update stride */ + u32 stride = state->view.color_plane[0].scanout_stride / 64; + + plane_ctl &= ~PLANE_CTL_TILED_MASK; + intel_de_write_fw(display, PLANE_STRIDE(plane->pipe, plane->id), + PLANE_STRIDE_(stride)); + } + 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)); +} + struct intel_plane * skl_universal_plane_create(struct intel_display *display, enum pipe pipe, enum plane_id plane_id) @@ -2838,6 +2863,7 @@ skl_universal_plane_create(struct intel_display *display, plane->max_height = skl_plane_max_height; plane->min_cdclk = skl_plane_min_cdclk; } + plane->disable_tiling = skl_disable_tiling; if (DISPLAY_VER(display) >= 13) plane->max_stride = adl_plane_max_stride; @@ -3010,7 +3036,7 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, return; } - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + intel_fb = intel_bo_alloc_framebuffer(); if (!intel_fb) { drm_dbg_kms(display->drm, "failed to alloc fb\n"); return; diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 2c2371574d6f..222c069fdadb 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -6,14 +6,14 @@ #include <linux/debugfs.h> #include <drm/drm_blend.h> +#include <drm/drm_file.h> +#include <drm/drm_print.h> #include "soc/intel_dram.h" - -#include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "i9xx_wm.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" #include "intel_bw.h" #include "intel_cdclk.h" #include "intel_crtc.h" @@ -26,17 +26,33 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fixed.h" +#include "intel_flipq.h" #include "intel_pcode.h" +#include "intel_plane.h" #include "intel_wm.h" #include "skl_universal_plane_regs.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" -/*It is expected that DSB can do posted writes to every register in - * the pipe and planes within 100us. For flip queue use case, the - * recommended DSB execution time is 100us + one SAGV block time. - */ -#define DSB_EXE_TIME 100 +struct intel_dbuf_state { + struct intel_global_state base; + + struct skl_ddb_entry ddb[I915_MAX_PIPES]; + unsigned int weight[I915_MAX_PIPES]; + u8 slices[I915_MAX_PIPES]; + u8 enabled_slices; + u8 active_pipes; + u8 mdclk_cdclk_ratio; + bool joined_mbus; +}; + +#define to_intel_dbuf_state(global_state) \ + container_of_const((global_state), struct intel_dbuf_state, base) + +#define intel_atomic_get_old_dbuf_state(state) \ + to_intel_dbuf_state(intel_atomic_get_old_global_obj_state(state, &to_intel_display(state)->dbuf.obj)) +#define intel_atomic_get_new_dbuf_state(state) \ + to_intel_dbuf_state(intel_atomic_get_new_global_obj_state(state, &to_intel_display(state)->dbuf.obj)) static void skl_sagv_disable(struct intel_display *display); @@ -87,8 +103,6 @@ intel_has_sagv(struct intel_display *display) static u32 intel_sagv_block_time(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - if (DISPLAY_VER(display) >= 14) { u32 val; @@ -99,9 +113,9 @@ intel_sagv_block_time(struct intel_display *display) u32 val = 0; int ret; - ret = snb_pcode_read(&i915->uncore, - GEN12_PCODE_READ_SAGV_BLOCK_TIME_US, - &val, NULL); + ret = intel_pcode_read(display->drm, + GEN12_PCODE_READ_SAGV_BLOCK_TIME_US, + &val, NULL); if (ret) { drm_dbg_kms(display->drm, "Couldn't read SAGV block time!\n"); return 0; @@ -159,7 +173,6 @@ static void intel_sagv_init(struct intel_display *display) */ static void skl_sagv_enable(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); int ret; if (!intel_has_sagv(display)) @@ -169,8 +182,8 @@ static void skl_sagv_enable(struct intel_display *display) return; drm_dbg_kms(display->drm, "Enabling SAGV\n"); - ret = snb_pcode_write(&i915->uncore, GEN9_PCODE_SAGV_CONTROL, - GEN9_SAGV_ENABLE); + ret = intel_pcode_write(display->drm, GEN9_PCODE_SAGV_CONTROL, + GEN9_SAGV_ENABLE); /* We don't need to wait for SAGV when enabling */ @@ -192,7 +205,6 @@ static void skl_sagv_enable(struct intel_display *display) static void skl_sagv_disable(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); int ret; if (!intel_has_sagv(display)) @@ -203,10 +215,9 @@ static void skl_sagv_disable(struct intel_display *display) drm_dbg_kms(display->drm, "Disabling SAGV\n"); /* bspec says to keep retrying for at least 1 ms */ - ret = skl_pcode_request(&i915->uncore, GEN9_PCODE_SAGV_CONTROL, - GEN9_SAGV_DISABLE, - GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED, - 1); + ret = intel_pcode_request(display->drm, GEN9_PCODE_SAGV_CONTROL, + GEN9_SAGV_DISABLE, + GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED, 1); /* * Some skl systems, pre-release machines in particular, * don't actually have SAGV. @@ -232,7 +243,7 @@ static void skl_sagv_pre_plane_update(struct intel_atomic_state *state) if (!new_bw_state) return; - if (!intel_can_enable_sagv(display, new_bw_state)) + if (!intel_bw_can_enable_sagv(display, new_bw_state)) skl_sagv_disable(display); } @@ -245,74 +256,10 @@ static void skl_sagv_post_plane_update(struct intel_atomic_state *state) if (!new_bw_state) return; - if (intel_can_enable_sagv(display, new_bw_state)) + if (intel_bw_can_enable_sagv(display, new_bw_state)) skl_sagv_enable(display); } -static void icl_sagv_pre_plane_update(struct intel_atomic_state *state) -{ - struct intel_display *display = to_intel_display(state); - const struct intel_bw_state *old_bw_state = - intel_atomic_get_old_bw_state(state); - const struct intel_bw_state *new_bw_state = - intel_atomic_get_new_bw_state(state); - u16 old_mask, new_mask; - - if (!new_bw_state) - return; - - old_mask = old_bw_state->qgv_points_mask; - new_mask = old_bw_state->qgv_points_mask | new_bw_state->qgv_points_mask; - - if (old_mask == new_mask) - return; - - WARN_ON(!new_bw_state->base.changed); - - drm_dbg_kms(display->drm, "Restricting QGV points: 0x%x -> 0x%x\n", - old_mask, new_mask); - - /* - * Restrict required qgv points before updating the configuration. - * According to BSpec we can't mask and unmask qgv points at the same - * time. Also masking should be done before updating the configuration - * and unmasking afterwards. - */ - icl_pcode_restrict_qgv_points(display, new_mask); -} - -static void icl_sagv_post_plane_update(struct intel_atomic_state *state) -{ - struct intel_display *display = to_intel_display(state); - const struct intel_bw_state *old_bw_state = - intel_atomic_get_old_bw_state(state); - const struct intel_bw_state *new_bw_state = - intel_atomic_get_new_bw_state(state); - u16 old_mask, new_mask; - - if (!new_bw_state) - return; - - old_mask = old_bw_state->qgv_points_mask | new_bw_state->qgv_points_mask; - new_mask = new_bw_state->qgv_points_mask; - - if (old_mask == new_mask) - return; - - WARN_ON(!new_bw_state->base.changed); - - drm_dbg_kms(display->drm, "Relaxing QGV points: 0x%x -> 0x%x\n", - old_mask, new_mask); - - /* - * Allow required qgv points after updating the configuration. - * According to BSpec we can't mask and unmask qgv points at the same - * time. Also masking should be done before updating the configuration - * and unmasking afterwards. - */ - icl_pcode_restrict_qgv_points(display, new_mask); -} - void intel_sagv_pre_plane_update(struct intel_atomic_state *state) { struct intel_display *display = to_intel_display(state); @@ -446,16 +393,6 @@ bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) return skl_crtc_can_enable_sagv(crtc_state); } -bool intel_can_enable_sagv(struct intel_display *display, - const struct intel_bw_state *bw_state) -{ - if (DISPLAY_VER(display) < 11 && - bw_state->active_pipes && !is_power_of_2(bw_state->active_pipes)) - return false; - - return bw_state->pipe_sagv_reject == 0; -} - static u16 skl_ddb_entry_init(struct skl_ddb_entry *entry, u16 start, u16 end) { @@ -2236,7 +2173,7 @@ cdclk_prefill_adjustment(const struct intel_crtc_state *crtc_state) } return min(1, DIV_ROUND_UP(crtc_state->pixel_rate, - 2 * cdclk_state->logical.cdclk)); + 2 * intel_cdclk_logical(cdclk_state))); } static int @@ -2680,6 +2617,97 @@ static char enast(bool enable) return enable ? '*' : ' '; } +static noinline_for_stack void +skl_print_plane_changes(struct intel_display *display, + struct intel_plane *plane, + const struct skl_plane_wm *old_wm, + const struct skl_plane_wm *new_wm) +{ + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm" + " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm\n", + plane->base.base.id, plane->base.name, + enast(old_wm->wm[0].enable), enast(old_wm->wm[1].enable), + enast(old_wm->wm[2].enable), enast(old_wm->wm[3].enable), + enast(old_wm->wm[4].enable), enast(old_wm->wm[5].enable), + enast(old_wm->wm[6].enable), enast(old_wm->wm[7].enable), + enast(old_wm->trans_wm.enable), + enast(old_wm->sagv.wm0.enable), + enast(old_wm->sagv.trans_wm.enable), + enast(new_wm->wm[0].enable), enast(new_wm->wm[1].enable), + enast(new_wm->wm[2].enable), enast(new_wm->wm[3].enable), + enast(new_wm->wm[4].enable), enast(new_wm->wm[5].enable), + enast(new_wm->wm[6].enable), enast(new_wm->wm[7].enable), + enast(new_wm->trans_wm.enable), + enast(new_wm->sagv.wm0.enable), + enast(new_wm->sagv.trans_wm.enable)); + + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d" + " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d\n", + plane->base.base.id, plane->base.name, + enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].lines, + enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].lines, + enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].lines, + enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].lines, + enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].lines, + enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].lines, + enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].lines, + enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].lines, + enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.lines, + enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.lines, + enast(old_wm->sagv.trans_wm.ignore_lines), old_wm->sagv.trans_wm.lines, + enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].lines, + enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].lines, + enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].lines, + enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].lines, + enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].lines, + enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].lines, + enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].lines, + enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].lines, + enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.lines, + enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.lines, + enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.lines); + + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", + plane->base.base.id, plane->base.name, + old_wm->wm[0].blocks, old_wm->wm[1].blocks, + old_wm->wm[2].blocks, old_wm->wm[3].blocks, + old_wm->wm[4].blocks, old_wm->wm[5].blocks, + old_wm->wm[6].blocks, old_wm->wm[7].blocks, + old_wm->trans_wm.blocks, + old_wm->sagv.wm0.blocks, + old_wm->sagv.trans_wm.blocks, + new_wm->wm[0].blocks, new_wm->wm[1].blocks, + new_wm->wm[2].blocks, new_wm->wm[3].blocks, + new_wm->wm[4].blocks, new_wm->wm[5].blocks, + new_wm->wm[6].blocks, new_wm->wm[7].blocks, + new_wm->trans_wm.blocks, + new_wm->sagv.wm0.blocks, + new_wm->sagv.trans_wm.blocks); + + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", + plane->base.base.id, plane->base.name, + old_wm->wm[0].min_ddb_alloc, old_wm->wm[1].min_ddb_alloc, + old_wm->wm[2].min_ddb_alloc, old_wm->wm[3].min_ddb_alloc, + old_wm->wm[4].min_ddb_alloc, old_wm->wm[5].min_ddb_alloc, + old_wm->wm[6].min_ddb_alloc, old_wm->wm[7].min_ddb_alloc, + old_wm->trans_wm.min_ddb_alloc, + old_wm->sagv.wm0.min_ddb_alloc, + old_wm->sagv.trans_wm.min_ddb_alloc, + new_wm->wm[0].min_ddb_alloc, new_wm->wm[1].min_ddb_alloc, + new_wm->wm[2].min_ddb_alloc, new_wm->wm[3].min_ddb_alloc, + new_wm->wm[4].min_ddb_alloc, new_wm->wm[5].min_ddb_alloc, + new_wm->wm[6].min_ddb_alloc, new_wm->wm[7].min_ddb_alloc, + new_wm->trans_wm.min_ddb_alloc, + new_wm->sagv.wm0.min_ddb_alloc, + new_wm->sagv.trans_wm.min_ddb_alloc); +} + static void skl_print_wm_changes(struct intel_atomic_state *state) { @@ -2709,7 +2737,6 @@ skl_print_wm_changes(struct intel_atomic_state *state) if (skl_ddb_entry_equal(old, new)) continue; - drm_dbg_kms(display->drm, "[PLANE:%d:%s] ddb (%4d - %4d) -> (%4d - %4d), size %4d -> %4d\n", plane->base.base.id, plane->base.name, @@ -2727,89 +2754,7 @@ skl_print_wm_changes(struct intel_atomic_state *state) if (skl_plane_wm_equals(display, old_wm, new_wm)) continue; - drm_dbg_kms(display->drm, - "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm" - " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm\n", - plane->base.base.id, plane->base.name, - enast(old_wm->wm[0].enable), enast(old_wm->wm[1].enable), - enast(old_wm->wm[2].enable), enast(old_wm->wm[3].enable), - enast(old_wm->wm[4].enable), enast(old_wm->wm[5].enable), - enast(old_wm->wm[6].enable), enast(old_wm->wm[7].enable), - enast(old_wm->trans_wm.enable), - enast(old_wm->sagv.wm0.enable), - enast(old_wm->sagv.trans_wm.enable), - enast(new_wm->wm[0].enable), enast(new_wm->wm[1].enable), - enast(new_wm->wm[2].enable), enast(new_wm->wm[3].enable), - enast(new_wm->wm[4].enable), enast(new_wm->wm[5].enable), - enast(new_wm->wm[6].enable), enast(new_wm->wm[7].enable), - enast(new_wm->trans_wm.enable), - enast(new_wm->sagv.wm0.enable), - enast(new_wm->sagv.trans_wm.enable)); - - drm_dbg_kms(display->drm, - "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d" - " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d\n", - plane->base.base.id, plane->base.name, - enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].lines, - enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].lines, - enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].lines, - enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].lines, - enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].lines, - enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].lines, - enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].lines, - enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].lines, - enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.lines, - enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.lines, - enast(old_wm->sagv.trans_wm.ignore_lines), old_wm->sagv.trans_wm.lines, - enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].lines, - enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].lines, - enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].lines, - enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].lines, - enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].lines, - enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].lines, - enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].lines, - enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].lines, - enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.lines, - enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.lines, - enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.lines); - - drm_dbg_kms(display->drm, - "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" - " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", - plane->base.base.id, plane->base.name, - old_wm->wm[0].blocks, old_wm->wm[1].blocks, - old_wm->wm[2].blocks, old_wm->wm[3].blocks, - old_wm->wm[4].blocks, old_wm->wm[5].blocks, - old_wm->wm[6].blocks, old_wm->wm[7].blocks, - old_wm->trans_wm.blocks, - old_wm->sagv.wm0.blocks, - old_wm->sagv.trans_wm.blocks, - new_wm->wm[0].blocks, new_wm->wm[1].blocks, - new_wm->wm[2].blocks, new_wm->wm[3].blocks, - new_wm->wm[4].blocks, new_wm->wm[5].blocks, - new_wm->wm[6].blocks, new_wm->wm[7].blocks, - new_wm->trans_wm.blocks, - new_wm->sagv.wm0.blocks, - new_wm->sagv.trans_wm.blocks); - - drm_dbg_kms(display->drm, - "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" - " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", - plane->base.base.id, plane->base.name, - old_wm->wm[0].min_ddb_alloc, old_wm->wm[1].min_ddb_alloc, - old_wm->wm[2].min_ddb_alloc, old_wm->wm[3].min_ddb_alloc, - old_wm->wm[4].min_ddb_alloc, old_wm->wm[5].min_ddb_alloc, - old_wm->wm[6].min_ddb_alloc, old_wm->wm[7].min_ddb_alloc, - old_wm->trans_wm.min_ddb_alloc, - old_wm->sagv.wm0.min_ddb_alloc, - old_wm->sagv.trans_wm.min_ddb_alloc, - new_wm->wm[0].min_ddb_alloc, new_wm->wm[1].min_ddb_alloc, - new_wm->wm[2].min_ddb_alloc, new_wm->wm[3].min_ddb_alloc, - new_wm->wm[4].min_ddb_alloc, new_wm->wm[5].min_ddb_alloc, - new_wm->wm[6].min_ddb_alloc, new_wm->wm[7].min_ddb_alloc, - new_wm->trans_wm.min_ddb_alloc, - new_wm->sagv.wm0.min_ddb_alloc, - new_wm->sagv.trans_wm.min_ddb_alloc); + skl_print_plane_changes(display, plane, old_wm, new_wm); } } } @@ -2913,67 +2858,79 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state, return 0; } -/* - * If Fixed Refresh Rate or For VRR case Vmin = Vmax = Flipline: - * Program DEEP PKG_C_LATENCY Pkg C with highest valid latency from - * watermark level1 and up and above. If watermark level 1 is - * invalid program it with all 1's. - * Program PKG_C_LATENCY Added Wake Time = DSB execution time - * If Variable Refresh Rate where Vmin != Vmax != Flipline: - * Program DEEP PKG_C_LATENCY Pkg C with all 1's. - * Program PKG_C_LATENCY Added Wake Time = 0 - */ +static int pkgc_max_linetime(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + const struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + int i, max_linetime; + + /* + * Apparenty the hardware uses WM_LINETIME internally for + * this stuff, compute everything based on that. + */ + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { + display->pkgc.disable[crtc->pipe] = crtc_state->vrr.enable; + display->pkgc.linetime[crtc->pipe] = DIV_ROUND_UP(crtc_state->linetime, 8); + } + + max_linetime = 0; + for_each_intel_crtc(display->drm, crtc) { + if (display->pkgc.disable[crtc->pipe]) + return 0; + + max_linetime = max(display->pkgc.linetime[crtc->pipe], max_linetime); + } + + return max_linetime; +} + void intel_program_dpkgc_latency(struct intel_atomic_state *state) { struct intel_display *display = to_intel_display(state); - struct intel_crtc *crtc; - struct intel_crtc_state *new_crtc_state; - u32 latency = LNL_PKG_C_LATENCY_MASK; - u32 added_wake_time = 0; - u32 max_linetime = 0; - u32 clear, val; - bool fixed_refresh_rate = false; - int i; + int max_linetime, latency, added_wake_time = 0; if (DISPLAY_VER(display) < 20) return; - for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { - if (!new_crtc_state->vrr.enable || - (new_crtc_state->vrr.vmin == new_crtc_state->vrr.vmax && - new_crtc_state->vrr.vmin == new_crtc_state->vrr.flipline)) - fixed_refresh_rate = true; + mutex_lock(&display->wm.wm_mutex); - max_linetime = max(new_crtc_state->linetime, max_linetime); - } + latency = skl_watermark_max_latency(display, 1); - if (fixed_refresh_rate) { - added_wake_time = DSB_EXE_TIME + - display->sagv.block_time_us; + /* FIXME runtime changes to enable_flipq are racy */ + if (display->params.enable_flipq) + added_wake_time = intel_flipq_exec_time_us(display); - latency = skl_watermark_max_latency(display, 1); + /* + * Wa_22020432604 + * "PKG_C_LATENCY Added Wake Time field is not working" + */ + if (latency && IS_DISPLAY_VER(display, 20, 30)) { + latency += added_wake_time; + added_wake_time = 0; + } - /* Wa_22020432604 */ - if ((DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30) && !latency) { - latency += added_wake_time; - added_wake_time = 0; - } + max_linetime = pkgc_max_linetime(state); - /* Wa_22020299601 */ - if ((latency && max_linetime) && - (DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30)) { - latency = max_linetime * DIV_ROUND_UP(latency, max_linetime); - } else if (!latency) { - latency = LNL_PKG_C_LATENCY_MASK; - } + if (max_linetime == 0 || latency == 0) { + latency = REG_FIELD_GET(LNL_PKG_C_LATENCY_MASK, + LNL_PKG_C_LATENCY_MASK); + added_wake_time = 0; + } else { + /* + * Wa_22020299601 + * "Increase the latency programmed in PKG_C_LATENCY Pkg C Latency to be a + * multiple of the pipeline time from WM_LINETIME" + */ + latency = roundup(latency, max_linetime); } - clear = LNL_ADDED_WAKE_TIME_MASK | LNL_PKG_C_LATENCY_MASK; - val = REG_FIELD_PREP(LNL_PKG_C_LATENCY_MASK, latency) | - REG_FIELD_PREP(LNL_ADDED_WAKE_TIME_MASK, added_wake_time); + intel_de_write(display, LNL_PKG_C_LATENCY, + REG_FIELD_PREP(LNL_ADDED_WAKE_TIME_MASK, added_wake_time) | + REG_FIELD_PREP(LNL_PKG_C_LATENCY_MASK, latency)); - intel_de_rmw(display, LNL_PKG_C_LATENCY, clear, val); + mutex_unlock(&display->wm.wm_mutex); } static int @@ -3011,7 +2968,7 @@ skl_compute_wm(struct intel_atomic_state *state) * drm_atomic_check_only() gets upset if we pull more crtcs * into the state, so we have to calculate this based on the * individual intel_crtc_can_enable_sagv() rather than - * the overall intel_can_enable_sagv(). Otherwise the + * the overall intel_bw_can_enable_sagv(). Otherwise the * crtcs not included in the commit would not switch to the * SAGV watermarks when we are about to enable SAGV, and that * would lead to underruns. This does mean extra power draw @@ -3279,7 +3236,6 @@ static void mtl_read_wm_latency(struct intel_display *display, u16 wm[]) static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) { - struct drm_i915_private *i915 = to_i915(display->drm); int num_levels = display->wm.num_levels; int read_latency = DISPLAY_VER(display) >= 12 ? 3 : 2; int mult = display->platform.dg2 ? 2 : 1; @@ -3288,7 +3244,7 @@ static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) /* read the first set of memory latencies[0:3] */ val = 0; /* data0 to be programmed to 0 for first set */ - ret = snb_pcode_read(&i915->uncore, GEN9_PCODE_READ_MEM_LATENCY, &val, NULL); + ret = intel_pcode_read(display->drm, GEN9_PCODE_READ_MEM_LATENCY, &val, NULL); if (ret) { drm_err(display->drm, "SKL Mailbox read error = %d\n", ret); return; @@ -3301,7 +3257,7 @@ static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) /* read the second set of memory latencies[4:7] */ val = 1; /* data0 to be programmed to 1 for second set */ - ret = snb_pcode_read(&i915->uncore, GEN9_PCODE_READ_MEM_LATENCY, &val, NULL); + ret = intel_pcode_read(display->drm, GEN9_PCODE_READ_MEM_LATENCY, &val, NULL); if (ret) { drm_err(display->drm, "SKL Mailbox read error = %d\n", ret); return; @@ -3693,6 +3649,38 @@ void intel_dbuf_post_plane_update(struct intel_atomic_state *state) gen9_dbuf_slices_update(display, new_slices); } +int intel_dbuf_num_enabled_slices(const struct intel_dbuf_state *dbuf_state) +{ + return hweight8(dbuf_state->enabled_slices); +} + +int intel_dbuf_num_active_pipes(const struct intel_dbuf_state *dbuf_state) +{ + return hweight8(dbuf_state->active_pipes); +} + +bool intel_dbuf_pmdemand_needs_update(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; + + new_dbuf_state = intel_atomic_get_new_dbuf_state(state); + old_dbuf_state = intel_atomic_get_old_dbuf_state(state); + + if (new_dbuf_state && + new_dbuf_state->active_pipes != old_dbuf_state->active_pipes) + return true; + + if (DISPLAY_VER(display) < 30) { + if (new_dbuf_state && + new_dbuf_state->enabled_slices != + old_dbuf_state->enabled_slices) + return true; + } + + return false; +} + static void skl_mbus_sanitize(struct intel_display *display) { struct intel_dbuf_state *dbuf_state = diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h index 95b0b599d5c3..62790816f030 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.h +++ b/drivers/gpu/drm/i915/display/skl_watermark.h @@ -8,17 +8,15 @@ #include <linux/types.h> -#include "intel_display_limits.h" -#include "intel_global_state.h" -#include "intel_wm_types.h" - +enum plane_id; struct intel_atomic_state; -struct intel_bw_state; struct intel_crtc; struct intel_crtc_state; +struct intel_dbuf_state; struct intel_display; struct intel_plane; struct intel_plane_state; +struct skl_ddb_entry; struct skl_pipe_wm; struct skl_wm_level; @@ -27,8 +25,6 @@ u8 intel_enabled_dbuf_slices_mask(struct intel_display *display); void intel_sagv_pre_plane_update(struct intel_atomic_state *state); void intel_sagv_post_plane_update(struct intel_atomic_state *state); bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state); -bool intel_can_enable_sagv(struct intel_display *display, - const struct intel_bw_state *bw_state); bool intel_has_sagv(struct intel_display *display); u32 skl_ddb_dbuf_slice_mask(struct intel_display *display, @@ -63,28 +59,11 @@ unsigned int skl_plane_relative_data_rate(const struct intel_crtc_state *crtc_st struct intel_plane *plane, int width, int height, int cpp); -struct intel_dbuf_state { - struct intel_global_state base; - - struct skl_ddb_entry ddb[I915_MAX_PIPES]; - unsigned int weight[I915_MAX_PIPES]; - u8 slices[I915_MAX_PIPES]; - u8 enabled_slices; - u8 active_pipes; - u8 mdclk_cdclk_ratio; - bool joined_mbus; -}; - struct intel_dbuf_state * intel_atomic_get_dbuf_state(struct intel_atomic_state *state); -#define to_intel_dbuf_state(global_state) \ - container_of_const((global_state), struct intel_dbuf_state, base) - -#define intel_atomic_get_old_dbuf_state(state) \ - to_intel_dbuf_state(intel_atomic_get_old_global_obj_state(state, &to_intel_display(state)->dbuf.obj)) -#define intel_atomic_get_new_dbuf_state(state) \ - to_intel_dbuf_state(intel_atomic_get_new_global_obj_state(state, &to_intel_display(state)->dbuf.obj)) +int intel_dbuf_num_enabled_slices(const struct intel_dbuf_state *dbuf_state); +int intel_dbuf_num_active_pipes(const struct intel_dbuf_state *dbuf_state); int intel_dbuf_init(struct intel_display *display); int intel_dbuf_state_set_mdclk_cdclk_ratio(struct intel_atomic_state *state, @@ -98,5 +77,7 @@ void intel_dbuf_mbus_pre_ddb_update(struct intel_atomic_state *state); void intel_dbuf_mbus_post_ddb_update(struct intel_atomic_state *state); void intel_program_dpkgc_latency(struct intel_atomic_state *state); +bool intel_dbuf_pmdemand_needs_update(struct intel_atomic_state *state); + #endif /* __SKL_WATERMARK_H__ */ diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 3433deb635ef..6d9f3312de7e 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1591,8 +1591,8 @@ static void vlv_dsi_add_properties(struct intel_connector *connector) static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) { + struct intel_display *display = to_intel_display(&intel_dsi->base); struct intel_connector *connector = intel_dsi->attached_connector; - struct intel_display *display = to_intel_display(connector); struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; u32 tlpx_ns, extra_byte_count, tlpx_ui; u32 ui_num, ui_den; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 05e440643aa2..f4f1c979d1b9 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -105,7 +105,7 @@ static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct * if (!obj->base.filp) return -ENODEV; - ret = call_mmap(obj->base.filp, vma); + ret = vfs_mmap(obj->base.filp, vma); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index f6d37dff320d..75f5b0e871ef 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -5,7 +5,6 @@ #include <linux/anon_inodes.h> #include <linux/mman.h> -#include <linux/pfn_t.h> #include <linux/sizes.h> #include <drm/drm_cache.h> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index c34f41605b46..565f8fa330db 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -16,7 +16,9 @@ #include "i915_gem_ww.h" #include "i915_vma_types.h" +struct drm_scanout_buffer; enum intel_region_id; +struct intel_framebuffer; #define obj_to_i915(obj__) to_i915((obj__)->base.dev) @@ -691,6 +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); + /** * i915_gem_object_pin_map - return a contiguous mapping of the entire object * @obj: the object to map into kernel address space diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index 7f83f8bdc8fb..c16a57160b26 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -4,8 +4,11 @@ */ #include <drm/drm_cache.h> +#include <drm/drm_panic.h> #include <linux/vmalloc.h> +#include "display/intel_fb.h" +#include "display/intel_display_types.h" #include "gt/intel_gt.h" #include "gt/intel_tlb.h" @@ -354,6 +357,145 @@ static void *i915_gem_object_map_pfn(struct drm_i915_gem_object *obj, return vaddr ?: ERR_PTR(-ENOMEM); } +struct i915_panic_data { + 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) +{ + if (panic->vaddr) { + drm_clflush_virt_range(panic->vaddr, PAGE_SIZE); + kunmap_local(panic->vaddr); + panic->vaddr = NULL; + } +} + +static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj) +{ + unsigned long n_pages = obj->base.size >> PAGE_SHIFT, i; + struct page *page; + struct page **pages; + struct sgt_iter iter; + + /* For a 3840x2160 32 bits Framebuffer, this should require ~64K */ + pages = kmalloc_array(n_pages, sizeof(*pages), GFP_ATOMIC); + if (!pages) + return NULL; + + i = 0; + for_each_sgt_page(page, iter, obj->mm.pages) + pages[i++] = page; + return pages; +} + +static void i915_gem_object_panic_map_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, + unsigned int y, u32 color) +{ + struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; + unsigned int offset = fb->panic_tiling(sb->width, x, y); + + iosys_map_wr(&sb->map[0], offset, u32, color); +} + +/* + * The scanout buffer pages are not mapped, so for each pixel, + * use kmap_local_page_try_from_panic() to map the page, and write the pixel. + * Try to keep the map from the previous pixel, to avoid too much map/unmap. + */ +static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, + unsigned int y, u32 color) +{ + 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); + + if (fb->panic_tiling) + offset = fb->panic_tiling(sb->width, x, y); + else + offset = y * sb->pitch[0] + x * sb->format->cpp[0]; + + new_page = offset >> PAGE_SHIFT; + offset = offset % PAGE_SIZE; + if (new_page != panic->page) { + i915_panic_kunmap(panic); + panic->page = new_page; + panic->vaddr = + kmap_local_page_try_from_panic(panic->pages[panic->page]); + } + if (panic->vaddr) { + u32 *pix = panic->vaddr + offset; + *pix = color; + } +} + +struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void) +{ + struct i915_framebuffer *i915_fb; + + i915_fb = kzalloc(sizeof(*i915_fb), GFP_KERNEL); + if (i915_fb) + return &i915_fb->base; + return NULL; +} + +/* + * Setup the gem framebuffer for drm_panic access. + * 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) +{ + 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)); + void *ptr; + + ptr = page_unpack_bits(obj->mm.mapping, &has_type); + if (ptr) { + if (i915_gem_object_has_iomem(obj)) + iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)ptr); + else + iosys_map_set_vaddr(&sb->map[0], ptr); + + if (fb->panic_tiling) + sb->set_pixel = i915_gem_object_panic_map_set_pixel; + return 0; + } + if (i915_gem_object_has_struct_page(obj)) { + panic->pages = i915_gem_object_panic_pages(obj); + if (!panic->pages) + return -ENOMEM; + panic->page = -1; + sb->set_pixel = i915_gem_object_panic_page_set_pixel; + return 0; + } + return -EOPNOTSUPP; +} + +void i915_gem_object_panic_finish(struct intel_framebuffer *fb) +{ + struct i915_panic_data *panic = to_i915_panic_data(fb); + + i915_panic_kunmap(panic); + panic->page = -1; + kfree(panic->pages); + panic->pages = NULL; +} + /* get, pin, and map the pages of the object into kernel space */ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, enum i915_map_type type) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 19a3eb82dc6a..e3d188455f67 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -6,6 +6,7 @@ #include <linux/pagevec.h> #include <linux/shmem_fs.h> #include <linux/swap.h> +#include <linux/uio.h> #include <drm/drm_cache.h> @@ -302,7 +303,6 @@ void __shmem_writeback(size_t size, struct address_space *mapping) .nr_to_write = SWAP_CLUSTER_MAX, .range_start = 0, .range_end = LLONG_MAX, - .for_reclaim = 1, }; struct folio *folio = NULL; int error = 0; @@ -317,7 +317,7 @@ void __shmem_writeback(size_t size, struct address_space *mapping) if (folio_mapped(folio)) folio_redirty_for_writepage(&wbc, folio); else - error = shmem_writeout(folio, &wbc); + error = shmem_writeout(folio, NULL, NULL); } } @@ -400,12 +400,12 @@ static int shmem_pwrite(struct drm_i915_gem_object *obj, const struct drm_i915_gem_pwrite *arg) { - struct address_space *mapping = obj->base.filp->f_mapping; - const struct address_space_operations *aops = mapping->a_ops; char __user *user_data = u64_to_user_ptr(arg->data_ptr); - u64 remain; - loff_t pos; - unsigned int pg; + struct file *file = obj->base.filp; + struct kiocb kiocb; + struct iov_iter iter; + ssize_t written; + u64 size = arg->size; /* Caller already validated user args */ GEM_BUG_ON(!access_ok(user_data, arg->size)); @@ -428,63 +428,24 @@ shmem_pwrite(struct drm_i915_gem_object *obj, if (obj->mm.madv != I915_MADV_WILLNEED) return -EFAULT; - /* - * Before the pages are instantiated the object is treated as being - * in the CPU domain. The pages will be clflushed as required before - * use, and we can freely write into the pages directly. If userspace - * races pwrite with any other operation; corruption will ensue - - * that is userspace's prerogative! - */ - - remain = arg->size; - pos = arg->offset; - pg = offset_in_page(pos); - - do { - unsigned int len, unwritten; - struct folio *folio; - void *data, *vaddr; - int err; - char __maybe_unused c; - - len = PAGE_SIZE - pg; - if (len > remain) - len = remain; + if (size > MAX_RW_COUNT) + return -EFBIG; - /* Prefault the user page to reduce potential recursion */ - err = __get_user(c, user_data); - if (err) - return err; + if (!file->f_op->write_iter) + return -EINVAL; - err = __get_user(c, user_data + len - 1); - if (err) - return err; + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = arg->offset; + iov_iter_ubuf(&iter, ITER_SOURCE, (void __user *)user_data, size); - err = aops->write_begin(obj->base.filp, mapping, pos, len, - &folio, &data); - if (err < 0) - return err; + written = file->f_op->write_iter(&kiocb, &iter); + BUG_ON(written == -EIOCBQUEUED); - vaddr = kmap_local_folio(folio, offset_in_folio(folio, pos)); - pagefault_disable(); - unwritten = __copy_from_user_inatomic(vaddr, user_data, len); - pagefault_enable(); - kunmap_local(vaddr); + if (written != size) + return -EIO; - err = aops->write_end(obj->base.filp, mapping, pos, len, - len - unwritten, folio, data); - if (err < 0) - return err; - - /* We don't handle -EFAULT, leave it to the caller to check */ - if (unwritten) - return -ENODEV; - - remain -= len; - user_data += len; - pos += len; - pg = 0; - } while (remain); + if (written < 0) + return written; return 0; } @@ -637,9 +598,8 @@ i915_gem_object_create_shmem_from_data(struct drm_i915_private *i915, { struct drm_i915_gem_object *obj; struct file *file; - const struct address_space_operations *aops; - loff_t pos; - int err; + loff_t pos = 0; + ssize_t err; GEM_WARN_ON(IS_DGFX(i915)); obj = i915_gem_object_create_shmem(i915, round_up(size, PAGE_SIZE)); @@ -649,29 +609,15 @@ i915_gem_object_create_shmem_from_data(struct drm_i915_private *i915, GEM_BUG_ON(obj->write_domain != I915_GEM_DOMAIN_CPU); file = obj->base.filp; - aops = file->f_mapping->a_ops; - pos = 0; - do { - unsigned int len = min_t(typeof(size), size, PAGE_SIZE); - struct folio *folio; - void *fsdata; + err = kernel_write(file, data, size, &pos); - err = aops->write_begin(file, file->f_mapping, pos, len, - &folio, &fsdata); - if (err < 0) - goto fail; + if (err < 0) + goto fail; - memcpy_to_folio(folio, offset_in_folio(folio, pos), data, len); - - err = aops->write_end(file, file->f_mapping, pos, len, len, - folio, fsdata); - if (err < 0) - goto fail; - - size -= len; - data += len; - pos += len; - } while (size); + if (err != size) { + err = -EIO; + goto fail; + } return obj; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index 7127e90c1a8f..991666fd9f85 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -106,11 +106,6 @@ static void fence_set_priority(struct dma_fence *fence, rcu_read_unlock(); } -static inline bool __dma_fence_is_chain(const struct dma_fence *fence) -{ - return fence->ops == &dma_fence_chain_ops; -} - void i915_gem_fence_wait_priority(struct dma_fence *fence, const struct i915_sched_attr *attr) { @@ -126,7 +121,7 @@ void i915_gem_fence_wait_priority(struct dma_fence *fence, for (i = 0; i < array->num_fences; i++) fence_set_priority(array->fences[i], attr); - } else if (__dma_fence_is_chain(fence)) { + } else if (dma_fence_is_chain(fence)) { struct dma_fence *iter; /* The chain is ordered; if we boost the last, we boost all */ diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.c b/drivers/gpu/drm/i915/gem/i915_gemfs.c index 65d84a93c525..a09e2eb47175 100644 --- a/drivers/gpu/drm/i915/gem/i915_gemfs.c +++ b/drivers/gpu/drm/i915/gem/i915_gemfs.c @@ -5,16 +5,23 @@ #include <linux/fs.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include "i915_drv.h" #include "i915_gemfs.h" #include "i915_utils.h" +static int add_param(struct fs_context *fc, const char *key, const char *val) +{ + return vfs_parse_fs_string(fc, key, val, strlen(val)); +} + void i915_gemfs_init(struct drm_i915_private *i915) { - char huge_opt[] = "huge=within_size"; /* r/w */ struct file_system_type *type; + struct fs_context *fc; struct vfsmount *gemfs; + int ret; /* * By creating our own shmemfs mountpoint, we can pass in @@ -38,8 +45,16 @@ void i915_gemfs_init(struct drm_i915_private *i915) if (!type) goto err; - gemfs = vfs_kern_mount(type, SB_KERNMOUNT, type->name, huge_opt); - if (IS_ERR(gemfs)) + fc = fs_context_for_mount(type, SB_KERNMOUNT); + if (IS_ERR(fc)) + goto err; + ret = add_param(fc, "source", "tmpfs"); + if (!ret) + ret = add_param(fc, "huge", "within_size"); + if (!ret) + gemfs = fc_mount_longterm(fc); + put_fs_context(fc); + if (ret) goto err; i915->mm.gemfs = gemfs; diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 325da0414d94..f6a98cf1e5a5 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -79,6 +79,29 @@ struct lock_class_key; #define ENGINE_WRITE(...) __ENGINE_WRITE_OP(write, __VA_ARGS__) #define ENGINE_WRITE_FW(...) __ENGINE_WRITE_OP(write_fw, __VA_ARGS__) +#define __HAS_ENGINE(engine_mask, id) ((engine_mask) & BIT(id)) +#define HAS_ENGINE(gt, id) __HAS_ENGINE((gt)->info.engine_mask, id) + +#define __ENGINE_INSTANCES_MASK(mask, first, count) ({ \ + unsigned int first__ = (first); \ + unsigned int count__ = (count); \ + ((mask) & GENMASK(first__ + count__ - 1, first__)) >> first__; \ +}) + +#define ENGINE_INSTANCES_MASK(gt, first, count) \ + __ENGINE_INSTANCES_MASK((gt)->info.engine_mask, first, count) + +#define RCS_MASK(gt) \ + ENGINE_INSTANCES_MASK(gt, RCS0, I915_MAX_RCS) +#define BCS_MASK(gt) \ + ENGINE_INSTANCES_MASK(gt, BCS0, I915_MAX_BCS) +#define VDBOX_MASK(gt) \ + ENGINE_INSTANCES_MASK(gt, VCS0, I915_MAX_VCS) +#define VEBOX_MASK(gt) \ + ENGINE_INSTANCES_MASK(gt, VECS0, I915_MAX_VECS) +#define CCS_MASK(gt) \ + ENGINE_INSTANCES_MASK(gt, CCS0, I915_MAX_CCS) + #define GEN6_RING_FAULT_REG_READ(engine__) \ intel_uncore_read((engine__)->uncore, RING_FAULT_REG(engine__)) @@ -355,4 +378,12 @@ u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value); u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value); u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value); +#define rb_to_uabi_engine(rb) \ + rb_entry_safe(rb, struct intel_engine_cs, uabi_node) + +#define for_each_uabi_engine(engine__, i915__) \ + for ((engine__) = rb_to_uabi_engine(rb_first(&(i915__)->uabi_engines));\ + (engine__); \ + (engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node))) + #endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c index 1e925c75fb08..c43febc862dc 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.c +++ b/drivers/gpu/drm/i915/gt/intel_gsc.c @@ -284,7 +284,7 @@ static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id) if (gt->gsc.intf[intf_id].irq < 0) return; - ret = generic_handle_irq(gt->gsc.intf[intf_id].irq); + ret = generic_handle_irq_safe(gt->gsc.intf[intf_id].irq); if (ret) gt_err_ratelimited(gt, "error handling GSC irq: %d\n", ret); } diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c index a876a34455f1..2a6d79abf25b 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c @@ -610,7 +610,6 @@ static int ring_context_alloc(struct intel_context *ce) /* One ringbuffer to rule them all */ GEM_BUG_ON(!engine->legacy.ring); ce->ring = engine->legacy.ring; - ce->timeline = intel_timeline_get(engine->legacy.timeline); GEM_BUG_ON(ce->state); if (engine->context_size) { @@ -623,6 +622,8 @@ static int ring_context_alloc(struct intel_context *ce) ce->state = vma; } + ce->timeline = intel_timeline_get(engine->legacy.timeline); + return 0; } diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index b37e400f74e5..5a95f06900b5 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -634,6 +634,8 @@ static void cfl_ctx_workarounds_init(struct intel_engine_cs *engine, static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { + struct drm_i915_private *i915 = engine->i915; + /* Wa_1406697149 (WaDisableBankHangMode:icl) */ wa_write(wal, GEN8_L3CNTLREG, GEN8_ERRDETBCTRL); @@ -669,6 +671,15 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_1406306137:icl,ehl */ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU); + + if (IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) { + /* + * Disable Repacking for Compression (masked R/W access) + * before rendering compressed surfaces for display. + */ + wa_masked_en(wal, CACHE_MODE_0_GEN7, + DISABLE_REPACKING_FOR_COMPRESSION); + } } /* @@ -2306,15 +2317,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN8_RC_SEMA_IDLE_MSG_DISABLE); } - if (IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) { - /* - * "Disable Repacking for Compression (masked R/W access) - * before rendering compressed surfaces for display." - */ - wa_masked_en(wal, CACHE_MODE_0_GEN7, - DISABLE_REPACKING_FOR_COMPRESSION); - } - if (GRAPHICS_VER(i915) == 11) { /* This is not an Wa. Enable for better image quality */ wa_masked_en(wal, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 9df80c325fc1..f360f020d8f1 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -313,8 +313,13 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) * * The same WA bit is used for both and 22011391025 is applicable to * all DG2. + * + * Platforms post DG2 prevent this issue in hardware by stalling + * submissions. With this flag GuC will schedule as to avoid such + * stalls. */ - if (IS_DG2(gt->i915)) + if (IS_DG2(gt->i915) || + (CCS_MASK(gt) && GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))) flags |= GUC_WA_DUAL_QUEUE; /* Wa_22011802037: graphics version 11/12 */ 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 e8a04e476c57..09a64f224c49 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -220,8 +220,7 @@ static int guc_action_control_log(struct intel_guc *guc, bool enable, */ static int subbuf_start_callback(struct rchan_buf *buf, void *subbuf, - void *prev_subbuf, - size_t prev_padding) + void *prev_subbuf) { /* * Use no-overwrite mode by default, where relay will stop accepting diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5e4c49f0d5d4..4e4e89746aa6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -66,8 +66,6 @@ struct intel_display; struct intel_pxp; struct vlv_s0ix_state; -#define GEM_QUIRK_PIN_SWIZZLED_PAGES BIT(0) - /* Data Stolen Memory (DSM) aka "i915 stolen memory" */ struct i915_dsm { /* @@ -354,14 +352,6 @@ static inline struct intel_gt *to_gt(const struct drm_i915_private *i915) return i915->gt[0]; } -#define rb_to_uabi_engine(rb) \ - rb_entry_safe(rb, struct intel_engine_cs, uabi_node) - -#define for_each_uabi_engine(engine__, i915__) \ - for ((engine__) = rb_to_uabi_engine(rb_first(&(i915__)->uabi_engines));\ - (engine__); \ - (engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node))) - #define INTEL_INFO(i915) ((i915)->__info) #define RUNTIME_INFO(i915) (&(i915)->__runtime) #define DRIVER_CAPS(i915) (&(i915)->caps) @@ -570,29 +560,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_GEN9_LP(i915) (IS_BROXTON(i915) || IS_GEMINILAKE(i915)) #define IS_GEN9_BC(i915) (GRAPHICS_VER(i915) == 9 && !IS_GEN9_LP(i915)) -#define __HAS_ENGINE(engine_mask, id) ((engine_mask) & BIT(id)) -#define HAS_ENGINE(gt, id) __HAS_ENGINE((gt)->info.engine_mask, id) - -#define __ENGINE_INSTANCES_MASK(mask, first, count) ({ \ - unsigned int first__ = (first); \ - unsigned int count__ = (count); \ - ((mask) & GENMASK(first__ + count__ - 1, first__)) >> first__; \ -}) - -#define ENGINE_INSTANCES_MASK(gt, first, count) \ - __ENGINE_INSTANCES_MASK((gt)->info.engine_mask, first, count) - -#define RCS_MASK(gt) \ - ENGINE_INSTANCES_MASK(gt, RCS0, I915_MAX_RCS) -#define BCS_MASK(gt) \ - ENGINE_INSTANCES_MASK(gt, BCS0, I915_MAX_BCS) -#define VDBOX_MASK(gt) \ - ENGINE_INSTANCES_MASK(gt, VCS0, I915_MAX_VCS) -#define VEBOX_MASK(gt) \ - ENGINE_INSTANCES_MASK(gt, VECS0, I915_MAX_VECS) -#define CCS_MASK(gt) \ - ENGINE_INSTANCES_MASK(gt, CCS0, I915_MAX_CCS) - #define HAS_MEDIA_RATIO_MODE(i915) (INTEL_INFO(i915)->has_media_ratio_mode) /* diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 82e9d289398c..20b3cb29cfff 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -134,4 +134,6 @@ int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file); #define I915_GEM_IDLE_TIMEOUT (HZ / 5) +#define GEM_QUIRK_PIN_SWIZZLED_PAGES BIT(0) + #endif /* __I915_GEM_H__ */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index f434b6825fc2..0e4b832dff84 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -2506,8 +2506,8 @@ static const struct bin_attribute error_state_attr = { .attr.name = "error", .attr.mode = S_IRUSR | S_IWUSR, .size = 0, - .read_new = error_state_read, - .write_new = error_state_write, + .read = error_state_read, + .write = error_state_write, }; void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 21006c7f615c..b2e311f4791a 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -663,7 +663,6 @@ static const struct intel_device_info dg1_info = { DGFX_FEATURES, .__runtime.graphics.ip.rel = 10, PLATFORM(INTEL_DG1), - .require_force_probe = 1, .platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0) | BIT(VCS2), diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index e5a188ce3185..5bc696bfbb0f 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -108,11 +108,11 @@ static unsigned int config_bit(const u64 config) return other_bit(config); } -static u32 config_mask(const u64 config) +static __always_inline u32 config_mask(const u64 config) { unsigned int bit = config_bit(config); - if (__builtin_constant_p(config)) + if (__builtin_constant_p(bit)) BUILD_BUG_ON(bit > BITS_PER_TYPE(typeof_member(struct i915_pmu, enable)) - 1); @@ -121,7 +121,7 @@ static u32 config_mask(const u64 config) BITS_PER_TYPE(typeof_member(struct i915_pmu, enable)) - 1); - return BIT(config_bit(config)); + return BIT(bit); } static bool is_engine_event(struct perf_event *event) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 52a902532e6f..03b895897f60 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -385,7 +385,6 @@ #define VLV_PCBR _MMIO(VLV_DISPLAY_BASE + 0x2120) #define VLV_PCBR_ADDR_SHIFT 12 -#define DISPLAY_PLANE_FLIP_PENDING(plane) (1 << (11 - (plane))) /* A and B only */ #define EIR _MMIO(0x20b0) #define EMR _MMIO(0x20b4) #define ESR _MMIO(0x20b8) @@ -763,8 +762,7 @@ */ #define GEN9_CLKGATE_DIS_0 _MMIO(0x46530) #define DARBF_GATING_DIS REG_BIT(27) -#define MTL_PIPEDMC_GATING_DIS_A REG_BIT(15) -#define MTL_PIPEDMC_GATING_DIS_B REG_BIT(14) +#define MTL_PIPEDMC_GATING_DIS(pipe) REG_BIT(15 - (pipe)) #define PWM2_GATING_DIS REG_BIT(14) #define PWM1_GATING_DIS REG_BIT(13) @@ -1205,16 +1203,6 @@ */ #define GEN7_SO_WRITE_OFFSET(n) _MMIO(0x5280 + (n) * 4) -/* SKL Fuse Status */ -enum skl_power_gate { - SKL_PG0, - SKL_PG1, - SKL_PG2, - ICL_PG3, - ICL_PG4, -}; - - #define GEN9_TIMESTAMP_OVERRIDE _MMIO(0x44074) #define GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_SHIFT 0 #define GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_MASK 0x3ff diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index f936e8f1f129..622c66666935 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -140,8 +140,8 @@ i915_l3_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute dpf_attrs = { .attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)}, .size = GEN7_L3LOG_SIZE, - .read_new = i915_l3_read, - .write_new = i915_l3_write, + .read = i915_l3_read, + .write = i915_l3_write, .mmap = NULL, .private = (void *)0 }; @@ -149,8 +149,8 @@ static const struct bin_attribute dpf_attrs = { static const struct bin_attribute dpf_attrs_1 = { .attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)}, .size = GEN7_L3LOG_SIZE, - .read_new = i915_l3_read, - .write_new = i915_l3_write, + .read = i915_l3_read, + .write = i915_l3_write, .mmap = NULL, .private = (void *)1 }; diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 632e316f8b05..25e97031d76e 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1607,6 +1607,26 @@ err_rpm: return err; } +int i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) +{ + struct i915_gem_ww_ctx ww; + int err; + + i915_gem_ww_ctx_init(&ww, true); +retry: + err = i915_gem_object_lock(vma->obj, &ww); + if (!err) + err = i915_vma_pin_ww(vma, &ww, size, alignment, flags); + if (err == -EDEADLK) { + err = i915_gem_ww_ctx_backoff(&ww); + if (!err) + goto retry; + } + i915_gem_ww_ctx_fini(&ww); + + return err; +} + static void flush_idle_contexts(struct intel_gt *gt) { struct intel_engine_cs *engine; diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index 6a6be8048aa8..0f9eee6d18d2 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -289,26 +289,8 @@ int __must_check i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, u64 size, u64 alignment, u64 flags); -static inline int __must_check -i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) -{ - struct i915_gem_ww_ctx ww; - int err; - - i915_gem_ww_ctx_init(&ww, true); -retry: - err = i915_gem_object_lock(vma->obj, &ww); - if (!err) - err = i915_vma_pin_ww(vma, &ww, size, alignment, flags); - if (err == -EDEADLK) { - err = i915_gem_ww_ctx_backoff(&ww); - if (!err) - goto retry; - } - i915_gem_ww_ctx_fini(&ww); - - return err; -} +int __must_check +i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags); int i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, u32 align, unsigned int flags); @@ -353,6 +335,11 @@ static inline bool i915_node_color_differs(const struct drm_mm_node *node, return drm_mm_node_allocated(node) && node->color != color; } +static inline void __iomem *i915_vma_get_iomap(struct i915_vma *vma) +{ + return READ_ONCE(vma->iomap); +} + /** * i915_vma_pin_iomap - calls ioremap_wc to map the GGTT VMA via the aperture * @vma: VMA to iomap diff --git a/drivers/gpu/drm/i915/intel_pcode.c b/drivers/gpu/drm/i915/intel_pcode.c index 3db2ba439bb5..81da75108c60 100644 --- a/drivers/gpu/drm/i915/intel_pcode.c +++ b/drivers/gpu/drm/i915/intel_pcode.c @@ -110,13 +110,12 @@ int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val, u32 *val1) } int snb_pcode_write_timeout(struct intel_uncore *uncore, u32 mbox, u32 val, - int fast_timeout_us, int slow_timeout_ms) + int timeout_ms) { int err; mutex_lock(&uncore->i915->sb_lock); - err = __snb_pcode_rw(uncore, mbox, &val, NULL, - fast_timeout_us, slow_timeout_ms, false); + err = __snb_pcode_rw(uncore, mbox, &val, NULL, 250, timeout_ms, false); mutex_unlock(&uncore->i915->sb_lock); if (err) { @@ -273,3 +272,27 @@ int snb_pcode_write_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u3 return err; } + +/* Helpers with drm device */ +int intel_pcode_read(struct drm_device *drm, u32 mbox, u32 *val, u32 *val1) +{ + struct drm_i915_private *i915 = to_i915(drm); + + return snb_pcode_read(&i915->uncore, mbox, val, val1); +} + +int intel_pcode_write_timeout(struct drm_device *drm, u32 mbox, u32 val, int timeout_ms) +{ + struct drm_i915_private *i915 = to_i915(drm); + + return snb_pcode_write_timeout(&i915->uncore, mbox, val, timeout_ms); +} + +int intel_pcode_request(struct drm_device *drm, u32 mbox, u32 request, + u32 reply_mask, u32 reply, int timeout_base_ms) +{ + struct drm_i915_private *i915 = to_i915(drm); + + return skl_pcode_request(&i915->uncore, mbox, request, reply_mask, reply, + timeout_base_ms); +} diff --git a/drivers/gpu/drm/i915/intel_pcode.h b/drivers/gpu/drm/i915/intel_pcode.h index 8d2198e29422..c91a821a88d4 100644 --- a/drivers/gpu/drm/i915/intel_pcode.h +++ b/drivers/gpu/drm/i915/intel_pcode.h @@ -8,13 +8,13 @@ #include <linux/types.h> +struct drm_device; struct intel_uncore; int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val, u32 *val1); -int snb_pcode_write_timeout(struct intel_uncore *uncore, u32 mbox, u32 val, - int fast_timeout_us, int slow_timeout_ms); +int snb_pcode_write_timeout(struct intel_uncore *uncore, u32 mbox, u32 val, int timeout_ms); #define snb_pcode_write(uncore, mbox, val) \ - snb_pcode_write_timeout(uncore, mbox, val, 500, 0) + snb_pcode_write_timeout((uncore), (mbox), (val), 1) int skl_pcode_request(struct intel_uncore *uncore, u32 mbox, u32 request, u32 reply_mask, u32 reply, int timeout_base_ms); @@ -27,4 +27,13 @@ int intel_pcode_init(struct intel_uncore *uncore); int snb_pcode_read_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u32 *val); int snb_pcode_write_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u32 val); +/* Helpers with drm device */ +int intel_pcode_read(struct drm_device *drm, u32 mbox, u32 *val, u32 *val1); +int intel_pcode_write_timeout(struct drm_device *drm, u32 mbox, u32 val, int timeout_ms); +#define intel_pcode_write(drm, mbox, val) \ + intel_pcode_write_timeout((drm), (mbox), (val), 1) + +int intel_pcode_request(struct drm_device *drm, u32 mbox, u32 request, + u32 reply_mask, u32 reply, int timeout_base_ms); + #endif /* _INTEL_PCODE_H */ diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8d9f4c410546..7ce3e6de0c19 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -59,7 +59,9 @@ static struct drm_i915_private *rpm_to_i915(struct intel_runtime_pm *rpm) static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm->kdev)); + if (!rpm->debug.class) + ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, + "intel_runtime_pm"); } static intel_wakeref_t diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c index 51561b190b93..7fa194de5d35 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -114,7 +114,8 @@ void __intel_wakeref_init(struct intel_wakeref *wf, "wakeref.work", &key->work, 0); #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) - ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, name); + if (!wf->debug.class) + ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, "intel_wakeref"); #endif } diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 88870844b5bd..2fb7a9e7efec 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -73,8 +73,8 @@ static int igt_add_request(void *arg) /* Basic preliminary test to create a request and let it loose! */ request = mock_request(rcs0(i915)->kernel_context, HZ / 10); - if (!request) - return -ENOMEM; + if (IS_ERR(request)) + return PTR_ERR(request); i915_request_add(request); @@ -91,8 +91,8 @@ static int igt_wait_request(void *arg) /* Submit a request, then wait upon it */ request = mock_request(rcs0(i915)->kernel_context, T); - if (!request) - return -ENOMEM; + if (IS_ERR(request)) + return PTR_ERR(request); i915_request_get(request); @@ -160,8 +160,8 @@ static int igt_fence_wait(void *arg) /* Submit a request, treat it as a fence and wait upon it */ request = mock_request(rcs0(i915)->kernel_context, T); - if (!request) - return -ENOMEM; + if (IS_ERR(request)) + return PTR_ERR(request); if (dma_fence_wait_timeout(&request->fence, false, T) != -ETIME) { pr_err("fence wait success before submit (expected timeout)!\n"); @@ -219,8 +219,8 @@ static int igt_request_rewind(void *arg) GEM_BUG_ON(IS_ERR(ce)); request = mock_request(ce, 2 * HZ); intel_context_put(ce); - if (!request) { - err = -ENOMEM; + if (IS_ERR(request)) { + err = PTR_ERR(request); goto err_context_0; } @@ -237,8 +237,8 @@ static int igt_request_rewind(void *arg) GEM_BUG_ON(IS_ERR(ce)); vip = mock_request(ce, 0); intel_context_put(ce); - if (!vip) { - err = -ENOMEM; + if (IS_ERR(vip)) { + err = PTR_ERR(vip); goto err_context_1; } diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c index f08f6674911e..7b856b5090f9 100644 --- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c +++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c @@ -413,15 +413,8 @@ static int igt_mock_splintered_region(void *arg) close_objects(mem, &objects); - /* - * While we should be able allocate everything without any flag - * restrictions, if we consider I915_BO_ALLOC_CONTIGUOUS then we are - * actually limited to the largest power-of-two for the region size i.e - * max_order, due to the inner workings of the buddy allocator. So make - * sure that does indeed hold true. - */ - - obj = igt_object_create(mem, &objects, size, I915_BO_ALLOC_CONTIGUOUS); + obj = igt_object_create(mem, &objects, roundup_pow_of_two(size), + I915_BO_ALLOC_CONTIGUOUS); if (!IS_ERR(obj)) { pr_err("%s too large contiguous allocation was not rejected\n", __func__); @@ -429,8 +422,7 @@ static int igt_mock_splintered_region(void *arg) goto out_close; } - obj = igt_object_create(mem, &objects, rounddown_pow_of_two(size), - I915_BO_ALLOC_CONTIGUOUS); + obj = igt_object_create(mem, &objects, size, I915_BO_ALLOC_CONTIGUOUS); if (IS_ERR(obj)) { pr_err("%s largest possible contiguous allocation failed\n", __func__); diff --git a/drivers/gpu/drm/i915/selftests/mock_request.c b/drivers/gpu/drm/i915/selftests/mock_request.c index 09f747228dff..1b0cf073e964 100644 --- a/drivers/gpu/drm/i915/selftests/mock_request.c +++ b/drivers/gpu/drm/i915/selftests/mock_request.c @@ -35,7 +35,7 @@ mock_request(struct intel_context *ce, unsigned long delay) /* NB the i915->requests slab cache is enlarged to fit mock_request */ request = intel_context_create_request(ce); if (IS_ERR(request)) - return NULL; + return request; request->mock.delay = delay; return request; diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c index 59032c939d0f..deb159548a09 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.c +++ b/drivers/gpu/drm/i915/soc/intel_dram.c @@ -14,6 +14,7 @@ #include "intel_dram.h" #include "intel_mchbar_regs.h" #include "intel_pcode.h" +#include "intel_uncore.h" #include "vlv_iosf_sb.h" struct dram_dimm_info { @@ -590,8 +591,8 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv, u32 val = 0; int ret; - ret = snb_pcode_read(&dev_priv->uncore, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | - ICL_PCODE_MEM_SS_READ_GLOBAL_INFO, &val, NULL); + ret = intel_pcode_read(&dev_priv->drm, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | + ICL_PCODE_MEM_SS_READ_GLOBAL_INFO, &val, NULL); if (ret) return ret; |
