diff mbox

[RFC,18/37] DRM: CRTC: Use pointer for display mode

Message ID 1426739616-10635-18-git-send-email-daniels@collabora.com (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Stone March 19, 2015, 4:33 a.m. UTC
Holding a pointer to the mode, rather than an embed, allows us to get
towards sharing refcounted modes.

XXX: split into two - drm_mode_copy changes first, then the others

Signed-off-by: Daniel Stone <daniels@collabora.com>
---
 drivers/gpu/drm/armada/armada_overlay.c        |  4 +--
 drivers/gpu/drm/ast/ast_mode.c                 |  8 ++---
 drivers/gpu/drm/drm_atomic_helper.c            | 47 +++++++++++++++-----------
 drivers/gpu/drm/drm_crtc.c                     | 11 ++++--
 drivers/gpu/drm/drm_crtc_helper.c              | 34 ++++++++++++-------
 drivers/gpu/drm/drm_plane_helper.c             |  6 ++--
 drivers/gpu/drm/i2c/sil164_drv.c               |  2 +-
 drivers/gpu/drm/i915/intel_atomic.c            | 26 ++++++--------
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c       |  4 +--
 drivers/gpu/drm/nouveau/dispnv04/crtc.c        |  2 +-
 drivers/gpu/drm/nouveau/dispnv04/cursor.c      |  2 +-
 drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c |  4 +--
 drivers/gpu/drm/nouveau/nouveau_connector.c    |  2 +-
 drivers/gpu/drm/nouveau/nv50_display.c         |  2 +-
 drivers/gpu/drm/omapdrm/omap_crtc.c            |  4 +--
 drivers/gpu/drm/qxl/qxl_display.c              |  4 +--
 drivers/gpu/drm/radeon/atombios_crtc.c         | 12 +++----
 drivers/gpu/drm/radeon/cik.c                   |  4 +--
 drivers/gpu/drm/radeon/evergreen.c             |  6 ++--
 drivers/gpu/drm/radeon/r100.c                  |  4 +--
 drivers/gpu/drm/radeon/radeon_connectors.c     |  2 +-
 drivers/gpu/drm/radeon/radeon_cursor.c         |  4 +--
 drivers/gpu/drm/radeon/radeon_display.c        | 12 +++----
 drivers/gpu/drm/radeon/rs600.c                 |  4 +--
 drivers/gpu/drm/radeon/rs690.c                 | 16 ++++-----
 drivers/gpu/drm/radeon/rs780_dpm.c             |  4 +--
 drivers/gpu/drm/radeon/rv515.c                 | 20 +++++------
 drivers/gpu/drm/radeon/si.c                    |  6 ++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c         |  2 +-
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c      |  2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c    |  8 ++---
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c      |  2 +-
 drivers/gpu/drm/sti/sti_drm_crtc.c             |  2 +-
 drivers/gpu/drm/tegra/dc.c                     | 16 ++++++---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c           | 10 +++---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c            | 32 +++++++++---------
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c            | 10 +++---
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c           |  6 ++--
 include/drm/drm_crtc.h                         |  2 +-
 39 files changed, 187 insertions(+), 161 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index c5b06fd..4e586ab 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -109,8 +109,8 @@  armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 	unsigned idx = 0;
 	int ret;
 
-	crtc_w = armada_limit(crtc_x, crtc_w, dcrtc->crtc.mode.hdisplay);
-	crtc_h = armada_limit(crtc_y, crtc_h, dcrtc->crtc.mode.vdisplay);
+	crtc_w = armada_limit(crtc_x, crtc_w, dcrtc->crtc.mode->hdisplay);
+	crtc_h = armada_limit(crtc_y, crtc_h, dcrtc->crtc.mode->vdisplay);
 	ctrl0 = CFG_DMA_FMT(drm_fb_to_armada_fb(fb)->fmt) |
 		CFG_DMA_MOD(drm_fb_to_armada_fb(fb)->mod) |
 		CFG_CBSH_ENA | CFG_DMA_HSMOOTH | CFG_DMA_ENA;
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index fb11f75..3585624 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -100,7 +100,7 @@  static bool ast_get_vbios_mode_info(struct drm_crtc *crtc,
 		return false;
 	}
 
-	switch (crtc->mode.crtc_hdisplay) {
+	switch (crtc->mode->crtc_hdisplay) {
 	case 640:
 		vbios_mode->enh_table = &res_640x480[refresh_rate_index];
 		break;
@@ -111,7 +111,7 @@  static bool ast_get_vbios_mode_info(struct drm_crtc *crtc,
 		vbios_mode->enh_table = &res_1024x768[refresh_rate_index];
 		break;
 	case 1280:
-		if (crtc->mode.crtc_vdisplay == 800)
+		if (crtc->mode->crtc_vdisplay == 800)
 			vbios_mode->enh_table = &res_1280x800[refresh_rate_index];
 		else
 			vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
@@ -123,7 +123,7 @@  static bool ast_get_vbios_mode_info(struct drm_crtc *crtc,
 		vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
 		break;
 	case 1600:
-		if (crtc->mode.crtc_vdisplay == 900)
+		if (crtc->mode->crtc_vdisplay == 900)
 			vbios_mode->enh_table = &res_1600x900[refresh_rate_index];
 		else
 			vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
@@ -132,7 +132,7 @@  static bool ast_get_vbios_mode_info(struct drm_crtc *crtc,
 		vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
 		break;
 	case 1920:
-		if (crtc->mode.crtc_vdisplay == 1080)
+		if (crtc->mode->crtc_vdisplay == 1080)
 			vbios_mode->enh_table = &res_1920x1080[refresh_rate_index];
 		else
 			vbios_mode->enh_table = &res_1920x1200[refresh_rate_index];
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 962443d..bc7b629 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -699,7 +699,14 @@  set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
 		if (!crtc)
 			continue;
 
-		crtc->mode = *crtc->state->mode;
+		if (crtc->state->mode) {
+			if (crtc->mode)
+				drm_mode_destroy(dev, crtc->mode);
+			crtc->mode = drm_mode_duplicate(dev, crtc->state->mode);
+		} else if (crtc->mode) {
+			drm_mode_destroy(dev, crtc->mode);
+			crtc->mode = NULL;
+		}
 		crtc->enabled = crtc->state->enable;
 		crtc->x = crtc->primary->state->src_x >> 16;
 		crtc->y = crtc->primary->state->src_y >> 16;
@@ -1643,7 +1650,9 @@  retry:
 
 	crtc_state->enable = true;
 	crtc_state->active = true;
-	drm_mode_copy(crtc_state->mode, set->mode);
+	if (crtc_state->mode)
+		drm_mode_destroy(crtc->dev, crtc_state->mode);
+	crtc_state->mode = drm_mode_duplicate(crtc->dev, set->mode);
 
 	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
 	if (ret != 0)
@@ -2058,22 +2067,16 @@  EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
  */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 {
-	if (crtc->state)
-		kfree(crtc->state->mode);
+	if (crtc->state && crtc->state->mode)
+		drm_mode_destroy(crtc->dev, crtc->state->mode);
 
 	kfree(crtc->state);
 	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
 
-	if (crtc->state) {
-		crtc->state->crtc = crtc;
-		crtc->state->mode =
-			kzalloc(sizeof(*crtc->state->mode), GFP_KERNEL);
-	}
+	if (!crtc->state)
+		return;
 
-	if (crtc->state && !crtc->state->mode) {
-		kfree(crtc->state);
-		crtc->state = NULL;
-	}
+	crtc->state->crtc = crtc;
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
 
@@ -2094,12 +2097,18 @@  drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
 
 	state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
 
-	if (state) {
-		state->mode_changed = false;
-		state->active_changed = false;
-		state->planes_changed = false;
-		state->event = NULL;
-		state->mode = drm_mode_duplicate(crtc->dev, crtc->state->mode);
+	if (!state)
+		return NULL;
+
+	state->mode_changed = false;
+	state->active_changed = false;
+	state->planes_changed = false;
+	state->event = NULL;
+
+	if (crtc->state->mode) {
+		state->mode =
+			drm_mode_duplicate(crtc->dev,
+			                   crtc->state->mode);
 		if (!state->mode) {
 			kfree(state);
 			state = NULL;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 6023851..cf44403 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -662,6 +662,7 @@  int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
 	crtc->dev = dev;
 	crtc->funcs = funcs;
 	crtc->invert_dimensions = false;
+	crtc->mode = NULL;
 
 	drm_modeset_lock_init(&crtc->mutex);
 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
@@ -700,6 +701,9 @@  void drm_crtc_cleanup(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 
+	kfree(crtc->mode);
+	crtc->mode = NULL;
+
 	kfree(crtc->gamma_store);
 	crtc->gamma_store = NULL;
 
@@ -2008,6 +2012,7 @@  int drm_mode_getcrtc(struct drm_device *dev,
 		crtc_resp->x = crtc->primary->state->src_x >> 16;
 		crtc_resp->y = crtc->primary->state->src_y >> 16;
 		if (crtc->state->enable) {
+			WARN_ON(!crtc->state->mode);
 			drm_crtc_convert_to_umode(&crtc_resp->mode, crtc->state->mode);
 			crtc_resp->mode_valid = 1;
 
@@ -2018,7 +2023,9 @@  int drm_mode_getcrtc(struct drm_device *dev,
 		crtc_resp->x = crtc->x;
 		crtc_resp->y = crtc->y;
 		if (crtc->enabled) {
-			drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+			WARN_ON(!crtc->mode);
+			drm_crtc_convert_to_umode(&crtc_resp->mode,
+			                          crtc->mode);
 			crtc_resp->mode_valid = 1;
 
 		} else {
@@ -4942,7 +4949,7 @@  int drm_mode_page_flip_ioctl(struct drm_device *dev,
 		goto out;
 	}
 
-	ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
+	ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, crtc->mode, fb);
 	if (ret)
 		goto out;
 
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 8a9a045..46497dd 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -270,7 +270,8 @@  bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 			      struct drm_framebuffer *old_fb)
 {
 	struct drm_device *dev = crtc->dev;
-	struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
+	const struct drm_display_mode *saved_mode;
+	struct drm_display_mode *adjusted_mode, saved_hwmode;
 	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 	struct drm_encoder_helper_funcs *encoder_funcs;
 	int saved_x, saved_y;
@@ -292,14 +293,17 @@  bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 	}
 
 	saved_mode = crtc->mode;
-	saved_hwmode = crtc->hwmode;
+	drm_mode_copy(&saved_hwmode, &crtc->hwmode);
 	saved_x = crtc->x;
 	saved_y = crtc->y;
 
 	/* Update crtc values up front so the driver can rely on them for mode
 	 * setting.
 	 */
-	crtc->mode = *mode;
+	if (mode)
+		crtc->mode = drm_mode_duplicate(crtc->dev, mode);
+	else
+		crtc->mode = NULL;
 	crtc->x = x;
 	crtc->y = y;
 
@@ -335,7 +339,7 @@  bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 	}
 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
-	crtc->hwmode = *adjusted_mode;
+	drm_mode_copy(&crtc->hwmode, adjusted_mode);
 
 	/* Prepare the encoders and CRTCs before setting the mode. */
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -410,10 +414,14 @@  done:
 	drm_mode_destroy(dev, adjusted_mode);
 	if (!ret) {
 		crtc->enabled = saved_enabled;
+		if (crtc->mode)
+			drm_mode_destroy(crtc->dev, crtc->mode);
 		crtc->mode = saved_mode;
-		crtc->hwmode = saved_hwmode;
+		drm_mode_copy(&crtc->hwmode, &saved_hwmode);
 		crtc->x = saved_x;
 		crtc->y = saved_y;
+	} else {
+		drm_mode_destroy(dev, saved_mode);
 	}
 
 	return ret;
@@ -539,7 +547,7 @@  int drm_crtc_helper_set_config(struct drm_mode_set *set)
 	}
 
 	save_set.crtc = set->crtc;
-	save_set.mode = &set->crtc->mode;
+	save_set.mode = set->crtc->mode;
 	save_set.x = set->crtc->x;
 	save_set.y = set->crtc->y;
 	save_set.fb = set->crtc->primary->fb;
@@ -563,9 +571,9 @@  int drm_crtc_helper_set_config(struct drm_mode_set *set)
 	if (set->x != set->crtc->x || set->y != set->crtc->y)
 		fb_changed = true;
 
-	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
+	if (set->mode && !drm_mode_equal(set->mode, set->crtc->mode)) {
 		DRM_DEBUG_KMS("modes are different, full mode set\n");
-		drm_mode_debug_printmodeline(&set->crtc->mode);
+		drm_mode_debug_printmodeline(set->crtc->mode);
 		drm_mode_debug_printmodeline(set->mode);
 		mode_changed = true;
 	}
@@ -881,7 +889,7 @@  void drm_helper_resume_force_mode(struct drm_device *dev)
 		if (!crtc->enabled)
 			continue;
 
-		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
+		ret = drm_crtc_helper_set_mode(crtc, crtc->mode,
 					       crtc->x, crtc->y, crtc->primary->fb);
 
 		/* Restoring the old config should never fail! */
@@ -1040,12 +1048,12 @@  int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
 	plane_state->crtc_x = 0;
 	plane_state->crtc_y = 0;
-	plane_state->crtc_h = crtc->mode.vdisplay;
-	plane_state->crtc_w = crtc->mode.hdisplay;
+	plane_state->crtc_h = crtc->mode ? crtc->mode->vdisplay : 0;
+	plane_state->crtc_w = crtc->mode ? crtc->mode->hdisplay : 0;
 	plane_state->src_x = x << 16;
 	plane_state->src_y = y << 16;
-	plane_state->src_h = crtc->mode.vdisplay << 16;
-	plane_state->src_w = crtc->mode.hdisplay << 16;
+	plane_state->src_h = crtc->mode ? crtc->mode->vdisplay << 16 : 0;
+	plane_state->src_w = crtc->mode ? crtc->mode->hdisplay << 16 : 0;
 
 	return drm_plane_helper_commit(plane, plane_state, old_fb);
 }
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 33807e0..079ac2b 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -230,7 +230,7 @@  int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 	struct drm_mode_set set = {
 		.crtc = crtc,
 		.fb = fb,
-		.mode = &crtc->mode,
+		.mode = crtc->mode,
 		.x = src_x >> 16,
 		.y = src_y >> 16,
 	};
@@ -247,8 +247,8 @@  int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 		.y2 = crtc_y + crtc_h,
 	};
 	const struct drm_rect clip = {
-		.x2 = crtc->mode.hdisplay,
-		.y2 = crtc->mode.vdisplay,
+		.x2 = crtc->mode ? crtc->mode->hdisplay : 0,
+		.y2 = crtc->mode ? crtc->mode->vdisplay : 0,
 	};
 	struct drm_connector **connector_list;
 	int num_connectors, ret;
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
index dd7cea2..f8baf08 100644
--- a/drivers/gpu/drm/i2c/sil164_drv.c
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
@@ -218,7 +218,7 @@  sil164_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct sil164_priv *priv = to_sil164_priv(encoder);
 	bool on = (mode == DRM_MODE_DPMS_ON);
-	bool duallink = (on && encoder->crtc->mode.clock > 165000);
+	bool duallink = (on && encoder->crtc->mode->clock > 165000);
 
 	sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on);
 
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index c479386..80cb562 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -222,26 +222,22 @@  intel_crtc_duplicate_state(struct drm_crtc *crtc)
 		crtc_state = kmemdup(intel_crtc->config,
 				     sizeof(*intel_crtc->config), GFP_KERNEL);
 
-	if (crtc_state) {
-		crtc_state->base.crtc = crtc;
+	if (!crtc_state)
+		return NULL;
 
-		/* XXX: this is tedious */
-		if (intel_crtc->config) {
-			crtc_state->mode =
-				drm_mode_duplicate(crtc->dev,
-						   intel_crtc->config->mode);
-		} else {
-			crtc_state->mode =
-				kzalloc(sizeof(*crtc_state->mode), GFP_KERNEL);
-		}
+	crtc_state->base.crtc = crtc;
 
-		if (!crtc_state->mode) {
-			kfree(crtc_state);
-			crtc_state = NULL;
-		}
+	if (intel_crtc->config && intel_crtc->config->mode) {
+		crtc_state->mode =
+			drm_mode_duplicate(crtc->dev, intel_crtc->config->mode);
+		if (!crtc_state->mode)
+			goto err;
 	}
 
 	return &crtc_state->base;
+err:
+	kfree(crtc_state);
+	return NULL;
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 2f2863c..1d6c510 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -414,8 +414,8 @@  static int mdp5_crtc_set_property(struct drm_crtc *crtc,
 static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h)
 {
 	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	uint32_t xres = crtc->mode.hdisplay;
-	uint32_t yres = crtc->mode.vdisplay;
+	uint32_t xres = crtc->mode->hdisplay;
+	uint32_t yres = crtc->mode->vdisplay;
 
 	/*
 	 * Cursor Region Of Interest (ROI) is a plane read from cursor
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 093a420..c9d19c6 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -886,7 +886,7 @@  nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
 	nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start);
 
 	/* Update the arbitration parameters. */
-	nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
+	nouveau_calc_arb(dev, crtc->mode->clock, drm_fb->bits_per_pixel,
 			 &arb_burst, &arb_lwm);
 
 	regp->CRTC[NV_CIO_CRE_FF_INDEX] = arb_burst;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/cursor.c b/drivers/gpu/drm/nouveau/dispnv04/cursor.c
index 4e61173..e9a83aa 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/cursor.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/cursor.c
@@ -47,7 +47,7 @@  nv04_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
 		XLATE(offset, 17, NV_CIO_CRE_HCUR_ADDR0_ADR);
 	regp->CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX] =
 		XLATE(offset, 11, NV_CIO_CRE_HCUR_ADDR1_ADR);
-	if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
+	if (crtc->mode->flags & DRM_MODE_FLAG_DBLSCAN)
 		regp->CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX] |=
 			MASK(NV_CIO_CRE_HCUR_ADDR1_CUR_DBL);
 	regp->CRTC[NV_CIO_CRE_HCUR_ADDR2_INDEX] = offset >> 24;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
index 08c6f5e..eb11ec8 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
@@ -317,7 +317,7 @@  static void tv_setup_filter(struct drm_encoder *encoder)
 {
 	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
-	struct drm_display_mode *mode = &encoder->crtc->mode;
+	struct drm_display_mode *mode = encoder->crtc->mode;
 	uint32_t (*filters[])[4][7] = {&tv_enc->state.hfilter,
 				       &tv_enc->state.vfilter};
 	int i, j, k;
@@ -546,7 +546,7 @@  void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
 	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 	int head = nouveau_crtc(encoder->crtc)->index;
 	struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];
-	struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
+	struct drm_display_mode *crtc_mode = encoder->crtc->mode;
 	struct drm_display_mode *output_mode =
 		&get_tv_norm(encoder)->ctv_enc_mode.mode;
 	int overscan, hmargin, vmargin, hratio, vratio;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 604d944..1b4ac68 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -501,7 +501,7 @@  nouveau_connector_set_property(struct drm_connector *connector,
 
 		if (modeset || !nv_crtc->set_scale) {
 			ret = drm_crtc_helper_set_mode(&nv_crtc->base,
-							&nv_crtc->base.mode,
+							nv_crtc->base.mode,
 							nv_crtc->base.x,
 							nv_crtc->base.y, NULL);
 			if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 05b21ef..b1da742 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -722,7 +722,7 @@  static int
 nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
 {
 	struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
-	struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
+	struct drm_display_mode *omode, *umode = nv_crtc->base.mode;
 	struct drm_crtc *crtc = &nv_crtc->base;
 	struct nouveau_connector *nv_connector;
 	int mode = DRM_MODE_SCALE_NONE;
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index f394fdd..b3ea6ae 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -282,7 +282,7 @@  static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_plane *plane = omap_crtc->plane;
-	struct drm_display_mode *mode = &crtc->mode;
+	struct drm_display_mode *mode = crtc->mode;
 
 	return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
@@ -315,7 +315,7 @@  static void page_flip_worker(struct work_struct *work)
 	struct omap_crtc *omap_crtc =
 			container_of(work, struct omap_crtc, page_flip_work);
 	struct drm_crtc *crtc = &omap_crtc->base;
-	struct drm_display_mode *mode = &crtc->mode;
+	struct drm_display_mode *mode = crtc->mode;
 	struct drm_gem_object *bo;
 
 	drm_modeset_lock(&crtc->mutex, NULL);
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 189119d..83180e4 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -665,7 +665,7 @@  static int qxl_crtc_mode_set(struct drm_crtc *crtc,
 static void qxl_crtc_prepare(struct drm_crtc *crtc)
 {
 	DRM_DEBUG("current: %dx%d+%d+%d (%d).\n",
-		  crtc->mode.hdisplay, crtc->mode.vdisplay,
+		  crtc->mode->hdisplay, crtc->mode->vdisplay,
 		  crtc->x, crtc->y, crtc->enabled);
 }
 
@@ -765,7 +765,7 @@  static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev,
 	head = &qdev->monitors_config->heads[i];
 	head->id = i;
 	if (encoder->crtc->enabled) {
-		mode = &encoder->crtc->mode;
+		mode = encoder->crtc->mode;
 		head->width = mode->hdisplay;
 		head->height = mode->vdisplay;
 		head->x = encoder->crtc->x;
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 050e908..269e9fb 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1404,10 +1404,10 @@  static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	y &= ~1;
 	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
 	       (x << 16) | y);
-	viewport_w = crtc->mode.hdisplay;
-	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+	viewport_w = crtc->mode->hdisplay;
+	viewport_h = (crtc->mode->vdisplay + 1) & ~1;
 	if ((rdev->family >= CHIP_BONAIRE) &&
-	    (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE))
+	    (crtc->mode->flags & DRM_MODE_FLAG_INTERLACE))
 		viewport_h *= 2;
 	WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
 	       (viewport_w << 16) | viewport_h);
@@ -1607,8 +1607,8 @@  static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
 	y &= ~1;
 	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
 	       (x << 16) | y);
-	viewport_w = crtc->mode.hdisplay;
-	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+	viewport_w = crtc->mode->hdisplay;
+	viewport_h = (crtc->mode->vdisplay + 1) & ~1;
 	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
 	       (viewport_w << 16) | viewport_h);
 
@@ -1780,7 +1780,7 @@  static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
 			}
 			/* for non-DP check the clock */
 			test_adjusted_clock = test_radeon_crtc->adjusted_clock;
-			if ((crtc->mode.clock == test_crtc->mode.clock) &&
+			if ((crtc->mode->clock == test_crtc->mode->clock) &&
 			    (adjusted_clock == test_adjusted_clock) &&
 			    (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) &&
 			    (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID))
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 3e670d3..bb604f0 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -9325,7 +9325,7 @@  static void dce8_program_watermarks(struct radeon_device *rdev,
 				    struct radeon_crtc *radeon_crtc,
 				    u32 lb_size, u32 num_heads)
 {
-	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct drm_display_mode *mode = radeon_crtc->base.mode;
 	struct dce8_wm_params wm_low, wm_high;
 	u32 pixel_period;
 	u32 line_time = 0;
@@ -9467,7 +9467,7 @@  void dce8_bandwidth_update(struct radeon_device *rdev)
 			num_heads++;
 	}
 	for (i = 0; i < rdev->num_crtc; i++) {
-		mode = &rdev->mode_info.crtcs[i]->base.mode;
+		mode = rdev->mode_info.crtcs[i]->base.mode;
 		lb_size = dce8_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode);
 		dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
 	}
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 973df06..439a0ee 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2180,7 +2180,7 @@  static void evergreen_program_watermarks(struct radeon_device *rdev,
 					 struct radeon_crtc *radeon_crtc,
 					 u32 lb_size, u32 num_heads)
 {
-	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct drm_display_mode *mode = radeon_crtc->base.mode;
 	struct evergreen_wm_params wm_low, wm_high;
 	u32 dram_channels;
 	u32 pixel_period;
@@ -2356,8 +2356,8 @@  void evergreen_bandwidth_update(struct radeon_device *rdev)
 			num_heads++;
 	}
 	for (i = 0; i < rdev->num_crtc; i += 2) {
-		mode0 = &rdev->mode_info.crtcs[i]->base.mode;
-		mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
+		mode0 = rdev->mode_info.crtcs[i]->base.mode;
+		mode1 = rdev->mode_info.crtcs[i+1]->base.mode;
 		lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
 		evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
 		lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 04f2514..31fc514 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3223,12 +3223,12 @@  void r100_bandwidth_update(struct radeon_device *rdev)
 	radeon_update_display_priority(rdev);
 
 	if (rdev->mode_info.crtcs[0]->base.enabled) {
-		mode1 = &rdev->mode_info.crtcs[0]->base.mode;
+		mode1 = rdev->mode_info.crtcs[0]->base.mode;
 		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.primary->fb->bits_per_pixel / 8;
 	}
 	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
 		if (rdev->mode_info.crtcs[1]->base.enabled) {
-			mode2 = &rdev->mode_info.crtcs[1]->base.mode;
+			mode2 = rdev->mode_info.crtcs[1]->base.mode;
 			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.primary->fb->bits_per_pixel / 8;
 		}
 	}
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 2aae77f..91eeb6d 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -90,7 +90,7 @@  static void radeon_property_change_mode(struct drm_encoder *encoder)
 	struct drm_crtc *crtc = encoder->crtc;
 
 	if (crtc && crtc->enabled) {
-		drm_crtc_helper_set_mode(crtc, &crtc->mode,
+		drm_crtc_helper_set_mode(crtc, crtc->mode,
 					 crtc->x, crtc->y, crtc->primary->fb);
 	}
 }
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 45e5406..fc2c51b 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -162,7 +162,7 @@  static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
 			int cursor_end, frame_end;
 
 			cursor_end = x - xorigin + w;
-			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
+			frame_end = crtc->x + crtc->mode->crtc_hdisplay;
 			if (cursor_end >= frame_end) {
 				w = w - (cursor_end - frame_end);
 				if (!(frame_end & 0x7f))
@@ -193,7 +193,7 @@  static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
 		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
 		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 	} else {
-		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
+		if (crtc->mode->flags & DRM_MODE_FLAG_DBLSCAN)
 			y *= 2;
 
 		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 913fafa..4f2ebe0e 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1702,9 +1702,9 @@  bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
 			memcpy(&radeon_crtc->native_mode,
 			       &radeon_encoder->native_mode,
 				sizeof(struct drm_display_mode));
-			src_v = crtc->mode.vdisplay;
+			src_v = crtc->mode->vdisplay;
 			dst_v = radeon_crtc->native_mode.vdisplay;
-			src_h = crtc->mode.hdisplay;
+			src_h = crtc->mode->hdisplay;
 			dst_h = radeon_crtc->native_mode.hdisplay;
 
 			/* fix up for overscan on hdmi */
@@ -1723,10 +1723,10 @@  bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
 				else
 					radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
 				radeon_crtc->rmx_type = RMX_FULL;
-				src_v = crtc->mode.vdisplay;
-				dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2);
-				src_h = crtc->mode.hdisplay;
-				dst_h = crtc->mode.hdisplay - (radeon_crtc->h_border * 2);
+				src_v = crtc->mode->vdisplay;
+				dst_v = crtc->mode->vdisplay - (radeon_crtc->v_border * 2);
+				src_h = crtc->mode->hdisplay;
+				dst_h = crtc->mode->hdisplay - (radeon_crtc->h_border * 2);
 			}
 			first = false;
 		} else {
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 97a9048..15c9085 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -894,9 +894,9 @@  void rs600_bandwidth_update(struct radeon_device *rdev)
 	radeon_update_display_priority(rdev);
 
 	if (rdev->mode_info.crtcs[0]->base.enabled)
-		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+		mode0 = rdev->mode_info.crtcs[0]->base.mode;
 	if (rdev->mode_info.crtcs[1]->base.enabled)
-		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+		mode1 = rdev->mode_info.crtcs[1]->base.mode;
 
 	rs690_line_buffer_adjust(rdev, mode0, mode1);
 
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 516ca27..0a8ce19 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -263,7 +263,7 @@  static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 					 struct rs690_watermark *wm,
 					 bool low)
 {
-	struct drm_display_mode *mode = &crtc->base.mode;
+	struct drm_display_mode *mode = crtc->base.mode;
 	fixed20_12 a, b, c;
 	fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
 	fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
@@ -337,7 +337,7 @@  static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 *  LineTime = total number of horizontal pixels
 	 *  pclk = pixel clock period(ns)
 	 */
-	a.full = dfixed_const(crtc->base.mode.crtc_htotal);
+	a.full = dfixed_const(crtc->base.mode->crtc_htotal);
 	line_time.full = dfixed_mul(a, pclk);
 
 	/* Determine active time
@@ -345,8 +345,8 @@  static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 *  hactive = total number of horizontal active pixels
 	 *  htotal = total number of horizontal pixels
 	 */
-	a.full = dfixed_const(crtc->base.mode.crtc_htotal);
-	b.full = dfixed_const(crtc->base.mode.crtc_hdisplay);
+	a.full = dfixed_const(crtc->base.mode->crtc_htotal);
+	b.full = dfixed_const(crtc->base.mode->crtc_hdisplay);
 	wm->active_time.full = dfixed_mul(line_time, b);
 	wm->active_time.full = dfixed_div(wm->active_time, a);
 
@@ -429,14 +429,14 @@  static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 *  width = viewport width in pixels
 	 */
 	a.full = dfixed_const(16);
-	wm->priority_mark_max.full = dfixed_const(crtc->base.mode.crtc_hdisplay);
+	wm->priority_mark_max.full = dfixed_const(crtc->base.mode->crtc_hdisplay);
 	wm->priority_mark_max.full = dfixed_div(wm->priority_mark_max, a);
 	wm->priority_mark_max.full = dfixed_ceil(wm->priority_mark_max);
 
 	/* Determine estimated width */
 	estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full;
 	estimated_width.full = dfixed_div(estimated_width, consumption_time);
-	if (dfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) {
+	if (dfixed_trunc(estimated_width) > crtc->base.mode->crtc_hdisplay) {
 		wm->priority_mark.full = dfixed_const(10);
 	} else {
 		a.full = dfixed_const(16);
@@ -586,9 +586,9 @@  void rs690_bandwidth_update(struct radeon_device *rdev)
 	radeon_update_display_priority(rdev);
 
 	if (rdev->mode_info.crtcs[0]->base.enabled)
-		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+		mode0 = rdev->mode_info.crtcs[0]->base.mode;
 	if (rdev->mode_info.crtcs[1]->base.enabled)
-		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+		mode1 = rdev->mode_info.crtcs[1]->base.mode;
 	/*
 	 * Set display0/1 priority up in the memory controller for
 	 * modes if the user specifies HIGH for displaypriority
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
index 9031f4b..d0b7213 100644
--- a/drivers/gpu/drm/radeon/rs780_dpm.c
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -62,8 +62,8 @@  static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
 		if (crtc && crtc->enabled) {
 			radeon_crtc = to_radeon_crtc(crtc);
 			pi->crtc_id = radeon_crtc->crtc_id;
-			if (crtc->mode.htotal && crtc->mode.vtotal)
-				pi->refresh_rate = drm_mode_vrefresh(&crtc->mode);
+			if (crtc->mode->htotal && crtc->mode->vtotal)
+				pi->refresh_rate = drm_mode_vrefresh(crtc->mode);
 			break;
 		}
 	}
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index c55d653..23da03f 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -955,7 +955,7 @@  static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 					 struct rv515_watermark *wm,
 					 bool low)
 {
-	struct drm_display_mode *mode = &crtc->base.mode;
+	struct drm_display_mode *mode = crtc->base.mode;
 	fixed20_12 a, b, c;
 	fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
 	fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
@@ -1026,7 +1026,7 @@  static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 *  LineTime = total number of horizontal pixels
 	 *  pclk = pixel clock period(ns)
 	 */
-	a.full = dfixed_const(crtc->base.mode.crtc_htotal);
+	a.full = dfixed_const(crtc->base.mode->crtc_htotal);
 	line_time.full = dfixed_mul(a, pclk);
 
 	/* Determine active time
@@ -1034,8 +1034,8 @@  static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 *  hactive = total number of horizontal active pixels
 	 *  htotal = total number of horizontal pixels
 	 */
-	a.full = dfixed_const(crtc->base.mode.crtc_htotal);
-	b.full = dfixed_const(crtc->base.mode.crtc_hdisplay);
+	a.full = dfixed_const(crtc->base.mode->crtc_htotal);
+	b.full = dfixed_const(crtc->base.mode->crtc_hdisplay);
 	wm->active_time.full = dfixed_mul(line_time, b);
 	wm->active_time.full = dfixed_div(wm->active_time, a);
 
@@ -1089,14 +1089,14 @@  static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 *  width = viewport width in pixels
 	 */
 	a.full = dfixed_const(16);
-	wm->priority_mark_max.full = dfixed_const(crtc->base.mode.crtc_hdisplay);
+	wm->priority_mark_max.full = dfixed_const(crtc->base.mode->crtc_hdisplay);
 	wm->priority_mark_max.full = dfixed_div(wm->priority_mark_max, a);
 	wm->priority_mark_max.full = dfixed_ceil(wm->priority_mark_max);
 
 	/* Determine estimated width */
 	estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full;
 	estimated_width.full = dfixed_div(estimated_width, consumption_time);
-	if (dfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) {
+	if (dfixed_trunc(estimated_width) > crtc->base.mode->crtc_hdisplay) {
 		wm->priority_mark.full = wm->priority_mark_max.full;
 	} else {
 		a.full = dfixed_const(16);
@@ -1241,9 +1241,9 @@  void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
 	u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt;
 
 	if (rdev->mode_info.crtcs[0]->base.enabled)
-		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+		mode0 = rdev->mode_info.crtcs[0]->base.mode;
 	if (rdev->mode_info.crtcs[1]->base.enabled)
-		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+		mode1 = rdev->mode_info.crtcs[1]->base.mode;
 	rs690_line_buffer_adjust(rdev, mode0, mode1);
 
 	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false);
@@ -1283,9 +1283,9 @@  void rv515_bandwidth_update(struct radeon_device *rdev)
 	radeon_update_display_priority(rdev);
 
 	if (rdev->mode_info.crtcs[0]->base.enabled)
-		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+		mode0 = rdev->mode_info.crtcs[0]->base.mode;
 	if (rdev->mode_info.crtcs[1]->base.enabled)
-		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+		mode1 = rdev->mode_info.crtcs[1]->base.mode;
 	/*
 	 * Set display0/1 priority up in the memory controller for
 	 * modes if the user specifies HIGH for displaypriority
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index e088e55..6c7ac2b 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -2222,7 +2222,7 @@  static void dce6_program_watermarks(struct radeon_device *rdev,
 					 struct radeon_crtc *radeon_crtc,
 					 u32 lb_size, u32 num_heads)
 {
-	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct drm_display_mode *mode = radeon_crtc->base.mode;
 	struct dce6_wm_params wm_low, wm_high;
 	u32 dram_channels;
 	u32 pixel_period;
@@ -2395,8 +2395,8 @@  void dce6_bandwidth_update(struct radeon_device *rdev)
 			num_heads++;
 	}
 	for (i = 0; i < rdev->num_crtc; i += 2) {
-		mode0 = &rdev->mode_info.crtcs[i]->base.mode;
-		mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
+		mode0 = rdev->mode_info.crtcs[i]->base.mode;
+		mode1 = rdev->mode_info.crtcs[i+1]->base.mode;
 		lb_size = dce6_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
 		dce6_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
 		lb_size = dce6_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 9e72133..18a1ad9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -373,7 +373,7 @@  static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 	 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
 	 * actively driven).
 	 */
-	interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
+	interlaced = rcrtc->crtc.mode->flags & DRM_MODE_FLAG_INTERLACE;
 	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
 			     (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
 			     DSYSR_TVM_MASTER);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
index 85043c5..98c7cb9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -41,7 +41,7 @@  static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
 static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 				 struct rcar_du_crtc *rcrtc)
 {
-	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+	const struct drm_display_mode *mode = rcrtc->crtc.mode;
 	unsigned int freq = mode->clock;
 	u32 lvdcr0;
 	u32 lvdhcr;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 25f89b3..88e99aa 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -542,8 +542,8 @@  static int vop_update_plane_event(struct drm_plane *plane,
 		.y2 = src_y + src_h,
 	};
 	const struct drm_rect clip = {
-		.x2 = crtc->mode.hdisplay,
-		.y2 = crtc->mode.vdisplay,
+		.x2 = crtc->mode->hdisplay,
+		.y2 = crtc->mode->vdisplay,
 	};
 	bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY;
 
@@ -576,8 +576,8 @@  static int vop_update_plane_event(struct drm_plane *plane,
 	crtc_x = max(0, crtc_x);
 	crtc_y = max(0, crtc_y);
 
-	dsp_stx = crtc_x + crtc->mode.htotal - crtc->mode.hsync_start;
-	dsp_sty = crtc_y + crtc->mode.vtotal - crtc->mode.vsync_start;
+	dsp_stx = crtc_x + crtc->mode->htotal - crtc->mode->hsync_start;
+	dsp_sty = crtc_y + crtc->mode->vtotal - crtc->mode->vsync_start;
 
 	offset = (src.x1 >> 16) * (fb->bits_per_pixel >> 3);
 	offset += (src.y1 >> 16) * fb->pitches[0];
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index ab3b4f4..7414766 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -74,7 +74,7 @@  static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc)
 	struct drm_crtc *crtc = &scrtc->crtc;
 	struct shmob_drm_device *sdev = crtc->dev->dev_private;
 	const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
-	const struct drm_display_mode *mode = &crtc->mode;
+	const struct drm_display_mode *mode = crtc->mode;
 	u32 value;
 
 	value = sdev->ldmt1r
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c
index cfb75dc..b92e7e08 100644
--- a/drivers/gpu/drm/sti/sti_drm_crtc.c
+++ b/drivers/gpu/drm/sti/sti_drm_crtc.c
@@ -122,7 +122,7 @@  sti_drm_crtc_mode_set(struct drm_crtc *crtc,
 	}
 
 	sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
-			compo->vtg_main : compo->vtg_aux, &crtc->mode);
+			compo->vtg_main : compo->vtg_aux, crtc->mode);
 
 	/* a GDP is reserved to the CRTC FB */
 	layer = to_sti_layer(crtc->primary);
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 40f6e74..6717f07 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -995,6 +995,9 @@  static void tegra_crtc_reset(struct drm_crtc *crtc)
 {
 	struct tegra_dc_state *state;
 
+	if (crtc->state && crtc->state->mode)
+		drm_mode_destroy(crtc->dev, crtc->state->mode);
+
 	kfree(crtc->state);
 	crtc->state = NULL;
 
@@ -1015,11 +1018,11 @@  tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 	if (!copy)
 		return NULL;
 
-	/* XXX: tedium */
-	copy->base.mode = drm_mode_duplicate(crtc->dev, state->base.mode);
-	if (!copy->base.mode) {
-		kfree(copy);
-		return NULL;
+	if (state->base.mode) {
+		copy->base.mode =
+			drm_mode_duplicate(crtc->dev, state->base.mode);
+		if (!copy->base.mode)
+			goto err;
 	}
 
 	copy->base.mode_changed = false;
@@ -1028,6 +1031,9 @@  tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 	copy->base.event = NULL;
 
 	return &copy->base;
+err:
+	kfree(copy);
+	return NULL;
 }
 
 static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index d5fafef..2734deb 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -96,7 +96,7 @@  static void update_scanout(struct drm_crtc *crtc)
 			(crtc->y * fb->pitches[0]) + (crtc->x * bpp/8);
 
 	tilcdc_crtc->end = tilcdc_crtc->start +
-			(crtc->mode.vdisplay * fb->pitches[0]);
+			(crtc->mode->vdisplay * fb->pitches[0]);
 
 	if (tilcdc_crtc->dpms == DRM_MODE_DPMS_ON) {
 		/* already enabled, so just mark the frames that need
@@ -549,17 +549,17 @@  void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
 		tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 
 	/* in raster mode, minimum divisor is 2: */
-	ret = clk_set_rate(priv->disp_clk, crtc->mode.clock * 1000 * 2);
+	ret = clk_set_rate(priv->disp_clk, crtc->mode->clock * 1000 * 2);
 	if (ret) {
 		dev_err(dev->dev, "failed to set display clock rate to: %d\n",
-				crtc->mode.clock);
+				crtc->mode->clock);
 		goto out;
 	}
 
 	lcd_clk = clk_get_rate(priv->clk);
-	div = lcd_clk / (crtc->mode.clock * 1000);
+	div = lcd_clk / (crtc->mode->clock * 1000);
 
-	DBG("lcd_clk=%u, mode clock=%d, div=%u", lcd_clk, crtc->mode.clock, div);
+	DBG("lcd_clk=%u, mode clock=%d, div=%u", lcd_clk, crtc->mode->clock, div);
 	DBG("fck=%lu, dpll_disp_ck=%lu", clk_get_rate(priv->clk), clk_get_rate(priv->disp_clk));
 
 	/* Configure the LCD clock divisor. */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8725b79..172aa3d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -536,8 +536,8 @@  static int do_surface_dirty_sou(struct vmw_private *dev_priv,
 		clip.y2 = bottom - unit->crtc.y;
 
 		/* skip any crtcs that misses the clip region */
-		if (clip.x1 >= unit->crtc.mode.hdisplay ||
-		    clip.y1 >= unit->crtc.mode.vdisplay ||
+		if (clip.x1 >= unit->crtc.mode->hdisplay ||
+		    clip.y1 >= unit->crtc.mode->vdisplay ||
 		    clip.x2 <= 0 || clip.y2 <= 0)
 			continue;
 
@@ -551,8 +551,8 @@  static int do_surface_dirty_sou(struct vmw_private *dev_priv,
 		cmd->body.destRect.bottom = clip.y2;
 
 		/* create a clip rect of the crtc in dest coords */
-		clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
-		clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
+		clip.x2 = unit->crtc.mode->hdisplay - clip.x1;
+		clip.y2 = unit->crtc.mode->vdisplay - clip.y1;
 		clip.x1 = 0 - clip.x1;
 		clip.y1 = 0 - clip.y1;
 
@@ -900,14 +900,14 @@  static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
 			int move_x, move_y;
 
 			/* skip any crtcs that misses the clip region */
-			if (clip_x1 >= unit->crtc.mode.hdisplay ||
-			    clip_y1 >= unit->crtc.mode.vdisplay ||
+			if (clip_x1 >= unit->crtc.mode->hdisplay ||
+			    clip_y1 >= unit->crtc.mode->vdisplay ||
 			    clip_x2 <= 0 || clip_y2 <= 0)
 				continue;
 
 			/* clip size to crtc size */
-			clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay);
-			clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay);
+			clip_x2 = min_t(int, clip_x2, unit->crtc.mode->hdisplay);
+			clip_y2 = min_t(int, clip_y2, unit->crtc.mode->vdisplay);
 
 			/* translate both src and dest to bring clip into screen */
 			move_x = min_t(int, clip_x1, 0);
@@ -1306,8 +1306,8 @@  int vmw_kms_present(struct vmw_private *dev_priv,
 		clip.y2 = bottom + destY - unit->crtc.y;
 
 		/* skip any crtcs that misses the clip region */
-		if (clip.x1 >= unit->crtc.mode.hdisplay ||
-		    clip.y1 >= unit->crtc.mode.vdisplay ||
+		if (clip.x1 >= unit->crtc.mode->hdisplay ||
+		    clip.y1 >= unit->crtc.mode->vdisplay ||
 		    clip.x2 <= 0 || clip.y2 <= 0)
 			continue;
 
@@ -1321,8 +1321,8 @@  int vmw_kms_present(struct vmw_private *dev_priv,
 		cmd->body.destRect.bottom = clip.y2;
 
 		/* create a clip rect of the crtc in dest coords */
-		clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
-		clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
+		clip.x2 = unit->crtc.mode->hdisplay - clip.x1;
+		clip.y2 = unit->crtc.mode->vdisplay - clip.y1;
 		clip.x1 = 0 - clip.x1;
 		clip.y1 = 0 - clip.y1;
 
@@ -1429,12 +1429,12 @@  int vmw_kms_readback(struct vmw_private *dev_priv,
 			/* clip */
 			clip_x1 = max(clip_x1, 0);
 			clip_y1 = max(clip_y1, 0);
-			clip_x2 = min(clip_x2, units[i]->crtc.mode.hdisplay);
-			clip_y2 = min(clip_y2, units[i]->crtc.mode.vdisplay);
+			clip_x2 = min(clip_x2, units[i]->crtc.mode->hdisplay);
+			clip_y2 = min(clip_y2, units[i]->crtc.mode->vdisplay);
 
 			/* and cull any rects that misses the crtc */
-			if (clip_x1 >= units[i]->crtc.mode.hdisplay ||
-			    clip_y1 >= units[i]->crtc.mode.vdisplay ||
+			if (clip_x1 >= units[i]->crtc.mode->hdisplay ||
+			    clip_y1 >= units[i]->crtc.mode->vdisplay ||
 			    clip_x2 <= 0 || clip_y2 <= 0)
 				continue;
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 3c231b2..e71b7b2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -87,8 +87,8 @@  static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
 		int w = 0, h = 0;
 		list_for_each_entry(entry, &lds->active, active) {
 			crtc = &entry->base.crtc;
-			w = max(w, crtc->x + crtc->mode.hdisplay);
-			h = max(h, crtc->y + crtc->mode.vdisplay);
+			w = max(w, crtc->x + crtc->mode->hdisplay);
+			h = max(h, crtc->y + crtc->mode->vdisplay);
 			i++;
 		}
 
@@ -120,8 +120,8 @@  static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
 		vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i);
 		vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, crtc->x);
 		vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, crtc->y);
-		vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, crtc->mode.hdisplay);
-		vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, crtc->mode.vdisplay);
+		vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, crtc->mode->hdisplay);
+		vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, crtc->mode->vdisplay);
 		vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
 
 		i++;
@@ -286,7 +286,7 @@  static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 	connector->encoder = encoder;
 	crtc->x = set->x;
 	crtc->y = set->y;
-	crtc->mode = *mode;
+	drm_mode_copy(crtc->mode, mode);
 	crtc->enabled = true;
 
 	vmw_ldu_add_active(dev_priv, ldu, vfb);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 213afa5..9f13ba0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -333,8 +333,8 @@  static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 
 	vmw_fb_off(dev_priv);
 
-	if (mode->hdisplay != crtc->mode.hdisplay ||
-	    mode->vdisplay != crtc->mode.vdisplay) {
+	if (mode->hdisplay != crtc->mode->hdisplay ||
+	    mode->vdisplay != crtc->mode->vdisplay) {
 		/* no need to check if depth is different, because backing
 		 * store depth is forced to 4 by the device.
 		 */
@@ -381,7 +381,7 @@  static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 
 	connector->encoder = encoder;
 	encoder->crtc = crtc;
-	crtc->mode = *mode;
+	drm_mode_copy(crtc->mode, mode);
 	crtc->primary->fb = fb;
 	crtc->x = set->x;
 	crtc->y = set->y;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 2bce96e..7e91b8f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -446,7 +446,7 @@  struct drm_crtc {
 	bool enabled;
 
 	/* Requested mode from modesetting. */
-	struct drm_display_mode mode;
+	struct drm_display_mode *mode;
 
 	/* Programmed mode in hw, after adjustments for encoders,
 	 * crtc, panel scaling etc. Needed for timestamping etc.