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:
Simona Vetter
2025-07-08 14:07:44 +02:00
86 changed files with 2638 additions and 904 deletions
+8 -2
View File
@@ -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
--------------------
+3 -2
View File
@@ -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 \
+6 -9
View File
@@ -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;
}
+30 -6
View File
@@ -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;
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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);
}
+17
View File
@@ -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);
}
+5
View File
@@ -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__ */
+164 -24
View File
@@ -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;
}
+10 -43
View File
@@ -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__ */
+123 -33
View File
@@ -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;
}
+11 -39
View File
@@ -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);
}
+1 -1
View File
@@ -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"
+5 -5
View File
@@ -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;
+7 -1
View File
@@ -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)
+20
View File
@@ -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);
+61 -18
View File
@@ -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
+328 -129
View File
@@ -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;
}
+15 -3
View File
@@ -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__ */
+1 -3
View File
@@ -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));
}
+3
View File
@@ -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)
+17 -3
View File
@@ -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;
}
+4 -3
View File
@@ -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)
+2 -3
View File
@@ -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));
}
+4 -4
View File
@@ -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);
+6 -1
View File
@@ -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
+3 -3
View File
@@ -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);
}
+5 -1
View File
@@ -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__ */
+472
View File
@@ -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__ */
+12 -15
View File
@@ -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) : \
+3 -9
View File
@@ -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)
+3 -2
View File
@@ -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;
@@ -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",
@@ -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)
+9 -32
View File
@@ -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);
+4 -3
View File
@@ -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);
}
+24 -7
View File
@@ -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);
}
/**
+2
View File
@@ -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,
+7 -7
View File
@@ -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;
+57 -64
View File
@@ -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;
+220 -232
View File
@@ -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 =
+7 -26
View File
@@ -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__ */
+1 -1
View File
@@ -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
+142
View File
@@ -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)
+1 -13
View File
@@ -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
+5
View File
@@ -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
+26 -3
View File
@@ -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);
}
+12 -3
View File
@@ -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 */
+10 -10
View File
@@ -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;
+3 -2
View File
@@ -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;
+26
View File
@@ -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
*
+2 -1
View File
@@ -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)
{
+91
View File
@@ -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;
}
+5
View File
@@ -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"
+30
View File
@@ -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
+11 -1
View File
@@ -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
+6
View File
@@ -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
+1
View File
@@ -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);