[PATCH 10/14] drm/i915: cache crt edid

Daniel Vetter daniel.vetter at ffwll.ch
Thu May 24 12:26:45 PDT 2012


Let's put all this new&neat output detection infrastructure and rework
to some good use and cache the crt edid. Given that the drm helpers
now only call ->detect when actually required, we only need to reset
the edid there and can keep it otherwise.

Slashes xrandr time on systems that are hotplug capable if there's
something connected to the VGA connector.

v2: Remember to clean up the cached edid on destroy.

Signed-Off-by: Daniel Vetter <daniel.vetter at ffwll.ch>
---
 drivers/gpu/drm/i915/intel_crt.c   |   25 ++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_drv.h   |    1 +
 drivers/gpu/drm/i915/intel_modes.c |   18 ++++++++++++++----
 3 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index a60d131..46a0716 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -47,6 +47,7 @@
 struct intel_crt {
 	struct intel_encoder base;
 	bool force_hotplug_required;
+	struct edid *cached_edid;
 };
 
 static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
@@ -310,7 +311,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
 		if (edid != NULL) {
 			is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
 			connector->display_info.raw_edid = NULL;
-			kfree(edid);
+			crt->cached_edid = edid;
 		}
 
 		if (!is_digital) {
@@ -452,6 +453,10 @@ intel_crt_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status status;
 	struct intel_load_detect_pipe tmp;
 
+	/* Clean the edid cache. */
+	kfree(crt->cached_edid);
+	crt->cached_edid = NULL;
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		if (intel_crt_detect_hotplug(connector)) {
 			DRM_DEBUG_KMS("CRT detected via hotplug\n");
@@ -485,8 +490,11 @@ intel_crt_detect(struct drm_connector *connector, bool force)
 
 static void intel_crt_destroy(struct drm_connector *connector)
 {
+	struct intel_crt *crt = intel_attached_crt(connector);
+
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
+	kfree(crt->cached_edid);
 	kfree(connector);
 }
 
@@ -494,17 +502,24 @@ static int intel_crt_get_modes(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int ret;
+	struct intel_crt *crt = intel_attached_crt(connector);
+	int ret = 0;
 	struct i2c_adapter *i2c;
 
-	i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
-	ret = intel_ddc_get_modes(connector, i2c);
+	if (!crt->cached_edid) {
+		i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+		crt->cached_edid = drm_get_edid(connector, i2c);
+	}
+
+	ret = intel_edid_get_modes(connector, crt->cached_edid);
 	if (ret || !IS_G4X(dev))
 		return ret;
 
 	/* Try to probe digital port for output in DVI-I -> VGA mode. */
 	i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
-	return intel_ddc_get_modes(connector, i2c);
+	kfree(crt->cached_edid);
+	crt->cached_edid = drm_get_edid(connector, i2c);
+	return intel_edid_get_modes(connector, crt->cached_edid);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3e09188..3b6f716 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -335,6 +335,7 @@ struct intel_fbc_work {
 };
 
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
+int intel_edid_get_modes(struct drm_connector *connector, struct edid *edid);
 extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
 extern void intel_attach_force_audio_property(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index d67ec3a..6c723d9 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -60,6 +60,19 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
 			    msgs, 2) == 2;
 }
 
+int intel_edid_get_modes(struct drm_connector *connector,
+			 struct edid *edid)
+{
+	int ret;
+
+	drm_mode_connector_update_edid_property(connector, edid);
+	ret = drm_add_edid_modes(connector, edid);
+	drm_edid_to_eld(connector, edid);
+	connector->display_info.raw_edid = NULL;
+
+	return ret;
+}
+
 /**
  * intel_ddc_get_modes - get modelist from monitor
  * @connector: DRM connector device to use
@@ -75,10 +88,7 @@ int intel_ddc_get_modes(struct drm_connector *connector,
 
 	edid = drm_get_edid(connector, adapter);
 	if (edid) {
-		drm_mode_connector_update_edid_property(connector, edid);
-		ret = drm_add_edid_modes(connector, edid);
-		drm_edid_to_eld(connector, edid);
-		connector->display_info.raw_edid = NULL;
+		intel_edid_get_modes(connector, edid);
 		kfree(edid);
 	}
 
-- 
1.7.7.6



More information about the dri-devel mailing list