Skip to content

Commit 4e6f551

Browse files
vsyrjalatursulin
authored andcommitted
drm/i915: Workaround broken BIOS DBUF configuration on TGL/RKL
On TGL/RKL the BIOS likes to use some kind of bogus DBUF layout that doesn't match what the spec recommends. With a single active pipe that is not going to be a problem, but with multiple pipes active skl_commit_modeset_enables() goes into an infinite loop since it can't figure out any order in which it can commit the pipes without causing DBUF overlaps between the planes. We'd need some kind of extra DBUF defrag stage in between to make the transition possible. But that is clearly way too complex a solution, so in the name of simplicity let's just sanitize the DBUF state by simply turning off all planes when we detect a pipe encroaching on its neighbours' DBUF slices. We only have to disable the primary planes as all other planes should have already been disabled (if they somehow were enabled) by earlier sanitization steps. And for good measure let's also sanitize in case the DBUF allocations of the pipes already seem to overlap each other. Cc: <[email protected]> # v5.14+ Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/4762 Signed-off-by: Ville Syrjälä <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Reviewed-by: Stanislav Lisovskiy <[email protected]> (cherry picked from commit 1551202) Signed-off-by: Tvrtko Ursulin <[email protected]>
1 parent 85bb289 commit 4e6f551

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

drivers/gpu/drm/i915/display/intel_display.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10673,6 +10673,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
1067310673
vlv_wm_sanitize(dev_priv);
1067410674
} else if (DISPLAY_VER(dev_priv) >= 9) {
1067510675
skl_wm_get_hw_state(dev_priv);
10676+
skl_wm_sanitize(dev_priv);
1067610677
} else if (HAS_PCH_SPLIT(dev_priv)) {
1067710678
ilk_wm_get_hw_state(dev_priv);
1067810679
}

drivers/gpu/drm/i915/intel_pm.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6698,6 +6698,74 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
66986698
dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices;
66996699
}
67006700

6701+
static bool skl_dbuf_is_misconfigured(struct drm_i915_private *i915)
6702+
{
6703+
const struct intel_dbuf_state *dbuf_state =
6704+
to_intel_dbuf_state(i915->dbuf.obj.state);
6705+
struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
6706+
struct intel_crtc *crtc;
6707+
6708+
for_each_intel_crtc(&i915->drm, crtc) {
6709+
const struct intel_crtc_state *crtc_state =
6710+
to_intel_crtc_state(crtc->base.state);
6711+
6712+
entries[crtc->pipe] = crtc_state->wm.skl.ddb;
6713+
}
6714+
6715+
for_each_intel_crtc(&i915->drm, crtc) {
6716+
const struct intel_crtc_state *crtc_state =
6717+
to_intel_crtc_state(crtc->base.state);
6718+
u8 slices;
6719+
6720+
slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes,
6721+
dbuf_state->joined_mbus);
6722+
if (dbuf_state->slices[crtc->pipe] & ~slices)
6723+
return true;
6724+
6725+
if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.ddb, entries,
6726+
I915_MAX_PIPES, crtc->pipe))
6727+
return true;
6728+
}
6729+
6730+
return false;
6731+
}
6732+
6733+
void skl_wm_sanitize(struct drm_i915_private *i915)
6734+
{
6735+
struct intel_crtc *crtc;
6736+
6737+
/*
6738+
* On TGL/RKL (at least) the BIOS likes to assign the planes
6739+
* to the wrong DBUF slices. This will cause an infinite loop
6740+
* in skl_commit_modeset_enables() as it can't find a way to
6741+
* transition between the old bogus DBUF layout to the new
6742+
* proper DBUF layout without DBUF allocation overlaps between
6743+
* the planes (which cannot be allowed or else the hardware
6744+
* may hang). If we detect a bogus DBUF layout just turn off
6745+
* all the planes so that skl_commit_modeset_enables() can
6746+
* simply ignore them.
6747+
*/
6748+
if (!skl_dbuf_is_misconfigured(i915))
6749+
return;
6750+
6751+
drm_dbg_kms(&i915->drm, "BIOS has misprogrammed the DBUF, disabling all planes\n");
6752+
6753+
for_each_intel_crtc(&i915->drm, crtc) {
6754+
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
6755+
const struct intel_plane_state *plane_state =
6756+
to_intel_plane_state(plane->base.state);
6757+
struct intel_crtc_state *crtc_state =
6758+
to_intel_crtc_state(crtc->base.state);
6759+
6760+
if (plane_state->uapi.visible)
6761+
intel_plane_disable_noatomic(crtc, plane);
6762+
6763+
drm_WARN_ON(&i915->drm, crtc_state->active_planes != 0);
6764+
6765+
memset(&crtc_state->wm.skl.ddb, 0, sizeof(crtc_state->wm.skl.ddb));
6766+
}
6767+
}
6768+
67016769
static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
67026770
{
67036771
struct drm_device *dev = crtc->base.dev;

drivers/gpu/drm/i915/intel_pm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
4747
struct skl_pipe_wm *out);
4848
void g4x_wm_sanitize(struct drm_i915_private *dev_priv);
4949
void vlv_wm_sanitize(struct drm_i915_private *dev_priv);
50+
void skl_wm_sanitize(struct drm_i915_private *dev_priv);
5051
bool intel_can_enable_sagv(struct drm_i915_private *dev_priv,
5152
const struct intel_bw_state *bw_state);
5253
void intel_sagv_pre_plane_update(struct intel_atomic_state *state);

0 commit comments

Comments
 (0)