diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-25 16:18:27 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-25 16:18:27 -0700 |
commit | 2518f226c60d8e04d18ba4295500a5b0b8ac7659 (patch) | |
tree | e74de5ca0db01398cbb0c34376f74a81d7583c75 /drivers/gpu/drm/i915/intel_pm.c | |
parent | 86c87bea6b42100c67418af690919c44de6ede6e (diff) | |
parent | c4955d9cd2fc56c43e78c908dad4e2cac7cc9073 (diff) |
Merge tag 'drm-next-2022-05-25' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"Intel have enabled DG2 on certain SKUs for laptops, AMD has started
some new GPU support, msm has user allocated VA controls
dma-buf:
- add dma_resv_replace_fences
- add dma_resv_get_singleton
- make dma_excl_fence private
core:
- EDID parser refactorings
- switch drivers to drm_mode_copy/duplicate
- DRM managed mutex initialization
display-helper:
- put HDMI, SCDC, HDCP, DSC and DP into new module
gem:
- rework fence handling
ttm:
- rework bulk move handling
- add common debugfs for resource managers
- convert to kvcalloc
format helpers:
- support monochrome formats
- RGB888, RGB565 to XRGB8888 conversions
fbdev:
- cfb/sys_imageblit fixes
- pagelist corruption fix
- create offb platform device
- deferred io improvements
sysfb:
- Kconfig rework
- support for VESA mode selection
bridge:
- conversions to devm_drm_of_get_bridge
- conversions to panel_bridge
- analogix_dp - autosuspend support
- it66121 - audio support
- tc358767 - DSI to DPI support
- icn6211 - PLL/I2C fixes, DT property
- adv7611 - enable DRM_BRIDGE_OP_HPD
- anx7625 - fill ELD if no monitor
- dw_hdmi - add audio support
- lontium LT9211 support, i.MXMP LDB
- it6505: Kconfig fix, DPCD set power fix
- adv7511 - CEC support for ADV7535
panel:
- ltk035c5444t, B133UAN01, NV3052C panel support
- DataImage FG040346DSSWBG04 support
- st7735r - DT bindings fix
- ssd130x - fixes
i915:
- DG2 laptop PCI-IDs ("motherboard down")
- Initial RPL-P PCI IDs
- compute engine ABI
- DG2 Tile4 support
- DG2 CCS clear color compression support
- DG2 render/media compression formats support
- ATS-M platform info
- RPL-S PCI IDs added
- Bump ADL-P DMC version to v2.16
- Support static DRRS
- Support multiple eDP/LVDS native mode refresh rates
- DP HDR support for HSW+
- Lots of display refactoring + fixes
- GuC hwconfig support and query
- sysfs support for multi-tile
- fdinfo per-client gpu utilisation
- add geometry subslices query
- fix prime mmap with LMEM
- fix vm open count and remove vma refcounts
- contiguous allocation fixes
- steered register write support
- small PCI BAR enablement
- GuC error capture support
- sunset igpu legacy mmap support for newer devices
- GuC version 70.1.1 support
amdgpu:
- Initial SoC21 support
- SMU 13.x enablement
- SMU 13.0.4 support
- ttm_eu cleanups
- USB-C, GPUVM updates
- TMZ fixes for RV
- RAS support for VCN
- PM sysfs code cleanup
- DC FP rework
- extend CG/PG flags to 64-bit
- SI dpm lockdep fix
- runtime PM fixes
amdkfd:
- RAS/SVM fixes
- TLB flush fixes
- CRIU GWS support
- ignore bogus MEC signals more efficiently
msm:
- Fourcc modifier for tiled but not compressed layouts
- Support for userspace allocated IOVA (GPU virtual address)
- DPU: DSC (Display Stream Compression) support
- DP: eDP support
- DP: conversion to use drm_bridge and drm_bridge_connector
- Merge DPU1 and MDP5 MDSS driver
- DPU: writeback support
nouveau:
- make some structures static
- make some variables static
- switch to drm_gem_plane_helper_prepare_fb
radeon:
- misc fixes/cleanups
mxsfb:
- rework crtc mode setting
- LCDIF CRC support
etnaviv:
- fencing improvements
- fix address space collisions
- cleanup MMU reference handling
gma500:
- GEM/GTT improvements
- connector handling fixes
komeda:
- switch to plane reset helper
mediatek:
- MIPI DSI improvements
omapdrm:
- GEM improvements
qxl:
- aarch64 support
vc4:
- add a CL submission tracepoint
- HDMI YUV support
- HDMI/clock improvements
- drop is_hdmi caching
virtio:
- remove restriction of non-zero blob types
vmwgfx:
- support for cursormob and cursorbypass 4
- fence improvements
tidss:
- reset DISPC on startup
solomon:
- SPI support
- DT improvements
sun4i:
- allwinner D1 support
- drop is_hdmi caching
imx:
- use swap() instead of open-coding
- use devm_platform_ioremap_resource
- remove redunant initializations
ast:
- Displayport support
rockchip:
- Refactor IOMMU initialisation
- make some structures static
- replace drm_detect_hdmi_monitor with drm_display_info.is_hdmi
- support swapped YUV formats,
- clock improvements
- rk3568 support
- VOP2 support
mediatek:
- MT8186 support
tegra:
- debugabillity improvements"
* tag 'drm-next-2022-05-25' of git://anongit.freedesktop.org/drm/drm: (1740 commits)
drm/i915/dsi: fix VBT send packet port selection for ICL+
drm/i915/uc: Fix undefined behavior due to shift overflowing the constant
drm/i915/reg: fix undefined behavior due to shift overflowing the constant
drm/i915/gt: Fix use of static in macro mismatch
drm/i915/audio: fix audio code enable/disable pipe logging
drm/i915: Fix CFI violation with show_dynamic_id()
drm/i915: Fix 'mixing different enum types' warnings in intel_display_power.c
drm/i915/gt: Fix build error without CONFIG_PM
drm/msm/dpu: handle pm_runtime_get_sync() errors in bind path
drm/msm/dpu: add DRM_MODE_ROTATE_180 back to supported rotations
drm/msm: don't free the IRQ if it was not requested
drm/msm/dpu: limit writeback modes according to max_linewidth
drm/amd: Don't reset dGPUs if the system is going to s2idle
drm/amdgpu: Unmap legacy queue when MES is enabled
drm: msm: fix possible memory leak in mdp5_crtc_cursor_set()
drm/msm: Fix fb plane offset calculation
drm/msm/a6xx: Fix refcount leak in a6xx_gpu_init
drm/msm/dsi: don't powerup at modeset time for parade-ps8640
drm/rockchip: Change register space names in vop2
dt-bindings: display: rockchip: make reg-names mandatory for VOP2
...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 545 |
1 files changed, 255 insertions, 290 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5167d63010b9..5735915facc5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -26,6 +26,7 @@ */ #include <linux/module.h> +#include <linux/string_helpers.h> #include <linux/pm_runtime.h> #include <drm/drm_atomic_helper.h> @@ -56,6 +57,8 @@ #include "vlv_sideband.h" #include "../../../platform/x86/intel_ips.h" +static void skl_sagv_disable(struct drm_i915_private *dev_priv); + struct drm_i915_clock_gating_funcs { void (*init_clock_gating)(struct drm_i915_private *i915); }; @@ -418,8 +421,8 @@ static bool _intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enabl trace_intel_memory_cxsr(dev_priv, was_enabled, enable); drm_dbg_kms(&dev_priv->drm, "memory self-refresh is %s (was %s)\n", - enableddisabled(enable), - enableddisabled(was_enabled)); + str_enabled_disabled(enable), + str_enabled_disabled(was_enabled)); return was_enabled; } @@ -3669,8 +3672,8 @@ intel_has_sagv(struct drm_i915_private *dev_priv) dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED; } -static void -skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) +static u32 +intel_sagv_block_time(struct drm_i915_private *dev_priv) { if (DISPLAY_VER(dev_priv) >= 12) { u32 val = 0; @@ -3679,26 +3682,48 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) ret = snb_pcode_read(dev_priv, GEN12_PCODE_READ_SAGV_BLOCK_TIME_US, &val, NULL); - if (!ret) { - dev_priv->sagv_block_time_us = val; - return; + if (ret) { + drm_dbg_kms(&dev_priv->drm, "Couldn't read SAGV block time!\n"); + return 0; } - drm_dbg(&dev_priv->drm, "Couldn't read SAGV block time!\n"); + return val; } else if (DISPLAY_VER(dev_priv) == 11) { - dev_priv->sagv_block_time_us = 10; - return; - } else if (DISPLAY_VER(dev_priv) == 10) { - dev_priv->sagv_block_time_us = 20; - return; - } else if (DISPLAY_VER(dev_priv) == 9) { - dev_priv->sagv_block_time_us = 30; - return; + return 10; + } else if (DISPLAY_VER(dev_priv) == 9 && !IS_LP(dev_priv)) { + return 30; } else { - MISSING_CASE(DISPLAY_VER(dev_priv)); + return 0; } +} + +static void intel_sagv_init(struct drm_i915_private *i915) +{ + if (!intel_has_sagv(i915)) + i915->sagv_status = I915_SAGV_NOT_CONTROLLED; - dev_priv->sagv_block_time_us = 0; + /* + * Probe to see if we have working SAGV control. + * For icl+ this was already determined by intel_bw_init_hw(). + */ + if (DISPLAY_VER(i915) < 11) + skl_sagv_disable(i915); + + drm_WARN_ON(&i915->drm, i915->sagv_status == I915_SAGV_UNKNOWN); + + i915->sagv_block_time_us = intel_sagv_block_time(i915); + + drm_dbg_kms(&i915->drm, "SAGV supported: %s, original SAGV block time: %u us\n", + str_yes_no(intel_has_sagv(i915)), i915->sagv_block_time_us); + + /* avoid overflow when adding with wm0 latency/etc. */ + if (drm_WARN(&i915->drm, i915->sagv_block_time_us > U16_MAX, + "Excessive SAGV block time %u, ignoring\n", + i915->sagv_block_time_us)) + i915->sagv_block_time_us = 0; + + if (!intel_has_sagv(i915)) + i915->sagv_block_time_us = 0; } /* @@ -3712,16 +3737,15 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) * - All planes can enable watermarks for latencies >= SAGV engine block time * - We're not using an interlaced display configuration */ -static int -intel_enable_sagv(struct drm_i915_private *dev_priv) +static void skl_sagv_enable(struct drm_i915_private *dev_priv) { int ret; if (!intel_has_sagv(dev_priv)) - return 0; + return; if (dev_priv->sagv_status == I915_SAGV_ENABLED) - return 0; + return; drm_dbg_kms(&dev_priv->drm, "Enabling SAGV\n"); ret = snb_pcode_write(dev_priv, GEN9_PCODE_SAGV_CONTROL, @@ -3736,26 +3760,24 @@ intel_enable_sagv(struct drm_i915_private *dev_priv) if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) { drm_dbg(&dev_priv->drm, "No SAGV found on system, ignoring\n"); dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED; - return 0; + return; } else if (ret < 0) { drm_err(&dev_priv->drm, "Failed to enable SAGV\n"); - return ret; + return; } dev_priv->sagv_status = I915_SAGV_ENABLED; - return 0; } -static int -intel_disable_sagv(struct drm_i915_private *dev_priv) +static void skl_sagv_disable(struct drm_i915_private *dev_priv) { int ret; if (!intel_has_sagv(dev_priv)) - return 0; + return; if (dev_priv->sagv_status == I915_SAGV_DISABLED) - return 0; + return; drm_dbg_kms(&dev_priv->drm, "Disabling SAGV\n"); /* bspec says to keep retrying for at least 1 ms */ @@ -3770,14 +3792,13 @@ intel_disable_sagv(struct drm_i915_private *dev_priv) if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) { drm_dbg(&dev_priv->drm, "No SAGV found on system, ignoring\n"); dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED; - return 0; + return; } else if (ret < 0) { drm_err(&dev_priv->drm, "Failed to disable SAGV (%d)\n", ret); - return ret; + return; } dev_priv->sagv_status = I915_SAGV_DISABLED; - return 0; } static void skl_sagv_pre_plane_update(struct intel_atomic_state *state) @@ -3790,7 +3811,7 @@ static void skl_sagv_pre_plane_update(struct intel_atomic_state *state) return; if (!intel_can_enable_sagv(i915, new_bw_state)) - intel_disable_sagv(i915); + skl_sagv_disable(i915); } static void skl_sagv_post_plane_update(struct intel_atomic_state *state) @@ -3803,7 +3824,7 @@ static void skl_sagv_post_plane_update(struct intel_atomic_state *state) return; if (intel_can_enable_sagv(i915, new_bw_state)) - intel_enable_sagv(i915); + skl_sagv_enable(i915); } static void icl_sagv_pre_plane_update(struct intel_atomic_state *state) @@ -4325,46 +4346,31 @@ static void skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv, const enum pipe pipe, const enum plane_id plane_id, - struct skl_ddb_entry *ddb_y, - struct skl_ddb_entry *ddb_uv) + struct skl_ddb_entry *ddb, + struct skl_ddb_entry *ddb_y) { - u32 val, val2; - u32 fourcc = 0; + u32 val; /* Cursor doesn't support NV12/planar, so no extra calculation needed */ if (plane_id == PLANE_CURSOR) { val = intel_uncore_read(&dev_priv->uncore, CUR_BUF_CFG(pipe)); - skl_ddb_entry_init_from_hw(ddb_y, val); + skl_ddb_entry_init_from_hw(ddb, val); return; } - val = intel_uncore_read(&dev_priv->uncore, PLANE_CTL(pipe, plane_id)); - - /* No DDB allocated for disabled planes */ - if (val & PLANE_CTL_ENABLE) - fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK_SKL, - val & PLANE_CTL_ORDER_RGBX, - val & PLANE_CTL_ALPHA_MASK); - - if (DISPLAY_VER(dev_priv) >= 11) { - val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id)); - skl_ddb_entry_init_from_hw(ddb_y, val); - } else { - val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id)); - val2 = intel_uncore_read(&dev_priv->uncore, PLANE_NV12_BUF_CFG(pipe, plane_id)); + val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id)); + skl_ddb_entry_init_from_hw(ddb, val); - if (fourcc && - drm_format_info_is_yuv_semiplanar(drm_format_info(fourcc))) - swap(val, val2); + if (DISPLAY_VER(dev_priv) >= 11) + return; - skl_ddb_entry_init_from_hw(ddb_y, val); - skl_ddb_entry_init_from_hw(ddb_uv, val2); - } + val = intel_uncore_read(&dev_priv->uncore, PLANE_NV12_BUF_CFG(pipe, plane_id)); + skl_ddb_entry_init_from_hw(ddb_y, val); } void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, - struct skl_ddb_entry *ddb_y, - struct skl_ddb_entry *ddb_uv) + struct skl_ddb_entry *ddb, + struct skl_ddb_entry *ddb_y) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum intel_display_power_domain power_domain; @@ -4380,8 +4386,8 @@ void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, for_each_plane_id_on_crtc(crtc, plane_id) skl_ddb_get_hw_plane_state(dev_priv, pipe, plane_id, - &ddb_y[plane_id], - &ddb_uv[plane_id]); + &ddb[plane_id], + &ddb_y[plane_id]); intel_display_power_put(dev_priv, power_domain, wakeref); } @@ -4913,17 +4919,6 @@ static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes, bool } static bool -use_min_ddb(const struct intel_crtc_state *crtc_state, - struct intel_plane *plane) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - - return DISPLAY_VER(i915) >= 13 && - crtc_state->uapi.async_flip && - plane->async_flip; -} - -static bool use_minimal_wm0_only(const struct intel_crtc_state *crtc_state, struct intel_plane *plane) { @@ -4935,134 +4930,24 @@ use_minimal_wm0_only(const struct intel_crtc_state *crtc_state, } static u64 -skl_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; - int width, height; - - if (!plane_state->uapi.visible) - return 0; - - if (plane->id == PLANE_CURSOR) - return 0; - - /* - * We calculate extra ddb based on ratio plane rate/total data rate - * in case, in some cases we should not allocate extra ddb for the plane, - * so do not count its data rate, if this is the case. - */ - if (use_min_ddb(crtc_state, plane)) - return 0; - - if (color_plane == 1 && - !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - return 0; - - /* - * Src coordinates are already rotated by 270 degrees for - * the 90/270 degree plane rotation cases (to match the - * GTT mapping), hence no need to account for rotation here. - */ - width = drm_rect_width(&plane_state->uapi.src) >> 16; - height = drm_rect_height(&plane_state->uapi.src) >> 16; - - /* UV plane does 1/2 pixel sub-sampling */ - if (color_plane == 1) { - width /= 2; - height /= 2; - } - - return width * height * fb->format->cpp[color_plane]; -} - -static u64 -skl_get_total_relative_data_rate(struct intel_atomic_state *state, - struct intel_crtc *crtc) +skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state) { - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - const struct intel_plane_state *plane_state; - struct intel_plane *plane; - u64 total_data_rate = 0; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum plane_id plane_id; - int i; - - /* Calculate and cache data rate for each plane */ - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - if (plane->pipe != crtc->pipe) - continue; - - plane_id = plane->id; - - /* packed/y */ - crtc_state->plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 0); - - /* uv-plane */ - crtc_state->uv_plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 1); - } + u64 data_rate = 0; for_each_plane_id_on_crtc(crtc, plane_id) { - total_data_rate += crtc_state->plane_data_rate[plane_id]; - total_data_rate += crtc_state->uv_plane_data_rate[plane_id]; - } - - return total_data_rate; -} - -static u64 -icl_get_total_relative_data_rate(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - const struct intel_plane_state *plane_state; - struct intel_plane *plane; - u64 total_data_rate = 0; - enum plane_id plane_id; - int i; - - /* Calculate and cache data rate for each plane */ - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - if (plane->pipe != crtc->pipe) + if (plane_id == PLANE_CURSOR) continue; - plane_id = plane->id; - - if (!plane_state->planar_linked_plane) { - crtc_state->plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 0); - } else { - enum plane_id y_plane_id; - - /* - * The slave plane might not iterate in - * intel_atomic_crtc_state_for_each_plane_state(), - * and needs the master plane state which may be - * NULL if we try get_new_plane_state(), so we - * always calculate from the master. - */ - if (plane_state->planar_slave) - continue; - - /* Y plane rate is calculated on the slave */ - y_plane_id = plane_state->planar_linked_plane->id; - crtc_state->plane_data_rate[y_plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 0); + data_rate += crtc_state->rel_data_rate[plane_id]; - crtc_state->plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 1); - } + if (DISPLAY_VER(i915) < 11) + data_rate += crtc_state->rel_data_rate_y[plane_id]; } - for_each_plane_id_on_crtc(crtc, plane_id) - total_data_rate += crtc_state->plane_data_rate[plane_id]; - - return total_data_rate; + return data_rate; } const struct skl_wm_level * @@ -5103,18 +4988,18 @@ skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm, * So this is actually safe to do. */ static void -skl_check_wm_level(struct skl_wm_level *wm, u64 total) +skl_check_wm_level(struct skl_wm_level *wm, const struct skl_ddb_entry *ddb) { - if (wm->min_ddb_alloc > total) + if (wm->min_ddb_alloc > skl_ddb_entry_size(ddb)) memset(wm, 0, sizeof(*wm)); } static void skl_check_nv12_wm_level(struct skl_wm_level *wm, struct skl_wm_level *uv_wm, - u64 total, u64 uv_total) + const struct skl_ddb_entry *ddb_y, const struct skl_ddb_entry *ddb) { - if (wm->min_ddb_alloc > total || - uv_wm->min_ddb_alloc > uv_total) { + if (wm->min_ddb_alloc > skl_ddb_entry_size(ddb_y) || + uv_wm->min_ddb_alloc > skl_ddb_entry_size(ddb)) { memset(wm, 0, sizeof(*wm)); memset(uv_wm, 0, sizeof(*uv_wm)); } @@ -5134,17 +5019,16 @@ static bool icl_need_wm1_wa(struct drm_i915_private *i915, struct skl_plane_ddb_iter { u64 data_rate; - u16 total[I915_MAX_PLANES]; - u16 uv_total[I915_MAX_PLANES]; u16 start, size; }; -static u16 +static void skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, + struct skl_ddb_entry *ddb, const struct skl_wm_level *wm, u64 data_rate) { - u16 extra = 0; + u16 size, extra = 0; if (data_rate) { extra = min_t(u16, iter->size, @@ -5154,7 +5038,15 @@ skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, iter->data_rate -= data_rate; } - return wm->min_ddb_alloc + extra; + /* + * Keep ddb entry of all disabled planes explicitly zeroed + * to avoid skl_ddb_add_affected_planes() adding them to + * the state when other planes change their allocations. + */ + size = wm->min_ddb_alloc + extra; + if (size) + iter->start = skl_ddb_entry_init(ddb, iter->start, + iter->start + size); } static int @@ -5168,32 +5060,31 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, intel_atomic_get_new_dbuf_state(state); const struct skl_ddb_entry *alloc = &dbuf_state->ddb[crtc->pipe]; int num_active = hweight8(dbuf_state->active_pipes); - struct skl_plane_ddb_iter iter = {}; + struct skl_plane_ddb_iter iter; enum plane_id plane_id; + u16 cursor_size; u32 blocks; int level; /* Clear the partitioning for disabled planes. */ + memset(crtc_state->wm.skl.plane_ddb, 0, sizeof(crtc_state->wm.skl.plane_ddb)); memset(crtc_state->wm.skl.plane_ddb_y, 0, sizeof(crtc_state->wm.skl.plane_ddb_y)); - memset(crtc_state->wm.skl.plane_ddb_uv, 0, sizeof(crtc_state->wm.skl.plane_ddb_uv)); if (!crtc_state->hw.active) return 0; - if (DISPLAY_VER(dev_priv) >= 11) - iter.data_rate = icl_get_total_relative_data_rate(state, crtc); - else - iter.data_rate = skl_get_total_relative_data_rate(state, crtc); - + iter.start = alloc->start; iter.size = skl_ddb_entry_size(alloc); if (iter.size == 0) return 0; /* Allocate fixed number of blocks for cursor. */ - iter.total[PLANE_CURSOR] = skl_cursor_allocation(crtc_state, num_active); - iter.size -= iter.total[PLANE_CURSOR]; - skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR], - alloc->end - iter.total[PLANE_CURSOR], alloc->end); + cursor_size = skl_cursor_allocation(crtc_state, num_active); + iter.size -= cursor_size; + skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], + alloc->end - cursor_size, alloc->end); + + iter.data_rate = skl_total_relative_data_rate(crtc_state); /* * Find the highest watermark level for which we can satisfy the block @@ -5206,7 +5097,10 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, &crtc_state->wm.skl.optimal.planes[plane_id]; if (plane_id == PLANE_CURSOR) { - if (wm->wm[level].min_ddb_alloc > iter.total[PLANE_CURSOR]) { + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + + if (wm->wm[level].min_ddb_alloc > skl_ddb_entry_size(ddb)) { drm_WARN_ON(&dev_priv->drm, wm->wm[level].min_ddb_alloc != U16_MAX); blocks = U32_MAX; @@ -5243,47 +5137,29 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, * proportional to its relative data rate. */ for_each_plane_id_on_crtc(crtc, plane_id) { + struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + struct skl_ddb_entry *ddb_y = + &crtc_state->wm.skl.plane_ddb_y[plane_id]; const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; if (plane_id == PLANE_CURSOR) continue; - iter.total[plane_id] = - skl_allocate_plane_ddb(&iter, &wm->wm[level], - crtc_state->plane_data_rate[plane_id]); - - iter.uv_total[plane_id] = - skl_allocate_plane_ddb(&iter, &wm->uv_wm[level], - crtc_state->uv_plane_data_rate[plane_id]); + if (DISPLAY_VER(dev_priv) < 11 && + crtc_state->nv12_planes & BIT(plane_id)) { + skl_allocate_plane_ddb(&iter, ddb_y, &wm->wm[level], + crtc_state->rel_data_rate_y[plane_id]); + skl_allocate_plane_ddb(&iter, ddb, &wm->uv_wm[level], + crtc_state->rel_data_rate[plane_id]); + } else { + skl_allocate_plane_ddb(&iter, ddb, &wm->wm[level], + crtc_state->rel_data_rate[plane_id]); + } } drm_WARN_ON(&dev_priv->drm, iter.size != 0 || iter.data_rate != 0); - /* Set the actual DDB start/end points for each plane */ - iter.start = alloc->start; - for_each_plane_id_on_crtc(crtc, plane_id) { - struct skl_ddb_entry *plane_alloc = - &crtc_state->wm.skl.plane_ddb_y[plane_id]; - struct skl_ddb_entry *uv_plane_alloc = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; - - if (plane_id == PLANE_CURSOR) - continue; - - /* Gen11+ uses a separate plane for UV watermarks */ - drm_WARN_ON(&dev_priv->drm, - DISPLAY_VER(dev_priv) >= 11 && iter.uv_total[plane_id]); - - /* Leave disabled planes at (0,0) */ - if (iter.total[plane_id]) - iter.start = skl_ddb_entry_init(plane_alloc, iter.start, - iter.start + iter.total[plane_id]); - - if (iter.uv_total[plane_id]) - iter.start = skl_ddb_entry_init(uv_plane_alloc, iter.start, - iter.start + iter.uv_total[plane_id]); - } - /* * When we calculated watermark values we didn't know how high * of a level we'd actually be able to hit, so we just marked @@ -5292,12 +5168,20 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, */ for (level++; level <= ilk_wm_max_level(dev_priv); level++) { for_each_plane_id_on_crtc(crtc, plane_id) { + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + const struct skl_ddb_entry *ddb_y = + &crtc_state->wm.skl.plane_ddb_y[plane_id]; struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - skl_check_nv12_wm_level(&wm->wm[level], &wm->uv_wm[level], - iter.total[plane_id], - iter.uv_total[plane_id]); + if (DISPLAY_VER(dev_priv) < 11 && + crtc_state->nv12_planes & BIT(plane_id)) + skl_check_nv12_wm_level(&wm->wm[level], + &wm->uv_wm[level], + ddb_y, ddb); + else + skl_check_wm_level(&wm->wm[level], ddb); if (icl_need_wm1_wa(dev_priv, plane_id) && level == 1 && wm->wm[0].enable) { @@ -5313,12 +5197,24 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, * if it turns out we don't have enough DDB blocks for them. */ for_each_plane_id_on_crtc(crtc, plane_id) { + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + const struct skl_ddb_entry *ddb_y = + &crtc_state->wm.skl.plane_ddb_y[plane_id]; struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - skl_check_wm_level(&wm->trans_wm, iter.total[plane_id]); - skl_check_wm_level(&wm->sagv.wm0, iter.total[plane_id]); - skl_check_wm_level(&wm->sagv.trans_wm, iter.total[plane_id]); + if (DISPLAY_VER(dev_priv) < 11 && + crtc_state->nv12_planes & BIT(plane_id)) { + skl_check_wm_level(&wm->trans_wm, ddb_y); + } else { + WARN_ON(skl_ddb_entry_size(ddb_y)); + + skl_check_wm_level(&wm->trans_wm, ddb); + } + + skl_check_wm_level(&wm->sagv.wm0, ddb); + skl_check_wm_level(&wm->sagv.trans_wm, ddb); } return 0; @@ -5408,6 +5304,7 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, } wp->y_tiled = modifier == I915_FORMAT_MOD_Y_TILED || + modifier == I915_FORMAT_MOD_4_TILED || modifier == I915_FORMAT_MOD_Yf_TILED || modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS; @@ -5578,6 +5475,25 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, } blocks = fixed16_to_u32_round_up(selected_result) + 1; + /* + * Lets have blocks at minimum equivalent to plane_blocks_per_line + * as there will be at minimum one line for lines configuration. This + * is a work around for FIFO underruns observed with resolutions like + * 4k 60 Hz in single channel DRAM configurations. + * + * As per the Bspec 49325, if the ddb allocation can hold at least + * one plane_blocks_per_line, we should have selected method2 in + * the above logic. Assuming that modern versions have enough dbuf + * and method2 guarantees blocks equivalent to at least 1 line, + * select the blocks as plane_blocks_per_line. + * + * TODO: Revisit the logic when we have better understanding on DRAM + * channels' impact on the level 0 memory latency and the relevant + * wm calculations. + */ + if (skl_wm_has_lines(dev_priv, level)) + blocks = max(blocks, + fixed16_to_u32_round_up(wp->plane_blocks_per_line)); lines = div_round_up_fixed16(selected_result, wp->plane_blocks_per_line); @@ -5926,7 +5842,7 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv, val |= PLANE_WM_EN; if (level->ignore_lines) val |= PLANE_WM_IGNORE_LINES; - val |= level->blocks; + val |= REG_FIELD_PREP(PLANE_WM_BLOCKS_MASK, level->blocks); val |= REG_FIELD_PREP(PLANE_WM_LINES_MASK, level->lines); intel_de_write_fw(dev_priv, reg, val); @@ -5940,11 +5856,10 @@ void skl_write_plane_wm(struct intel_plane *plane, enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; - const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; const struct skl_ddb_entry *ddb_y = &crtc_state->wm.skl.plane_ddb_y[plane_id]; - const struct skl_ddb_entry *ddb_uv = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; for (level = 0; level <= max_level; level++) skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level), @@ -5954,25 +5869,20 @@ void skl_write_plane_wm(struct intel_plane *plane, skl_plane_trans_wm(pipe_wm, plane_id)); if (HAS_HW_SAGV_WM(dev_priv)) { + const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; + skl_write_wm_level(dev_priv, PLANE_WM_SAGV(pipe, plane_id), &wm->sagv.wm0); skl_write_wm_level(dev_priv, PLANE_WM_SAGV_TRANS(pipe, plane_id), &wm->sagv.trans_wm); } - if (DISPLAY_VER(dev_priv) >= 11) { - skl_ddb_entry_write(dev_priv, - PLANE_BUF_CFG(pipe, plane_id), ddb_y); - return; - } - - if (wm->is_planar) - swap(ddb_y, ddb_uv); - - skl_ddb_entry_write(dev_priv, - PLANE_BUF_CFG(pipe, plane_id), ddb_y); skl_ddb_entry_write(dev_priv, - PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv); + PLANE_BUF_CFG(pipe, plane_id), ddb); + + if (DISPLAY_VER(dev_priv) < 11) + skl_ddb_entry_write(dev_priv, + PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_y); } void skl_write_cursor_wm(struct intel_plane *plane, @@ -5984,7 +5894,7 @@ void skl_write_cursor_wm(struct intel_plane *plane, enum pipe pipe = plane->pipe; const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; const struct skl_ddb_entry *ddb = - &crtc_state->wm.skl.plane_ddb_y[plane_id]; + &crtc_state->wm.skl.plane_ddb[plane_id]; for (level = 0; level <= max_level; level++) skl_write_wm_level(dev_priv, CUR_WM(pipe, level), @@ -6081,10 +5991,10 @@ skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state, struct intel_plane_state *plane_state; enum plane_id plane_id = plane->id; - if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id], - &new_crtc_state->wm.skl.plane_ddb_y[plane_id]) && - skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id], - &new_crtc_state->wm.skl.plane_ddb_uv[plane_id])) + if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb[plane_id], + &new_crtc_state->wm.skl.plane_ddb[plane_id]) && + skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id], + &new_crtc_state->wm.skl.plane_ddb_y[plane_id])) continue; plane_state = intel_atomic_get_plane_state(state, plane); @@ -6147,7 +6057,7 @@ skl_compute_ddb(struct intel_atomic_state *state) return ret; } - if (IS_ALDERLAKE_P(dev_priv)) + if (HAS_MBUS_JOINING(dev_priv)) new_dbuf_state->joined_mbus = adlp_check_mbus_joined(new_dbuf_state->active_pipes); @@ -6186,8 +6096,8 @@ skl_compute_ddb(struct intel_atomic_state *state) old_dbuf_state->enabled_slices, new_dbuf_state->enabled_slices, INTEL_INFO(dev_priv)->dbuf.slice_mask, - yesno(old_dbuf_state->joined_mbus), - yesno(new_dbuf_state->joined_mbus)); + str_yes_no(old_dbuf_state->joined_mbus), + str_yes_no(new_dbuf_state->joined_mbus)); } for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { @@ -6253,8 +6163,8 @@ skl_print_wm_changes(struct intel_atomic_state *state) enum plane_id plane_id = plane->id; const struct skl_ddb_entry *old, *new; - old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id]; - new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id]; + old = &old_crtc_state->wm.skl.plane_ddb[plane_id]; + new = &new_crtc_state->wm.skl.plane_ddb[plane_id]; if (skl_ddb_entry_equal(old, new)) continue; @@ -6574,7 +6484,7 @@ static void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level) { level->enable = val & PLANE_WM_EN; level->ignore_lines = val & PLANE_WM_IGNORE_LINES; - level->blocks = val & PLANE_WM_BLOCKS_MASK; + level->blocks = REG_FIELD_GET(PLANE_WM_BLOCKS_MASK, val); level->lines = REG_FIELD_GET(PLANE_WM_LINES_MASK, val); } @@ -6639,7 +6549,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) to_intel_dbuf_state(dev_priv->dbuf.obj.state); struct intel_crtc *crtc; - if (IS_ALDERLAKE_P(dev_priv)) + if (HAS_MBUS_JOINING(dev_priv)) dbuf_state->joined_mbus = intel_de_read(dev_priv, MBUS_CTL) & MBUS_JOIN; for_each_intel_crtc(&dev_priv->drm, crtc) { @@ -6656,16 +6566,16 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) memset(&dbuf_state->ddb[pipe], 0, sizeof(dbuf_state->ddb[pipe])); for_each_plane_id_on_crtc(crtc, plane_id) { + struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; struct skl_ddb_entry *ddb_y = &crtc_state->wm.skl.plane_ddb_y[plane_id]; - struct skl_ddb_entry *ddb_uv = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; skl_ddb_get_hw_plane_state(dev_priv, crtc->pipe, - plane_id, ddb_y, ddb_uv); + plane_id, ddb, ddb_y); + skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb); skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_y); - skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_uv); } dbuf_state->weight[pipe] = intel_crtc_ddb_weight(crtc_state); @@ -6689,7 +6599,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) crtc->base.base.id, crtc->base.name, dbuf_state->slices[pipe], dbuf_state->ddb[pipe].start, dbuf_state->ddb[pipe].end, dbuf_state->active_pipes, - yesno(dbuf_state->joined_mbus)); + str_yes_no(dbuf_state->joined_mbus)); } dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices; @@ -7000,7 +6910,8 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) "Initial HPLL watermarks: plane=%d, SR cursor=%d fbc=%d\n", wm->hpll.plane, wm->hpll.cursor, wm->hpll.fbc); drm_dbg_kms(&dev_priv->drm, "Initial SR=%s HPLL=%s FBC=%s\n", - yesno(wm->cxsr), yesno(wm->hpll_en), yesno(wm->fbc_en)); + str_yes_no(wm->cxsr), str_yes_no(wm->hpll_en), + str_yes_no(wm->fbc_en)); } void g4x_wm_sanitize(struct drm_i915_private *dev_priv) @@ -7578,6 +7489,9 @@ static void adlp_init_clock_gating(struct drm_i915_private *dev_priv) /* Wa_22011091694:adlp */ intel_de_rmw(dev_priv, GEN9_CLKGATE_DIS_5, 0, DPCE_GATING_DIS); + + /* Bspec/49189 Initialize Sequence */ + intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1, DDI_CLOCK_REG_ACCESS, 0); } static void dg1_init_clock_gating(struct drm_i915_private *dev_priv) @@ -8175,8 +8089,7 @@ void intel_init_pm(struct drm_i915_private *dev_priv) else if (GRAPHICS_VER(dev_priv) == 5) ilk_get_mem_freq(dev_priv); - if (intel_has_sagv(dev_priv)) - skl_setup_sagv_block_time(dev_priv); + intel_sagv_init(dev_priv); /* For FIFO watermark updates */ if (DISPLAY_VER(dev_priv) >= 9) { @@ -8301,7 +8214,7 @@ static void update_mbus_pre_enable(struct intel_atomic_state *state) const struct intel_dbuf_state *dbuf_state = intel_atomic_get_new_dbuf_state(state); - if (!IS_ALDERLAKE_P(dev_priv)) + if (!HAS_MBUS_JOINING(dev_priv)) return; /* @@ -8367,3 +8280,55 @@ void intel_dbuf_post_plane_update(struct intel_atomic_state *state) gen9_dbuf_slices_update(dev_priv, new_dbuf_state->enabled_slices); } + +void intel_mbus_dbox_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; + const struct intel_crtc_state *new_crtc_state; + const struct intel_crtc *crtc; + u32 val = 0; + int i; + + if (DISPLAY_VER(i915) < 11) + return; + + 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->joined_mbus == old_dbuf_state->joined_mbus && + new_dbuf_state->active_pipes == old_dbuf_state->active_pipes)) + return; + + if (DISPLAY_VER(i915) >= 12) { + val |= MBUS_DBOX_B2B_TRANSACTIONS_MAX(16); + val |= MBUS_DBOX_B2B_TRANSACTIONS_DELAY(1); + val |= MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN; + } + + /* Wa_22010947358:adl-p */ + if (IS_ALDERLAKE_P(i915)) + val |= new_dbuf_state->joined_mbus ? MBUS_DBOX_A_CREDIT(6) : + MBUS_DBOX_A_CREDIT(4); + else + val |= MBUS_DBOX_A_CREDIT(2); + + if (IS_ALDERLAKE_P(i915)) { + val |= MBUS_DBOX_BW_CREDIT(2); + val |= MBUS_DBOX_B_CREDIT(8); + } else if (DISPLAY_VER(i915) >= 12) { + val |= MBUS_DBOX_BW_CREDIT(2); + val |= MBUS_DBOX_B_CREDIT(12); + } else { + val |= MBUS_DBOX_BW_CREDIT(1); + val |= MBUS_DBOX_B_CREDIT(8); + } + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!new_crtc_state->hw.active || + !intel_crtc_needs_modeset(new_crtc_state)) + continue; + + intel_de_write(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe), val); + } +} |