mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
Merge tag 'drm-intel-fixes-2026-03-12' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-fixes
- Avoid hang when configuring VRR [icl] (Ville Syrjälä) - Fix sg_table overflow with >4GB folios (Janusz Krzysztofik) - Fix PSR Selective Update handling [psr] (Jouni Högander) - Fix eDP ALPM read-out sequence [dp] (Arun R Murthy) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Tvrtko Ursulin <tursulin@igalia.com> Link: https://patch.msgid.link/abJ_MQ7o-5ghyaNW@linux
This commit is contained in:
@@ -43,12 +43,6 @@ bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp,
|
||||
|
||||
void intel_alpm_init(struct intel_dp *intel_dp)
|
||||
{
|
||||
u8 dpcd;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_RECEIVER_ALPM_CAP, &dpcd) < 0)
|
||||
return;
|
||||
|
||||
intel_dp->alpm_dpcd = dpcd;
|
||||
mutex_init(&intel_dp->alpm.lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -1614,7 +1614,6 @@ static void hsw_configure_cpu_transcoder(const struct intel_crtc_state *crtc_sta
|
||||
}
|
||||
|
||||
intel_set_transcoder_timings(crtc_state);
|
||||
intel_vrr_set_transcoder_timings(crtc_state);
|
||||
|
||||
if (cpu_transcoder != TRANSCODER_EDP)
|
||||
intel_de_write(display, TRANS_MULT(display, cpu_transcoder),
|
||||
|
||||
@@ -4577,6 +4577,7 @@ static bool
|
||||
intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
int ret;
|
||||
|
||||
/* this function is meant to be called only once */
|
||||
drm_WARN_ON(display->drm, intel_dp->dpcd[DP_DPCD_REV] != 0);
|
||||
@@ -4616,6 +4617,12 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
|
||||
*/
|
||||
intel_dp_init_source_oui(intel_dp);
|
||||
|
||||
/* Read the ALPM DPCD caps */
|
||||
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_RECEIVER_ALPM_CAP,
|
||||
&intel_dp->alpm_dpcd);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* This has to be called after intel_dp->edp_dpcd is filled, PSR checks
|
||||
* for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1]
|
||||
|
||||
@@ -2619,6 +2619,12 @@ void intel_psr2_program_trans_man_trk_ctl(struct intel_dsb *dsb,
|
||||
|
||||
intel_de_write_dsb(display, dsb, PIPE_SRCSZ_ERLY_TPT(crtc->pipe),
|
||||
crtc_state->pipe_srcsz_early_tpt);
|
||||
|
||||
if (!crtc_state->dsc.compression_enable)
|
||||
return;
|
||||
|
||||
intel_dsc_su_et_parameters_configure(dsb, encoder, crtc_state,
|
||||
drm_rect_height(&crtc_state->psr2_su_area));
|
||||
}
|
||||
|
||||
static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
|
||||
@@ -2689,11 +2695,12 @@ static void clip_area_update(struct drm_rect *overlap_damage_area,
|
||||
overlap_damage_area->y2 = damage_area->y2;
|
||||
}
|
||||
|
||||
static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state)
|
||||
static bool intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
|
||||
u16 y_alignment;
|
||||
bool su_area_changed = false;
|
||||
|
||||
/* ADLP aligns the SU region to vdsc slice height in case dsc is enabled */
|
||||
if (crtc_state->dsc.compression_enable &&
|
||||
@@ -2702,10 +2709,18 @@ static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_st
|
||||
else
|
||||
y_alignment = crtc_state->su_y_granularity;
|
||||
|
||||
crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment;
|
||||
if (crtc_state->psr2_su_area.y2 % y_alignment)
|
||||
if (crtc_state->psr2_su_area.y1 % y_alignment) {
|
||||
crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment;
|
||||
su_area_changed = true;
|
||||
}
|
||||
|
||||
if (crtc_state->psr2_su_area.y2 % y_alignment) {
|
||||
crtc_state->psr2_su_area.y2 = ((crtc_state->psr2_su_area.y2 /
|
||||
y_alignment) + 1) * y_alignment;
|
||||
su_area_changed = true;
|
||||
}
|
||||
|
||||
return su_area_changed;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2839,7 +2854,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
|
||||
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
|
||||
struct intel_plane_state *new_plane_state, *old_plane_state;
|
||||
struct intel_plane *plane;
|
||||
bool full_update = false, cursor_in_su_area = false;
|
||||
bool full_update = false, su_area_changed;
|
||||
int i, ret;
|
||||
|
||||
if (!crtc_state->enable_psr2_sel_fetch)
|
||||
@@ -2946,15 +2961,32 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Adjust su area to cover cursor fully as necessary (early
|
||||
* transport). This needs to be done after
|
||||
* drm_atomic_add_affected_planes to ensure visible cursor is added into
|
||||
* affected planes even when cursor is not updated by itself.
|
||||
*/
|
||||
intel_psr2_sel_fetch_et_alignment(state, crtc, &cursor_in_su_area);
|
||||
do {
|
||||
bool cursor_in_su_area;
|
||||
|
||||
intel_psr2_sel_fetch_pipe_alignment(crtc_state);
|
||||
/*
|
||||
* Adjust su area to cover cursor fully as necessary
|
||||
* (early transport). This needs to be done after
|
||||
* drm_atomic_add_affected_planes to ensure visible
|
||||
* cursor is added into affected planes even when
|
||||
* cursor is not updated by itself.
|
||||
*/
|
||||
intel_psr2_sel_fetch_et_alignment(state, crtc, &cursor_in_su_area);
|
||||
|
||||
su_area_changed = intel_psr2_sel_fetch_pipe_alignment(crtc_state);
|
||||
|
||||
/*
|
||||
* If the cursor was outside the SU area before
|
||||
* alignment, the alignment step (which only expands
|
||||
* SU) may pull the cursor partially inside, so we
|
||||
* must run ET alignment again to fully cover it. But
|
||||
* if the cursor was already fully inside before
|
||||
* alignment, expanding the SU area won't change that,
|
||||
* so no further work is needed.
|
||||
*/
|
||||
if (cursor_in_su_area)
|
||||
break;
|
||||
} while (su_area_changed);
|
||||
|
||||
/*
|
||||
* Now that we have the pipe damaged area check if it intersect with
|
||||
@@ -3014,6 +3046,10 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
|
||||
}
|
||||
|
||||
skip_sel_fetch_set_loop:
|
||||
if (full_update)
|
||||
clip_area_update(&crtc_state->psr2_su_area, &crtc_state->pipe_src,
|
||||
&crtc_state->pipe_src);
|
||||
|
||||
psr2_man_trk_ctl_calc(crtc_state, full_update);
|
||||
crtc_state->pipe_srcsz_early_tpt =
|
||||
psr2_pipe_srcsz_early_tpt_calc(crtc_state, full_update);
|
||||
|
||||
@@ -767,6 +767,29 @@ void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
|
||||
sizeof(dp_dsc_pps_sdp));
|
||||
}
|
||||
|
||||
void intel_dsc_su_et_parameters_configure(struct intel_dsb *dsb, struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state, int su_lines)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
|
||||
enum pipe pipe = crtc->pipe;
|
||||
int vdsc_instances_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state);
|
||||
int slice_row_per_frame = su_lines / vdsc_cfg->slice_height;
|
||||
u32 val;
|
||||
|
||||
drm_WARN_ON_ONCE(display->drm, su_lines % vdsc_cfg->slice_height);
|
||||
drm_WARN_ON_ONCE(display->drm, vdsc_instances_per_pipe > 2);
|
||||
|
||||
val = DSC_SUPS0_SU_SLICE_ROW_PER_FRAME(slice_row_per_frame);
|
||||
val |= DSC_SUPS0_SU_PIC_HEIGHT(su_lines);
|
||||
|
||||
intel_de_write_dsb(display, dsb, LNL_DSC0_SU_PARAMETER_SET_0(pipe), val);
|
||||
|
||||
if (vdsc_instances_per_pipe == 2)
|
||||
intel_de_write_dsb(display, dsb, LNL_DSC1_SU_PARAMETER_SET_0(pipe), val);
|
||||
}
|
||||
|
||||
static i915_reg_t dss_ctl1_reg(struct intel_crtc *crtc, enum transcoder cpu_transcoder)
|
||||
{
|
||||
return is_pipe_dsc(crtc, cpu_transcoder) ?
|
||||
|
||||
@@ -13,6 +13,7 @@ struct drm_printer;
|
||||
enum transcoder;
|
||||
struct intel_crtc;
|
||||
struct intel_crtc_state;
|
||||
struct intel_dsb;
|
||||
struct intel_encoder;
|
||||
|
||||
bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state);
|
||||
@@ -31,6 +32,8 @@ void intel_dsc_dsi_pps_write(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_dsc_su_et_parameters_configure(struct intel_dsb *dsb, struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state, int su_lines);
|
||||
void intel_vdsc_state_dump(struct drm_printer *p, int indent,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state);
|
||||
|
||||
@@ -196,6 +196,18 @@
|
||||
#define DSC_PPS18_NSL_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS18_NSL_BPG_OFFSET_MASK, offset)
|
||||
#define DSC_PPS18_SL_OFFSET_ADJ(offset) REG_FIELD_PREP(DSC_PPS18_SL_OFFSET_ADJ_MASK, offset)
|
||||
|
||||
#define _LNL_DSC0_SU_PARAMETER_SET_0_PA 0x78064
|
||||
#define _LNL_DSC1_SU_PARAMETER_SET_0_PA 0x78164
|
||||
#define _LNL_DSC0_SU_PARAMETER_SET_0_PB 0x78264
|
||||
#define _LNL_DSC1_SU_PARAMETER_SET_0_PB 0x78364
|
||||
#define LNL_DSC0_SU_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe), _LNL_DSC0_SU_PARAMETER_SET_0_PA, _LNL_DSC0_SU_PARAMETER_SET_0_PB)
|
||||
#define LNL_DSC1_SU_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe), _LNL_DSC1_SU_PARAMETER_SET_0_PA, _LNL_DSC1_SU_PARAMETER_SET_0_PB)
|
||||
|
||||
#define DSC_SUPS0_SU_SLICE_ROW_PER_FRAME_MASK REG_GENMASK(31, 20)
|
||||
#define DSC_SUPS0_SU_SLICE_ROW_PER_FRAME(rows) REG_FIELD_PREP(DSC_SUPS0_SU_SLICE_ROW_PER_FRAME_MASK, (rows))
|
||||
#define DSC_SUPS0_SU_PIC_HEIGHT_MASK REG_GENMASK(15, 0)
|
||||
#define DSC_SUPS0_SU_PIC_HEIGHT(h) REG_FIELD_PREP(DSC_SUPS0_SU_PIC_HEIGHT_MASK, (h))
|
||||
|
||||
/* Icelake Rate Control Buffer Threshold Registers */
|
||||
#define DSCA_RC_BUF_THRESH_0 _MMIO(0x6B230)
|
||||
#define DSCA_RC_BUF_THRESH_0_UDW _MMIO(0x6B230 + 4)
|
||||
|
||||
@@ -597,6 +597,18 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
|
||||
if (!HAS_VRR(display))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Bspec says:
|
||||
* "(note: VRR needs to be programmed after
|
||||
* TRANS_DDI_FUNC_CTL and before TRANS_CONF)."
|
||||
*
|
||||
* In practice it turns out that ICL can hang if
|
||||
* TRANS_VRR_VMAX/FLIPLINE are written before
|
||||
* enabling TRANS_DDI_FUNC_CTL.
|
||||
*/
|
||||
drm_WARN_ON(display->drm,
|
||||
!(intel_de_read(display, TRANS_DDI_FUNC_CTL(display, cpu_transcoder)) & TRANS_DDI_FUNC_ENABLE));
|
||||
|
||||
/*
|
||||
* This bit seems to have two meanings depending on the platform:
|
||||
* TGL: generate VRR "safe window" for DSB vblank waits
|
||||
@@ -939,6 +951,8 @@ void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
|
||||
intel_vrr_set_transcoder_timings(crtc_state);
|
||||
|
||||
if (!intel_vrr_possible(crtc_state))
|
||||
return;
|
||||
|
||||
|
||||
@@ -153,8 +153,12 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
|
||||
}
|
||||
} while (1);
|
||||
|
||||
nr_pages = min_t(unsigned long,
|
||||
folio_nr_pages(folio), page_count - i);
|
||||
nr_pages = min_array(((unsigned long[]) {
|
||||
folio_nr_pages(folio),
|
||||
page_count - i,
|
||||
max_segment / PAGE_SIZE,
|
||||
}), 3);
|
||||
|
||||
if (!i ||
|
||||
sg->length >= max_segment ||
|
||||
folio_pfn(folio) != next_pfn) {
|
||||
@@ -164,7 +168,9 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
|
||||
st->nents++;
|
||||
sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0);
|
||||
} else {
|
||||
/* XXX: could overflow? */
|
||||
nr_pages = min_t(unsigned long, nr_pages,
|
||||
(max_segment - sg->length) / PAGE_SIZE);
|
||||
|
||||
sg->length += nr_pages * PAGE_SIZE;
|
||||
}
|
||||
next_pfn = folio_pfn(folio) + nr_pages;
|
||||
|
||||
Reference in New Issue
Block a user