Merge tag 'drm-intel-next-2025-07-04' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
drm/i915 feature pull #2 for v6.17: Features and functionality: - Add drm_panic support for both i915 and xe drivers (Jocelyn Falempe) - Add initial flip queue implementation, disabled by default, for LNL and PTL (Ville) - Add support for Wildcat Lake (WCL) display, version 30.02 (Matt Roper, Matt Atwood, Dnyaneshwar) - Extend drm_panel and follower support to DDI eDP (Arun) Refactoring and cleanups: - Make all global state objects opaque (Jani) - Move display works to display specific unordered workqueue (Luca) - Add and use struct drm_device based pcode interface (Jani, Lucas) - Use clamp() instead of max()+min() combo (Ankit) - Simplify wait for power well disable (Jani) - Various stylistics cleanups and renames (Jani) Fixes: - Deal with loss of pipe DMC state (Ville) - Fix PTL HDCP2 stream status check (Suraj) - Add workaround for ADL-P DKL PHY DP and HDMI (Nemesa) - Fix skl_print_wm_changes() stack usage with KMSAN (Arnd Bergmann) - Fix PCON capability reads on non-branch devices (Chaitanya) - Fix which platforms have ultra joiner (Ankit) DRM core changes: - Add ttm_bo_kmap_try_from_panic() for xe drm_panic support (Jocelyn Falempe) - Add private pointer to struct drm_scanout buffer for xe/i915 drm_panic support (Jocelyn Falempe) Merges: - Backmerge drm-next for drm_panel and xe changes (Jani) Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch> From: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/6d728bf6ef23681b00dfbc7da9aeae41042dee02@intel.com
This commit is contained in:
@@ -112,10 +112,10 @@ panel self refresh.
|
||||
Atomic Plane Helpers
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_atomic_plane.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_plane.c
|
||||
:doc: atomic plane helpers
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_atomic_plane.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_plane.c
|
||||
:internal:
|
||||
|
||||
Asynchronous Page Flip
|
||||
@@ -204,6 +204,12 @@ DMC Firmware Support
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
|
||||
:internal:
|
||||
|
||||
DMC Flip Queue
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_flipq.c
|
||||
:doc: DMC Flip Queue
|
||||
|
||||
DMC wakelock support
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -7183,7 +7199,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 +7225,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 +7236,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 +7264,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 +7280,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 +7424,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 +7448,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -479,6 +479,12 @@ struct intel_display {
|
||||
u32 pipestat_irq_mask[I915_MAX_PIPES];
|
||||
} irq;
|
||||
|
||||
struct {
|
||||
/* protected by wm.wm_mutex */
|
||||
u16 linetime[I915_MAX_PIPES];
|
||||
bool disable[I915_MAX_PIPES];
|
||||
} pkgc;
|
||||
|
||||
struct {
|
||||
wait_queue_head_t waitqueue;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)");
|
||||
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
return;
|
||||
|
||||
if (!has_dmc_id_fw(display, dmc_id))
|
||||
continue;
|
||||
|
||||
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,28 +886,19 @@ 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);
|
||||
|
||||
for_each_dmc_id(dmc_id)
|
||||
disable_all_event_handlers(display, dmc_id);
|
||||
|
||||
pipedmc_clock_gating_wa(display, false);
|
||||
}
|
||||
|
||||
void assert_dmc_loaded(struct intel_display *display)
|
||||
{
|
||||
struct intel_dmc *dmc = display_to_dmc(display);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
static bool fw_info_matches_stepping(const struct intel_fw_info *fw_info,
|
||||
const struct stepping_info *si)
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -3726,6 +3726,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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1286,10 +1286,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);
|
||||
}
|
||||
@@ -2346,7 +2346,7 @@ intel_framebuffer_create(struct drm_gem_object *obj,
|
||||
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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1576,7 +1576,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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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,
|
||||
|
||||
@@ -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) : \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+184
-15
@@ -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",
|
||||
+10
-12
@@ -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__ */
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -3320,7 +3339,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,14 +3353,13 @@ 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 (intel_dp->psr.psr2_sel_fetch_cff_enabled) {
|
||||
@@ -3367,7 +3384,7 @@ static void _psr_flush_handle(struct intel_dp *intel_dp)
|
||||
|
||||
if (!intel_dp->psr.psr2_sel_fetch_enabled && !intel_dp->psr.active &&
|
||||
!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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
/* FIXME runtime changes to enable_flipq are racy */
|
||||
if (display->params.enable_flipq)
|
||||
added_wake_time = intel_flipq_exec_time_us(display);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (fixed_refresh_rate) {
|
||||
added_wake_time = DSB_EXE_TIME +
|
||||
display->sagv.block_time_us;
|
||||
max_linetime = pkgc_max_linetime(state);
|
||||
|
||||
latency = skl_watermark_max_latency(display, 1);
|
||||
|
||||
/* Wa_22020432604 */
|
||||
if ((DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30) && !latency) {
|
||||
latency += added_wake_time;
|
||||
added_wake_time = 0;
|
||||
}
|
||||
|
||||
/* 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 =
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -335,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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -381,6 +381,32 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
|
||||
return (!map->virtual) ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ttm_bo_kmap_try_from_panic
|
||||
*
|
||||
* @bo: The buffer object
|
||||
* @page: The page to map
|
||||
*
|
||||
* Sets up a kernel virtual mapping using kmap_local_page_try_from_panic().
|
||||
* This should only be called from the panic handler, if you make sure the bo
|
||||
* is the one being displayed, so is properly allocated, and protected.
|
||||
*
|
||||
* Returns the vaddr, that you can use to write to the bo, and that you should
|
||||
* pass to kunmap_local() when you're done with this page, or NULL if the bo
|
||||
* is in iomem.
|
||||
*/
|
||||
void *ttm_bo_kmap_try_from_panic(struct ttm_buffer_object *bo, unsigned long page)
|
||||
{
|
||||
if (page + 1 > PFN_UP(bo->resource->size))
|
||||
return NULL;
|
||||
|
||||
if (!bo->resource->bus.is_iomem && bo->ttm->pages && bo->ttm->pages[page])
|
||||
return kmap_local_page_try_from_panic(bo->ttm->pages[page]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ttm_bo_kmap_try_from_panic);
|
||||
|
||||
/**
|
||||
* ttm_bo_kmap
|
||||
*
|
||||
|
||||
@@ -205,7 +205,6 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
|
||||
i915-display/icl_dsi.o \
|
||||
i915-display/intel_alpm.o \
|
||||
i915-display/intel_atomic.o \
|
||||
i915-display/intel_atomic_plane.o \
|
||||
i915-display/intel_audio.o \
|
||||
i915-display/intel_backlight.o \
|
||||
i915-display/intel_bios.o \
|
||||
@@ -255,6 +254,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
|
||||
i915-display/intel_fbc.o \
|
||||
i915-display/intel_fdi.o \
|
||||
i915-display/intel_fifo_underrun.o \
|
||||
i915-display/intel_flipq.o \
|
||||
i915-display/intel_frontbuffer.o \
|
||||
i915-display/intel_global_state.o \
|
||||
i915-display/intel_gmbus.o \
|
||||
@@ -271,6 +271,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
|
||||
i915-display/intel_modeset_verify.o \
|
||||
i915-display/intel_panel.o \
|
||||
i915-display/intel_pfit.o \
|
||||
i915-display/intel_plane.o \
|
||||
i915-display/intel_pmdemand.o \
|
||||
i915-display/intel_pch.o \
|
||||
i915-display/intel_pps.o \
|
||||
|
||||
@@ -6,37 +6,6 @@
|
||||
#ifndef __INTEL_PCODE_H__
|
||||
#define __INTEL_PCODE_H__
|
||||
|
||||
#include "intel_uncore.h"
|
||||
#include "xe_pcode.h"
|
||||
|
||||
static inline int
|
||||
snb_pcode_write_timeout(struct intel_uncore *uncore, u32 mbox, u32 val,
|
||||
int fast_timeout_us, int slow_timeout_ms)
|
||||
{
|
||||
return xe_pcode_write_timeout(__compat_uncore_to_tile(uncore), mbox, val,
|
||||
slow_timeout_ms ?: 1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
snb_pcode_write(struct intel_uncore *uncore, u32 mbox, u32 val)
|
||||
{
|
||||
|
||||
return xe_pcode_write(__compat_uncore_to_tile(uncore), mbox, val);
|
||||
}
|
||||
|
||||
static inline int
|
||||
snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val, u32 *val1)
|
||||
{
|
||||
return xe_pcode_read(__compat_uncore_to_tile(uncore), mbox, val, val1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
skl_pcode_request(struct intel_uncore *uncore, u32 mbox,
|
||||
u32 request, u32 reply_mask, u32 reply,
|
||||
int timeout_base_ms)
|
||||
{
|
||||
return xe_pcode_request(__compat_uncore_to_tile(uncore), mbox, request, reply_mask, reply,
|
||||
timeout_base_ms);
|
||||
}
|
||||
|
||||
#endif /* __INTEL_PCODE_H__ */
|
||||
|
||||
@@ -24,13 +24,6 @@ static inline struct xe_mmio *__compat_uncore_to_mmio(struct intel_uncore *uncor
|
||||
return xe_root_tile_mmio(xe);
|
||||
}
|
||||
|
||||
static inline struct xe_tile *__compat_uncore_to_tile(struct intel_uncore *uncore)
|
||||
{
|
||||
struct xe_device *xe = container_of(uncore, struct xe_device, uncore);
|
||||
|
||||
return xe_device_get_root_tile(xe);
|
||||
}
|
||||
|
||||
static inline u32 intel_uncore_read(struct intel_uncore *uncore,
|
||||
i915_reg_t i915_reg)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/* Copyright © 2024 Intel Corporation */
|
||||
|
||||
#include <drm/drm_cache.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_panic.h>
|
||||
|
||||
#include "intel_fb.h"
|
||||
#include "intel_display_types.h"
|
||||
|
||||
#include "xe_bo.h"
|
||||
#include "intel_bo.h"
|
||||
@@ -59,3 +64,89 @@ void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj)
|
||||
{
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
struct xe_panic_data {
|
||||
struct page **pages;
|
||||
int page;
|
||||
void *vaddr;
|
||||
};
|
||||
|
||||
struct xe_framebuffer {
|
||||
struct intel_framebuffer base;
|
||||
struct xe_panic_data panic;
|
||||
};
|
||||
|
||||
static inline struct xe_panic_data *to_xe_panic_data(struct intel_framebuffer *fb)
|
||||
{
|
||||
return &container_of_const(fb, struct xe_framebuffer, base)->panic;
|
||||
}
|
||||
|
||||
static void xe_panic_kunmap(struct xe_panic_data *panic)
|
||||
{
|
||||
if (panic->vaddr) {
|
||||
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
|
||||
kunmap_local(panic->vaddr);
|
||||
panic->vaddr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
|
||||
unsigned int y, u32 color)
|
||||
{
|
||||
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
|
||||
struct xe_panic_data *panic = to_xe_panic_data(fb);
|
||||
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
|
||||
unsigned int new_page;
|
||||
unsigned int offset;
|
||||
|
||||
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) {
|
||||
xe_panic_kunmap(panic);
|
||||
panic->page = new_page;
|
||||
panic->vaddr = ttm_bo_kmap_try_from_panic(&bo->ttm,
|
||||
panic->page);
|
||||
}
|
||||
if (panic->vaddr) {
|
||||
u32 *pix = panic->vaddr + offset;
|
||||
*pix = color;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_framebuffer *intel_bo_alloc_framebuffer(void)
|
||||
{
|
||||
struct xe_framebuffer *xe_fb;
|
||||
|
||||
xe_fb = kzalloc(sizeof(*xe_fb), GFP_KERNEL);
|
||||
if (xe_fb)
|
||||
return &xe_fb->base;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int intel_bo_panic_setup(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
|
||||
struct xe_panic_data *panic = to_xe_panic_data(fb);
|
||||
|
||||
panic->page = -1;
|
||||
sb->set_pixel = xe_panic_page_set_pixel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_bo_panic_finish(struct intel_framebuffer *fb)
|
||||
{
|
||||
struct xe_panic_data *panic = to_xe_panic_data(fb);
|
||||
|
||||
xe_panic_kunmap(panic);
|
||||
panic->page = -1;
|
||||
}
|
||||
|
||||
@@ -457,3 +457,8 @@ u64 intel_dpt_offset(struct i915_vma *dpt_vma)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_fb_get_map(struct i915_vma *vma, struct iosys_map *map)
|
||||
{
|
||||
*map = vma->bo->vmap;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "xe_ggtt.h"
|
||||
#include "xe_mmio.h"
|
||||
|
||||
#include "intel_atomic_plane.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_display.h"
|
||||
#include "intel_display_core.h"
|
||||
@@ -19,6 +18,7 @@
|
||||
#include "intel_fb.h"
|
||||
#include "intel_fb_pin.h"
|
||||
#include "intel_frontbuffer.h"
|
||||
#include "intel_plane.h"
|
||||
#include "intel_plane_initial.h"
|
||||
#include "xe_bo.h"
|
||||
#include "xe_wa.h"
|
||||
|
||||
@@ -336,3 +336,33 @@ int xe_pcode_probe_early(struct xe_device *xe)
|
||||
return xe_pcode_ready(xe, false);
|
||||
}
|
||||
ALLOW_ERROR_INJECTION(xe_pcode_probe_early, ERRNO); /* See xe_pci_probe */
|
||||
|
||||
/* Helpers with drm device. These should only be called by the display side */
|
||||
#if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
|
||||
|
||||
int intel_pcode_read(struct drm_device *drm, u32 mbox, u32 *val, u32 *val1)
|
||||
{
|
||||
struct xe_device *xe = to_xe_device(drm);
|
||||
struct xe_tile *tile = xe_device_get_root_tile(xe);
|
||||
|
||||
return xe_pcode_read(tile, mbox, val, val1);
|
||||
}
|
||||
|
||||
int intel_pcode_write_timeout(struct drm_device *drm, u32 mbox, u32 val, int timeout_ms)
|
||||
{
|
||||
struct xe_device *xe = to_xe_device(drm);
|
||||
struct xe_tile *tile = xe_device_get_root_tile(xe);
|
||||
|
||||
return xe_pcode_write_timeout(tile, 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 xe_device *xe = to_xe_device(drm);
|
||||
struct xe_tile *tile = xe_device_get_root_tile(xe);
|
||||
|
||||
return xe_pcode_request(tile, mbox, request, reply_mask, reply, timeout_base_ms);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#define _XE_PCODE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
struct xe_tile;
|
||||
|
||||
struct drm_device;
|
||||
struct xe_device;
|
||||
struct xe_tile;
|
||||
|
||||
void xe_pcode_init(struct xe_tile *tile);
|
||||
int xe_pcode_probe_early(struct xe_device *xe);
|
||||
@@ -32,4 +34,12 @@ int xe_pcode_request(struct xe_tile *tile, u32 mbox, u32 request,
|
||||
| FIELD_PREP(PCODE_MB_PARAM1, param1)\
|
||||
| FIELD_PREP(PCODE_MB_PARAM2, param2))
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -72,6 +72,12 @@ struct drm_scanout_buffer {
|
||||
void (*set_pixel)(struct drm_scanout_buffer *sb, unsigned int x,
|
||||
unsigned int y, u32 color);
|
||||
|
||||
/**
|
||||
* @private: private pointer that you can use in the callbacks
|
||||
* set_pixel()
|
||||
*/
|
||||
void *private;
|
||||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DRM_PANIC
|
||||
|
||||
@@ -409,6 +409,7 @@ int ttm_bo_init_validate(struct ttm_device *bdev, struct ttm_buffer_object *bo,
|
||||
int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page,
|
||||
unsigned long num_pages, struct ttm_bo_kmap_obj *map);
|
||||
void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map);
|
||||
void *ttm_bo_kmap_try_from_panic(struct ttm_buffer_object *bo, unsigned long page);
|
||||
int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map);
|
||||
void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map);
|
||||
int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo);
|
||||
|
||||
Reference in New Issue
Block a user