diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3533609..e283355 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -598,6 +598,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
 		drm_mode_remove(connector, mode);
 
 	mutex_lock(&dev->mode_config.mutex);
+	drm_cache_edid(connector, NULL);
 	drm_mode_object_put(dev, &connector->base);
 	list_del(&connector->head);
 	dev->mode_config.num_connector--;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a47fa7f..28b877c 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -419,6 +419,38 @@ fixup_edid(u8 **blockp, int valid_extensions)
 	}
 }
 
+static bool
+compare_get_edid_from_cache(struct drm_connector *connector, struct edid **edidp)
+{
+	if (connector->edid_cache &&
+	    connector->edid_cache->prod_code[0] == (*edidp)->prod_code[0] &&
+	    connector->edid_cache->prod_code[1] == (*edidp)->prod_code[1] &&
+	    connector->edid_cache->serial == (*edidp)->serial &&
+	    connector->edid_cache->input == (*edidp)->input) {
+		int size = (connector->edid_cache->extensions + 1) * EDID_LENGTH;
+		struct edid *new = kmemdup(connector->edid_cache, size, GFP_KERNEL);
+		if (!new)
+			return false;
+		DRM_DEBUG_KMS("Got EDID for %s from cache.\n", drm_get_connector_name(connector));
+		kfree(*edidp);
+		*edidp = new;
+		return true;
+	}
+	return false;
+}
+
+void
+drm_cache_edid(struct drm_connector *connector, struct edid *edid)
+{
+	struct edid *new = NULL;
+	kfree(connector->edid_cache);
+	if (edid) {
+		int size = (edid->extensions + 1) * EDID_LENGTH;
+		new = kmemdup(edid, size, GFP_KERNEL);
+	}
+	connector->edid_cache = new;
+}
+
 static u8 *
 drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
@@ -429,28 +461,30 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
 	/* check if the user has specified a 'firmware' EDID file */
 	block = (u8 *)drm_load_edid_firmware(connector);
-	if (block)
+	if (block) {
+		drm_cache_edid(connector, NULL);
 		return block;
+	}
 #endif
 
 	if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
-		return NULL;
+		goto error;
 
 	/* base block fetch */
 	for (i = 0; i < 4; i++) {
 		if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
-			goto out;
+			goto error_free;
 		if (drm_edid_block_valid(block, 0, print_bad_edid))
 			break;
 		if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
 			connector->null_edid_counter++;
-			goto carp;
+			goto error_carp;
 		}
 	}
 	if (i == 4)
-		goto carp;
+		goto error_carp;
 
-	/* if there's no extensions, we're done */
+	/* if there are no extensions, we're done - don't bother caching */
 	if (block[EDID_EXTENSION_FLAG_OFFSET] == 0)
 		return block;
 
@@ -458,6 +492,10 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 	if (block[EDID_VERSION_MINOR_OFFSET] < 3)
 		goto done_fix_extension_count;
 
+	/* see if EDID is in the cache - no need to read all extension blocks */
+	if (compare_get_edid_from_cache(connector, (struct edid **)&block))
+		return block;
+
 	new = krealloc(block, (block[EDID_EXTENSION_FLAG_OFFSET] + 1) * EDID_LENGTH, GFP_KERNEL);
 	if (!new) {
 		dev_warn(connector->dev->dev, "%s: cannot allocate memory for %d EDID blocks: truncating.\n",
@@ -500,18 +538,21 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 
 done_fix_extension_count:
 	fixup_edid(&block, valid_extensions);
+	drm_cache_edid(connector, (valid_extensions > 0) ? (struct edid *)block : NULL);
 
 	return block;
 
-carp:
+error_carp:
 	if (print_bad_edid) {
 		dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
 			 drm_get_connector_name(connector), j);
 	}
 	connector->bad_edid_counter++;
 
-out:
+error_free:
 	kfree(block);
+error:
+	drm_cache_edid(connector, NULL);
 	return NULL;
 }
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 49dd8c2..6a1054c 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -601,6 +601,7 @@ struct drm_connector {
 	struct drm_encoder *encoder; /* currently active encoder */
 
 	/* EDID bits */
+	struct edid *edid_cache;
 	uint8_t eld[MAX_ELD_BYTES];
 	bool dvi_dual;
 	int max_tmds_clock;	/* in MHz */
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 53c619c..c880510 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -256,5 +256,6 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
 struct edid *drm_load_edid_firmware(struct drm_connector *connector);
 #endif
 int drm_validate_edid_blob(struct drm_connector *connector, u8 **blockp, int len);
+void drm_cache_edid(struct drm_connector *connector, struct edid *edid);
 
 #endif /* __DRM_EDID_H__ */
