[PATCH 30/58] drm/i915: read out the modeset hw state at load and resume time

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, 19 Aug 2012 21:12:47 +0200
Daniel Vetter <daniel.vetter at ffwll.ch> wrote:
> +static void
> +intel_connector_break_all_links(struct intel_connector *connector)
> +{
> +	connector->base.dpms = DRM_MODE_DPMS_OFF;
> +	connector->base.encoder = NULL;
> +	connector->encoder->connectors_active = false;
> +	connector->encoder->base.crtc = NULL;
> +}

Maybe connector_clear_state() or init_state()? instead?

> +
> +static void intel_sanitize_crtc(struct intel_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	u32 reg, val;
> +
> +	/* Clear the dpms state for compatibility with code still using that
> +	 * deprecated state variable. */
> +	crtc->dpms_mode = -1;
> +
> +	/* Clear any frame start delays used for debugging left by the BIOS */
> +	reg = PIPECONF(crtc->pipe);
> +	I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
> +
> +	/* We need to sanitize the plane -> pipe mapping first because this will
> +	 * disable the crtc (and hence change the state) if it is wrong. */
> +	if (!HAS_PCH_SPLIT(dev)) {
> +		struct intel_connector *connector;
> +		bool plane;
> +
> +		reg = DSPCNTR(crtc->plane);
> +		val = I915_READ(reg);
> +
> +		if ((val & DISPLAY_PLANE_ENABLE) == 0 &&
> +		    (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
> +			goto ok;
> +
> +		DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
> +			      crtc->base.base.id);
> +
> +		/* Pipe has the wrong plane attached and the plane is active.
> +		 * Temporarily change the plane mapping and disable everything
> +		 * ...  */
> +		plane = crtc->plane;
> +		crtc->plane = !plane;
> +		dev_priv->display.crtc_disable(&crtc->base);
> +		crtc->plane = plane;
> +
> +		/* ... and break all links. */
> +		list_for_each_entry(connector, &dev->mode_config.connector_list,
> +				    base.head) {
> +			if (connector->encoder->base.crtc != &crtc->base)
> +				continue;
> +
> +			intel_connector_break_all_links(connector);
> +		}
> +
> +		WARN_ON(crtc->active);
> +		crtc->base.enabled = false;
> +	}
> +ok:
> +
> +	/* Adjust the state of the output pipe according to whether we
> +	 * have active connectors/encoders. */
> +	intel_crtc_update_dpms(&crtc->base);
> +
> +	if (crtc->active != crtc->base.enabled) {
> +		struct intel_encoder *encoder;
> +
> +		/* This can happen either due to bugs in the get_hw_state
> +		 * functions or because the pipe is force-enabled due to the
> +		 * pipe A quirk. */
> +		DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
> +			      crtc->base.base.id,
> +			      crtc->base.enabled ? "enabled" : "disabled",
> +			      crtc->active ? "enabled" : "disabled");
> +
> +		crtc->base.enabled = crtc->active;
> +
> +		/* Because we only establish the connector -> encoder ->
> +		 * crtc links if something is active, this means the
> +		 * crtc is now deactivated. Break the links. connector
> +		 * -> encoder links are only establish when things are
> +		 *  actually up, hence no need to break them. */
> +		WARN_ON(crtc->active);
> +
> +		for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
> +			WARN_ON(encoder->connectors_active);
> +			encoder->base.crtc = NULL;
> +		}
> +	}
> +}
> +
> +static void intel_sanitize_encoder(struct intel_encoder *encoder)
> +{
> +	struct intel_connector *connector;
> +	struct drm_device *dev = encoder->base.dev;
> +
> +	/* We need to check both for a crtc link (meaning that the
> +	 * encoder is active and trying to read from a pipe) and the
> +	 * pipe itself being active. */
> +	bool has_active_crtc = encoder->base.crtc &&
> +		to_intel_crtc(encoder->base.crtc)->active;
> +
> +	if (encoder->connectors_active && !has_active_crtc) {
> +		DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
> +			      encoder->base.base.id,
> +			      drm_get_encoder_name(&encoder->base));
> +
> +		/* Connector is active, but has no active pipe. This is
> +		 * fallout from our resume register restoring. Disable
> +		 * the encoder manually again. */
> +		if (encoder->base.crtc) {
> +			DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
> +				      encoder->base.base.id,
> +				      drm_get_encoder_name(&encoder->base));
> +			encoder->disable(encoder);
> +		}
> +
> +		/* Inconsisten output/port/pipe state happens presumably due to
> +		 * a bug in one of the get_hw_state functions. Or someplace else
> +		 * in our code, like the register restore mess on resume. Clamp
> +		 * things to off as a safer default. */
> +		list_for_each_entry(connector,
> +				    &dev->mode_config.connector_list,
> +				    base.head) {
> +			if (connector->encoder != encoder)
> +				continue;
> +
> +			intel_connector_break_all_links(connector);
> +		}
> +	}
> +	/* Enabled encoders without active connectors will be fixed in
> +	 * the crtc fixup. */
> +}
> +
> +/* Scan out the current hw modeset state, sanitizes it and maps it into the drm
> + * and i915 state tracking structures. */
> +void intel_modeset_setup_hw_state(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	enum pipe pipe;
> +	u32 tmp;
> +	struct intel_crtc *crtc;
> +	struct intel_encoder *encoder;
> +	struct intel_connector *connector;
> +
> +	for_each_pipe(pipe) {
> +		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> +
> +		tmp = I915_READ(PIPECONF(pipe));
> +		if (tmp & PIPECONF_ENABLE)
> +			crtc->active = true;
> +		else
> +			crtc->active = false;
> +
> +		crtc->base.enabled = crtc->active;
> +
> +		DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
> +			      crtc->base.base.id,
> +			      crtc->active ? "enabled" : "disabled");
> +	}
> +
> +	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
> +			    base.head) {
> +		pipe = 0;
> +
> +		if (encoder->get_hw_state(encoder, &pipe)) {
> +			encoder->base.crtc =
> +				dev_priv->pipe_to_crtc_mapping[pipe];
> +		} else {
> +			encoder->base.crtc = NULL;
> +		}
> +
> +		encoder->connectors_active = false;
> +		DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe=%i\n",
> +			      encoder->base.base.id,
> +			      drm_get_encoder_name(&encoder->base),
> +			      encoder->base.crtc ? "enabled" : "disabled",
> +			      pipe);
> +	}
> +
> +	list_for_each_entry(connector, &dev->mode_config.connector_list,
> +			    base.head) {
> +		if (connector->get_hw_state(connector)) {
> +			connector->base.dpms = DRM_MODE_DPMS_ON;
> +			connector->encoder->connectors_active = true;
> +			connector->base.encoder = &connector->encoder->base;
> +		} else {
> +			connector->base.dpms = DRM_MODE_DPMS_OFF;
> +			connector->base.encoder = NULL;
> +		}
> +		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n",
> +			      connector->base.base.id,
> +			      drm_get_connector_name(&connector->base),
> +			      connector->base.encoder ? "enabled" : "disabled");
> +	}
> +
> +	/* HW state is read out, now we need to sanitize this mess. */
> +	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
> +			    base.head) {
> +		intel_sanitize_encoder(encoder);
> +	}
> +
> +	for_each_pipe(pipe) {
> +		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> +		intel_sanitize_crtc(crtc);
> +	}
> +}

I was going to suggest calling this fetch_hw_state or something, but it
really does do some sanitizing, so maybe setup_hw_state is ok...

Reviewed-by: Jesse Barnes <jbarnes at virtuousgeek.org>

-- 
Jesse Barnes, Intel Open Source Technology Center


[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux