Skip to content

Commit 2492935

Browse files
committed
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work out. To properly disable the output pipelines at the initial modeset after resume or boot up we need to have an accurate picture of which outputs are enabled and connected to which crtcs. Otherwise we risk disabling things at the wrong time, which can lead to hangs (or at least royally confused panels), both requiring a walk to the reset button to fix. Hence read out the hw state with the freshly introduce get_hw_state functions and then sanitize it afterwards. For a full modeset readout (which would allow us to avoid the initial modeset at boot up) a few things are still missing: - Reading out the mode from the pipe, especially the dotclock computation is quite some fun. - Reading out the parameters for the stolen memory framebuffer and wrapping it up. - Reading out the pch pll connections - luckily the disable code simply bails out if the crtc doesn't have a pch pll attached (even for configurations that would need one). This patch here turned up tons of smelly stuff around resume: We restore tons of register in seemingly random way (well, not quite, but we're not too careful either), which leaves the hw in a rather ill-defined state: E.g. the port registers are sometimes unconditionally restore (lvds, crt), leaving us with an active encoder/connector but no active pipe connected to it. Luckily the hw state sanitizer detects this madness and fixes things up a bit. v2: When checking whether an encoder with active connectors has a crtc wire up to it, check for both the crtc _and_ it's active state. v3: - Extract intel_sanitize_encoder. - Manually disable active encoders without an active pipe. v4: Correclty fix up the pipe<->plane mapping on machines where we switch pipes/planes. Noticed by Chris Wilson, who also provided the fixup. v5: Spelling fix in a comment, noticed by Paulo Zanoni Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent 732ce74 commit 2492935

File tree

3 files changed

+214
-66
lines changed

3 files changed

+214
-66
lines changed

drivers/gpu/drm/i915/i915_drv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ static int i915_drm_thaw(struct drm_device *dev)
543543
mutex_unlock(&dev->struct_mutex);
544544

545545
intel_modeset_init_hw(dev);
546+
intel_modeset_setup_hw_state(dev);
546547
drm_mode_config_reset(dev);
547548
drm_irq_install(dev);
548549

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,7 @@ extern void intel_modeset_init(struct drm_device *dev);
15391539
extern void intel_modeset_gem_init(struct drm_device *dev);
15401540
extern void intel_modeset_cleanup(struct drm_device *dev);
15411541
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
1542+
extern void intel_modeset_setup_hw_state(struct drm_device *dev);
15421543
extern bool intel_fbc_enabled(struct drm_device *dev);
15431544
extern void intel_disable_fbc(struct drm_device *dev);
15441545
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);

drivers/gpu/drm/i915/intel_display.c

Lines changed: 212 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3589,7 +3589,7 @@ void intel_connector_dpms(struct drm_connector *connector, int mode)
35893589
* of the connector. */
35903590
bool intel_connector_get_hw_state(struct intel_connector *connector)
35913591
{
3592-
enum pipe pipe;
3592+
enum pipe pipe = 0;
35933593
struct intel_encoder *encoder = connector->encoder;
35943594

35953595
return encoder->get_hw_state(encoder, &pipe);
@@ -6533,65 +6533,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
65336533
return ret;
65346534
}
65356535

6536-
static void intel_sanitize_modesetting(struct drm_device *dev,
6537-
int pipe, int plane)
6538-
{
6539-
struct drm_i915_private *dev_priv = dev->dev_private;
6540-
u32 reg, val;
6541-
int i;
6542-
6543-
/* Clear any frame start delays used for debugging left by the BIOS */
6544-
for_each_pipe(i) {
6545-
reg = PIPECONF(i);
6546-
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
6547-
}
6548-
6549-
if (HAS_PCH_SPLIT(dev))
6550-
return;
6551-
6552-
/* Who knows what state these registers were left in by the BIOS or
6553-
* grub?
6554-
*
6555-
* If we leave the registers in a conflicting state (e.g. with the
6556-
* display plane reading from the other pipe than the one we intend
6557-
* to use) then when we attempt to teardown the active mode, we will
6558-
* not disable the pipes and planes in the correct order -- leaving
6559-
* a plane reading from a disabled pipe and possibly leading to
6560-
* undefined behaviour.
6561-
*/
6562-
6563-
reg = DSPCNTR(plane);
6564-
val = I915_READ(reg);
6565-
6566-
if ((val & DISPLAY_PLANE_ENABLE) == 0)
6567-
return;
6568-
if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
6569-
return;
6570-
6571-
/* This display plane is active and attached to the other CPU pipe. */
6572-
pipe = !pipe;
6573-
6574-
/* Disable the plane and wait for it to stop reading from the pipe. */
6575-
intel_disable_plane(dev_priv, plane, pipe);
6576-
intel_disable_pipe(dev_priv, pipe);
6577-
}
6578-
6579-
static void intel_crtc_reset(struct drm_crtc *crtc)
6580-
{
6581-
struct drm_device *dev = crtc->dev;
6582-
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
6583-
6584-
/* Reset flags back to the 'unknown' status so that they
6585-
* will be correctly set on the initial modeset.
6586-
*/
6587-
intel_crtc->dpms_mode = -1;
6588-
6589-
/* We need to fix up any BIOS configuration that conflicts with
6590-
* our expectations.
6591-
*/
6592-
intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
6593-
}
6594-
65956536
static struct drm_crtc_helper_funcs intel_helper_funcs = {
65966537
.mode_set_base_atomic = intel_pipe_set_base_atomic,
65976538
.load_lut = intel_crtc_load_lut,
@@ -7006,7 +6947,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
70066947
}
70076948

70086949
static const struct drm_crtc_funcs intel_crtc_funcs = {
7009-
.reset = intel_crtc_reset,
70106950
.cursor_set = intel_crtc_cursor_set,
70116951
.cursor_move = intel_crtc_cursor_move,
70126952
.gamma_set = intel_crtc_gamma_set,
@@ -7064,8 +7004,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
70647004
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
70657005
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
70667006

7067-
intel_crtc_reset(&intel_crtc->base);
7068-
intel_crtc->active = true; /* force the pipe off on setup_init_config */
70697007
intel_crtc->bpp = 24; /* default for pre-Ironlake */
70707008

70717009
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
@@ -7273,9 +7211,6 @@ static void intel_setup_outputs(struct drm_device *dev)
72737211
intel_encoder_clones(encoder);
72747212
}
72757213

7276-
/* disable all the possible outputs/crtcs before entering KMS mode */
7277-
drm_helper_disable_unused_functions(dev);
7278-
72797214
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
72807215
ironlake_init_pch_refclk(dev);
72817216
}
@@ -7634,11 +7569,222 @@ void intel_modeset_init(struct drm_device *dev)
76347569
intel_setup_outputs(dev);
76357570
}
76367571

7572+
static void
7573+
intel_connector_break_all_links(struct intel_connector *connector)
7574+
{
7575+
connector->base.dpms = DRM_MODE_DPMS_OFF;
7576+
connector->base.encoder = NULL;
7577+
connector->encoder->connectors_active = false;
7578+
connector->encoder->base.crtc = NULL;
7579+
}
7580+
7581+
static void intel_sanitize_crtc(struct intel_crtc *crtc)
7582+
{
7583+
struct drm_device *dev = crtc->base.dev;
7584+
struct drm_i915_private *dev_priv = dev->dev_private;
7585+
u32 reg, val;
7586+
7587+
/* Clear the dpms state for compatibility with code still using that
7588+
* deprecated state variable. */
7589+
crtc->dpms_mode = -1;
7590+
7591+
/* Clear any frame start delays used for debugging left by the BIOS */
7592+
reg = PIPECONF(crtc->pipe);
7593+
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
7594+
7595+
/* We need to sanitize the plane -> pipe mapping first because this will
7596+
* disable the crtc (and hence change the state) if it is wrong. */
7597+
if (!HAS_PCH_SPLIT(dev)) {
7598+
struct intel_connector *connector;
7599+
bool plane;
7600+
7601+
reg = DSPCNTR(crtc->plane);
7602+
val = I915_READ(reg);
7603+
7604+
if ((val & DISPLAY_PLANE_ENABLE) == 0 &&
7605+
(!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
7606+
goto ok;
7607+
7608+
DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
7609+
crtc->base.base.id);
7610+
7611+
/* Pipe has the wrong plane attached and the plane is active.
7612+
* Temporarily change the plane mapping and disable everything
7613+
* ... */
7614+
plane = crtc->plane;
7615+
crtc->plane = !plane;
7616+
dev_priv->display.crtc_disable(&crtc->base);
7617+
crtc->plane = plane;
7618+
7619+
/* ... and break all links. */
7620+
list_for_each_entry(connector, &dev->mode_config.connector_list,
7621+
base.head) {
7622+
if (connector->encoder->base.crtc != &crtc->base)
7623+
continue;
7624+
7625+
intel_connector_break_all_links(connector);
7626+
}
7627+
7628+
WARN_ON(crtc->active);
7629+
crtc->base.enabled = false;
7630+
}
7631+
ok:
7632+
7633+
/* Adjust the state of the output pipe according to whether we
7634+
* have active connectors/encoders. */
7635+
intel_crtc_update_dpms(&crtc->base);
7636+
7637+
if (crtc->active != crtc->base.enabled) {
7638+
struct intel_encoder *encoder;
7639+
7640+
/* This can happen either due to bugs in the get_hw_state
7641+
* functions or because the pipe is force-enabled due to the
7642+
* pipe A quirk. */
7643+
DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
7644+
crtc->base.base.id,
7645+
crtc->base.enabled ? "enabled" : "disabled",
7646+
crtc->active ? "enabled" : "disabled");
7647+
7648+
crtc->base.enabled = crtc->active;
7649+
7650+
/* Because we only establish the connector -> encoder ->
7651+
* crtc links if something is active, this means the
7652+
* crtc is now deactivated. Break the links. connector
7653+
* -> encoder links are only establish when things are
7654+
* actually up, hence no need to break them. */
7655+
WARN_ON(crtc->active);
7656+
7657+
for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
7658+
WARN_ON(encoder->connectors_active);
7659+
encoder->base.crtc = NULL;
7660+
}
7661+
}
7662+
}
7663+
7664+
static void intel_sanitize_encoder(struct intel_encoder *encoder)
7665+
{
7666+
struct intel_connector *connector;
7667+
struct drm_device *dev = encoder->base.dev;
7668+
7669+
/* We need to check both for a crtc link (meaning that the
7670+
* encoder is active and trying to read from a pipe) and the
7671+
* pipe itself being active. */
7672+
bool has_active_crtc = encoder->base.crtc &&
7673+
to_intel_crtc(encoder->base.crtc)->active;
7674+
7675+
if (encoder->connectors_active && !has_active_crtc) {
7676+
DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
7677+
encoder->base.base.id,
7678+
drm_get_encoder_name(&encoder->base));
7679+
7680+
/* Connector is active, but has no active pipe. This is
7681+
* fallout from our resume register restoring. Disable
7682+
* the encoder manually again. */
7683+
if (encoder->base.crtc) {
7684+
DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
7685+
encoder->base.base.id,
7686+
drm_get_encoder_name(&encoder->base));
7687+
encoder->disable(encoder);
7688+
}
7689+
7690+
/* Inconsistent output/port/pipe state happens presumably due to
7691+
* a bug in one of the get_hw_state functions. Or someplace else
7692+
* in our code, like the register restore mess on resume. Clamp
7693+
* things to off as a safer default. */
7694+
list_for_each_entry(connector,
7695+
&dev->mode_config.connector_list,
7696+
base.head) {
7697+
if (connector->encoder != encoder)
7698+
continue;
7699+
7700+
intel_connector_break_all_links(connector);
7701+
}
7702+
}
7703+
/* Enabled encoders without active connectors will be fixed in
7704+
* the crtc fixup. */
7705+
}
7706+
7707+
/* Scan out the current hw modeset state, sanitizes it and maps it into the drm
7708+
* and i915 state tracking structures. */
7709+
void intel_modeset_setup_hw_state(struct drm_device *dev)
7710+
{
7711+
struct drm_i915_private *dev_priv = dev->dev_private;
7712+
enum pipe pipe;
7713+
u32 tmp;
7714+
struct intel_crtc *crtc;
7715+
struct intel_encoder *encoder;
7716+
struct intel_connector *connector;
7717+
7718+
for_each_pipe(pipe) {
7719+
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
7720+
7721+
tmp = I915_READ(PIPECONF(pipe));
7722+
if (tmp & PIPECONF_ENABLE)
7723+
crtc->active = true;
7724+
else
7725+
crtc->active = false;
7726+
7727+
crtc->base.enabled = crtc->active;
7728+
7729+
DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
7730+
crtc->base.base.id,
7731+
crtc->active ? "enabled" : "disabled");
7732+
}
7733+
7734+
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
7735+
base.head) {
7736+
pipe = 0;
7737+
7738+
if (encoder->get_hw_state(encoder, &pipe)) {
7739+
encoder->base.crtc =
7740+
dev_priv->pipe_to_crtc_mapping[pipe];
7741+
} else {
7742+
encoder->base.crtc = NULL;
7743+
}
7744+
7745+
encoder->connectors_active = false;
7746+
DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe=%i\n",
7747+
encoder->base.base.id,
7748+
drm_get_encoder_name(&encoder->base),
7749+
encoder->base.crtc ? "enabled" : "disabled",
7750+
pipe);
7751+
}
7752+
7753+
list_for_each_entry(connector, &dev->mode_config.connector_list,
7754+
base.head) {
7755+
if (connector->get_hw_state(connector)) {
7756+
connector->base.dpms = DRM_MODE_DPMS_ON;
7757+
connector->encoder->connectors_active = true;
7758+
connector->base.encoder = &connector->encoder->base;
7759+
} else {
7760+
connector->base.dpms = DRM_MODE_DPMS_OFF;
7761+
connector->base.encoder = NULL;
7762+
}
7763+
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n",
7764+
connector->base.base.id,
7765+
drm_get_connector_name(&connector->base),
7766+
connector->base.encoder ? "enabled" : "disabled");
7767+
}
7768+
7769+
/* HW state is read out, now we need to sanitize this mess. */
7770+
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
7771+
base.head) {
7772+
intel_sanitize_encoder(encoder);
7773+
}
7774+
7775+
for_each_pipe(pipe) {
7776+
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
7777+
intel_sanitize_crtc(crtc);
7778+
}
7779+
}
7780+
76377781
void intel_modeset_gem_init(struct drm_device *dev)
76387782
{
76397783
intel_modeset_init_hw(dev);
76407784

76417785
intel_setup_overlay(dev);
7786+
7787+
intel_modeset_setup_hw_state(dev);
76427788
}
76437789

76447790
void intel_modeset_cleanup(struct drm_device *dev)

0 commit comments

Comments
 (0)